PaGMO  1.1.5
base_nlopt.cpp
1 /*****************************************************************************
2  * Copyright (C) 2004-2015 The PaGMO development team, *
3  * Advanced Concepts Team (ACT), European Space Agency (ESA) *
4  * *
5  * https://github.com/esa/pagmo *
6  * *
7  * act@esa.int *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the *
21  * Free Software Foundation, Inc., *
22  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23  *****************************************************************************/
24 
25 #include <algorithm>
26 #include <boost/numeric/conversion/cast.hpp>
27 #include <cstddef>
28 #include <nlopt.hpp>
29 #include <sstream>
30 #include <string>
31 #include <vector>
32 
33 #include "../exceptions.h"
34 #include "../population.h"
35 #include "../problem/base.h"
36 #include "../types.h"
37 #include "base.h"
38 #include "base_nlopt.h"
39 
40 namespace pagmo { namespace algorithm {
41 
43 
55 base_nlopt::base_nlopt(nlopt::algorithm algo, bool constrained, bool only_ineq, int max_iter, const double &ftol, const double &xtol):base(),
56  m_algo(algo),m_constrained(constrained),m_only_ineq(only_ineq),m_max_iter(boost::numeric_cast<std::size_t>(max_iter)),m_ftol(ftol),m_xtol(xtol)
57 {
58  if ( (ftol <= 0) || (xtol <= 0) ) {
59  pagmo_throw(value_error,"tolerances must be positive");
60  }
61  //Dummy init for m_opt
62  nlopt::opt opt(algo,1);
63  m_opt = opt;
64 }
65 
67 {
68  std::ostringstream oss;
69  oss << "max_iter: " << m_max_iter << ' ';
70  oss << "ftol: " << m_ftol << " ";
71  oss << "xtol: " << m_xtol;
72  return oss.str();
73 }
74 
75 // Objective function wrapper.
76 double base_nlopt::objfun_wrapper(const std::vector<double> &x, std::vector<double> &grad, void* data)
77 {
78  nlopt_wrapper_data *d = (nlopt_wrapper_data *)data;
79  pagmo_assert(d->f.size() == 1);
80 
81  // Compute the gradient by central diffs if necessary TODO: also ipopt has this code (or similar)
82  // It should be moved elswhere in PaGMO. Plus be aware that here a chromsome outside the bounds
83  // can be created, thus invaidating its compatibility with the problem (exception will be thrown)
84 
85  if (!grad.empty()) {
86  std::copy(x.begin(),x.end(),d->dx.begin());
87  double central_diff;
88  const double h0=1e-8;
89  double h;
90  double mem;
91  for (size_t i =0; i < d->dx.size(); ++i)
92  {
93  h = h0 * std::max(1.,fabs(d->dx[i]));
94  mem = d->dx[i];
95  d->dx[i] += h;
96  d->prob->objfun(d->f,d->dx);
97  central_diff = d->f[0];
98  d->dx[i] -= 2*h;
99  d->prob->objfun(d->f,d->dx);
100  central_diff = (central_diff-d->f[0]) / 2 / h;
101  grad[i] = central_diff;
102  d->dx[i] = mem;
103  }
104  }
105 
106  // Calculate the objective function.
107  d->prob->objfun(d->f,x);
108  // Return the fitness.
109  return (d->f)[0];
110 }
111 
112 
113 // Constraint function wrapper.
114 double base_nlopt::constraints_wrapper(const std::vector<double> &x, std::vector<double> &grad, void* data)
115 {
116  nlopt_wrapper_data *d = (nlopt_wrapper_data *)data;
117  pagmo_assert(d->c.size() == d->prob->get_c_dimension());
118 
119  // Compute the gradient by central diffs (if necessary). TODO: also ipopt has this code (or similar)
120  // It should be moved elswhere in PaGMO. Plus be aware that here a chromsome outside the bounds
121  // can be created, thus invaidating its compatibility with the problem (exception will be thrown)
122 
123  if (!grad.empty()) {
124  std::copy(x.begin(),x.end(),d->dx.begin());
125  double central_diff;
126  const double h0=1e-8;
127  double h;
128  double mem;
129  for (size_t i =0; i < d->dx.size(); ++i)
130  {
131  h = h0 * std::max(1.,fabs(d->dx[i]));
132  mem = d->dx[i];
133  d->dx[i] += h;
134  d->prob->compute_constraints(d->c,d->dx);
135  central_diff = d->c[d->c_comp];
136  d->dx[i] -= 2*h;
137  d->prob->compute_constraints(d->c,d->dx);
138  central_diff = (central_diff-d->c[d->c_comp]) / 2 / h;
139  grad[i] = central_diff;
140  d->dx[i] = mem;
141  }
142  }
143 
144  // Calculate the constraints.
145  d->prob->compute_constraints(d->c,x);
146  // Return the constraints component.
147  return (d->c)[d->c_comp];
148 }
149 
150 // Evolve method.
152 {
153  // Useful variables.
154  const problem::base &problem = pop.problem();
155  if (problem.get_f_dimension() != 1) {
156  pagmo_throw(value_error,"this algorithm does not support multi-objective optimisation");
157  }
158  const problem::base::c_size_type c_size = problem.get_c_dimension();
159  const problem::base::c_size_type ec_size = problem.get_c_dimension() - problem.get_ic_dimension();
160  if (c_size && !m_constrained) {
161  pagmo_throw(value_error,"this algorithm does not support constraints");
162  }
163  if (ec_size && m_only_ineq) {
164  pagmo_throw(value_error,"this algorithm does not support equality constraints");
165  }
166  const problem::base::size_type cont_size = problem.get_dimension() - problem.get_i_dimension();
167  if (!cont_size) {
168  pagmo_throw(value_error,"the problem has no continuous part");
169  }
170  // Do nothing if the population is empty.
171  if (!pop.size()) {
172  return;
173  }
174  // Extract the best individual and set the inital point
175  const population::size_type best_ind_idx = pop.get_best_idx();
176  const population::individual_type &best_ind = pop.get_individual(best_ind_idx);
177 
178 
179  // Structure to pass data to the objective function wrapper.
180  nlopt_wrapper_data data_objfun;
181 
182  data_objfun.prob = &problem;
183  data_objfun.x.resize(problem.get_dimension());
184  data_objfun.dx.resize(problem.get_dimension());
185  data_objfun.f.resize(1);
186 
187  // Structure to pass data to the constraint function wrapper.
188  std::vector<nlopt_wrapper_data> data_constrfun(boost::numeric_cast<std::vector<nlopt_wrapper_data>::size_type>(c_size));
189  for (problem::base::c_size_type i = 0; i < c_size; ++i) {
190  data_constrfun[i].prob = &problem;
191  data_constrfun[i].x.resize(problem.get_dimension());
192  data_constrfun[i].dx.resize(problem.get_dimension());
193  data_constrfun[i].c.resize(problem.get_c_dimension());
194  data_constrfun[i].c_comp = i;
195  }
196 
197  // Main NLopt call.
198  nlopt::opt opt(m_algo, problem.get_dimension());
199  m_opt = opt;
200  // Sets local optimizer for aug_lag methods, do nothing otherwise
201  set_local(problem.get_dimension());
202  m_opt.set_lower_bounds(problem.get_lb());
203  m_opt.set_upper_bounds(problem.get_ub());
204  m_opt.set_min_objective(objfun_wrapper, &data_objfun);
205  for (problem::base::c_size_type i =0; i<ec_size; ++i) {
206  m_opt.add_equality_constraint(constraints_wrapper, &data_constrfun[i], problem.get_c_tol().at(i));
207  }
208  for (problem::base::c_size_type i =ec_size; i<c_size; ++i) {
209  m_opt.add_inequality_constraint(constraints_wrapper, &data_constrfun[i], problem.get_c_tol().at(i));
210  }
211 
212  m_opt.set_ftol_abs(m_ftol);
213  m_opt.set_xtol_abs(m_xtol);
214  m_opt.set_maxeval(m_max_iter);
215 
216  //nlopt::result result;
217  double dummy;
218  decision_vector x0(best_ind.cur_x);
219  m_opt.optimize(x0, dummy);
220  pop.set_x(best_ind_idx,x0);
221 }
222 
223 void base_nlopt::set_local(size_t d) const
224 {
225  (void)d;
226 }
227 }}
Root PaGMO namespace.
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
nlopt::opt m_opt
NLOPT optimization method.
Definition: base_nlopt.h:94
const double m_xtol
Tolerance on the decision_vector variation function (stopping criteria)
Definition: base_nlopt.h:104
const individual_type & get_individual(const size_type &) const
Get constant reference to individual at position n.
Definition: population.cpp:277
Base algorithm class.
c_size_type get_ic_dimension() const
Return inequality constraints dimension.
Individuals stored in the population.
Definition: population.h:80
STL namespace.
const std::size_t m_max_iter
Maximum number of iterations.
Definition: base_nlopt.h:100
Base problem class.
Definition: problem/base.h:148
Population class.
Definition: population.h:70
size_type get_dimension() const
Return global dimension.
void evolve(population &) const
Evolve method.
Definition: base_nlopt.cpp:151
std::string human_readable_extra() const
Extra information in human readable format.
Definition: base_nlopt.cpp:66
size_type get_i_dimension() const
Return integer dimension.
const double m_ftol
Tolerance on the fitness function variation (stopping criteria)
Definition: base_nlopt.h:102
const std::vector< double > & get_c_tol() const
Return constraints tolerance.
c_size_type get_c_dimension() const
Return global constraints dimension.
const decision_vector & get_ub() const
Upper bounds getter.
container_type::size_type size_type
Population size type.
Definition: population.h:192
decision_vector cur_x
Current decision vector.
Definition: population.h:83
f_size_type get_f_dimension() const
Return fitness dimension.
constraint_vector::size_type c_size_type
Constraints' size type: the same as pagmo::constraint_vector's size type.
Definition: problem/base.h:164
const decision_vector & get_lb() const
Lower bounds getter.
base_nlopt(nlopt::algorithm, bool, bool, int, const double &, const double &)
Constructor.
Definition: base_nlopt.cpp:55
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
Definition: problem/base.h:160