1 // @HEADER
2 // ************************************************************************
3 //
4 //               Rapid Optimization Library (ROL) Package
5 //                 Copyright (2014) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact lead developers:
38 //              Drew Kouri   (dpkouri@sandia.gov) and
39 //              Denis Ridzal (dridzal@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
44 #ifndef ROL_OBJECTIVE_H
45 #define ROL_OBJECTIVE_H
46 
47 #include "ROL_Vector.hpp"
48 #include "ROL_Types.hpp"
49 #include <iostream>
50 
51 /** @ingroup func_group
52     \class ROL::Objective
53     \brief Provides the interface to evaluate objective functions.
54 
55     ROL's objective function interface is designed for Fr$eacute;chet differentiable
56     functionals \f$f:\mathcal{X}\to\mathbb{R}\f$, where \f$\mathcal{X}\f$ is a Banach
57     space.  The basic operator interace, to be implemented by the user, requires:
58     \li #value -- objective function evaluation.
59 
60     It is strongly recommended that the user additionally overload:
61     \li #gradient -- the objective function gradient -- the default is a finite-difference approximation;
62     \li #hessVec  -- the action of the Hessian -- the default is a finite-difference approximation.
63 
64     The user may also overload:
65     \li #update     -- update the objective function at each new iteration;
66     \li #dirDeriv   -- compute the directional derivative -- the default is a finite-difference approximation;
67     \li #invHessVec -- the action of the inverse Hessian;
68     \li #precond    -- the action of a preconditioner for the Hessian.
69 
70     ---
71 */
72 
73 
74 namespace ROL {
75 
76 template <class Real>
77 class Objective {
78 public:
79 
~Objective()80   virtual ~Objective() {}
81 
82   /** \brief Update objective function.
83 
84       This function updates the objective function at new iterations.
85       @param[in]          x      is the new iterate.
86       @param[in]          flag   is true if the iterate has changed.
87       @param[in]          iter   is the outer algorithm iterations count.
88   */
update(const Vector<Real> & x,bool flag=true,int iter=-1)89   virtual void update( const Vector<Real> &x, bool flag = true, int iter = -1 ) {
90     ROL_UNUSED(x);
91     ROL_UNUSED(flag);
92     ROL_UNUSED(iter);
93   }
94 
95   /** \brief Compute value.
96 
97       This function returns the objective function value.
98       @param[in]          x   is the current iterate.
99       @param[in]          tol is a tolerance for inexact objective function computation.
100   */
101   virtual Real value( const Vector<Real> &x, Real &tol ) = 0;
102 
103   /** \brief Compute gradient.
104 
105       This function returns the objective function gradient.
106       @param[out]         g   is the gradient.
107       @param[in]          x   is the current iterate.
108       @param[in]          tol is a tolerance for inexact objective function computation.
109 
110       The default implementation is a finite-difference approximation based on the function value.
111       This requires the definition of a basis \f$\{\phi_i\}\f$ for the optimization vectors x and
112       the definition of a basis \f$\{\psi_j\}\f$ for the dual optimization vectors (gradient vectors g).
113       The bases must be related through the Riesz map, i.e., \f$ R \{\phi_i\} = \{\psi_j\}\f$,
114       and this must be reflected in the implementation of the ROL::Vector::dual() method.
115   */
116   virtual void gradient( Vector<Real> &g, const Vector<Real> &x, Real &tol ) ;
117 
118   /** \brief Compute directional derivative.
119 
120       This function returns the directional derivative of the objective function in the \f$d\f$ direction.
121       @param[in]          x   is the current iterate.
122       @param[in]          d   is the direction.
123       @param[in]          tol is a tolerance for inexact objective function computation.
124   */
125   virtual Real dirDeriv( const Vector<Real> &x, const Vector<Real> &d, Real &tol ) ;
126 
127   /** \brief Apply Hessian approximation to vector.
128 
129       This function applies the Hessian of the objective function to the vector \f$v\f$.
130       @param[out]         hv  is the the action of the Hessian on \f$v\f$.
131       @param[in]          v   is the direction vector.
132       @param[in]          x   is the current iterate.
133       @param[in]          tol is a tolerance for inexact objective function computation.
134   */
135   virtual void hessVec( Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &x, Real &tol );
136 
137   /** \brief Apply inverse Hessian approximation to vector.
138 
139       This function applies the inverse Hessian of the objective function to the vector \f$v\f$.
140       @param[out]         hv  is the action of the inverse Hessian on \f$v\f$.
141       @param[in]          v   is the direction vector.
142       @param[in]          x   is the current iterate.
143       @param[in]          tol is a tolerance for inexact objective function computation.
144   */
invHessVec(Vector<Real> & hv,const Vector<Real> & v,const Vector<Real> & x,Real & tol)145   virtual void invHessVec( Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &x, Real &tol ) {
146     ROL_UNUSED(hv);
147     ROL_UNUSED(v);
148     ROL_UNUSED(x);
149     ROL_UNUSED(tol);
150     ROL_TEST_FOR_EXCEPTION(true, std::invalid_argument,
151       ">>> ERROR (ROL::Objective): invHessVec not implemented!");
152     //hv.set(v.dual());
153   }
154 
155   /** \brief Apply preconditioner to vector.
156 
157       This function applies a preconditioner for the Hessian of the objective function to the vector \f$v\f$.
158       @param[out]         Pv  is the action of the Hessian preconditioner on \f$v\f$.
159       @param[in]          v   is the direction vector.
160       @param[in]          x   is the current iterate.
161       @param[in]          tol is a tolerance for inexact objective function computation.
162   */
precond(Vector<Real> & Pv,const Vector<Real> & v,const Vector<Real> & x,Real & tol)163   virtual void precond( Vector<Real> &Pv, const Vector<Real> &v, const Vector<Real> &x, Real &tol ) {
164     ROL_UNUSED(x);
165     ROL_UNUSED(tol);
166     Pv.set(v.dual());
167   }
168 
169   /** \brief Finite-difference gradient check.
170 
171       This function computes a sequence of one-sided finite-difference checks for the gradient.
172       At each step of the sequence, the finite difference step size is decreased.  The output
173       compares the error
174       \f[
175           \left| \frac{f(x+td) - f(x)}{t} - \langle \nabla f(x),d\rangle_{\mathcal{X}^*,\mathcal{X}}\right|.
176       \f]
177       if the approximation is first order. More generally, difference approximation is
178       \f[
179           \frac{1}{t} \sum\limits_{i=1}^m w_i f(x+t c_i d)
180       \f]
181       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
182       @param[in]      x             is an optimization variable.
183       @param[in]      d             is a direction vector.
184       @param[in]      printToStream is a flag that turns on/off output.
185       @param[out]     outStream     is the output stream.
186       @param[in]      numSteps      is a parameter which dictates the number of finite difference steps.
187       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
188   */
checkGradient(const Vector<Real> & x,const Vector<Real> & d,const bool printToStream=true,std::ostream & outStream=std::cout,const int numSteps=ROL_NUM_CHECKDERIV_STEPS,const int order=1)189   virtual std::vector<std::vector<Real> > checkGradient( const Vector<Real> &x,
190                                                          const Vector<Real> &d,
191                                                          const bool printToStream = true,
192                                                          std::ostream & outStream = std::cout,
193                                                          const int numSteps = ROL_NUM_CHECKDERIV_STEPS,
194                                                          const int order = 1 ) {
195     return checkGradient(x, x.dual(), d, printToStream, outStream, numSteps, order);
196   }
197 
198   /** \brief Finite-difference gradient check.
199 
200       This function computes a sequence of one-sided finite-difference checks for the gradient.
201       At each step of the sequence, the finite difference step size is decreased.  The output
202       compares the error
203       \f[
204           \left| \frac{f(x+td) - f(x)}{t} - \langle \nabla f(x),d\rangle_{\mathcal{X}^*,\mathcal{X}}\right|.
205       \f]
206       if the approximation is first order. More generally, difference approximation is
207       \f[
208           \frac{1}{t} \sum\limits_{i=1}^m w_i f(x+t c_i d)
209       \f]
210       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
211 
212       @param[in]      x             is an optimization variable.
213       @param[in]      g             is used to create a temporary gradient vector.
214       @param[in]      d             is a direction vector.
215       @param[in]      printToStream is a flag that turns on/off output.
216       @param[out]     outStream     is the output stream.
217       @param[in]      numSteps      is a parameter which dictates the number of finite difference steps.
218       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
219   */
220   virtual std::vector<std::vector<Real> > checkGradient( const Vector<Real> &x,
221                                                          const Vector<Real> &g,
222                                                          const Vector<Real> &d,
223                                                          const bool printToStream = true,
224                                                          std::ostream & outStream = std::cout,
225                                                          const int numSteps = ROL_NUM_CHECKDERIV_STEPS,
226                                                          const int order = 1 );
227 
228 
229   /** \brief Finite-difference gradient check with specified step sizes.
230 
231       This function computes a sequence of one-sided finite-difference checks for the gradient.
232       At each step of the sequence, the finite difference step size is decreased.  The output
233       compares the error
234       \f[
235           \left| \frac{f(x+td) - f(x)}{t} - \langle \nabla f(x),d\rangle_{\mathcal{X}^*,\mathcal{X}}\right|.
236       \f]
237       if the approximation is first order. More generally, difference approximation is
238       \f[
239           \frac{1}{t} \sum\limits_{i=1}^m w_i f(x+t c_i d)
240       \f]
241       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
242       @param[in]      x             is an optimization variable.
243       @param[in]      d             is a direction vector.
244       @param[in]      steps         is vector of steps of user-specified size.
245       @param[in]      printToStream is a flag that turns on/off output.
246       @param[out]     outStream     is the output stream.
247       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
248   */
checkGradient(const Vector<Real> & x,const Vector<Real> & d,const std::vector<Real> & steps,const bool printToStream=true,std::ostream & outStream=std::cout,const int order=1)249   virtual std::vector<std::vector<Real> > checkGradient( const Vector<Real> &x,
250                                                          const Vector<Real> &d,
251                                                          const std::vector<Real> &steps,
252                                                          const bool printToStream = true,
253                                                          std::ostream & outStream = std::cout,
254                                                          const int order = 1 ) {
255 
256     return checkGradient(x, x.dual(), d, steps, printToStream, outStream, order);
257 
258   }
259 
260 
261   /** \brief Finite-difference gradient check with specified step sizes.
262 
263       This function computes a sequence of one-sided finite-difference checks for the gradient.
264       At each step of the sequence, the finite difference step size is decreased.  The output
265       compares the error
266       \f[
267           \left| \frac{f(x+td) - f(x)}{t} - \langle \nabla f(x),d\rangle_{\mathcal{X}^*,\mathcal{X}}\right|.
268       \f]
269       if the approximation is first order. More generally, difference approximation is
270       \f[
271           \frac{1}{t} \sum\limits_{i=1}^m w_i f(x+t c_i d)
272       \f]
273       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
274 
275       @param[in]      x             is an optimization variable.
276       @param[in]      g             is used to create a temporary gradient vector.
277       @param[in]      d             is a direction vector.
278       @param[in]      steps         is vector of steps of user-specified size.
279       @param[in]      printToStream is a flag that turns on/off output.
280       @param[out]     outStream     is the output stream.
281       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
282   */
283   virtual std::vector<std::vector<Real> > checkGradient( const Vector<Real> &x,
284                                                          const Vector<Real> &g,
285                                                          const Vector<Real> &d,
286                                                          const std::vector<Real> &steps,
287                                                          const bool printToStream = true,
288                                                          std::ostream & outStream = std::cout,
289                                                          const int order = 1 );
290 
291   /** \brief Finite-difference Hessian-applied-to-vector check.
292 
293       This function computes a sequence of one-sided finite-difference checks for the Hessian.
294       At each step of the sequence, the finite difference step size is decreased.  The output
295       compares the error
296       \f[
297           \left\| \frac{\nabla f(x+tv) - \nabla f(x)}{t} - \nabla^2 f(x)v\right\|_{\mathcal{X}^*},
298       \f]
299       if the approximation is first order. More generally, difference approximation is
300       \f[
301           \frac{1}{t} \sum\limits_{i=1}^m w_i \nabla f(x+t c_i v),
302       \f]
303       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
304       @param[in]      x             is an optimization variable.
305       @param[in]      v             is a direction vector.
306       @param[in]      printToStream is a flag that turns on/off output.
307       @param[out]     outStream     is the output stream.
308       @param[in]      numSteps      is a parameter which dictates the number of finite difference steps.
309       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
310   */
checkHessVec(const Vector<Real> & x,const Vector<Real> & v,const bool printToStream=true,std::ostream & outStream=std::cout,const int numSteps=ROL_NUM_CHECKDERIV_STEPS,const int order=1)311   virtual std::vector<std::vector<Real> > checkHessVec( const Vector<Real> &x,
312                                                         const Vector<Real> &v,
313                                                         const bool printToStream = true,
314                                                         std::ostream & outStream = std::cout,
315                                                         const int numSteps = ROL_NUM_CHECKDERIV_STEPS,
316                                                         const int order = 1 ) {
317 
318     return checkHessVec(x, x.dual(), v, printToStream, outStream, numSteps, order);
319 
320   }
321 
322   /** \brief Finite-difference Hessian-applied-to-vector check.
323 
324       This function computes a sequence of one-sided finite-difference checks for the Hessian.
325       At each step of the sequence, the finite difference step size is decreased.  The output
326       compares the error
327       \f[
328           \left\| \frac{\nabla f(x+tv) - \nabla f(x)}{t} - \nabla^2 f(x)v\right\|_{\mathcal{X}^*},
329       \f]
330       if the approximation is first order. More generally, difference approximation is
331       \f[
332           \frac{1}{t} \sum\limits_{i=1}^m w_i \nabla f(x+t c_i v),
333       \f]
334       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
335       @param[in]      x             is an optimization variable.
336       @param[in]      hv            is used to create temporary gradient and Hessian-times-vector vectors.
337       @param[in]      v             is a direction vector.
338       @param[in]      printToStream is a flag that turns on/off output.
339       @param[out]     outStream     is the output stream.
340       @param[in]      numSteps      is a parameter which dictates the number of finite difference steps.
341       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
342   */
343   virtual std::vector<std::vector<Real> > checkHessVec( const Vector<Real> &x,
344                                                         const Vector<Real> &hv,
345                                                         const Vector<Real> &v,
346                                                         const bool printToStream = true,
347                                                         std::ostream & outStream = std::cout,
348                                                         const int numSteps = ROL_NUM_CHECKDERIV_STEPS,
349                                                         const int order = 1) ;
350 
351 
352   /** \brief Finite-difference Hessian-applied-to-vector check with specified step sizes.
353 
354       This function computes a sequence of one-sided finite-difference checks for the Hessian.
355       At each step of the sequence, the finite difference step size is decreased.  The output
356       compares the error
357       \f[
358           \left\| \frac{\nabla f(x+tv) - \nabla f(x)}{t} - \nabla^2 f(x)v\right\|_{\mathcal{X}^*},
359       \f]
360       if the approximation is first order. More generally, difference approximation is
361       \f[
362           \frac{1}{t} \sum\limits_{i=1}^m w_i \nabla f(x+t c_i v),
363       \f]
364       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
365       @param[in]      x             is an optimization variable.
366       @param[in]      v             is a direction vector.
367       @param[in]      steps         is vector of steps of user-specified size.
368       @param[in]      printToStream is a flag that turns on/off output.
369       @param[out]     outStream     is the output stream.
370       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
371   */
checkHessVec(const Vector<Real> & x,const Vector<Real> & v,const std::vector<Real> & steps,const bool printToStream=true,std::ostream & outStream=std::cout,const int order=1)372   virtual std::vector<std::vector<Real> > checkHessVec( const Vector<Real> &x,
373                                                         const Vector<Real> &v,
374                                                         const std::vector<Real> &steps,
375                                                         const bool printToStream = true,
376                                                         std::ostream & outStream = std::cout,
377                                                         const int order = 1 ) {
378 
379     return checkHessVec(x, x.dual(), v, steps, printToStream, outStream, order);
380 
381   }
382 
383   /** \brief Finite-difference Hessian-applied-to-vector check with specified step sizes.
384 
385       This function computes a sequence of one-sided finite-difference checks for the Hessian.
386       At each step of the sequence, the finite difference step size is decreased.  The output
387       compares the error
388       \f[
389           \left\| \frac{\nabla f(x+tv) - \nabla f(x)}{t} - \nabla^2 f(x)v\right\|_{\mathcal{X}^*},
390       \f]
391       if the approximation is first order. More generally, difference approximation is
392       \f[
393           \frac{1}{t} \sum\limits_{i=1}^m w_i \nabla f(x+t c_i v),
394       \f]
395       where m = order+1, \f$w_i\f$ are the difference weights and \f$c_i\f$ are the difference steps
396       @param[in]      x             is an optimization variable.
397       @param[in]      hv            is used to create temporary gradient and Hessian-times-vector vectors.
398       @param[in]      v             is a direction vector.
399       @param[in]      steps         is vector of steps of user-specified size.
400       @param[in]      printToStream is a flag that turns on/off output.
401       @param[out]     outStream     is the output stream.
402       @param[in]      order         is the order of the finite difference approximation (1,2,3,4)
403   */
404   virtual std::vector<std::vector<Real> > checkHessVec( const Vector<Real> &x,
405                                                         const Vector<Real> &hv,
406                                                         const Vector<Real> &v,
407                                                         const std::vector<Real> &steps,
408                                                         const bool printToStream = true,
409                                                         std::ostream & outStream = std::cout,
410                                                         const int order = 1) ;
411 
412 
413   /** \brief Hessian symmetry check.
414 
415       This function checks the symmetry of the Hessian by comparing
416       \f[
417          \langle \nabla^2f(x)v,w\rangle_{\mathcal{X}^*,\mathcal{X}}
418          \quad\text{and}\quad
419          \langle \nabla^2f(x)w,v\rangle_{\mathcal{X}^*,\mathcal{X}}.
420       \f]
421       @param[in]      x             is an optimization variable.
422       @param[in]      v             is a direction vector.
423       @param[in]      w             is a direction vector.
424       @param[in]      printToStream is a flag that turns on/off output.
425       @param[out]     outStream     is the output stream.
426   */
checkHessSym(const Vector<Real> & x,const Vector<Real> & v,const Vector<Real> & w,const bool printToStream=true,std::ostream & outStream=std::cout)427   virtual std::vector<Real> checkHessSym( const Vector<Real> &x,
428                                           const Vector<Real> &v,
429                                           const Vector<Real> &w,
430                                           const bool printToStream = true,
431                                           std::ostream & outStream = std::cout ) {
432 
433     return checkHessSym(x, x.dual(), v, w, printToStream, outStream);
434 
435   }
436 
437   /** \brief Hessian symmetry check.
438 
439       This function checks the symmetry of the Hessian by comparing
440       \f[
441          \langle \nabla^2f(x)v,w\rangle_{\mathcal{X}^*,\mathcal{X}}
442          \quad\text{and}\quad
443          \langle \nabla^2f(x)w,v\rangle_{\mathcal{X}^*,\mathcal{X}}.
444       \f]
445       @param[in]      x             is an optimization variable.
446       @param[in]      hv            is used to create temporary Hessian-times-vector vectors.
447       @param[in]      v             is a direction vector.
448       @param[in]      w             is a direction vector.
449       @param[in]      printToStream is a flag that turns on/off output.
450       @param[out]     outStream     is the output stream.
451   */
452   virtual std::vector<Real> checkHessSym( const Vector<Real> &x,
453                                           const Vector<Real> &hv,
454                                           const Vector<Real> &v,
455                                           const Vector<Real> &w,
456                                           const bool printToStream = true,
457                                           std::ostream & outStream = std::cout );
458 
459 // Definitions for parametrized (stochastic) objective functions
460 private:
461   std::vector<Real> param_;
462 
463 protected:
getParameter(void) const464   const std::vector<Real> getParameter(void) const {
465     return param_;
466   }
467 
468 public:
setParameter(const std::vector<Real> & param)469   virtual void setParameter(const std::vector<Real> &param) {
470     param_.assign(param.begin(),param.end());
471   }
472 
473 }; // class Objective
474 
475 } // namespace ROL
476 
477 // include templated definitions
478 #include <ROL_ObjectiveDef.hpp>
479 
480 #endif
481