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: DakotaConstraints
10 //- Description: Class implementation
11 //- Owner: Mike Eldred
12
13 #include "dakota_system_defs.hpp"
14 #include "ProblemDescDB.hpp"
15 #include "DakotaConstraints.hpp"
16 #include "RelaxedVarConstraints.hpp"
17 #include "MixedVarConstraints.hpp"
18 #include "dakota_data_util.hpp"
19
20 static const char rcsId[]="@(#) $Id: DakotaConstraints.cpp 7029 2010-10-22 00:17:02Z mseldre $";
21
22 namespace Dakota {
23
24
25 /** This constructor is the one which must build the base class data
26 for all derived classes. get_constraints() instantiates a derived
27 class letter and the derived constructor selects this base class
28 constructor in its initialization list (to avoid recursion in the
29 base class constructor calling get_constraints() again). Since
30 the letter IS the representation, its rep pointer is set to NULL. */
31 Constraints::
Constraints(BaseConstructor,const ProblemDescDB & problem_db,const SharedVariablesData & svd)32 Constraints(BaseConstructor, const ProblemDescDB& problem_db,
33 const SharedVariablesData& svd):
34 sharedVarsData(svd),
35 numNonlinearIneqCons(
36 problem_db.get_sizet("responses.num_nonlinear_inequality_constraints")),
37 nonlinearIneqConLowerBnds(
38 problem_db.get_rv("responses.nonlinear_inequality_lower_bounds")),
39 nonlinearIneqConUpperBnds(
40 problem_db.get_rv("responses.nonlinear_inequality_upper_bounds")),
41 numNonlinearEqCons(
42 problem_db.get_sizet("responses.num_nonlinear_equality_constraints")),
43 nonlinearEqConTargets(
44 problem_db.get_rv("responses.nonlinear_equality_targets")),
45 numLinearIneqCons(0), numLinearEqCons(0),
46 linearIneqConLowerBnds(
47 problem_db.get_rv("variables.linear_inequality_lower_bounds")),
48 linearIneqConUpperBnds(
49 problem_db.get_rv("variables.linear_inequality_upper_bounds")),
50 linearEqConTargets(
51 problem_db.get_rv("variables.linear_equality_targets"))
52 {
53 shape(); // size all*{Lower,Upper}Bnds arrays
54 build_views(); // construct active/inactive views of all arrays
55 manage_linear_constraints(problem_db); // manage linear constraints
56 }
57
58
59 /** This constructor is the one which must build the base class data
60 for all derived classes. get_constraints() instantiates a derived
61 class letter and the derived constructor selects this base class
62 constructor in its initialization list (to avoid recursion in the
63 base class constructor calling get_constraints() again). Since
64 the letter IS the representation, its rep pointer is set to NULL. */
65 Constraints::
Constraints(BaseConstructor,const SharedVariablesData & svd)66 Constraints(BaseConstructor, const SharedVariablesData& svd):
67 sharedVarsData(svd), numNonlinearIneqCons(0), numNonlinearEqCons(0),
68 numLinearIneqCons(0), numLinearEqCons(0)
69 {
70 shape(); // size all*{Lower,Upper}Bnds arrays
71 build_views(); // construct active/inactive views of all arrays
72 // no linear constraints for this lightweight ctor
73 }
74
75
76 /** The default constructor: constraintsRep is NULL in this case (a
77 populated problem_db is needed to build a meaningful Constraints
78 object). */
Constraints()79 Constraints::Constraints()
80 { /* empty ctor */ }
81
82
83 /** The envelope constructor only needs to extract enough data to
84 properly execute get_constraints, since the constructor
85 overloaded with BaseConstructor builds the actual base class data
86 inherited by the derived classes. */
87 Constraints::
Constraints(const ProblemDescDB & problem_db,const SharedVariablesData & svd)88 Constraints(const ProblemDescDB& problem_db, const SharedVariablesData& svd):
89 // Set the rep pointer to the appropriate variable constraints type
90 constraintsRep(get_constraints(problem_db, svd))
91 {
92 if (!constraintsRep) // bad type or insufficient memory
93 abort_handler(-1);
94 }
95
96
97 /** Initializes constraintsRep to the appropriate derived type, as given
98 by the variables view. */
99 std::shared_ptr<Constraints> Constraints::
get_constraints(const ProblemDescDB & problem_db,const SharedVariablesData & svd)100 get_constraints(const ProblemDescDB& problem_db, const SharedVariablesData& svd)
101 {
102 short active_view = svd.view().first;
103 switch (active_view) {
104 case MIXED_ALL: case MIXED_DESIGN: case MIXED_ALEATORY_UNCERTAIN:
105 case MIXED_EPISTEMIC_UNCERTAIN: case MIXED_UNCERTAIN: case MIXED_STATE:
106 return std::make_shared<MixedVarConstraints>(problem_db, svd);
107 break;
108 case RELAXED_ALL: case RELAXED_DESIGN: case RELAXED_ALEATORY_UNCERTAIN:
109 case RELAXED_EPISTEMIC_UNCERTAIN: case RELAXED_UNCERTAIN: case RELAXED_STATE:
110 return std::make_shared<RelaxedVarConstraints>(problem_db, svd);
111 break;
112 default:
113 Cerr << "Constraints active view " << active_view << " not currently "
114 << "supported in derived Constraints classes." << std::endl;
115 return std::shared_ptr<Constraints>();
116 break;
117 }
118 }
119
120
121 /** Envelope constructor for instantiations on the fly. This
122 constructor executes get_constraints(view), which invokes the
123 default derived/base constructors, followed by a reshape() based
124 on vars_comps. */
Constraints(const SharedVariablesData & svd)125 Constraints::Constraints(const SharedVariablesData& svd):
126 // Set the rep pointer to the appropriate variable constraints type
127 constraintsRep(get_constraints(svd))
128 {
129 if (!constraintsRep)
130 abort_handler(-1);
131 }
132
133
134 /** Initializes constraintsRep to the appropriate derived type, as given by
135 the variables view. The default derived class constructors are invoked. */
136 std::shared_ptr<Constraints>
get_constraints(const SharedVariablesData & svd) const137 Constraints::get_constraints(const SharedVariablesData& svd) const
138 {
139 short active_view = svd.view().first;
140 switch (active_view) {
141 case MIXED_ALL: case MIXED_DESIGN: case MIXED_ALEATORY_UNCERTAIN:
142 case MIXED_EPISTEMIC_UNCERTAIN: case MIXED_UNCERTAIN: case MIXED_STATE:
143 return std::make_shared<MixedVarConstraints>(svd);
144 break;
145 case RELAXED_ALL: case RELAXED_DESIGN: case RELAXED_ALEATORY_UNCERTAIN:
146 case RELAXED_EPISTEMIC_UNCERTAIN: case RELAXED_UNCERTAIN: case RELAXED_STATE:
147 return std::make_shared<RelaxedVarConstraints>(svd);
148 break;
149 default:
150 Cerr << "Constraints active view " << active_view << " not currently "
151 << "supported in derived Constraints classes." << std::endl;
152 return std::shared_ptr<Constraints>();
153 break;
154 }
155 }
156
157
158 /** Copy constructor manages sharing of constraintsRep */
Constraints(const Constraints & con)159 Constraints::Constraints(const Constraints& con)
160 {
161 constraintsRep = con.constraintsRep;
162 }
163
164
165 /** Assignment operator shares the constraintsRep with this envelope. */
operator =(const Constraints & con)166 Constraints Constraints::operator=(const Constraints& con)
167 {
168 constraintsRep = con.constraintsRep;
169 return *this; // calls copy constructor since returned by value
170 }
171
172
~Constraints()173 Constraints::~Constraints()
174 { /* empty dtor */ }
175
176
build_active_views()177 void Constraints::build_active_views()
178 {
179 // Initialize active views
180 if (sharedVarsData.view().first == EMPTY_VIEW) {
181 Cerr << "Error: active view cannot be EMPTY_VIEW in VarConstraints."
182 << std::endl;
183 abort_handler(-1);
184 }
185 sharedVarsData.initialize_active_start_counts();
186 sharedVarsData.initialize_active_components();
187
188 size_t num_cv = sharedVarsData.cv(), num_div = sharedVarsData.div(),
189 /*num_dsv = sharedVarsData.dsv(),*/ num_drv = sharedVarsData.drv();
190 if (num_cv) {
191 size_t cv_start = sharedVarsData.cv_start();
192 continuousLowerBnds = RealVector(Teuchos::View,
193 &allContinuousLowerBnds[cv_start], num_cv);
194 continuousUpperBnds = RealVector(Teuchos::View,
195 &allContinuousUpperBnds[cv_start], num_cv);
196 }
197 if (num_div) {
198 size_t div_start = sharedVarsData.div_start();
199 discreteIntLowerBnds = IntVector(Teuchos::View,
200 &allDiscreteIntLowerBnds[div_start], num_div);
201 discreteIntUpperBnds = IntVector(Teuchos::View,
202 &allDiscreteIntUpperBnds[div_start], num_div);
203 }
204 if (num_drv) {
205 size_t drv_start = sharedVarsData.drv_start();
206 discreteRealLowerBnds = RealVector(Teuchos::View,
207 &allDiscreteRealLowerBnds[drv_start], num_drv);
208 discreteRealUpperBnds = RealVector(Teuchos::View,
209 &allDiscreteRealUpperBnds[drv_start], num_drv);
210 }
211 }
212
213
build_inactive_views()214 void Constraints::build_inactive_views()
215 {
216 // Initialize inactive views
217 if (sharedVarsData.view().second == MIXED_ALL ||
218 sharedVarsData.view().second == RELAXED_ALL) {
219 Cerr << "Error: inactive view cannot be ALL in VarConstraints."<< std::endl;
220 abort_handler(-1);
221 }
222 sharedVarsData.initialize_inactive_start_counts();
223 sharedVarsData.initialize_inactive_components();
224
225 size_t num_icv = sharedVarsData.icv(), num_idiv = sharedVarsData.idiv(),
226 /*num_idsv = sharedVarsData.idsv(),*/ num_idrv = sharedVarsData.idrv();
227 if (num_icv) {
228 size_t icv_start = sharedVarsData.icv_start();
229 inactiveContinuousLowerBnds = RealVector(Teuchos::View,
230 &allContinuousLowerBnds[icv_start], num_icv);
231 inactiveContinuousUpperBnds = RealVector(Teuchos::View,
232 &allContinuousUpperBnds[icv_start], num_icv);
233 }
234 if (num_idiv) {
235 size_t idiv_start = sharedVarsData.idiv_start();
236 inactiveDiscreteIntLowerBnds = IntVector(Teuchos::View,
237 &allDiscreteIntLowerBnds[idiv_start], num_idiv);
238 inactiveDiscreteIntUpperBnds = IntVector(Teuchos::View,
239 &allDiscreteIntUpperBnds[idiv_start], num_idiv);
240 }
241 if (num_idrv) {
242 size_t idrv_start = sharedVarsData.idrv_start();
243 inactiveDiscreteRealLowerBnds = RealVector(Teuchos::View,
244 &allDiscreteRealLowerBnds[idrv_start], num_idrv);
245 inactiveDiscreteRealUpperBnds = RealVector(Teuchos::View,
246 &allDiscreteRealUpperBnds[idrv_start], num_idrv);
247 }
248 }
249
250
inactive_view(short view2)251 void Constraints::inactive_view(short view2)
252 {
253 if (constraintsRep)
254 constraintsRep->inactive_view(view2);
255 else {
256 short view1 = sharedVarsData.view().first;
257 // If active view is {RELAXED,MIXED}_ALL, outer level active view is
258 // aggregated in inner loop all view and inactive view remains EMPTY_VIEW.
259 // Disallow assignment of an inactive ALL view.
260 if (view1 > MIXED_ALL && view2 > MIXED_ALL) {
261 sharedVarsData.inactive_view(view2); // likely redundant with Variables
262 //check_view_compatibility(); // performed in Variables
263 build_inactive_views();
264 }
265 }
266 }
267
268
read(std::istream & s)269 void Constraints::read(std::istream& s)
270 {
271 if (constraintsRep)
272 constraintsRep->read(s); // envelope fwd to letter
273 else { // letter lacking redefinition of virtual fn.!
274 Cerr << "Error: Letter lacking redefinition of virtual read function.\n"
275 << "No default defined at base class." << std::endl;
276 abort_handler(-1);
277 }
278 }
279
280
write(std::ostream & s) const281 void Constraints::write(std::ostream& s) const
282 {
283 if (constraintsRep)
284 constraintsRep->write(s); // envelope fwd to letter
285 else { // letter lacking redefinition of virtual fn.!
286 Cerr << "Error: Letter lacking redefinition of virtual write function.\n"
287 << "No default defined at base class." << std::endl;
288 abort_handler(-1);
289 }
290 }
291
292
293 /** Deep copies are used for history mechanisms that catalogue
294 permanent copies (should not change as the representation within
295 userDefinedConstraints changes). */
copy() const296 Constraints Constraints::copy() const
297 {
298 // the envelope class instantiates a new envelope and a new letter and copies
299 // current attributes into the new objects.
300 Constraints con; // new envelope: constraintsRep=NULL
301
302 if (constraintsRep) {
303 // new letter: allocate a constraintsRep
304 con.constraintsRep = get_constraints(constraintsRep->sharedVarsData);
305
306 // nonlinear constraints
307 con.constraintsRep->numNonlinearIneqCons
308 = constraintsRep->numNonlinearIneqCons;
309 con.constraintsRep->numNonlinearEqCons = constraintsRep->numNonlinearEqCons;
310 con.constraintsRep->nonlinearIneqConLowerBnds
311 = constraintsRep->nonlinearIneqConLowerBnds;
312 con.constraintsRep->nonlinearIneqConUpperBnds
313 = constraintsRep->nonlinearIneqConUpperBnds;
314 con.constraintsRep->nonlinearEqConTargets
315 = constraintsRep->nonlinearEqConTargets;
316 // linear constraints
317 con.constraintsRep->numLinearIneqCons = constraintsRep->numLinearIneqCons;
318 con.constraintsRep->numLinearEqCons = constraintsRep->numLinearEqCons;
319 con.constraintsRep->linearIneqConCoeffs
320 = constraintsRep->linearIneqConCoeffs;
321 con.constraintsRep->linearEqConCoeffs = constraintsRep->linearEqConCoeffs;
322 con.constraintsRep->linearIneqConLowerBnds
323 = constraintsRep->linearIneqConLowerBnds;
324 con.constraintsRep->linearIneqConUpperBnds
325 = constraintsRep->linearIneqConUpperBnds;
326 con.constraintsRep->linearEqConTargets = constraintsRep->linearEqConTargets;
327 // bounds
328 con.constraintsRep->allContinuousLowerBnds
329 = constraintsRep->allContinuousLowerBnds;
330 con.constraintsRep->allContinuousUpperBnds
331 = constraintsRep->allContinuousUpperBnds;
332 con.constraintsRep->allDiscreteIntLowerBnds
333 = constraintsRep->allDiscreteIntLowerBnds;
334 con.constraintsRep->allDiscreteIntUpperBnds
335 = constraintsRep->allDiscreteIntUpperBnds;
336 con.constraintsRep->allDiscreteRealLowerBnds
337 = constraintsRep->allDiscreteRealLowerBnds;
338 con.constraintsRep->allDiscreteRealUpperBnds
339 = constraintsRep->allDiscreteRealUpperBnds;
340
341 // update active and inactive views
342 con.constraintsRep->build_views();
343 }
344
345 return con;
346 }
347
348
349 /** Resizes the derived bounds arrays. */
shape()350 void Constraints::shape()
351 {
352 if (constraintsRep) // envelope
353 constraintsRep->shape();
354 else { // base class portion invoked by derived class redefinitions
355
356 size_t num_acv, num_adiv, num_adsv, num_adrv;
357 sharedVarsData.all_counts(num_acv, num_adiv, num_adsv, num_adrv);
358
359 allContinuousLowerBnds.sizeUninitialized(num_acv);
360 allContinuousUpperBnds.sizeUninitialized(num_acv);
361 allDiscreteIntLowerBnds.sizeUninitialized(num_adiv);
362 allDiscreteIntUpperBnds.sizeUninitialized(num_adiv);
363 //allDiscreteStringLowerBnds.sizeUninitialized(num_adsv);
364 //allDiscreteStringUpperBnds.sizeUninitialized(num_adsv);
365 allDiscreteRealLowerBnds.sizeUninitialized(num_adrv);
366 allDiscreteRealUpperBnds.sizeUninitialized(num_adrv);
367 }
368 }
369
370
371 void Constraints::
reshape(size_t num_nln_ineq_cons,size_t num_nln_eq_cons,size_t num_lin_ineq_cons,size_t num_lin_eq_cons,const SharedVariablesData & svd)372 reshape(size_t num_nln_ineq_cons, size_t num_nln_eq_cons,
373 size_t num_lin_ineq_cons, size_t num_lin_eq_cons,
374 const SharedVariablesData& svd)
375 {
376 if (constraintsRep) // envelope
377 constraintsRep->reshape(num_nln_ineq_cons, num_nln_eq_cons,
378 num_lin_ineq_cons, num_lin_eq_cons, svd);
379 else { // base class implementation for letter
380 sharedVarsData = svd;
381 reshape();
382 build_views();
383 reshape(num_nln_ineq_cons, num_nln_eq_cons, num_lin_ineq_cons,
384 num_lin_eq_cons);
385 }
386 }
387
388
reshape()389 void Constraints::reshape()
390 {
391 if (constraintsRep) // envelope
392 constraintsRep->reshape();
393 else { // base class portion invoked by derived class redefinitions
394
395 size_t num_acv, num_adiv, num_adsv, num_adrv;
396 sharedVarsData.all_counts(num_acv, num_adiv, num_adsv, num_adrv);
397
398 allContinuousLowerBnds.resize(num_acv);
399 allContinuousUpperBnds.resize(num_acv);
400 allDiscreteIntLowerBnds.resize(num_adiv);
401 allDiscreteIntUpperBnds.resize(num_adiv);
402 //allDiscreteStringLowerBnds.resize(num_adsv);
403 //allDiscreteStringUpperBnds.resize(num_adsv);
404 allDiscreteRealLowerBnds.resize(num_adrv);
405 allDiscreteRealUpperBnds.resize(num_adrv);
406 }
407 }
408
409
410 /** Resizes the linear and nonlinear constraint arrays at the base
411 class. Does NOT currently resize the derived bounds arrays. */
412 void Constraints::
reshape(size_t num_nln_ineq_cons,size_t num_nln_eq_cons,size_t num_lin_ineq_cons,size_t num_lin_eq_cons)413 reshape(size_t num_nln_ineq_cons, size_t num_nln_eq_cons,
414 size_t num_lin_ineq_cons, size_t num_lin_eq_cons)
415 {
416 if (constraintsRep) // envelope
417 constraintsRep->reshape(num_nln_ineq_cons, num_nln_eq_cons,
418 num_lin_ineq_cons, num_lin_eq_cons);
419 else { // base class implementation for letter
420
421 // Reshape attributes used by all letters
422 numNonlinearIneqCons = num_nln_ineq_cons;
423 nonlinearIneqConLowerBnds.resize(num_nln_ineq_cons);
424 nonlinearIneqConUpperBnds.resize(num_nln_ineq_cons);
425
426 numNonlinearEqCons = num_nln_eq_cons;
427 nonlinearEqConTargets.resize(num_nln_eq_cons);
428
429 size_t num_av = continuousLowerBnds.length() +
430 discreteIntLowerBnds.length() + discreteRealLowerBnds.length();
431
432 numLinearIneqCons = num_lin_ineq_cons;
433 linearIneqConLowerBnds.resize(num_lin_ineq_cons);
434 linearIneqConUpperBnds.resize(num_lin_ineq_cons);
435 linearIneqConCoeffs.reshape(num_lin_ineq_cons, num_av);
436
437 numLinearEqCons = num_lin_eq_cons;
438 linearEqConTargets.resize(num_lin_eq_cons);
439 linearEqConCoeffs.reshape(num_lin_eq_cons, num_av);
440 }
441 }
442
443
444 /** Convenience function called from derived class constructors. The
445 number of variables active for applying linear constraints is
446 currently defined to be the number of active continuous variables
447 plus the number of active discrete variables (the most general
448 case), even though very few optimizers can currently support mixed
449 variable linear constraints. */
manage_linear_constraints(const ProblemDescDB & problem_db)450 void Constraints::manage_linear_constraints(const ProblemDescDB& problem_db)
451 {
452 const RealVector& linear_ineq_cons
453 = problem_db.get_rv("variables.linear_inequality_constraints");
454 const RealVector& linear_eq_cons
455 = problem_db.get_rv("variables.linear_equality_constraints");
456 size_t lin_ineq_len = linear_ineq_cons.length(),
457 lin_eq_len = linear_eq_cons.length();
458 // get number of active variables to which linear constraints are applied.
459 size_t num_vars = continuousLowerBnds.length() +
460 discreteIntLowerBnds.length() + discreteRealLowerBnds.length();
461
462 if (lin_ineq_len || lin_eq_len) { // check sanity of inputs
463 // check on num_vars is embedded so that, if there are no linear
464 // constraints, the error is managed downstream within the iterators
465 if (num_vars == 0) {
466 Cerr << "Error: no active variable bounds in Constraints::"
467 << "manage_linear_constraints()." << std::endl;
468 abort_handler(-1);
469 }
470 else if (lin_ineq_len%num_vars || lin_eq_len%num_vars) {
471 Cerr << "Error: number of terms in linear constraint specification not "
472 << "evenly\n divisible by " << num_vars << " variables."
473 << std::endl;
474 abort_handler(-1);
475 }
476 }
477
478 if (lin_ineq_len) {
479 numLinearIneqCons = lin_ineq_len/num_vars;
480 copy_data(linear_ineq_cons, linearIneqConCoeffs, (int)numLinearIneqCons,
481 (int)num_vars);
482
483 size_t i, len_lower_bnds = linearIneqConLowerBnds.length(),
484 len_upper_bnds = linearIneqConUpperBnds.length();
485 if (!len_lower_bnds) {
486 linearIneqConLowerBnds.sizeUninitialized(numLinearIneqCons);
487 linearIneqConLowerBnds
488 = -std::numeric_limits<Real>::infinity(); // default lower bounds
489 }
490 else if (len_lower_bnds != numLinearIneqCons) {
491 Cerr << "Error: length of linear inequality lower bounds specification "
492 << "not equal to\n number of linear inequality constraints."
493 << std::endl;
494 abort_handler(-1);
495 }
496 if (!len_upper_bnds) {
497 linearIneqConUpperBnds.sizeUninitialized(numLinearIneqCons);
498 linearIneqConUpperBnds = 0.0; // default upper bounds
499 }
500 else if (len_upper_bnds != numLinearIneqCons) {
501 Cerr << "Error: length of linear inequality upper bounds specification "
502 << "not equal to\n number of linear inequality constraints."
503 << std::endl;
504 abort_handler(-1);
505 }
506 // Sanity check on bounds (prevents subtle specification error resulting
507 // from specifying positive lower bounds and relying on the default upper
508 // bounds of 0).
509 for (i=0; i<numLinearIneqCons; i++) {
510 if (linearIneqConLowerBnds[i] > linearIneqConUpperBnds[i]) {
511 Cerr << "Error: linear inequality lower bound values must be less than "
512 << "or equal to\n linear inequality upper bound values."
513 << std::endl;
514 abort_handler(-1);
515 }
516 }
517 }
518 if (lin_eq_len) {
519 numLinearEqCons = lin_eq_len/num_vars;
520 copy_data(linear_eq_cons, linearEqConCoeffs, (int)numLinearEqCons,
521 (int)num_vars);
522
523 size_t len_targets = linearEqConTargets.length();
524 if (!len_targets) {
525 linearEqConTargets.sizeUninitialized(numLinearEqCons);
526 linearEqConTargets = 0.0;
527 }
528 else if (len_targets != numLinearEqCons) {
529 Cerr << "Error: length of linear equality targets specification not "
530 << "equal to\n number of linear equality constraints."
531 << std::endl;
532 abort_handler(-1);
533 }
534 }
535 }
536
537 } // namespace Dakota
538