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