ROL
ROL_Fletcher.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Rapid Optimization Library (ROL) Package
4 //
5 // Copyright 2014 NTESS and the ROL contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef ROL_FLETCHER_H
11 #define ROL_FLETCHER_H
12 
13 #include "ROL_FletcherBase.hpp"
14 #include "ROL_Objective.hpp"
15 #include "ROL_Constraint.hpp"
16 #include "ROL_Vector.hpp"
17 #include "ROL_Types.hpp"
18 #include "ROL_Ptr.hpp"
19 #include "ROL_Krylov.hpp"
21 #include <iostream>
22 
23 namespace ROL {
24 
25 template <class Real>
26 class Fletcher : public FletcherBase<Real> {
27 private:
28  // Required for Fletcher penalty function definition
31 
34 
35  // Evaluation counters
39 
40  using FletcherBase<Real>::fPhi_; // value of penalty function
41  using FletcherBase<Real>::gPhi_; // gradient of penalty function
42 
43  using FletcherBase<Real>::y_; // multiplier estimate
44 
45  using FletcherBase<Real>::fval_; // value of objective function
46  using FletcherBase<Real>::g_; // gradient of objective value
47  using FletcherBase<Real>::c_; // constraint value
48  using FletcherBase<Real>::scaledc_; // penaltyParameter_ * c_
49  using FletcherBase<Real>::gL_; // gradient of Lagrangian (g - A*y)
50 
51  using FletcherBase<Real>::cnorm_; // norm of constraint violation
52 
59 
60  using FletcherBase<Real>::delta_; // regularization parameter
61 
63 
64  // Temporaries
65  Ptr<Vector<Real> > Tv_; // Temporary for matvecs
66  Ptr<Vector<Real> > w_; // first component of augmented system solve solution
67  Ptr<Vector<Real> > v_; // second component of augmented system solve solution
68  Ptr<Vector<Real> > wg_; // first component of augmented system solve solution for gradient
69  Ptr<Vector<Real> > vg_; // second component of augmented system solve solution for gradient
70 
71  Ptr<Vector<Real> > xzeros_; // zero vector
72  Ptr<Vector<Real> > czeros_; // zero vector
73 
75 
76  using FletcherBase<Real>::multSolverError_; // Error from augmented system solve in value()
77  using FletcherBase<Real>::gradSolveError_; // Error from augmented system solve in gradient()
78 
79  // For Augmented system solves
92 
93  class AugSystem : public LinearOperator<Real> {
94  private:
95  const Ptr<Constraint<Real> > con_;
96  const Ptr<const Vector<Real> > x_;
97  const Real delta_;
98  public:
99  AugSystem(const Ptr<Constraint<Real> > &con,
100  const Ptr<const Vector<Real> > &x,
101  const Real delta) : con_(con), x_(x), delta_(delta) {}
102 
103  void apply(Vector<Real> &Hv, const Vector<Real> &v, Real &tol) const {
104  PartitionedVector<Real> &Hvp = dynamic_cast<PartitionedVector<Real>&>(Hv);
105  const PartitionedVector<Real> &vp = dynamic_cast<const PartitionedVector<Real>&>(v);
106 
107  con_->applyAdjointJacobian(*(Hvp.get(0)), *(vp.get(1)), *x_, tol);
108  Hvp.get(0)->plus(*(vp.get(0)));
109 
110  con_->applyJacobian(*(Hvp.get(1)), *(vp.get(0)), *x_, tol);
111  Hvp.get(1)->axpy(-delta_*delta_, *(vp.get(1)));
112  }
113  };
114 
115  class AugSystemPrecond : public LinearOperator<Real> {
116  private:
117  const Ptr<Constraint<Real> > con_;
118  const Ptr<const Vector<Real> > x_;
119  public:
121  const Ptr<const Vector<Real> > x) : con_(con), x_(x) {}
122 
123  void apply(Vector<Real> &Hv, const Vector<Real> &v, Real &tol) const {
124  Hv.set(v.dual());
125  }
126  void applyInverse(Vector<Real> &Hv, const Vector<Real> &v, Real &tol) const {
127  Real zero(0);
128  PartitionedVector<Real> &Hvp = dynamic_cast<PartitionedVector<Real>&>(Hv);
129  const PartitionedVector<Real> &vp = dynamic_cast<const PartitionedVector<Real>&>(v);
130 
131  Hvp.set(0, *(vp.get(0)));
132  // Second x should be dual, but unused?
133  con_->applyPreconditioner(*(Hvp.get(1)),*(vp.get(1)),*x_,*x_, zero);
134  }
135  };
136 
137 public:
138  Fletcher(const ROL::Ptr<Objective<Real> > &obj,
139  const ROL::Ptr<Constraint<Real> > &con,
140  const Vector<Real> &optVec,
141  const Vector<Real> &conVec,
142  ROL::ParameterList &parlist)
143  : FletcherBase<Real>(obj, con) {
144 
145  gPhi_ = optVec.dual().clone();
146  y_ = conVec.dual().clone();
147  g_ = optVec.dual().clone();
148  gL_ = optVec.dual().clone();
149  c_ = conVec.clone();
150  scaledc_ = conVec.clone();
151 
152  Tv_ = optVec.dual().clone();
153  w_ = optVec.dual().clone();
154  v_ = conVec.dual().clone();
155  wg_ = optVec.dual().clone();
156  vg_ = conVec.dual().clone();
157 
158  xzeros_ = optVec.dual().clone();
159  xzeros_->zero();
160  czeros_ = conVec.clone();
161  czeros_->zero();
162 
163  v1_ = optVec.dual().clone();
164  v2_ = conVec.dual().clone();
165  vv_ = makePtr<PartitionedVector<Real>>(std::vector<Ptr<Vector<Real>> >({v1_, v2_}));
166 
167  w1_ = optVec.dual().clone();
168  w2_ = conVec.dual().clone();
169  ww_ = makePtr<PartitionedVector<Real>>(std::vector<Ptr<Vector<Real>> >({w1_, w2_}));
170 
171  b1_ = optVec.dual().clone();
172  b2_ = conVec.clone();
173  bb_ = makePtr<PartitionedVector<Real>>(std::vector<Ptr<Vector<Real>> >({b1_, b2_}));
174 
175  ROL::ParameterList& sublist = parlist.sublist("Step").sublist("Fletcher");
176  HessianApprox_ = sublist.get("Level of Hessian Approximation", 0);
177  penaltyParameter_ = sublist.get("Penalty Parameter", 1.0);
178  quadPenaltyParameter_ = sublist.get("Quadratic Penalty Parameter", 0.0);
179 
180  delta_ = sublist.get("Regularization Parameter", 0.0);
181 
182  useInexact_ = sublist.get("Inexact Solves", false);
183 
184  ROL::ParameterList krylovList;
185  Real atol = static_cast<Real>(1e-12);
186  Real rtol = static_cast<Real>(1e-2);
187  krylovList.sublist("General").sublist("Krylov").set("Type", "GMRES");
188  krylovList.sublist("General").sublist("Krylov").set("Absolute Tolerance", atol);
189  krylovList.sublist("General").sublist("Krylov").set("Relative Tolerance", rtol);
190  krylovList.sublist("General").sublist("Krylov").set("Iteration Limit", 200);
191  krylov_ = KrylovFactory<Real>(krylovList);
192  }
193 
194  void update( const Vector<Real> &x, bool flag = true, int iter = -1 ) {
195  obj_->update(x,flag,iter);
196  con_->update(x,flag,iter);
197  isValueComputed_ = (flag ? false : isValueComputed_);
198  isGradientComputed_ = (flag ? false : isGradientComputed_);
199  isMultiplierComputed_ = (flag ? false : isMultiplierComputed_);
200  isObjValueComputed_ = (flag ? false : isObjValueComputed_);
201  isObjGradComputed_ = (flag ? false : isObjGradComputed_);
202  isConValueComputed_ = (flag ? false : isConValueComputed_);
203  }
204 
205  Real value( const Vector<Real> &x, Real &tol ) {
206  if( isValueComputed_ && multSolverError_*cnorm_ <= tol) {
207  tol = multSolverError_*cnorm_;
208  return fPhi_;
209  }
210 
211  Real zero(0);
212 
213  // Reset tolerances
214  Real origTol = tol;
215  Real tol2 = origTol;
216 
217  FletcherBase<Real>::objValue(x, tol2); tol2 = origTol;
218  multSolverError_ = origTol / (static_cast<Real>(2) * std::max(static_cast<Real>(1), cnorm_));
220  tol = multSolverError_*cnorm_;
221 
222  fPhi_ = fval_ - c_->dot(y_->dual());
223 
224  if( quadPenaltyParameter_ > zero ) {
225  fPhi_ = fPhi_ + Real(0.5)*quadPenaltyParameter_*(c_->dot(c_->dual()));
226  }
227 
228  isValueComputed_ = true;
229 
230  return fPhi_;
231  }
232 
233  void gradient( Vector<Real> &g, const Vector<Real> &x, Real &tol ) {
234  if( isGradientComputed_ && gradSolveError_ <= tol) {
235  tol = gradSolveError_;
236  g.set(*gPhi_);
237  return;
238  }
239 
240  Real zero(0);
241 
242  // Reset tolerances
243  Real origTol = tol;
244  Real tol2 = origTol;
245 
246  gradSolveError_ = origTol / static_cast<Real>(2);
248 
249  bool refine = isGradientComputed_;
250 
251  // gPhi = sum y_i H_i w + sigma w + sum v_i H_i gL - H w + gL
252  solveAugmentedSystem( *wg_, *vg_, *xzeros_, *c_, x, gradSolveError_, refine );
254  tol = gradSolveError_;
255 
256  con_->applyAdjointHessian( *gPhi_, *y_, *wg_, x, tol2 ); tol2 = origTol;
257  gPhi_->axpy( penaltyParameter_, *wg_ );
258 
259  obj_->hessVec( *Tv_, *wg_, x, tol2 ); tol2 = origTol;
260  gPhi_->axpy( static_cast<Real>(-1), *Tv_ );
261 
262  con_->applyAdjointHessian( *Tv_, *vg_, *gL_, x, tol2 ); tol2 = origTol;
263  gPhi_->plus( *Tv_ );
264 
265  gPhi_->plus( *gL_ );
266 
267  if( quadPenaltyParameter_ > zero ) {
268  con_->applyAdjointJacobian( *Tv_, *c_, x, tol2 ); tol2 = origTol;
269  gPhi_->axpy( quadPenaltyParameter_, *Tv_ );
270  }
271 
272  g.set(*gPhi_);
273  isGradientComputed_ = true;
274  }
275 
276  void hessVec( Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &x, Real &tol ) {
277  Real zero(0);
278 
279  // Reset tolerances
280  Real origTol = tol;
281  Real tol2 = origTol;
282 
284  // hessVec tol is always set to ~1e-8. So if inexact linear system solves are used, then
285  // the multipliers will always get re-evaluated to high precision, which defeats the purpose
286  // of computing the objective/gradient approximately.
287  // Thus if inexact linear system solves are used, we will not update the multiplier estimates
288  // to high precision.
289  computeMultipliers(x, tol);
290  }
291 
292  obj_->hessVec( hv, v, x, tol2 ); tol2 = origTol;
293  con_->applyAdjointHessian( *Tv_, *y_, v, x, tol2 ); tol2 = origTol;
294  hv.axpy(static_cast<Real>(-1), *Tv_ );
295 
296  tol2 = tol;
297  solveAugmentedSystem( *w_, *v_, hv, *czeros_, x, tol2 ); tol2 = origTol;
298  hv.scale( static_cast<Real>(-1) );
299  hv.plus( *w_ );
300 
301  Tv_->set(v);
302  tol2 = tol;
303  solveAugmentedSystem( *w_, *v_, *Tv_, *czeros_, x, tol2 ); tol2 = origTol;
304  hv.axpy(static_cast<Real>(-2)*penaltyParameter_, *w_);
305 
306  obj_->hessVec( *Tv_, *w_, x, tol2 ); tol2 = origTol;
307  hv.plus( *Tv_ );
308  con_->applyAdjointHessian( *Tv_, *y_, *w_, x, tol2 ); tol2 = origTol;
309  hv.axpy( static_cast<Real>(-1), *Tv_ );
310 
311  hv.axpy( static_cast<Real>(2)*penaltyParameter_, v );
312 
313  if( quadPenaltyParameter_ > zero ) {
314  con_->applyJacobian( *b2_, v, x, tol2 ); tol2 = origTol;
315  con_->applyAdjointJacobian( *Tv_, *b2_, x, tol2 ); tol2 = origTol;
317  con_->applyAdjointHessian( *Tv_, *c_, v, x, tol2); tol2 = origTol;
318  hv.axpy( -quadPenaltyParameter_, *Tv_ );
319  }
320 
321  }
322 
324  Vector<Real> &v2,
325  const Vector<Real> &b1,
326  const Vector<Real> &b2,
327  const Vector<Real> &x,
328  Real &tol,
329  bool refine = false) {
330  // Ignore tol for now
331  ROL::Ptr<LinearOperator<Real> > K
332  = ROL::makePtr<AugSystem>(con_, makePtrFromRef(x), delta_);
333  ROL::Ptr<LinearOperator<Real> > P
334  = ROL::makePtr<AugSystemPrecond>(con_, makePtrFromRef(x));
335 
336  b1_->set(b1);
337  b2_->set(b2);
338 
339  if( refine ) {
340  // TODO: Make sure this tol is actually ok...
341  Real origTol = tol;
342  w1_->set(v1);
343  w2_->set(v2);
344  K->apply(*vv_, *ww_, tol); tol = origTol;
345 
346  b1_->axpy( static_cast<Real>(-1), *v1_ );
347  b2_->axpy( static_cast<Real>(-1), *v2_ );
348  }
349 
350  v1_->zero();
351  v2_->zero();
352 
353  // If inexact, change tolerance
354  if( useInexact_ ) {
355  krylov_->resetAbsoluteTolerance(tol);
356  }
357 
358  flagKrylov_ = 0;
359  tol = krylov_->run(*vv_,*K,*bb_,*P,iterKrylov_,flagKrylov_);
360 
361  if( refine ) {
362  v1.plus(*v1_);
363  v2.plus(*v2_);
364  } else {
365  v1.set(*v1_);
366  v2.set(*v2_);
367  }
368  }
369 
370  void computeMultipliers(const Vector<Real>& x, const Real tol) {
371  if( isMultiplierComputed_ && multSolverError_ <= tol) {
372  return;
373  }
374 
375  if( !isMultiplierComputed_ ) {
376  Real tol2 = tol;
377  FletcherBase<Real>::objGrad(x, tol2); tol2 = tol;
379  cnorm_ = c_->norm();
380  }
381 
382  bool refine = isMultiplierComputed_;
383 
384  multSolverError_ = tol;
386 
387  isMultiplierComputed_ = true;
388  }
389 
390 }; // class Fletcher
391 
392 } // namespace ROL
393 
394 #endif
Provides the interface to evaluate objective functions.
Real value(const Vector< Real > &x, Real &tol)
Compute value.
Ptr< Vector< Real > > c_
virtual const Vector & dual() const
Return dual representation of , for example, the result of applying a Riesz map, or change of basis...
Definition: ROL_Vector.hpp:192
Ptr< Vector< Real > > w2_
Ptr< Vector< Real > > gPhi_
virtual void scale(const Real alpha)=0
Compute where .
virtual ROL::Ptr< Vector > clone() const =0
Clone to make a new (uninitialized) vector.
const Ptr< Constraint< Real > > con_
ROL::Ptr< const Vector< Real > > get(size_type i) const
virtual void plus(const Vector &x)=0
Compute , where .
virtual void axpy(const Real alpha, const Vector &x)
Compute where .
Definition: ROL_Vector.hpp:119
Defines the linear algebra of vector space on a generic partitioned vector.
void objValue(const Vector< Real > &x, Real &tol)
const Ptr< Objective< Real > > obj_
void applyInverse(Vector< Real > &Hv, const Vector< Real > &v, Real &tol) const
Apply inverse of linear operator.
Ptr< Vector< Real > > vg_
Contains definitions of custom data types in ROL.
void solveAugmentedSystem(Vector< Real > &v1, Vector< Real > &v2, const Vector< Real > &b1, const Vector< Real > &b2, const Vector< Real > &x, Real &tol, bool refine=false)
Fletcher(const ROL::Ptr< Objective< Real > > &obj, const ROL::Ptr< Constraint< Real > > &con, const Vector< Real > &optVec, const Vector< Real > &conVec, ROL::ParameterList &parlist)
Ptr< Vector< Real > > wg_
const Ptr< const Vector< Real > > x_
const Ptr< const Vector< Real > > x_
AugSystemPrecond(const Ptr< Constraint< Real > > con, const Ptr< const Vector< Real > > x)
Ptr< Vector< Real > > czeros_
Ptr< Vector< Real > > w1_
Ptr< Vector< Real > > Tv_
Defines the linear algebra or vector space interface.
Definition: ROL_Vector.hpp:46
Ptr< Krylov< Real > > krylov_
Objective_SerialSimOpt(const Ptr< Obj > &obj, const V &ui) z0_ zero()
Ptr< Vector< Real > > gL_
Ptr< Vector< Real > > v1_
Ptr< Vector< Real > > b1_
AugSystem(const Ptr< Constraint< Real > > &con, const Ptr< const Vector< Real > > &x, const Real delta)
Ptr< Vector< Real > > w_
Ptr< Vector< Real > > scaledc_
void apply(Vector< Real > &Hv, const Vector< Real > &v, Real &tol) const
Apply linear operator.
Ptr< Vector< Real > > g_
void conValue(const Vector< Real > &x, Real &tol)
void set(const V &x)
Set where .
void computeMultipliers(const Vector< Real > &x, const Real tol)
Ptr< Vector< Real > > y_
Ptr< Vector< Real > > xzeros_
Ptr< PartitionedVector< Real > > vv_
Provides the interface to apply a linear operator.
const Ptr< Constraint< Real > > con_
void hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply Hessian approximation to vector.
virtual void set(const Vector &x)
Set where .
Definition: ROL_Vector.hpp:175
void update(const Vector< Real > &x, bool flag=true, int iter=-1)
Update objective function.
Ptr< Vector< Real > > v2_
Ptr< Vector< Real > > b2_
Ptr< PartitionedVector< Real > > bb_
const Ptr< Constraint< Real > > con_
Ptr< PartitionedVector< Real > > ww_
void gradient(Vector< Real > &g, const Vector< Real > &x, Real &tol)
Compute gradient.
void objGrad(const Vector< Real > &x, Real &tol)
Defines the general constraint operator interface.
void apply(Vector< Real > &Hv, const Vector< Real > &v, Real &tol) const
Apply linear operator.
Ptr< Vector< Real > > v_