source: trunk/yat/utility/MultiMinimizerDerivative.h @ 4252

Last change on this file since 4252 was 4252, checked in by Peter, 4 months ago

merge 0.20 release into trunk

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.2 KB
Line 
1#ifndef theplu_yat_utility_multi_minimizer_derivative
2#define theplu_yat_utility_multi_minimizer_derivative
3
4// $Id: MultiMinimizerDerivative.h 4252 2022-11-18 02:54:04Z peter $
5//
6// Copyright (C) 2022 Peter Johansson
7//
8// This program is free software; you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation; either version 3 of the License, or
11// (at your option) any later version.
12//
13// This program is distributed in the hope that it will be useful, but
14// WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16// General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21#include "multivariable/df.h"
22#include "multivariable/f.h"
23
24#include <yat/utility/Vector.h>
25#include <yat/utility/VectorMutable.h>
26#include <yat/utility/version.h>
27
28#include <gsl/gsl_multimin.h>
29
30#include <cassert>
31#include <memory>
32
33namespace theplu {
34namespace yat {
35namespace utility {
36
37  /**
38     \brief Wrapper class around gsl_multimin_fdfminimizer in GSL.
39
40     Class is the abstract base class for several minimisation
41     algorithms using the derivative.
42  */
43  class MultiMinimizerDerivative
44  {
45  public:
46    /// Copy is not allowed
47    MultiMinimizerDerivative(const MultiMinimizerDerivative&) = delete;
48
49    /// Assignment not allowed
50    MultiMinimizerDerivative&
51    operator=(const MultiMinimizerDerivative&) = delete;
52
53    /**
54       \brief Number of epochs (iterations) used in last minimisation.
55     */
56    unsigned int epochs(void) const;
57
58    /**
59       The size of the first trial step is given by \c step_size
60
61       \see gsl_multimin_fdfminimizer_set
62     */
63    double step_size(void) const;
64
65    /**
66       The size of the first trial step is given by \c step_size
67
68       \see gsl_multimin_fdfminimizer_set
69     */
70    void step_size(double ss);
71
72    /**
73       The accuracy of the line minimization is specified by \c
74       tolerance
75
76       \see <a href="https://www.gnu.org/software/gsl/doc/html/multimin.html#initializing-the-multidimensional-minimizer">gsl_multimin_fdfminimizer_set</a>
77     */
78    double tolerance(void) const;
79
80    /**
81       The accuracy of the line minimization is specified by \c
82       tolerance
83
84       \see <a href="https://www.gnu.org/software/gsl/doc/html/multimin.html#initializing-the-multidimensional-minimizer">gsl_multimin_fdfminimizer_set</a>
85     */
86    void tolerance(double tol);
87
88    /// Abstract class defining the interface for functions defining
89    /// the stop criteria in the minimization
90    class Stopper
91    {
92    public:
93      /// return true is search should stop
94      virtual bool operator()(const gsl_multimin_fdfminimizer*)=0;
95    };
96
97
98    /// wrapper around
99    /// <a href="https://www.gnu.org/software/gsl/doc/html/multimin.html#stopping-criteria">gsl_multimin_test_gradient</a>
100    class Gradient : public Stopper
101    {
102    public:
103      /// \param epsabs tolerance
104      explicit Gradient(double epsabs);
105
106      /**
107         \return \c true if <a
108         href="https://www.gnu.org/software/gsl/doc/html/multimin.html#stopping-criteria">gsl_multimin_test_gradient</a>(gradient,
109         epsabs) does not return \c GSL_CONTINUE, where \c gradient is
110         defined by \c gsl_multimin_fdfminimizer_gradient and \c
111         epsabs is defined in constructor.
112       */
113      bool operator()(const gsl_multimin_fdfminimizer*);
114    private:
115      double epsabs_;
116    };
117
118
119    /**
120       Function finds an \c x that minimizes the function defined by
121       \c func. It calls gsl_multimin_fdfminimizer_iterate until
122       either \c GSL_ENOPROG is returned or the norm of the gradient
123       is smaller than \c epsabs, as tested by
124       gsl_multimin_test_gradient.
125
126       Type Requirements:
127       - \c FUNC must have an operator defining the function
128       double operator()(const VectorBase& x)
129       - \c FUNC must have an operator defining the gradient
130       void operator()(const VectorBase& x, VectorMutable&)
131    */
132    template<class FUNC>
133    void operator()(yat::utility::VectorMutable&, FUNC& func,
134                    MultiMinimizerDerivative::Stopper&& stopper);
135
136    /**
137       Same as
138       operator()(yat::utility::VectorMutable&, FUNC& func, double epsabs)
139       but iterate at maximum \c max_epochs iterations.
140     */
141    template<class FUNC>
142    void operator()(yat::utility::VectorMutable&, FUNC& func,
143                    MultiMinimizerDerivative::Stopper&& stopper,
144                    unsigned int max_epochs);
145  protected:
146    /**
147       \brief Constructor
148
149       \param t defines type of GSL minimizer
150       \param size Number of dimensions in the input space.
151     */
152    MultiMinimizerDerivative(const gsl_multimin_fdfminimizer_type* t,
153                             size_t size);
154  private:
155    const gsl_multimin_fdfminimizer_type* type_;
156    unsigned int epochs_;
157    size_t size_;
158    struct GslFree
159    {
160      void operator()(gsl_multimin_fdfminimizer*) const;
161    };
162    std::unique_ptr<gsl_multimin_fdfminimizer, GslFree> solver_;
163    double step_size_;
164    double tol_;
165  };
166
167
168  // template implementation
169
170  template<class FUNC>
171  void
172  MultiMinimizerDerivative::operator()(yat::utility::VectorMutable& x,
173                                       FUNC& func,
174                                       MultiMinimizerDerivative::Stopper&& stopper)
175  {
176    unsigned int max_epochs = std::numeric_limits<unsigned int>::max();
177    (*this)(x, func, std::move(stopper), max_epochs);
178  }
179
180
181  template<class FUNC>
182  void
183  MultiMinimizerDerivative::operator()(yat::utility::VectorMutable& x,
184                                       FUNC& func,
185                                       MultiMinimizerDerivative::Stopper&& stopper,
186                                       unsigned int max_epochs)
187  {
188    assert(size_ == x.size());
189    gsl_multimin_function_fdf gsl_func;
190    gsl_func.n = size_;
191    gsl_func.f = multivariable::f<FUNC>;
192    gsl_func.df = multivariable::df<FUNC>;
193    gsl_func.fdf = multivariable::fdf<FUNC>;
194    gsl_func.params = &func;
195
196    gsl_multimin_fdfminimizer_set(solver_.get(), &gsl_func, x.gsl_vector_p(),
197                                  step_size_, tol_);
198
199    int status = 0;
200    for (epochs_=0; epochs_<max_epochs; ++epochs_) {
201      status = gsl_multimin_fdfminimizer_iterate(solver_.get());
202      if (status) {
203        if (status == GSL_ENOPROG)
204          break;
205        throw yat::utility::GSL_error("MultiMinimizerDerivative", status);
206      }
207
208      if (stopper(solver_.get()))
209        break;
210      //if (gsl_multimin_test_gradient(solver_->gradient,epsabs) != GSL_CONTINUE)
211      //break;
212    }
213
214    // copy result to passed x
215    yat::utility::VectorConstView view(solver_->x);
216    x = view;
217  }
218
219}}}
220#endif
Note: See TracBrowser for help on using the repository browser.