BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
gsl_root_finder.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of BubbleProfiler.
3  *
4  * BubbleProfiler is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * BubbleProfiler is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with BubbleProfiler. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef BUBBLEPROFILER_GSL_ROOT_FINDER_HPP_INCLUDED
19 #define BUBBLEPROFILER_GSL_ROOT_FINDER_HPP_INCLUDED
20 
21 #include "error.hpp"
22 #include "raii_guard.hpp"
23 #include "root_finder.hpp"
24 
25 #include <Eigen/Core>
26 #include <gsl/gsl_multiroots.h>
27 
28 #include <cmath>
29 
30 namespace BubbleProfiler {
31 
32 template <int N>
33 class GSL_root_finder : public Root_finder<Eigen::Matrix<double,N,1> > {
34 public:
35  using Function_argument = Eigen::Matrix<double,N,1>;
36  using Function_value = Eigen::Matrix<double,N,1>;
37 
38  enum class Algorithm {
40  };
41 
42  virtual ~GSL_root_finder() = default;
43 
44  virtual const Function_argument& get_solution() const override {
45  return solution;
46  }
47 
49  void set_relative_error(double e) { rel_err = e; }
50  void set_absolute_error(double e) { abs_err = e; }
53  }
54  void set_max_iterations(std::size_t i) { max_iterations = i; }
55 
56 protected:
57  using Function = std::function<Function_value(const Function_argument&)>;
58 
59  virtual Root_finder_status solve(const Function&, const Function_argument&) override;
60 
61 private:
62  std::size_t n_dims;
64  double rel_err{1.e-6};
65  double abs_err{1.e-6};
67  std::size_t max_iterations{100};
68  Function function{nullptr};
70 
71  const gsl_multiroot_fsolver_type* get_gsl_solver_type() const;
72  static int gsl_function(const gsl_vector*, void*, gsl_vector*);
73 };
74 
75 template <int N>
77  const gsl_vector* x, void* parameters, gsl_vector* f)
78 {
79  const std::size_t length = x->size;
80  for (std::size_t i = 0; i < length; ++i) {
81  if (!std::isfinite(gsl_vector_get(x, i))) {
82  gsl_vector_set_all(f, std::numeric_limits<double>::max());
83  return GSL_EDOM;
84  }
85  }
86 
87  Function* func = static_cast<Function*>(parameters);
88  Function_argument arg(Function_argument::Map(x->data, length));
89  Function_value result(length);
90  result.setConstant(std::numeric_limits<double>::max());
91 
92  int status = GSL_SUCCESS;
93  try {
94  result = (*func)(arg);
95  bool finite_result = true;
96  for (std::size_t i = 0; i < length; ++i) {
97  finite_result = finite_result && std::isfinite(result(i));
98  }
99  status = finite_result ? GSL_SUCCESS : GSL_EDOM;
100  } catch (const Error&) {
101  status = GSL_EDOM;
102  }
103 
104  for (std::size_t i = 0; i < length; ++i) {
105  gsl_vector_set(f, i, result(i));
106  }
107 
108  return status;
109 }
110 
111 template <int N>
113  const Function& f, const Function_argument& initial_guess)
114 {
115  if (!f) {
116  throw Setup_error("GSL_root_finder::solve: "
117  "invalid function provided");
118  }
119 
120  n_dims = initial_guess.size();
121  function = f;
122  solution = initial_guess;
123 
124  void* parameters = &function;
125  gsl_multiroot_function func = {gsl_function, n_dims, parameters};
126 
127  gsl_multiroot_fsolver* solver
128  = gsl_multiroot_fsolver_alloc(get_gsl_solver_type(), n_dims);
129 
130  if (!solver) {
131  throw Out_of_memory_error("cannot allocate root finder");
132  }
133 
134  const auto handler = gsl_set_error_handler_off();
135 
136  const auto solver_guard = make_raii_guard(
137  [solver, handler]() {
138  gsl_multiroot_fsolver_free(solver);
139  gsl_set_error_handler(handler);
140  });
141 
142  gsl_vector* guess = gsl_vector_alloc(n_dims);
143 
144  if (!guess) {
145  throw Out_of_memory_error("cannot allocate solution guess");
146  }
147 
148  const auto vector_guard = make_raii_guard(
149  [guess]() {
150  gsl_vector_free(guess);
151  });
152 
153  for (std::size_t i = 0; i < n_dims; ++i) {
154  gsl_vector_set(guess, i, initial_guess(i));
155  }
156 
157  gsl_multiroot_fsolver_set(solver, &func, guess);
158 
159  std::size_t iterations = 0;
160  int status;
161  do {
162  iterations++;
163 
164  status = gsl_multiroot_fsolver_iterate(solver);
165 
166  if (status) {
167  break;
168  }
169 
171  status = gsl_multiroot_test_residual(solver->f, abs_err);
172  } else {
173  status = gsl_multiroot_test_delta(solver->dx, solver->x,
174  abs_err, rel_err);
175  }
176  } while (status == GSL_CONTINUE && iterations < max_iterations);
177 
178  for (std::size_t i = 0; i < n_dims; ++i) {
179  solution(i) = gsl_vector_get(solver->x, i);
180  }
181 
182  return (status == GSL_SUCCESS ? Root_finder_status::SUCCESS
184 }
185 
186 template <int N>
187 const gsl_multiroot_fsolver_type* GSL_root_finder<N>::get_gsl_solver_type() const
188 {
189  switch (solver_algorithm) {
190  case Algorithm::GSL_hybrids: return gsl_multiroot_fsolver_hybrids;
191  case Algorithm::GSL_hybrid: return gsl_multiroot_fsolver_hybrid;
192  case Algorithm::GSL_dnewton: return gsl_multiroot_fsolver_dnewton;
193  default:
194  throw Setup_error("GSL_root_finder::get_gsl_solver: "
195  "unrecognized solver type");
196  }
197 
198  return nullptr;
199 }
200 
201 } // namespace BubbleProfiler
202 
203 #endif
const gsl_multiroot_fsolver_type * get_gsl_solver_type() const
Eigen::Matrix< double, N, 1 > Function_value
virtual Root_finder_status solve(const Function &, const Function_argument &) override
Exception indicating that memory allocation failed.
Definition: error.hpp:98
static int gsl_function(const gsl_vector *, void *, gsl_vector *)
constexpr RAII_guard< F > make_raii_guard(F f)
Definition: raii_guard.hpp:43
void set_max_iterations(std::size_t i)
virtual ~GSL_root_finder()=default
Eigen::Matrix< double, N, 1 > Function_argument
virtual const Function_argument & get_solution() const override
std::function< Function_value(const Function_argument &)> Function
Exception indicating general setup error.
Definition: error.hpp:32
void set_use_stepsize_convergence_check(bool flag)