FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
alglib_wrapper.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/base.hpp>
9#include <kernel/solver/iterative.hpp>
10#include <kernel/solver/nlcg.hpp>
11
12#include <deque>
13
14#ifdef FEAT_HAVE_ALGLIB
15FEAT_DISABLE_WARNINGS
16#include <optimization.h>
17FEAT_RESTORE_WARNINGS
18#endif // FEAT_HAVE_ALGLIB
19
20#if defined(FEAT_HAVE_ALGLIB) || defined(DOXYGEN)
21
22namespace FEAT
23{
24 namespace Solver
25 {
27 namespace Intern
28 {
30 template <typename Evaluator_, typename T_>
31 auto derefer(T_ & object, typename Evaluator_::GateType *) -> decltype(object.local())
32 {
33 return object.local();
34 }
35
37 template <typename Evaluator_, typename T_>
38 T_& derefer(T_ & object, ...)
39 {
40 return object;
41 }
42 } // namespace Intern
44
60 template<typename Functional_, typename Filter_>
61 class ALGLIBMinLBFGS: public NLOptLS<Functional_, Filter_>
62 {
63 public:
65 typedef Functional_ FunctionalType;
67 typedef Filter_ FilterType;
68
70 typedef typename Functional_::GradientType GradientType;
72 typedef typename Functional_::VectorTypeR VectorType;
74 typedef typename Functional_::DataType DataType;
75
80
81 protected:
82
87
89 alglib::real_1d_array _functionalt_var;
91 alglib::minlbfgsstate _state;
93 alglib::minlbfgsreport _report;
95 alglib::ae_int_t _lbfgs_dim;
96
97 public:
99 std::deque<VectorType>* iterates;
100
101 public:
119 Functional_& functional_, Filter_& filter_, const alglib::ae_int_t lbfgs_dim_ = alglib::ae_int_t(0),
120 const bool keep_iterates = false) :
121 BaseClass("ALGLIBMinLBFGS", functional_, filter_, nullptr),
122 _lbfgs_dim(lbfgs_dim_),
123 iterates(nullptr)
124 {
125
126 this->set_ls_iter_digits(2);
127
128 if(keep_iterates)
129 {
130 iterates = new std::deque<VectorType>;
131 }
132
133 if(_lbfgs_dim == alglib::ae_int_t(0))
134 {
135 _lbfgs_dim = alglib::ae_int_t(Math::min(Index(7), this->_functional.columns()));
136 }
137 }
138
155 explicit ALGLIBMinLBFGS(const String& section_name, const PropertyMap* section,
156 Functional_& functional_, Filter_& filter_) :
157 BaseClass("ALGLIBMinLBFGS", section_name, section, functional_, filter_, nullptr),
158 _lbfgs_dim(0),
159 iterates(nullptr)
160 {
161
162 this->set_ls_iter_digits(2);
163
164 // Get direction update
165 auto lbfgs_dim_p = section->query("lbfgs_dim");
166 if(lbfgs_dim_p.second)
167 {
168 _lbfgs_dim = alglib::ae_int_t(std::stoul(lbfgs_dim_p.first));
169 XASSERT(_lbfgs_dim > alglib::ae_int_t(0));
170 }
171
172 // Check if we have to keep the iterates
173 auto keep_iterates_p = section->query("keep_iterates");
174 if(keep_iterates_p.second && std::stoul(keep_iterates_p.first) == 1)
175 {
176 iterates = new std::deque<VectorType>;
177 }
178 }
179
184 {
185 if(iterates != nullptr)
186 {
187 delete iterates;
188 }
189 }
190
192 virtual void init_symbolic() override
193 {
195 // create two temporary vectors
196 _vec_def = this->_functional.create_vector_r();
197 _vec_tmp = this->_functional.create_vector_r();
198
199 // The length of the optimization variable is the raw length of a temporary vector
200 _functionalt_var.setlength(alglib::ae_int_t(
201 Intern::derefer<VectorType>(_vec_def, nullptr).template size<LAFEM::Perspective::pod>()));
202
203 for(alglib::ae_int_t i(0); i < _functionalt_var.length(); ++i)
204 {
205 _functionalt_var[i] = double(0);
206 }
207
208 alglib::minlbfgscreate(_lbfgs_dim, _functionalt_var, _state);
209 alglib::minlbfgssetxrep(_state, true);
210 // Set stopping criteria: absolute tolerance, function improvement, length of update step, max iterations
211 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
212 // second argument
213 alglib::minlbfgssetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
214 alglib::ae_int_t(this->_max_iter));
215 }
216
218 virtual void done_symbolic() override
219 {
220 this->_vec_def.clear();
221 this->_vec_tmp.clear();
223 }
224
226 virtual String name() const override
227 {
228 return "ALGLIBMinLBFGS";
229 }
230
238 void set_tol_abs(DataType tol_abs)
239 {
240 BaseClass::set_tol_abs(tol_abs);
241 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
242 // second argument
243 alglib::minlbfgssetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
244 alglib::ae_int_t(this->_max_iter));
245 }
246
256 virtual void set_tol_fval(DataType tol_fval) override
257 {
258 BaseClass::set_tol_fval(tol_fval);
259 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
260 // second argument
261 alglib::minlbfgssetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
262 alglib::ae_int_t(this->_max_iter));
263 }
264
269 {
271 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
272 // second argument
273 alglib::minlbfgssetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
274 alglib::ae_int_t(this->_max_iter));
275 }
276
280 void set_lbfgs_dim(alglib::ae_int_t lbfgs_dim)
281 {
282 XASSERT(lbfgs_dim > alglib::ae_int_t(0));
283 _lbfgs_dim = lbfgs_dim;
284 }
285
289 void set_keep_iterates(bool keep_iterates)
290 {
291 if(iterates != nullptr)
292 {
293 delete iterates;
294 }
295
296 if(keep_iterates)
297 {
298 iterates = new std::deque<VectorType>;
299 }
300
301 }
302
304 virtual Status apply(VectorType& vec_cor, const VectorType& vec_def) override
305 {
306
307 // Unused here
308 DataType fval(0);
309
310 // clear solution vector
311 vec_cor.format();
312
313 this->_functional.prepare(vec_cor, this->_filter);
314 this->_functional.eval_fval_grad(fval, this->_vec_def);
315
316 // Copy back defect
317 this->_vec_def.copy(vec_def);
318 this->_filter.filter_def(this->_vec_def);
319
320 // apply
321 this->_status = _apply_intern(vec_cor);
322 this->plot_summary();
323 return this->_status;
324 }
325
327 virtual Status correct(VectorType& vec_sol, const VectorType& DOXY(vec_rhs)) override
328 {
329
330 this->_functional.prepare(vec_sol, this->_filter);
331 // compute defect
332 this->_functional.eval_fval_grad(this->_fval, this->_vec_def);
333 this->_vec_def.scale(this->_vec_def,DataType(-1));
334 this->_filter.filter_def(this->_vec_def);
335
336 // apply
337 this->_status = _apply_intern(vec_sol);
338 this->plot_summary();
339 return this->_status;
340 }
341
342 protected:
357 {
358 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
359
360 // Write initial guess to iterates if desired
361 if(iterates != nullptr)
362 {
363 auto tmp = vec_sol.clone();
364 iterates->push_back(std::move(tmp));
365 }
366
367 // compute initial defect
368 Status status = this->_set_initial_defect(this->_vec_def, vec_sol);
369
370 if(status != Status::progress)
371 {
372 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
373 return status;
374 }
375
376 // Copy initial guess to optimization state variable
377 auto vec_sol_elements = Intern::derefer<VectorType>(vec_sol, nullptr).template elements<LAFEM::Perspective::pod>();
378 for(alglib::ae_int_t i(0); i < _functionalt_var.length(); ++i)
379 {
380 _functionalt_var[i] = vec_sol_elements[i];
381 }
382
383 alglib::minlbfgsrestartfrom(_state, _functionalt_var);
384
385 IterationStats stat(*this);
386 alglib::minlbfgsoptimize(_state, _func_grad, _log, this);
387 alglib::minlbfgsresults(_state, _functionalt_var, _report);
388
389 for(alglib::ae_int_t i(0); i < _functionalt_var.length(); ++i)
390 {
391 vec_sol_elements[i] = DataType(_functionalt_var[i]);
392 }
393
394 switch(_report.terminationtype)
395 {
396 case(-8):
397 //std::cout << "ALGLIB: Got inf or NaN in function/gradient evaluation.\n";
398 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
399 return Status::aborted;
400 case(-7):
401 //std::cout << "ALGLIB: Gradient verification failed.\n";
402 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
403 return Status::aborted;
404 case(1):
405 //std::cout << "ALGLIB: Function value improvement criterion fulfilled.\n";
406 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
407 return Status::success;
408 case(2):
409 //std::cout << "ALGLIB: Update step size stagnated.\n";
410 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
411 return Status::success;
412 case(4):
413 //std::cout << "ALGLIB: Gradient norm criterion fulfilled.\n";
414 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
415 return Status::success;
416 case(5):
417 //std::cout << "ALGLIB: Maximum number of iterations\n";
418 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::max_iter, this->get_num_iter()));
419 return Status::max_iter;
420 case(7):
421 //std::cout << "ALGLIB: Stopping criteria too stringent, further improvement impossible.\n";
422 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::stagnated, this->get_num_iter()));
423 return Status::stagnated;
424 case(8):
425 //std::cout << "ALGLIB: Stopped by user\n";
426 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
427 return Status::success;
428 default:
429 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::undefined, this->get_num_iter()));
430 return Status::undefined;
431 }
432 }
433
447 static void _log(const alglib::real_1d_array& DOXY(x), double DOXY(func), void* ptr)
448 {
450 reinterpret_cast<ALGLIBMinLBFGS<FunctionalType, FilterType>*>(ptr);
451
452 // Because of how ALGLIB counts its iterations, we have to make sure we do not call this before the first
453 // functional evaluation (repnfev is the reported number of functional evaluations)
454 if(me->_state.c_ptr()->repnfev> 0)
455 {
456 me->_steplength = DataType(me->_state.c_ptr()->stp);
457 me->_ls_its = Index(me->_state.c_ptr()->nfev);
458 Status st = me->_set_new_defect(me->_vec_def, me->_vec_tmp);
459 // Because ALGLIB knows no relative tolerance, we have to do it here
460 if( st != Status::progress )
461 {
462 alglib::minlbfgsrequesttermination(me->_state);
463 }
464 }
465
466 }
467
484 static void _func_grad(const alglib::real_1d_array& x, double& fval, alglib::real_1d_array& grad, void* ptr)
485 {
486 // Downcast because we know what we are doing, right?
488 (ptr);
489
490 auto vec_tmp_elements = Intern::derefer<VectorType>(me->_vec_tmp, nullptr).template elements<LAFEM::Perspective::pod>();
491
492 // Copy back ALGLIB's state variable to our solver
493 for(alglib::ae_int_t i(0); i < x.length(); ++i)
494 vec_tmp_elements[i] = DataType(x[i]);
495
496 me->_fval_prev = me->_fval;
497 // Prepare the functional
498 me->_functional.prepare(me->_vec_tmp, me->_filter);
499 // Compute functional value and gradient
500 me->_functional.eval_fval_grad(me->_fval, me->_vec_def);
501 me->_filter.filter_def(me->_vec_def);
502
503 fval = double(me->_fval);
504
505 // Copy the functional's gradient to ALGLIB's grad variable
506 auto vec_def_elements = Intern::derefer<VectorType>(me->_vec_def, nullptr).template elements<LAFEM::Perspective::pod>();
507 for(alglib::ae_int_t i(0); i < grad.length(); ++i)
508 {
509 grad[i] = double(vec_def_elements[i]);
510 }
511
512 }
513
514 }; // class ALGLIBMinLBFGS
515
534 template<typename Functional_, typename Filter_>
535 inline std::shared_ptr<ALGLIBMinLBFGS<Functional_, Filter_>> new_alglib_minlbfgs(
536 Functional_& functional_, Filter_& filter_,
537 alglib::ae_int_t lbfgs_dim_ = alglib::ae_int_t(0), bool keep_iterates = false)
538 {
539 return std::make_shared<ALGLIBMinLBFGS<Functional_, Filter_>>(functional_, filter_, lbfgs_dim_, keep_iterates);
540 }
541
560 template<typename Functional_, typename Filter_>
561 inline std::shared_ptr<ALGLIBMinLBFGS<Functional_, Filter_>> new_alglib_minlbfgs(
562 const String& section_name, const PropertyMap* section,
563 Functional_& functional_, Filter_& filter_)
564 {
565 return std::make_shared<ALGLIBMinLBFGS<Functional_, Filter_>>(section_name, section, functional_, filter_);
566 }
567
588 template<typename Functional_, typename Filter_>
589 class ALGLIBMinCG : public NLOptLS<Functional_, Filter_>
590 {
591 public:
593 typedef Functional_ FunctionalType;
595 typedef Filter_ FilterType;
596
598 typedef typename Functional_::GradientType GradientType;
600 typedef typename Functional_::VectorTypeR VectorType;
602 typedef typename Functional_::DataType DataType;
603
608
610 static constexpr NLCGDirectionUpdate direction_update_default = NLCGDirectionUpdate::DYHSHybrid;
611
612 protected:
615
620
622 alglib::real_1d_array _functionalt_var;
624 alglib::mincgstate _state;
626 alglib::mincgreport _report;
627
628 public:
630 std::deque<VectorType>* iterates;
631
632 public:
646 explicit ALGLIBMinCG(Functional_& functional_, Filter_& filter_,
647 NLCGDirectionUpdate du_ = direction_update_default, bool keep_iterates = false) :
648 BaseClass("ALGLIBMinCG", functional_, filter_, nullptr),
650 iterates(nullptr)
651 {
652
653 this->set_ls_iter_digits(2);
654
655 if(keep_iterates)
656 {
657 iterates = new std::deque<VectorType>;
658 }
659
660 }
661
678 explicit ALGLIBMinCG(const String& section_name, const PropertyMap* section,
679 Functional_& functional_, Filter_& filter_) :
680 BaseClass("ALGLIBMinCG", section_name, section, functional_, filter_, nullptr),
682 iterates(nullptr)
683 {
684
685 this->set_ls_iter_digits(2);
686
687 // Get direction update
688 auto direction_update_p = section->query("direction_update");
689 if(direction_update_p.second)
690 {
691 NLCGDirectionUpdate my_update;
692 my_update << direction_update_p.first;
693 set_direction_update(my_update);
694 }
695
696 // Check if we have to keep the iterates
697 auto keep_iterates_p = section->query("keep_iterates");
698 if(keep_iterates_p.second && std::stoul(keep_iterates_p.first) == 1)
699 {
700 iterates = new std::deque<VectorType>;
701 }
702 }
703
707 virtual ~ALGLIBMinCG()
708 {
709 if(iterates != nullptr)
710 delete iterates;
711 }
712
714 virtual void init_symbolic() override
715 {
717 // Create two temporary vectors
718 _vec_def = this->_functional.create_vector_r();
719 _vec_tmp = this->_functional.create_vector_r();
720
721 // The length of the optimization variable is the raw length of a temporary vector
722 _functionalt_var.setlength(alglib::ae_int_t(
723 Intern::derefer<VectorType>(_vec_def, nullptr).template size<LAFEM::Perspective::pod>()));
724
725 for(alglib::ae_int_t i(0); i < _functionalt_var.length(); ++i)
726 {
727 _functionalt_var[i] = double(0);
728 }
729
730 alglib::mincgcreate(_functionalt_var, _state);
731 alglib::mincgsetxrep(_state, true);
732 // Set stopping criteria: Absolute tolerance, function improvement, length of update step, max iterations
733 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
734 // second argument
735 alglib::mincgsetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
736 alglib::ae_int_t(this->_max_iter));
737 // Set the direction update
738 set_direction_update(this->_direction_update);
739 }
740
745 {
746 switch(update_)
747 {
748 case NLCGDirectionUpdate::DaiYuan:
749 alglib::mincgsetcgtype(_state, 0);
750 break;
751 case NLCGDirectionUpdate::DYHSHybrid:
752 alglib::mincgsetcgtype(_state, 1);
753 break;
754 default:
755 XABORTM("got invalid direction update: " +stringify(update_));
756 }
757 }
758
762 void set_keep_iterates(bool keep_iterates)
763 {
764 if(iterates != nullptr)
765 {
766 delete iterates;
767 }
768
769 if(keep_iterates)
770 {
771 iterates = new std::deque<VectorType>;
772 }
773
774 }
775
785 virtual void set_tol_fval(DataType tol_fval) override
786 {
787 BaseClass::set_tol_fval(tol_fval);
788 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
789 // second argument
790 alglib::mincgsetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
791 alglib::ae_int_t(this->_max_iter));
792 }
793
798 {
800 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
801 // second argument
802 alglib::mincgsetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
803 alglib::ae_int_t(this->_max_iter));
804 }
805
813 void set_tol_abs(DataType tol_abs)
814 {
815 BaseClass::set_tol_abs(tol_abs);
816 // Since we do not want the solver to stop based on the absolute criterion alone, we always pass 0 as the
817 // second argument
818 alglib::mincgsetcond(_state, double(0), double(this->_tol_fval), double(this->_tol_step),
819 alglib::ae_int_t(this->_max_iter));
820 }
821
822
824 virtual void done_symbolic() override
825 {
826 this->_vec_def.clear();
827 this->_vec_tmp.clear();
829 }
830
832 virtual String name() const override
833 {
834 return "ALGLIBMinCG";
835 }
836
838 virtual Status apply(VectorType& vec_cor, const VectorType& vec_def) override
839 {
840 // clear solution vector
841 vec_cor.format();
842
843 this->_functional.prepare(vec_cor, this->_filter);
844 this->_functional.eval_fval_grad(this->_fval, this->_vec_def);
845
846 // Copy back defect
847 this->_vec_def.copy(vec_def);
848 this->_filter.filter_def(this->_vec_def);
849
850 // apply
851 this->_status = _apply_intern(vec_cor);
852 this->plot_summary();
853 return this->_status;
854 }
855
857 virtual Status correct(VectorType& vec_sol, const VectorType& DOXY(vec_rhs)) override
858 {
859
860 this->_functional.prepare(vec_sol, this->_filter);
861 // compute defect
862 this->_functional.eval_fval_grad(this->_fval, this->_vec_def);
863 this->_vec_def.scale(this->_vec_def,DataType(-1));
864 this->_filter.filter_def(this->_vec_def);
865
866 // apply
867 this->_status = _apply_intern(vec_sol);
868 this->plot_summary();
869 return this->_status;
870 }
871
872 protected:
887 {
888 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
889
890 // Write initial guess to iterates if desired
891 if(iterates != nullptr)
892 {
893 auto tmp = vec_sol.clone();
894 iterates->push_back(std::move(tmp));
895 }
896 // compute initial defect
897 Status status = this->_set_initial_defect(this->_vec_def, vec_sol);
898
899 if(status != Status::progress)
900 return status;
901
902 // Copy initial guess to optimization state variable
903 auto vec_sol_elements = Intern::derefer<VectorType>(vec_sol, nullptr).template elements<LAFEM::Perspective::pod>();
904 for(alglib::ae_int_t i(0); i < _functionalt_var.length(); ++i)
905 {
906 _functionalt_var[i] = vec_sol_elements[i];
907 }
908
909 alglib::mincgrestartfrom(_state, _functionalt_var);
910 IterationStats stat(*this);
911 alglib::mincgoptimize(_state, _func_grad, _log, this);
912 alglib::mincgresults(_state, _functionalt_var, _report);
913
914 for(alglib::ae_int_t i(0); i < _functionalt_var.length(); ++i)
915 {
916 vec_sol_elements[i] = DataType(_functionalt_var[i]);
917 }
918
919 switch(_report.terminationtype)
920 {
921 case(-8):
922 //std::cout << "ALGLIB: Got inf or NaN in function/gradient evaluation.\n";
923 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
924 return Status::aborted;
925 case(-7):
926 //std::cout << "ALGLIB: Gradient verification failed.\n";
927 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
928 return Status::aborted;
929 case(1):
930 //std::cout << "ALGLIB: Function value improvement criterion fulfilled.\n";
931 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
932 return Status::success;
933 case(2):
934 //std::cout << "ALGLIB: Update step size stagnated.\n";
935 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
936 return Status::success;
937 case(4):
938 //std::cout << "ALGLIB: Gradient norm criterion fulfilled.\n";
939 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
940 return Status::success;
941 case(5):
942 //std::cout << "ALGLIB: Maximum number of iterations\n";
943 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::max_iter, this->get_num_iter()));
944 return Status::max_iter;
945 case(7):
946 //std::cout << "ALGLIB: Stopping criteria too stringent, further improvement impossible.\n";
947 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::stagnated, this->get_num_iter()));
948 return Status::stagnated;
949 case(8):
950 //std::cout << "ALGLIB: Stopped by user\n";
951 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::success, this->get_num_iter()));
952 return Status::success;
953 default:
954 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::undefined, this->get_num_iter()));
955 return Status::undefined;
956 }
957 }
958
972 static void _log(const alglib::real_1d_array& DOXY(x), double DOXY(func), void* ptr)
973 {
975
976 // Because of how ALGLIB counts its iterations, we have to make sure we do not call this before the first
977 // functional evaluation (repnfev is the reported number of functional evaluations)
978 if(me->_state.c_ptr()->repnfev > 0)
979 {
980 me->_steplength = DataType(me->_state.c_ptr()->stp);
981 me->_ls_its = Index(me->_state.c_ptr()->nfev);
982 Status st = me->_set_new_defect(me->_vec_def, me->_vec_tmp);
983 // Because ALGLIB knows no relative tolerance, we have to do it here
984 if( st != Status::progress )
985 {
986 alglib::mincgrequesttermination(me->_state);
987 }
988 }
989
990 }
991
1008 static void _func_grad(const alglib::real_1d_array& x, double& fval, alglib::real_1d_array& grad, void* ptr)
1009 {
1010 // Downcast because we know what we are doing, right?
1012
1013 auto vec_tmp_elements = Intern::derefer<VectorType>(me->_vec_tmp, nullptr).template
1014 elements<LAFEM::Perspective::pod>();
1015
1016 // Copy back ALGLIB's state variable to our solver
1017 for(alglib::ae_int_t i(0); i < x.length(); ++i)
1018 {
1019 vec_tmp_elements[i] = DataType(x[i]);
1020 }
1021
1022 me->_fval_prev = me->_fval;
1023 // Prepare the functional
1024 me->_functional.prepare(me->_vec_tmp, me->_filter);
1025 // Compute functional value and gradient
1026 me->_functional.eval_fval_grad(me->_fval, me->_vec_def);
1027 me->_filter.filter_def(me->_vec_def);
1028
1029 fval = double(me->_fval);
1030
1031 // Copy the functional's gradient to ALGLIB's grad variable
1032 auto vec_def_elements = Intern::derefer<VectorType>(me->_vec_def, nullptr).template
1033 elements<LAFEM::Perspective::pod>();
1034
1035 for(alglib::ae_int_t i(0); i < grad.length(); ++i)
1036 {
1037 grad[i] = double(vec_def_elements[i]);
1038 }
1039
1040 }
1041
1042 }; // class ALGLIBMinCG
1043
1059 template<typename Functional_, typename Filter_>
1060 inline std::shared_ptr<ALGLIBMinCG<Functional_, Filter_>> new_alglib_mincg(
1061 Functional_& functional_, Filter_& filter_,
1063 bool keep_iterates_ = false)
1064 {
1065 return std::make_shared<ALGLIBMinCG<Functional_, Filter_>>(functional_, filter_, du_, keep_iterates_);
1066 }
1067
1086 template<typename Functional_, typename Filter_>
1087 inline std::shared_ptr<ALGLIBMinCG<Functional_, Filter_>> new_alglib_mincg(
1088 const String& section_name, const PropertyMap* section,
1089 Functional_& functional_, Filter_& filter_)
1090 {
1091 return std::make_shared<ALGLIBMinCG<Functional_, Filter_>>(section_name, section, functional_, filter_);
1092 }
1093 } // namespace Solver
1094} // namespace FEAT
1095#endif // defined(FEAT_HAVE_ALGLIB) || defined(DOXYGEN)
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#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.
Wrapper around ALGLIB's mincg implementation for minimising an functional's gradient.
VectorType _vec_def
defect vector
virtual Status _apply_intern(VectorType &vec_sol)
Internal function, applies the solver.
void set_direction_update(NLCGDirectionUpdate update_)
Sets the direction update method.
virtual Status apply(VectorType &vec_cor, const VectorType &vec_def) override
Solver application method.
NLCGDirectionUpdate _direction_update
Method to update the search direction, defaults to DYHSHybrid.
void set_tol_abs(DataType tol_abs)
Sets the relative tolerance for the norm of the defect vector.
void set_max_iter(Index max_iter)
Sets the maximum iteration count for the solver.
VectorType _vec_tmp
temporary vector
virtual Status correct(VectorType &vec_sol, const VectorType &vec_rhs) override
Solver correction method.
ALGLIBMinCG(const String &section_name, const PropertyMap *section, Functional_ &functional_, Filter_ &filter_)
Constructor using a PropertyMap.
Filter_ FilterType
The filter type.
alglib::real_1d_array _functionalt_var
Optimization variable for ALGLIB.
static void _log(const alglib::real_1d_array &x, double func, void *ptr)
Internal function for logging/plotting.
alglib::mincgstate _state
This will hold the state of the optimization problem in ALGLIB.
void set_keep_iterates(bool keep_iterates)
Sets the iterates deque according to a bool.
virtual String name() const override
Returns a descriptive string.
virtual ~ALGLIBMinCG()
Virtual destructor.
std::deque< VectorType > * iterates
Can hold all iterates for debugging purposes.
virtual void set_tol_fval(DataType tol_fval) override
Sets the tolerance for function value improvement.
static constexpr NLCGDirectionUpdate direction_update_default
Default NLCG search direction update.
Functional_::DataType DataType
Underlying floating point type.
virtual void init_symbolic() override
Symbolic initialization method.
SolverBase< VectorType > PrecondType
Generic preconditioner.
Functional_::VectorTypeR VectorType
Input type for the gradient.
Functional_::GradientType GradientType
Type of the functional's gradient has.
alglib::mincgreport _report
Convergence report etc.
NLOptLS< Functional_, Filter_ > BaseClass
Our baseclass.
ALGLIBMinCG(Functional_ &functional_, Filter_ &filter_, NLCGDirectionUpdate du_=direction_update_default, bool keep_iterates=false)
Standard constructor.
Functional_ FunctionalType
The nonlinear functional type.
static void _func_grad(const alglib::real_1d_array &x, double &fval, alglib::real_1d_array &grad, void *ptr)
Internal function for computing functional value and gradient.
virtual void done_symbolic() override
Symbolic finalization method.
Wrapper around ALGLIB's lBFGS implementation for minimising an functional's gradient.
virtual ~ALGLIBMinLBFGS()
Virtual destructor.
alglib::minlbfgsstate _state
This will hold the state of the optimization problem in ALGLIB.
void set_max_iter(Index max_iter)
Sets the maximum iteration count for the solver.
VectorType _vec_tmp
temporary vector
alglib::real_1d_array _functionalt_var
Optimization variable for ALGLIB.
Filter_ FilterType
The filter type.
void set_lbfgs_dim(alglib::ae_int_t lbfgs_dim)
Sets the dimension for the LBFGS update.
VectorType _vec_def
defect vector
virtual void set_tol_fval(DataType tol_fval) override
Sets the tolerance for function value improvement.
SolverBase< VectorType > PrecondType
Generic preconditioner.
virtual Status _apply_intern(VectorType &vec_sol)
Internal function, applies the solver.
virtual void done_symbolic() override
Symbolic finalization method.
void set_keep_iterates(bool keep_iterates)
Sets the iterates deque according to a bool.
virtual Status apply(VectorType &vec_cor, const VectorType &vec_def) override
Solver application method.
std::deque< VectorType > * iterates
Can hold all iterates for debugging purposes.
virtual void init_symbolic() override
Symbolic initialization method.
Functional_::VectorTypeR VectorType
Input type for the gradient.
ALGLIBMinLBFGS(const String &section_name, const PropertyMap *section, Functional_ &functional_, Filter_ &filter_)
Constructor using a PropertyMap.
alglib::ae_int_t _lbfgs_dim
Dimension for lBFGS Hessian update.
static void _log(const alglib::real_1d_array &x, double func, void *ptr)
Internal function for logging/plotting.
virtual String name() const override
Returns a descriptive string.
NLOptLS< Functional_, Filter_ > BaseClass
Our baseclass.
alglib::minlbfgsreport _report
Convergence report etc.
static void _func_grad(const alglib::real_1d_array &x, double &fval, alglib::real_1d_array &grad, void *ptr)
Internal function for computing functional value and gradient.
Functional_::GradientType GradientType
Type of the functional's gradient has.
Functional_ FunctionalType
The nonlinear functional type.
Functional_::DataType DataType
Underlying floating point type.
virtual Status correct(VectorType &vec_sol, const VectorType &vec_rhs) override
Solver correction method.
void set_tol_abs(DataType tol_abs)
Sets the relative tolerance for the norm of the defect vector.
ALGLIBMinLBFGS(Functional_ &functional_, Filter_ &filter_, const alglib::ae_int_t lbfgs_dim_=alglib::ae_int_t(0), const bool keep_iterates=false)
Standard constructor.
Helper class for iteration statistics collection.
Definition: base.hpp:392
void set_max_iter(Index max_iter)
Sets the maximum iteration count for the solver.
Definition: iterative.hpp:455
Index get_num_iter() const
Returns number of performed iterations.
Definition: iterative.hpp:462
void set_tol_abs(DataType tol_abs)
Sets the absolute tolerance for the solver.
Definition: iterative.hpp:371
Status _status
current status of the solver
Definition: iterative.hpp:213
virtual void plot_summary() const
Plot a summary of the last solver run.
Definition: iterative.hpp:627
Index _max_iter
maximum number of iterations
Definition: iterative.hpp:229
Base class for line search based nonlinear optimizers.
Definition: nloptls.hpp:43
virtual Status _set_initial_defect(const VectorType &vec_def, const VectorType &vec_sol) override
Internal function: sets the initial defect vector.
Definition: nloptls.hpp:267
DataType _fval_prev
Functional value from the previous iteration.
Definition: nloptls.hpp:80
virtual Status _set_new_defect(const VectorType &vec_r, const VectorType &vec_sol) override
Internal function: sets the new defect norm.
Definition: nloptls.hpp:325
DataType _fval
Current functional value.
Definition: nloptls.hpp:78
Functional_ & _functional
Our nonlinear functional.
Definition: nloptls.hpp:66
virtual void set_tol_fval(DataType tol_fval)
Sets the tolerance for function value improvement.
Definition: nloptls.hpp:235
DataType _tol_fval
Tolerance for function improvement.
Definition: nloptls.hpp:71
DataType _tol_step
Tolerance for the length of the update step.
Definition: nloptls.hpp:73
virtual void set_ls_iter_digits(Index digits)
Sets the number of digits used to plot line search iteration numbers.
Definition: nloptls.hpp:258
Index _ls_its
The number of iterations the linesearch performed in the last iteration of this solver.
Definition: nloptls.hpp:86
Filter_ & _filter
The filter we apply to the gradient.
Definition: nloptls.hpp:68
DataType _steplength
The last step length of the line search.
Definition: nloptls.hpp:82
Polymorphic solver interface.
Definition: base.hpp:183
virtual void init_symbolic()
Symbolic initialization method.
Definition: base.hpp:227
virtual void done_symbolic()
Symbolic finalization method.
Definition: base.hpp:255
String class implementation.
Definition: string.hpp:46
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
NLCGDirectionUpdate
Enum for NLCG search direction updates.
Definition: nlcg.hpp:23
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)
@ max_iter
solver reached maximum iterations
@ aborted
premature abort (solver aborted due to internal errors or preconditioner failure)
std::shared_ptr< ALGLIBMinCG< Functional_, Filter_ > > new_alglib_mincg(Functional_ &functional_, Filter_ &filter_, NLCGDirectionUpdate du_=ALGLIBMinCG< Functional_, Filter_ >::direction_update_default, bool keep_iterates_=false)
Creates a new ALGLIBMinCG solver object.
std::shared_ptr< ALGLIBMinLBFGS< Functional_, Filter_ > > new_alglib_minlbfgs(Functional_ &functional_, Filter_ &filter_, alglib::ae_int_t lbfgs_dim_=alglib::ae_int_t(0), bool keep_iterates=false)
Creates a new ALGLIBMinLBFGS solver object.
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
@ grad
specifies whether the space should supply basis function gradients
std::uint64_t Index
Index data type.