FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
mqc_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 {
49 template<typename Functional_, typename Filter_>
50 class MQCLinesearch : public Linesearch<Functional_, Filter_>
51 {
52 public:
54 typedef Filter_ FilterType;
56 typedef typename Functional_::VectorTypeR VectorType;
58 typedef typename Functional_::DataType DataType;
61
62 protected:
71
72 public:
86 explicit MQCLinesearch(Functional_& functional, Filter_& filter, bool keep_iterates = false) :
87 BaseClass("MQC-LS", functional, filter, keep_iterates),
92 {
93 }
94
111 explicit MQCLinesearch(const String& section_name, const PropertyMap* section,
112 Functional_& functional, Filter_& filter) :
113 BaseClass("MQC-LS", section_name, section, functional, filter),
118 {
119 }
120
123 {
124 }
125
127 virtual String name() const override
128 {
129 return "MQCLinesearch";
130 }
131
133 virtual void reset() override
134 {
140 }
141
153 virtual Status apply(VectorType& vec_cor, const VectorType& vec_dir) override
154 {
155 // clear solution vector
156 vec_cor.format();
157 this->_functional.prepare(vec_cor, this->_filter);
158
159 // apply
160 this->_status = _apply_intern(vec_cor, vec_dir);
161 this->plot_summary();
162 return this->_status;
163 }
164
176 virtual Status correct(VectorType& vec_sol, const VectorType& vec_dir) override
177 {
178 this->_functional.prepare(vec_sol, this->_filter);
179
180 // apply
181 this->_status = _apply_intern(vec_sol, vec_dir);
182 this->plot_summary();
183 return this->_status;
184 }
185
186 protected:
201 virtual Status _apply_intern(VectorType& vec_sol, const VectorType& vec_dir)
202 {
203 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
204
205 static constexpr DataType extrapolation_width = DataType(4);
206 Status status(Status::progress);
207
208 // The step length wrt. to the NORMALISED search direction
209 DataType alpha(0);
210 // The functional value
211 DataType fval(0);
213 DataType df(0);
214
215 // Perform initializations and checks
216 Status st = this->_startup(alpha, fval, df, vec_sol, vec_dir);
217 //alpha = this->_alpha_0;
218 if(st != Status::progress)
219 {
220 return st;
221 }
222
223 // Scaling if we are to use step sizes wrt. to the non-normalized search direction
224 // This appears to be the right thing theoretically, but in practice not using the search direction norm as
225 // initial guess for the step size works better. Stupid reality...
226 //if(this->_dir_scaling)
227 //{
228 // alpha = this->_norm_dir;
229 //}
230
231 // Set hard limits to default values if they have not been set
233 // This bogus value should be around 1e50 for double precision. It is chosen to make comparing results with
234 // ALGLIB easier
235 if(_alpha_hard_max < Math::eps<DataType>())
236 {
237 _alpha_hard_max = Math::pow(Math::huge<DataType>(), DataType(0.1622));
238 }
239
240 // Set the intervall of uncertainty
242 _alpha_soft_max = this->_alpha_0 + extrapolation_width*this->_alpha_0;
243 _alpha_soft_max = Math::min(_alpha_soft_max, _alpha_hard_max);
244
245 //std::cout << "Linesearch initial alpha " << this->_alpha_0 << "\n";
246
247 DataType alpha_lo(0);
248 // It is critical that _f_0 was set from the outside!
249 DataType fval_lo(this->_fval_0);
250 DataType df_lo(this->_delta_0);
251
252 DataType alpha_hi(0);
253 DataType fval_hi(this->_fval_0);
254 DataType df_hi(this->_delta_0);
255
256 // This is the width of the search interval
257 DataType width(Math::abs(_alpha_hard_max - _alpha_hard_min));
258 DataType width_old(DataType(2)*width);
259
260 // Do we know the interval of uncertainty?
261 bool interval_known(false);
262 // Is the minimum in the interval of uncertainty?
263 bool min_in_interval(false);
264 // Does the minimum lie outside the current search interval, requiring us to drive the step to its
265 // boundary?
266 bool drive_to_bndry(false);
267
268 // start iterating
269 while(status == Status::progress)
270 {
271
272 IterationStats stat(*this);
273 ++(this->_num_iter);
274
275 // If we know the minimum is in the search interval, the interval of uncertainty is the search interval
276 if(min_in_interval)
277 {
278 _alpha_soft_min = Math::min(alpha_lo, alpha_hi);
279 _alpha_soft_max = Math::max(alpha_lo, alpha_hi);
280 }
281 // Enlarge the interval of uncertainty
282 else
283 {
284 _alpha_soft_min = alpha_lo;
285 _alpha_soft_max = alpha + extrapolation_width*Math::abs(alpha - alpha_lo);
286 }
287 //std::cout << "Set alpha_smin " << _alpha_soft_min << " alpha_smax " << _alpha_soft_max << "\n";
288
289 // Update solution: sol <- initial_sol + _alpha*dir
290 vec_sol.copy(this->_vec_initial_sol);
291 vec_sol.axpy(this->_vec_pn, alpha);
292 //std::cout << "Linesearch alpha " << alpha << "\n";
293 //std::cout << "initial_sol " << *(this->_vec_initial_sol) << "\n";
294 //std::cout << "dir " << *this->_vec_pn << "\n";
295 //std::cout << "sol " << *vec_sol << "\n";
296
297 // Prepare and evaluate
298 this->_functional.prepare(vec_sol, this->_filter);
299
300 // Compute and filter the gradient
301 this->_functional.eval_fval_grad(fval, this->_vec_grad);
302 this->trim_func_grad(fval);
303 this->_filter.filter_def(this->_vec_grad);
304
305 // New directional derivative and new defect
306 df = this->_vec_pn.dot(this->_vec_grad);
307 status = this->_check_convergence(fval, df, alpha);
308
309 // If success is reported, check if it is a real success or if something fishy is going on
310 if(status == Status::success)
311 {
312 this->_vec_tmp.copy(this->_vec_initial_sol);
313 this->_vec_tmp.axpy(vec_sol, -DataType(1));
314 if(fval >= this->_fval_0 || this->_vec_tmp.norm2() == DataType(0))
315 {
316 status = Status::stagnated;
317 }
318 }
319 // If we are not successful, check if the interval of uncertainty has become too small
320 else if(min_in_interval && (_alpha_soft_max - _alpha_soft_min) <= this->_tol_step*_alpha_soft_max)
321 {
322 //std::cout << "interval width " << _alpha_soft_max - _alpha_soft_min << " : " << this->_tol_step*_alpha_soft_max << "\n";
323 status = Status::stagnated;
324 }
325 // Stagnation due to rounding errors
326 //if(min_in_interval && (alpha <= _alpha_soft_min || alpha >= _alpha_soft_max))
327 //{
328 // std::cout << "Rounding errors\n";
329 // status = Status::stagnated;
330 //}
331 // This is not used at the moment because it is only relevant if there are constraints limiting the
332 // step length
333 //if( alpha == _alpha_hard_max)
334 //if( alpha == _alpha_hard_min)
335
336 if(status != Status::progress)
337 {
338 break;
339 }
340
341 if(!interval_known
342 && (fval < this->_fval_0 + this->_tol_decrease*alpha*this->_delta_0)
343 && (df >= Math::min(this->_tol_decrease, this->_tol_curvature)))
344 {
345 interval_known = true;
346 }
347
348 //std::cout << "interval known " << interval_known << "\n";
349 // If we do not know that the minimum was in the previous interval of uncertainty, we need to compute a
350 // new step size to expand the interval of uncertainty at the start of the next iteration.
351 if(!interval_known && (fval <= fval_lo)
352 && fval > this->_fval_0 + alpha*this->_tol_decrease*this->_delta_0)
353 {
354 DataType fval_m(fval - alpha*this->_tol_decrease*this->_delta_0);
355 DataType df_m(df - this->_tol_decrease*this->_delta_0);
356 DataType fval_lo_m(fval_lo - alpha_lo*this->_tol_decrease*this->_delta_0);
357 DataType df_lo_m(df_lo - this->_tol_decrease*this->_delta_0);
358 DataType fval_hi_m(fval_hi - alpha_hi*this->_tol_decrease*this->_delta_0);
359 DataType df_hi_m(df_hi - this->_tol_decrease*this->_delta_0);
360
361 // Note that the expansion step might already give us the information that the minimum is the the
362 // new search interval
364 alpha, fval_m, df_m, alpha_lo, fval_lo_m, df_lo_m,
365 alpha_hi, fval_hi_m, df_hi_m, min_in_interval, drive_to_bndry);
366
367 fval_lo = fval_lo_m + alpha_lo*this->_tol_decrease*this->_delta_0;
368 df_lo = df_lo_m + this->_tol_decrease*this->_delta_0;
369 fval_hi = fval_hi_m * alpha_hi*this->_tol_decrease*this->_delta_0;
370 df_hi = df_hi_m + this->_tol_decrease*this->_delta_0;
371
372 }
373 else
374 {
375 _polynomial_fit(alpha, fval, df, alpha_lo, fval_lo, df_lo, alpha_hi, fval_hi, df_hi, min_in_interval,
376 drive_to_bndry);
377
378 //std::cout << "width " << width << " width_old " << width_old << " min_in_interval " << min_in_interval <<"\n";
379
380 if(min_in_interval)
381 {
382 if(Math::abs(alpha_hi - alpha_lo) >= DataType(0.66)*width_old)
383 {
384 //std::cout << "Forcing " << alpha << " to ";
385 alpha = alpha_lo + DataType(0.5)*(alpha_hi - alpha_lo);
386 //std::cout << alpha << "\n";
387 }
388 width_old = width;
389 width = Math::abs(alpha_lo - alpha_hi);
390 }
391 }
392
393 } // while(status == Status:progress)
394
395 this->_alpha_min = alpha;
396 this->_fval_min = fval;
397
398 // If we are successful, we save the last step length as the new initial step length
399 if(status == Status::success)
400 {
401 this->_alpha_0 = this->_alpha_min;
402 }
403 // If we are not successful, we update the best step length and need to re-evaluate everything for that
404 // step
405 else
406 {
407 this->_alpha_min = alpha_lo;
408 this->_fval_min = fval_lo;
409 //std::cout << "Unusual termination alpha_lo " << alpha_lo << "fval_lo " << fval_lo << "\n";
410 vec_sol.copy(this->_vec_initial_sol);
411 vec_sol.axpy(this->_vec_pn, alpha_lo);
412
413 // Prepare and evaluate
414 this->_functional.prepare(vec_sol, this->_filter);
415 this->_functional.eval_fval_grad(fval, this->_vec_grad);
416 this->trim_func_grad(fval);
417 this->_filter.filter_def(this->_vec_grad);
418 }
419
420 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
421 return status;
422 }
423
471 DataType& alpha, DataType& fval, DataType& df,
472 DataType& alpha_lo, DataType& fval_lo, DataType& df_lo,
473 DataType& alpha_hi, DataType& fval_hi, DataType& df_hi,
474 bool& min_in_interval, bool& drive_to_bndry)
475 {
476 DataType alpha_c(0);
477 DataType alpha_q(0);
478 DataType alpha_new(0);
479
480 // Case 1: The function value increased.
481 if( fval > fval_lo)
482 {
483 // Computation of cubic step
484 alpha_c = _argmin_cubic(alpha_lo, fval_lo, df_lo, alpha, fval, df);
485 // The first derivative was negative, but the function value increases, so the minimum has to be in this
486 // interval (or have been in the original interval, which this interval is a subset of)
487 min_in_interval = true;
488 drive_to_bndry = true;
489 // Use 2nd order approximation NOT using the derivative df because it might be garbage (i.e. if we hit a
490 // singularity) because the function value increased
491 alpha_q = _argmin_quadratic(alpha_lo, fval_lo, df_lo, alpha, fval, df, false);
492
493 // If the cubic minimum is closer to the old best step length, take it. Otherwise, take the mean
494 if(Math::abs(alpha_c - alpha_lo) < Math::abs(alpha_q - alpha_lo))
495 alpha_new = alpha_c;
496 else
497 alpha_new = (alpha_q + alpha_c)/DataType(2);
498 //std::cout << "Case 1: alpha " << alpha_new << " q " << alpha_q << " c " << alpha_c << "\n";
499
500 }
501 // Case 2: The first derivative changes sign
502 // We also know that the function value increased in the last trial step
503 else if( df_lo*df < DataType(0) )
504 {
505 alpha_c = _argmin_cubic(alpha, fval, df, alpha_lo, fval_lo, df_lo);
506 // Because the derivative changed sign, it has to be zero somewhere in between, so the minimum is in the
507 // current interval
508 min_in_interval = true;
509 drive_to_bndry = false;
510 // Default: Quadratic interpolant using fval_lo, df_lo and df
511 alpha_q = _argmin_quadratic(alpha_lo, fval_lo, df_lo, alpha, fval, df, true);
512 // Take the step closer to the new step alpha
513 Math::abs(alpha - alpha_c) > Math::abs(alpha - alpha_q) ? alpha_new = alpha_c : alpha_new = alpha_q;
514 //std::cout << "Case 2: alpha " << alpha_new << " q " << alpha_q << " c " << alpha_c << "\n";
515 }
516 // Case 3: The absolute value of the derivative increases
517 // We also know that the function value increased in the last trial step and that the derivative did not
518 // change sign.
519 // This means we have to further search in the direction of alpha.
520 else if(Math::abs(df) < Math::abs(df_lo))
521 {
522 alpha_c = _argmin_cubic_case_3(alpha, fval, df, alpha_lo, fval_lo, df_lo);
523 drive_to_bndry = true;
524
525 // Quadratic interpolant using fval_lo, df_lo and df
526 alpha_q = _argmin_quadratic(alpha, fval, df, alpha_lo, fval_lo, df_lo, true);
527
528 // If the cubic step is closer to the trial step
529 if(Math::abs(alpha - alpha_c) < Math::abs(alpha - alpha_q))
530 {
531 min_in_interval ? alpha_new = alpha_c : alpha_new = alpha_q;
532 }
533 else
534 {
535 min_in_interval ? alpha_new = alpha_q : alpha_new = alpha_c;
536 }
537 //std::cout << "Case 3: alpha " << alpha_new << " q " << alpha_q << " c " << alpha_c << "\n";
538 }
539 // Case 4: The absolute value of the derivative did not increase
540 // We also know that the function value increased in the last trial step and that the derivative did not
541 // change sign.
542 else
543 {
544 drive_to_bndry = false;
545 // Note that the arguments for argmin_cubic are different in this case
546 // Here we can just take the cubic step because the cubic interpolation sets it to the alpha_soft_max
547 // if it recognises that the minimum is outside the current interval.
548 if(min_in_interval)
549 {
550 alpha_c = _argmin_cubic(alpha, fval , df, alpha_hi, fval_hi, df_hi);
551 alpha_new = alpha_c;
552 }
553 else
554 {
555 alpha > alpha_lo ? alpha_new = _alpha_soft_max : alpha_new = _alpha_soft_min;
556 }
557 //std::cout << "Case 4: alpha " << alpha_new << "\n";
558 }
559
560 // Update the inverval of uncertainty. Has to happen befor we clamp the step to the admissible interval.
561 // Check which step(s) we need to replace
562 if(fval > fval_lo)
563 {
564 alpha_hi = alpha;
565 fval_hi = fval;
566 df_hi = df;
567 }
568 else
569 {
570 if(df * df_lo < DataType(0))
571 {
572 alpha_hi = alpha_lo;
573 fval_hi = fval_lo;
574 df_hi = df_lo;
575 }
576 alpha_lo = alpha;
577 fval_lo = fval;
578 df_lo = df;
579 }
580
581 _clamp_step(alpha_new);
582
583 // If we know the minimum is in the interval, we can drive alpha to the corresponding end more quickly
584 if(min_in_interval && drive_to_bndry)
585 {
586 //std::cout << "Bracketing adjust " << alpha_lo << " " << alpha_hi << " " << alpha_new << "\n";
587 //std::cout << "Bracketing adjust alpha_new from " << alpha_new;
588 if(alpha_lo < alpha_hi)
589 alpha_new = Math::min(alpha_lo + DataType(0.66)*(alpha_hi - alpha_lo), alpha_new);
590 else
591 alpha_new = Math::max(alpha_lo + DataType(0.66)*(alpha_hi - alpha_lo), alpha_new);
592 //std::cout << " to " << alpha_new << "\n";
593 }
594
595 alpha = alpha_new;
596
597 //std::cout << "Polynomial fit: new " << alpha << " " << fval << " " << df <<"\n";
598 //std::cout << "Polynomial fit: lo " << alpha_lo << " " << fval_lo << " " << df_lo <<"\n";
599 //std::cout << "Polynomial fit: hi " << alpha_hi << " " << fval_hi << " " << df_hi <<"\n";
600
601 return Status::success;
602 }
603
611 void _clamp_step(DataType& alpha_new) const
612 {
613 alpha_new = Math::max(alpha_new, _alpha_hard_min);
614 alpha_new = Math::min(alpha_new, _alpha_hard_max);
615
616 alpha_new = Math::max(alpha_new, _alpha_soft_min);
617 alpha_new = Math::min(alpha_new, _alpha_soft_max);
618 }
619
652 DataType _argmin_quadratic(const DataType alpha_lo, const DataType fval_lo, const DataType df_lo, const DataType alpha_hi, const DataType fval_hi, const DataType df_hi, const bool interpolate_derivative) const
653 {
654 DataType alpha(alpha_lo);
655
656 // Quadratic interpolation using fval_lo, df_lo, df_hi
657 if(interpolate_derivative)
658 alpha += df_lo /(df_lo - df_hi) * (alpha_hi - alpha_lo);
659 // Quadratic interpolation using fval_lo, fval_hi, df_lo
660 else
661 alpha += df_lo/( (fval_hi - fval_lo)/( alpha_hi - alpha_lo) - df_lo)/DataType(2)*(alpha_lo - alpha_hi);
662
663 return alpha;
664 }
665
698 DataType alpha_hi, DataType fval_hi, DataType df_hi) const
699 {
700 DataType alpha(alpha_lo);
701
702 DataType d1 = DataType(3)*(fval_lo - fval_hi)/(alpha_hi - alpha_lo) + df_lo + df_hi;
703 // Scale the computation of r for better numerical stability
704 DataType scale = Math::max(Math::abs(df_lo), Math::abs(df_hi));
705 scale = Math::max(scale, Math::abs(d1));
706
707 DataType r = Math::sqr(d1/scale) - (df_lo/scale) * (df_hi/scale);
708
709 //std::cout << "fval_hi " << fval_hi << " fval_lo "<< fval_lo << "\n";
710 //std::cout << "alpha_hi " << alpha_hi << " alpha_lo "<< alpha_lo << "\n";
711 //std::cout << "df_hi " << df_hi << " df_lo "<< df_lo << "\n";
712 //std::cout << "d1 " << d1 << "\n";
713 //std::cout << "scale " << scale << "\n";
714
715 DataType d2(0);
716
717 if(r > DataType(0))
718 {
719 d2 = Math::signum(alpha_hi - alpha_lo) * scale * Math::sqrt(r);
720
721 DataType p(d2 - df_lo + d1);
722
723 DataType q(0);
724 // This sorting is done to avoid annihilation
725 df_hi*df_lo > DataType(0) ? q = d2 +(df_hi-df_lo) + d2 : q = d2 - df_lo + d2 + df_hi;
726
727 //std::cout << "d2 " << d2 << "\n";
728 //std::cout << "p " << p << " q " << q << "\n";
729
730 alpha += (alpha_hi - alpha_lo)*(p/q);
731 }
732 // r <= 0 means that the minimum is not in the interior, so it has to lie across the endpoint with the
733 // lower function value
734 else
735 {
736 //d2 = Math::signum(alpha_hi - alpha_lo) * scale *
737 // Math::sqrt(Math::max(r, DataType(0)));
738 //DataType q(0);
739 //if(df_hi*df_lo > 0)
740 // q = d2 +(df_hi-df_lo) + d2;
741 //else
742 // q = d2 - df_lo + d2 +df_hi;
743 //std::cout << "d2 " << d2 << "\n";
744 //std::cout << "p " << (d2 - df_lo + d1) << " q " << q << "\n";
745
746 (alpha_lo < alpha_hi && df_lo > DataType(0) )? alpha = _alpha_soft_min: alpha = _alpha_soft_max;
747 }
748
749 return alpha;
750 }
751
758 const DataType alpha_lo, const DataType fval_lo, const DataType df_lo,
759 const DataType alpha_hi, const DataType fval_hi, DataType df_hi) const
760 {
761 DataType alpha_c(alpha_lo);
762
763 if(alpha_lo == alpha_hi)
764 {
765 return alpha_lo;
766 }
767
768 DataType d1 = DataType(3)*(fval_hi - fval_lo)/(alpha_lo - alpha_hi) + df_hi + df_lo;
769 DataType scale = Math::max(Math::abs(df_lo), Math::abs(df_hi));
770 scale = Math::max(scale, Math::abs(d1));
771
772 DataType r = Math::sqr(d1/scale) - (df_lo/scale) * (df_hi/scale);
773
774 DataType d2 = Math::signum(alpha_hi - alpha_lo) * scale * Math::sqrt(Math::max(r, DataType(0)));
775
776 DataType p(d2 - df_lo + d1);
777 DataType q(d2 +(df_hi - df_lo) + d2);
778
779 //std::cout << "fval_hi " << fval_hi << " fval_lo "<< fval_lo << "\n";
780 //std::cout << "alpha_hi " << alpha_hi << " alpha_lo "<< alpha_lo << "\n";
781 //std::cout << "df_hi " << df_hi << " df_lo "<< df_lo << "\n";
782 //std::cout << "d1 " << d1 << "\n";
783 //std::cout << "scale " << scale << "\n";
784 //std::cout << "d2 " << d2 << "\n";
785 //std::cout << "p " << (d2 - df_lo + d1) << " q " << q << "\n";
786
787 if( p/q < DataType(0) && d2 != DataType(0))
788 alpha_c += p/q*(alpha_hi - alpha_lo);
789 else
790 {
791 //std::cout << "Weird ";
792 alpha_lo > alpha_hi ? alpha_c = _alpha_soft_max : alpha_c = _alpha_soft_min;
793 }
794
795 return alpha_c;
796 }
797
798 }; // class MQCLinesearch
799
815 template<typename Functional_, typename Filter_>
816 inline std::shared_ptr<MQCLinesearch<Functional_, Filter_>> new_mqc_linesearch(
817 Functional_& functional, Filter_& filter, bool keep_iterates = false)
818 {
819 return std::make_shared<MQCLinesearch<Functional_, Filter_>>(functional, filter, keep_iterates);
820 }
821
840 template<typename Functional_, typename Filter_>
841 inline std::shared_ptr<MQCLinesearch<Functional_, Filter_>> new_mqc_linesearch(
842 const String& section_name, const PropertyMap* section, Functional_& functional, Filter_& filter)
843 {
844 return std::make_shared<MQCLinesearch<Functional_, Filter_>> (section_name, section, functional, filter);
845 }
846
847 } // namespace Solver
848} // namespace FEAT
FEAT Kernel base header.
A class organizing a tree of key-value pairs.
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
Functional_ & _functional
The (nonlinear) functional.
Definition: linesearch.hpp:48
VectorType _vec_initial_sol
Initial solution.
Definition: linesearch.hpp:55
virtual void trim_func_grad(DataType &func)
Trims the function value and gradient according to some threshold.
Definition: linesearch.hpp:430
DataType _fval_0
Initial functional value.
Definition: linesearch.hpp:64
DataType _tol_curvature
Tolerance for sufficient decrease in the norm of the gradient (Wolfe conditions)
Definition: linesearch.hpp:80
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 _delta_0
Initial <vec_dir, vec_grad>
Definition: linesearch.hpp:73
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 _tol_decrease
Tolerance for sufficient decrease in the functional value (Wolfe conditions)
Definition: linesearch.hpp:82
DataType _alpha_0
Initial line search parameter.
Definition: linesearch.hpp:69
DataType _alpha_min
Line search parameter.
Definition: linesearch.hpp:71
DataType _tol_step
Tolerance for the update step.
Definition: linesearch.hpp:84
VectorType _vec_tmp
temporary vector
Definition: linesearch.hpp:57
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
Mixed quadratic-cubic line search.
DataType _alpha_hard_max
Hard maximum for the step length.
virtual String name() const override
Returns a descriptive string.
MQCLinesearch(Functional_ &functional, Filter_ &filter, bool keep_iterates=false)
Standard constructor.
DataType _argmin_cubic_case_3(const DataType alpha_lo, const DataType fval_lo, const DataType df_lo, const DataType alpha_hi, const DataType fval_hi, DataType df_hi) const
Computes the minimum of a cubic interpolation polynomial.
DataType _alpha_soft_max
Lower bound of the interval of uncertainty.
Functional_::DataType DataType
Underlying floating point type.
MQCLinesearch(const String &section_name, const PropertyMap *section, Functional_ &functional, Filter_ &filter)
Constructor using a PropertyMap.
DataType _argmin_quadratic(const DataType alpha_lo, const DataType fval_lo, const DataType df_lo, const DataType alpha_hi, const DataType fval_hi, const DataType df_hi, const bool interpolate_derivative) const
Computes the minimum of a quadratic interpolation polynomial.
DataType _alpha_soft_min
Upper bound of the interval of uncertainty.
virtual Status correct(VectorType &vec_sol, const VectorType &vec_dir) override
Applies the solver, making use of an initial guess.
Filter_ FilterType
Filter type to be applied to the gradient of the functional.
DataType _argmin_cubic(DataType alpha_lo, DataType fval_lo, DataType df_lo, DataType alpha_hi, DataType fval_hi, DataType df_hi) const
Computes the minimum of a cubic interpolation polynomial.
DataType _alpha_hard_min
Hard minimum for the step length.
Linesearch< Functional_, Filter_ > BaseClass
Our base class.
virtual Status apply(VectorType &vec_cor, const VectorType &vec_dir) override
Applies the solver, setting the initial guess to zero.
Status _polynomial_fit(DataType &alpha, DataType &fval, DataType &df, DataType &alpha_lo, DataType &fval_lo, DataType &df_lo, DataType &alpha_hi, DataType &fval_hi, DataType &df_hi, bool &min_in_interval, bool &drive_to_bndry)
The great magick trick to find a minimum of a 1d function.
Functional_::VectorTypeR VectorType
Input vector type for the functional's gradient.
void _clamp_step(DataType &alpha_new) const
Enforces hard and soft step limits, adjusting the soft limits if necessary.
virtual Status _apply_intern(VectorType &vec_sol, const VectorType &vec_dir)
Internal function: Applies the solver.
virtual void reset() override
Resets various member variables in case the solver is reused.
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
T_ pow(T_ x, T_ y)
Returns x raised to the power of y.
Definition: math.hpp:643
T_ sqr(T_ x)
Returns the square of a value.
Definition: math.hpp:95
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
T_ signum(T_ x)
Returns the sign of a value.
Definition: math.hpp:250
T_ max(T_ a, T_ b)
Returns the maximum of two values.
Definition: math.hpp:137
Status
Solver status return codes enumeration.
Definition: base.hpp:47
@ success
solving successful (convergence criterion fulfilled)
@ progress
continue iteration (internal use only)
@ stagnated
solver stagnated (stagnation criterion fulfilled)
std::shared_ptr< MQCLinesearch< Functional_, Filter_ > > new_mqc_linesearch(Functional_ &functional, Filter_ &filter, bool keep_iterates=false)
Creates a new MQCLinesearch object.
FEAT namespace.
Definition: adjactor.hpp:12