1 /*  _______________________________________________________________________
2     DAKOTA: Design Analysis Kit for Optimization and Terascale Applications
3     Copyright 2014-2020 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
4     This software is distributed under the GNU Lesser General Public License.
5     For more information, see the README file in the top Dakota directory.
6     _______________________________________________________________________ */
7 
8 //- Class:        Optimizer
9 //- Description:  Abstract base class to logically represent a variety
10 //-               of DAKOTA optimizer objects in a generic fashion.
11 //- Owner:        Mike Eldred
12 //- Version: $Id: DakotaOptimizer.hpp 7018 2010-10-12 02:25:22Z mseldre $
13 
14 #ifndef DAKOTA_OPTIMIZER_H
15 #define DAKOTA_OPTIMIZER_H
16 
17 #include "DakotaMinimizer.hpp"
18 
19 namespace Dakota {
20 
21 /** Adapter for copying initial continuous variables values from a Dakota Model
22    into TPL vectors */
23 
24 template <typename VecT>
get_initial_values(const Model & model,VecT & values)25 void get_initial_values( const Model & model,
26                                VecT  & values)
27 {
28   const RealVector& initial_points = model.continuous_variables();
29 
30   for(int i=0; i<model.cv(); ++i)
31     values[i] = initial_points[i];
32 }
33 
34 /** Adapter for copying continuous variables data from Dakota RealVector
35    into TPL vectors */
36 
37 //PDH: At some point, need to get rid of big_real_bound_size.  Was no_value
38 //specific to APPS?  I think it was.  If so, we should look at how general
39 //that is across the other TPLs.  It might make more sense to push it back
40 //down to APPS.
41 
42 template <typename VecT>
get_bounds(const RealVector & lower_source,const RealVector & upper_source,VecT & lower_target,VecT & upper_target,Real big_real_bound_size,Real no_value)43 bool get_bounds( const RealVector  & lower_source,
44                  const RealVector  & upper_source,
45                        VecT        & lower_target,
46                        VecT        & upper_target,
47                        Real          big_real_bound_size,
48                        Real          no_value)
49 {
50   bool allSet = true;
51 
52   int len = lower_source.length();
53   for (int i=0; i<len; i++) {
54     if (lower_source[i] > -big_real_bound_size)
55       lower_target[i] = lower_source[i];
56     else {
57       lower_target[i] = no_value;
58       allSet = false;
59     }
60     if (upper_source[i] < big_real_bound_size)
61       upper_target[i] = upper_source[i];
62     else {
63       upper_target[i] = no_value;
64       allSet = false;
65     }
66   }
67 
68   return allSet;
69 }
70 
71 /** Adapter for copying continuous variables data from a Dakota Model
72    into TPL vectors */
73 
74 template <typename VecT>
get_bounds(const Model & model,VecT & lower_target,VecT & upper_target)75 void get_bounds( const Model & model,
76                        VecT  & lower_target,
77                        VecT  & upper_target)
78 {
79   const RealVector& c_l_bnds = model.continuous_lower_bounds();
80   const RealVector& c_u_bnds = model.continuous_upper_bounds();
81 
82   for( int i=0; i<c_l_bnds.length(); ++i )
83   {
84     lower_target[i] = c_l_bnds[i];
85     upper_target[i] = c_u_bnds[i];
86   }
87 }
88 
89 /** Adapter originating from (and somewhat specialized based on)
90    APPSOptimizer for copying discrete variables from a set-based Dakota
91    container into TPL vectors */
92 
93 //PDH: I think the target_offset can be eliminated from the argument list
94 //by using a trait specifying expected order.
95 
96 template <typename SetT, typename VecT>
get_bounds(const SetT & source_set,VecT & lower_target,VecT & upper_target,int target_offset)97 void get_bounds( const SetT & source_set,
98                        VecT & lower_target,
99                        VecT & upper_target,
100                        int    target_offset)
101 {
102   for (size_t i=0; i<source_set.size(); ++i) {
103     lower_target[i+target_offset] = 0;
104     upper_target[i+target_offset] = source_set[i].size() - 1;
105   }
106 }
107 
108 /** Adapter originating from (and somewhat specialized based on)
109    APPSOptimizer for copying discrete integer variables data
110    with bit masking from Dakota into TPL vectors */
111 
112 //PDH: Same comments as above for bigBoundSize, no_value, target_offset.
113 
114 template <typename OrdinalType, typename ScalarType, typename VectorType2, typename MaskType, typename SetArray>
get_mixed_bounds(const MaskType & mask_set,const SetArray & source_set,const Teuchos::SerialDenseVector<OrdinalType,ScalarType> & lower_source,const Teuchos::SerialDenseVector<OrdinalType,ScalarType> & upper_source,VectorType2 & lower_target,VectorType2 & upper_target,ScalarType bigBoundSize,ScalarType no_value,int target_offset=0)115 bool get_mixed_bounds( const MaskType& mask_set,
116                        const SetArray& source_set,
117                        const Teuchos::SerialDenseVector<OrdinalType, ScalarType>& lower_source,
118                        const Teuchos::SerialDenseVector<OrdinalType, ScalarType>& upper_source,
119                        VectorType2& lower_target,
120                        VectorType2& upper_target,
121                        ScalarType bigBoundSize,
122                        ScalarType no_value,
123                        int target_offset = 0)
124 {
125   bool allSet = true;
126   size_t i, set_cntr, len = lower_source.length();
127 
128   for(i=0, set_cntr=0; i<len; ++i)
129   {
130     if (mask_set[i]) {
131       lower_target[i+target_offset] = 0;
132       upper_target[i+target_offset] = source_set[set_cntr].size() - 1;
133       ++set_cntr;
134     }
135     else
136     {
137       if (lower_source[i] > -bigBoundSize)
138         lower_target[i+target_offset] = lower_source[i];
139       else
140       {
141         lower_target[i] = no_value;
142         allSet = false;
143       }
144       if (upper_source[i] < bigBoundSize)
145         upper_target[i+target_offset] = upper_source[i];
146       else
147       {
148         upper_target[i] = no_value;
149         allSet = false;
150       }
151     }
152   }
153 
154   return allSet;
155 }
156 
157 /** Adapter originating from (and somewhat specialized based on)
158     APPSOptimizer for copying heterogeneous bounded data from
159     Dakota::Variables into concatenated TPL vectors */
160 
161 //PDH: Same for big_real_bound_size, big_int_bound_size.
162 
163 template <typename AdapterT>
get_variable_bounds(Model & model,Real big_real_bound_size,int big_int_bound_size,typename AdapterT::VecT & lower,typename AdapterT::VecT & upper)164 bool get_variable_bounds( Model &                   model, // would like to make const but cannot due to discrete_int_sets below
165                           Real                      big_real_bound_size,
166                           int                       big_int_bound_size,
167                           typename AdapterT::VecT & lower,
168                           typename AdapterT::VecT & upper)
169 {
170   const RealVector& lower_bnds_cont = model.continuous_lower_bounds();
171   const RealVector& upper_bnds_cont = model.continuous_upper_bounds();
172 
173   const IntVector& lower_bnds_int = model.discrete_int_lower_bounds();
174   const IntVector& upper_bnds_int = model.discrete_int_upper_bounds();
175 
176   const RealVector& lower_bnds_real = model.discrete_real_lower_bounds();
177   const RealVector& upper_bnds_real = model.discrete_real_upper_bounds();
178 
179   const BitArray& int_set_bits = model.discrete_int_sets(); // appears to be able to modify the model object ...
180   const IntSetArray& init_pt_set_int = model.discrete_set_int_values();
181   const RealSetArray& init_pt_set_real = model.discrete_set_real_values();
182   const StringSetArray& init_pt_set_string = model.discrete_set_string_values();
183 
184   // Sanity checks ?
185 
186   bool allSet = get_bounds(lower_bnds_cont,
187                            upper_bnds_cont,
188                            lower,
189                            upper,
190                            big_real_bound_size,
191                            AdapterT::noValue());
192 
193   int offset = model.cv();
194   allSet = allSet &&
195            get_mixed_bounds(
196                    int_set_bits,
197                    init_pt_set_int,
198                    lower_bnds_int,
199                    upper_bnds_int,
200                    lower,
201                    upper,
202                    big_int_bound_size,
203                    (int)AdapterT::noValue(),
204                    offset);
205 
206   offset += model.div();
207   get_bounds(init_pt_set_real, lower, upper, offset);
208 
209   offset += model.drv();
210   get_bounds(init_pt_set_string, lower, upper, offset);
211 
212   return allSet;
213 }
214 
215 /** Adapter for configuring inequality constraint maps used when
216    transferring data between Dakota and a TPL */
217 
218 //PDH: Yes, scaling should be tied to a trait.  And get rid of big_real...
219 
220 template <typename RVecT, typename IVecT>
configure_inequality_constraint_maps(const Model & model,Real big_real_bound_size,CONSTRAINT_TYPE ctype,IVecT & map_indices,RVecT & map_multipliers,RVecT & map_offsets,Real scaling=1.0)221 int configure_inequality_constraint_maps(
222                                const Model & model,
223                                Real big_real_bound_size,
224                                CONSTRAINT_TYPE ctype,
225                                IVecT & map_indices,
226                                RVecT & map_multipliers,
227                                RVecT & map_offsets,
228                                Real scaling = 1.0 /* should this be tied to a trait ? RWH */)
229 {
230   const RealVector& ineq_lwr_bnds = ( ctype == CONSTRAINT_TYPE::NONLINEAR ) ?
231                                         model.nonlinear_ineq_constraint_lower_bounds() :
232                                         model.linear_ineq_constraint_lower_bounds();
233   const RealVector& ineq_upr_bnds = ( ctype == CONSTRAINT_TYPE::NONLINEAR ) ?
234                                         model.nonlinear_ineq_constraint_upper_bounds() :
235                                         model.linear_ineq_constraint_upper_bounds();
236   int num_ineq_constr             = ( ctype == CONSTRAINT_TYPE::NONLINEAR ) ?
237                                         model.num_nonlinear_ineq_constraints() :
238                                         model.num_linear_ineq_constraints();
239 
240   int num_added = 0;
241 
242   for (int i=0; i<num_ineq_constr; i++) {
243     if (ineq_lwr_bnds[i] > -big_real_bound_size) {
244       num_added++;
245       map_indices.push_back(i);
246       map_multipliers.push_back(scaling);
247       map_offsets.push_back(-scaling*ineq_lwr_bnds[i]);
248     }
249     if (ineq_upr_bnds[i] < big_real_bound_size) {
250       num_added++;
251       map_indices.push_back(i);
252       map_multipliers.push_back(-scaling);
253       map_offsets.push_back(scaling*ineq_upr_bnds[i]);
254     }
255   }
256   return num_added;
257 }
258 
259 /** Adapter for configuring equality constraint maps used when
260    transferring data between Dakota and a TPL */
261 
262 //PDH: I'll have to remind myself what the call chain is.  Ultimately,
263 //make_one_sided should be tied to a trait somewhere along the line.
264 //Same for the map-related vectors (e.g., multipliers).
265 
266 template <typename RVecT, typename IVecT>
configure_equality_constraint_maps(Model & model,CONSTRAINT_TYPE ctype,IVecT & indices,size_t index_offset,RVecT & multipliers,RVecT & values,bool make_one_sided)267 void configure_equality_constraint_maps(
268                                Model & model,
269                                CONSTRAINT_TYPE ctype,
270                                IVecT & indices,
271                                size_t index_offset,
272                                RVecT & multipliers,
273                                RVecT & values,
274                                bool make_one_sided)
275 {
276   const RealVector& eq_targets = ( ctype == CONSTRAINT_TYPE::NONLINEAR ) ?
277                                      model.nonlinear_eq_constraint_targets() :
278                                      model.linear_eq_constraint_targets();
279   int num_eq                   = ( ctype == CONSTRAINT_TYPE::NONLINEAR ) ?
280                                      model.num_nonlinear_eq_constraints() :
281                                      model.num_linear_eq_constraints();
282 
283   if( make_one_sided )
284   {
285     for (int i=0; i<num_eq; i++) {
286       indices.push_back(i+index_offset);
287       multipliers.push_back(-1.0);
288       values.push_back(eq_targets[i]);
289       indices.push_back(i+index_offset);
290       multipliers.push_back(1.0);
291       values.push_back(-eq_targets[i]);
292     }
293   }
294   else // leave as two-sided
295   {
296     for (int i=0; i<num_eq; i++) {
297       indices.push_back(i+index_offset);
298       multipliers.push_back(1.0);
299       values.push_back(-eq_targets[i]);
300     }
301   }
302 }
303 
304 /** Adapter based initially on APPSOptimizer for linear constraint
305    maps and including matrix and bounds data;
306        * bundles a few steps together which could (should?) be broken
307          into two or more adapters */
308 
309 template <typename AdapterT>
get_linear_constraints(Model & model,Real big_real_bound_size,typename AdapterT::VecT & lin_ineq_lower_bnds,typename AdapterT::VecT & lin_ineq_upper_bnds,typename AdapterT::VecT & lin_eq_targets,typename AdapterT::MatT & lin_ineq_coeffs,typename AdapterT::MatT & lin_eq_coeffs)310 void get_linear_constraints( Model & model,
311                              Real big_real_bound_size,
312                              typename AdapterT::VecT & lin_ineq_lower_bnds,
313                              typename AdapterT::VecT & lin_ineq_upper_bnds,
314                              typename AdapterT::VecT & lin_eq_targets,
315                              typename AdapterT::MatT & lin_ineq_coeffs,
316                              typename AdapterT::MatT & lin_eq_coeffs)
317 {
318   const RealMatrix& linear_ineq_coeffs     = model.linear_ineq_constraint_coeffs();
319   const RealVector& linear_ineq_lower_bnds = model.linear_ineq_constraint_lower_bounds();
320   const RealVector& linear_ineq_upper_bnds = model.linear_ineq_constraint_upper_bounds();
321   const RealMatrix& linear_eq_coeffs       = model.linear_eq_constraint_coeffs();
322   const RealVector& linear_eq_targets      = model.linear_eq_constraint_targets();
323 
324   // These are special cases involving matrices which get delegated to the adapter for now
325   AdapterT::copy_matrix_data(linear_ineq_coeffs, lin_ineq_coeffs);
326   AdapterT::copy_matrix_data(linear_eq_coeffs,   lin_eq_coeffs);
327 
328   get_bounds(linear_ineq_lower_bnds,
329              linear_ineq_upper_bnds,
330              lin_ineq_lower_bnds,
331              lin_ineq_upper_bnds,
332              big_real_bound_size,
333              AdapterT::noValue());
334 
335   copy_data(linear_eq_targets, lin_eq_targets);
336 }
337 
338 //----------------------------------------------------------------
339 
340 /** Data adapter to transfer data from Dakota to third-party opt
341     packages.  The vector values might contain additional constraints;
342     the first entries corresponding to linear constraints are
343     populated by apply. */
344 template <typename VecT>
apply_linear_constraints(const Model & model,CONSTRAINT_EQUALITY_TYPE etype,const VecT & in_vals,VecT & values,bool adjoint=false)345 void apply_linear_constraints( const Model & model,
346                                CONSTRAINT_EQUALITY_TYPE etype,
347                                const VecT & in_vals,
348 			       VecT & values,
349 			       bool adjoint = false)
350 {
351   size_t num_linear_consts      = ( etype == CONSTRAINT_EQUALITY_TYPE::EQUALITY ) ?
352                                               model.num_linear_eq_constraints() :
353                                               model.num_linear_ineq_constraints();
354   const RealMatrix & lin_coeffs = ( etype == CONSTRAINT_EQUALITY_TYPE::EQUALITY ) ?
355                                               model.linear_eq_constraint_coeffs() :
356                                               model.linear_ineq_constraint_coeffs();
357 
358   apply_matrix_partial(lin_coeffs, in_vals, values);
359 
360   if( etype == CONSTRAINT_EQUALITY_TYPE::EQUALITY )
361   {
362     const RealVector & lin_eq_targets = model.linear_eq_constraint_targets();
363     for(size_t i=0;i<num_linear_consts;++i)
364       values[i] -= lin_eq_targets(i);
365   }
366 }
367 
368 //----------------------------------------------------------------
369 
370 /** Data adapter to transfer data from Dakota to third-party opt packages
371 
372     If adjoint = false, (perhaps counter-intuitively) apply the
373     Jacobian (transpose of the gradient) to in_vals, which should be
374     of size num_continuous_vars: J*x = G'*x, resulting in
375     num_nonlinear_const values getting populated (possibly a subset of
376     the total constraint vector).
377 
378     If adjoint = true, apply the adjoint Jacobian (gradient) to the
379     nonlinear constraint portion of in_vals, which should be of size
380     at least num_nonlinear_consts: J'*y = G*y, resulting in
381     num_continuous_vars values getting populated.
382 */
383 template <typename VecT>
apply_nonlinear_constraints(const Model & model,CONSTRAINT_EQUALITY_TYPE etype,const VecT & in_vals,VecT & values,bool adjoint=false)384 void apply_nonlinear_constraints( const Model & model,
385                                CONSTRAINT_EQUALITY_TYPE etype,
386                                const VecT & in_vals,
387 				  VecT & values ,
388 				  bool adjoint = false)
389 {
390   size_t num_resp = 1; // does this need to be generalized to more than one response value? - RWH
391 
392   size_t num_continuous_vars         = model.cv();
393 
394   size_t num_linear_consts           = ( etype == CONSTRAINT_EQUALITY_TYPE::EQUALITY ) ?
395                                                    model.num_linear_eq_constraints() :
396                                                    model.num_linear_ineq_constraints();
397   size_t num_nonlinear_consts        = ( etype == CONSTRAINT_EQUALITY_TYPE::EQUALITY ) ?
398                                                    model.num_nonlinear_eq_constraints() :
399                                                    model.num_nonlinear_ineq_constraints();
400 
401   const RealMatrix & gradient_matrix = model.current_response().function_gradients();
402 
403   int grad_offset = ( etype == CONSTRAINT_EQUALITY_TYPE::EQUALITY ) ?
404                                                    num_resp + model.num_nonlinear_ineq_constraints() :
405                                                    num_resp;
406 
407   if (adjoint)
408     for (size_t i=0; i<num_continuous_vars; ++i) {
409       // BMA --> RWH: can't zero in case compounding linear and nonlinear (usability issue)
410       // values[i] = 0.0;
411       for(size_t j=0; j<num_nonlinear_consts; ++j)
412 	values[i] += gradient_matrix(i, grad_offset+j) * in_vals[num_linear_consts+j];
413     }
414   else
415     for(size_t j=0; j<num_nonlinear_consts; ++j) {
416       values[num_linear_consts+j] = 0.0;
417       for (size_t i=0; i<num_continuous_vars; i++)
418 	values[num_linear_consts+j] += gradient_matrix(i, grad_offset+j) * in_vals[i];
419     }
420 }
421 
422 //----------------------------------------------------------------
423 
424 /// Base class for the optimizer branch of the iterator hierarchy.
425 
426 /** The Optimizer class provides common data and functionality for
427     DOTOptimizer, CONMINOptimizer, NPSOLOptimizer, SNLLOptimizer,
428     NLPQLPOptimizer, COLINOptimizer, OptDartsOptimizer, NCSUOptimizer,
429     NonlinearCGOptimizer, NomadOptimizer, and JEGAOptimizer. */
430 
431 class Optimizer: public Minimizer
432 {
433 public:
434 
435   /// Static helper function: third-party opt packages which are not available
436   static void not_available(const std::string& package_name);
437 
438 //----------------------------------------------------------------
439 
440   /** Convenience method for common optimizer stopping criteria vectors */
get_common_stopping_criteria(int & max_fn_evals,int & max_iters,double & conv_tol,double & min_var_chg,double & obj_target)441   void get_common_stopping_criteria(int    & max_fn_evals,
442                                     int    & max_iters,
443                                     double & conv_tol,
444                                     double & min_var_chg,
445                                     double & obj_target )
446   {
447     max_fn_evals =  maxFunctionEvals;
448     max_iters = maxIterations;
449     conv_tol = convergenceTol;
450     min_var_chg = probDescDB.get_real("method.variable_tolerance");
451     obj_target = probDescDB.get_real("method.solution_target");
452   }
453 
454 //----------------------------------------------------------------
455 
num_nonlin_ineq_constraints_found() const456   int num_nonlin_ineq_constraints_found() const
457     { return numNonlinearIneqConstraintsFound; }
458 
459   /** Method for transferring variable bounds from Dakota data to TPL data */
460   template <typename AdapterT>
get_variable_bounds_from_dakota(typename AdapterT::VecT & lower,typename AdapterT::VecT & upper)461     bool get_variable_bounds_from_dakota(
462         typename AdapterT::VecT & lower,
463         typename AdapterT::VecT & upper)
464     {
465       return get_variable_bounds<AdapterT>(
466                             iteratedModel,
467                             bigRealBoundSize,
468                             bigIntBoundSize,
469                             lower,
470                             upper);
471     }
472 
473   /** Method for transferring responses from Dakota data to TPL data */
474   template <typename VecT>
get_responses_from_dakota(const RealVector & dak_fn_vals,VecT & funs,VecT & cEqs,VecT & cIneqs)475     void get_responses_from_dakota(
476         const RealVector & dak_fn_vals,
477         VecT & funs,
478         VecT & cEqs,
479         VecT & cIneqs)
480     {
481       return get_responses( iteratedModel,
482                             dak_fn_vals,
483                             constraintMapIndices,
484                             constraintMapMultipliers,
485                             constraintMapOffsets,
486                             funs,
487                             cEqs,
488                             cIneqs);
489     }
490 
491 
492 protected:
493 
494   //
495   //- Heading: Constructors and destructor
496   //
497 
498   /// default constructor
499   Optimizer(std::shared_ptr<TraitsBase> traits);
500   /// alternate constructor; accepts a model
501   Optimizer(ProblemDescDB& problem_db, Model& model, std::shared_ptr<TraitsBase> traits);
502 
503   /// alternate constructor for "on the fly" instantiations
504   Optimizer(unsigned short method_name, Model& model, std::shared_ptr<TraitsBase> traits);
505   /// alternate constructor for "on the fly" instantiations
506   Optimizer(unsigned short method_name, size_t num_cv, size_t num_div,
507 	    size_t num_dsv, size_t num_drv, size_t num_lin_ineq,
508 	    size_t num_lin_eq, size_t num_nln_ineq, size_t num_nln_eq, std::shared_ptr<TraitsBase> traits);
509 
510   /// destructor
511   ~Optimizer();
512 
513   //
514   //- Heading: Virtual member function redefinitions
515   //
516 
517   void initialize_run();
518   void post_run(std::ostream& s);
519   void finalize_run();
520   void print_results(std::ostream& s, short results_state = FINAL_RESULTS);
521 
522   // Configure data transfer helper/adapters
523   void configure_constraint_maps();
524 
525   //
526   //- Heading: Data
527   //
528 
529   /// number of objective functions (iterator view)
530   size_t numObjectiveFns;
531 
532   /// flag indicating whether local recasting to a single objective is used
533   bool localObjectiveRecast;
534 
535   /// pointer to Optimizer instance used in static member functions
536   static Optimizer* optimizerInstance;
537   /// pointer containing previous value of optimizerInstance
538   Optimizer* prevOptInstance;
539 
540   /// number of nonlinear ineq constraints actually used (based on conditional and bigRealBoundSize
541   int numNonlinearIneqConstraintsFound;
542 
543   /// map from Dakota constraint number to APPS constraint number
544   std::vector<int> constraintMapIndices;
545 
546   /// multipliers for constraint transformations
547   std::vector<double> constraintMapMultipliers;
548 
549   /// offsets for constraint transformations
550   std::vector<double> constraintMapOffsets;
551 
552 //----------------------------------------------------------------
553 
configure_inequality_constraints(CONSTRAINT_TYPE ctype)554   int configure_inequality_constraints( CONSTRAINT_TYPE ctype )
555   {
556     Real scaling = 1.0;
557     if( ctype == CONSTRAINT_TYPE::NONLINEAR )
558       scaling = (traits()->nonlinear_inequality_format() == NONLINEAR_INEQUALITY_FORMAT::ONE_SIDED_LOWER)
559         ? 1.0 : -1.0;
560     else if( ctype == CONSTRAINT_TYPE::LINEAR )
561       scaling = (traits()->linear_inequality_format() == LINEAR_INEQUALITY_FORMAT::ONE_SIDED_LOWER)
562         ? 1.0 : -1.0;
563     else
564     {
565       Cerr << "\nError: inconsistent format for CONSTRAINT_TYPE in configure_inequality_constraints adapter." << std::endl;
566       abort_handler(-1);
567     }
568 
569     return configure_inequality_constraint_maps(
570         iteratedModel,
571         bigRealBoundSize,
572         ctype,
573         constraintMapIndices,
574         constraintMapMultipliers,
575         constraintMapOffsets,
576         scaling);
577   }
578 
579 //----------------------------------------------------------------
580 
configure_equality_constraints(CONSTRAINT_TYPE ctype,size_t index_offset)581   void configure_equality_constraints( CONSTRAINT_TYPE ctype, size_t index_offset)
582   {
583     bool split_into_one_sided = true;
584     if( (ctype == CONSTRAINT_TYPE::NONLINEAR) &&
585         (traits()->nonlinear_equality_format() == NONLINEAR_EQUALITY_FORMAT::TRUE_EQUALITY) )
586       split_into_one_sided = false;
587 
588     return configure_equality_constraint_maps(
589         iteratedModel,
590         ctype,
591         constraintMapIndices,
592         index_offset,
593         constraintMapMultipliers,
594         constraintMapOffsets,
595         split_into_one_sided);
596   }
597 
598 //----------------------------------------------------------------
599 
600   template <typename AdapterT>
get_linear_constraints_and_bounds(typename AdapterT::VecT & lin_ineq_lower_bnds,typename AdapterT::VecT & lin_ineq_upper_bnds,typename AdapterT::VecT & lin_eq_targets,typename AdapterT::MatT & lin_ineq_coeffs,typename AdapterT::MatT & lin_eq_coeffs)601   void get_linear_constraints_and_bounds(
602           typename AdapterT::VecT & lin_ineq_lower_bnds,
603           typename AdapterT::VecT & lin_ineq_upper_bnds,
604           typename AdapterT::VecT & lin_eq_targets,
605           typename AdapterT::MatT & lin_ineq_coeffs,
606           typename AdapterT::MatT & lin_eq_coeffs)
607   {
608     return get_linear_constraints<AdapterT>(
609         iteratedModel,
610         bigRealBoundSize,
611         lin_ineq_lower_bnds,
612         lin_ineq_upper_bnds,
613         lin_eq_targets,
614         lin_ineq_coeffs,
615         lin_eq_coeffs);
616   }
617 
618 private:
619 
620   //
621   //- Heading: Convenience/Helper functions
622   //
623 
624   /// Wrap iteratedModel in a RecastModel that performs (weighted)
625   /// multi-objective or sum-of-squared residuals transformation
626   void reduce_model(bool local_nls_recast, bool require_hessians);
627 
628   /// Recast callback to reduce multiple objectives or residuals to a
629   /// single objective, with gradients and Hessians as needed
630   static void primary_resp_reducer(const Variables& full_vars,
631 				   const Variables& reduced_vars,
632 				   const Response& full_response,
633 				   Response& reduced_response);
634 
635   /// forward mapping: maps multiple primary response functions to a single
636   /// weighted objective for single-objective optimizers
637   void objective_reduction(const Response& full_response,
638 			   const BoolDeque& sense, const RealVector& full_wts,
639 			   Response& reduced_response) const;
640 
641   //
642   //- Heading: Data
643   //
644 };
645 
646 
Optimizer(std::shared_ptr<TraitsBase> traits)647 inline Optimizer::Optimizer(std::shared_ptr<TraitsBase> traits): Minimizer(traits), localObjectiveRecast(false)
648 { }
649 
650 
~Optimizer()651 inline Optimizer::~Optimizer()
652 { }
653 
654 
finalize_run()655 inline void Optimizer::finalize_run()
656 {
657   // Restore previous object instance in case of recursion.
658   optimizerInstance = prevOptInstance;
659 
660   Minimizer::finalize_run();
661 }
662 
663 
not_available(const std::string & package_name)664 inline void Optimizer::not_available(const std::string& package_name)
665 {
666   Cerr << package_name << " is not available.\n";
667   abort_handler(-1);
668 }
669 
670 
671 //----------------------------------------------------------------
672 
673 //PDH: How much of everything from here on is used by both APPS and ROL?
674 //Probably need to make a pass to look for possible redundancies and to
675 //consolidate if/where necessary.
676 
677 // Data utilities supporting Opt TPL refactor which may eventually be promoted
678 // to a more generally accessible location - RWH
679 template <typename VectorType1, typename VectorType2, typename SetArray>
copy_variables(const VectorType1 & source,const BitArray & set_bits,const SetArray & set_vars,VectorType2 & dest,size_t offset,size_t len)680 void copy_variables( const VectorType1 & source,
681                      const BitArray & set_bits,
682                      const SetArray& set_vars,
683                            VectorType2 & dest,
684                            size_t offset,
685                            size_t len)
686 {
687   size_t i, index, set_cntr;
688 
689   for(i=0, set_cntr=0; i<len; ++i)
690   {
691     if (set_bits[i])
692     {
693       index = set_value_to_index(source[i], set_vars[set_cntr]);
694       if (index == _NPOS) {
695         Cerr << "\ncopy_data Error: bad index in discrete set lookup." << std::endl;
696         abort_handler(-1);
697       }
698       else
699 	dest[i+offset] = (int)index;
700 
701       ++set_cntr;
702     }
703     else
704       dest[i+offset] = source[i];
705   }
706 }
707 
708 
709 //----------------------------------------------------------------
710 
711 
712 template <typename VectorType1, typename VectorType2, typename SetArray>
copy_variables(const VectorType1 & source,const SetArray & set_vars,VectorType2 & dest,size_t offset,size_t len)713 void copy_variables( const VectorType1 & source,
714                      const SetArray& set_vars,
715                            VectorType2 & dest,
716                            size_t offset,
717                            size_t len)
718 {
719   size_t i, index;
720   for(i=0; i<len; ++i)
721   {
722     index = set_value_to_index(source[i], set_vars[i]);
723     if (index == _NPOS) {
724       Cerr << "\ncopy_data Error: bad index in discrete set lookup." << std::endl;
725       abort_handler(-1);
726     }
727     else
728       dest[i+offset] = (int)index;
729   }
730 }
731 
732 //----------------------------------------------------------------
733 
734 template <typename VectorType1, typename VectorType2>
copy_variables(const VectorType1 & source,VectorType2 & dest,const BitArray & int_set_bits,const IntSetArray & set_int_vars,size_t offset,size_t len)735 void copy_variables( const VectorType1 & source,
736                            VectorType2 & dest,
737                      const BitArray & int_set_bits,
738                      const IntSetArray& set_int_vars,
739                      size_t offset,
740                      size_t len)
741 {
742   size_t i, dsi_cntr;
743   for(i=0, dsi_cntr=0; i<len; ++i)
744   {
745     // This active discrete int var is a set type
746     // Map from index back to value.
747     if (int_set_bits[i])
748       dest[i] = set_index_to_value(source[i+offset], set_int_vars[dsi_cntr++]);
749 
750     // This active discrete int var is a range type
751     else
752       dest[i] = source[i+offset];
753   }
754 }
755 
756 //----------------------------------------------------------------
757 
758 /** Data adapter for use by third-party opt packages to transfer response data to Dakota */
759 template <typename AdapterT>
set_best_responses(typename AdapterT::OptT & optimizer,const Model & model,const std::vector<int> constraint_map_indices,const std::vector<double> constraint_map_multipliers,const std::vector<double> constraint_map_offsets,ResponseArray & response_array)760 void set_best_responses( typename AdapterT::OptT & optimizer,
761                          const Model & model,
762                          const std::vector<int> constraint_map_indices,
763                          const std::vector<double> constraint_map_multipliers,
764                          const std::vector<double> constraint_map_offsets,
765                                ResponseArray & response_array)
766 {
767   RealVector best_fns(model.response_size());
768 
769   size_t num_nl_eq_constr = model.num_nonlinear_eq_constraints();
770   size_t num_nl_ineq_constr = model.num_nonlinear_ineq_constraints();
771 
772   // Get best Objective - assumes single objective only for now
773   std::vector<double> bestEqs(num_nl_eq_constr);
774   std::vector<double> bestIneqs(constraint_map_indices.size()-num_nl_eq_constr);
775   const BoolDeque& max_sense = model.primary_response_fn_sense();
776   best_fns[0] = (!max_sense.empty() && max_sense[0]) ?  -AdapterT::getBestObj(optimizer) : AdapterT::getBestObj(optimizer);
777 
778   // Get best Nonlinear Equality Constraints
779   if (num_nl_eq_constr > 0) {
780     optimizer.getBestNonlEqs(bestEqs); // we leave this method name the same for now but could generalize depending on other TPLs
781     for (size_t i=0; i<num_nl_eq_constr; i++)
782       // Need to figure out how best to generalize use of 2 index arrays, 1 value array and the expression - could use lambdas with c++11
783       best_fns[constraint_map_indices[i]+1] = (bestEqs[i]-constraint_map_offsets[i]) / constraint_map_multipliers[i];
784   }
785 
786   // Get best Nonlinear Inequality Constraints
787   if (num_nl_ineq_constr > 0) {
788     optimizer.getBestNonlIneqs(bestIneqs); // we leave this method name the same for now but could generalize depending on other TPLs
789     for (size_t i=0; i<bestIneqs.size(); i++)
790       // Need to figure out how best to generalize use of 2 index arrays, 1 value array and the expression - could use lambdas with c++11
791       best_fns[constraint_map_indices[i+num_nl_eq_constr]+1] =
792         (bestIneqs[i]-constraint_map_offsets[i+num_nl_eq_constr]) / constraint_map_multipliers[i+num_nl_eq_constr];
793   }
794   response_array.front().function_values(best_fns);
795 }
796 
797 //----------------------------------------------------------------
798 
799 /** copy appropriate slices of source vector to Dakota::Variables */
800 template <typename VectorType>
set_variables(const VectorType & source,Model & model,Variables & vars)801 void set_variables( const VectorType & source,
802                           Model & model,
803                           Variables & vars)
804 {
805   int num_cont_vars = vars.cv();
806   int num_disc_int_vars = vars.div();
807   int num_disc_real_vars = vars.drv();
808   int num_disc_string_vars = vars.dsv();
809 
810   const BitArray& int_set_bits = model.discrete_int_sets();
811   const IntSetArray& set_int_vars = model.discrete_set_int_values();
812   const RealSetArray& set_real_vars = model.discrete_set_real_values();
813   const StringSetArray& set_string_vars = model.discrete_set_string_values();
814 
815   RealVector contVars(num_cont_vars);
816   IntVector  discIntVars(num_disc_int_vars);
817   RealVector discRealVars(num_disc_real_vars);
818 
819   size_t i, dsi_cntr;
820 
821   copy_data_partial(source, 0, contVars, 0, num_cont_vars);
822   vars.continuous_variables(contVars);
823 
824   copy_variables(source, discIntVars, int_set_bits, set_int_vars, num_cont_vars, num_disc_int_vars);
825   vars.discrete_int_variables(discIntVars);
826 
827   // Does this work for more than one discrete Real variables set? - RWH
828   for (i=0; i<num_disc_real_vars; i++)
829     discRealVars[i] = set_index_to_value(source[i+num_cont_vars+num_disc_int_vars], set_real_vars[i]);
830   vars.discrete_real_variables(discRealVars);
831 
832   for (i=0; i<num_disc_string_vars; i++)
833     vars.discrete_string_variable(set_index_to_value(source[i+num_cont_vars+num_disc_int_vars+num_disc_real_vars], set_string_vars[i]), i);
834 }
835 
836 //----------------------------------------------------------------
837 
838 /** copy the various pieces comprising Dakota::Variables into a concatenated TPL vector */
839 template <typename VectorType>
get_variables(Model & model,VectorType & vec)840 void get_variables( Model & model,
841                     VectorType & vec)
842 {
843   const RealVector& cvars = model.continuous_variables();
844   const IntVector& divars = model.discrete_int_variables();
845   const RealVector& drvars = model.discrete_real_variables();
846   const StringMultiArrayConstView dsvars = model.discrete_string_variables();
847 
848   // Could do a sanity check ?
849   if( (model.cv()  !=  cvars.length()) ||
850       (model.div() != divars.length()) ||
851       (model.drv() != drvars.length()) ||
852       (model.dsv() != dsvars.size())   )
853   {
854     Cerr << "\nget_variables Error: model variables have inconsistent lengths." << std::endl;
855     abort_handler(-1);
856   }
857 
858   const BitArray& int_set_bits = model.discrete_int_sets();
859   const IntSetArray& pt_set_int = model.discrete_set_int_values();
860   const RealSetArray& pt_set_real = model.discrete_set_real_values();
861   const StringSetArray& pt_set_string = model.discrete_set_string_values();
862 
863   int offset = 0;
864   copy_data_partial(cvars, 0, vec, offset, cvars.length());
865 
866   offset = cvars.length();
867   copy_variables(divars, int_set_bits, pt_set_int, vec, offset, divars.length());
868 
869   offset += divars.length();
870   copy_variables(drvars, pt_set_real, vec, offset, drvars.length());
871 
872   offset = drvars.length();
873   copy_variables(dsvars, pt_set_string, vec, offset, dsvars.size());
874 }
875 
876 //----------------------------------------------------------------
877 
878 /** Data adapter to transfer data from Dakota to third-party opt packages */
879 template <typename vectorType>
get_responses(const Model & model,const RealVector & dak_fn_vals,const std::vector<int> constraint_map_indices,const std::vector<double> constraint_map_multipliers,const std::vector<double> constraint_map_offsets,vectorType & f_vec,vectorType & cEqs_vec,vectorType & cIneqs_vec)880 void get_responses( const Model & model,
881                     const RealVector & dak_fn_vals,
882                     const std::vector<int> constraint_map_indices,
883                     const std::vector<double> constraint_map_multipliers,
884                     const std::vector<double> constraint_map_offsets,
885                     vectorType & f_vec,
886                     vectorType & cEqs_vec,
887                     vectorType & cIneqs_vec)
888 {
889   size_t num_nl_eq_constr = model.num_nonlinear_eq_constraints();
890 
891   // Copy Objective - assumes single objective only for now
892   f_vec.resize(1);
893   const BoolDeque& max_sense = model.primary_response_fn_sense();
894   f_vec[0] = (!max_sense.empty() && max_sense[0]) ? -dak_fn_vals[0] : dak_fn_vals[0];
895 
896   // Get best Nonlinear Equality Constraints - see comments in set_best_responses
897   cEqs_vec.resize(num_nl_eq_constr);
898   for (int i=0; i<cEqs_vec.size(); i++)
899     cEqs_vec[i] = constraint_map_offsets[i] +
900       constraint_map_multipliers[i]*dak_fn_vals[constraint_map_indices[i]+1];
901 
902   // Get best Nonlinear Inequality Constraints - see comments in set_best_responses
903   cIneqs_vec.resize(constraint_map_indices.size()-num_nl_eq_constr);
904   for (int i=0; i<cIneqs_vec.size(); i++)
905     cIneqs_vec[i] = constraint_map_offsets[i+num_nl_eq_constr] +
906       constraint_map_multipliers[i+num_nl_eq_constr] *
907       dak_fn_vals[constraint_map_indices[i+num_nl_eq_constr]+1];
908 }
909 
910 //----------------------------------------------------------------
911 
912 /** Data adapter to transfer data from Dakota to third-party opt packages */
913 template <typename VecT>
get_nonlinear_eq_constraints(const Model & model,VecT & values,Real scale,int offset=-1)914 void get_nonlinear_eq_constraints( const Model & model,
915                                          VecT & values,
916                                          Real scale,
917                                          int offset = -1 )
918 {
919   if( -1 == offset )
920     offset = model.num_linear_eq_constraints();
921   size_t num_nonlinear_ineq        = model.num_nonlinear_ineq_constraints();
922   size_t num_nonlinear_eq          = model.num_nonlinear_eq_constraints();
923   const RealVector& nln_eq_targets = model.nonlinear_eq_constraint_targets();
924   const RealVector& curr_resp_vals = model.current_response().function_values();
925 
926   for (int i=0; i<num_nonlinear_eq; i++)
927     values[i+offset] = curr_resp_vals[i+1+num_nonlinear_ineq] + scale*nln_eq_targets[i];
928 }
929 
930 //----------------------------------------------------------------
931 
932 /** Data adapter to transfer data from Dakota to third-party opt packages */
933 template <typename VecT>
get_nonlinear_eq_constraints(Model & model,const RealVector & curr_resp_vals,VecT & values,Real scale,int offset=0)934 void get_nonlinear_eq_constraints( Model & model,
935                                    const RealVector & curr_resp_vals,
936                                          VecT & values,
937                                          Real scale,
938                                          int offset = 0 )
939 {
940   const RealVector& nln_eq_targets = model.nonlinear_eq_constraint_targets();
941   int num_nl_eq_constr             = model.num_nonlinear_eq_constraints();
942 
943   for (int i=0; i<num_nl_eq_constr; i++)
944     values[i+offset] = curr_resp_vals[i] + scale*nln_eq_targets[i];
945 }
946 
947 //----------------------------------------------------------------
948 
949 /** Data adapter to transfer data from Dakota to third-party opt packages (ROL-specific) */
950 template <typename VecT>
get_nonlinear_ineq_constraints(const Model & model,VecT & values)951 void get_nonlinear_ineq_constraints( const Model & model,
952                                            VecT & values)
953 {
954   size_t num_nonlinear_ineq        = model.num_nonlinear_ineq_constraints();
955   size_t num_linear_ineq           = model.num_linear_ineq_constraints();
956   const RealVector& curr_resp_vals = model.current_response().function_values();
957 
958   copy_data_partial(curr_resp_vals, 1, values, num_linear_ineq, num_nonlinear_ineq);
959 }
960 
961 //----------------------------------------------------------------
962 
963 ///  Would like to combine the previous adapter with this one (based on APPSOptimizer and COLINOptimizer)
964 ///  and then see how much more generalization is needed to support other TPLs like JEGA
965 
966 /** Data adapter to transfer data from Dakota to third-party opt packages */
967 template <typename VecT>
get_nonlinear_bounds(Model & model,VecT & nonlin_ineq_lower,VecT & nonlin_ineq_upper,VecT & nonlin_eq_targets)968 void get_nonlinear_bounds( Model & model,
969                            VecT & nonlin_ineq_lower,
970                            VecT & nonlin_ineq_upper,
971                            VecT & nonlin_eq_targets)
972 {
973   const RealVector& nln_ineq_lwr_bnds = model.nonlinear_ineq_constraint_lower_bounds();
974   const RealVector& nln_ineq_upr_bnds = model.nonlinear_ineq_constraint_upper_bounds();
975   const RealVector& nln_eq_targets    = model.nonlinear_eq_constraint_targets();
976 
977   copy_data(nln_ineq_lwr_bnds, nonlin_ineq_lower);
978   copy_data(nln_ineq_upr_bnds, nonlin_ineq_upper);
979   copy_data(nln_eq_targets   , nonlin_eq_targets);
980 }
981 
982 } // namespace Dakota
983 
984 #endif
985