ROL
ROL_MINRES.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#pragma once
11#ifndef ROL_MINRES_HPP
12#define ROL_MINRES_HPP
13
14#include <array>
15#include "ROL_Krylov.hpp"
16#include "ROL_VectorClone.hpp"
17
18namespace ROL {
19
26namespace details {
27
28template<typename Real>
29class MINRES : public Krylov<Real> {
30
31 using V = Vector<Real>;
33
34private:
35
36 // Givens rotation matrix elements
40 std::array<Real,4> H_;
41 std::array<Real,2> rhs_;
42
44
45 void givens( Real& c, Real& s, Real& r, Real a, Real b ) const {
46
47 Real zero(0), one(1);
48
49 if( b == zero ) {
50 c = ( a >= zero ? one : -one );
51 s = zero;
52 r = std::abs(a);
53 }
54 else if( a == zero ) {
55 c = zero;
56 s = ( b >= zero ? one : -one );
57 r = std::abs(b);
58 }
59 else if( std::abs(a) > std::abs(b) ) {
60 auto t = b/a;
61 auto u = std::copysign(std::sqrt(one+t*t),a);
62 c = one/u;
63 s = c*t;
64 r = a*u;
65 }
66 else {
67 auto t = a/b;
68 auto u = std::copysign(std::sqrt(one+t*t),b);
69 s = 1/u;
70 c = s*t;
71 r = b*u;
72 }
73 } // givens()
74
75public:
76
77 MINRES( Real absTol = 1.e-4, Real relTol = 1.e-2, unsigned maxit = 100, bool useInexact = false) :
78 Krylov<Real>(absTol,relTol,maxit), useInexact_(useInexact),
79 clones_("v_prev","v_curr","v_next","w_prev","w_curr","w_next") { }
80
81 // Note: Preconditioner is not implemented
82 virtual Real run( V &x, OP &A, const V &b, OP &M, int &iter, int &flag ) override {
83
84 auto v_prev = clones_( x, "v_prev" ); v_prev->zero();
85 auto v_curr = clones_( x, "v_curr" ); v_curr->set(b);
86 auto v_next = clones_( x, "v_next" ); v_next->zero();
87 auto w_prev = clones_( x, "w_prev" ); w_prev->zero();
88 auto w_curr = clones_( x, "w_curr" ); w_curr->zero();
89 auto w_next = clones_( x, "w_next" ); w_next->zero();
90
91 Real c_prev{0}, s_prev{0}, c_curr{0}, s_curr{0}, c_next{0}, s_next{0};
92
93 resnorm_ = v_curr->norm();
95 Real itol = std::sqrt(ROL_EPSILON<Real>());
96
97 for( auto &e: H_ ) e = 0;
98
99 rhs_[0] = resnorm_; rhs_[1] = 0;
100
101 v_curr->scale(1.0/resnorm_);
102
103 for( iter=0; iter < (int)Krylov<Real>::getMaximumIteration(); iter++) {
104 if ( useInexact_ ) {
105 itol = rtol/((Real)Krylov<Real>::getMaximumIteration() * resnorm_);
106 }
107
108 if( resnorm_ < rtol ) break;
109
110 A.apply( *v_next, *v_curr, itol );
111
112 if( iter>0 ) v_next->axpy(-H_[1],*v_prev);
113
114 H_[2] = v_next->dot(*v_curr);
115
116 v_next->axpy(-H_[2],*v_curr);
117
118 H_[3] = v_next->norm();
119
120 v_next->scale(1.0/H_[3]);
121
122 // Rotation on H_[0] and H_[1].
123 if( iter>1 ) {
124 H_[0] = s_prev*H_[1];
125 H_[1] *= c_prev;
126 }
127
128 // Rotation on H_[1] and H_[2]
129 if( iter>0 ) {
130 auto tmp = c_curr*H_[2]-s_curr*H_[1];
131 H_[1] = c_curr*H_[1] + s_curr*H_[2];
132 H_[2] = tmp;
133 }
134
135 // Form rotation coefficients
136 givens( c_next, s_next, H_[2], H_[2], H_[3] );
137 rhs_[1] = -s_next*rhs_[0];
138 rhs_[0] *= c_next;
139
140 w_next->set( *v_curr );
141
142 if( iter>0 ) w_next->axpy( -H_[1], *w_curr );
143 if( iter>1 ) w_next->axpy( -H_[0], *w_prev );
144
145 w_next->scale(1.0/H_[2]);
146
147 x.axpy( rhs_[0], *w_next );
148
149 v_prev->set( *v_curr );
150 v_curr->set( *v_next );
151 w_prev->set( *w_curr );
152 w_curr->set( *w_next );
153
154 c_prev = c_curr;
155 c_curr = c_next;
156 s_prev = s_curr;
157 s_curr = s_next;
158
159 rhs_[0] = rhs_[1];
160
161 H_[1] = H_[3];
162
163 resnorm_ = std::abs( rhs_[1] );
164
165 } // for (iter)
166
167 if ( iter == (int)Krylov<Real>::getMaximumIteration() ) flag = 1;
168 else iter++;
169
170 return resnorm_;
171 } // run()
172
173}; // class MINRES
174
175} // namespace details
176
177
178using details::MINRES;
179
180
181} // namespace ROL
182
183
184#endif // ROL_MINRES_HPP
185
Objective_SerialSimOpt(const Ptr< Obj > &obj, const V &ui) z0_ zero()
Provides definitions for Krylov solvers.
Provides the interface to apply a linear operator.
virtual void apply(Vector< Real > &Hv, const Vector< Real > &v, Real &tol) const =0
Apply linear operator.
Defines the linear algebra or vector space interface.
virtual void axpy(const Real alpha, const Vector &x)
Compute where .
VectorCloneMap< Real > clones_
std::array< Real, 4 > H_
MINRES(Real absTol=1.e-4, Real relTol=1.e-2, unsigned maxit=100, bool useInexact=false)
virtual Real run(V &x, OP &A, const V &b, OP &M, int &iter, int &flag) override
std::array< Real, 2 > rhs_
void givens(Real &c, Real &s, Real &r, Real a, Real b) const