1\documentclass[dakotalogo]{dakota-article} 2 3 4\usepackage{pifont}% allow use of arrows for items 5\newcommand{\myitem}{\item[\color{darkblue}\ding{228}]} 6 7 8\funding{This work was supported by ASC software. Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly 9owned subsidiary of Lockheed Martin Corporation, for the U.S. Department of Energy's National Nuclear Security 10Administration under contract DE-AC04-94AL85000.} 11\def\mytitle{Surrogates: Emulating computer simulations} 12\title{\mytitle} 13\shorttitle{Dakota Technical Design Document} 14\date{March 2017} 15\def\mycorauthor{John D. Jakeman} 16\corauthor{\mycorauthor} 17\coremail{jdjakem@sandia.gov} 18 19\def\SNL{Sandia National Laboratories, Albuquerque, New Mexico, USA } 20%\def\corauthor{{\color{darkblue} Correspondence author}. \SNL (jdjakem@sandia.gov)} 21 22\shortauthor{Adams, Hooper, Jakeman, Rushdi} 23\author{B. Adams\thanks{\SNL}, R. Hooper\samethanks[1], \mycorauthor\samethanks[1], A. Rushdi\samethanks[1]} 24 25\setlength{\headheight}{21pt}% 26\begin{document} 27\pagestyle{myheader} 28\maketitle 29\section{Introduction} 30\subsection{Purpose} 31This library will provide a suite of algorithms for emulating expensive computer simulations. 32 33\subsection{Scope} 34This library will replace the existing surrogate tools in Dakota and enrich these existing tools with additional state of the art surrogates and algorithms. 35 36\subsection{Overview} 37This library will consist of 5 main software components visible to the user at the highest level of abstraction: 38\begin{itemize} 39\myitem Function - A class, from which surrogates is derived whose interface represents the mathematical properties of a $C_2$ continous function, e.g supports evaluation of values, gradients and Hessians. evaluated 40\myitem Variables - A class defining the properties of the function variables, e.g. probability distribution, ranges, etc. We will support all current Dakota Variable types in addition to blocks of correlated variables whose distribution is known, data-based-variables whose distribution is computed from data, and compositions of all variables. 41\myitem Data - A class to store data returned by function and the associated samples of the function variables. This class will also contain fault information. We must provide modules that convert simple structures such as matrices and vectors of samples and values into this class. 42\myitem SurrogateFactory - A factory to construct a surrogate/approximation. Typical workflow will be generate a set of samples, evaluate function at those samples and build approximation. This call structure can be repeated iteratively to build up surrogates adaptively. We will also support the use and enrichment of archived data. This factor will support typical Dakota use-cases, however uses will be easily able to develop and add there own methods for building surrogates. 43\myitem SurrogateAnalyzer - A factory for running various types of analysis on surrogate models, e.g. compute moments, sobol indices, etc. If certain surrogates support fast operations to compute these values, e.g. PCE can compute mean and variance analytically these specialized functions will be envoked, but other wise a default will be called. 44\end{itemize} 45Currently the above notions of function and surrogate builders and analysis are heaverly intertwined in Dakota. Our design will allow these distinct components to be separated. This will allow surrogates to become a standalone part of the dakota Model hierarchy and surrogate analyzers to become lightweight Dakota Iterators. 46 47\subsection{Requirements} 48The following is a list of requirements 49\begin{itemize} 50\myitem User flexibity. Design must support 'push-button' users that want hired wired behavior and power users that wish to develop their own surrogate methods or expose low-level functionality. 51\myitem Serialization of surrogates - Ability to save and load surrogate objects 52\myitem Python interface - be able to call both high-level and low-level functions using Python. 53\myitem Gaussian Process consolidation - Consolidate GP methods in Dakota. Extend GP to include estimation of hyper-parametersa and use PCE trend function. 54\myitem Surrogates for multiple QOI - Build a single surrogate for multiple QOI. Allow for composition of surrogate types. 55\myitem Exending variable class - Support all Dakota variable types as well as blocks of correlated variables whose distribution is known, data-based-variables whose distribution is computed from data, and compositions of all variables. Retirement of AleatoryDistParams in Dakota. 56\myitem Simple approximation classes. Separation of approximation and the code used to construct it. Particularly relevant in Pecos. RegressOrthogPolynomial contains PCE object but also regression methods used to build the PCE. Similarly for Sparse grids need to seperate approximation, either lagrange polynomials or PCE, from refinement tools For example, split current subspaces which are part of approximation from active subspaces being considered for refinement which should only been known to sparse grid builder 57\myitem Function Data. The function data class should have no notion of active and stored data we shold just use indexing to access the data needed. 58\end{itemize} 59 60 61\section{Design} 62\subsection{High-level interface} 63The following is an example of the typical workflow used to build a surrogate 64\begin{codelisting}[]{Construct Surrogate Demonstration} 65 66// Configure options used to build surrogate 67Teuchos::ParameterList factor_opts; 68factory_opts.set(function, "target function"); 69factory_opts.set(data, "optional archived data"); 70factory_opts.set(PCE, "approximation type"); 71factory_opts.set("regression", "construction method"); 72//factory_opts.set("adapted-regression", "construction method"); 73factory_opts.set("OMP", "regression solver"); 74factory_opts.set("random", "sample type"); 75//factory_opts.set("optimal", "sample type"); 76 77// Build surrogate 78Teuchos::RCP<Approximation> approx = SurrogateFactory(factory_opts); 79 80// Analyze surrogate 81Teuchos::ParameterList analyzer_opts; 82analyzer_opts.set(MOMENTS, "analysis type"); 83Teuchos::RCP<AnalyzerMetrics> result = SurrogateAnalyzer(approx, analyzer_opts); 84 85// Print metrics 86std::cout << "Mean: " << result.get("mean") << std::endl; 87std::cout << "Variance: " << result.get("variance") << std::endl; 88 89\end{codelisting} 90 91\subsection{Surrogate Interface} 92We will use a factory pattern to build a surrogate. The Surrogate factory will call lower level factories which are specific to each type of approximation. Approximation types can be added at these levels without the call to surrogate factory being modified. These new types can just be created by passing appropriate options via {\texttt Teuchos::ParameterList}. 93\begin{codelisting}[]{Surrogate Factory} 94enum ApproxType {PCE,GP}; 95Teuchos::RCP<Approximation> surrogate_factory(const Teuchos::ParameterList opts){ 96 ApproxType approx_type = opts.get<ApproxType>("approximation type"); 97 switch (approx_type){ 98 case PCE : { 99 return PCEFactory(opts, approx); 100 } 101 case GP : { 102 return GPFactory(opts, approx); 103 } 104 default : { 105 throw(std::runtime_error("Incorrect approximation type")); 106 } 107 } 108} 109\end{codelisting} 110 111\subsection{Surrogate Analyzer} 112The surrogate analyzer will be implemented using a factory pattern. The analyzer will support various types of analysis on surrogate models, e.g. the computation of moments, sobol indices, etc. If certain surrogates support fast operations to compute these values, e.g. PCE can compute mean and variance analytically these specialized functions will be envoked, but other wise a default will be called. 113\begin{codelisting}{Surrogate Analyzer} 114enum AnalysisType {MOMENTS,SOBOL_INDICES}; 115Teuchos::RCP<AnaylzerMetrics> surrogate_anaylzer_factory(const Teuchos::ParameterList opts, Approximation &approx){ 116 AnalysisType analysis_type = opts.get<AnalysisType>("analysis type"); 117 switch (analysis_type){ 118 case MOMENTS : { 119 RealVector means, variances; 120 Teuchos::ParameterList moment_opts; 121 moment_opts.set(false, "compute mean"); 122 moment_opts.set(false, "compute variance"); 123 if (!approx.get("mean",means)) 124 // if specialized method does not exist use default 125 moment_opts.set(true, "compute mean"); 126 if (!approx.get("variance",variances)) 127 // if specialized method does not exist use default 128 moment_opts.set(true, "compute variance"); 129 compute_moments_using_sampling_carlo( 130 approx,moment_opts,means,variances) 131 break; 132 } 133 case SOBOL_INDICES : { 134 RealMatrix sobol_indices; 135 if (!approx.get("sobol_indices",sobol_indices)) 136 // if specialized method does not exist use default 137 // opts can contain options like restricted indices 138 compute_sobol_indices_using_sampling(approx,opts,sobol_indices); 139 break; 140 } 141 default : { 142 throw(std::runtime_error("Incorrect approximation type")); 143 } 144 } 145} 146\end{codelisting} 147 148\subsection{Approximations} 149Approximations will all be derived from a base function class. The interface of the function class will be restricted to only those functions that represents the mathematical properties of a $C_2$ continous function, e.g supports evaluation of values, gradients and Hessians. Each approximation will only contain the methods relevant to its construction, e.g. PCE has {\texttt build\_basis\_matrix} and {\texttt set\_coefficients} and GP has {\texttt build\_correlation\_matrix} and {\texttt set\_correlation\_lenghts}. 150 151The basic approximation class hierarchy is depicted in Figure~\ref{fig:approx-class-hierarcy}. This hierarchy will be extended as additional approximation types are added. 152 153\begin{figure}[htb]\centering 154\includegraphics[width=0.7\textwidth]{classSurrogates_1_1Function.png} 155\caption{Function class hierarchy.} 156\label{fig:approx-class-hierarcy} 157\end{figure} 158 159\subsubsection{Function base class} 160 161Here we describe the abstract base class representation of a function $f(x)$ for a multivariate variable x. 162Functions derived from this class can either be $C_0, C_1$ or $C_2$ 163 continuous. Regardlesd of the function regularity any derived class must 164implement value(), $C_1$ functions must implement gradient() and jacobian() 165and $C_2$ functions must implement hessian(). 166 167To avoid complexity of the function hierarchy we do not create seperate classes 168for $C_0, C_1$ and $C_2$ functions but rather only implement the 169functions necessitated by the function regularity. All other functions must 170raise an exception if called (these exceptions are implemented in this base 171class) 172\begin{figure}[htb]\centering 173\includegraphics[width=0.7\textwidth]{function-class-members.png} 174\caption{Function base class member functions.} 175\end{figure} 176 177QUESTION: Do we have functions for value, gradient, hessian or do we 178have a function value(samples,opts) where opts specifies what of the 179three data to return. 180 181\subsection{Variables} 182Variables is a class defining the properties of the function variables, e.g. probability distribution, ranges, etc. There is almost no functionality in the base class except {\texttt num\_vars}. The rest of the functionality is implemented in the derived class and variable transformations or approximations which use the derived class must know what additional functions are implemented. An example of a variable class is shown in Figure~\ref{fig:bounded-vars-class}. 183 184\begin{figure}[htb]\centering 185\includegraphics[width=0.7\textwidth]{bounded-vars-members.png} 186\caption{Example of a variables class.} 187\label{fig:bounded-vars-class} 188\end{figure} 189 190\subsubsection{Variable Transformations} 191Surrogates will sometimes the users provided variables to be mapped to a set of variables that the approximation can use. E.g a PCE requires variables on canonical domains such as Uniform on $[-1,1]$. These mappings are peformed by variable transformations. An example implementation for an affine transformation of bounded variables is shown below. 192\begin{codelisting}{Example of variable transformation code} 193void AffineVariableTransformation:: 194map_samples_from_user_space(const RealMatrix &samples, 195RealMatrix &transformed_samples) const { 196 int num_vars = boundedVars_->num_vars(); 197 if ( samples.numRows() != boundedVars_->num_vars() ) 198 throw( std::runtime_error("Samples have incorrect number of random variables") ); 199 200 int num_samples = samples.numCols(); 201 transformed_samples.shapeUninitialized(num_vars, num_samples); 202 for ( int j=0; j<num_samples; j++ ){ 203 for ( int i=0; i<num_vars; i++ ){ 204 transformed_samples(j,i) = 205 (samples(i,j)+1)/2.*(boundedVars_->ub(i)-boundedVars_->lb(i))+boundedVars_->lb(i); 206 } 207 } 208} 209\end{codelisting} 210 211Here is an example of using a variable transformation 212\section{Approximation Builders} 213The approximation factories call approximation builders. An example of 214how a builder may work is given below. This builder consists of two 215steps defining the approximation and the sampling the function and 216solving for its coefficients using regression. builders may call 217other builder in an inner loop. For example we may wish to iteratively 218add samples. In which case we would call this builder in an inner loop 219until an error estimate reaches a desired level of accuracy. In the 220example below we pass in a function but we could also pass in existing data. 221\begin{codelisting}{Example of a surrogate builder} 222// Define the function variables 223 RealVector ranges; 224 define_homogeneous_ranges(num_vars, 0., 1., ranges); 225 Teuchos::RCP<Variables> variables(new BoundedVariables()); 226 Teuchos::rcp_dynamic_cast<BoundedVariables>(variables)->set_ranges(ranges); 227 228 // Define the variable transformation. Need to decide if a seperate 229 // transformation should exist for approximation and for mapping samples 230 // generated. For example approximation accepts samples in user x-space 231 // but operates in a standardized u-space. But sample generator produces 232 // samples in (possibly another standardized space) and must map these to 233 // x-space, or even to approximation u-space. 234 Teuchos::RCP<VariableTransformation> var_transform(new AffineVariableTransformation()); 235 var_transform->set_variables(variables); 236 237// Initialize the approximation 238 Teuchos::ParameterList monomial_opts; 239 monomial_opts.set("max_total_degree",degree, 240 "max degree of total-degree polynomial space"); 241 monomial_opts.set("num_qoi", num_qoi, "number of quantites of interest."); 242 Monomial monomial; 243 monomial.set_options(monomial_opts); 244 monomial.set_variable_transformation(var_transform); 245 IntMatrix basis_indices; 246 compute_hyperbolic_indices(num_vars, degree, 1., basis_indices); 247 monomial.set_basis_indices(basis_indices); 248 249 // Generate the approximation coefficients using a regression based method 250 Teuchos::ParameterList regression_opts; 251 regression_opts.set("regression type",SVD_LEAST_SQ_REGRESSION); 252 regression_opts.set("num_samples",num_samples); 253 regression_opts.set("sample_type","probabilistic_MC"); 254 RegressionBuilder builder; 255 builder.set_target_function(model); 256 builder.build(regression_opts, monomial); 257\end{codelisting} 258QUESTION: DO we pass in target function and any data through 259ParameterList opts or through member functions? 260\subsection{Regression methods} 261For a given approximation type, there are a number of ways one might want 262to construt the approximation. For example we can use different types 263of regression to build a PCE, neural net etc, or we may want to build 264a pseudo spectral pce using different types of quadrature. In these 265cases we need factories to choose the builder sub-component, 266e.g. least squares or l1 minimization for regression based pce, or 267monte carlo or sparse grid quadrature for pseudo spectral pce. 268An example of such builders is given below. 269\begin{codelisting}[]{Example builder for regression based 270 approximations} 271 // Generate samples to build approximation 272 int num_samples = opts.get<int>("num_samples"); 273 std::string sample_type = opts.get<std::string>("sample_type"); 274 275 // Create mc sampler and pass in sample type. 276 // For now hack support for uniform mc sampler 277 RealMatrix samples; 278 int seed = 1337; 279 Teuchos::RCP<VariableTransformation> var_transform = 280 approx.get_variable_transformation(); 281 generate_uniform_samples(approx.num_vars(), num_samples, seed, 282 *var_transform, samples); 283 284 // Evaluate the function at the build samples 285 RealMatrix values; 286 targetFunction_->value(samples, values); 287 288 //\todo consider having opts have multiple parameterLists 289 //each associated with a particular aspect of build 290 //e.g. opts = (sample_opts, regression_opts) 291 PolynomialApproximation& poly_approx = 292 dynamic_cast<PolynomialApproximation&>(approx); 293 294 // Generate matrix of the linear system to be used in 295 // regression solve 296 RealMatrix basis_matrix; 297 poly_approx.generate_basis_matrix(samples,basis_matrix); 298 299 // Solve regression problem to get coefficients 300 Teuchos::RCP<LinearSystemSolver> solver = 301 regression_solver_factory(opts); 302 RealMatrix coeffs, metrics; 303 solver->solve(basis_matrix, values, coeffs, metrics, opts); 304 305 // Set the approximation coefficients 306 poly_approx.set_coefficients(coeffs); 307\end{codelisting} 308The solvers inheritance diagram is depicted in 309Figure~\ref{fig:regresion-solver-inheritance}. The hierarchy lets each 310class define specialized implementations of things like cross 311validation. Sparse solvers have a default implementation of iterative 312reweighting which they can call, the definition of this function DOES 313NOT exist in the base class. 314\begin{figure}[htb]\centering 315\includegraphics[width=0.7\textwidth]{classSurrogates_1_1LinearSystemSolver.png} 316\caption{The regression solver hierarchy.} 317\label{fig:regresion-solver-inheritance} 318\end{figure} 319Specialization of sparse solver is shown in 320Figure~\ref{fig:sparse-solver-members} 321\begin{figure}[htb]\centering 322\includegraphics[width=0.7\textwidth]{sparsesolverclass.jpeg} 323\caption{Sparse solver member functions. Only solve exists in baseclass} 324\label{fig:sparse-solver-members} 325\end{figure} 326\section{Integration with Dakota} 327Currently the notions of Approximation (DataFitSurrogate) and surrogate builders and analysis are heaverly intertwined in Dakota. Our design will allow these distinct components to be separated. This will allow Approximation to become a standalone part of the dakota Model hierarchy and surrogate analyzers to become lightweight Dakota Iterators. 328 329\include{variables_class} 330 331% \begin{figure}[htb]\centering 332% %\includegraphics[width=0.7\textwidth]{bounded-vars-members.png} 333% \caption{The relationship of surrogate classes to the Dakota class hierarchy} 334% \label{fig:bounded-vars-class} 335% \end{figure} 336\end{document} 337 338%%% Local Variables: 339%%% mode: latex 340%%% TeX-master: t 341%%% End: 342