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