FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
secant_linesearch.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
8#include <kernel/solver/linesearch.hpp>
9
10namespace FEAT
11{
12 namespace Solver
13 {
31 template<typename Functional_, typename Filter_>
32 class SecantLinesearch : public Linesearch<Functional_, Filter_>
33 {
34 public:
36 typedef Filter_ FilterType;
38 typedef typename Functional_::VectorTypeR VectorType;
40 typedef typename Functional_::DataType DataType;
44 static constexpr DataType secant_step_default = DataType(1e-2);
45
46 protected:
49
50 public:
68 Functional_& functional, Filter_& filter,
69 const DataType secant_step = secant_step_default,
70 const bool keep_iterates = false) :
71 BaseClass("S-LS", functional, filter, keep_iterates),
72 _secant_step(secant_step)
73 {
74 this->_alpha_0 = _secant_step;
75 }
76
93 explicit SecantLinesearch(const String& section_name, const PropertyMap* section,
94 Functional_& functional, Filter_& filter) :
95 BaseClass("S-LS", section_name, section, functional, filter),
97 {
98 auto secant_step_p = section->query("secant_step");
99 if(secant_step_p.second)
100 {
101 set_secant_step(DataType(std::stod(secant_step_p.first)));
102 }
103
104 this->_alpha_0 = _secant_step;
105 }
106
109 {
110 }
111
113 virtual String name() const override
114 {
115 return "SecantLinesearch";
116 }
117
119 virtual void reset() override
120 {
122 this->_alpha_0 = _secant_step;
123 }
124
129 void set_secant_step(DataType secant_step)
130 {
131 XASSERT(secant_step > DataType(0));
132
133 _secant_step = secant_step;
134 }
135
147 virtual Status apply(VectorType& vec_cor, const VectorType& vec_dir) override
148 {
149 // clear solution vector
150 vec_cor.format();
151 this->_functional.prepare(vec_cor, this->_filter);
152
153 // apply
154 this->_status = _apply_intern(vec_cor, vec_dir);
155 this->plot_summary();
156 return this->_status;
157 }
158
170 virtual Status correct(VectorType& vec_sol, const VectorType& vec_dir) override
171 {
172 this->_functional.prepare(vec_sol, this->_filter);
173
174 // apply
175 this->_status = _apply_intern(vec_sol, vec_dir);
176 this->plot_summary();
177 return this->_status;
178 }
179
180 protected:
195 virtual Status _apply_intern(VectorType& vec_sol, const VectorType& vec_dir)
196 {
197 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
198
199 // The step length wrt. to the NORMALISED search direction
200 DataType alpha(0);
201 // The functional value
202 DataType fval(0);
204 DataType df(0);
205
206 // Perform initializations and checks
207 Status st = this->_startup(alpha, fval, df, vec_sol, vec_dir);
208 // Use the additional information about the preconditioned search direction's length?
209 if(this->_dir_scaling)
210 {
211 alpha *= this->_norm_dir;
212 }
213
214 DataType alpha_update(alpha);
215
216 // The second secant point in the first iteration is x + _secant_step * vec_dir
217 // The first "other" point for the secant
218 vec_sol.copy(this->_vec_initial_sol);
219 vec_sol.axpy(this->_vec_pn, alpha);
220
221 // start iterating
222 while(st == Status::progress)
223 {
224 IterationStats stat(*this);
225
226 // Increase iteration count
227 ++this->_num_iter;
228
229 this->_functional.prepare(vec_sol, this->_filter);
230 this->_functional.eval_fval_grad(fval, this->_vec_grad);
231 // DO NOT call trim() here, as this simple linesearch accepts bad steps too, which would then be trimmed
232 // and used.
233 //this->trim_func_grad(fval);
234 this->_filter.filter_def(this->_vec_grad);
235
236 if(fval < this->_fval_min)
237 {
238 this->_fval_min = fval;
239 this->_alpha_min = alpha;
240 }
241
242 // Set new defect, do convergence checks and compute the new _alpha
243 DataType df_prev = df;
244 df = this->_vec_pn.dot(this->_vec_grad);
245
246 st = this->_check_convergence(fval, df, alpha);
247
248 // Check if the diffence in etas is too small, thus leading to a huge update of relative size > sqrt(eps)
249 if(Math::abs(df - df_prev) < Math::abs(alpha_update*df)*Math::sqrt(Math::eps<DataType>()))
250 {
252 }
253
254 if(st != Status::progress)
255 {
256 break;
257 }
258
259 // Update alpha according to secant formula
260 alpha_update *= df/(df_prev - df);
261 alpha += alpha_update;
262
263 // Update the solution
264 vec_sol.copy(this->_vec_initial_sol);
265 vec_sol.axpy(this->_vec_pn, alpha);
266 }
267
268 // If we are successful, we could save the last step length as the new initial step length. This is
269 // disabled by default, as it can lead to stagnation e.g. for minimising the Rosenbrock function.
270 //if(st == Status::success)
271 //{
272 // this->_alpha_0 = this->_alpha_min/this->_norm_dir;
273 //}
274 // If we are not successful, we update the best step length and need to re-evaluate everything for that
275 // step
276 if(st != Status::success)
277 {
278 vec_sol.copy(this->_vec_initial_sol);
279 vec_sol.axpy(this->_vec_pn, this->_alpha_min);
280
281 // Prepare and evaluate
282 this->_functional.prepare(vec_sol, this->_filter);
283 this->_functional.eval_fval_grad(fval, this->_vec_grad);
284 // DO NOT call trim() here, as this simple linesearch accepts bad steps too, which would then be trimmed
285 // and used.
286 //this->trim_func_grad(fval);
287 this->_filter.filter_def(this->_vec_grad);
288 }
289 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::undefined, this->get_num_iter()));
290 return st;
291 }
292
293 }; // class SecantLinesearch
294
313 template<typename Functional_, typename Filter_>
314 inline std::shared_ptr<SecantLinesearch<Functional_, Filter_>> new_secant_linesearch(
315 Functional_& functional, Filter_& filter,
316 typename Functional_::DataType secant_step = SecantLinesearch<Functional_, Filter_>::secant_step_default,
317 bool keep_iterates = false)
318 {
319 return std::make_shared<SecantLinesearch<Functional_, Filter_>>(functional, filter, secant_step,
320 keep_iterates);
321 }
322
341 template<typename Functional_, typename Filter_>
342 inline std::shared_ptr<SecantLinesearch<Functional_, Filter_>> new_secant_linesearch(
343 const String& section_name, const PropertyMap* section,
344 Functional_& functional, Filter_& filter)
345 {
346 return std::make_shared<SecantLinesearch<Functional_, Filter_>>(section_name, section, functional, filter);
347 }
348
349 } // namespace Solver
350} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
FEAT Kernel base header.
A class organizing a tree of key-value pairs.
std::pair< String, bool > query(String key_path) const
Queries a value by its key path.
Helper class for iteration statistics collection.
Definition: base.hpp:392
Index get_num_iter() const
Returns number of performed iterations.
Definition: iterative.hpp:462
Index _num_iter
number of performed iterations
Definition: iterative.hpp:231
virtual void plot_summary() const
Plot a summary of the last solver run.
Definition: iterative.hpp:627
Linesearch base class.
Definition: linesearch.hpp:34
VectorType _vec_grad
Gradient vector.
Definition: linesearch.hpp:53
DataType _norm_dir
The 2-norm of the search direction.
Definition: linesearch.hpp:75
Functional_ & _functional
The (nonlinear) functional.
Definition: linesearch.hpp:48
VectorType _vec_initial_sol
Initial solution.
Definition: linesearch.hpp:55
virtual Status _startup(DataType &alpha, DataType &fval, DataType &delta, const VectorType &vec_sol, const VectorType &vec_dir)
Performs the startup of the iteration.
Definition: linesearch.hpp:464
VectorType _vec_pn
descend direction vector, normalized for better numerical stability
Definition: linesearch.hpp:59
virtual void reset()
Resets various member variables in case the solver is reused.
Definition: linesearch.hpp:299
DataType _fval_min
Functional functional value.
Definition: linesearch.hpp:62
Filter_ & _filter
The filter to be applied to the functional's gradient.
Definition: linesearch.hpp:50
DataType _alpha_0
Initial line search parameter.
Definition: linesearch.hpp:69
DataType _alpha_min
Line search parameter.
Definition: linesearch.hpp:71
virtual Status _check_convergence(const DataType fval, const DataType df, const DataType alpha)
Performs the line search convergence checks using the strong Wolfe conditions.
Definition: linesearch.hpp:543
Functional_::DataType DataType
Underlying floating point type.
SecantLinesearch(Functional_ &functional, Filter_ &filter, const DataType secant_step=secant_step_default, const bool keep_iterates=false)
Standard constructor.
virtual Status _apply_intern(VectorType &vec_sol, const VectorType &vec_dir)
Internal function: Applies the solver.
virtual Status apply(VectorType &vec_cor, const VectorType &vec_dir) override
Applies the solver, setting the initial guess to zero.
static constexpr DataType secant_step_default
Default initial step length.
SecantLinesearch(const String &section_name, const PropertyMap *section, Functional_ &functional, Filter_ &filter)
Constructor using a PropertyMap.
Filter_ FilterType
Filter type to be applied to the gradient of the functional.
DataType _secant_step
Default step for calculating the "other" secant point in the initial step. Crucial.
virtual Status correct(VectorType &vec_sol, const VectorType &vec_dir) override
Applies the solver, making use of an initial guess.
void set_secant_step(DataType secant_step)
Sets the length of the first secant step.
virtual void reset() override
Resets various member variables in case the solver is reused.
Functional_::VectorTypeR VectorType
Input vector type for the functional's gradient.
Linesearch< Functional_, Filter_ > BaseClass
Our base class.
virtual String name() const override
Returns a descriptive string.
String class implementation.
Definition: string.hpp:46
T_ sqrt(T_ x)
Returns the square-root of a value.
Definition: math.hpp:300
T_ abs(T_ x)
Returns the absolute value.
Definition: math.hpp:275
std::shared_ptr< SecantLinesearch< Functional_, Filter_ > > new_secant_linesearch(Functional_ &functional, Filter_ &filter, typename Functional_::DataType secant_step=SecantLinesearch< Functional_, Filter_ >::secant_step_default, bool keep_iterates=false)
Creates a new SecantLinesearch object.
Status
Solver status return codes enumeration.
Definition: base.hpp:47
@ success
solving successful (convergence criterion fulfilled)
@ progress
continue iteration (internal use only)
@ undefined
undefined status
@ stagnated
solver stagnated (stagnation criterion fulfilled)
FEAT namespace.
Definition: adjactor.hpp:12