BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
nlopt_optimizer.cpp
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 
23 #include "nlopt_optimizer.hpp"
24 #include "error.hpp"
25 
26 #include <string>
27 
28 namespace BubbleProfiler {
29 
30 bool optimization_succeeded(nlopt::result r)
31 {
32  switch (r) {
33  case nlopt::FAILURE: return false;
34  case nlopt::INVALID_ARGS: return false;
35  case nlopt::OUT_OF_MEMORY: return false;
36  case nlopt::ROUNDOFF_LIMITED: return false;
37  case nlopt::FORCED_STOP: return false;
38  case nlopt::SUCCESS: return true;
39  case nlopt::STOPVAL_REACHED: return true;
40  case nlopt::FTOL_REACHED: return true;
41  case nlopt::XTOL_REACHED: return true;
42  case nlopt::MAXEVAL_REACHED: return true;
43  case nlopt::MAXTIME_REACHED: return true;
44  default:
45  throw Optimizer_error("unrecognized NLopt status code: "
46  + std::to_string(r));
47  }
48 }
49 
51  : n_dims(n)
52  , lower_bounds(Eigen::VectorXd::Zero(n))
53  , upper_bounds(Eigen::VectorXd::Zero(n))
54 {
55 }
56 
57 void NLopt_optimizer::set_xtol_rel(double xtol_rel_)
58 {
59  xtol_rel = xtol_rel_;
60 }
61 
62 void NLopt_optimizer::set_ftol_rel(double ftol_rel_)
63 {
64  ftol_rel = ftol_rel_;
65 }
66 
68 {
69  lower_bounds = lb * Eigen::VectorXd::Ones(n_dims);
70 }
71 
73 {
74  if (i < 0 || i >= n_dims) {
75  throw Out_of_bounds_error(i, "NLopt_optimizer::set_lower_bounds: "
76  "array index out of bounds");
77  }
78  lower_bounds(i) = lb;
79 }
80 
81 void NLopt_optimizer::set_lower_bounds(const Eigen::VectorXd& lb)
82 {
83  if (lb.size() != lower_bounds.size()) {
84  throw Setup_error("NLopt_optimizer::set_lower_bounds: "
85  "size of bounds vectors must match");
86  }
87  lower_bounds = lb;
88 }
89 
91 {
92  upper_bounds = ub * Eigen::VectorXd::Ones(n_dims);
93 }
94 
96 {
97  if (i < 0 || i >= n_dims) {
98  throw Out_of_bounds_error(i, "NLopt_optimizer::set_upper_bounds: "
99  "array index out of bounds");
100  }
101  upper_bounds(i) = ub;
102 }
103 
104 void NLopt_optimizer::set_upper_bounds(const Eigen::VectorXd& ub)
105 {
106  if (ub.size() != upper_bounds.size()) {
107  throw Setup_error("NLopt_optimizer::set_upper_bounds: "
108  "size of bounds vectors must match");
109  }
110  upper_bounds = ub;
111 }
112 
113 void NLopt_optimizer::set_max_time(double maxtime_) {
114  if (maxtime < 0) {
115  throw Setup_error("NLopt_optimizer::set_max_time: "
116  "maximum allowed time must be non-negative");
117  }
118  maxtime = maxtime_;
119 }
120 
121 
122 nlopt::result NLopt_optimizer::optimize(const Eigen::VectorXd& guess)
123 {
124  if (guess.size() != n_dims) {
125  throw Setup_error("NLopt_optimizer::optimize: "
126  "initial guess size must match number of variables");
127  }
128 
129  nlopt::opt optimizer(algorithm, n_dims);
130 
131  void* parameters = &function;
133  optimizer.set_min_objective(nlopt_function, parameters);
134  } else {
135  optimizer.set_max_objective(nlopt_function, parameters);
136  }
137 
138  std::vector<double> lb(lower_bounds.data(), lower_bounds.data() + n_dims);
139  std::vector<double> ub(upper_bounds.data(), upper_bounds.data() + n_dims);
140  optimizer.set_lower_bounds(lb);
141  optimizer.set_upper_bounds(ub);
142 
143  optimizer.set_ftol_rel(ftol_rel);
144  optimizer.set_xtol_rel(xtol_rel);
145 
146  // Set max timeout if appropriate
147  if (maxtime > 0) {
148  optimizer.set_maxtime(maxtime);
149  }
150 
151  std::vector<double> x(guess.data(), guess.data() + n_dims);
152  const nlopt::result status = optimizer.optimize(x, extremum_value);
153 
154  // Throw an exception if we hit the max timeout
155  if(status == nlopt::MAXTIME_REACHED) {
156  throw Optimizer_error("NLopt_optimizer::optimize: "
157  "Timed out before locating extremum");
158  }
159 
160  extremum = Eigen::VectorXd::Map(x.data(), n_dims);
161 
162  return status;
163 }
164 
165 double NLopt_optimizer::nlopt_function(const std::vector<double>& x,
166  std::vector<double>& /* grad */,
167  void* params)
168 {
169  Function* func = static_cast<Function*>(params);
170  const Eigen::VectorXd coords(Eigen::VectorXd::Map(x.data(), x.size()));
171  return (*func)(coords);
172 }
173 
174 } // namespace BubbleProfiler
Eigen::VectorXd::Index Index
Exception indicating that the optimizer failed to converge.
Definition: error.hpp:104
nlopt::result optimize(const Eigen::VectorXd &guess)
bool optimization_succeeded(nlopt::result)
Exception indicating out of bounds access error.
Definition: error.hpp:75
std::function< double(const Eigen::VectorXd &)> Function
Exception indicating general setup error.
Definition: error.hpp:32
void set_ftol_rel(double ftol_rel_)
static double nlopt_function(const std::vector< double > &, std::vector< double > &, void *)
void set_xtol_rel(double xtol_rel_)