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:       NomadOptimizer
10 //- Description: Implementation of the NOMADOptimizer class, including
11 //		    derived subclasses used by the NOMAD Library.
12 //- Owner:       Patty Hough
13 //- Checked by:
14 //- Version: $Id$
15 
16 #include <ProblemDescDB.hpp>
17 
18 #include <algorithm>
19 #include <sstream>
20 
21 #include <nomad.hpp>
22 #include "NomadOptimizer.hpp"
23 
24 
25 using namespace std;
26 
27 namespace Dakota {
28 
29 // Main Class: NomadOptimizer
30 
NomadOptimizer(ProblemDescDB & problem_db,Model & model)31 NomadOptimizer::NomadOptimizer(ProblemDescDB& problem_db, Model& model):
32   Optimizer(problem_db, model, std::shared_ptr<TraitsBase>(new NomadTraits()))
33 {
34   // Set initial mesh size
35   initMesh = probDescDB.get_real("method.mesh_adaptive_search.initial_delta");
36 
37   // Set minimum mesh size
38   minMesh = probDescDB.get_real("method.mesh_adaptive_search.variable_tolerance");
39 
40   // Set Rnd Seed
41   randomSeed = probDescDB.get_int("method.random_seed");
42 
43   // Set Max # of BB Evaluations
44   maxBlackBoxEvals = probDescDB.get_int("method.max_function_evaluations");
45 
46   // STATS_FILE -- File Output
47   outputFormat =
48     probDescDB.get_string("method.mesh_adaptive_search.display_format");
49 
50   // DISPLAY_ALL_EVAL -- If set, shows all evaluation points during
51   // Outputs, instead of just improvements
52   displayAll =
53     probDescDB.get_bool("method.mesh_adaptive_search.display_all_evaluations");
54 
55   // Expected precision of the function.  Any differences less than
56   // this are noise.
57   epsilon = probDescDB.get_real("method.function_precision");
58 
59   // Maximum number of iterations.
60   maxIterations = probDescDB.get_int("method.max_iterations");
61 
62   // VNS = Variable Neighbor Search, it is used to escape local minima
63   // if VNS >0.0, the NOMAD Parameter must be set with a Real number.
64   vns =
65     probDescDB.get_real("method.mesh_adaptive_search.variable_neighborhood_search");
66 
67   // Number of dimensions up to which should be perturbed (according
68   // to adjacency matrices) to determine categorical neighbors.
69   numHops = probDescDB.get_int("method.mesh_adaptive_search.neighbor_order");
70 
71   // Set the History File, which will contain all the evaluations history
72   historyFile =
73     probDescDB.get_string("method.mesh_adaptive_search.history_file");
74 
75   // Identify which integer set variables are categorical.
76   discreteSetIntCat =
77     probDescDB.get_ba("variables.discrete_design_set_int.categorical");
78 
79   // Identify which real set variables are categorical.
80   discreteSetRealCat =
81     probDescDB.get_ba("variables.discrete_design_set_real.categorical");
82 
83   // Adjacency matrices for integer categorical variables.
84   discreteSetIntAdj =
85     probDescDB.get_rma("variables.discrete_design_set_int.adjacency_matrix");
86 
87   // Adjacency matrices for real categorical variables.
88   discreteSetRealAdj =
89     probDescDB.get_rma("variables.discrete_design_set_real.adjacency_matrix");
90 
91   // Adjacency matrices for string variables.
92   discreteSetStrAdj =
93     probDescDB.get_rma("variables.discrete_design_set_str.adjacency_matrix");
94 
95   // Definition for how to use surrogate model.
96   useSurrogate = probDescDB.get_string("method.mesh_adaptive_search.use_surrogate");
97 }
98 
NomadOptimizer(Model & model)99 NomadOptimizer::NomadOptimizer(Model& model):
100   Optimizer(MESH_ADAPTIVE_SEARCH, model, std::shared_ptr<TraitsBase>(new NomadTraits()))
101 {
102 }
103 
104 // Driver, this class runs the Mads algorithm.  This is the stuff that
105 // normally went into the main of the sample programs
106 
core_run()107 void NomadOptimizer::core_run()
108 {
109   // Set up Output (NOMAD::Display)
110   NOMAD::Display out (std::cout);
111   out.precision (NOMAD::DISPLAY_PRECISION_STD);
112 
113   // This is only used when using NOMAD with MPI
114   NOMAD::begin ( 0 , NULL );
115 
116   // Create parameters
117   NOMAD::Parameters p (out);
118 
119   // Verify that user has requested surrogate model construction
120   // when use_surrogate is defined.
121   if ((iteratedModel.model_type() != "surrogate") &&
122     ((useSurrogate.compare("inform_search") == 0) || (useSurrogate.compare("optimize") == 0))) {
123   Cerr << "Error: Specified use_surrogate without requesting surrogate model "
124     << "construction." << std::endl;
125     abort_handler(-1);
126   }
127 
128   // Overwriting dummy default needed for error catching
129   if (useSurrogate.compare("none") == 0){
130     useSurrogate = "optimize";
131   }
132 
133   // If model is a surrogate, build it. Subsequently, tell NOMAD to make
134   // use of it if use_surrogate is set to inform_search
135   if (iteratedModel.model_type() == "surrogate") {
136     iteratedModel.build_approximation();
137 
138     if (useSurrogate.compare("inform_search") == 0){
139     p.set_HAS_SGTE(true);
140     }
141   }
142 
143   // Map dakota output levels to NOMAD's four different levels
144   // of display. Default is set to normal NOMAD output level
145   // (see NORMAL_DISPLAY setting in NOMAD manual)
146   switch (outputLevel)
147   {
148       case SILENT_OUTPUT: p.set_DISPLAY_DEGREE ( 0 ); break;
149       case QUIET_OUTPUT: p.set_DISPLAY_DEGREE ( 1 ); break;
150       case NORMAL_OUTPUT: p.set_DISPLAY_DEGREE ( 2  ); break;
151       case DEBUG_OUTPUT: p.set_DISPLAY_DEGREE ( 3  ); break;
152       case VERBOSE_OUTPUT: p.set_DISPLAY_DEGREE ( 3  ); break;
153       default: p.set_DISPLAY_DEGREE ( 1  );
154   }
155 
156   // Load Input Parameters
157   numTotalVars = numContinuousVars + numDiscreteIntVars
158                + numDiscreteRealVars + numDiscreteStringVars;
159   p.set_DIMENSION(this->numTotalVars);
160   this->load_parameters(iteratedModel, p);
161 
162   // Set up response types
163   vector<NOMAD::bb_output_type>
164     bb_responses(1+numNomadNonlinearIneqConstraints+numNonlinearEqConstraints);
165   bb_responses[0] = NOMAD::OBJ;
166   for(int i=0; i<this->numNomadNonlinearIneqConstraints;i++)
167     bb_responses[i+1] = NOMAD::PB;
168   for(int i=0; i<this->numNonlinearEqConstraints;i++)
169     bb_responses[i+1+this->numNomadNonlinearIneqConstraints] = NOMAD::EB;
170 
171   // Set output and inputs.
172   p.set_BB_OUTPUT_TYPE (bb_responses);
173   p.set_X0 (this->initialPoint);
174   p.set_LOWER_BOUND(this->lowerBound);
175   p.set_UPPER_BOUND(this->upperBound);
176 
177   // Set Max # of BB Evaluations
178   p.set_MAX_BB_EVAL (maxBlackBoxEvals);
179 
180   // DISPLAY_STATS -- Standard Output
181   // STATS_FILE -- File Output
182   // These two format the information displayed using keywords to indicate
183   // how the information is displayed in their respective output media.
184   // Keywords:
185   // BBE		BB Evaluation
186   // BBO		BB Output
187   // EVAL		Evaluations
188   // MESH_INDEX	Mesh Index
189   // MESH_SIZE	Mesh Size Parameter
190   // OBJ		Objective Function Value
191   // POLL_SIZE	Poll Size pParameter
192   // SGTE		# of Surrogate Evals
193   // SIM_BBE		Simulated BB evaluations (when using cache)
194   // SOL		Solution, format is iSOLj, i and j are optional strings
195   // STAT_AVG	AVG statistic, defined in BB_OUTPUT_TYPE
196   // STAT_SUM	SUM statistic, defined in BB_OUTPUT_TYPE
197   // TIME		Wall clock time
198   // VARi 		Value of Variable i (0-based)
199 
200   p.set_DISPLAY_STATS(outputFormat);
201   p.set_DISPLAY_ALL_EVAL(displayAll);
202 
203   // Set method control parameters.
204   p.set_INITIAL_MESH_SIZE(initMesh);
205   p.set_MIN_MESH_SIZE(minMesh);
206   p.set_EPSILON(epsilon);
207   p.set_MAX_ITERATIONS(maxIterations);
208   p.set_SEED(randomSeed);
209 
210   // VNS = Variable Neighbor Search, it is used to escape local minima
211   // if VNS >0.0, the NOMAD Parameter must be set with a Real number.
212   if(vns>0.0) {
213     if (vns > 1.0) {
214       Cerr << "\nWarning: variable_neighborhood_search outside acceptable "
215 	   << "range of (0,1].\nUsing default value of 0.75.\n\n";
216       vns = 0.75;
217     }
218     p.set_VNS_SEARCH(vns);
219   }
220 
221   // Set the History File, which will contain all the evaluations history
222   p.set_HISTORY_FILE( historyFile );
223 
224   // Allow as many simultaneous evaluations as NOMAD wishes and let Dakota schedule
225   if (iteratedModel.asynch_flag())
226     p.set_BB_MAX_BLOCK_SIZE(INT_MAX);
227 
228   // Check the parameters -- Required by NOMAD for execution
229   p.check();
230 
231   // Create Evaluator object and communicate constraint mapping and surrogate usage.
232   NomadOptimizer::Evaluator ev (p, iteratedModel);
233 
234 //PDH: May be able to get rid of setting the constraint map once we
235 //have something in place that everyone can access.
236 
237   ev.set_constraint_map(numNomadNonlinearIneqConstraints, numNonlinearEqConstraints, constraintMapIndices, constraintMapMultipliers, constraintMapOffsets);
238   ev.set_surrogate_usage(useSurrogate);
239 
240   // Construct Extended Poll object to form categorical neighbors.
241   NomadOptimizer::Extended_Poll ep (p,categoricalAdjacency,numHops);
242 
243   // Create Algorithm ( NOMAD::Mads mads ( params, &evaluator ) )
244   NOMAD::Mads mads (p,&ev,&ep,NULL,NULL);
245   // Use Dakota's recast model for multi-objective for now.  Enable
246   // NOMAD's native support for multi-objective later.
247   NOMAD::Mads::set_flag_check_bimads(false);
248 
249   // Run!
250   mads.run();
251 
252   // Retrieve best iterate and convert from NOMAD to DAKOTA
253   // vector.
254 
255   const NOMAD::Eval_Point * bestX;
256   bestX = mads.get_best_feasible();
257   if (!bestX) {
258     Cout << "WARNING: No feasible solution was found. "
259 	 << "Best point shown is best infeasible point.\n" << std::endl;
260     bestX = mads.get_best_infeasible();
261   }
262 
263 //PDH: Set final solution.
264 //     Includes mappings of discrete variables.
265 //     Similar to APPSPACK but need to look into NOMAD's Point more.
266 //     Think the code from here to the end of the method
267 //     can be greatly simplified with data adapters built
268 //     on top of data tranfers.
269 //     Would like to just do something like
270 //     setBestVariables(...)
271 //     setBestResponses(...)
272 
273   RealVector contVars(numContinuousVars);
274   IntVector  discIntVars(numDiscreteIntVars);
275   RealVector discRealVars(numDiscreteRealVars);
276 
277   const BitArray& int_set_bits = iteratedModel.discrete_int_sets();
278   const IntSetArray& set_int_vars = iteratedModel.discrete_set_int_values();
279   const RealSetArray& set_real_vars = iteratedModel.discrete_set_real_values();
280   const StringSetArray& set_string_vars = iteratedModel.discrete_set_string_values();
281 
282   size_t j, dsi_cntr;
283 
284   for(j=0; j<numContinuousVars; j++)
285     contVars[j] = (*bestX)[j].value();
286   bestVariablesArray.front().continuous_variables(contVars);
287 
288   for(j=0, dsi_cntr=0; j<numDiscreteIntVars; j++)
289   {
290     // This active discrete int var is a set type
291     // Map from index back to value.
292     if (int_set_bits[j]) {
293       discIntVars[j] =
294 	set_index_to_value((*bestX)[j+numContinuousVars].value(), set_int_vars[dsi_cntr]);
295       ++dsi_cntr;
296     }
297     // This active discrete int var is a range type
298     else
299       discIntVars[j] = (*bestX)[j+numContinuousVars].value();
300   }
301 
302   // For real sets and strings, map from index back to value.
303   bestVariablesArray.front().discrete_int_variables(discIntVars);
304   for (j=0; j<numDiscreteRealVars; j++)
305     discRealVars =
306       set_index_to_value((*bestX)[j+numContinuousVars+numDiscreteIntVars].value(), set_real_vars[j]);
307   bestVariablesArray.front().discrete_real_variables(discRealVars);
308 
309   for (j=0; j<numDiscreteStringVars; j++)
310     bestVariablesArray.front().discrete_string_variable(set_index_to_value((*bestX)[j+numContinuousVars+numDiscreteIntVars+numDiscreteRealVars].value(), set_string_vars[j]), j);
311 
312 //PDH: Similar to APPSPACK but need to look into NOMAD's Point more.
313 //     Has to respect Dakota's ordering of inequality and equality constraints.
314 //     Has to map format of constraints.
315 //     Then populate bestResponseArray.
316 
317   // Retrieve the best responses and convert from NOMAD to
318   // DAKOTA vector.h
319   if (!localObjectiveRecast) {
320     // else local_objective_recast_retrieve() is used in Optimizer::post_run()
321     const NOMAD::Point & bestFs = bestX->get_bb_outputs();
322     RealVector best_fns(numFunctions);
323     std::vector<double> bestIneqs(constraintMapIndices.size()-numNonlinearEqConstraints);
324     std::vector<double> bestEqs(numNonlinearEqConstraints);
325     const BoolDeque& max_sense = iteratedModel.primary_response_fn_sense();
326 
327     // Map objective appropriately based on minimizing or maximizing.
328     best_fns[0] = (!max_sense.empty() && max_sense[0]) ?
329       -bestFs[0].value() : bestFs[0].value();
330 
331     // Map linear and nonlinear constraints according to constraint map.
332     if (numNonlinearIneqConstraints > 0) {
333       for (int i=0; i<numNomadNonlinearIneqConstraints; i++) {
334 	best_fns[constraintMapIndices[i]+1] = (bestFs[i+1].value() -
335 		 constraintMapOffsets[i]) / constraintMapMultipliers[i];
336       }
337     }
338     if (numNonlinearEqConstraints > 0) {
339       for (int i=0; i<numNonlinearEqConstraints; i++)
340 	best_fns[constraintMapIndices[i+numNomadNonlinearIneqConstraints]+1] =
341 	  (bestFs[i+numNomadNonlinearIneqConstraints+1].value() -
342 	   constraintMapOffsets[i+numNomadNonlinearIneqConstraints]) /
343 	  constraintMapMultipliers[i+numNomadNonlinearIneqConstraints];
344     }
345     bestResponseArray.front().function_values(best_fns);
346   }
347 
348   // Stop NOMAD output.  Required.
349   NOMAD::Slave::stop_slaves ( out );
350   NOMAD::end();
351 }
352 
353 // Sub Class: EvaluatorCreator, this class creates an Evaluator
354 // using a Dakota Model
355 
356 // Sub Class: Evaluator, this class bridges NOMAD-style inputs with
357 // DAKOTA style communication w/Black Box program.
358 
Evaluator(const NOMAD::Parameters & p,Model & model)359 NomadOptimizer::Evaluator::Evaluator(const NOMAD::Parameters &p, Model& model)
360                          : NOMAD::Evaluator (p),_model(model)
361 {
362   // Here we should take the parameters and get the problem information
363   // Like # of variables and types, # and types of constrs
364   /*
365     p.get_bb_nb_outputs(); // Get # of BB Outputs
366     p.get_bb_input_type(); // Returns a vector<NOMAD::bb_input_type>
367     p.get_bb_output_type(); // same, but with output_type
368     p.get_index_obj(); // get indices of obj fn, it's a list
369   */
370   // We can also access the parameters through _p
371   vector<NOMAD::bb_input_type> input_types;
372   input_types = _p.get_bb_input_type();
373 
374   n_cont = 0;
375   n_disc_int = 0;
376   n_disc_real = 0;
377 
378   for(int i=0;i<input_types.size();i++)
379   {
380     if(input_types[i]==NOMAD::CONTINUOUS)
381     {
382       n_cont++;
383     }
384     else
385     {
386       n_disc_int++;
387     }
388   }
389 }
390 
~Evaluator(void)391 NomadOptimizer::Evaluator::~Evaluator(void){};
392 
eval_x(std::list<NOMAD::Eval_Point * > & x,const NOMAD::Double & h_max,std::list<bool> & count_eval) const393 bool NomadOptimizer::Evaluator::eval_x ( std::list<NOMAD::Eval_Point *>& x,
394 					 const NOMAD::Double& h_max,
395 					 std::list<bool>& count_eval ) const
396 {
397   for (auto xi : x) {
398     set_variables(*xi);
399     bool allow_asynch = true;
400     eval_model(allow_asynch, *xi); // calls evaluate() or evaluate_nowait()
401     // collect and store if blocking
402     if (!_model.asynch_flag())
403       get_responses(_model.current_response().function_values(), *xi);
404   }
405 
406   // block, collect, and store asynch responses
407   if (_model.asynch_flag()) {
408     const IntResponseMap& resp_map = _model.synchronize();
409     if (x.size() != resp_map.size() || x.size() != count_eval.size()) {
410       Cerr << "\nError: Incompatible container sizes in NOMAD batch eval_x()\n";
411       abort_handler(METHOD_ERROR);
412     }
413     IntRespMCIter evalid_resp = resp_map.begin();
414     auto xi = x.begin();
415     auto cnt_eval = count_eval.begin();
416     for ( ; xi != x.end(); ++evalid_resp, ++xi, ++cnt_eval) {
417       get_responses(evalid_resp->second.function_values(), **xi);
418       *cnt_eval = true;
419     }
420   }
421 
422   return true;
423 }
424 
425 
eval_x(NOMAD::Eval_Point & x,const NOMAD::Double & h_max,bool & count_eval) const426 bool NomadOptimizer::Evaluator::eval_x ( NOMAD::Eval_Point &x,
427 					 const NOMAD::Double &h_max,
428 					 bool &count_eval) const
429 {
430   set_variables(x);
431   // Compute the Response using Dakota Interface
432   // if single point eval is called, always want to block
433   bool allow_asynch = false;
434   eval_model(allow_asynch, x);
435   get_responses(_model.current_response().function_values(), x);
436   count_eval = true;
437 
438   return true;
439 }
440 
441 
set_variables(const NOMAD::Eval_Point & x) const442 void NomadOptimizer::Evaluator::set_variables(const NOMAD::Eval_Point &x) const
443 {
444   //PDH: Set current iterate values for evaluation.
445   //     Similar to APPSPACK but need to look into NOMAD Point more.
446   //     Think this code can be greatly simplified with data adapters
447   //     built on top of data transfers.  Would like to just do
448   //     something like
449   //     setEvalVariables(...)
450 
451   int n_cont_vars = _model.cv();
452   int n_disc_int_vars = _model.div();
453   int n_disc_real_vars = _model.drv();
454   int n_disc_string_vars = _model.dsv();
455 
456   // Prepare Vectors for Dakota model.
457   RealVector contVars(n_cont_vars);
458   IntVector  discIntVars(n_disc_int_vars);
459   RealVector discRealVars(n_disc_real_vars);
460 
461   const BitArray& int_set_bits = _model.discrete_int_sets();
462   const IntSetArray&  set_int_vars = _model.discrete_set_int_values();
463   const RealSetArray& set_real_vars = _model.discrete_set_real_values();
464   const StringSetArray& set_string_vars = _model.discrete_set_string_values();
465 
466   size_t i, dsi_cntr;
467 
468   // Parameters contain Problem Information (variable: _p)
469 
470   // Here we are going to fetch the input information in x in a format that can be read by DAKOTA
471   // Transform values in x into something DAKOTA can read...
472 
473   // In the NOMAD parameters model:
474   // 1. Continuous Variables = NOMAD::CONTINUOUS
475   // 2. Discrete Integer Variables = NOMAD::INTEGER and NOMAD::BINARY
476   // 3. Discrete Real Variables = NOMAD::CATEGORICAL (??)
477 
478   // x.get_n() = # of BB Inputs
479   // x.get_m() = # of BB Outputs
480   for(i=0; i<n_cont_vars; i++)
481   {
482     _model.continuous_variable(x[i].value(), i);
483   }
484 
485   for(i=0, dsi_cntr=0; i<n_disc_int_vars; i++)
486   {
487     // This active discrete int var is a set type
488     // Map from index to value.
489     if (int_set_bits[i]) {
490       int dakota_value = set_index_to_value(x[i+n_cont_vars].value(),
491 					    set_int_vars[dsi_cntr]);
492       _model.discrete_int_variable(dakota_value, i);
493       ++dsi_cntr;
494     }
495     // This active discrete int var is a range type
496     else  {
497       _model.discrete_int_variable(x[i+n_cont_vars].value(), i);
498     }
499   }
500 
501   // For real set and strings, map from index to value.
502   for (i=0; i<n_disc_real_vars; i++) {
503     Real dakota_value = set_index_to_value(x[i+n_cont_vars+n_disc_int_vars].value(), set_real_vars[i]);
504     _model.discrete_real_variable(dakota_value, i);
505   }
506 
507   for (i=0; i<n_disc_string_vars; i++) {
508     _model.discrete_string_variable(set_index_to_value(x[i+n_cont_vars+n_disc_int_vars+n_disc_real_vars].value(), set_string_vars[i]), i);
509   }
510 
511 }
512 
513 
eval_model(bool allow_asynch,const NOMAD::Eval_Point & x) const514 void NomadOptimizer::Evaluator::eval_model(bool allow_asynch, const NOMAD::Eval_Point& x) const
515 {
516   // Compute the Response using Dakota Interface
517   if ((_model.model_type() == "surrogate") && (x.get_eval_type() != NOMAD::SGTE) &&
518       (useSgte.compare("inform_search") == 0)) {
519     short orig_resp_mode = _model.surrogate_response_mode();
520     _model.surrogate_response_mode(BYPASS_SURROGATE);
521     // hierarchical surrogates can be asynchronous
522     if (allow_asynch && _model.asynch_flag())
523       _model.evaluate_nowait();
524     else
525       _model.evaluate();
526     _model.surrogate_response_mode(orig_resp_mode);
527   }
528   else {
529     if (allow_asynch && _model.asynch_flag())
530       _model.evaluate_nowait();
531     else
532       _model.evaluate();
533   }
534 }
535 
536 
get_responses(const RealVector & ftn_vals,NOMAD::Eval_Point & x) const537 void NomadOptimizer::Evaluator::get_responses(const RealVector& ftn_vals,
538 					      NOMAD::Eval_Point &x) const
539 {
540   //PDH: NOMAD response values set one at a time.
541   //     Has to respect ordering of inequality and equality constraints.
542   //     Has to map format of constraints.
543 
544   // Map objective according to minimizing or maximizing.
545   const BoolDeque& sense = _model.primary_response_fn_sense();
546   bool max_flag = (!sense.empty() && sense[0]);
547   Real obj_fcn = (max_flag) ? -ftn_vals[0] : ftn_vals[0];
548   x.set_bb_output  ( 0 , NOMAD::Double(obj_fcn) );
549 
550   // Map constraints according to constraint map.
551   int numTotalConstr = numNomadNonlinearIneqConstr+numNomadNonlinearEqConstr;
552   for(int i=1;i<=numTotalConstr;i++)
553   {
554     Real constr_value = constrMapOffsets[i-1] +
555       constrMapMultipliers[i-1]*ftn_vals[constrMapIndices[i-1]+1];
556     x.set_bb_output  ( i , NOMAD::Double(constr_value)  );
557   }
558 
559 }
560 
561 
562 // Called by NOMAD to provide a list of categorical neighbors.
563 void NomadOptimizer::Extended_Poll::
construct_extended_points(const NOMAD::Eval_Point & nomad_point)564 construct_extended_points(const NOMAD::Eval_Point &nomad_point)
565 {
566   NOMAD::Point current_point = nomad_point;
567   NOMAD::Signature *nomad_signature = nomad_point.get_signature();
568 
569   // Call this recursive function for multi-dimensional neighbors.
570   construct_multihop_neighbors(current_point, *nomad_signature,
571 			       adjacency_matrix.begin(), -1, nHops);
572 }
573 
574 // Recursive helper function to determine multi-dimensional neighbors.
575 void NomadOptimizer::Extended_Poll::
construct_multihop_neighbors(NOMAD::Point & base_point,NOMAD::Signature point_signature,RealMatrixArray::iterator rma_iter,size_t last_cat_index,int num_hops)576 construct_multihop_neighbors(NOMAD::Point &base_point,
577 NOMAD::Signature point_signature, RealMatrixArray::iterator
578 rma_iter, size_t last_cat_index, int num_hops)
579 {
580   size_t i, j, k;
581 
582   RealMatrixArray::iterator pass_through_iter(rma_iter), tmp_iter;
583   const std::vector<NOMAD::bb_input_type>& input_types = point_signature.get_input_types();
584 
585   // Iterate through point from last categorical variable.
586   for (i=last_cat_index+1, tmp_iter=rma_iter; i<point_signature.get_n(); i++)
587   {
588     if (input_types[i] == NOMAD::CATEGORICAL)
589     {
590       NOMAD::Point neighbor = base_point;
591       j = (size_t) base_point[i].value();
592       pass_through_iter++;
593       for (k=0; k<(*tmp_iter).numCols(); k++)
594       {
595 	if ((*tmp_iter)[j][k]>0 && j!=k)
596 	{
597 	  neighbor[i] = k;
598 	  add_extended_poll_point(neighbor, point_signature);
599 	  if (num_hops > 1)
600 	  {
601 	    construct_multihop_neighbors(neighbor, point_signature, pass_through_iter, i, num_hops-1);
602 	  }
603 	}
604       }
605       tmp_iter++;
606     }
607   }
608 }
609 
load_parameters(Model & model,NOMAD::Parameters & p)610 void NomadOptimizer::load_parameters(Model &model, NOMAD::Parameters &p)
611 {
612 //PDH: This initializes everything for NOMAD.
613 //     Similar to APPSPACK but need to look into NOMAD Point more.
614 //     Don't want any references to iteratedModel.
615 //     Need to handle discrete variable mapping.
616 //     Need to respect equality, inequality constraint ordering.
617 //     Need to handle constraint mapping.
618 
619   //     numTotalVars = numContinuousVars +
620   //                    numDiscreteIntVars + numDiscreteRealVars;
621 
622   // Define Input Types and Bounds
623 
624   NOMAD::Point _initial_point (numTotalVars);
625   NOMAD::Point _upper_bound (numTotalVars);
626   NOMAD::Point _lower_bound (numTotalVars);
627 
628   const RealVector& initial_point_cont = model.continuous_variables();
629   const RealVector& lower_bound_cont = model.continuous_lower_bounds();
630   const RealVector& upper_bound_cont = model.continuous_upper_bounds();
631 
632   const IntVector& initial_point_int = model.discrete_int_variables();
633   const IntVector& lower_bound_int = model.discrete_int_lower_bounds();
634   const IntVector& upper_bound_int = model.discrete_int_upper_bounds();
635 
636   const RealVector& initial_point_real = model.discrete_real_variables();
637   const RealVector& lower_bound_real = model.discrete_real_lower_bounds();
638   const RealVector& upper_bound_real = model.discrete_real_upper_bounds();
639 
640   const StringMultiArrayConstView initial_point_string =
641     model.discrete_string_variables();
642 
643   const BitArray& int_set_bits = iteratedModel.discrete_int_sets();
644   const IntSetArray& initial_point_set_int =
645     iteratedModel.discrete_set_int_values();
646   const RealSetArray& initial_point_set_real =
647     iteratedModel.discrete_set_real_values();
648   const StringSetArray& initial_point_set_string =
649     iteratedModel.discrete_set_string_values();
650 
651   RealMatrix tmp_categorical_adjacency;
652 
653   size_t i, j, k, index, dsi_cntr;
654 
655   for(i=0;i<numContinuousVars;i++)
656   {
657     _initial_point[i] = initial_point_cont[i];
658     if (lower_bound_cont[i] > -bigRealBoundSize)
659       _lower_bound[i] = lower_bound_cont[i];
660     else {
661       Cerr << "\nError: NomadOptimizer::load_parameters\n"
662 	   << "mesh_adaptive_search requires lower bounds "
663 	   << "for all continuous variables" << std::endl;
664       abort_handler(-1);
665     }
666     if (upper_bound_cont[i] < bigRealBoundSize)
667       _upper_bound[i] = upper_bound_cont[i];
668     else {
669       Cerr << "\nError: NomadOptimizer::load_parameters\n"
670 	   << "mesh_adaptive_search requires upper bounds "
671 	   << "for all continuous variables" << std::endl;
672       abort_handler(-1);
673     }
674     p.set_BB_INPUT_TYPE(i,NOMAD::CONTINUOUS);
675   }
676   for(i=0, dsi_cntr=0; i<numDiscreteIntVars; i++)
677   {
678     if (int_set_bits[i]) {
679       index = set_value_to_index(initial_point_int[i],
680 				 initial_point_set_int[dsi_cntr]);
681       if (index == _NPOS) {
682 	Cerr << "\nError: failure in discrete integer set lookup within "
683 	     << "NomadOptimizer::load_parameters(Model &model)" << std::endl;
684 	abort_handler(-1);
685       }
686       else {
687 	_initial_point[i+numContinuousVars] = (int)index;
688       }
689       if (!discreteSetIntCat.empty() && discreteSetIntCat[dsi_cntr] == 1)
690       {
691 	p.set_BB_INPUT_TYPE(i+numContinuousVars,NOMAD::CATEGORICAL);
692 	if (!discreteSetIntAdj.empty())
693 	  categoricalAdjacency.push_back(discreteSetIntAdj[dsi_cntr]);
694 	else
695 	{
696 	  tmp_categorical_adjacency.reshape(initial_point_set_int[dsi_cntr].size(),
697 					    initial_point_set_int[dsi_cntr].size());
698 	  for (j=0; j<initial_point_set_int[dsi_cntr].size(); j++)
699 	  {
700 	    for (k=0; k<initial_point_set_int[dsi_cntr].size(); k++)
701 	    {
702 	      if (k==j-1 || k==j || k==j+1)
703 		tmp_categorical_adjacency[j][k] = 1;
704 	      else
705 		tmp_categorical_adjacency[j][k] = 0;
706 	    }
707 	  }
708 	  categoricalAdjacency.push_back(tmp_categorical_adjacency);
709 	}
710       }
711       else
712       {
713 	p.set_BB_INPUT_TYPE(i+numContinuousVars,NOMAD::INTEGER);
714 	_lower_bound[i+numContinuousVars] = 0;
715 	_upper_bound[i+numContinuousVars] =
716 	  initial_point_set_int[dsi_cntr].size() - 1;
717       }
718       ++dsi_cntr;
719     }
720     else
721     {
722       _initial_point[i+numContinuousVars] = initial_point_int[i];
723       if (lower_bound_int[i] > -bigIntBoundSize)
724 	_lower_bound[i+numContinuousVars] = lower_bound_int[i];
725       else
726       {
727 	Cerr << "\nError: NomadOptimizer::load_parameters\n"
728 	     << "mesh_adaptive_search requires lower bounds "
729 	     << "for all discrete range variables" << std::endl;
730 	abort_handler(-1);
731       }
732       if (upper_bound_int[i] < bigIntBoundSize)
733 	_upper_bound[i+numContinuousVars] = upper_bound_int[i];
734       else
735       {
736 	Cerr << "\nError: NomadOptimizer::load_parameters\n"
737 	     << "mesh_adaptive_search requires upper bounds "
738 	     << "for all discrete range variables" << std::endl;
739 	abort_handler(-1);
740       }
741       p.set_BB_INPUT_TYPE(i+numContinuousVars,NOMAD::INTEGER);
742     }
743   }
744   for (i=0; i<numDiscreteRealVars; i++) {
745     index = set_value_to_index(initial_point_real[i],
746 			       initial_point_set_real[i]);
747     if (index == _NPOS) {
748       Cerr << "\nError: failure in discrete real set lookup within "
749 	   << "NomadOptimizer::load_parameters(Model &model)" << std::endl;
750       abort_handler(-1);
751     }
752     else {
753       _initial_point[i+numContinuousVars+numDiscreteIntVars] = (int)index;
754     }
755     if (!discreteSetRealCat.empty() && discreteSetRealCat[i] == 1)
756     {
757       p.set_BB_INPUT_TYPE(i+numContinuousVars+numDiscreteIntVars,
758 			  NOMAD::CATEGORICAL);
759       if (!discreteSetRealAdj.empty())
760 	categoricalAdjacency.push_back(discreteSetRealAdj[i]);
761       else
762       {
763 	tmp_categorical_adjacency.reshape(initial_point_set_real[i].size(),
764 					  initial_point_set_real[i].size());
765 	for (j=0; j<initial_point_set_real[i].size(); j++)
766 	{
767 	  for (k=0; k<initial_point_set_real[i].size(); k++)
768 	  {
769 	    if (k==j-1 || k==j || k==j+1)
770 	      tmp_categorical_adjacency[j][k] = 1;
771 	    else
772 	      tmp_categorical_adjacency[j][k] = 0;
773 	  }
774 	}
775 	categoricalAdjacency.push_back(tmp_categorical_adjacency);
776       }
777     }
778     else
779     {
780       p.set_BB_INPUT_TYPE(i+numContinuousVars+numDiscreteIntVars,
781 			  NOMAD::INTEGER);
782       _lower_bound[i+numContinuousVars+numDiscreteIntVars] = 0;
783       _upper_bound[i+numContinuousVars+numDiscreteIntVars] =
784 	initial_point_set_real[i].size() - 1;
785     }
786   }
787   for (i=0; i<numDiscreteStringVars; i++) {
788     index = set_value_to_index(initial_point_string[i],
789 			       initial_point_set_string[i]);
790     if (index == _NPOS) {
791       Cerr << "\nError: failure in discrete string set lookup within "
792 	   << "NomadOptimizer::load_parameters(Model &model)" << std::endl;
793       abort_handler(-1);
794     }
795     else {
796       _initial_point[i+numContinuousVars+numDiscreteIntVars+numDiscreteRealVars] =
797 	(int)index;
798     }
799     p.set_BB_INPUT_TYPE(i+numContinuousVars+numDiscreteIntVars+
800 			numDiscreteRealVars,NOMAD::CATEGORICAL);
801     if (!discreteSetStrAdj.empty())
802       categoricalAdjacency.push_back(discreteSetStrAdj[i]);
803     else
804     {
805       tmp_categorical_adjacency.reshape(initial_point_set_string[i].size(),
806 					initial_point_set_string[i].size());
807       for (j=0; j<initial_point_set_string[i].size(); j++)
808       {
809 	for (k=0; k<initial_point_set_string[i].size(); k++)
810 	{
811 	  if (k==j-1 || k==j || k==j+1)
812 	    tmp_categorical_adjacency[j][k] = 1;
813 	  else
814 	    tmp_categorical_adjacency[j][k] = 0;
815 	}
816       }
817       categoricalAdjacency.push_back(tmp_categorical_adjacency);
818     }
819   }
820 
821   initialPoint = _initial_point;
822   lowerBound = _lower_bound;
823   upperBound = _upper_bound;
824 
825   // Define Output Types
826   // responses.
827   //		objective_functions
828   //		nonlinear_inequality_constraints
829   //		nonlinear_equality_constraints
830 
831   const RealVector& nln_eq_targets
832     = iteratedModel.nonlinear_eq_constraint_targets();
833 
834   numNomadNonlinearIneqConstraints = numNonlinearIneqConstraintsFound;
835 
836   configure_equality_constraints(CONSTRAINT_TYPE::NONLINEAR, numNonlinearIneqConstraints);
837 }
838 
~NomadOptimizer()839 NomadOptimizer::~NomadOptimizer() {};
840 
841 }
842 
843 
844