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: Declaration of wrapper class for NOMAD solver
11 //- Owner:       Patty Hough
12 //- Checked by:
13 //- Version: $Id$
14 
15 
16 #include <DakotaOptimizer.hpp>
17 #include <ProblemDescDB.hpp>
18 
19 #include <algorithm>
20 #include <sstream>
21 
22 #include <nomad.hpp>
23 
24 // Forward Declarations
25 class NomadOptimizer;
26 
27 namespace Dakota {
28 
29   /// Wrapper class for NOMAD Optimizer
30 
31   /**  NOMAD (is a Nonlinear Optimization by Mesh Adaptive Direct
32        search) is a simulation-based optimization package designed
33        to efficiently explore a design space using Mesh Adaptive
34        Search.
35 
36        Mesh Adaptive Direct Search uses Meshes, discretizations of
37        the domain space of variables. It generates multiple meshes,
38        and as its name implies, it also adapts the refinement of
39        the meshes in order to find the best solution of a problem.
40 
41        The objective of each iteration is to find points in a mesh
42        that improves the current solution. If a better solution is
43        not found, the next iteration is done over a finer mesh.
44 
45        Each iteration is composed of two steps: Search and Poll.
46        The Search step finds any point in the mesh in an attempt
47        to find an improvement; while the Poll step generates trial
48        mesh points surrounding the current best current solution.
49 
50        The NomadOptimizer is a wrapper for the NOMAD library. It
51        features the following attributes: \c max_function_evaluations,
52        \c display_format, \c display_all_evaluations, \c function_precision,
53        \c max_iterations.
54   */
55 
56 /**
57  * \brief A version of TraitsBase specialized for Nomad
58  *
59  */
60 
61 class NomadTraits: public TraitsBase
62 {
63   public:
64 
65   /// default constructor
NomadTraits()66   NomadTraits() { }
67 
68   /// destructor
~NomadTraits()69   virtual ~NomadTraits() { }
70 
71   /// A temporary query used in the refactor
is_derived()72   virtual bool is_derived() { return true; }
73 
74   /// Return the flag indicating whether method supports continuous variables
supports_continuous_variables()75   bool supports_continuous_variables() { return true; }
76 
77   /// Return the flag indicating whether method supports discrete variables
supports_discrete_variables()78   bool supports_discrete_variables() { return true; }
79 
80   /// Return the flag indicating whether method supports nonlinear equalities
supports_nonlinear_equality()81   bool supports_nonlinear_equality() { return true; }
82 
83   /// Return the format used for nonlinear equality constraints
nonlinear_equality_format()84   NONLINEAR_EQUALITY_FORMAT nonlinear_equality_format()
85     { return NONLINEAR_EQUALITY_FORMAT::TRUE_EQUALITY; }
86 
87   /// Return the flag indicating whether method supports nonlinear inequalities
supports_nonlinear_inequality()88   bool supports_nonlinear_inequality() { return true; }
89 
90   /// Return the format used for nonlinear inequality constraints
nonlinear_inequality_format()91   NONLINEAR_INEQUALITY_FORMAT nonlinear_inequality_format()
92     { return NONLINEAR_INEQUALITY_FORMAT::ONE_SIDED_UPPER; }
93 };
94 
95 
96 class NomadOptimizer : public Optimizer
97 {
98 public:
99 
100   /// Constructor
101   /** NOMAD Optimizer Constructor
102       @param model DAKOTA Model object
103   */
104   NomadOptimizer(ProblemDescDB& problem_db, Model &model);
105 
106   /// alternate constructor for Iterator instantiations without DB
107   NomadOptimizer(Model& model);
108 
109   /// Destructor
110   ~NomadOptimizer();
111 
112   //
113   //- Heading: Virtual member function redefinitions
114   //
115 
116   /// Calls the NOMAD solver
117   void core_run();
118 
119 private:
120 
121   // Forward Declaration
122   class Evaluator;
123   class Extended_Poll;
124 
125   /// Convenience function for Parameter loading.
126   /** This function takes the Parameters provided by the user
127       in the DAKOTA model.
128         @param model NOMAD Model object
129       Variables for the stuff that must go in the parameters.
130       Will be filled by calling load_parameters after the
131       constructor to capture model recasts.
132   */
133   void load_parameters(Model &model, NOMAD::Parameters &p);
134 
135   /// Total across all types of variables
136   int numTotalVars;
137 
138   /// Number of nonlinear inequality constraints after
139   /// put into the format required by NOMAD
140   int numNomadNonlinearIneqConstraints;
141 
142   /// Algorithm control parameters passed to NOMAD
143   int randomSeed, maxBlackBoxEvals, maxIterations;
144   NOMAD::Double initMesh, minMesh, epsilon, vns;
145 
146   /// Output control parameters passed to NOMAD
147   std::string outputFormat, historyFile;
148   bool displayAll;
149 
150   /// Parameters needed for categorical neighbor construction
151   int numHops;
152   BitArray discreteSetIntCat, discreteSetRealCat;
153   RealMatrixArray discreteSetIntAdj, discreteSetRealAdj, discreteSetStrAdj;
154   RealMatrixArray categoricalAdjacency;
155 
156   /// Pointer to Nomad initial point
157   NOMAD::Point initialPoint;
158 
159   /// Pointer to Nomad upper bounds
160   NOMAD::Point upperBound;
161 
162   /// Pointer to Nomad lower bounds
163   NOMAD::Point lowerBound;
164 
165   /// defines use of surrogate in NOMAD
166   std::string useSurrogate;
167 };
168 
169 ///  NOMAD-based Evaluator class.
170 
171 /**  The NOMAD process requires an evaluation step, which
172      calls the Simulation program. In the simplest version
173      of this call, NOMAD executes the black box executable,
174      which proceeds to write a file in a NOMAD-compatible
175      format, which NOMAD reads to continue the process.
176 
177      Because DAKOTA files are different form NOMAD files,
178      and the simulations processed by DAKOTA already produce
179      DAKOTA-compatible files, we cannot use this method for
180      NOMAD. Instead, we implement the \c NomadEvaluator class,
181      which takes the NOMAD inputs and passes them to DAKOTA's
182      Interface for processing. The evaluator then passes
183      the evaluation Responses into the NOMAD objects for
184      further analysis.
185 */
186 
187 class NomadOptimizer::Evaluator : public NOMAD::Evaluator
188 {
189 private:
190 
191   /// map NOMAD evaluation point to Dakota model
192   void set_variables(const NOMAD::Eval_Point &x) const;
193   /// evaluate the Dakota model (block or not, but don't collect response)
194   void eval_model(bool allow_asynch, const NOMAD::Eval_Point& x) const;
195   /// map Dakota model responses to NOMAD evaluation point
196   void get_responses(const RealVector& ftn_vals, NOMAD::Eval_Point &x) const;
197 
198   Model& _model;
199   int n_cont,n_disc_int, n_disc_real;
200 
201   /// Number of nonlinear constraints after put into Nomad format
202   int numNomadNonlinearIneqConstr, numNomadNonlinearEqConstr;
203 
204   /// map from Dakota constraint number to Nomad constraint number
205   std::vector<int> constrMapIndices;
206 
207   /// multipliers for constraint transformations
208   std::vector<double> constrMapMultipliers;
209 
210   /// offsets for constraint transformations
211   std::vector<double> constrMapOffsets;
212 
213   /// defines use of surrogate in NOMAD
214   std::string useSgte;
215 
216 public:
217 
218   /// Constructor
219   /** NOMAD Evaluator Constructor
220         @param p NOMAD Parameters object
221 	@param model DAKOTA Model object
222   */
223   Evaluator(const NOMAD::Parameters &p, Model& model);
224 
225   /// Destructor
226   ~Evaluator(void);
227 
228   /// Main Evaluation Method
229   /** Method that handles the communication between
230       the NOMAD search process and the Black Box
231       Evaluation managed by DAKOTA's Interface.
232 	@param x Object that contains the points that
233 	         need to evaluated. Once the evaluation
234 		 is completed, this object also stores
235 		 the output back to be read by NOMAD.
236 	@param h_max Current value of the barrier
237 	             parameter. Not used in this
238 		     implementation.
239 	@param count_eval Flag that indicates whether
240 	                  this evaluation counts
241 			  towards the max number of
242 			  evaluations, often set to
243 			  \c false when the evaluation
244 			  does not meet certain costs
245 			  during expensive evaluations.
246 			  Not used in this
247 			  implementation.
248 	@return \c true if the evaluation was successful;
249 	        \c false otherwise.
250   */
251   bool eval_x (NOMAD::Eval_Point &x,
252 	       const NOMAD::Double &h_max,
253 	       bool &count_eval) const;
254 
255   /// multi-point variant of evaluator
256   bool eval_x ( std::list<NOMAD::Eval_Point *>& x,
257 		const NOMAD::Double& h_max,
258 		std::list<bool>& count_eval ) const;
259 
260   /// publishes constraint transformation
set_constraint_map(int numNomadNonlinearIneqConstraints,int numNomadNonlinearEqConstraints,std::vector<int> constraintMapIndices,std::vector<double> constraintMapMultipliers,std::vector<double> constraintMapOffsets)261   void set_constraint_map (int numNomadNonlinearIneqConstraints,
262 			   int numNomadNonlinearEqConstraints,
263 			   std::vector<int> constraintMapIndices,
264 			   std::vector<double> constraintMapMultipliers,
265 			   std::vector<double> constraintMapOffsets)
266   { numNomadNonlinearIneqConstr = numNomadNonlinearIneqConstraints;
267     numNomadNonlinearEqConstr = numNomadNonlinearEqConstraints,
268       constrMapIndices = constraintMapIndices;
269     constrMapMultipliers = constraintMapMultipliers;
270     constrMapOffsets = constraintMapOffsets;}
271 
272   /// publishes surrogate usage
set_surrogate_usage(std::string useSurrogate)273   void set_surrogate_usage (std::string useSurrogate)
274   { useSgte = useSurrogate;}
275 };
276 
277 class NomadOptimizer::Extended_Poll : public NOMAD::Extended_Poll
278 {
279 private:
280 
281   RealMatrixArray &adjacency_matrix;
282   int nHops;
283 
284 public:
285 
286   /// Constructor
Extended_Poll(NOMAD::Parameters & p,RealMatrixArray & categoricalAdjacency,int numHops)287   Extended_Poll(NOMAD::Parameters &p, RealMatrixArray &categoricalAdjacency,
288 		int numHops) : NOMAD::Extended_Poll(p),
289 			       adjacency_matrix(categoricalAdjacency),
290 			       nHops(numHops) {};
291 
292   /// Destructor
~Extended_Poll(void)293   ~Extended_Poll(void){};
294 
295   /// Construct the extended poll points.  Called by NOMAD.
296   void construct_extended_points(const NOMAD::Eval_Point &nomad_point);
297 
298   /// Recursive helper function to construct the multi-hop neighbors
299   /// derived from adjacency matrices and returned to
300   /// construct_extended_points.
301   void construct_multihop_neighbors(NOMAD::Point &base_point,
302 				    NOMAD::Signature point_signature,
303 				    RealMatrixArray::iterator rma_iter,
304 				    size_t last_cat_index, int num_hops);
305 };
306 
307 }  // namespace DAKOTA
308