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
20namespace ROL {
21
22template<class Real>
23class lSR1 : public Secant<Real> {
24private:
25
26 //mutable bool updateIterate_;
28 mutable bool H0called_, B0called_;
29 Ptr<Vector<Real>> Bs_, Hy_, prim_, dual_;
30
31 using Secant<Real>::state_;
32 using Secant<Real>::y_;
34 using Secant<Real>::Bscaling_;
35
36public:
37 lSR1(int M, bool useDefaultScaling = true, Real Bscaling = Real(1), ESecantMode mode = SECANTMODE_BOTH)
38 : Secant<Real>(M,useDefaultScaling,Bscaling,mode), isInitialized_(false),
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
Contains definitions of custom data types in ROL.
Provides interface for and implements limited-memory secant operators.
bool useDefaultScaling_
const Ptr< SecantState< Real > > state_
Ptr< Vector< Real > > y_
Defines the linear algebra or vector space interface.
virtual Real apply(const Vector< Real > &x) const
Apply to a dual vector. This is equivalent to the call .
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 ROL::Ptr< Vector > clone() const =0
Clone to make a new (uninitialized) vector.
virtual void axpy(const Real alpha, const Vector &x)
Compute where .
Provides definitions for limited-memory SR1 operators.
Definition ROL_lSR1.hpp:23
void applyB(Vector< Real > &Bv, const Vector< Real > &v) const
Definition ROL_lSR1.hpp:240
Ptr< Vector< Real > > Bs_
Definition ROL_lSR1.hpp:29
Ptr< Vector< Real > > Hy_
Definition ROL_lSR1.hpp:29
Ptr< Vector< Real > > dual_
Definition ROL_lSR1.hpp:29
bool isInitialized_
Definition ROL_lSR1.hpp:27
void applyH(Vector< Real > &Hv, const Vector< Real > &v) const
Definition ROL_lSR1.hpp:174
Ptr< Vector< Real > > prim_
Definition ROL_lSR1.hpp:29
bool B0called_
Definition ROL_lSR1.hpp:28
virtual void applyH0(Vector< Real > &Hv, const Vector< Real > &v) const
Definition ROL_lSR1.hpp:161
lSR1(int M, bool useDefaultScaling=true, Real Bscaling=Real(1), ESecantMode mode=SECANTMODE_BOTH)
Definition ROL_lSR1.hpp:37
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
virtual void applyB0(Vector< Real > &Bv, const Vector< Real > &v) const
Definition ROL_lSR1.hpp:227
bool H0called_
Definition ROL_lSR1.hpp:28
ESecantMode
@ SECANTMODE_FORWARD
@ SECANTMODE_INVERSE
@ SECANTMODE_BOTH