31 #ifndef INCLUDE_DTO_SNOPT_INTERFACE_HPP_
32 #define INCLUDE_DTO_SNOPT_INTERFACE_HPP_
34 #include <Eigen/Dense>
36 #include <snopt7/snoptProblem.hpp>
38 namespace DirectTrajectoryOptimization {
41 template <
typename DIMENSIONS>
42 class DTOMethodInterface;
48 template <
class DIMENSIONS>
54 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
56 typedef typename DIMENSIONS::state_vector_array_t state_vector_array_t;
57 typedef typename DIMENSIONS::control_vector_array_t control_vector_array_t;
67 bool snopt_verbose,
bool feasible_point_only) :
70 this->_verbose = snopt_verbose;
73 minor_print_level_param = 0;
74 major_print_level_param = 1;
77 _feasible_point_only = feasible_point_only;
84 if (use_computeJacobian) {
97 std::shared_ptr<DTOMethodInterface<DIMENSIONS> >
_method;
99 snFunA spt_constraints_function = NULL;
100 int status_output_flag = 0;
101 bool use_computeJacobian =
false;
102 bool use_print_file =
false;
103 bool _feasible_point_only =
false;
106 static void NLP_function(
int *Status,
int *n,
double x[],
107 int *needF,
int *neF,
double F[],
108 int *needG,
int *neG,
double G[],
109 char *cu,
int *lencu,
110 int iu[],
int *leniu,
111 double ru[],
int *lenru );
114 const std::string & problem_name,
115 const std::string & output_file,
116 const std::string & param_file =
"",
117 const bool & computeJacobian =
false)
override;
118 void setupSNOPTvariables();
119 void setupNLPsolver();
120 void setupWarmStart();
122 void estimateJacobianStructure();
123 virtual void Solve(
bool warminit=
false)
override;
125 void setSparsityVariables();
126 void setSnoptFLimits();
128 void readParametersFromFile(
const std::string & param_file);
131 void validateSNOPTStatus(
const int & status,
132 const Eigen::Map<Eigen::VectorXd> & x,
const Eigen::Map<Eigen::VectorXd> & F);
135 state_vector_array_t &yTraj,
136 control_vector_array_t &uTraj,
137 Eigen::VectorXd &hTraj)
override;
139 state_vector_array_t & y_trajectory,
140 control_vector_array_t & u_trajectory,
141 Eigen::VectorXd & h_trajectory,
142 std::vector<int> & phaseId)
override;
145 state_vector_array_t &ydotTraj, control_vector_array_t & uTraj,
146 Eigen::VectorXd &hTraj, std::vector<int> &phaseId)
override;
148 virtual void GetFVector(Eigen::VectorXd &fVec)
override {fVec = F_vector;}
151 Eigen::VectorXi & _x_state,
152 Eigen::VectorXd & _x_mul,
153 Eigen::VectorXi & _f_state,
154 Eigen::VectorXd & _f_mul)
override;
157 const state_vector_array_t & y_sol,
158 const control_vector_array_t & u_sol,
159 const Eigen::VectorXd & h_sol)
override;
162 const Eigen::VectorXd & x_mul,
163 const Eigen::VectorXi & f_state,
164 const Eigen::VectorXd & f_mul)
override;
166 void SetVerifyLevel(
const int & level)
override {
167 if(level > -2 && level < 4)
168 verify_level_param = level;
170 std::cout <<
"incorrect verification level!" << std::endl;
171 std::exit(EXIT_FAILURE);
175 void UsePrintFile(
const bool & flag)
override {
176 use_print_file = flag;
180 char* spt_name_of_problem = NULL;
181 char* spt_name_of_output_file = NULL;
182 char* spt_name_of_print_file=NULL;
192 int original_size_G = 0;
197 double * spt_A = NULL;
199 int * spt_iGfun = NULL;
200 int * spt_jGvar = NULL;
202 int * spt_iAfun = NULL;
203 int * spt_jAvar = NULL;
205 double * spt_xlb = NULL;
206 double * spt_xub = NULL;
208 double * spt_Flb = NULL;
209 double * spt_Fub = NULL;
211 Eigen::VectorXd x_variables;
212 Eigen::VectorXd x_variables_validation;
213 Eigen::VectorXd x_multipliers;
214 Eigen::VectorXi x_state;
216 Eigen::VectorXd F_vector;
217 Eigen::VectorXd F_vector_validation;
218 Eigen::VectorXd F_multipliers;
219 Eigen::VectorXi F_state;
221 int snopt_warm_flag = 0;
223 Eigen::VectorXd snopt_Flb_v;
224 Eigen::VectorXd snopt_Fub_v;
225 Eigen::VectorXi snopt_iGfun;
226 Eigen::VectorXi snopt_jGvar;
231 int derivative_option_param = 0;
233 int scale_option_param = 1;
234 int verify_level_param = -1;
235 int major_iteration_limit_param = 80000;
236 int minor_iteration_limit_param = 80000;
237 int iteration_limit_param = 40000000;
238 double major_optimality_tolerance_param = 1e-1;
239 double major_feasibility_tolerance_param = 1e-6;
240 double minor_feasibility_tolerance_param = 1e-6;
241 int print_file_param = 0;
242 int minor_print_level_param = 0;
243 int major_print_level_param = 0;
244 int backup_basis_file_param = 0;
245 double line_search_tolerance_param = 0.9;
247 std::string print_solution_param =
"No";
250 template<
class DIMENSIONS>
251 std::shared_ptr<DTOSnoptInterface<DIMENSIONS> > DTOSnoptInterface<DIMENSIONS>::interface_pointer;
253 template <
class DIMENSIONS>
255 const std::string & output_file,
const std::string & param_file ,
256 const bool &computeJacobian) {
258 use_computeJacobian = computeJacobian;
261 _method->Initialize();
263 std::string print_file_name = output_file;
264 std::string real_output_file = output_file +
".out";
266 spt_name_of_problem =
const_cast<char*
>(problem_name.c_str());
267 spt_name_of_output_file =
const_cast<char*
>(real_output_file.c_str());
268 spt_name_of_print_file =
const_cast<char*
>(print_file_name.c_str());
271 setupSNOPTvariables();
273 if (param_file!=
"") {
274 readParametersFromFile(param_file);
277 nlp_solver = std::shared_ptr<snoptProblemA>(
new snoptProblemA(spt_name_of_problem));
280 SetupSolverParameters();
283 template<
class DIMENSIONS>
286 interface_pointer = std::enable_shared_from_this<DTOSnoptInterface<DIMENSIONS>>::shared_from_this();
287 spt_constraints_function = &this->DTOSnoptInterface::NLP_function;
290 spt_n_vars = _method->myNLP.GetNumVars();
293 spt_lenF = _method->myNLP.GetNumF() + 1;
294 spt_xlb = _method->myNLP.GetXlb_p();
295 spt_xub = _method->myNLP.GetXub_p();
297 x_variables.resize(spt_n_vars);
298 x_variables_validation.resize(spt_n_vars);
299 x_variables.setZero();
300 x_multipliers.resize(spt_n_vars);
301 x_state.resize(spt_n_vars);
304 F_vector.resize(spt_lenF);
305 F_vector_validation.resize(spt_lenF);
306 F_multipliers.resize(spt_lenF);
307 F_state.resize(spt_lenF);
310 setSparsityVariables();
313 template <
class DIMENSIONS>
314 void DTOSnoptInterface<DIMENSIONS>::setSnoptFLimits() {
316 Eigen::VectorXd local_Flb = _method->myNLP.GetFlb();
317 Eigen::VectorXd local_Fub = _method->myNLP.GetFub();
319 snopt_Flb_v.resize(spt_lenF);
320 snopt_Fub_v.resize(spt_lenF);
322 snopt_Flb_v(0) = -infy;
323 snopt_Fub_v(0) = infy;
325 snopt_Flb_v.segment(1,spt_lenF-1) = local_Flb;
326 snopt_Fub_v.segment(1,spt_lenF-1) = local_Fub;
328 spt_Flb = snopt_Flb_v.data();
329 spt_Fub = snopt_Fub_v.data();
331 if (this->_verbose) {
332 std::cout <<
"[VERBOSE] spt_lenF : " << spt_lenF << std::endl;
333 std::cout <<
"[VERBOSE] snopt_Flb : " << snopt_Flb_v.transpose() << std::endl;
334 std::cout <<
"[VERBOSE] snopt_Fub : " << snopt_Fub_v.transpose() << std::endl;
339 template <
class DIMENSIONS>
340 void DTOSnoptInterface<DIMENSIONS>::setSparsityVariables() {
342 Eigen::VectorXi local_iGfun = _method->myNLP.GetiGfun();
343 Eigen::VectorXi local_jGvar = _method->myNLP.GetjGvar();
344 Eigen::VectorXi local_jGcost =_method->myNLP.GetjGvarCost();
346 jgcost_size = local_jGcost.size();
347 original_size_G = _method->myNLP.GetDimG();
350 spt_lenA = spt_lenF*spt_n_vars;
351 spt_iAfun =
new int[spt_lenA];
352 spt_jAvar =
new int[spt_lenA];
353 spt_A =
new double[spt_lenA];
355 if (use_computeJacobian) {
357 spt_neG = spt_lenF*spt_n_vars;
358 spt_iGfun =
new int[spt_neG];
359 spt_jGvar =
new int[spt_neG];
362 spt_neG = original_size_G + jgcost_size;
363 snopt_iGfun.resize(spt_neG);
364 snopt_jGvar.resize(spt_neG);
366 snopt_iGfun.segment(0,jgcost_size) = Eigen::VectorXi::Zero(jgcost_size);
367 snopt_iGfun.segment(jgcost_size,original_size_G) = local_iGfun + Eigen::VectorXi::Ones(local_iGfun.size());
368 snopt_jGvar.segment(0,jgcost_size) = local_jGcost;
369 snopt_jGvar.segment(jgcost_size,original_size_G) = local_jGvar;
371 spt_iGfun = snopt_iGfun.data();
372 spt_jGvar = snopt_jGvar.data();
375 if (this->_verbose) {
376 std::cout <<
"[VERBOSE] jgcost_size : " << jgcost_size << std::endl;
377 std::cout <<
"[VERBOSE] spt_neG : " << spt_neG << std::endl;
379 std::cout <<
"[VERBOSE] snopt_iGfun : " << snopt_iGfun.transpose() << std::endl;
381 std::cout <<
"[VERBOSE] snopt_jGvar : " << snopt_jGvar.transpose() << std::endl;
386 template <
class DIMENSIONS>
387 void DTOSnoptInterface<DIMENSIONS>::setupNLPsolver() {
390 nlp_solver->setProblemSize( spt_n_vars , spt_lenF );
391 nlp_solver->setObjective ( spt_obj_row , spt_obj_add );
392 nlp_solver->setA ( spt_lenA, spt_neA, spt_iAfun, spt_jAvar, spt_A);
393 nlp_solver->setG ( spt_neG, spt_neG, spt_iGfun, spt_jGvar );
394 nlp_solver->setX ( x_variables.data() , spt_xlb , spt_xub , x_multipliers.data() , x_state.data());
395 nlp_solver->setF ( F_vector.data(), spt_Flb , spt_Fub , F_multipliers.data(), F_state.data() );
398 nlp_solver->setUserFun (spt_constraints_function);
401 nlp_solver->setPrintFile(spt_name_of_print_file);
403 if (use_computeJacobian) {
404 this->estimateJacobianStructure();
408 template <
class DIMENSIONS>
411 std::cout << std::endl <<
"setting parameters..." << std::endl;
413 nlp_solver->setIntParameter(
"Scale option" , scale_option_param);
418 if (use_computeJacobian)
419 derivative_option_param = 0;
421 derivative_option_param = 1;
424 nlp_solver->setRealParameter(
"Major feasibility tolerance", major_feasibility_tolerance_param);
427 nlp_solver->setRealParameter(
"Minor feasibility tolerance", minor_feasibility_tolerance_param);
429 nlp_solver->setIntParameter(
"Derivative option", derivative_option_param);
430 nlp_solver->setIntParameter(
"Verify level" , verify_level_param);
431 nlp_solver->setIntParameter(
"Major iterations limit", major_iteration_limit_param);
432 nlp_solver->setIntParameter(
"Minor iterations limit", minor_iteration_limit_param);
433 nlp_solver->setIntParameter(
"Iterations limit", iteration_limit_param);
434 nlp_solver->setRealParameter(
"Major optimality tolerance", major_optimality_tolerance_param);
435 nlp_solver->setIntParameter(
"Minor print level", minor_print_level_param);
436 nlp_solver->setIntParameter(
"Major print level", major_print_level_param);
439 nlp_solver->setIntParameter(
"New basis file", this->new_basis_file_param);
440 nlp_solver->setIntParameter(
"Old basis file", this->old_basis_file_param);
441 nlp_solver->setIntParameter(
"Backup basis file", backup_basis_file_param);
444 nlp_solver->setIntParameter(
"Save frequency",100000000);
446 if(this->_totally_quiet_) {
447 nlp_solver->setParameter(
"Solution No");
448 nlp_solver->setIntParameter(
"Summary file",0);
454 nlp_solver->setRealParameter(
"Linesearch tolerance", line_search_tolerance_param);
458 if (_feasible_point_only) {
459 nlp_solver->setIntParameter(
"Feasible point only",1);
460 nlp_solver->setParameter(
"Feasible point");
466 template <
class DIMENSIONS>
469 nlp_solver->computeJac(spt_neA,spt_neG);
472 std::cout <<
"Jacobian Structure has been estimated" << std::endl;
473 std::cout <<
"please press [ENTER] if you want to continue with optimization" << std::endl;
477 template <
class DIMENSIONS>
479 std::cout <<
"Ready to solve... " << std::endl;
487 nlp_solver->solve(snopt_warm_flag);
489 if(this->x_variables_validation.size() < 1){
490 std::cout <<
"Internal error!" << std::endl;
494 double epsilon_e = 1e-5;
495 for(
auto i = 0 ; i < this->spt_n_vars ; ++i) {
496 if(std::fabs(this->x_variables(i) - this->x_variables_validation(i)) > epsilon_e) {
497 std::cout <<
"SNOPT BUG! : X_variables are not the same!" << std::endl;
498 std::cout <<
"x_variables("<< i <<
") : " << x_variables(i) << std::endl;
499 std::cout <<
"x_validation("<< i <<
") : " << x_variables_validation(i) << std::endl;
503 for(
auto i = 0 ; i < this->spt_lenF; ++i) {
504 if(std::fabs(this->F_vector(i) - this->F_vector_validation(i)) > epsilon_e) {
505 std::cout <<
"SNOPT BUG! : Constraints are not consistent" << std::endl;
506 std::cout <<
"F_vector("<< i <<
") : " << F_vector(i) << std::endl;
507 std::cout <<
"F_validation("<< i <<
") : " << F_vector_validation(i) << std::endl;
508 std::cout <<
"F_lb("<< i <<
") : " << this->snopt_Flb_v(i) << std::endl;
509 std::cout <<
"F_ub("<< i <<
") : " << this->snopt_Fub_v(i) << std::endl;
577 template <
class DIMENSIONS>
582 template <
class DIMENSIONS>
583 void DTOSnoptInterface<DIMENSIONS>::validateSNOPTStatus(
const int & status,
584 const Eigen::Map<Eigen::VectorXd> & X,
const Eigen::Map<Eigen::VectorXd> & F) {
595 message =
"OPTIMAL SOLUTION FOUND!!!!";
598 message =
"Problem is Infeasible :-(";
601 message =
"---> Unbounded <---";
604 message =
"-> Iteration Limit <-";
608 std::cout << message << std::endl;
610 this->F_vector_validation = F;
611 this->x_variables_validation = X;
614 template <
class DIMENSIONS>
616 Eigen::VectorXd & _x_mul, Eigen::VectorXi & _f_state, Eigen::VectorXd & _f_mul) {
618 _x_state = this->x_state;
619 _x_mul = this->x_multipliers;
621 _f_state = this->F_state;
622 _f_mul = this->F_multipliers;
626 template <
class DIMENSIONS>
628 const control_vector_array_t & u_sol,
const Eigen::VectorXd &h_sol) {
630 _method->SetDecisionVariablesFromStateControlIncrementsTrajectories(this->x_variables,y_sol,u_sol,h_sol);
634 template <
class DIMENSIONS>
636 const Eigen::VectorXd & p_x_mul,
const Eigen::VectorXi & p_f_state,
637 const Eigen::VectorXd & p_f_mul) {
639 if(p_x_state.size() == spt_n_vars) {
641 x_multipliers = p_x_mul;
643 F_multipliers = p_f_mul;
645 std::cout <<
"Error during SNOPT solver initialization" << std::endl;
646 std::exit(EXIT_FAILURE);
650 template <
class DIMENSIONS>
652 control_vector_array_t & u_trajectory, Eigen::VectorXd & h_trajectory) {
653 Eigen::Map<Eigen::VectorXd> x_vector(x_variables.data(),spt_n_vars);
655 _method->getStateControlIncrementsTrajectoriesFromDecisionVariables(x_vector,y_trajectory,u_trajectory,h_trajectory);
658 template <
class DIMENSIONS>
660 control_vector_array_t & u_trajectory, Eigen::VectorXd & h_trajectory,
661 std::vector<int> & phaseId) {
663 this->GetDTOSolution(y_trajectory, u_trajectory, h_trajectory);
665 phaseId = _method->node_to_phase_map;
668 template <
class DIMENSIONS>
670 control_vector_array_t & uTraj, Eigen::VectorXd &hTraj, std::vector<int> &phaseId) {
674 _method->UpdateDecisionVariables(x_variables.data());
675 _method->getCompleteSolution(yTraj,ydotTraj,uTraj,hTraj,phaseId);
679 template <
class DIMENSIONS>
681 int *needF,
int *neF,
double F[],
682 int *needG,
int *neG,
double G[],
683 char *cu,
int *lencu,
684 int iu[],
int *leniu,
685 double ru[],
int *lenru ) {
707 DTOSnoptInterface<DIMENSIONS>::interface_pointer->_method->evalObjective(&F[0]);
708 DTOSnoptInterface<DIMENSIONS>::interface_pointer->_method->evalConstraintFct(&F[1], *neF - 1);
717 Eigen::Map<Eigen::VectorXd> F_b(F,*neF);
718 Eigen::Map<Eigen::VectorXd> X_vector(x,*n);
719 DTOSnoptInterface<DIMENSIONS>::interface_pointer->status_output_flag = *Status;
720 DTOSnoptInterface<DIMENSIONS>::interface_pointer->validateSNOPTStatus(*Status,X_vector,F_b);
virtual void InitializeSolver(const std::string &problem_name, const std::string &output_file, const std::string ¶m_file="", const bool &computeJacobian=false) override
DTO initializes the solver using this method.
Definition: snopt.hpp:254
This class serves as a base interface for inheriting classes.
Definition: base_method_interface.hpp:60
virtual void GetDTOSolution(state_vector_array_t &yTraj, control_vector_array_t &uTraj, Eigen::VectorXd &hTraj) override
Method to get the current values of the solution.
Definition: snopt.hpp:651
std::shared_ptr< DTOMethodInterface< DIMENSIONS > > _method
Definition: snopt.hpp:97
void InitializeDecisionVariablesFromTrajectory(const state_vector_array_t &y_sol, const control_vector_array_t &u_sol, const Eigen::VectorXd &h_sol) override
Initial solution point for the solver.
Definition: snopt.hpp:627
void SetupSolverParameters() override
Setting up solver parameters.
Definition: snopt.hpp:409
Base class for NLP Solvers interface.
virtual void Solve(bool warminit=false) override
DTO request the solver to proceed with the NLP.
Definition: snopt.hpp:478
This class serves as a base interface for inheriting classes.
Definition: base_solver_interface.hpp:47
Class interfacing SNOPT NLP with DTO Problem.
Definition: snopt.hpp:49
std::shared_ptr< snoptProblemA > nlp_solver
Definition: snopt.hpp:98
virtual void GetFVector(Eigen::VectorXd &fVec) override
Returns the vector of NLP-constraints.
Definition: snopt.hpp:148
void GetSolverSolutionVariables(Eigen::VectorXi &_x_state, Eigen::VectorXd &_x_mul, Eigen::VectorXi &_f_state, Eigen::VectorXd &_f_mul) override
Method to get final values of internal solver variables.
Definition: snopt.hpp:615
static std::shared_ptr< DTOSnoptInterface< DIMENSIONS > > interface_pointer
Definition: snopt.hpp:93
DTOSnoptInterface(std::shared_ptr< DTOMethodInterface< DIMENSIONS > > method, bool snopt_verbose, bool feasible_point_only)
Constructor.
Definition: snopt.hpp:65
void WarmSolverInitialization(const Eigen::VectorXi &x_state, const Eigen::VectorXd &x_mul, const Eigen::VectorXi &f_state, const Eigen::VectorXd &f_mul) override
Warm Initialization of NLP Solver.
Definition: snopt.hpp:635