ROL
ROL_lSR1.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_LSR1_H
11 #define ROL_LSR1_H
12 
17 #include "ROL_Secant.hpp"
18 #include "ROL_Types.hpp"
19 
20 namespace ROL {
21 
22 template<class Real>
23 class lSR1 : public Secant<Real> {
24 private:
25 
26  //mutable bool updateIterate_;
28  mutable bool H0called_, B0called_;
29  Ptr<Vector<Real>> Bs_, Hy_, prim_, dual_;
30 
32  using Secant<Real>::y_;
35 
36 public:
37  lSR1(int M, bool useDefaultScaling = true, Real Bscaling = Real(1), ESecantMode mode = SECANTMODE_BOTH)
39  H0called_(false), B0called_(false) {
40  if (useDefaultScaling_) Bscaling_ = static_cast<Real>(1);
41  //updateIterate_ = true;
42  }
43 
44  // Update Secant Approximation
45  void updateStorage( const Vector<Real> &x, const Vector<Real> &grad,
46  const Vector<Real> &gp, const Vector<Real> &s,
47  const Real snorm, const int iter ) {
48  const Real one(1), tol(std::sqrt(ROL_EPSILON<Real>()));
49  if ( !isInitialized_ ) {
50  state_->iterate = x.clone();
51  y_ = grad.clone();
52  if (state_->mode == SECANTMODE_FORWARD) {
53  Bs_ = grad.clone(); dual_ = grad.clone();
54  }
55  else if (state_->mode == SECANTMODE_INVERSE) {
56  Hy_ = x.clone(); prim_ = x.clone();
57  }
58  else {
59  Bs_ = grad.clone(); dual_ = grad.clone();
60  Hy_ = x.clone(); prim_ = x.clone();
61  }
62  isInitialized_ = true;
63  }
64 
65  // Update iterate
66  state_->iter = iter;
67  state_->iterate->set(x);
68 
69  // Compute gradient difference
70  y_->set(grad);
71  y_->axpy(-one,gp);
72 
73  Real dotF(ROL_INF<Real>()), tolF(0), dotI(ROL_INF<Real>()), tolI(0);
74  if (state_->mode == SECANTMODE_FORWARD || state_->mode == SECANTMODE_BOTH) {
75  // Compute y - Bs and <s, y - Bs>
76  applyB(*Bs_,s);
77  Bs_->scale(-one);
78  Bs_->plus(*y_);
79  //dotF = s.dot(Bs_->dual());
80  dotF = s.apply(*Bs_);
81  tolF = tol*snorm*Bs_->norm();
82  }
83  if (state_->mode == SECANTMODE_INVERSE || state_->mode == SECANTMODE_BOTH) {
84  // Compute s - Hy and <y, s - Hy>
85  applyH(*Hy_,*y_);
86  Hy_->scale(-one);
87  Hy_->plus(s);
88  //dotI = y_->dot(Hy_->dual());
89  dotI = y_->apply(*Hy_);
90  tolI = tol*y_->norm()*Hy_->norm();
91  }
92  if (std::abs(dotF) > tolF && std::abs(dotI) > tolI) {
93  if (state_->current < state_->storage-1) {
94  state_->current++;
95  if (state_->mode == SECANTMODE_INVERSE || state_->mode == SECANTMODE_BOTH) {
96  state_->iterDiff.push_back(x.clone()); // Create new memory
97  }
98  if (state_->mode == SECANTMODE_FORWARD || state_->mode == SECANTMODE_BOTH) {
99  state_->gradDiff.push_back(grad.clone()); // Create new memory
100  }
101  }
102  else {
103  if (state_->mode == SECANTMODE_INVERSE || state_->mode == SECANTMODE_BOTH) {
104  state_->iterDiff.push_back(state_->iterDiff[0]); // Move first element to the last
105  state_->iterDiff.erase(state_->iterDiff.begin()); // Remove first element of s list
106  state_->product2.erase(state_->product2.begin()); // Remove first element of rho list
107  }
108  if (state_->mode == SECANTMODE_FORWARD || state_->mode == SECANTMODE_BOTH) {
109  state_->gradDiff.push_back(state_->gradDiff[0]); // Move first element to the last
110  state_->gradDiff.erase(state_->gradDiff.begin()); // Remove first element of y list
111  state_->product.erase(state_->product.begin()); // Remove first element of rho list
112  }
113  }
114  if (state_->mode == SECANTMODE_INVERSE || state_->mode == SECANTMODE_BOTH) {
115  state_->iterDiff[state_->current]->set(*Hy_); // s_k - H_k y_k
116  state_->product2.push_back(dotI); // (s_k - H_k y_k)' y_k
117  }
118  if (state_->mode == SECANTMODE_FORWARD || state_->mode == SECANTMODE_BOTH) {
119  state_->gradDiff[state_->current]->set(*Bs_); // y_k - B_k s_k
120  state_->product.push_back(dotF); // (y_k - B_k s_k)' s_k
121  }
122  //if (useDefaultScaling_) Bscaling_ = s.dot(y_->dual())/(snorm*snorm);
123  if (useDefaultScaling_) Bscaling_ = s.apply(*y_)/(snorm*snorm);
124  }
125  /*
126  const Real one(1);
127  if ( !isInitialized_ ) {
128  state_->iterate = x.clone();
129  y_ = grad.clone();
130  isInitialized_ = true;
131  }
132 
133  state_->iterate->set(x);
134  state_->iter = iter;
135  y_->set(grad);
136  y_->axpy(-one,gp);
137 
138  if (updateIterate_ || state_->current == -1) {
139  Real sy = s.dot(y_->dual());
140  if (state_->current < state_->storage-1) {
141  state_->current++; // Increment Storage
142  state_->iterDiff.push_back(s.clone()); // Create new memory
143  state_->gradDiff.push_back(grad.clone()); // Create new memory
144  }
145  else {
146  state_->iterDiff.push_back(state_->iterDiff[0]); // Move first element to the last
147  state_->gradDiff.push_back(state_->gradDiff[0]); // Move first element to the last
148  state_->iterDiff.erase(state_->iterDiff.begin()); // Remove first element of s list
149  state_->gradDiff.erase(state_->gradDiff.begin()); // Remove first element of y list
150  state_->product.erase(state_->product.begin()); // Remove first element of rho list
151  }
152  state_->iterDiff[state_->current]->set(s); // s=x_{k+1}-x_k
153  state_->gradDiff[state_->current]->set(*y_); // y=g_{k+1}-g_k
154  state_->product.push_back(sy); // ys=1/rho
155  }
156  updateIterate_ = true;
157  */
158  }
159 
160  // Apply Initial Secant Approximate Inverse Hessian
161  virtual void applyH0( Vector<Real> &Hv, const Vector<Real> &v ) const {
162  if (state_->current > -1) {
163  prim_->set(v.dual());
164  Hv.set(*prim_);
165  H0called_ = true;
166  }
167  else {
168  Hv.set(v.dual());
169  }
170  Hv.scale(static_cast<Real>(1)/Bscaling_);
171  }
172 
173  // Apply lSR1 Approximate Inverse Hessian
174  void applyH( Vector<Real> &Hv, const Vector<Real> &v ) const {
175  if (state_->mode == SECANTMODE_INVERSE || state_->mode == SECANTMODE_BOTH) {
176  // Apply initial Hessian approximation to v
177  H0called_ = false;
178  applyH0(Hv,v);
179  // Apply rank one updates
180  if (state_->current > -1) {
181  Real prod(0);
182  if (!H0called_) prim_->set(v.dual());
183  for (int i = 0; i <= state_->current; ++i) {
184  prod = state_->iterDiff[i]->dot(*prim_);
185  Hv.axpy(prod/state_->product2[i],*state_->iterDiff[i]);
186  }
187  }
188  }
189  else {
190  throw Exception::NotImplemented(">>> ROL::lSR1::applyH : Not supported in forward mode!");
191  }
192  /*
193  std::vector<Ptr<Vector<Real>>> a(state_->current+1);
194  std::vector<Ptr<Vector<Real>>> b(state_->current+1);
195  Real byi(0), byj(0), bv(0), normbi(0), normyi(0), one(1);
196  for (int i = 0; i <= state_->current; i++) {
197  // Compute Hy
198  a[i] = Hv.clone();
199  applyH0(*(a[i]),*(state_->gradDiff[i]));
200  for (int j = 0; j < i; j++) {
201  byj = b[j]->dot((state_->gradDiff[j])->dual());
202  byi = b[j]->dot((state_->gradDiff[i])->dual());
203  a[i]->axpy(byi/byj,*(b[j]));
204  }
205  // Compute s - Hy
206  b[i] = Hv.clone();
207  b[i]->set(*(state_->iterDiff[i]));
208  b[i]->axpy(-one,*(a[i]));
209 
210  // Compute Hv
211  byi = b[i]->dot((state_->gradDiff[i])->dual());
212  normbi = b[i]->norm();
213  normyi = (state_->gradDiff[i])->norm();
214  if ( i == state_->current && std::abs(byi) < sqrt(ROL_EPSILON<Real>())*normbi*normyi ) {
215  updateIterate_ = false;
216  }
217  else {
218  updateIterate_ = true;
219  bv = b[i]->dot(v.dual());
220  Hv.axpy(bv/byi,*(b[i]));
221  }
222  }
223  */
224  }
225 
226  // Apply Initial Secant Approximate Hessian
227  virtual void applyB0( Vector<Real> &Bv, const Vector<Real> &v ) const {
228  if (state_->current > -1) {
229  dual_->set(v.dual());
230  Bv.set(*dual_);
231  B0called_ = true;
232  }
233  else {
234  Bv.set(v.dual());
235  }
236  Bv.scale(Bscaling_);
237  }
238 
239  // Apply lSR1 Approximate Hessian
240  void applyB( Vector<Real> &Bv, const Vector<Real> &v ) const {
241  if (state_->mode == SECANTMODE_FORWARD || state_->mode == SECANTMODE_BOTH) {
242  // Apply initial Hessian approximation to v
243  B0called_ = false;
244  applyB0(Bv,v);
245  // Apply rank one updates
246  if (state_->current > -1) {
247  Real prod(0);
248  if (!B0called_) dual_->set(v.dual());
249  for (int i = 0; i <= state_->current; ++i) {
250  prod = state_->gradDiff[i]->dot(*dual_);
251  Bv.axpy(prod/state_->product[i],*state_->gradDiff[i]);
252  }
253  }
254  }
255  else {
256  throw Exception::NotImplemented(">>> ROL::lSR1::applyB : Not supported in inverse mode!");
257  }
258  /*
259  std::vector<Ptr<Vector<Real>>> a(state_->current+1);
260  std::vector<Ptr<Vector<Real>>> b(state_->current+1);
261  Real bsi(0), bsj(0), bv(0), normbi(0), normsi(0), one(1);
262  for (int i = 0; i <= state_->current; i++) {
263  // Compute Hy
264  a[i] = Bv.clone();
265  applyB0(*(a[i]),*(state_->iterDiff[i]));
266  for (int j = 0; j < i; j++) {
267  bsj = (state_->iterDiff[j])->dot(b[j]->dual());
268  bsi = (state_->iterDiff[i])->dot(b[j]->dual());
269  a[i]->axpy(bsi/bsj,*(b[j]));
270  }
271  // Compute s - Hy
272  b[i] = Bv.clone();
273  b[i]->set(*(state_->gradDiff[i]));
274  b[i]->axpy(-one,*(a[i]));
275 
276  // Compute Hv
277  bsi = (state_->iterDiff[i])->dot(b[i]->dual());
278  normbi = b[i]->norm();
279  normsi = (state_->iterDiff[i])->norm();
280  if ( i == state_->current && std::abs(bsi) < sqrt(ROL_EPSILON<Real>())*normbi*normsi ) {
281  updateIterate_ = false;
282  }
283  else {
284  updateIterate_ = true;
285  bv = b[i]->dot(v.dual());
286  Bv.axpy(bv/bsi,*(b[i]));
287  }
288  }
289  */
290  }
291 };
292 
293 }
294 
295 #endif
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
virtual void scale(const Real alpha)=0
Compute where .
virtual ROL::Ptr< Vector > clone() const =0
Clone to make a new (uninitialized) vector.
virtual Real apply(const Vector< Real > &x) const
Apply to a dual vector. This is equivalent to the call .
Definition: ROL_Vector.hpp:204
virtual void applyB0(Vector< Real > &Bv, const Vector< Real > &v) const
Definition: ROL_lSR1.hpp:227
virtual void axpy(const Real alpha, const Vector &x)
Compute where .
Definition: ROL_Vector.hpp:119
void applyB(Vector< Real > &Bv, const Vector< Real > &v) const
Definition: ROL_lSR1.hpp:240
useDefaultScaling
Definition: ROL_lSR1.hpp:38
void applyH(Vector< Real > &Hv, const Vector< Real > &v) const
Definition: ROL_lSR1.hpp:174
Contains definitions of custom data types in ROL.
Provides definitions for limited-memory SR1 operators.
Definition: ROL_lSR1.hpp:23
virtual void applyH0(Vector< Real > &Hv, const Vector< Real > &v) const
Definition: ROL_lSR1.hpp:161
bool useDefaultScaling_
Definition: ROL_Secant.hpp:50
bool isInitialized_
Definition: ROL_lSR1.hpp:27
Defines the linear algebra or vector space interface.
Definition: ROL_Vector.hpp:46
bool B0called_
Definition: ROL_lSR1.hpp:28
Ptr< Vector< Real > > y_
Definition: ROL_Secant.hpp:49
ESecantMode
Definition: ROL_Secant.hpp:23
Provides interface for and implements limited-memory secant operators.
Definition: ROL_Secant.hpp:45
Ptr< Vector< Real > > dual_
Definition: ROL_lSR1.hpp:29
Ptr< Vector< Real > > Bs_
Definition: ROL_lSR1.hpp:29
Ptr< Vector< Real > > Hy_
Definition: ROL_lSR1.hpp:29
const Ptr< SecantState< Real > > state_
Definition: ROL_Secant.hpp:48
Ptr< Vector< Real > > prim_
Definition: ROL_lSR1.hpp:29
virtual void set(const Vector &x)
Set where .
Definition: ROL_Vector.hpp:175
Real Bscaling_
Definition: ROL_Secant.hpp:51
bool H0called_
Definition: ROL_lSR1.hpp:28
void updateStorage(const Vector< Real > &x, const Vector< Real > &grad, const Vector< Real > &gp, const Vector< Real > &s, const Real snorm, const int iter)
Definition: ROL_lSR1.hpp:45