ROL
ROL_BundleStep.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_BUNDLE_STEP_H
11 #define ROL_BUNDLE_STEP_H
12 
13 #include "ROL_Bundle_AS.hpp"
14 #include "ROL_Bundle_TT.hpp"
15 #include "ROL_Types.hpp"
16 #include "ROL_Step.hpp"
17 #include "ROL_Vector.hpp"
18 #include "ROL_Objective.hpp"
19 #include "ROL_BoundConstraint.hpp"
20 #include "ROL_LineSearch.hpp"
21 
22 #include "ROL_ParameterList.hpp"
23 #include "ROL_Ptr.hpp"
24 
30 namespace ROL {
31 
32 template <class Real>
33 class BundleStep : public Step<Real> {
34 private:
35  // Bundle
36  ROL::Ptr<Bundle<Real> > bundle_; // Bundle of subgradients and linearization errors
37  ROL::Ptr<LineSearch<Real> > lineSearch_; // Line-search object for nonconvex problems
38 
39  // Dual cutting plane solution
40  unsigned QPiter_; // Number of QP solver iterations
41  unsigned QPmaxit_; // Maximum number of QP iterations
42  Real QPtol_; // QP subproblem tolerance
43 
44  // Step flag
45  int step_flag_; // Whether serious or null step
46 
47  // Additional storage
48  ROL::Ptr<Vector<Real> > y_;
49 
50  // Updated iterate storage
51  Real linErrNew_;
52  Real valueNew_;
53 
54  // Aggregate subgradients, linearizations, and distance measures
55  ROL::Ptr<Vector<Real> > aggSubGradNew_; // New aggregate subgradient
56  Real aggSubGradOldNorm_; // Old aggregate subgradient norm
57  Real aggLinErrNew_; // New aggregate linearization error
58  Real aggLinErrOld_; // Old aggregate linearization error
59  Real aggDistMeasNew_; // New aggregate distance measure
60 
61  // Algorithmic parameters
62  Real T_;
63  Real tol_;
64  Real m1_;
65  Real m2_;
66  Real m3_;
67  Real nu_;
68 
69  // Line-search parameters
70  int ls_maxit_;
71 
73  bool isConvex_;
74 
75  Real ftol_;
76 
78 
79 public:
80 
82  using Step<Real>::compute;
83  using Step<Real>::update;
84 
85  BundleStep(ROL::ParameterList &parlist)
86  : bundle_(ROL::nullPtr), lineSearch_(ROL::nullPtr),
87  QPiter_(0), QPmaxit_(0), QPtol_(0), step_flag_(0),
88  y_(ROL::nullPtr), linErrNew_(0), valueNew_(0),
89  aggSubGradNew_(ROL::nullPtr), aggSubGradOldNorm_(0),
91  T_(0), tol_(0), m1_(0), m2_(0), m3_(0), nu_(0),
92  ls_maxit_(0), first_print_(true), isConvex_(false),
93  ftol_(ROL_EPSILON<Real>()) {
94  Real zero(0), two(2), oem3(1.e-3), oem6(1.e-6), oem8(1.e-8), p1(0.1), p2(0.2), p9(0.9), oe3(1.e3), oe8(1.e8);
95  ROL::Ptr<StepState<Real> > state = Step<Real>::getState();
96  state->searchSize = parlist.sublist("Step").sublist("Bundle").get("Initial Trust-Region Parameter", oe3);
97  T_ = parlist.sublist("Step").sublist("Bundle").get("Maximum Trust-Region Parameter", oe8);
98  tol_ = parlist.sublist("Step").sublist("Bundle").get("Epsilon Solution Tolerance", oem6);
99  m1_ = parlist.sublist("Step").sublist("Bundle").get("Upper Threshold for Serious Step", p1);
100  m2_ = parlist.sublist("Step").sublist("Bundle").get("Lower Threshold for Serious Step", p2);
101  m3_ = parlist.sublist("Step").sublist("Bundle").get("Upper Threshold for Null Step", p9);
102  nu_ = parlist.sublist("Step").sublist("Bundle").get("Tolerance for Trust-Region Parameter", oem3);
103 
104  // Initialize bundle
105  Real coeff = parlist.sublist("Step").sublist("Bundle").get("Distance Measure Coefficient", zero);
106  Real omega = parlist.sublist("Step").sublist("Bundle").get("Locality Measure Coefficient", two);
107  unsigned maxSize = parlist.sublist("Step").sublist("Bundle").get("Maximum Bundle Size", 200);
108  unsigned remSize = parlist.sublist("Step").sublist("Bundle").get("Removal Size for Bundle Update", 2);
109  int cps = parlist.sublist("Step").sublist("Bundle").get("Cutting Plane Solver",0);
110  if (cps) {
111  bundle_ = ROL::makePtr<Bundle_TT<Real>>(maxSize,coeff,omega,remSize);
112  //bundle_ = ROL::makePtr<Bundle_AS<Real>>(maxSize,coeff,omega,remSize);
113  }
114  else {
115  bundle_ = ROL::makePtr<Bundle_AS<Real>>(maxSize,coeff,omega,remSize);
116  }
117  isConvex_ = ((coeff == zero) ? true : false);
118 
119  // Initialize QP solver
120  QPtol_ = parlist.sublist("Step").sublist("Bundle").get("Cutting Plane Tolerance", oem8);
121  QPmaxit_ = parlist.sublist("Step").sublist("Bundle").get("Cutting Plane Iteration Limit", 1000);
122 
123  // Initialize Line Search
124  ls_maxit_
125  = parlist.sublist("Step").sublist("Line Search").get("Maximum Number of Function Evaluations",20);
126  if ( !isConvex_ ) {
127  lineSearch_ = LineSearchFactory<Real>(parlist);
128  }
129 
130  // Get verbosity level
131  verbosity_ = parlist.sublist("General").get("Print Verbosity", 0);
132  }
133 
134  void initialize( Vector<Real> &x, const Vector<Real> &g,
136  AlgorithmState<Real> &algo_state ) {
137  // Call default initializer, but maintain current searchSize
138  ROL::Ptr<StepState<Real> > state = Step<Real>::getState();
139  Real searchSize = state->searchSize;
140  Step<Real>::initialize(x,x,g,obj,con,algo_state);
141  state->searchSize = searchSize;
142  // Initialize bundle
143  bundle_->initialize(*(state->gradientVec));
144  // Initialize storage for updated iterate
145  y_ = x.clone();
146  // Initialize storage for aggregate subgradients
147  aggSubGradNew_ = g.clone();
148  aggSubGradOldNorm_ = algo_state.gnorm;
149  // Initialize line search
150  if ( !isConvex_ ) {
151  lineSearch_->initialize(x,x,g,obj,con);
152  }
153  }
154 
156  BoundConstraint<Real> &con, AlgorithmState<Real> &algo_state ) {
157  ROL::Ptr<StepState<Real> > state = Step<Real>::getState();
158  first_print_ = false; // Print header only on first serious step
159  QPiter_ = (step_flag_==1 ? 0 : QPiter_); // Reset QPiter only on serious steps
160  Real v(0), l(0), u = T_, gd(0); // Scalar storage
161  Real zero(0), two(2), half(0.5);
162  bool flag = true;
163  while (flag) {
164  /*************************************************************/
165  /******** Solve Dual Cutting Plane QP Problem ****************/
166  /*************************************************************/
167  QPiter_ += bundle_->solveDual(state->searchSize,QPmaxit_,QPtol_); // Solve QP subproblem
168  bundle_->aggregate(*aggSubGradNew_,aggLinErrNew_,aggDistMeasNew_); // Compute aggregate info
169  algo_state.aggregateGradientNorm = aggSubGradNew_->norm(); // Aggregate subgradient norm
170  if (verbosity_ > 0) {
171  std::cout << std::endl;
172  std::cout << " Computation of aggregrate quantities" << std::endl;
173  std::cout << " Aggregate subgradient norm: " << algo_state.aggregateGradientNorm << std::endl;
174  std::cout << " Aggregate linearization error: " << aggLinErrNew_ << std::endl;
175  std::cout << " Aggregate distance measure: " << aggDistMeasNew_ << std::endl;
176  }
177  /*************************************************************/
178  /******** Construct Cutting Plane Solution *******************/
179  /*************************************************************/
180  v = -state->searchSize*std::pow(algo_state.aggregateGradientNorm,two)-aggLinErrNew_; // CP objective value
181  s.set(aggSubGradNew_->dual()); s.scale(-state->searchSize); // CP solution
182  algo_state.snorm = state->searchSize*algo_state.aggregateGradientNorm; // Step norm
183  if (verbosity_ > 0) {
184  std::cout << std::endl;
185  std::cout << " Solve cutting plan subproblem" << std::endl;
186  std::cout << " Cutting plan objective value: " << v << std::endl;
187  std::cout << " Norm of computed step: " << algo_state.snorm << std::endl;
188  std::cout << " 'Trust-region' radius: " << state->searchSize << std::endl;
189  }
190  /*************************************************************/
191  /******** Decide Whether Step is Serious or Null *************/
192  /*************************************************************/
193  if (std::max(algo_state.aggregateGradientNorm,aggLinErrNew_) <= tol_) {
194  // Current iterate is already epsilon optimal!
195  s.zero(); algo_state.snorm = zero;
196  flag = false;
197  step_flag_ = 1;
198  algo_state.flag = true;
199  break;
200  }
201  else if (std::isnan(algo_state.aggregateGradientNorm)
202  || std::isnan(aggLinErrNew_)
203  || (std::isnan(aggDistMeasNew_) && !isConvex_)) {
204  s.zero(); algo_state.snorm = zero;
205  flag = false;
206  step_flag_ = 2;
207  algo_state.flag = true;
208  }
209  else {
210  // Current iterate is not epsilon optimal.
211  y_->set(x); y_->plus(s); // y is the candidate iterate
212  obj.update(*y_,true,algo_state.iter); // Update objective at y
213  valueNew_ = obj.value(*y_,ftol_); // Compute objective value at y
214  algo_state.nfval++;
215  obj.gradient(*(state->gradientVec),*y_,ftol_); // Compute objective (sub)gradient at y
216  algo_state.ngrad++;
217  // Compute new linearization error and distance measure
218  gd = s.dot(state->gradientVec->dual());
219  linErrNew_ = algo_state.value - (valueNew_ - gd); // Linearization error
220  // Determine whether to take a serious or null step
221  Real eps = static_cast<Real>(10)*ROL_EPSILON<Real>();
222  Real del = eps*std::max(static_cast<Real>(1),std::abs(algo_state.value));
223  Real Df = (valueNew_ - algo_state.value) - del;
224  Real Dm = v - del;
225  bool SS1 = false;
226  if (std::abs(Df) < eps && std::abs(Dm) < eps) {
227  SS1 = true;
228  }
229  else {
230  SS1 = (Df < m1_*Dm);
231  }
232  //bool SS1 = (valueNew_-algo_state.value < m1_*v);
233  //bool NS1 = (valueNew_-algo_state.value >= m1_*v);
234  bool NS2a = (bundle_->computeAlpha(algo_state.snorm,linErrNew_) <= m3_*aggLinErrOld_);
235  bool NS2b = (std::abs(algo_state.value-valueNew_) <= aggSubGradOldNorm_ + aggLinErrOld_);
236  if (verbosity_ > 0) {
237  std::cout << std::endl;
238  std::cout << " Check for serious/null step" << std::endl;
239  std::cout << " Serious step test SS(i): " << SS1 << std::endl;
240  std::cout << " -> Left hand side: " << valueNew_-algo_state.value << std::endl;
241  std::cout << " -> Right hand side: " << m1_*v << std::endl;
242  std::cout << " Null step test NS(iia): " << NS2a << std::endl;
243  std::cout << " -> Left hand side: " << bundle_->computeAlpha(algo_state.snorm,linErrNew_) << std::endl;
244  std::cout << " -> Right hand side: " << m3_*aggLinErrOld_ << std::endl;
245  std::cout << " Null step test NS(iib): " << NS2b << std::endl;
246  std::cout << " -> Left hand side: " << std::abs(algo_state.value-valueNew_) << std::endl;
247  std::cout << " -> Right hand side: " << aggSubGradOldNorm_ + aggLinErrOld_ << std::endl;
248  }
249  if ( isConvex_ ) {
250  /************* Convex objective ****************/
251  if ( SS1 ) {
252  bool SS2 = (gd >= m2_*v || state->searchSize >= T_-nu_);
253  if (verbosity_ > 0) {
254  std::cout << " Serious step test SS(iia): " << (gd >= m2_*v) << std::endl;
255  std::cout << " -> Left hand side: " << gd << std::endl;
256  std::cout << " -> Right hand side: " << m2_*v << std::endl;
257  std::cout << " Serious step test SS(iia): " << (state->searchSize >= T_-nu_) << std::endl;
258  std::cout << " -> Left hand side: " << state->searchSize << std::endl;
259  std::cout << " -> Right hand side: " << T_-nu_ << std::endl;
260  }
261  if ( SS2 ) { // Serious Step
262  step_flag_ = 1;
263  flag = false;
264  if (verbosity_ > 0) {
265  std::cout << " Serious step taken" << std::endl;
266  }
267  break;
268  }
269  else { // Increase trust-region radius
270  l = state->searchSize;
271  state->searchSize = half*(u+l);
272  if (verbosity_ > 0) {
273  std::cout << " Increase 'trust-region' radius: " << state->searchSize << std::endl;
274  }
275  }
276  }
277  else {
278  if ( NS2a || NS2b ) { // Null step
279  s.zero(); algo_state.snorm = zero;
280  step_flag_ = 0;
281  flag = false;
282  if (verbosity_ > 0) {
283  std::cout << " Null step taken" << std::endl;
284  }
285  break;
286  }
287  else { // Decrease trust-region radius
288  u = state->searchSize;
289  state->searchSize = half*(u+l);
290  if (verbosity_ > 0) {
291  std::cout << " Decrease 'trust-region' radius: " << state->searchSize << std::endl;
292  }
293  }
294  }
295  }
296  else {
297  /************* Nonconvex objective *************/
298  bool NS3 = (gd - bundle_->computeAlpha(algo_state.snorm,linErrNew_) >= m2_*v);
299  if (verbosity_ > 0) {
300  std::cout << " Null step test NS(iii): " << NS3 << std::endl;
301  std::cout << " -> Left hand side: " << gd - bundle_->computeAlpha(algo_state.snorm,linErrNew_) << std::endl;
302  std::cout << " -> Right hand side: " << m2_*v << std::endl;
303  }
304  if ( SS1 ) { // Serious step
305  step_flag_ = 1;
306  flag = false;
307  break;
308  }
309  else {
310  if ( NS2a || NS2b ) {
311  if ( NS3 ) { // Null step
312  s.zero();
313  step_flag_ = 0;
314  flag = false;
315  break;
316  }
317  else {
318  if ( NS2b ) { // Line search
319  Real alpha = zero;
320  int ls_nfval = 0, ls_ngrad = 0;
321  lineSearch_->run(alpha,valueNew_,ls_nfval,ls_ngrad,gd,s,x,obj,con);
322  if ( ls_nfval == ls_maxit_ ) { // Null step
323  s.zero();
324  step_flag_ = 0;
325  flag = false;
326  break;
327  }
328  else { // Serious step
329  s.scale(alpha);
330  step_flag_ = 1;
331  flag = false;
332  break;
333  }
334  }
335  else { // Decrease trust-region radius
336  u = state->searchSize;
337  state->searchSize = half*(u+l);
338  }
339  }
340  }
341  else { // Decrease trust-region radius
342  u = state->searchSize;
343  state->searchSize = half*(u+l);
344  }
345  }
346  }
347  }
348  } // End While
349  /*************************************************************/
350  /******** Update Algorithm State *****************************/
351  /*************************************************************/
352  algo_state.aggregateModelError = aggLinErrNew_;
355  } // End Compute
356 
357  void update( Vector<Real> &x, const Vector<Real> &s, Objective<Real> &obj,
358  BoundConstraint<Real> &con, AlgorithmState<Real> &algo_state ) {
359  ROL::Ptr<StepState<Real> > state = Step<Real>::getState();
360  state->flag = step_flag_;
361  state->SPiter = QPiter_;
362  if ( !algo_state.flag ) {
363  /*************************************************************/
364  /******** Reset Bundle If Maximum Size Reached ***************/
365  /*************************************************************/
366  bundle_->reset(*aggSubGradNew_,aggLinErrNew_,algo_state.snorm);
367  /*************************************************************/
368  /******** Update Bundle with Step Information ****************/
369  /*************************************************************/
370  if ( step_flag_==1 ) {
371  // Serious step was taken
372  x.plus(s); // Update iterate
373  Real valueOld = algo_state.value; // Store previous objective value
374  algo_state.value = valueNew_; // Add new objective value to state
375  bundle_->update(step_flag_,valueNew_-valueOld,algo_state.snorm,*(state->gradientVec),s);
376  }
377  else if ( step_flag_==0 ) {
378  // Null step was taken
379  bundle_->update(step_flag_,linErrNew_,algo_state.snorm,*(state->gradientVec),s);
380  }
381  }
382  /*************************************************************/
383  /******** Update Algorithm State *****************************/
384  /*************************************************************/
385  algo_state.iterateVec->set(x);
386  algo_state.gnorm = (state->gradientVec)->norm();
387  if ( step_flag_==1 ) {
388  algo_state.iter++;
389  }
390  } // End Update
391 
392  std::string printHeader( void ) const {
393  std::stringstream hist;
394  hist << " ";
395  hist << std::setw(6) << std::left << "iter";
396  hist << std::setw(15) << std::left << "value";
397  hist << std::setw(15) << std::left << "gnorm";
398  hist << std::setw(15) << std::left << "snorm";
399  hist << std::setw(10) << std::left << "#fval";
400  hist << std::setw(10) << std::left << "#grad";
401  hist << std::setw(15) << std::left << "znorm";
402  hist << std::setw(15) << std::left << "alpha";
403  hist << std::setw(15) << std::left << "TRparam";
404  hist << std::setw(10) << std::left << "QPiter";
405  hist << "\n";
406  return hist.str();
407  }
408 
409  std::string printName( void ) const {
410  std::stringstream hist;
411  hist << "\n" << "Bundle Trust-Region Algorithm \n";
412  return hist.str();
413  }
414 
415  std::string print( AlgorithmState<Real> &algo_state, bool print_header = false ) const {
416  const ROL::Ptr<const StepState<Real> > state = Step<Real>::getStepState();
417  std::stringstream hist;
418  hist << std::scientific << std::setprecision(6);
419  if ( algo_state.iter == 0 && first_print_ ) {
420  hist << printName();
421  if ( print_header ) {
422  hist << printHeader();
423  }
424  hist << " ";
425  hist << std::setw(6) << std::left << algo_state.iter;
426  hist << std::setw(15) << std::left << algo_state.value;
427  hist << std::setw(15) << std::left << algo_state.gnorm;
428  hist << "\n";
429  }
430  if ( step_flag_==1 && algo_state.iter > 0 ) {
431  if ( print_header ) {
432  hist << printHeader();
433  }
434  else {
435  hist << " ";
436  hist << std::setw(6) << std::left << algo_state.iter;
437  hist << std::setw(15) << std::left << algo_state.value;
438  hist << std::setw(15) << std::left << algo_state.gnorm;
439  hist << std::setw(15) << std::left << algo_state.snorm;
440  hist << std::setw(10) << std::left << algo_state.nfval;
441  hist << std::setw(10) << std::left << algo_state.ngrad;
442  hist << std::setw(15) << std::left << algo_state.aggregateGradientNorm;
443  hist << std::setw(15) << std::left << algo_state.aggregateModelError;
444  hist << std::setw(15) << std::left << state->searchSize;
445  hist << std::setw(10) << std::left << QPiter_;
446  hist << "\n";
447  }
448  }
449  return hist.str();
450  };
451 
452 }; // class BundleStep
453 
454 } // namespace ROL
455 
456 #endif
Provides the interface to evaluate objective functions.
virtual void scale(const Real alpha)=0
Compute where .
virtual ROL::Ptr< Vector > clone() const =0
Clone to make a new (uninitialized) vector.
ROL::Ptr< Vector< Real > > y_
virtual void plus(const Vector &x)=0
Compute , where .
virtual Real value(const Vector< Real > &x, Real &tol)=0
Compute value.
Provides the interface to compute optimization steps.
Definition: ROL_Step.hpp:34
Contains definitions of custom data types in ROL.
BundleStep(ROL::ParameterList &parlist)
std::string printName(void) const
Print step name.
virtual void zero()
Set to zero vector.
Definition: ROL_Vector.hpp:133
Defines the linear algebra or vector space interface.
Definition: ROL_Vector.hpp:46
virtual void update(const Vector< Real > &x, UpdateType type, int iter=-1)
Update objective function.
virtual Real dot(const Vector &x) const =0
Compute where .
Objective_SerialSimOpt(const Ptr< Obj > &obj, const V &ui) z0_ zero()
State for algorithm class. Will be used for restarts.
Definition: ROL_Types.hpp:109
virtual void gradient(Vector< Real > &g, const Vector< Real > &x, Real &tol)
Compute gradient.
ROL::Ptr< StepState< Real > > getState(void)
Definition: ROL_Step.hpp:39
void initialize(Vector< Real > &x, const Vector< Real > &g, Objective< Real > &obj, BoundConstraint< Real > &con, AlgorithmState< Real > &algo_state)
Initialize step with bound constraint.
ROL::Ptr< Vector< Real > > iterateVec
Definition: ROL_Types.hpp:123
std::string printHeader(void) const
Print iterate header.
Provides the interface to apply upper and lower bound constraints.
void update(Vector< Real > &x, const Vector< Real > &s, Objective< Real > &obj, BoundConstraint< Real > &con, AlgorithmState< Real > &algo_state)
Update step, if successful.
std::string print(AlgorithmState< Real > &algo_state, bool print_header=false) const
Print iterate status.
void compute(Vector< Real > &s, const Vector< Real > &x, Objective< Real > &obj, BoundConstraint< Real > &con, AlgorithmState< Real > &algo_state)
Compute step.
Provides the interface to compute bundle trust-region steps.
ROL::Ptr< Vector< Real > > aggSubGradNew_
virtual void initialize(Vector< Real > &x, const Vector< Real > &g, Objective< Real > &obj, BoundConstraint< Real > &con, AlgorithmState< Real > &algo_state)
Initialize step with bound constraint.
Definition: ROL_Step.hpp:54
virtual void set(const Vector &x)
Set where .
Definition: ROL_Vector.hpp:175
Real ROL_EPSILON(void)
Platform-dependent machine epsilon.
Definition: ROL_Types.hpp:57
ROL::Ptr< Bundle< Real > > bundle_
ROL::Ptr< LineSearch< Real > > lineSearch_
const ROL::Ptr< const StepState< Real > > getStepState(void) const
Get state for step object.
Definition: ROL_Step.hpp:177