ROL
ROL_PoissonInversion.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
15#ifndef USE_HESSVEC
16#define USE_HESSVEC 1
17#endif
18
19#ifndef ROL_POISSONINVERSION_HPP
20#define ROL_POISSONINVERSION_HPP
21
22#include "ROL_StdVector.hpp"
23#include "ROL_TestProblem.hpp"
25
26#include "ROL_LAPACK.hpp"
27#include "ROL_LinearAlgebra.hpp"
28
29namespace ROL {
30namespace ZOO {
31
34template<class Real>
36
37 typedef std::vector<Real> vector;
38 typedef Vector<Real> V;
40
41 typedef typename vector::size_type uint;
42
43private:
46
47 Real hu_;
48 Real hz_;
49
50 Real alpha_;
51
52 Real eps_;
54
55 ROL::Ptr<const vector> getVector( const V& x ) {
56
57 return dynamic_cast<const SV&>(x).getVector();
58 }
59
60 ROL::Ptr<vector> getVector( V& x ) {
61
62 return dynamic_cast<SV&>(x).getVector();
63 }
64
65public:
66
67 /* CONSTRUCTOR */
68 Objective_PoissonInversion(uint nz = 32, Real alpha = 1.e-4)
69 : nu_(nz-1), nz_(nz), hu_(1./((Real)nu_+1.)), hz_(hu_),
70 alpha_(alpha), eps_(1.e-4), reg_type_(2) {}
71
72 /* REGULARIZATION DEFINITIONS */
73 Real reg_value(const Vector<Real> &z) {
74
75
76 ROL::Ptr<const vector> zp = getVector(z);
77
78 Real val = 0.0;
79 for (uint i = 0; i < nz_; i++) {
80 if ( reg_type_ == 2 ) {
81 val += alpha_/2.0 * hz_ * (*zp)[i]*(*zp)[i];
82 }
83 else if ( reg_type_ == 1 ) {
84 val += alpha_ * hz_ * std::sqrt((*zp)[i]*(*zp)[i] + eps_);
85 }
86 else if ( reg_type_ == 0 ) {
87 if ( i < nz_-1 ) {
88 val += alpha_ * std::sqrt(std::pow((*zp)[i]-(*zp)[i+1],2.0)+eps_);
89 }
90 }
91 }
92 return val;
93 }
94
96
97
98 if ( reg_type_ == 2 ) {
99 g.set(z);
100 g.scale(alpha_*hz_);
101 }
102 else if ( reg_type_ == 1 ) {
103 ROL::Ptr<const vector> zp = getVector(z);
104 ROL::Ptr<vector > gp = getVector(g);
105
106 for (uint i = 0; i < nz_; i++) {
107 (*gp)[i] = alpha_ * hz_ * (*zp)[i]/std::sqrt(std::pow((*zp)[i],2.0)+eps_);
108 }
109 }
110 else if ( reg_type_ == 0 ) {
111 ROL::Ptr<const vector> zp = getVector(z);
112 ROL::Ptr<vector> gp = getVector(g);
113
114 Real diff = 0.0;
115 for (uint i = 0; i < nz_; i++) {
116 if ( i == 0 ) {
117 diff = (*zp)[i]-(*zp)[i+1];
118 (*gp)[i] = alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
119 }
120 else if ( i == nz_-1 ) {
121 diff = (*zp)[i-1]-(*zp)[i];
122 (*gp)[i] = -alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
123 }
124 else {
125 diff = (*zp)[i]-(*zp)[i+1];
126 (*gp)[i] = alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
127 diff = (*zp)[i-1]-(*zp)[i];
128 (*gp)[i] -= alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
129 }
130 }
131 }
132 }
133
134 void reg_hessVec(Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &z) {
135
136
137
138 if ( reg_type_ == 2 ) {
139 hv.set(v);
140 hv.scale(alpha_*hz_);
141 }
142 else if ( reg_type_ == 1 ) {
143 ROL::Ptr<const vector> zp = getVector(z);
144 ROL::Ptr<const vector> vp = getVector(v);
145 ROL::Ptr<vector> hvp = getVector(hv);
146
147 for (uint i = 0; i < nz_; i++) {
148 (*hvp)[i] = alpha_*hz_*(*vp)[i]*eps_/std::pow(std::pow((*zp)[i],2.0)+eps_,3.0/2.0);
149 }
150 }
151 else if ( reg_type_ == 0 ) {
152 ROL::Ptr<const vector> zp = getVector(z);
153 ROL::Ptr<const vector> vp = getVector(v);
154 ROL::Ptr<vector> hvp = getVector(hv);
155
156 Real diff1 = 0.0;
157 Real diff2 = 0.0;
158 for (uint i = 0; i < nz_; i++) {
159 if ( i == 0 ) {
160 diff1 = (*zp)[i]-(*zp)[i+1];
161 diff1 = eps_/std::pow(std::pow(diff1,2.0)+eps_,3.0/2.0);
162 (*hvp)[i] = alpha_* ((*vp)[i]*diff1 - (*vp)[i+1]*diff1);
163 }
164 else if ( i == nz_-1 ) {
165 diff2 = (*zp)[i-1]-(*zp)[i];
166 diff2 = eps_/std::pow(std::pow(diff2,2.0)+eps_,3.0/2.0);
167 (*hvp)[i] = alpha_* (-(*vp)[i-1]*diff2 + (*vp)[i]*diff2);
168 }
169 else {
170 diff1 = (*zp)[i]-(*zp)[i+1];
171 diff1 = eps_/std::pow(std::pow(diff1,2.0)+eps_,3.0/2.0);
172 diff2 = (*zp)[i-1]-(*zp)[i];
173 diff2 = eps_/std::pow(std::pow(diff2,2.0)+eps_,3.0/2.0);
174 (*hvp)[i] = alpha_* (-(*vp)[i-1]*diff2 + (*vp)[i]*(diff1 + diff2) - (*vp)[i+1]*diff1);
175 }
176 }
177 }
178 }
179
180 /* FINITE ELEMENT DEFINTIONS */
181 void apply_mass(Vector<Real> &Mf, const Vector<Real> &f ) {
182
183
184 ROL::Ptr<const vector> fp = getVector(f);
185 ROL::Ptr<vector> Mfp = getVector(Mf);
186
187 for (uint i = 0; i < nu_; i++) {
188 if ( i == 0 ) {
189 (*Mfp)[i] = hu_/6.0*(4.0*(*fp)[i] + (*fp)[i+1]);
190 }
191 else if ( i == nu_-1 ) {
192 (*Mfp)[i] = hu_/6.0*((*fp)[i-1] + 4.0*(*fp)[i]);
193 }
194 else {
195 (*Mfp)[i] = hu_/6.0*((*fp)[i-1] + 4.0*(*fp)[i] + (*fp)[i+1]);
196 }
197 }
198 }
199
201
202
203 ROL::Ptr<const vector> zp = getVector(z);
204 ROL::Ptr<vector> up = getVector(u);
205 ROL::Ptr<vector> bp = getVector(b);
206
207 // Get Diagonal and Off-Diagonal Entries of PDE Jacobian
208 vector d(nu_,1.0);
209 vector o(nu_-1,1.0);
210 for ( uint i = 0; i < nu_; i++ ) {
211 d[i] = (std::exp((*zp)[i]) + std::exp((*zp)[i+1]))/hu_;
212 if ( i < nu_-1 ) {
213 o[i] *= -std::exp((*zp)[i+1])/hu_;
214 }
215 }
216
217 // Solve Tridiagonal System Using LAPACK's SPD Tridiagonal Solver
218 ROL::LAPACK<int,Real> lp;
219 int info;
220 int ldb = nu_;
221 int nhrs = 1;
222 lp.PTTRF(nu_,&d[0],&o[0],&info);
223 lp.PTTRS(nu_,nhrs,&d[0],&o[0],&(*bp)[0],ldb,&info);
224 u.set(b);
225 }
226
227 Real evaluate_target(Real x) {
228 return x*(1.0-x);
229 }
230
232 const Vector<Real> &d, const Vector<Real> &u ) {
233
234
235
236 ROL::Ptr<const vector> zp = getVector(z);
237 ROL::Ptr<const vector> up = getVector(u);
238 ROL::Ptr<const vector> dp = getVector(d);
239 ROL::Ptr<vector> Bdp = getVector(Bd);
240
241 for (uint i = 0; i < nu_; i++) {
242 if ( i == 0 ) {
243 (*Bdp)[i] = 1.0/hu_*( std::exp((*zp)[i])*(*up)[i]*(*dp)[i]
244 + std::exp((*zp)[i+1])*((*up)[i]-(*up)[i+1])*(*dp)[i+1] );
245 }
246 else if ( i == nu_-1 ) {
247 (*Bdp)[i] = 1.0/hu_*( std::exp((*zp)[i])*((*up)[i]-(*up)[i-1])*(*dp)[i]
248 + std::exp((*zp)[i+1])*(*up)[i]*(*dp)[i+1] );
249 }
250 else {
251 (*Bdp)[i] = 1.0/hu_*( std::exp((*zp)[i])*((*up)[i]-(*up)[i-1])*(*dp)[i]
252 + std::exp((*zp)[i+1])*((*up)[i]-(*up)[i+1])*(*dp)[i+1] );
253 }
254 }
255 }
256
258 const Vector<Real> &d, const Vector<Real> &u ) {
259
260
261 ROL::Ptr<const vector> zp = getVector(z);
262 ROL::Ptr<const vector> up = getVector(u);
263 ROL::Ptr<const vector> dp = getVector(d);
264 ROL::Ptr<vector> Bdp = getVector(Bd);
265
266 for (uint i = 0; i < nz_; i++) {
267 if ( i == 0 ) {
268 (*Bdp)[i] = std::exp((*zp)[i])/hu_*(*up)[i]*(*dp)[i];
269 }
270 else if ( i == nz_-1 ) {
271 (*Bdp)[i] = std::exp((*zp)[i])/hu_*(*up)[i-1]*(*dp)[i-1];
272 }
273 else {
274 (*Bdp)[i] = std::exp((*zp)[i])/hu_*( ((*up)[i]-(*up)[i-1])*((*dp)[i]-(*dp)[i-1]) );
275 }
276 }
277 }
278
280 const Vector<Real> &d, const Vector<Real> &u ) {
281
282 ROL::Ptr<const vector> zp = getVector(z);
283 ROL::Ptr<const vector> vp = getVector(v);
284 ROL::Ptr<const vector> up = getVector(u);
285 ROL::Ptr<const vector> dp = getVector(d);
286 ROL::Ptr<vector> Bdp = getVector(Bd);
287
288 for (uint i = 0; i < nz_; i++) {
289 if ( i == 0 ) {
290 (*Bdp)[i] = (*vp)[i]*std::exp((*zp)[i])/hu_*(*up)[i]*(*dp)[i];
291 }
292 else if ( i == nz_-1 ) {
293 (*Bdp)[i] = (*vp)[i]*std::exp((*zp)[i])/hu_*(*up)[i-1]*(*dp)[i-1];
294 }
295 else {
296 (*Bdp)[i] = (*vp)[i]*std::exp((*zp)[i])/hu_*( ((*up)[i]-(*up)[i-1])*((*dp)[i]-(*dp)[i-1]) );
297 }
298 }
299 }
300
301 /* STATE AND ADJOINT EQUATION DEFINTIONS */
303
304
305
306
307 Real k1 = 1.0;
308 Real k2 = 2.0;
309 // Right Hand Side
310 ROL::Ptr<vector> bp = ROL::makePtr<vector>(nu_, 0.0);
311 for ( uint i = 0; i < nu_; i++ ) {
312 if ( (Real)(i+1)*hu_ < 0.5 ) {
313 (*bp)[i] = 2.0*k1*hu_;
314 }
315 else if ( std::abs((Real)(i+1)*hu_ - 0.5) < ROL_EPSILON<Real>() ) {
316 (*bp)[i] = (k1+k2)*hu_;
317 }
318 else if ( (Real)(i+1)*hu_ > 0.5 ) {
319 (*bp)[i] = 2.0*k2*hu_;
320 }
321 }
322
323 SV b(bp);
324 // Solve Equation
325 solve_poisson(u,z,b);
326 }
327
329
330
331
332
333 ROL::Ptr<const vector> up = getVector(u);
334 ROL::Ptr<vector> rp = ROL::makePtr<vector>(nu_,0.0);
335 SV res(rp);
336
337 for ( uint i = 0; i < nu_; i++) {
338 (*rp)[i] = -((*up)[i]-evaluate_target((Real)(i+1)*hu_));
339 }
340 StdVector<Real> Mres( ROL::makePtr<std::vector<Real>>(nu_,0.0) );
341 apply_mass(Mres,res);
342 solve_poisson(p,z,Mres);
343 }
344
346 const Vector<Real> &u, const Vector<Real> &z) {
347
348
349 SV b( ROL::makePtr<vector>(nu_,0.0) );
351 solve_poisson(w,z,b);
352 }
353
355 const Vector<Real> &p, const Vector<Real> &u, const Vector<Real> &z) {
356
357
358
359 SV res( ROL::makePtr<vector>(nu_,0.0) );
360 apply_mass(res,w);
361 SV res1( ROL::makePtr<vector>(nu_,0.0) );
363 res.axpy(-1.0,res1);
364 solve_poisson(q,z,res);
365 }
366
367 /* OBJECTIVE FUNCTION DEFINITIONS */
368 Real value( const Vector<Real> &z, Real &tol ) {
369
370
371
372
373 // SOLVE STATE EQUATION
374 ROL::Ptr<vector> up = ROL::makePtr<vector>(nu_,0.0);
375 SV u( up );
376
378
379 // COMPUTE MISFIT
380 ROL::Ptr<vector> rp = ROL::makePtr<vector>(nu_,0.0);
381 SV res( rp );
382
383 for ( uint i = 0; i < nu_; i++) {
384 (*rp)[i] = ((*up)[i]-evaluate_target((Real)(i+1)*hu_));
385 }
386
387 ROL::Ptr<V> Mres = res.clone();
388 apply_mass(*Mres,res);
389 return 0.5*Mres->dot(res) + reg_value(z);
390 }
391
392 void gradient( Vector<Real> &g, const Vector<Real> &z, Real &tol ) {
393
394
395
396 // SOLVE STATE EQUATION
397 SV u( ROL::makePtr<vector>(nu_,0.0) );
399
400 // SOLVE ADJOINT EQUATION
401 SV p( ROL::makePtr<std::vector<Real>>(nu_,0.0) );
403
404 // Apply Transpose of Linearized Control Operator
406
407 // Regularization gradient
408 SV g_reg( ROL::makePtr<vector>(nz_,0.0) );
409 reg_gradient(g_reg,z);
410
411 // Build Gradient
412 g.plus(g_reg);
413 }
414#if USE_HESSVEC
415 void hessVec( Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &z, Real &tol ) {
416
417
418
419 // SOLVE STATE EQUATION
420 SV u( ROL::makePtr<vector>(nu_,0.0) );
422
423 // SOLVE ADJOINT EQUATION
424 SV p( ROL::makePtr<vector>(nu_,0.0) );
426
427 // SOLVE STATE SENSITIVITY EQUATION
428 SV w( ROL::makePtr<vector>(nu_,0.0) );
430
431 // SOLVE ADJOINT SENSITIVITY EQUATION
432 SV q( ROL::makePtr<vector>(nu_,0.0) );
434
435 // Apply Transpose of Linearized Control Operator
437
438 // Apply Transpose of Linearized Control Operator
439 SV tmp( ROL::makePtr<vector>(nz_,0.0) );
441 hv.axpy(-1.0,tmp);
442
443 // Apply Transpose of 2nd Derivative of Control Operator
444 tmp.zero();
446 hv.plus(tmp);
447
448 // Regularization hessVec
449 SV hv_reg( ROL::makePtr<vector>(nz_,0.0) );
450 reg_hessVec(hv_reg,v,z);
451
452 // Build hessVec
453 hv.plus(hv_reg);
454 }
455#endif
456
457 void invHessVec( Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &x, Real &tol ) {
458
459
460
461
462 // Cast hv and v vectors to std::vector.
463 ROL::Ptr<vector> hvp = getVector(hv);
464
465 std::vector<Real> vp(*getVector(v));
466
467 int dim = static_cast<int>(vp.size());
468
469
470 // Compute dense Hessian.
471 ROL::LA::Matrix<Real> H(dim, dim);
473 H = computeDenseHessian<Real>(obj, x);
474
475 // Compute eigenvalues, sort real part.
476 std::vector<vector> eigenvals = computeEigenvalues<Real>(H);
477 std::sort((eigenvals[0]).begin(), (eigenvals[0]).end());
478
479 // Perform 'inertia' correction.
480 Real inertia = (eigenvals[0])[0];
481 Real correction = 0.0;
482 if ( inertia <= 0.0 ) {
483 correction = 2.0*std::abs(inertia);
484 if ( inertia == 0.0 ) {
485 int cnt = 0;
486 while ( eigenvals[0][cnt] == 0.0 ) {
487 cnt++;
488 }
489 correction = 0.5*eigenvals[0][cnt];
490 if ( cnt == dim-1 ) {
491 correction = 1.0;
492 }
493 }
494 for (int i=0; i<dim; i++) {
495 H(i,i) += correction;
496 }
497 }
498
499 // Compute dense inverse Hessian.
500 ROL::LA::Matrix<Real> invH = computeInverse<Real>(H);
501
502 // Apply dense inverse Hessian using view constructors
503 ROL::LA::Vector<Real> hv_la(ROL::LA::View, &((*hvp)[0]), dim);
504 ROL::LA::Vector<Real> v_la(ROL::LA::View, &(vp[0]), dim);
505
506 // Apply matrix-vector multiply: hv_la = invH * v_la
507 for (int i = 0; i < dim; i++) {
508 hv_la(i) = 0.0;
509 for (int j = 0; j < dim; j++) {
510 hv_la(i) += invH(i,j) * v_la(j);
511 }
512 }
513 }
514
515};
516
517template<class Real>
518class getPoissonInversion : public TestProblem<Real> {
519public:
521
522 Ptr<Objective<Real>> getObjective(void) const {
523 // Problem dimension
524 int n = 128;
525 // Instantiate Objective Function
526 return ROL::makePtr<Objective_PoissonInversion<Real>>(n,1.e-6);
527 }
528
529 Ptr<Vector<Real>> getInitialGuess(void) const {
530 // Problem dimension
531 int n = 128;
532 // Get Initial Guess
533 ROL::Ptr<std::vector<Real> > x0p = ROL::makePtr<std::vector<Real>>(n,0.0);
534 for ( int i = 0; i < n; i++ ) {
535 (*x0p)[i] = 1.5;
536 }
537 return ROL::makePtr<StdVector<Real>>(x0p);
538 }
539
540 Ptr<Vector<Real>> getSolution(const int i = 0) const {
541 // Problem dimension
542 int n = 128;
543 // Get Solution
544 ROL::Ptr<std::vector<Real> > xp = ROL::makePtr<std::vector<Real>>(n,0.0);
545 Real h = 1.0/((Real)n+1), pt = 0.0, k1 = 1.0, k2 = 2.0;
546 for( int li = 0; li < n; li++ ) {
547 pt = (Real)(li+1)*h;
548 if ( pt >= 0.0 && pt < 0.5 ) {
549 (*xp)[li] = std::log(k1);
550 }
551 else if ( pt >= 0.5 && pt < 1.0 ) {
552 (*xp)[li] = std::log(k2);
553 }
554 }
555 return ROL::makePtr<StdVector<Real>>(xp);
556 }
557};
558
559} // End ZOO Namespace
560} // End ROL Namespace
561
562#endif
Contains definitions for helper functions in ROL.
Contains definitions of test objective functions.
Provides the interface to evaluate objective functions.
virtual void hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply Hessian approximation to vector.
Provides the ROL::Vector interface for scalar values, to be used, for example, with scalar constraint...
void axpy(const Real alpha, const Vector< Real > &x)
Compute where .
virtual Ptr< Vector< Real > > clone() const
Clone to make a new (uninitialized) vector.
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 void plus(const Vector &x)=0
Compute , where .
virtual void axpy(const Real alpha, const Vector &x)
Compute where .
void solve_adjoint_equation(Vector< Real > &p, const Vector< Real > &u, const Vector< Real > &z)
void solve_poisson(Vector< Real > &u, const Vector< Real > &z, Vector< Real > &b)
void solve_adjoint_sensitivity_equation(Vector< Real > &q, const Vector< Real > &w, const Vector< Real > &v, const Vector< Real > &p, const Vector< Real > &u, const Vector< Real > &z)
Real reg_value(const Vector< Real > &z)
void apply_mass(Vector< Real > &Mf, const Vector< Real > &f)
void reg_hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &z)
ROL::Ptr< const vector > getVector(const V &x)
void apply_transposed_linearized_control_operator(Vector< Real > &Bd, const Vector< Real > &z, const Vector< Real > &d, const Vector< Real > &u)
void solve_state_sensitivity_equation(Vector< Real > &w, const Vector< Real > &v, const Vector< Real > &u, const Vector< Real > &z)
void gradient(Vector< Real > &g, const Vector< Real > &z, Real &tol)
Compute gradient.
void solve_state_equation(Vector< Real > &u, const Vector< Real > &z)
void apply_linearized_control_operator(Vector< Real > &Bd, const Vector< Real > &z, const Vector< Real > &d, const Vector< Real > &u)
Objective_PoissonInversion(uint nz=32, Real alpha=1.e-4)
Real value(const Vector< Real > &z, Real &tol)
Compute value.
void reg_gradient(Vector< Real > &g, const Vector< Real > &z)
void apply_transposed_linearized_control_operator_2(Vector< Real > &Bd, const Vector< Real > &z, const Vector< Real > &v, const Vector< Real > &d, const Vector< Real > &u)
void invHessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply inverse Hessian approximation to vector.
Ptr< Vector< Real > > getInitialGuess(void) const
Ptr< Objective< Real > > getObjective(void) const
Ptr< Vector< Real > > getSolution(const int i=0) const
constexpr auto dim