PaGMO  1.1.5
snopt.cpp
1 /*****************************************************************************
2  * Copyright (C) 2004-2015 The PaGMO development team, *
3  * Advanced Concepts Team (ACT), European Space Agency (ESA) *
4  * http://apps.sourceforge.net/mediawiki/pagmo *
5  * http://apps.sourceforge.net/mediawiki/pagmo/index.php?title=Developers *
6  * http://apps.sourceforge.net/mediawiki/pagmo/index.php?title=Credits *
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 "../exceptions.h"
26 #include "../population.h"
27 #include "../problem/base.h"
28 #include "../types.h"
29 #include <limits.h>
30 #include "base.h"
31 #include "snopt.h"
32 #include "snopt_cpp_wrapper/snopt_PAGMO.h"
33 #include "snopt_cpp_wrapper/snfilewrapper_PAGMO.h"
34 #include "snopt_cpp_wrapper/snoptProblem_PAGMO.h"
35 
36 //These are here to solve a possible problem with the shared f2c libraries during linking
37 extern "C"{
38  void MAIN_(){}
39  void MAIN__(){}
40  void _MAIN_(){}
41 }
42 
43 
44 //This is a static function that is used to wrap the snopt libraries. It has the propotype that is required
45 //and uses the memory location pointed by cu to read all informations about the PaGMO problem.
46 static int snopt_function_(integer *Status, integer *n, doublereal *x,
47  integer *needF, integer *neF, doublereal *F,
48  integer *needG, integer *neG, doublereal *G,
49  char *cu, integer *lencu,
50  integer *iu, integer *leniu,
51  doublereal *ru, integer *lenru )
52 {
53  (void)n;
54  (void)needF;
55  (void)neF;
56  (void)needG;
57  (void)neG;
58  (void)G;
59  (void)lencu;
60  (void)iu;
61  (void)leniu;
62  (void)lenru;
63  //1 - We retrieve the pointer to the base problem (PaGMO) we have 'hidden' in *cu
65  prob = (pagmo::problem::base*)cu;
66 
67  //2 - We retrieve the pointer to the allocated memory area containing the std::vector where
68  //to copy the snopt x[] array
69  pagmo::algorithm::snopt::preallocated_memory* preallocated = (pagmo::algorithm::snopt::preallocated_memory*)ru;
70  for (size_t i = 0;i < ( prob->get_dimension() - prob->get_i_dimension() );i++) (preallocated->x)[i] = x[i];
71 
72  //1 - to F[0] (the objective function) the value returned by the problem
73  try {
74  prob->objfun(preallocated->f,preallocated->x);
75  F[0] = preallocated->f[0];
76  }
77  catch (value_error) {
78  *Status = -1; //signals to snopt that the evaluation of the objective function had numerical difficulties
79  }
80  //2 - and to F[.] the constraint values (equalities first)
81  try{
82  prob->compute_constraints(preallocated->c, preallocated->x);
83  for (pagmo::problem::base::size_type i=0;i<prob->get_c_dimension();++i) F[i+1] = preallocated->c[i];
84  }
85  catch (value_error) {
86  *Status = -1; //signals to snopt that the evaluation of the objective function had numerical difficulties
87  }
88 
89  return 0;
90 }
91 
92 namespace pagmo { namespace algorithm {
93 
95 
103 snopt::snopt(const int major,const double feas, const double opt) : m_major(major),m_feas(feas),m_opt(opt), m_file_out(false)
104 {
105  if (major < 0) {
106  pagmo_throw(value_error,"number of major iterations cannot be negative");
107  }
108  if (feas < 0 || feas > 1) {
109  pagmo_throw(value_error,"feasibility cireria ");
110  }
111  if (opt < 0 || opt > 1) {
112  pagmo_throw(value_error,"number of major iterations cannot be negative");
113  }
114 
115 }
116 
119 {
120  return base_ptr(new snopt(*this));
121 }
122 
124 
131 void snopt::evolve(population &pop) const
132 {
133  // Let's store some useful variables.
134  const problem::base &prob = pop.problem();
135  const problem::base::size_type D = prob.get_dimension(), prob_i_dimension = prob.get_i_dimension(), prob_c_dimension = prob.get_c_dimension(), prob_f_dimension = prob.get_f_dimension();
136  const decision_vector &lb = prob.get_lb(), &ub = prob.get_ub();
137  const population::size_type NP = pop.size();
138  const problem::base::size_type Dc = D - prob_i_dimension;
139  const std::vector<double>::size_type D_ineqc = prob.get_ic_dimension();
140  const std::vector<double>::size_type D_eqc = prob_c_dimension - D_ineqc;
141  const std::string name = prob.get_name();
142 
143  //We perform some checks to determine wether the problem/population are suitable for SNOPT
144  if ( prob_i_dimension != 0 ) {
145  pagmo_throw(value_error,"No integer part allowed yet....");
146  }
147 
148  if ( Dc == 0 ) {
149  pagmo_throw(value_error,"No continuous part....");
150  }
151 
152  if ( prob_f_dimension != 1 ) {
153  pagmo_throw(value_error,"The problem is not single objective and SNOPT is not suitable to solve it");
154  }
155 
156  // Get out if there is nothing to do.
157  if (NP == 0 || m_major == 0) {
158  return;
159  }
160 
161  // We allocate memory for the decision vector that will be used in the snopt_function_
162  di_comodo.x.resize(Dc);
163  di_comodo.c.resize(prob_c_dimension);
164  di_comodo.f.resize(prob_f_dimension);
165 
166 
167  // We construct a SnoptProblem_PAGMO passing the pointers to the problem and the allocated
168  //memory area for the di_comodo vector
169  snoptProblem_PAGMO SnoptProblem(prob, &di_comodo);
170 
171  // Allocate and initialize;
172  integer n = Dc;
173 
174  // Box-constrained non-linear optimization
175  integer neF = 1 + prob_c_dimension;
176 
177  //Memory sizing of A
178  integer lenA = Dc * (1 + prob_c_dimension); //overestimate
179  integer *iAfun = new integer[lenA];
180  integer *jAvar = new integer[lenA];
181  doublereal *A = new doublereal[lenA];
182 
183 
184  //Memory sizing of G
185  int lenG =Dc * (1 + prob_c_dimension); //overestimate
186  integer *iGfun = new integer[lenG];
187  integer *jGvar = new integer[lenG];
188 
189 
190 
191  //Decision vector memory allocation
192  doublereal *x = new doublereal[n];
193  doublereal *xlow = new doublereal[n];
194  doublereal *xupp = new doublereal[n];
195  doublereal *xmul = new doublereal[n];
196  integer *xstate = new integer[n];
197 
198  //Objective function memory allocation
199  doublereal *F = new doublereal[neF];
200  doublereal *Flow = new doublereal[neF];
201  doublereal *Fupp = new doublereal[neF];
202  doublereal *Fmul = new doublereal[neF];
203  integer *Fstate = new integer[neF];
204 
205  integer nxnames = 1;
206  integer nFnames = 1;
207  char *xnames = new char[nxnames*8];
208  char *Fnames = new char[nFnames*8];
209 
210  integer ObjRow = 0;
211  doublereal ObjAdd = 0;
212 
213  // Set the upper and lower bounds. And The initial Guess
214  int bestidx = pop.get_best_idx();
215  for (pagmo::problem::base::size_type i = 0; i < Dc; i++){
216  xlow[i] = lb[i];
217  xupp[i] = ub[i];
218  xstate[i] = 0;
219  x[i] = pop.get_individual(bestidx).cur_x[i];
220  }
221 
222  // Set the bounds for objective, equality and inequality constraints
223  // 1 - Objective function
224  Flow[0] = -std::numeric_limits<double>::max();
225  Fupp[0] = std::numeric_limits<double>::max();
226  F[0] = pop.get_individual(bestidx).cur_f[0];
227  // 2 - Equality constraints
228  for (pagmo::problem::base::size_type i=0;i<D_eqc;++i) {
229  Flow[i+1] = 0;
230  Fupp[i+1] = 0;
231  }
232  // 3 - Inequality constraints
233  for (pagmo::problem::base::size_type i=0;i<D_ineqc;++i) {
234  Flow[i+1+D_eqc] = -std::numeric_limits<double>::max();
235  Fupp[i+1+D_eqc] = 0;
236  }
237 
238  // Load the data for SnoptProblem ...
239  SnoptProblem.setProblemSize( n, neF );
240  SnoptProblem.setNeG( lenG );
241  SnoptProblem.setNeA( lenA );
242  SnoptProblem.setA ( lenA, iAfun, jAvar, A );
243  SnoptProblem.setG ( lenG, iGfun, jGvar );
244  SnoptProblem.setObjective ( ObjRow, ObjAdd );
245  SnoptProblem.setX ( x, xlow, xupp, xmul, xstate );
246  SnoptProblem.setF ( F, Flow, Fupp, Fmul, Fstate );
247  SnoptProblem.setXNames ( xnames, nxnames );
248  SnoptProblem.setFNames ( Fnames, nFnames );
249  SnoptProblem.setProbName ( name.c_str() ); //This is limited to be 8 characters!!!
250  SnoptProblem.setUserFun ( snopt_function_ );
251 
252  //We set some parameters
253  if (m_screen_output) SnoptProblem.setIntParameter("Summary file",6);
254  if (m_file_out) SnoptProblem.setPrintFile ( name.c_str() );
255  SnoptProblem.setIntParameter ( "Derivative option", 0 );
256  SnoptProblem.setIntParameter ( "Major iterations limit", m_major);
257  SnoptProblem.setIntParameter ( "Iterations limit",100000);
258  SnoptProblem.setRealParameter( "Major feasibility tolerance", m_feas);
259  SnoptProblem.setRealParameter( "Major optimality tolerance", m_opt);
260 
261 
262  //We set the sparsity structure
263  int neG;
264  try
265  {
266  std::vector<int> iGfun_vect, jGvar_vect;
267  prob.set_sparsity(neG,iGfun_vect,jGvar_vect);
268  for (int i=0;i < neG;i++)
269  {
270  iGfun[i] = iGfun_vect[i];
271  jGvar[i] = jGvar_vect[i];
272  }
273  SnoptProblem.setNeG( neG );
274  SnoptProblem.setNeA( 0 );
275  SnoptProblem.setG( lenG, iGfun, jGvar );
276 
277  } //the user did implement the sparsity in the problem
278  catch (not_implemented_error)
279  {
280  SnoptProblem.computeJac();
281  neG = SnoptProblem.getNeG();
282  } //the user did not implement the sparsity in the problem
283 
284 
285  if (m_screen_output)
286  {
287  std::cout << "PaGMO 4 SNOPT:" << std::endl << std::endl;
288  std::cout << "Sparsity pattern set, NeG = " << neG << std::endl;
289  std::cout << "iGfun: [";
290  for (int i=0; i<neG-1; ++i) std::cout << iGfun[i] << ",";
291  std::cout << iGfun[neG-1] << "]" << std::endl;
292  std::cout << "jGvar: [";
293  for (int i=0; i<neG-1; ++i) std::cout << jGvar[i] << ",";
294  std::cout << jGvar[neG-1] << "]" << std::endl;
295  }
296 
297  integer Cold = 0;
298 
299  //HERE WE CALL snoptA routine!!!!!
300  SnoptProblem.solve( Cold );
301 
302  //Save the final point making sure it is within the linear bounds
303  std::copy(x,x+n,di_comodo.x.begin());
304  decision_vector newx = di_comodo.x;
305  std::transform(di_comodo.x.begin(), di_comodo.x.end(), pop.get_individual(bestidx).cur_x.begin(), di_comodo.x.begin(),std::minus<double>());
306  for (integer i=0;i<n;i++)
307  {
308  newx[i] = std::min(std::max(lb[i],newx[i]),ub[i]);
309  }
310 
311  pop.set_x(bestidx,newx);
312  pop.set_v(bestidx,di_comodo.x);
313 
314  //Clean up memory allocated to call the snoptA routine
315  delete []iAfun; delete []jAvar; delete []A;
316  delete []iGfun; delete []jGvar;
317 
318  delete []x; delete []xlow; delete []xupp;
319  delete []xmul; delete []xstate;
320 
321  delete []F; delete []Flow; delete []Fupp;
322  delete []Fmul; delete []Fstate;
323 
324  delete []xnames; delete []Fnames;
325 
326 }
327 
328 
330 
335 void snopt::file_output(const bool p) {m_file_out = p;}
336 
338 std::string snopt::get_name() const
339 {
340  return "SNOPT";
341 }
342 
343 
345 
348 std::string snopt::human_readable_extra() const
349 {
350  std::ostringstream s;
351  s << "major_iter:" << m_major << " feas_tol: "<<m_feas<< " opt_tol: "<<m_opt << std::endl;
352  return s.str();
353 }
354 
355 }} //namespaces
356 
357 BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::algorithm::snopt)
boost::shared_ptr< base > base_ptr
Alias for shared pointer to base algorithm.
Root PaGMO namespace.
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
snopt(const int major=100, const double feas=1e-10, const double opt=1e-4)
Constructor.
Definition: snopt.cpp:103
fitness_vector cur_f
Current fitness vector.
Definition: population.h:89
const individual_type & get_individual(const size_type &) const
Get constant reference to individual at position n.
Definition: population.cpp:277
virtual void set_sparsity(int &lenG, std::vector< int > &iGfun, std::vector< int > &jGvar) const
Sets the sparsity pattern of the gradient.
c_size_type get_ic_dimension() const
Return inequality constraints dimension.
Base problem class.
Definition: problem/base.h:148
Population class.
Definition: population.h:70
size_type get_dimension() const
Return global dimension.
std::string get_name() const
Algorithm name.
Definition: snopt.cpp:338
fitness_vector objfun(const decision_vector &) const
Return fitness of pagmo::decision_vector.
bool m_screen_output
Indicates to the derived class whether to print stuff on screen.
Wrapper for the SNOPT solver.
Definition: snopt.h:67
void file_output(const bool)
Activate file output.
Definition: snopt.cpp:335
size_type get_i_dimension() const
Return integer dimension.
constraint_vector compute_constraints(const decision_vector &) const
Compute constraints and return constraint vector.
std::string human_readable_extra() const
Extra human readable algorithm info.
Definition: snopt.cpp:348
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.
void evolve(population &) const
Evolve implementation.
Definition: snopt.cpp:131
virtual std::string get_name() const
Get problem's name.
base_ptr clone() const
Clone method.
Definition: snopt.cpp:118
const decision_vector & get_lb() const
Lower bounds getter.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
Definition: problem/base.h:160