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:       SNLLOptimizer
10 //- Description: Wrapper class for opt++
11 //- Owner:       Mike Eldred
12 //- Checked by:
13 //- Version: $Id
14 
15 #ifndef SNLL_OPTIMIZER_H
16 #define SNLL_OPTIMIZER_H
17 
18 #include "DakotaOptimizer.hpp"
19 #include "SNLLBase.hpp"
20 
21 namespace OPTPP {
22 class NLF0;
23 class NLF1;
24 class NLF2;
25 class OptPDS;
26 class OptCG;
27 class OptLBFGS;
28 class OptNewton;
29 class OptQNewton;
30 class OptFDNewton;
31 class OptBCNewton;
32 class OptBCQNewton;
33 class OptBCFDNewton;
34 class OptNIPS;
35 class OptQNIPS;
36 class OptFDNIPS;
37 }
38 
39 
40 namespace Dakota {
41 
42 /**
43  * \brief A version of TraitsBase specialized for SNLL optimizers
44  *
45  */
46 class SNLLTraits: public TraitsBase
47 {
48   public:
49 
50   /// default constructor
SNLLTraits()51   SNLLTraits() { }
52 
53   /// destructor
~SNLLTraits()54   virtual ~SNLLTraits() { }
55 
56   /// A temporary query used in the refactor
is_derived()57   virtual bool is_derived() { return true; }
58 
59   // Traits are chosen to be the most common ones across a majority of methods within this TPL.
60 
61   /// Return the value of supportsContinuousVariables
supports_continuous_variables()62   bool supports_continuous_variables() { return true; }
63 
64   /// Return the flag indicating whether method supports linear equalities
supports_linear_equality()65   bool supports_linear_equality() { return true; }
66 
67   /// Return the flag indicating whether method supports linear inequalities
supports_linear_inequality()68   bool supports_linear_inequality() { return true; }
69 
70   /// Return the flag indicating whether method supports nonlinear equalities
supports_nonlinear_equality()71   bool supports_nonlinear_equality() { return true; }
72 
73   /// Return the flag indicating whether method supports nonlinear inequalities
supports_nonlinear_inequality()74   bool supports_nonlinear_inequality() { return true; }
75 
76   /// Return the format used for nonlinear inequality constraints
nonlinear_inequality_format()77   NONLINEAR_INEQUALITY_FORMAT nonlinear_inequality_format()
78     { return NONLINEAR_INEQUALITY_FORMAT::TWO_SIDED; }
79 
80 };
81 
82 
83 /// Wrapper class for the OPT++ optimization library.
84 
85 /** The SNLLOptimizer class provides a wrapper for OPT++, a C++
86     optimization library of nonlinear programming and pattern search
87     techniques from the Computational Sciences and Mathematics
88     Research (CSMR) department at Sandia's Livermore CA site.  It uses
89     a function pointer approach for which passed functions must be
90     either global functions or static member functions.  Any attribute
91     used within static member functions must be either local to that
92     function, a static member, or accessed by static pointer.
93 
94     The user input mappings are as follows: \c max_iterations, \c
95     max_function_evaluations, \c convergence_tolerance, \c max_step,
96     \c gradient_tolerance, \c search_method, and \c search_scheme_size
97     are set using OPT++'s setMaxIter(), setMaxFeval(), setFcnTol(),
98     setMaxStep(), setGradTol(), setSearchStrategy(), and setSSS()
99     member functions, respectively; \c output verbosity is used to
100     toggle OPT++'s debug mode using the setDebug() member function.
101     Internal to OPT++, there are 3 search strategies, while the DAKOTA
102     \c search_method specification supports 4 (\c
103     value_based_line_search, \c gradient_based_line_search, \c
104     trust_region, or \c tr_pds).  The difference stems from the
105     "is_expensive" flag in OPT++.  If the search strategy is
106     LineSearch and "is_expensive" is turned on, then the \c
107     value_based_line_search is used.  Otherwise (the "is_expensive"
108     default is off), the algorithm will use the \c
109     gradient_based_line_search.  Refer to [Meza, J.C., 1994] and to
110     the OPT++ source in the Dakota/packages/OPTPP directory for
111     information on OPT++ class member functions. */
112 class SNLLOptimizer: public Optimizer, public SNLLBase
113 {
114 public:
115 
116   //
117   //- Heading: Constructors and destructor
118   //
119 
120   /// standard constructor
121   SNLLOptimizer(ProblemDescDB& problem_db, Model& model);
122 
123   /// alternate constructor for instantiations "on the fly"
124   SNLLOptimizer(const String& method_string, Model& model);
125 
126   /// alternate constructor for instantiations "on the fly"
127   SNLLOptimizer(const RealVector& initial_pt,
128     const RealVector& var_l_bnds,      const RealVector& var_u_bnds,
129     const RealMatrix& lin_ineq_coeffs, const RealVector& lin_ineq_l_bnds,
130     const RealVector& lin_ineq_u_bnds, const RealMatrix& lin_eq_coeffs,
131     const RealVector& lin_eq_tgts,     const RealVector& nln_ineq_l_bnds,
132     const RealVector& nln_ineq_u_bnds, const RealVector& nln_eq_tgts,
133     void (*user_obj_eval) (int mode, int n, const RealVector& x, double& f,
134 			   RealVector& grad_f, int& result_mode),
135     void (*user_con_eval) (int mode, int n, const RealVector& x, RealVector& g,
136 			   RealMatrix& grad_g, int& result_mode));
137 
138   /// alternate constructor for instantiations "on the fly", also specifying different optimizer properties
139   SNLLOptimizer(const RealVector& initial_pt,
140     const RealVector& var_l_bnds,      const RealVector& var_u_bnds,
141     const RealMatrix& lin_ineq_coeffs, const RealVector& lin_ineq_l_bnds,
142     const RealVector& lin_ineq_u_bnds, const RealMatrix& lin_eq_coeffs,
143     const RealVector& lin_eq_tgts,     const RealVector& nln_ineq_l_bnds,
144     const RealVector& nln_ineq_u_bnds, const RealVector& nln_eq_tgts,
145     void (*user_obj_eval) (int mode, int n, const RealVector& x, double& f,
146          RealVector& grad_f, int& result_mode),
147     void (*user_con_eval) (int mode, int n, const RealVector& x, RealVector& g,
148          RealMatrix& grad_g, int& result_mode),
149     const int max_iter, const int max_fn_evals,
150     const Real conv_tol, const Real grad_tol,
151     Real max_step);
152 
153 
154   ~SNLLOptimizer(); ///< destructor
155 
156   //
157   //- Heading: Virtual member function redefinitions
158   //
159 
160   /// Performs the iterations to determine the optimal solution.
161   void core_run();
162 
163   void reset();
164 
165   void declare_sources();
166 
167 protected:
168 
169   //
170   //- Heading: Virtual member function redefinitions
171   //
172 
173   /// invokes Optimizer::initialize_run(),
174   /// SNLLBase::snll_initialize_run(), and performs other set-up
175   void initialize_run();
176 
177   /// performs data recovery and calls Optimizer::post_run()
178   void post_run(std::ostream& s);
179 
180   /// performs cleanup, restores instances and calls parent finalize
181   void finalize_run();
182 
183 private:
184 
185   //
186   //- Heading: Helper functions
187   //
188 
189   /// instantiate an OPTPP_Q_NEWTON solver using standard settings
190   void default_instantiate_q_newton(
191     void (*obj_eval) (int mode, int n, const RealVector& x, double& f,
192 		      RealVector& grad_f, int& result_mode),
193     void (*con_eval) (int mode, int n, const RealVector& x, RealVector& g,
194 		      RealMatrix& grad_g, int& result_mode) );
195   /// instantiate an OPTPP_NEWTON solver using standard settings
196   void default_instantiate_newton(
197     void (*obj_eval) (int mode, int n, const RealVector& x, double& f,
198 		      RealVector& grad_f, RealSymMatrix& hess_f,
199 		      int& result_mode),
200     void (*con_eval) (int mode, int n, const RealVector& x, RealVector& g,
201 		      RealMatrix& grad_g,
202 		      OPTPP::OptppArray<RealSymMatrix >& hess_g,
203 		      int& result_mode) );
204 
205   //
206   //- Heading: Static member functions required by opt++
207   //
208 
209   //- Fn. evaluation routines which invoke Model::compute_response
210   //- in order to supply f, df/dx, and d^2f/dx^2 to the OPT++ methods.
211 
212   /// objective function evaluator function for OPT++ methods which
213   /// require only function values.
214   static void nlf0_evaluator(int n, const RealVector& x, double& f,
215 			     int& result_mode);
216 
217   /// objective function evaluator function which provides function
218   /// values and gradients to OPT++ methods.
219   static void nlf1_evaluator(int mode, int n, const RealVector& x,
220 			     double& f, RealVector& grad_f, int& result_mode);
221 
222   /// objective function evaluator function which provides function
223   /// values, gradients, and Hessians to OPT++ methods.
224   static void nlf2_evaluator(int mode, int n, const RealVector& x,
225 			     double& f, RealVector& grad_f,
226 			     RealSymMatrix& hess_f, int& result_mode);
227 
228   //- Constraint evaluation routines that invoke Model::compute_response
229 
230   /// constraint evaluator function for OPT++ methods which require
231   /// only constraint values.
232   static void constraint0_evaluator(int n, const RealVector& x,
233 				    RealVector& g, int& result_mode);
234 
235   /// constraint evaluator function which provides constraint
236   /// values and gradients to OPT++ methods.
237   static void constraint1_evaluator(int mode, int n, const RealVector& x,
238 				    RealVector& g, RealMatrix& grad_g,
239 				    int& result_mode);
240 
241   /// constraint evaluator function which provides constraint
242   /// values, gradients, and Hessians to OPT++ methods.
243   static void constraint2_evaluator(int mode, int n, const RealVector& x,
244 				    RealVector& g, RealMatrix& grad_g,
245 				    OPTPP::OptppArray<RealSymMatrix >& hess_g,
246 				    int& result_mode);
247 
248   //
249   //- Heading: Data
250   //
251 
252   /// pointer to the active object instance used within the static evaluator
253   /// functions in order to avoid the need for static data
254   static SNLLOptimizer* snllOptInstance;
255   /// pointer to the previously active object instance used for
256   /// restoration in the case of iterator/model recursion
257   SNLLOptimizer* prevSnllOptInstance;
258 
259   //- Base class pointers to OPT++ objects
260   OPTPP::NLP0   *nlfObjective;  ///< objective  NLF base class pointer
261   OPTPP::NLP0   *nlfConstraint; ///< constraint NLF base class pointer
262   OPTPP::NLP    *nlpConstraint; ///< constraint NLP pointer
263 
264   //- additional pointers needed for option specification
265   /// pointer to objective NLF for nongradient optimizers
266   OPTPP::NLF0   *nlf0;
267   /// pointer to objective NLF for (analytic) gradient-based optimizers
268   OPTPP::NLF1   *nlf1;
269   /// pointer to constraint NLF for (analytic) gradient-based optimizers
270   OPTPP::NLF1   *nlf1Con;
271   /// pointer to objective NLF for (finite diff) gradient-based optimizers
272   OPTPP::FDNLF1 *fdnlf1;
273   /// pointer to constraint NLF for (finite diff) gradient-based optimizers
274   OPTPP::FDNLF1 *fdnlf1Con;
275   /// pointer to objective NLF for full Newton optimizers
276   OPTPP::NLF2   *nlf2;
277   /// pointer to constraint NLF for full Newton optimizers
278   OPTPP::NLF2   *nlf2Con;
279 
280   OPTPP::OptimizeClass *theOptimizer; ///< optimizer base class pointer
281   //- additional pointers needed for option specification
282   OPTPP::OptPDS        *optpds;       ///< PDS optimizer pointer
283   OPTPP::OptCG         *optcg;        ///< CG optimizer pointer
284   OPTPP::OptLBFGS      *optlbfgs;     ///< L-BFGS optimizer pointer
285   OPTPP::OptNewton     *optnewton;    ///< Newton optimizer pointer
286   OPTPP::OptQNewton    *optqnewton;   ///< Quasi-Newton optimizer pointer
287   OPTPP::OptFDNewton   *optfdnewton;  ///< Finite Difference Newton opt pointer
288   OPTPP::OptBCNewton   *optbcnewton;  ///< Bound constrained Newton opt pointer
289   OPTPP::OptBCQNewton  *optbcqnewton; ///< Bnd constrained Quasi-Newton opt ptr
290   OPTPP::OptBCFDNewton *optbcfdnewton;///< Bnd constrained FD-Newton opt ptr
291   OPTPP::OptNIPS       *optnips;      ///< NIPS optimizer pointer
292   OPTPP::OptQNIPS      *optqnips;     ///< Quasi-Newton NIPS optimizer pointer
293   OPTPP::OptFDNIPS     *optfdnips;    ///< Finite Difference NIPS opt pointer
294 
295   /// flag for iteration mode: "model" (normal usage) or "user_functions"
296   /// (user-supplied functions mode for "on the fly" instantiations).
297   /// NonDReliability currently uses the user_functions mode.
298   String setUpType;
299   /// holds initial point passed in for "user_functions" mode.
300   RealVector initialPoint;
301   /// holds variable lower bounds passed in for "user_functions" mode.
302   RealVector lowerBounds;
303   /// holds variable upper bounds passed in for "user_functions" mode.
304   RealVector upperBounds;
305 };
306 
307 } // namespace Dakota
308 
309 #endif
310