ROL
ROL_LineSearchStep.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_LINESEARCHSTEP_H
11#define ROL_LINESEARCHSTEP_H
12
13#include "ROL_Types.hpp"
14#include "ROL_Step.hpp"
15#include "ROL_LineSearch.hpp"
16
17// Unconstrained Methods
18#include "ROL_GradientStep.hpp"
20#include "ROL_SecantStep.hpp"
21#include "ROL_NewtonStep.hpp"
23
24// Bound Constrained Methods
28
29#include <sstream>
30#include <iomanip>
31
101namespace ROL {
102
103template <class Real>
104class LineSearchStep : public Step<Real> {
105private:
106
107 ROL::Ptr<Step<Real> > desc_;
108 ROL::Ptr<Secant<Real> > secant_;
109 ROL::Ptr<Krylov<Real> > krylov_;
110 ROL::Ptr<NonlinearCG<Real> > nlcg_;
111 ROL::Ptr<LineSearch<Real> > lineSearch_;
112
113 ROL::Ptr<Vector<Real> > d_;
114
117
119
121
124 Real fval_;
125
126 ROL::ParameterList parlist_;
127
128 std::string lineSearchName_;
129
130 Real GradDotStep(const Vector<Real> &g, const Vector<Real> &s,
131 const Vector<Real> &x,
132 BoundConstraint<Real> &bnd, Real eps = 0) {
133 Real gs(0), one(1);
134 if (!bnd.isActivated()) {
135 gs = s.dot(g.dual());
136 }
137 else {
138 d_->set(s);
139 bnd.pruneActive(*d_,g,x,eps);
140 gs = d_->dot(g.dual());
141 d_->set(x);
142 d_->axpy(-one,g.dual());
143 bnd.project(*d_);
144 d_->scale(-one);
145 d_->plus(x);
146 bnd.pruneInactive(*d_,g,x,eps);
147 gs -= d_->dot(g.dual());
148 }
149 return gs;
150 }
151
152public:
153
154 using Step<Real>::initialize;
155 using Step<Real>::compute;
156 using Step<Real>::update;
157
171 LineSearchStep( ROL::ParameterList &parlist,
172 const ROL::Ptr<LineSearch<Real> > &lineSearch = ROL::nullPtr,
173 const ROL::Ptr<Secant<Real> > &secant = ROL::nullPtr,
174 const ROL::Ptr<Krylov<Real> > &krylov = ROL::nullPtr,
175 const ROL::Ptr<NonlinearCG<Real> > &nlcg = ROL::nullPtr )
176 : Step<Real>(), desc_(ROL::nullPtr), secant_(secant),
177 krylov_(krylov), nlcg_(nlcg), lineSearch_(lineSearch),
179 verbosity_(0), computeObj_(true), fval_(0), parlist_(parlist) {
180 // Parse parameter list
181 ROL::ParameterList& Llist = parlist.sublist("Step").sublist("Line Search");
182 ROL::ParameterList& Glist = parlist.sublist("General");
183 std::string condName = Llist.sublist("Curvature Condition").get("Type","Strong Wolfe Conditions");
185 acceptLastAlpha_ = Llist.get("Accept Last Alpha", false);
186 verbosity_ = Glist.get("Print Verbosity",0);
187 computeObj_ = Glist.get("Recompute Objective Function",false);
188 // Initialize Line Search
189 if (lineSearch_ == ROL::nullPtr) {
190 lineSearchName_ = Llist.sublist("Line-Search Method").get("Type","Cubic Interpolation");
192 lineSearch_ = LineSearchFactory<Real>(parlist);
193 }
194 else { // User-defined linesearch provided
195 lineSearchName_ = Llist.sublist("Line-Search Method").get("User Defined Line-Search Name",
196 "Unspecified User Defined Line-Search");
197 }
198
199 }
200
201 void initialize( Vector<Real> &x, const Vector<Real> &s, const Vector<Real> &g,
203 AlgorithmState<Real> &algo_state ) {
204 d_ = x.clone();
205
206 // Initialize unglobalized step
207 ROL::ParameterList& list = parlist_.sublist("Step").sublist("Line Search").sublist("Descent Method");
208 std::string descentName = list.get("Type","Quasi-Newton Method");
209 EDescent edesc = StringToEDescent(descentName);
210 if (bnd.isActivated()) {
211 switch(edesc) {
212 case DESCENT_STEEPEST: {
213 desc_ = ROL::makePtr<GradientStep<Real>>(parlist_,computeObj_);
214 break;
215 }
216 case DESCENT_NONLINEARCG: {
217 desc_ = ROL::makePtr<NonlinearCGStep<Real>>(parlist_,nlcg_,computeObj_);
218 break;
219 }
220 case DESCENT_SECANT: {
221 desc_ = ROL::makePtr<ProjectedSecantStep<Real>>(parlist_,secant_,computeObj_);
222 break;
223 }
224 case DESCENT_NEWTON: {
225 desc_ = ROL::makePtr<ProjectedNewtonStep<Real>>(parlist_,computeObj_);
226 break;
227 }
229 desc_ = ROL::makePtr<ProjectedNewtonKrylovStep<Real>>(parlist_,krylov_,secant_,computeObj_);
230 break;
231 }
232 default:
233 ROL_TEST_FOR_EXCEPTION(true,std::invalid_argument,
234 ">>> (LineSearchStep::Initialize): Undefined descent type!");
235 }
236 }
237 else {
238 switch(edesc) {
239 case DESCENT_STEEPEST: {
240 desc_ = ROL::makePtr<GradientStep<Real>>(parlist_,computeObj_);
241 break;
242 }
243 case DESCENT_NONLINEARCG: {
244 desc_ = ROL::makePtr<NonlinearCGStep<Real>>(parlist_,nlcg_,computeObj_);
245 break;
246 }
247 case DESCENT_SECANT: {
248 desc_ = ROL::makePtr<SecantStep<Real>>(parlist_,secant_,computeObj_);
249 break;
250 }
251 case DESCENT_NEWTON: {
252 desc_ = ROL::makePtr<NewtonStep<Real>>(parlist_,computeObj_);
253 break;
254 }
256 desc_ = ROL::makePtr<NewtonKrylovStep<Real>>(parlist_,krylov_,secant_,computeObj_);
257 break;
258 }
259 default:
260 ROL_TEST_FOR_EXCEPTION(true,std::invalid_argument,
261 ">>> (LineSearchStep::Initialize): Undefined descent type!");
262 }
263 }
264 desc_->initialize(x,s,g,obj,bnd,algo_state);
265
266 // Initialize line search
267 lineSearch_->initialize(x,s,g,obj,bnd);
268 //const ROL::Ptr<const StepState<Real> > desc_state = desc_->getStepState();
269 //lineSearch_->initialize(x,s,*(desc_state->gradientVec),obj,bnd);
270 }
271
287 AlgorithmState<Real> &algo_state ) {
288 Real zero(0), one(1);
289 // Compute unglobalized step
290 desc_->compute(s,x,obj,bnd,algo_state);
291
292 // Ensure that s is a descent direction
293 // ---> If not, then default to steepest descent
294 const ROL::Ptr<const StepState<Real> > desc_state = desc_->getStepState();
295 Real gs = GradDotStep(*(desc_state->gradientVec),s,x,bnd,algo_state.gnorm);
296 if (gs >= zero) {
297 s.set((desc_state->gradientVec)->dual());
298 s.scale(-one);
299 gs = GradDotStep(*(desc_state->gradientVec),s,x,bnd,algo_state.gnorm);
300 }
301
302 // Perform line search
303 ROL::Ptr<StepState<Real> > step_state = Step<Real>::getState();
304 fval_ = algo_state.value;
305 step_state->nfval = 0; step_state->ngrad = 0;
306 lineSearch_->setData(algo_state.gnorm,*(desc_state->gradientVec));
307 lineSearch_->run(step_state->searchSize,fval_,step_state->nfval,step_state->ngrad,gs,s,x,obj,bnd);
308
309 // Make correction if maximum function evaluations reached
310 if(!acceptLastAlpha_) {
311 lineSearch_->setMaxitUpdate(step_state->searchSize,fval_,algo_state.value);
312 }
313
314 // Compute scaled descent direction
315 s.scale(step_state->searchSize);
316 if ( bnd.isActivated() ) {
317 s.plus(x);
318 bnd.project(s);
319 s.axpy(static_cast<Real>(-1),x);
320 }
321 }
322
334 void update( Vector<Real> &x, const Vector<Real> &s,
336 AlgorithmState<Real> &algo_state ) {
337 ROL::Ptr<StepState<Real> > step_state = Step<Real>::getState();
338 algo_state.nfval += step_state->nfval;
339 algo_state.ngrad += step_state->ngrad;
340 desc_->update(x,s,obj,bnd,algo_state);
341 step_state->flag = desc_->getStepState()->flag;
342 step_state->SPiter = desc_->getStepState()->SPiter;
343 step_state->SPflag = desc_->getStepState()->SPflag;
344 if ( !computeObj_ ) {
345 algo_state.value = fval_;
346 }
347 }
348
353 std::string printHeader( void ) const {
354 std::string head = desc_->printHeader();
355 head.erase(std::remove(head.end()-3,head.end(),'\n'), head.end());
356 std::stringstream hist;
357 hist.write(head.c_str(),head.length());
358 hist << std::setw(10) << std::left << "ls_#fval";
359 hist << std::setw(10) << std::left << "ls_#grad";
360 hist << "\n";
361 return hist.str();
362 }
363
368 std::string printName( void ) const {
369 std::string name = desc_->printName();
370 std::stringstream hist;
371 hist << name;
372 hist << "Line Search: " << lineSearchName_;
373 hist << " satisfying " << ECurvatureConditionToString(econd_) << "\n";
374 return hist.str();
375 }
376
384 std::string print( AlgorithmState<Real> & algo_state, bool print_header = false ) const {
385 const ROL::Ptr<const StepState<Real> > step_state = Step<Real>::getStepState();
386 std::string desc = desc_->print(algo_state,false);
387 desc.erase(std::remove(desc.end()-3,desc.end(),'\n'), desc.end());
388 std::string name = desc_->printName();
389 size_t pos = desc.find(name);
390 if ( pos != std::string::npos ) {
391 desc.erase(pos, name.length());
392 }
393
394 std::stringstream hist;
395 if ( algo_state.iter == 0 ) {
396 hist << printName();
397 }
398 if ( print_header ) {
399 hist << printHeader();
400 }
401 hist << desc;
402 if ( algo_state.iter == 0 ) {
403 hist << "\n";
404 }
405 else {
406 hist << std::setw(10) << std::left << step_state->nfval;
407 hist << std::setw(10) << std::left << step_state->ngrad;
408 hist << "\n";
409 }
410 return hist.str();
411 }
412}; // class LineSearchStep
413
414} // namespace ROL
415
416#endif
Objective_SerialSimOpt(const Ptr< Obj > &obj, const V &ui) z0_ zero()
Contains definitions of custom data types in ROL.
Provides the interface to apply upper and lower bound constraints.
void pruneInactive(Vector< Real > &v, const Vector< Real > &x, Real eps=Real(0))
Set variables to zero if they correspond to the -inactive set.
void pruneActive(Vector< Real > &v, const Vector< Real > &x, Real eps=Real(0))
Set variables to zero if they correspond to the -active set.
bool isActivated(void) const
Check if bounds are on.
virtual void project(Vector< Real > &x)
Project optimization variables onto the bounds.
Provides definitions for Krylov solvers.
Provides the interface to compute optimization steps with line search.
ECurvatureCondition econd_
enum determines type of curvature condition
bool acceptLastAlpha_
For backwards compatibility. When max function evaluations are reached take last step.
void update(Vector< Real > &x, const Vector< Real > &s, Objective< Real > &obj, BoundConstraint< Real > &bnd, AlgorithmState< Real > &algo_state)
Update step, if successful.
ROL::Ptr< Secant< Real > > secant_
Secant object (used for quasi-Newton)
ROL::Ptr< Step< Real > > desc_
Unglobalized step object.
void initialize(Vector< Real > &x, const Vector< Real > &s, const Vector< Real > &g, Objective< Real > &obj, BoundConstraint< Real > &bnd, AlgorithmState< Real > &algo_state)
Initialize step with bound constraint.
Real GradDotStep(const Vector< Real > &g, const Vector< Real > &s, const Vector< Real > &x, BoundConstraint< Real > &bnd, Real eps=0)
std::string printName(void) const
Print step name.
bool usePreviousAlpha_
If true, use the previously accepted step length (if any) as the new initial step length.
std::string printHeader(void) const
Print iterate header.
void compute(Vector< Real > &s, const Vector< Real > &x, Objective< Real > &obj, BoundConstraint< Real > &bnd, AlgorithmState< Real > &algo_state)
Compute step.
ROL::ParameterList parlist_
ROL::Ptr< Vector< Real > > d_
std::string print(AlgorithmState< Real > &algo_state, bool print_header=false) const
Print iterate status.
ROL::Ptr< NonlinearCG< Real > > nlcg_
Nonlinear CG object (used for nonlinear CG)
ELineSearch els_
enum determines type of line search
LineSearchStep(ROL::ParameterList &parlist, const ROL::Ptr< LineSearch< Real > > &lineSearch=ROL::nullPtr, const ROL::Ptr< Secant< Real > > &secant=ROL::nullPtr, const ROL::Ptr< Krylov< Real > > &krylov=ROL::nullPtr, const ROL::Ptr< NonlinearCG< Real > > &nlcg=ROL::nullPtr)
Constructor.
ROL::Ptr< Krylov< Real > > krylov_
Krylov solver object (used for inexact Newton)
ROL::Ptr< LineSearch< Real > > lineSearch_
Line-search object.
Provides interface for and implements line searches.
Provides the interface to evaluate objective functions.
Provides interface for and implements limited-memory secant operators.
Provides the interface to compute optimization steps.
Definition ROL_Step.hpp:34
ROL::Ptr< StepState< Real > > getState(void)
Definition ROL_Step.hpp:39
const ROL::Ptr< const StepState< Real > > getStepState(void) const
Get state for step object.
Definition ROL_Step.hpp:177
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 .
virtual Real dot(const Vector &x) const =0
Compute where .
EDescent StringToEDescent(std::string s)
@ DESCENT_NEWTONKRYLOV
@ DESCENT_SECANT
@ DESCENT_STEEPEST
@ DESCENT_NONLINEARCG
@ DESCENT_NEWTON
ECurvatureCondition
@ CURVATURECONDITION_WOLFE
std::string ECurvatureConditionToString(ECurvatureCondition ls)
ELineSearch
@ LINESEARCH_USERDEFINED
ELineSearch StringToELineSearch(std::string s)
ECurvatureCondition StringToECurvatureCondition(std::string s)
State for algorithm class. Will be used for restarts.