1 /*  _______________________________________________________________________
2 
3     DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
4     Copyright 2014-2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Dakota directory.
7     _______________________________________________________________________ */
8 
9 //- Class:       RecastModel
10 //- Description: Implementation code for the RecastModel class
11 //- Owner:       Mike Eldred
12 //- Checked by:
13 
14 #include "dakota_system_defs.hpp"
15 #include "RecastModel.hpp"
16 #include "EvaluationStore.hpp"
17 
18 static const char rcsId[]="@(#) $Id: RecastModel.cpp 7029 2010-10-22 00:17:02Z mseldre $";
19 
20 
21 using namespace std;
22 
23 namespace Dakota {
24 
25 //#define DEBUG
26 
27 // init static var
28 StringStringPairIntMap RecastModel::recastModelIdCounters;
29 
30 
31 /** Default recast model constructor.  Requires full definition of the
32     transformation; if any mappings are NULL, they are assumed to
33     remain so in later initialization or updates.  Parameter
34     vars_comps_totals indicates the number of each type of variable {4
35     types} x {3 domains} in the recast variable space.  Note:
36     recast_secondary_offset is the start index for equality
37     constraints, typically num nonlinear ineq constraints. */
38 RecastModel::
RecastModel(const Model & sub_model,const Sizet2DArray & vars_map_indices,const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr,bool nonlinear_vars_mapping,void (* variables_map)(const Variables & recast_vars,Variables & sub_model_vars),void (* set_map)(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set),const Sizet2DArray & primary_resp_map_indices,const Sizet2DArray & secondary_resp_map_indices,size_t recast_secondary_offset,short recast_resp_order,const BoolDequeArray & nonlinear_resp_mapping,void (* primary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response),void (* secondary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response))39 RecastModel(const Model& sub_model, const Sizet2DArray& vars_map_indices,
40 	    const SizetArray& vars_comps_totals, const BitArray& all_relax_di,
41 	    const BitArray& all_relax_dr, bool nonlinear_vars_mapping,
42 	    void (*variables_map)      (const Variables& recast_vars,
43 					Variables& sub_model_vars),
44 	    void (*set_map)            (const Variables& recast_vars,
45 					const ActiveSet& recast_set,
46 					ActiveSet& sub_model_set),
47 	    const Sizet2DArray& primary_resp_map_indices,
48 	    const Sizet2DArray& secondary_resp_map_indices,
49 	    size_t recast_secondary_offset, short recast_resp_order,
50 	    const BoolDequeArray& nonlinear_resp_mapping,
51 	    void (*primary_resp_map)   (const Variables& sub_model_vars,
52 					const Variables& recast_vars,
53 					const Response& sub_model_response,
54 					Response& recast_response),
55 	    void (*secondary_resp_map) (const Variables& sub_model_vars,
56 					const Variables& recast_vars,
57 					const Response& sub_model_response,
58 					Response& recast_response)):
59   Model(LightWtBaseConstructor(), sub_model.problem_description_db(),
60 	sub_model.parallel_library()),
61   subModel(sub_model), varsMapIndices(vars_map_indices),
62   nonlinearVarsMapping(nonlinear_vars_mapping),
63   primaryRespMapIndices(primary_resp_map_indices),
64   secondaryRespMapIndices(secondary_resp_map_indices),
65   nonlinearRespMapping(nonlinear_resp_mapping), recastModelEvalCntr(0),
66   variablesMapping(variables_map), setMapping(set_map),
67   primaryRespMapping(primary_resp_map),
68   secondaryRespMapping(secondary_resp_map), invVarsMapping(NULL),
69   invSetMapping(NULL), invPriRespMapping(NULL), invSecRespMapping(NULL)
70 {
71   modelType = "recast";
72   supportsEstimDerivs = false; // subModel estimates derivatives by default
73 
74   // synchronize output level and grad/Hess settings with subModel
75   initialize_data_from_submodel();
76 
77   // recasting of variables; only reshape if change in variable type counts
78   bool reshape_vars = false;
79   if (variablesMapping) {
80     // reshape as dictated by variable type changes
81     reshape_vars =
82       init_variables(vars_comps_totals, all_relax_di, all_relax_dr);
83   }
84   else {
85     // variables are not mapped: deep copy of vars to allow independence, but
86     // shallow copy of svd since types/labels/ids can be kept consistent
87     currentVariables = subModel.current_variables().copy(); // shared svd
88     numDerivVars = currentVariables.cv();
89   }
90 
91   if (nonlinearRespMapping.size() !=
92       primaryRespMapIndices.size() + secondaryRespMapIndices.size()) {
93     Cerr << "Error: size mismatch in response mapping configuration." << endl;
94     abort_handler(-1);
95   }
96 
97   if (primaryRespMapping || secondaryRespMapping) {
98     init_response(primaryRespMapIndices.size(), secondaryRespMapIndices.size(),
99 		  recast_resp_order, reshape_vars);
100   }
101   else {
102     currentResponse = subModel.current_response().copy();
103     numFns = currentResponse.num_functions();
104   }
105 
106   init_constraints(secondaryRespMapIndices.size(),
107 		   recast_secondary_offset, reshape_vars);
108 
109   modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
110 }
111 
112 
113 /** This alternate constructor defers initialization of the function
114     pointers until a separate call to initialize(), and accepts the
115     minimum information needed to construct currentVariables,
116     currentResponse, and userDefinedConstraints.  The resulting model
117     is sufficiently complete for passing to an Iterator.  Parameter
118     vars_comps_totals indicates the number of each type of variable {4
119     types} x {3 domains} in the recast variable space. Note:
120     recast_secondary_offset is the start index for equality
121     constraints, typically num nonlinear ineq constraints. */
122 RecastModel::
RecastModel(const Model & sub_model,const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr,size_t num_recast_primary_fns,size_t num_recast_secondary_fns,size_t recast_secondary_offset,short recast_resp_order)123 RecastModel(const Model& sub_model, //size_t num_deriv_vars,
124 	    const SizetArray& vars_comps_totals, const BitArray& all_relax_di,
125 	    const BitArray& all_relax_dr,    size_t num_recast_primary_fns,
126 	    size_t num_recast_secondary_fns, size_t recast_secondary_offset,
127 	    short recast_resp_order):
128   Model(LightWtBaseConstructor(), sub_model.problem_description_db(),
129 	sub_model.parallel_library()),
130   subModel(sub_model), nonlinearVarsMapping(false), recastModelEvalCntr(0),
131   variablesMapping(NULL), setMapping(NULL), primaryRespMapping(NULL),
132   secondaryRespMapping(NULL), invVarsMapping(NULL), invSetMapping(NULL),
133   invPriRespMapping(NULL), invSecRespMapping(NULL)
134 {
135   modelType = "recast";
136   supportsEstimDerivs = false; // subModel estimates derivatives by default
137 
138   // synchronize output level and grad/Hess settings with subModel
139   initialize_data_from_submodel();
140 
141   // initialize Variables, Response, and Constraints based on sizes
142   init_sizes(vars_comps_totals, all_relax_di, all_relax_dr,
143 	     num_recast_primary_fns, num_recast_secondary_fns,
144 	     recast_secondary_offset, recast_resp_order);
145   modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
146 }
147 
148 
RecastModel(ProblemDescDB & problem_db,const Model & sub_model)149 RecastModel::RecastModel(ProblemDescDB& problem_db, const Model& sub_model):
150   Model(BaseConstructor(), problem_db), subModel(sub_model),
151   recastModelEvalCntr(0), variablesMapping(NULL), setMapping(NULL),
152   primaryRespMapping(NULL), secondaryRespMapping(NULL), invVarsMapping(NULL),
153   invSetMapping(NULL), invPriRespMapping(NULL), invSecRespMapping(NULL)
154 {
155   modelType = "recast";
156   supportsEstimDerivs = false; // subModel estimates derivatives by default
157 
158   // synchronize output level and grad/Hess settings with subModel
159   initialize_data_from_submodel();
160   modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
161 }
162 
163 
RecastModel(const Model & sub_model)164 RecastModel::RecastModel(const Model& sub_model):
165   Model(LightWtBaseConstructor(), sub_model.problem_description_db(),
166    	sub_model.parallel_library()),
167   subModel(sub_model), recastModelEvalCntr(0), variablesMapping(NULL),
168   setMapping(NULL), primaryRespMapping(NULL), secondaryRespMapping(NULL),
169   invVarsMapping(NULL), invSetMapping(NULL), invPriRespMapping(NULL),
170   invSecRespMapping(NULL)
171 {
172   modelType = "recast";
173   supportsEstimDerivs = false; // subModel estimates derivatives by default
174 
175   // synchronize output level and grad/Hess settings with subModel
176   initialize_data_from_submodel();
177   numFns = sub_model.response_size();
178   modelId = RecastModel::recast_model_id(root_model_id(), "RECAST");
179 }
180 
181 
182 void RecastModel::
init_sizes(const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr,size_t num_recast_primary_fns,size_t num_recast_secondary_fns,size_t recast_secondary_offset,short recast_resp_order)183 init_sizes(const SizetArray& vars_comps_totals, const BitArray& all_relax_di,
184 	   const BitArray& all_relax_dr,    size_t num_recast_primary_fns,
185 	   size_t num_recast_secondary_fns, size_t recast_secondary_offset,
186 	   short recast_resp_order)
187 {
188   // recasting of variables; only reshape if change in variable type counts
189   bool reshape_vars =
190     init_variables(vars_comps_totals, all_relax_di, all_relax_dr);
191 
192   // Currently this reshape is subspace-specific and handled in derived classes
193   //if (reshape_vars) // else full-space initialization is sufficient
194   //  init_distribution(rv_types, vars_comps_totals); // reshape mvDist
195 
196   // recasting of response and constraints
197   init_response(num_recast_primary_fns, num_recast_secondary_fns,
198 		recast_resp_order, reshape_vars);
199 
200   init_constraints(num_recast_secondary_fns,
201 		   recast_secondary_offset, reshape_vars);
202 }
203 
204 
205 /** This function is used for late initialization of the recasting
206     functions.  It is used in concert with the alternate constructor. */
207 void RecastModel::
init_maps(const Sizet2DArray & vars_map_indices,bool nonlinear_vars_mapping,void (* variables_map)(const Variables & recast_vars,Variables & sub_model_vars),void (* set_map)(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set),const Sizet2DArray & primary_resp_map_indices,const Sizet2DArray & secondary_resp_map_indices,const BoolDequeArray & nonlinear_resp_mapping,void (* primary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response),void (* secondary_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_response,Response & recast_response))208 init_maps(const Sizet2DArray& vars_map_indices,
209 	  bool nonlinear_vars_mapping,
210 	  void (*variables_map)      (const Variables& recast_vars,
211 				      Variables& sub_model_vars),
212 	  void (*set_map)            (const Variables& recast_vars,
213 				      const ActiveSet& recast_set,
214 				      ActiveSet& sub_model_set),
215 	  const Sizet2DArray& primary_resp_map_indices,
216 	  const Sizet2DArray& secondary_resp_map_indices,
217 	  const BoolDequeArray& nonlinear_resp_mapping,
218 	  void (*primary_resp_map)   (const Variables& sub_model_vars,
219 				      const Variables& recast_vars,
220 				      const Response& sub_model_response,
221 				      Response& recast_response),
222 	  void (*secondary_resp_map) (const Variables& sub_model_vars,
223 				      const Variables& recast_vars,
224 				      const Response& sub_model_response,
225 				      Response& recast_response))
226 {
227   varsMapIndices          = vars_map_indices;
228   nonlinearVarsMapping    = nonlinear_vars_mapping;
229   variablesMapping        = variables_map;
230   setMapping              = set_map;
231   primaryRespMapIndices   = primary_resp_map_indices;
232   secondaryRespMapIndices = secondary_resp_map_indices;
233   nonlinearRespMapping    = nonlinear_resp_mapping;
234   primaryRespMapping      = primary_resp_map;
235   secondaryRespMapping    = secondary_resp_map;
236 
237   if (nonlinearRespMapping.size() != primaryRespMapIndices.size() +
238       secondaryRespMapIndices.size()) {
239     Cerr << "Error: size mismatch in response mapping configuration." << endl;
240     abort_handler(-1);
241   }
242 }
243 
244 
response_order(const Model & sub_model)245 short RecastModel::response_order(const Model& sub_model)
246 {
247   const Response& curr_resp = sub_model.current_response();
248 
249   short recast_resp_order = 1; // recast resp order to be same as original resp
250   if (!curr_resp.function_gradients().empty()) recast_resp_order |= 2;
251   if (!curr_resp.function_hessians().empty())  recast_resp_order |= 4;
252 
253   return recast_resp_order;
254 }
255 
256 
recast_model_id(const String & root_id,const String & type)257 String RecastModel::recast_model_id(const String &root_id, const String &type) {
258   auto key = std::make_pair(root_id, type);
259   int id;
260   if(recastModelIdCounters.find(key) == recastModelIdCounters.end())
261     recastModelIdCounters[key] = id = 1;
262   else
263     id = ++recastModelIdCounters[key];
264   return String("RECAST_") + root_id + "_" + type + "_" + std::to_string(id);
265 }
266 
267 
268 bool RecastModel::
init_variables(const SizetArray & vars_comps_totals,const BitArray & all_relax_di,const BitArray & all_relax_dr)269 init_variables(const SizetArray& vars_comps_totals,
270 	       const BitArray& all_relax_di, const BitArray& all_relax_dr)
271 {
272   const Variables& sub_model_vars = subModel.current_variables();
273   const SharedVariablesData&  svd = sub_model_vars.shared_data();
274 
275   // BMA: We actually don't allow the case of a change in
276   // vars_comp_totals, but no mapping, but have to allow it here in
277   // case mapping not yet provided.
278 
279   // if any change in variable types, will need a new SharedVariablesData
280   bool vars_char_same =
281     ( vars_comps_totals.empty() ||
282       svd.components_totals()         == vars_comps_totals ) &&
283     ( all_relax_di.empty() ||
284       svd.all_relaxed_discrete_int()  == all_relax_di )      &&
285     ( all_relax_dr.empty() ||
286       svd.all_relaxed_discrete_real() == all_relax_dr );
287 
288   // check change in character first as mapping may not yet be present...
289   if (vars_char_same) {
290     // variables are mapped but not resized: deep copy of vars and
291     // same svd, since types may change in transformed space
292     currentVariables = sub_model_vars.copy(true); // independent svd
293   }
294   else {
295     // variables are resized; need new SVD regardless
296     SharedVariablesData recast_svd(sub_model_vars.view(), vars_comps_totals,
297 				   all_relax_di, all_relax_dr);
298     currentVariables = Variables(recast_svd);
299   }
300 
301   // propagate number of active continuous vars to derivative vars
302   numDerivVars = currentVariables.cv();
303 
304   return !vars_char_same; // return reshape_vars
305 }
306 
307 
308 void RecastModel::
init_response(size_t num_recast_primary_fns,size_t num_recast_secondary_fns,short recast_resp_order,bool reshape_vars)309 init_response(size_t num_recast_primary_fns, size_t num_recast_secondary_fns,
310 	      short recast_resp_order, bool reshape_vars)
311 {
312   numFns = num_recast_primary_fns + num_recast_secondary_fns;
313 
314   // recasting of response
315   const Response& sub_model_resp = subModel.current_response();
316   currentResponse = sub_model_resp.copy();
317 
318   bool grad_flag = (recast_resp_order & 2),
319     hess_flag = (recast_resp_order & 4),
320     sm_grad_flag = !sub_model_resp.function_gradients().empty(),
321     sm_hess_flag = !sub_model_resp.function_hessians().empty();
322   const Variables& sub_model_vars = subModel.current_variables();
323   if ( sub_model_vars.cv()            != numDerivVars ||
324        sub_model_resp.num_functions() != numFns       ||
325        grad_flag != sm_grad_flag || hess_flag != sm_hess_flag )
326     currentResponse.reshape(numFns, numDerivVars, grad_flag, hess_flag);
327 }
328 
329 
330 void RecastModel::
reshape_response(size_t num_recast_primary_fns,size_t num_recast_secondary_fns)331 reshape_response(size_t num_recast_primary_fns, size_t num_recast_secondary_fns)
332 {
333   numFns = num_recast_primary_fns + num_recast_secondary_fns;
334   bool grad_flag = !currentResponse.function_gradients().empty();
335   bool hess_flag = !currentResponse.function_hessians().empty();
336 
337   currentResponse.reshape(numFns, numDerivVars, grad_flag, hess_flag);
338 }
339 
340 
341 void RecastModel::
init_constraints(size_t num_recast_secondary_fns,size_t recast_secondary_offset,bool reshape_vars)342 init_constraints(size_t num_recast_secondary_fns,
343 		 size_t recast_secondary_offset, bool reshape_vars)
344 {
345   // recasting of constraints
346   SharedVariablesData recast_svd = currentVariables.shared_data();
347   const Constraints& sub_model_cons = subModel.user_defined_constraints();
348   userDefinedConstraints = (reshape_vars) ?
349     Constraints(recast_svd) : sub_model_cons.copy();
350 
351   // the recast_secondary_offset cannot in general be inferred from the
352   // contributing fns in secondaryRespMapIndices (recast constraints may be
353   // defined, e.g., with no contributing fns), and must therefore be passed.
354   size_t num_recast_nln_ineq = recast_secondary_offset,
355     num_recast_nln_eq = num_recast_secondary_fns - num_recast_nln_ineq;
356   if ( num_recast_nln_ineq != sub_model_cons.num_nonlinear_ineq_constraints()
357        || num_recast_nln_eq   != sub_model_cons.num_nonlinear_eq_constraints() )
358     userDefinedConstraints.reshape(num_recast_nln_ineq, num_recast_nln_eq,
359       sub_model_cons.num_linear_ineq_constraints(),
360       sub_model_cons.num_linear_eq_constraints());
361 }
362 
363 
inverse_mappings(void (* inv_vars_map)(const Variables & recast_vars,Variables & sub_model_vars),void (* inv_set_map)(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set),void (* inv_pri_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_resp,Response & recast_resp),void (* inv_sec_resp_map)(const Variables & sub_model_vars,const Variables & recast_vars,const Response & sub_model_resp,Response & recast_resp))364 void RecastModel::inverse_mappings(
365     void (*inv_vars_map)     (const Variables& recast_vars,
366 			      Variables& sub_model_vars),
367     void (*inv_set_map)      (const Variables& recast_vars,
368 			      const ActiveSet& recast_set,
369 			      ActiveSet& sub_model_set),
370     void (*inv_pri_resp_map) (const Variables& sub_model_vars,
371 			      const Variables& recast_vars,
372 			      const Response& sub_model_resp,
373 			      Response& recast_resp),
374     void (*inv_sec_resp_map) (const Variables& sub_model_vars,
375 			      const Variables& recast_vars,
376 			      const Response& sub_model_resp,
377 			      Response& recast_resp))
378 {
379   invVarsMapping    = inv_vars_map;     invSetMapping     = inv_set_map;
380   invPriRespMapping = inv_pri_resp_map; invSecRespMapping = inv_sec_resp_map;
381 }
382 
383 
384 /** The RecastModel is evaluated by an Iterator for a recast problem
385     formulation.  Therefore, the currentVariables, incoming active set,
386     and output currentResponse all correspond to the recast inputs/outputs. */
derived_evaluate(const ActiveSet & set)387 void RecastModel::derived_evaluate(const ActiveSet& set)
388 {
389   ++recastModelEvalCntr;
390 
391   // transform from recast (Iterator) to sub-model (user) variables
392   transform_variables(currentVariables, subModel.current_variables());
393 
394   // the incoming set is for the recast problem, which must be converted
395   // back to the underlying response set for evaluation by the subModel.
396   ActiveSet sub_model_set;
397   transform_set(currentVariables, set, sub_model_set);
398 
399   // evaluate the subModel in the original fn set definition.  Doing this here
400   // eliminates the need for eval tracking logic within the separate eval fns.
401   subModel.evaluate(sub_model_set);
402 
403   // recast the subModel response ("user space") into the currentResponse
404   // ("iterator space")
405   currentResponse.active_set(set);
406   if (primaryRespMapping || secondaryRespMapping)
407     transform_response(currentVariables, subModel.current_variables(),
408 		       subModel.current_response(), currentResponse);
409   else
410     currentResponse.update(subModel.current_response());
411 
412 #ifdef DEBUG
413   Cout << "Recast variables:\n"   << currentVariables
414        << "subModel variables:\n" << subModel.current_variables()
415        << "subModel response:\n"  << subModel.current_response()
416        << "Recast response:\n"    << currentResponse;
417 #endif
418 }
419 
420 
derived_evaluate_nowait(const ActiveSet & set)421 void RecastModel::derived_evaluate_nowait(const ActiveSet& set)
422 {
423   ++recastModelEvalCntr;
424 
425   // transform from recast (Iterator) to sub-model (user) variables
426   transform_variables(currentVariables, subModel.current_variables());
427 
428   // the incoming set is for the recast problem, which must be converted
429   // back to the underlying response set for evaluation by the subModel.
430   ActiveSet sub_model_set;
431   transform_set(currentVariables, set, sub_model_set);
432 
433   // evaluate the subModel in the original fn set definition.  Doing this here
434   // eliminates the need for eval tracking logic within the separate eval fns.
435   subModel.evaluate_nowait(sub_model_set);
436   // in almost all cases, use of the subModel eval ids is sufficient, but
437   // protect against the rare case where not all subModel evaluations being
438   // scheduled were spawned from the RecastModel (e.g., a HierarchicalModel
439   // that uses an ActiveSubspaceModel as LF and the original model as HF).
440   recastIdMap[subModel.evaluation_id()] = recastModelEvalCntr;
441 
442   // bookkeep variables for use in primaryRespMapping/secondaryRespMapping
443   if (primaryRespMapping || secondaryRespMapping) {
444     recastSetMap[recastModelEvalCntr]  = set;
445     recastVarsMap[recastModelEvalCntr] = currentVariables.copy();
446     if (variablesMapping)
447       subModelVarsMap[recastModelEvalCntr]
448 	= subModel.current_variables().copy();
449   }
450 }
451 
452 
derived_synchronize()453 const IntResponseMap& RecastModel::derived_synchronize()
454 {
455   recastResponseMap.clear();
456 
457   if (primaryRespMapping || secondaryRespMapping) {
458     IntResponseMap resp_map_rekey;
459     rekey_synch(subModel, true, recastIdMap, resp_map_rekey);
460     transform_response_map(resp_map_rekey, recastResponseMap);
461   }
462   else
463     rekey_synch(subModel, true, recastIdMap, recastResponseMap);
464 
465   return recastResponseMap;
466 }
467 
468 
derived_synchronize_nowait()469 const IntResponseMap& RecastModel::derived_synchronize_nowait()
470 {
471   recastResponseMap.clear();
472 
473   if (primaryRespMapping || secondaryRespMapping) {
474     IntResponseMap resp_map_rekey;
475     rekey_synch(subModel, false, recastIdMap, resp_map_rekey);
476     transform_response_map(resp_map_rekey, recastResponseMap);
477   }
478   else
479     rekey_synch(subModel, false, recastIdMap, recastResponseMap);
480 
481   return recastResponseMap;
482 }
483 
484 
485 void RecastModel::
transform_response_map(const IntResponseMap & old_resp_map,IntResponseMap & new_resp_map)486 transform_response_map(const IntResponseMap& old_resp_map,
487 		       IntResponseMap& new_resp_map)
488 {
489   IntRespMCIter r_cit; IntASMIter s_it; IntVarsMIter v_it, sm_v_it;
490   for (r_cit=old_resp_map.begin(); r_cit!=old_resp_map.end(); ++r_cit) {
491     int native_id = r_cit->first;
492     s_it =  recastSetMap.find(native_id);
493     v_it = recastVarsMap.find(native_id);
494     if (variablesMapping) sm_v_it = subModelVarsMap.find(native_id);
495     else                  sm_v_it = v_it;
496 
497     Response new_resp(currentResponse.copy()); // correct size, labels, etc.
498     new_resp.active_set(s_it->second);
499     transform_response(v_it->second, sm_v_it->second, r_cit->second, new_resp);
500     new_resp_map[native_id] = new_resp;
501 
502     // cleanup
503     recastSetMap.erase(s_it);  recastVarsMap.erase(v_it);
504     if (variablesMapping) subModelVarsMap.erase(sm_v_it);
505   }
506 }
507 
508 
509 void RecastModel::
transform_variables(const Variables & recast_vars,Variables & sub_model_vars)510 transform_variables(const Variables& recast_vars, Variables& sub_model_vars)
511 {
512   // typical flow: mapping from recast variables ("iterator space")
513   // into the sub-model variables ("user space")
514   if (variablesMapping) {
515     assign_instance();
516     variablesMapping(recast_vars, sub_model_vars);
517   }
518   else
519     sub_model_vars.active_variables(recast_vars);
520 }
521 
522 
523 void RecastModel::
inverse_transform_variables(const Variables & sub_model_vars,Variables & recast_vars)524 inverse_transform_variables(const Variables& sub_model_vars,
525 			    Variables& recast_vars)
526 {
527   // atypical flow: mapping from sub-model variables ("user space")
528   // into the recast variables ("iterator space")
529   if (invVarsMapping) {
530     assign_instance();
531     invVarsMapping(sub_model_vars, recast_vars);
532   }
533   else
534     recast_vars.active_variables(sub_model_vars);
535 }
536 
537 
538 void RecastModel::
transform_set(const Variables & recast_vars,const ActiveSet & recast_set,ActiveSet & sub_model_set)539 transform_set(const Variables& recast_vars, const ActiveSet& recast_set,
540 	      ActiveSet& sub_model_set)
541 {
542   // typical flow: mapping from recast set ("iterator space") into the
543   // sub-model set ("user space")
544 
545   size_t i, j, num_recast_primary_fns = primaryRespMapIndices.size(),
546     num_recast_secondary_fns = secondaryRespMapIndices.size(),
547     num_recast_fns = num_recast_primary_fns + num_recast_secondary_fns;
548   const ShortArray& recast_asv = recast_set.request_vector();
549   if (recast_asv.size() != num_recast_fns) {
550     Cerr << "Error: inconsistent asv sizing in RecastModel::transform_set().\n"
551 	 << "       recast asv size = " << recast_asv.size() << '\n'
552 	 << "       recast functions = " << num_recast_fns << endl;
553     abort_handler(-1);
554   }
555 
556   // Define default request vector and derivative vector mappings:
557   // For the ASV, project each recast_asv request onto the contributing
558   // set of functions within the sub_model_asv.  In the case of nonlinear
559   // input/output mappings, the recast_asv request is augmented with
560   // additional data requirements derived from chain rule differentiation.
561   // The default sub-model DVV is just a copy of the recast DVV.
562   ShortArray sub_model_asv(subModel.response_size(), 0);
563   for (i=0; i<num_recast_fns; i++) {
564     short asv_val = recast_asv[i];
565     // For nonlinear variable mappings, gradient required to transform Hessian.
566     // A single nonlinear variable mapping affects all function derivatives.
567     if (nonlinearVarsMapping && (asv_val & 4))
568       asv_val |= 2;
569     // assign the asv_val to each contributing sub-model function
570     const SizetArray& recast_fn_contributors = (i<num_recast_primary_fns) ?
571       primaryRespMapIndices[i] :
572       secondaryRespMapIndices[i-num_recast_primary_fns];
573     size_t num_contributors = recast_fn_contributors.size();
574     for (j=0; j<num_contributors; j++) {
575       short sub_model_asv_val = asv_val;
576       // Bit deletions: for NLS recasting for full Newton without LeastSq term
577       // Hessians, could remove 4 bit based on {gradient,hessian}Type, but this
578       // is better accomplished from an Iterator's configuration using the
579       // setMapping plug-in below (e.g., see Optimizer::gnewton_set_recast()).
580 
581       // Bit additions: for nonlinear resp mappings, derivatives require all
582       // lower order data. The nonlinearity of each fn contribution is employed.
583       if (nonlinearRespMapping[i][j]) {
584 	if (asv_val & 4)
585 	  sub_model_asv_val |= 3;
586 	else if (asv_val & 2)
587 	  sub_model_asv_val |= 1;
588       }
589       sub_model_asv[recast_fn_contributors[j]] |= sub_model_asv_val;
590     }
591   }
592   sub_model_set.request_vector(sub_model_asv);
593   sub_model_set.derivative_vector(recast_set.derivative_vector()); // copy
594 
595   // a setMapping (provided in the RecastModel ctor or initialize()) augments
596   // the standard mappings.  Current examples include NonD::set_u_to_x_mapping,
597   // NonDReliability::PMA2_set_mapping, and Optimizer::gauss_newton_set_recast.
598   // This follows the standard mappings so that provided mappings don't get
599   // overwritten by the standard logic.  However, this means that any provided
600   // additions will not be automatically augmented by nonlinear mapping logic
601   // above.  This should not be a significant problem, since the provided
602   // additions have case-specific context whereas the logic above is generic.
603   // It would be preferable if provided mappings focused on updating the
604   // sub_model_set rather than generating it from recast_set.
605   if (setMapping) {
606     assign_instance();
607     setMapping(recast_vars, recast_set, sub_model_set);
608   }
609 }
610 
611 
612 void RecastModel::
inverse_transform_set(const Variables & sub_model_vars,const ActiveSet & sub_model_set,ActiveSet & recast_set)613 inverse_transform_set(const Variables& sub_model_vars,
614 		      const ActiveSet& sub_model_set, ActiveSet& recast_set)
615 {
616   // atypical flow: mapping from sub-model set ("user space") into the
617   // recast set ("iterator space")
618 
619   /* TO DO: modify mapping below from forward to inverse
620 
621   size_t i, j, num_recast_primary_fns = primaryRespMapIndices.size(),
622     num_recast_secondary_fns = secondaryRespMapIndices.size(),
623     num_recast_fns = num_recast_primary_fns + num_recast_secondary_fns;
624   const ShortArray& recast_asv = recast_set.request_vector();
625   if (recast_asv.size() != num_recast_fns) {
626     Cerr << "Error: inconsistent asv sizing in RecastModel::"
627          << "inverse_transform_set()." << std::endl;
628     abort_handler(-1);
629   }
630 
631   // Define default request vector and derivative vector mappings:
632   // For the ASV, project each recast_asv request onto the contributing
633   // set of functions within the sub_model_asv.  In the case of nonlinear
634   // input/output mappings, the recast_asv request is augmented with
635   // additional data requirements derived from chain rule differentiation.
636   // The default sub-model DVV is just a copy of the recast DVV.
637   ShortArray sub_model_asv(subModel.response_size(), 0);
638   for (i=0; i<num_recast_fns; i++) {
639     short asv_val = recast_asv[i];
640     // For nonlinear variable mappings, gradient required to transform Hessian.
641     // A single nonlinear variable mapping affects all function derivatives.
642     if (nonlinearVarsMapping && (asv_val & 4))
643       asv_val |= 2;
644     // assign the asv_val to each contributing sub-model function
645     const SizetArray& recast_fn_contributors = (i<num_recast_primary_fns) ?
646       primaryRespMapIndices[i] :
647       secondaryRespMapIndices[i-num_recast_primary_fns];
648     size_t num_contributors = recast_fn_contributors.size();
649     for (j=0; j<num_contributors; j++) {
650       short sub_model_asv_val = asv_val;
651       // Bit deletions: for NLS recasting for full Newton without LeastSq term
652       // Hessians, could remove 4 bit based on {gradient,hessian}Type, but this
653       // is better accomplished from an Iterator's configuration using the
654       // setMapping plug-in below (e.g., see Optimizer::gnewton_set_recast()).
655 
656       // Bit additions: for nonlinear resp mappings, derivatives require all
657       // lower order data. The nonlinearity of each fn contribution is employed.
658       if (nonlinearRespMapping[i][j]) {
659 	if (asv_val & 4)
660 	  sub_model_asv_val |= 3;
661 	else if (asv_val & 2)
662 	  sub_model_asv_val |= 1;
663       }
664       sub_model_asv[recast_fn_contributors[j]] |= sub_model_asv_val;
665     }
666   }
667   sub_model_set.request_vector(sub_model_asv);
668   sub_model_set.derivative_vector(recast_set.derivative_vector()); // copy
669   */
670 
671   // an invSetMapping (provided in inverse_mappings()) augments the standard
672   // mappings above, such that the provided mappings don't get overwritten by
673   // the standard logic.
674   if (invSetMapping) {
675     assign_instance();
676     invSetMapping(sub_model_vars, sub_model_set, recast_set);
677   }
678 }
679 
680 
681 void RecastModel::
transform_response(const Variables & recast_vars,const Variables & sub_model_vars,const Response & sub_model_resp,Response & recast_resp)682 transform_response(const Variables& recast_vars,
683 		   const Variables& sub_model_vars,
684 		   const Response& sub_model_resp, Response& recast_resp)
685 {
686   // typical flow: mapping from sub-model response ("user space") into
687   // the recast response ("iterator space")
688 
689   size_t num_recast_1_fns = primaryRespMapIndices.size();
690 
691   if (primaryRespMapping || secondaryRespMapping)
692     assign_instance();
693 
694   if (primaryRespMapping)
695     primaryRespMapping(sub_model_vars, recast_vars,
696 		       sub_model_resp, recast_resp);
697   else // number of recast primary = number of sub-model primary
698     recast_resp.update_partial(0, num_recast_1_fns, sub_model_resp, 0);
699 
700   if (secondaryRespMapping)
701     secondaryRespMapping(sub_model_vars, recast_vars,
702 			 sub_model_resp, recast_resp);
703   else {
704     // number of recast secondary = number of sub-model secondary,
705     // but primary offsets may differ
706     size_t num_recast_2_fns = secondaryRespMapIndices.size(),
707            num_sm_1_fns     = sub_model_resp.num_functions() - num_recast_2_fns;
708     recast_resp.update_partial(num_recast_1_fns, num_recast_2_fns,
709 			       sub_model_resp, num_sm_1_fns);
710   }
711 }
712 
713 
714 void RecastModel::
inverse_transform_response(const Variables & sub_model_vars,const Variables & recast_vars,const Response & recast_resp,Response & sub_model_resp)715 inverse_transform_response(const Variables& sub_model_vars,
716 			   const Variables& recast_vars,
717 			   const Response& recast_resp,
718 			   Response& sub_model_resp)
719 {
720   // atypical flow: mapping from the recast response ("iterator space")
721   // into the sub-model response ("user space")
722 
723   size_t num_recast_1_fns = primaryRespMapIndices.size();
724 
725   if (invPriRespMapping || invSecRespMapping)
726     assign_instance();
727 
728   if (invPriRespMapping)
729     invPriRespMapping(recast_vars, sub_model_vars, recast_resp, sub_model_resp);
730   else // number of recast primary = number of sub-model primary
731     sub_model_resp.update_partial(0, num_recast_1_fns, recast_resp, 0);
732 
733   if (invSecRespMapping)
734     invSecRespMapping(recast_vars, sub_model_vars, recast_resp, sub_model_resp);
735   else {
736     // number of recast secondary = number of sub-model secondary,
737     // but primary offsets may differ
738     size_t num_recast_2_fns = secondaryRespMapIndices.size(),
739            num_sm_1_fns     = sub_model_resp.num_functions() - num_recast_2_fns;
740     sub_model_resp.update_partial(num_sm_1_fns, num_recast_2_fns,
741 				  recast_resp, num_recast_1_fns);
742   }
743 }
744 
745 
initialize_data_from_submodel()746 void RecastModel::initialize_data_from_submodel()
747 {
748   componentParallelMode = SUB_MODEL_MODE;
749   outputLevel           = subModel.output_level();
750 
751   gradientType          = subModel.gradient_type();
752   methodSource          = subModel.method_source();
753   ignoreBounds          = subModel.ignore_bounds();
754   centralHess	        = subModel.central_hess();
755   intervalType          = subModel.interval_type();
756   fdGradStepSize        = subModel.fd_gradient_step_size();
757   fdGradStepType        = subModel.fd_gradient_step_type();
758   gradIdAnalytic        = subModel.gradient_id_analytic();
759   gradIdNumerical       = subModel.gradient_id_numerical();
760 
761   hessianType           = subModel.hessian_type();
762   quasiHessType         = subModel.quasi_hessian_type();
763   fdHessByFnStepSize    = subModel.fd_hessian_by_fn_step_size();
764   fdHessByGradStepSize  = subModel.fd_hessian_by_grad_step_size();
765   fdHessStepType        = subModel.fd_hessian_step_type();
766   hessIdAnalytic        = subModel.hessian_id_analytic();
767   hessIdNumerical       = subModel.hessian_id_numerical();
768   hessIdQuasi           = subModel.hessian_id_quasi();
769 
770   scalingOpts           = subModel.scaling_options();
771 }
772 
773 
774 /** Update inactive values and labels in currentVariables and inactive
775     bound constraints in userDefinedConstraints from variables and
776     constraints data within subModel. */
update_from_model(Model & model)777 void RecastModel::update_from_model(Model& model)
778 {
779   // break up into pieces so that derived Recasts can override with subsets
780 
781   bool update_active_complement = update_variables_from_model(model);
782 
783   if (update_active_complement)
784     update_variables_active_complement_from_model(model);
785 
786   update_response_from_model(model);
787 }
788 
789 
update_variables_from_model(Model & model)790 bool RecastModel::update_variables_from_model(Model& model)
791 {
792   bool update_active_complement = true;
793   if (invVarsMapping) { // inv mapping provided: sub-model -> recast
794     assign_instance();
795 
796     // generally restricted to active variables
797     invVarsMapping(model.current_variables(), currentVariables);
798 
799     // BMA TODO: there may be cases where we also want to update the
800     // constraints and values, but there's currently no mechanism to
801     // do so.  The client of a RecastModel must manage this.
802   }
803   else if (variablesMapping) { // only fwd mapping for recast -> sub-model
804     // no reasonable default for active vars
805 
806     // can't just apply variables mapping to values/bounds, since need inverse
807     // of variablesMapping to go from model vars to currentVariables
808 
809     // any label, uncertain variable distributions, and linear
810     // constraint mappings must be performed explicitly
811 
812     // for partial mapping of variables that are unmodified by a variable
813     // transformation, see NonDExpansion::initialize_expansion()
814 
815     // for mapping of distribution parameters that are part of a variable
816     // transformation, see ProbabilityTransformModel::update_transformation()
817   }
818   else {
819     update_active_complement = false; // can use all view updates below
820 
821     // variable values
822     currentVariables.all_continuous_variables(
823       model.all_continuous_variables());
824     currentVariables.all_discrete_int_variables(
825       model.all_discrete_int_variables());
826     currentVariables.all_discrete_string_variables(
827       model.all_discrete_string_variables());
828     currentVariables.all_discrete_real_variables(
829       model.all_discrete_real_variables());
830     // variable bounds
831     userDefinedConstraints.all_continuous_lower_bounds(
832       model.all_continuous_lower_bounds());
833     userDefinedConstraints.all_continuous_upper_bounds(
834       model.all_continuous_upper_bounds());
835     userDefinedConstraints.all_discrete_int_lower_bounds(
836       model.all_discrete_int_lower_bounds());
837     userDefinedConstraints.all_discrete_int_upper_bounds(
838       model.all_discrete_int_upper_bounds());
839     userDefinedConstraints.all_discrete_real_lower_bounds(
840       model.all_discrete_real_lower_bounds());
841     userDefinedConstraints.all_discrete_real_upper_bounds(
842       model.all_discrete_real_upper_bounds());
843     // variable labels
844     currentVariables.all_continuous_variable_labels(
845       model.all_continuous_variable_labels());
846     currentVariables.all_discrete_int_variable_labels(
847       model.all_discrete_int_variable_labels());
848     currentVariables.all_discrete_string_variable_labels(
849       model.all_discrete_string_variable_labels());
850     currentVariables.all_discrete_real_variable_labels(
851       model.all_discrete_real_variable_labels());
852 
853     // uncertain variable distribution data
854     // > deep copies were used previously for Pecos::DistributionParams
855     //mvDist.update(model.multivariate_distribution());
856     // Current approach: rep is shared
857     // > tramples an mvDist construction from Model(BaseConstructor) ....
858     // > populates mvDist for Model(LightWtBaseConstructor)
859     // > reassignments protected by smart ptr management
860     // Note: becomes less important w/ broader use of ProbabilityTransformModel
861     mvDist = subModel.multivariate_distribution(); // shared rep
862 
863     // linear constraints
864     if (model.num_linear_ineq_constraints()) {
865       userDefinedConstraints.linear_ineq_constraint_coeffs(
866         model.linear_ineq_constraint_coeffs());
867       userDefinedConstraints.linear_ineq_constraint_lower_bounds(
868         model.linear_ineq_constraint_lower_bounds());
869       userDefinedConstraints.linear_ineq_constraint_upper_bounds(
870         model.linear_ineq_constraint_upper_bounds());
871     }
872     if (model.num_linear_eq_constraints()) {
873       userDefinedConstraints.linear_eq_constraint_coeffs(
874         model.linear_eq_constraint_coeffs());
875       userDefinedConstraints.linear_eq_constraint_targets(
876         model.linear_eq_constraint_targets());
877     }
878   }
879 
880   return update_active_complement;
881 }
882 
883 
update_variables_active_complement_from_model(Model & model)884 void RecastModel::update_variables_active_complement_from_model(Model& model)
885 {
886   size_t i, cv_begin = currentVariables.cv_start(),
887     num_cv  = currentVariables.cv(), cv_end = cv_begin + num_cv,
888     num_acv = currentVariables.acv();
889   const RealVector& acv = model.all_continuous_variables();
890   const RealVector& acv_l_bnds = model.all_continuous_lower_bounds();
891   const RealVector& acv_u_bnds = model.all_continuous_upper_bounds();
892   StringMultiArrayConstView acv_labels
893     = model.all_continuous_variable_labels();
894   for (i=0; i<cv_begin; ++i) {
895     currentVariables.all_continuous_variable(acv[i], i);
896     userDefinedConstraints.all_continuous_lower_bound(acv_l_bnds[i], i);
897     userDefinedConstraints.all_continuous_upper_bound(acv_u_bnds[i], i);
898     currentVariables.all_continuous_variable_label(acv_labels[i], i);
899   }
900   for (i=cv_end; i<num_acv; ++i) {
901     currentVariables.all_continuous_variable(acv[i], i);
902     userDefinedConstraints.all_continuous_lower_bound(acv_l_bnds[i], i);
903     userDefinedConstraints.all_continuous_upper_bound(acv_u_bnds[i], i);
904     currentVariables.all_continuous_variable_label(acv_labels[i], i);
905   }
906 
907   size_t div_begin = currentVariables.div_start(),
908     num_div  = currentVariables.div(), div_end = div_begin + num_div,
909     num_adiv = currentVariables.adiv();
910   const IntVector& adiv = model.all_discrete_int_variables();
911   const IntVector& adiv_l_bnds = model.all_discrete_int_lower_bounds();
912   const IntVector& adiv_u_bnds = model.all_discrete_int_upper_bounds();
913   StringMultiArrayConstView adiv_labels
914     = model.all_discrete_int_variable_labels();
915   for (i=0; i<div_begin; ++i) {
916     currentVariables.all_discrete_int_variable(adiv[i], i);
917     userDefinedConstraints.all_discrete_int_lower_bound(adiv_l_bnds[i], i);
918     userDefinedConstraints.all_discrete_int_upper_bound(adiv_u_bnds[i], i);
919     currentVariables.all_discrete_int_variable_label(adiv_labels[i], i);
920   }
921   for (i=div_end; i<num_adiv; ++i) {
922     currentVariables.all_discrete_int_variable(adiv[i], i);
923     userDefinedConstraints.all_discrete_int_lower_bound(adiv_l_bnds[i], i);
924     userDefinedConstraints.all_discrete_int_upper_bound(adiv_u_bnds[i], i);
925     currentVariables.all_discrete_int_variable_label(adiv_labels[i], i);
926   }
927 
928   size_t dsv_begin = currentVariables.dsv_start(),
929     num_dsv  = currentVariables.dsv(), dsv_end = dsv_begin + num_dsv,
930     num_adsv = currentVariables.adsv();
931   StringMultiArrayConstView adsv = model.all_discrete_string_variables();
932   StringMultiArrayConstView adsv_labels
933     = model.all_discrete_string_variable_labels();
934   for (i=0; i<dsv_begin; ++i) {
935     currentVariables.all_discrete_string_variable(adsv[i], i);
936     currentVariables.all_discrete_string_variable_label(adsv_labels[i], i);
937   }
938   for (i=dsv_end; i<num_adsv; ++i) {
939     currentVariables.all_discrete_string_variable(adsv[i], i);
940     currentVariables.all_discrete_string_variable_label(adsv_labels[i], i);
941   }
942 
943   size_t drv_begin = currentVariables.drv_start(),
944     num_drv  = currentVariables.drv(), drv_end = drv_begin + num_drv,
945     num_adrv = currentVariables.adrv();
946   const RealVector& adrv = model.all_discrete_real_variables();
947   const RealVector& adrv_l_bnds = model.all_discrete_real_lower_bounds();
948   const RealVector& adrv_u_bnds = model.all_discrete_real_upper_bounds();
949   StringMultiArrayConstView adrv_labels
950     = model.all_discrete_real_variable_labels();
951   for (i=0; i<drv_begin; ++i) {
952     currentVariables.all_discrete_real_variable(adrv[i], i);
953     userDefinedConstraints.all_discrete_real_lower_bound(adrv_l_bnds[i], i);
954     userDefinedConstraints.all_discrete_real_upper_bound(adrv_u_bnds[i], i);
955     currentVariables.all_discrete_real_variable_label(adrv_labels[i], i);
956   }
957   for (i=drv_end; i<num_adrv; ++i) {
958     currentVariables.all_discrete_real_variable(adrv[i], i);
959     userDefinedConstraints.all_discrete_real_lower_bound(adrv_l_bnds[i], i);
960     userDefinedConstraints.all_discrete_real_upper_bound(adrv_u_bnds[i], i);
961     currentVariables.all_discrete_real_variable_label(adrv_labels[i], i);
962   }
963 }
964 
965 
update_response_from_model(Model & model)966 void RecastModel::update_response_from_model(Model& model)
967 {
968   if (primaryRespMapping) {
969     // response mappings are in opposite direction from variables
970     // mappings, so primaryRespMapping could potentially be used to
971     // update currentResponse from model primary fns
972   }
973   else {
974     // primary response function weights
975     primaryRespFnWts = model.primary_response_fn_weights();
976     // primary response function sense (min or max)
977     primaryRespFnSense = model.primary_response_fn_sense();
978 
979     // primary response function labels
980     const StringArray& sm_resp_labels = model.response_labels();
981     size_t i, num_primary = numFns
982       - userDefinedConstraints.num_nonlinear_eq_constraints()
983       - userDefinedConstraints.num_nonlinear_ineq_constraints();
984     for (i=0; i<num_primary; i++)
985       currentResponse.shared_data().function_label(sm_resp_labels[i], i);
986   }
987 
988   if (secondaryRespMapping) {
989     // response mappings are in opposite direction from variables
990     // mappings, so secondaryRespMapping could potentially be used to
991     // update currentResponse from model secondary fns
992   }
993   else {
994     // secondary response function labels
995     const StringArray& sm_resp_labels = model.response_labels();
996     size_t i,
997       num_nln_con = userDefinedConstraints.num_nonlinear_eq_constraints() +
998         userDefinedConstraints.num_nonlinear_ineq_constraints(),
999       num_primary    = numFns - num_nln_con,
1000       num_sm_primary = model.response_size() - num_nln_con;
1001     for (i=0; i<num_nln_con; i++)
1002       currentResponse.shared_data().function_label(
1003 	sm_resp_labels[num_sm_primary+i], num_primary+i);
1004 
1005     // nonlinear constraint bounds/targets
1006     if (model.num_nonlinear_ineq_constraints()) {
1007       userDefinedConstraints.nonlinear_ineq_constraint_lower_bounds(
1008         model.nonlinear_ineq_constraint_lower_bounds());
1009       userDefinedConstraints.nonlinear_ineq_constraint_upper_bounds(
1010         model.nonlinear_ineq_constraint_upper_bounds());
1011     }
1012     if (model.num_nonlinear_eq_constraints())
1013       userDefinedConstraints.nonlinear_eq_constraint_targets(
1014         model.nonlinear_eq_constraint_targets());
1015   }
1016 }
1017 
1018 
error_estimates()1019 const RealVector& RecastModel::error_estimates()
1020 {
1021   // linear mappings are fine (see NestedModel), but general nonlinear mappings
1022   // are problematic.
1023   if (primaryRespMapping || secondaryRespMapping) {
1024 
1025     // preclude nonlinear mappings and multi-component mappings for now.
1026     // Note: a linear multi-component mapping can be supported by NestedModel::
1027     //       iterator_error_estimation(), because the mapping coeffs are known.
1028 
1029     size_t i, num_recast_fns = nonlinearRespMapping.size();
1030     for (i=0; i<num_recast_fns; ++i) {
1031       const BoolDeque& nln_resp_map_i = nonlinearRespMapping[i];
1032       if (nln_resp_map_i.size() > 1 ||
1033 	  std::find(nln_resp_map_i.begin(), nln_resp_map_i.end(), true) !=
1034 	            nln_resp_map_i.end()) {
1035 	Cerr << "Error: error estimation not currently supported for Recast"
1036 	     << "Model with nonlinear or multi-component response mapping."
1037 	     << std::endl;
1038 	abort_handler(MODEL_ERROR);
1039       }
1040     }
1041 
1042     // push errors through linear single-component mapping (individual scaling)
1043 
1044     // make dummy responses for use with transform_response()
1045     const Response& sm_resp = subModel.current_response();
1046     ActiveSet sm_set = sm_resp.active_set(),
1047           recast_set = currentResponse.active_set();
1048     sm_set.request_values(1); recast_set.request_values(1);
1049     Response sm_error_est(sm_resp.shared_data(), sm_set),
1050          recast_error_est(currentResponse.shared_data(), recast_set);
1051     // transform the error estimates as Response::functionValues
1052     sm_error_est.function_values(subModel.error_estimates());
1053     if (outputLevel >= DEBUG_OUTPUT) // distinguish ScalingModel debug blocks
1054       Cout << "Transforming Error Estimates:\n";
1055     transform_response(currentVariables, subModel.current_variables(),
1056 		       sm_error_est, recast_error_est);
1057     mappedErrorEstimates = recast_error_est.function_values();
1058     return mappedErrorEstimates;
1059   }
1060   else
1061     return subModel.error_estimates();
1062 }
1063 
1064 
resize_response_mapping()1065 void RecastModel::resize_response_mapping()
1066 {
1067   // reshaping primaryRespMapIndices, secondaryRespMapIndices
1068   size_t num_curr_fns       = response_size(),
1069          num_curr_secondary = num_secondary_fns(),
1070          num_curr_primary   = num_curr_fns - num_curr_secondary,
1071          num_sm_fns         = subModel.response_size(),
1072          num_sm_secondary   = subModel.num_secondary_fns(),
1073          num_sm_primary     = num_sm_fns - num_sm_secondary,
1074          num_replicates, num_ind, offset, i, j, k;
1075 
1076   primaryRespMapIndices.resize(num_sm_primary);
1077   secondaryRespMapIndices.resize(num_sm_secondary);
1078   nonlinearRespMapping.resize(num_sm_fns);
1079 
1080   // the number of mappings to replicate corresponds to the number
1081   // of data sets being aggregated in, e.g., AGGREGATED_MODELS mode
1082 
1083   if (num_sm_primary > num_curr_primary) { // inflate existing mappings
1084     num_replicates = num_sm_primary / num_curr_primary;
1085     if (num_sm_primary % num_curr_primary) {
1086       Cerr << "Error: non-integer multiplier for response aggregation in "
1087 	   << "RecastModel::resize_response_mapping()" << std::endl;
1088       abort_handler(MODEL_ERROR);
1089     }
1090     for (i=0; i<num_curr_primary; ++i) {
1091       // mirror pattern within new response indices, but offset index mapping
1092       SizetArray& primary_ind_i = primaryRespMapIndices[i];
1093       num_ind = primary_ind_i.size();
1094       for (j=1; j<num_replicates; ++j) {
1095 	offset = j * num_curr_primary;
1096 	SizetArray& primary_ind_j = primaryRespMapIndices[i + offset];
1097 	primary_ind_j.resize(num_ind);
1098 	for (k=0; k<num_ind; ++k)
1099 	  primary_ind_j[k] = primary_ind_i[k] + offset;
1100       }
1101     }
1102   }
1103   if (num_sm_secondary > num_curr_secondary) { // inflate existing mappings
1104     num_replicates = num_sm_secondary / num_curr_secondary;
1105     if (num_sm_secondary % num_curr_secondary) {
1106       Cerr << "Error: non-integer multiplier for response aggregation in "
1107 	   << "RecastModel::resize_response_mapping()" << std::endl;
1108       abort_handler(MODEL_ERROR);
1109     }
1110     for (i=0; i<num_curr_secondary; ++i) {
1111       // mirror pattern within new response indices, but offset index mapping
1112       SizetArray& secondary_ind_i = secondaryRespMapIndices[i];
1113       num_ind = secondary_ind_i.size();
1114       for (j=1; j<num_replicates; ++j) {
1115 	offset = j * num_curr_secondary;
1116 	SizetArray& secondary_ind_j = secondaryRespMapIndices[i + offset];
1117 	secondary_ind_j.resize(num_ind);
1118 	for (k=0; k<num_ind; ++k)
1119 	  secondary_ind_j[k]   = secondary_ind_i[k] + offset;
1120       }
1121     }
1122   }
1123   if (num_sm_fns > num_curr_fns) { // inflate existing mappings
1124     num_replicates = num_sm_fns / num_curr_fns;
1125     if (num_sm_fns % num_curr_fns) {
1126       Cerr << "Error: non-integer multiplier for response aggregation in "
1127 	   << "RecastModel::resize_response_mapping()" << std::endl;
1128       abort_handler(MODEL_ERROR);
1129     }
1130     for (i=0; i<num_curr_fns; ++i) {
1131       // mirror pattern within new response indices, but offset index mapping
1132       BoolDeque& nonlin_resp_map_i = nonlinearRespMapping[i];
1133       for (j=1; j<num_replicates; ++j)
1134 	nonlinearRespMapping[i + j * num_curr_fns] = nonlin_resp_map_i;
1135     }
1136   }
1137 }
1138 
1139 
1140 bool RecastModel::
db_lookup(const Variables & search_vars,const ActiveSet & search_set,Response & found_resp)1141 db_lookup(const Variables& search_vars, const ActiveSet& search_set,
1142 	  Response& found_resp)
1143 {
1144   // transform from recast (Iterator) to sub-model (user) variables;
1145   // making copy to avoid modifying submodel state during the lookup
1146   Variables sub_model_vars(subModel.current_variables().copy());
1147   transform_variables(search_vars, sub_model_vars);
1148 
1149   // the incoming set is for the recast problem, which must be converted
1150   // back to the underlying response set for evaluation by the subModel.
1151   ActiveSet sub_model_set;
1152   transform_set(search_vars, search_set, sub_model_set);
1153 
1154   // invoke submodel lookup; making copy to avoid modifying submodel state
1155   // during the lookup
1156   Response sub_model_resp(subModel.current_response().copy());
1157   // sub_model_resp must have right ASV so lookup's update will pull right data
1158   sub_model_resp.active_set(sub_model_set);
1159   bool eval_found
1160     = subModel.db_lookup(sub_model_vars, sub_model_set, sub_model_resp);
1161   if (!eval_found)
1162     return false;
1163 
1164   // recast the subModel response ("user space") into the "iterator space"
1165   found_resp.active_set(search_set);
1166   if (primaryRespMapping || secondaryRespMapping)
1167     transform_response(search_vars, sub_model_vars, sub_model_resp, found_resp);
1168   else
1169     found_resp.update(sub_model_resp);
1170 
1171   return eval_found;
1172 }
1173 
1174 
assign_instance()1175 void RecastModel::assign_instance()
1176 { } // no static instance pointer to assign at base (default is no-op)
1177 
1178 
root_model_id()1179 String RecastModel::root_model_id() {
1180   return subModel.root_model_id();
1181 }
1182 
1183 
default_active_set()1184 ActiveSet RecastModel::default_active_set() {
1185   // The "base class" implementation assumes that supportsEstimDerivs is false
1186   // and that gradients/hessians, if available, are computed by a submodel and
1187   // hence can be provided by this model.
1188   ActiveSet set;
1189   set.derivative_vector(currentVariables.all_continuous_variable_ids());
1190   bool has_deriv_vars = set.derivative_vector().size() != 0;
1191   ShortArray asv(numFns, 1);
1192   if(has_deriv_vars) {
1193     if(gradientType != "none")// && (gradientType == "analytic" || supportsEstimDerivs))
1194         for(auto &a : asv)
1195           a |=  2;
1196 
1197     if(hessianType != "none") // && (hessianType == "analytic" || supportsEstimDerivs))
1198         for(auto &a : asv)
1199           a |=  4;
1200   }
1201   set.request_vector(asv);
1202   return set;
1203 }
1204 
1205 
declare_sources()1206 void RecastModel::declare_sources() {
1207   evaluationsDB.declare_source(modelId, modelType, subModel.model_id(), subModel.model_type());
1208 }
1209 
1210 } // namespace Dakota
1211