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
23namespace ROL {
24
25template <class Real>
26class Fletcher : public FletcherBase<Real> {
27private:
28 // Required for Fletcher penalty function definition
29 using FletcherBase<Real>::obj_;
30 using FletcherBase<Real>::con_;
31
34
35 // Evaluation counters
36 using FletcherBase<Real>::nfval_;
37 using FletcherBase<Real>::ngval_;
38 using FletcherBase<Real>::ncval_;
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
74 using FletcherBase<Real>::useInexact_;
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
80 using FletcherBase<Real>::krylov_;
81 using FletcherBase<Real>::iterKrylov_;
82 using FletcherBase<Real>::flagKrylov_;
83 using FletcherBase<Real>::v1_;
84 using FletcherBase<Real>::v2_;
85 using FletcherBase<Real>::vv_;
86 using FletcherBase<Real>::w1_;
87 using FletcherBase<Real>::w2_;
88 using FletcherBase<Real>::ww_;
89 using FletcherBase<Real>::b1_;
90 using FletcherBase<Real>::b2_;
91 using FletcherBase<Real>::bb_;
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
137public:
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_);
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 ) {
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_));
221
222 fPhi_ = fval_ - c_->dot(y_->dual());
223
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
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
268 con_->applyAdjointJacobian( *Tv_, *c_, x, tol2 ); tol2 = origTol;
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
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;
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) {
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
388 }
389
390}; // class Fletcher
391
392} // namespace ROL
393
394#endif
Objective_SerialSimOpt(const Ptr< Obj > &obj, const V &ui) z0_ zero()
Contains definitions of custom data types in ROL.
Defines the general constraint operator interface.
Ptr< Vector< Real > > v1_
Ptr< Vector< Real > > b2_
Ptr< Vector< Real > > c_
Ptr< Vector< Real > > w1_
const Ptr< Constraint< Real > > con_
void conValue(const Vector< Real > &x, Real &tol)
Ptr< Vector< Real > > scaledc_
Ptr< Vector< Real > > v2_
const Ptr< Objective< Real > > obj_
Ptr< Vector< Real > > gPhi_
Ptr< Vector< Real > > w2_
void objGrad(const Vector< Real > &x, Real &tol)
void objValue(const Vector< Real > &x, Real &tol)
Ptr< Vector< Real > > g_
Ptr< Vector< Real > > y_
Ptr< PartitionedVector< Real > > vv_
Ptr< Vector< Real > > gL_
Ptr< PartitionedVector< Real > > ww_
Ptr< PartitionedVector< Real > > bb_
Ptr< Krylov< Real > > krylov_
Ptr< Vector< Real > > b1_
const Ptr< const Vector< Real > > x_
const Ptr< Constraint< Real > > con_
AugSystemPrecond(const Ptr< Constraint< Real > > con, const Ptr< const Vector< Real > > x)
void apply(Vector< Real > &Hv, const Vector< Real > &v, Real &tol) const
Apply linear operator.
void applyInverse(Vector< Real > &Hv, const Vector< Real > &v, Real &tol) const
Apply inverse of linear operator.
const Ptr< Constraint< Real > > con_
void apply(Vector< Real > &Hv, const Vector< Real > &v, Real &tol) const
Apply linear operator.
const Ptr< const Vector< Real > > x_
AugSystem(const Ptr< Constraint< Real > > &con, const Ptr< const Vector< Real > > &x, const Real delta)
Ptr< Vector< Real > > v_
Fletcher(const ROL::Ptr< Objective< Real > > &obj, const ROL::Ptr< Constraint< Real > > &con, const Vector< Real > &optVec, const Vector< Real > &conVec, ROL::ParameterList &parlist)
void update(const Vector< Real > &x, bool flag=true, int iter=-1)
Update objective function.
Ptr< Vector< Real > > w_
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)
Ptr< Vector< Real > > wg_
Real value(const Vector< Real > &x, Real &tol)
Compute value.
Ptr< Vector< Real > > czeros_
void computeMultipliers(const Vector< Real > &x, const Real tol)
Ptr< Vector< Real > > Tv_
void gradient(Vector< Real > &g, const Vector< Real > &x, Real &tol)
Compute gradient.
Ptr< Vector< Real > > vg_
void hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply Hessian approximation to vector.
Ptr< Vector< Real > > xzeros_
Provides the interface to apply a linear operator.
Provides the interface to evaluate objective functions.
Defines the linear algebra of vector space on a generic partitioned vector.
ROL::Ptr< const Vector< Real > > get(size_type i) const
void set(const V &x)
Set where .
Defines the linear algebra or vector space interface.
virtual void set(const Vector &x)
Set where .
virtual void scale(const Real alpha)=0
Compute where .
virtual const Vector & dual() const
Return dual representation of , for example, the result of applying a Riesz map, or change of basis,...
virtual void plus(const Vector &x)=0
Compute , where .
virtual ROL::Ptr< Vector > clone() const =0
Clone to make a new (uninitialized) vector.
virtual void axpy(const Real alpha, const Vector &x)
Compute where .