32 namespace DirectTrajectoryOptimization {
34 template<
typename DIMENSIONS>
36 std::vector<std::shared_ptr<DynamicsBase<DIMENSIONS> > > dynamics,
37 std::vector<std::shared_ptr<DerivativesBaseDS<DIMENSIONS> > > derivatives,
38 std::shared_ptr<BaseClass::CostFunctionBase<DIMENSIONS> > costFunction,
40 Eigen::Vector2d duration,
int number_of_nodes,
bool methodVerbose) :
42 _derivatives(derivatives),
43 _costFunction(costFunction),
44 _constraints(constraints),
45 _trajTimeRange(duration),
46 _numberOfNodes(number_of_nodes),
47 _numControls(DIMENSIONS::CONTROL_SIZE),
48 _numStates(DIMENSIONS::STATE_SIZE),
49 _verbose(methodVerbose) {
51 if (dynamics.empty()) {
52 throw std::invalid_argument(
"Empty dynamics vector recieved.");
53 }
else if (derivatives.empty()) {
54 throw std::invalid_argument(
"Empty derivatives vector recieved.");
55 }
else if (costFunction ==
nullptr) {
56 throw std::invalid_argument(
"Cost object is nullptr.");
57 }
else if (constraints .empty()) {
58 throw std::invalid_argument(
"Constraints object is nullptr");
61 num_phases = _dynamics.size();
64 _multiphaseproblem =
true;
68 _interphase_constraint.clear();
69 _guardVectorDerivative.clear();
73 _flagInitialState = Eigen::VectorXi::Zero(_numStates);
74 _flagFinalState = Eigen::VectorXi::Zero(_numStates);
75 _flagInitialControl = Eigen::VectorXi::Zero(_numControls);
76 _flagFinalControl = Eigen::VectorXi::Zero(_numControls);
83 std::cout <<
"[VERBOSE] num_phases : " << num_phases << std::endl;
84 std::cout <<
"[VERBOSE] multiphaseproblem : " << _multiphaseproblem << std::endl;
92 template<
typename DIMENSIONS>
95 _flagInitialState = Eigen::VectorXi::Constant(y0.size(),1);
99 template<
typename DIMENSIONS>
100 void DTOMethodInterface<DIMENSIONS>::SetInitialControl(
const control_vector_t & u0) {
102 _flagInitialControl = Eigen::VectorXi::Constant(u0.size(),1);
106 template<
typename DIMENSIONS>
107 void DTOMethodInterface<DIMENSIONS>::SetFinalControl(
const control_vector_t & uf) {
109 _flagFinalControl = Eigen::VectorXi::Constant(uf.size(),1);
113 template<
typename DIMENSIONS>
114 void DTOMethodInterface<DIMENSIONS>::SetFinalState(
const state_vector_t & yF) {
116 _flagFinalState = Eigen::VectorXi::Constant(yF.size(),1);
121 template<
class DIMENSIONS>
122 void DTOMethodInterface<DIMENSIONS>::getTrajectoryIndexes(Eigen::VectorXi &hs,
123 Eigen::MatrixXi &ys, Eigen::MatrixXi &us) {
129 template<
class DIMENSIONS>
130 void DTOMethodInterface<DIMENSIONS>::SetStateBounds(
const state_vector_t & ylb,
131 const state_vector_t & yub) {
132 for (
int i = 0; i < num_phases; i++) {
138 template<
class DIMENSIONS>
139 void DTOMethodInterface<DIMENSIONS>::SetStateBounds(
140 const state_vector_array_t & ylb,
const state_vector_array_t & yub) {
142 assert(ylb.size() == num_phases);
143 assert(yub.size() == num_phases);
149 template<
class DIMENSIONS>
150 void DTOMethodInterface<DIMENSIONS>::SetControlBounds(
const control_vector_t & ulb,
151 const control_vector_t & uub) {
153 for (
int i = 0; i < num_phases; i++) {
160 template<
class DIMENSIONS>
161 void DTOMethodInterface<DIMENSIONS>::SetControlBounds(
162 const control_vector_array_t & ulb,
const control_vector_array_t & uub) {
164 assert(ulb.size() == num_phases);
165 assert(uub.size() == num_phases);
171 template<
class DIMENSIONS>
172 void DTOMethodInterface<DIMENSIONS>::setTimeIncrementsBounds(
173 const double & h_min,
const double & h_max) {
175 if (h_max < h_min || h_min < 0) {
176 std::cout <<
"Time increments bounds are not consistent!" << std::endl;
177 std::exit (EXIT_FAILURE);
179 minimum_increment_size = h_min;
180 maximum_increment_size = h_max;
183 template<
class DIMENSIONS>
184 void DTOMethodInterface<DIMENSIONS>::SetFreeFinalState(
int state_number) {
185 _flagFinalState(state_number) = 0;
188 template<
typename DIMENSIONS>
189 void DTOMethodInterface<DIMENSIONS>::Initialize() {
191 if (ValidateDuration() ==
false) {
195 if (ValidateStateControlBounds() ==
false) {
199 if(_guards.size() != num_phases - 1) {
200 throw std::invalid_argument(
"Vector of guard functions does not match number of dynamics passed.");
203 SetSizeOfVariables();
204 SetSizeOfConstraints();
205 SetTOConstraintsBounds();
206 SetTOVariablesBounds();
207 SetupJacobianVariables();
208 Method_specific_initialization();
213 template<
typename DIMENSIONS>
214 void DTOMethodInterface<DIMENSIONS>::SetPercentageNodesPerDynamics(Eigen::VectorXd nodeSplit) {
216 if (nodeSplit.size() != num_phases) {
217 throw std::invalid_argument(
"Mismatch between number of splits in percentage vector and number of dynamics.");
222 for (
int i = 0; i < nodeSplit.size(); i++) {
223 total += nodeSplit[i];
227 throw std::invalid_argument(
"Percentage split vector does not sum to 100%.");
233 _nodeSplitPercentage = nodeSplit;
234 _nodeSplitSet =
true;
237 template<
typename DIMENSIONS>
238 void DTOMethodInterface<DIMENSIONS>::SetNodesPerPhase(
const Eigen::VectorXi & nodes) {
241 if(nodes.rows() < num_phases) {
242 std::cout <<
"nodes distribution doesn't fit into number of phases" << std::endl;
243 std::exit(EXIT_FAILURE);
246 for(
int i = 0 ; i < num_phases ; i++){
247 number_nodes_phase.push_back(nodes(i));
248 std::cout <<
"nnp : " << number_nodes_phase[i] << std::endl;
252 for(
int k = 0 ; k < num_phases ; k++) {
253 for(
int i = 0 ; i < number_nodes_phase[k] ; i++){
254 node_to_phase_map.push_back(k);
260 _nodeSplitSet =
true;
261 _nodeDistribution =
true;
267 template<
typename DIMENSIONS>
268 void DTOMethodInterface<DIMENSIONS>::SetSizeOfVariables() {
271 n_inc = _numberOfNodes - num_phases;
273 int num_vars = _numberOfNodes * (_numStates + _numControls) + n_inc;
275 myNLP.SetVariablesSize(num_vars);
278 _y_trajectory.resize(_numberOfNodes);
279 _ydot_trajectory.resize(_numberOfNodes);
280 _u_trajectory.resize(_numberOfNodes);
281 _h_trajectory.resize(n_inc);
284 h_inds.resize(n_inc);
285 y_inds.resize(_numStates, _numberOfNodes);
286 u_inds.resize(_numControls, _numberOfNodes);
288 if(this->_multiphaseproblem) {
289 leftphase_nodes.resize(num_phases-1);
290 rightphase_nodes.resize(num_phases-1);
291 size_interphase_constraint.resize(num_phases - 1);
292 size_guard.resize(num_phases-1);
299 if (!_nodeSplitSet) {
301 _nodeSplitPercentage.resize(num_phases);
303 for (
int j = 0; j < num_phases - 1; j++) {
304 _nodeSplitPercentage[j] = 100.00/
static_cast<double>(num_phases);
305 sumAmt += _nodeSplitPercentage[j];
307 _nodeSplitPercentage[num_phases - 1] = 100 - sumAmt;
311 if (!_nodeDistribution) {
312 int startingNode = 0;
313 number_nodes_phase.clear();
315 for (
int i = 0; i < num_phases - 1; i++) {
316 std::cout <<
"_nodeSplitPercentage[i] : " << _nodeSplitPercentage[i] << std::endl;
319 int numberNodesThisPhase = _numberOfNodes/num_phases;
321 number_nodes_phase.push_back(numberNodesThisPhase);
322 for (
int j = startingNode; j < numberNodesThisPhase + startingNode; j++) {
323 node_to_phase_map.push_back(i);
325 startingNode += numberNodesThisPhase;
328 number_nodes_phase.push_back(_numberOfNodes-startingNode);
330 for (
int j = startingNode; j < _numberOfNodes; j++) {
331 node_to_phase_map.push_back(num_phases - 1);
335 assert(node_to_phase_map.size() == _numberOfNodes);
338 for (
int i = 0; i < n_inc; i++)
341 int initial_index_y = n_inc;
342 int initial_index_u = n_inc + (_numberOfNodes * _numStates);
344 for (
int node = 0; node < _numberOfNodes; node++) {
345 for (
int state = 0; state < _numStates; state++) {
346 y_inds(state, node) = initial_index_y + node * _numStates + state;
348 for (
int control = 0; control < _numControls; control++) {
349 u_inds(control, node) = initial_index_u + node * _numControls + control;
353 if(_multiphaseproblem) {
354 int first_node_this_phase = 0;
356 for(
int i = 0 ; i < num_phases - 1 ; i++) {
357 leftphase_nodes(i) = first_node_this_phase + number_nodes_phase[i]-1;
358 rightphase_nodes(i)= first_node_this_phase + number_nodes_phase[i];
359 first_node_this_phase += number_nodes_phase[i];
363 increments_solution.resize(n_inc);
364 states_solution.resize(_numStates, _numberOfNodes);
365 controls_solution.resize(_numControls, _numberOfNodes);
368 increments_solution.setConstant(-infy);
369 states_solution.setConstant(-infy);
370 controls_solution.setConstant(-infy);
373 std::cout <<
"[VERBOSE] h_inds : " << h_inds.transpose() << std::endl
374 <<
"[VERBOSE] y_inds : " << std::endl << y_inds << std::endl
375 <<
"[VERBOSE] u_inds : " << std::endl << u_inds << std::endl
376 <<
"[VERBOSE] Number of nodes : " << _numberOfNodes << std::endl
377 <<
"[VERBOSE] n_inc : " << n_inc << std::endl
378 <<
"[VERBOSE] _numStates : " << _numStates << std::endl
379 <<
"[VERBOSE] _numControls : " << _numControls << std::endl
380 <<
"[VERBOSE] number of phases : " << num_phases << std::endl;
382 for (
int i = 0 ; i < _numberOfNodes ; i++) {
383 std::cout <<
"Node ["<<i<<
"] = " << node_to_phase_map[i] << std::endl;
384 std::cout <<
"Testing Dynamics[" << i <<
"] : "
385 << this->_dynamics[node_to_phase_map[i]]->systemDynamics(state_vector_t::Zero(),control_vector_t::Zero()).transpose() << std::endl;
387 for (
int k = 0 ; k < this->num_phases ; k++) {
388 std::cout <<
"[VERBOSE] Number_of_nodes_phase[" << k <<
"] : " << number_nodes_phase[k] << std::endl;
392 std::cout <<
"[VERBOSE] leftphase_nodes : " << leftphase_nodes.transpose() << std::endl;
393 std::cout <<
"[VERBOSE] rightphase_nodes: " << rightphase_nodes.transpose() << std::endl;
400 template<
typename DIMENSIONS>
401 void DTOMethodInterface<DIMENSIONS>::SetSizeOfConstraints() {
404 num_defects = n_inc * _numStates;
405 defects_lb.resize(num_defects);
406 defects_ub.resize(num_defects);
407 defect_out_.resize(num_defects);
408 defect_out_.setZero();
411 num_parametric_constraints = _evenTimeIncr ? n_inc : 1;
412 parametricConstraints_lb.resize(num_parametric_constraints);
413 parametricConstraints_ub.resize(num_parametric_constraints);
414 parametric_out_.resize(num_parametric_constraints);
415 parametric_out_.setZero();
418 num_user_constraints_per_node_in_phase.clear();
419 num_user_constraints = 0;
421 for (
int k = 0 ; k < this->num_phases ; k++) {
423 int num_user_constraints_per_phase = _constraints[k]->getNumConstraints();
424 num_user_constraints_per_node_in_phase.push_back(num_user_constraints_per_phase);
427 num_user_constraints += num_user_constraints_per_phase * this->number_nodes_phase[k];
429 user_constraints_out_.resize(num_user_constraints);
430 user_constraints_out_.setZero();
432 userConstraints_lb.resize(num_user_constraints);
433 userConstraints_ub.resize(num_user_constraints);
436 if (_multiphaseproblem) {
440 for(
int i = 0 ; i < num_phases - 1 ; i++) {
441 size_guard[i] = this->_guards[i]->GetSize();
442 num_guards += size_guard[i];
445 guard_lb.resize(num_guards);
446 guard_ub.resize(num_guards);
450 for(
int i = 0 ; i < num_phases - 1 ; i++) {
451 size_interphase_constraint[i] = this->_interphase_constraint[i]->GetSize();
452 num_interphase_constraints += size_interphase_constraint[i];
454 interphase_lb.resize(num_interphase_constraints);
455 interphase_ub.resize(num_interphase_constraints);
457 guard_vector_.resize(num_guards);
458 interface_vector_.resize(num_interphase_constraints);
460 guard_vector_.setZero();
461 interface_vector_.setZero();
466 int num_F = num_defects + num_parametric_constraints + num_user_constraints + num_guards + num_interphase_constraints;
468 myNLP.SetConstraintsSize(num_F);
471 std::cout <<
" [VERBOSE] num_defects : " << num_defects << std::endl;
472 std::cout <<
" [VERBOSE] num_parametric_constraints : " << num_parametric_constraints << std::endl;
473 std::cout <<
" [VERBOSE] num_user_constraints : " << num_user_constraints << std::endl;
474 std::cout <<
" [VERBOSE] num_guards : " << num_guards << std::endl;
475 std::cout <<
" [VERBOSE] num_interphase_constraints : " << num_interphase_constraints << std::endl;
480 template<
typename DIMENSIONS>
481 void DTOMethodInterface<DIMENSIONS>::SetTOConstraintsBounds() {
484 defects_lb.setConstant(0);
485 defects_ub.setConstant(0);
488 parametricConstraints_lb(0) = _trajTimeRange(0);
489 parametricConstraints_ub(0) = _trajTimeRange(1);
492 parametricConstraints_lb.segment(1, n_inc - 1).setConstant(0);
493 parametricConstraints_ub.segment(1, n_inc - 1).setConstant(0);
498 for (
int i = 0 ; i < this->num_phases ; i++) {
499 int constraints_in_phase = number_nodes_phase[i]*num_user_constraints_per_node_in_phase[i];
500 userConstraints_lb.segment(aux_index,constraints_in_phase) = _constraints[i]->getConstraintsLowerBound().replicate(
501 number_nodes_phase[i],1);
502 userConstraints_ub.segment(aux_index,constraints_in_phase) = _constraints[i]->getConstraintsUpperBound().replicate(
503 number_nodes_phase[i],1);
504 aux_index += constraints_in_phase;
508 if (_multiphaseproblem) {
510 int first_index_guard = 0;
511 for (
int i = 0 ; i < this->num_phases -1 ; i++) {
512 interphase_lb.segment(first_index,this->size_interphase_constraint[i]) = _interphase_constraint[i]->getLowerBound();
513 interphase_ub.segment(first_index,this->size_interphase_constraint[i]) = _interphase_constraint[i]->getUpperBound();
514 first_index+=size_interphase_constraint[i];
517 guard_lb.segment(first_index_guard,this->size_guard[i])=_guards[i]->GetLowerBound();
518 guard_ub.segment(first_index_guard,this->size_guard[i])=_guards[i]->GetUpperBound();
519 first_index_guard +=size_guard[i];
523 Eigen::VectorXd Flb,Fub;
525 if (_multiphaseproblem) {
526 Flb.resize(myNLP.num_F);
527 Fub.resize(myNLP.num_F);
528 Flb << defects_lb, parametricConstraints_lb, userConstraints_lb, guard_lb, interphase_lb;
529 Fub << defects_ub, parametricConstraints_ub, userConstraints_ub, guard_ub, interphase_ub;
531 Flb.resize(myNLP.num_F);
532 Fub.resize(myNLP.num_F);
533 Flb << defects_lb, parametricConstraints_lb, userConstraints_lb;
534 Fub << defects_ub, parametricConstraints_ub, userConstraints_ub;
537 myNLP.SetConstraintsBounds(Flb,Fub);
540 std::cout <<
" [VERBOSE] defects_lb : " << defects_lb.transpose() << std::endl;
541 std::cout <<
" [VERBOSE] defects_ub : " << defects_ub.transpose() << std::endl;
542 std::cout <<
" [VERBOSE] parametricConstraints_lb : " << parametricConstraints_lb.transpose() << std::endl;
543 std::cout <<
" [VERBOSE] parametricConstraints_ub : " << parametricConstraints_ub.transpose() << std::endl;
544 std::cout <<
" [VERBOSE] guard_lb : " << guard_lb.transpose() << std::endl;
545 std::cout <<
" [VERBOSE] guard_ub : " << guard_ub.transpose() << std::endl;
546 std::cout <<
" [VERBOSE] interphase_lb : " << interphase_lb.transpose() << std::endl;
547 std::cout <<
" [VERBOSE] interphase_ub : " << interphase_ub.transpose() << std::endl;
553 template<
typename DIMENSIONS>
554 void DTOMethodInterface<DIMENSIONS>::SetTOVariablesBounds() {
556 Eigen::VectorXd x_lb(myNLP.GetNumVars());
557 Eigen::VectorXd x_ub(myNLP.GetNumVars());
560 x_lb.setConstant(-infy);
561 x_ub.setConstant(infy);
564 x_lb.segment(0, n_inc).setConstant(minimum_increment_size);
565 x_ub.segment(0, n_inc).setConstant(maximum_increment_size);
568 for (
int j = 0 ; j < _numberOfNodes ; j++) {
569 int index = node_to_phase_map[j];
570 for (
int i = 0 ; i < _numStates ; i++) {
571 x_lb(y_inds(i, j)) = y_lb[index](i);
572 x_ub(y_inds(i, j)) = y_ub[index](i);
577 for (
int j = 0 ; j < _numberOfNodes ; j++) {
578 int index = node_to_phase_map[j];
579 for (
int i = 0 ; i < _numControls ; i++) {
580 x_lb(u_inds(i, j)) = u_lb[index](i);
581 x_ub(u_inds(i, j)) = u_ub[index](i);
586 for (
int i = 0; i < _numStates; i++) {
588 if (_flagInitialState(i)) {
589 x_lb(y_inds(i, 0)) = y_0(i);
590 x_ub(y_inds(i, 0)) = y_0(i);
593 if (_flagFinalState(i)) {
595 int last_node = _numberOfNodes - 1;
596 x_lb(y_inds(i, last_node)) = y_f(i) - 0.01;
597 x_ub(y_inds(i, last_node)) = y_f(i) + 0.01;
602 for (
int i = 0 ; i < _numControls ; i++) {
604 if (_flagInitialControl(i)) {
605 x_lb(u_inds(i,0)) = u_0(i);
606 x_ub(u_inds(i,0)) = u_0(i);
608 if (_flagFinalControl(i)) {
609 int last_node = _numberOfNodes - 1;
610 x_lb(u_inds(i,last_node)) = u_f(i);
611 x_ub(u_inds(i,last_node)) = u_f(i);
615 myNLP.SetVariablesBounds(x_lb,x_ub);
618 template<
typename DIMENSIONS>
619 void DTOMethodInterface<DIMENSIONS>::SetupJacobianVariables() {
621 setNLPnnzConstraintJacobian();
623 setSparsityJacobianConstraint();
625 setSparsityJacobianCost();
628 template<
typename DIMENSIONS>
629 void DTOMethodInterface<DIMENSIONS>::setNLPnnzConstraintJacobian() {
635 int nnz_defects = this->num_defects * (1 + 2 * this->_numStates + 2 * this->_numControls);
636 nnz_jac_g += nnz_defects;
640 int nnz_parametric_constraints = this->n_inc;
642 if (this->_evenTimeIncr) {
644 nnz_parametric_constraints += 2 * (this->n_inc - 1);
646 nnz_jac_g += nnz_parametric_constraints;
649 this->nnz_user_constraints = this->getNumNonZeroUserJacobian();
650 nnz_jac_g += this->nnz_user_constraints;
653 int nnz_guard_constraints = 0;
654 int nnz_interphase_constraints = 0;
655 if(this->_multiphaseproblem) {
656 nnz_guard_constraints = this->getNumNonZeroGuardFunctionJacobian();
657 nnz_jac_g += nnz_guard_constraints;
659 nnz_interphase_constraints= this->getNumNonZeroInterphaseJacobian();
660 nnz_jac_g += nnz_interphase_constraints;
663 myNLP.SetGSize(nnz_jac_g);
665 if (this->_verbose) {
666 std::cout <<
"[VERBOSE] Nnz_Defects : " << nnz_defects << std::endl
667 <<
"[VERBOSE] nnz_parametric_constraints : "<< nnz_parametric_constraints << std::endl
668 <<
"[VERBOSE] nnz_user_constraints : " << this->nnz_user_constraints << std::endl
669 <<
"[VERBOSE] nnz_guard_constraints : " << nnz_guard_constraints << std::endl
670 <<
"[VERBOSE] nnz_interPhase_const : " << nnz_interphase_constraints << std::endl
671 <<
"[VERBOSE] Total nnz in Jacobian : " << nnz_jac_g << std::endl;
676 template<
typename DIMENSIONS>
677 int DTOMethodInterface<DIMENSIONS>::getNumNonZeroUserJacobian() {
679 int user_non_zero_G = 0;
681 for (
int i = 0 ; i < this->num_phases ; i++) {
682 int num_nonzero_jacobian_user_per_node = _constraints[i]->getNnzJac();
683 this->num_nonzero_jacobian_user_per_node_in_phase.push_back(num_nonzero_jacobian_user_per_node);
684 int user_non_zero_this_phase = num_nonzero_jacobian_user_per_node * this->number_nodes_phase[i];
685 this->user_non_zero_G_phase.push_back(user_non_zero_this_phase);
686 user_non_zero_G += user_non_zero_this_phase;
689 return user_non_zero_G;
692 template<
typename DIMENSIONS>
693 int DTOMethodInterface<DIMENSIONS>::getNumNonZeroGuardFunctionJacobian() {
697 int guard_nonZeroElements = num_guards * _numStates;
699 return guard_nonZeroElements;
702 template<
typename DIMENSIONS>
703 int DTOMethodInterface<DIMENSIONS>::getNumNonZeroInterphaseJacobian() {
705 int nnz_interphase = 0;
706 for (
int i = 0 ; i < this->num_phases - 1; i++) {
707 nnz_interphase += _interphase_constraint[i]->GetNnzJacobian();
709 return nnz_interphase;
712 template<
class DIMENSIONS>
713 void DTOMethodInterface<DIMENSIONS>::setSparsityJacobianCost() {
716 setNLPnnzCostFunctionJacobian();
720 int index_of_fist_node = 0;
724 for(
int p = 0 ; p < num_phases ; p++) {
725 for (
int k = 0 ; k < number_nodes_phase[p] - 1 ; k++) {
726 myNLP.jG_cost(g_index) = h_inds(inc_index);
728 myNLP.jG_cost.segment(g_index,this->_numStates) = y_inds.col(index_of_fist_node + k);
729 g_index += this->_numStates;
730 myNLP.jG_cost.segment(g_index,this->_numControls) = u_inds.col(index_of_fist_node + k);
731 g_index += this->_numControls;
734 index_of_fist_node +=number_nodes_phase[p];
738 myNLP.jG_cost.segment(g_index,this->_numStates) = y_inds.col(index_of_fist_node-1);
739 g_index += this->_numStates;
746 std::cout <<
"[VERBOSE] lenG_cost : " << myNLP.lenG_cost << std::endl;
747 std::cout <<
"[VERBOSE] jG_cost.size() : " << myNLP.jG_cost.size() << std::endl;
748 std::cout <<
"[VERBOSE] jG_cost : " << myNLP.jG_cost.transpose() << std::endl;
753 template<
typename DIMENSIONS>
754 void DTOMethodInterface<DIMENSIONS>::setNLPnnzCostFunctionJacobian() {
757 int cost_nonZeroElements = n_inc * (_numStates + _numControls) + _numStates + n_inc;
760 myNLP.setGcostSize(cost_nonZeroElements);
765 template<
typename DIMENSIONS>
766 void DTOMethodInterface<DIMENSIONS>::UpdateDecisionVariables(
const double* x) {
769 const Eigen::Map<Eigen::VectorXd> x_local(
770 const_cast<double *>(x), myNLP.num_vars);
772 UpdateDTOTrajectoriesFromDecisionVariables(x_local);
775 for(
int k = 0 ; k < this->_numberOfNodes ; k++) {
776 _ydot_trajectory[k] = this->_dynamics[node_to_phase_map[k]]->systemDynamics(_y_trajectory[k],_u_trajectory[k]);
779 _costFunction->setCurrentTrajectory(
780 _y_trajectory, _u_trajectory, _h_trajectory, leftphase_nodes);
783 template<
typename DIMENSIONS>
784 void DTOMethodInterface<DIMENSIONS>::getCompleteSolution(state_vector_array_t & yTraj,
785 state_vector_array_t & ydotTraj, control_vector_array_t & uTraj,
786 Eigen::VectorXd & hTraj, std::vector<int> & phaseId)
const {
790 int phase_first_node = 0;
791 std::vector<double> h_inc;
793 for(
int p = 0; p < this->num_phases ; p++ ){
795 for(
int n = 0 ; n < this->number_nodes_phase[p] - 1 ; n++) {
797 node = phase_first_node + n;
800 state_vector_t y_mid = 0.5*(this->_y_trajectory[node] + this->_y_trajectory[node+1])
801 + 0.125*this->_h_trajectory(inc)*(this->_ydot_trajectory[node] - this->_ydot_trajectory[node+1]);
803 state_vector_t ymid_dot = (1.5/this->_h_trajectory(inc))*(this->_y_trajectory[node+1] - this->_y_trajectory[node])
804 - 0.25*(this->_ydot_trajectory[node] + this->_ydot_trajectory[node+1]);
806 control_vector_t u_mid = 0.5*(_u_trajectory[node] + _u_trajectory[node+1]);
808 yTraj.push_back(_y_trajectory[node]);
809 yTraj.push_back(y_mid);
811 ydotTraj.push_back(_ydot_trajectory[node]);
812 ydotTraj.push_back(ymid_dot);
814 h_inc.push_back(_h_trajectory(inc) / 2);
815 h_inc.push_back(_h_trajectory(inc) / 2);
817 phaseId.push_back(node_to_phase_map[node]);
818 phaseId.push_back(node_to_phase_map[node]);
820 uTraj.push_back(_u_trajectory[node]);
821 uTraj.push_back(u_mid);
826 yTraj.push_back(this->_y_trajectory[node+1]);
827 phaseId.push_back(node_to_phase_map[node+1]);
828 ydotTraj.push_back(this->_ydot_trajectory[node+1]);
829 uTraj.push_back(_u_trajectory[node+1]);
831 phase_first_node += this->number_nodes_phase[p];
834 hTraj = Eigen::Map<Eigen::VectorXd>(h_inc.data(),h_inc.size());
838 template<
typename DIMENSIONS>
839 void DTOMethodInterface<DIMENSIONS>::evalObjective(
double *f) {
841 *f = _costFunction->evaluate();
844 template<
typename DIMENSIONS>
845 void DTOMethodInterface<DIMENSIONS>::evalConstraintFct(
846 double* f_constraint_pointer,
847 const int & constraint_pointer_size) {
850 Eigen::Map<Eigen::VectorXd> constraints_fct(
851 f_constraint_pointer, constraint_pointer_size);
853 evaluateDefects(defect_out_);
854 constraints_fct.segment(0, num_defects) = defect_out_;
856 evaluateParametricConstraints(parametric_out_);
857 constraints_fct.segment(num_defects, num_parametric_constraints) = parametric_out_;
859 if(num_user_constraints > 0) {
860 evaluateUserConstraints(user_constraints_out_);
861 constraints_fct.segment(num_defects + num_parametric_constraints, num_user_constraints) = user_constraints_out_;
864 if (_multiphaseproblem) {
866 evaluateGuardConstraints(guard_vector_);
867 constraints_fct.segment(num_defects + num_parametric_constraints + num_user_constraints, num_guards) = guard_vector_;
869 evaluateInterphaseConstraints(interface_vector_);
870 constraints_fct.segment(num_defects+num_parametric_constraints+num_user_constraints+num_guards, num_interphase_constraints) = interface_vector_;
874 template<
class DIMENSIONS>
875 void DTOMethodInterface<DIMENSIONS>::evaluateParametricConstraints(
876 Eigen::VectorXd & parametric_vector) {
878 parametric_vector.setZero();
880 for (
int i = 0; i < n_inc; i++) {
881 parametric_vector(0) += _h_trajectory(i);
885 for (
int i = 0; i < n_inc - 1; i++) {
886 parametric_vector(1 + i) =
887 _h_trajectory(i) - _h_trajectory(i + 1);
892 template<
class DIMENSIONS>
893 void DTOMethodInterface<DIMENSIONS>::evaluateUserConstraints(
894 Eigen::VectorXd & constraints_vector) {
896 constraints_vector.setZero();
899 for (
int k = 0; k < _numberOfNodes; k++) {
901 int loca_num_constraints = this->num_user_constraints_per_node_in_phase[this->node_to_phase_map[k]];
905 Eigen::VectorXd node_constraint = _constraints[this->node_to_phase_map[k]]->evalConstraintsFct(
906 _y_trajectory[k], _u_trajectory[k]);
908 constraints_vector.segment(current_row,
909 loca_num_constraints) = node_constraint;
911 current_row += loca_num_constraints;
915 template<
class DIMENSIONS>
916 void DTOMethodInterface<DIMENSIONS>::evaluateGuardConstraints(
917 Eigen::VectorXd & guardConstraint) {
920 guardConstraint.setZero();
923 for (
int it = 0 ; it < num_phases -1 ; it++ ) {
924 guardConstraint.segment(count,size_guard[it]) = _guards[it]->evalConstraintsFct(_y_trajectory[leftphase_nodes(it)]);
925 count += size_guard[it];
929 template<
class DIMENSIONS>
930 void DTOMethodInterface<DIMENSIONS>::evaluateInterphaseConstraints(
931 Eigen::VectorXd &interphaseVector) {
933 interphaseVector.setZero();
936 for(
int i = 0 ; i < num_phases -1 ; i++ ) {
937 interphaseVector.segment(index,size_interphase_constraint[i]) =
938 _interphase_constraint[i]->evalConstraintsFct(
939 _y_trajectory[leftphase_nodes(i)],_y_trajectory[rightphase_nodes(i)],
940 _u_trajectory[leftphase_nodes(i)],_u_trajectory[rightphase_nodes(i)]);
942 index += size_interphase_constraint[i];
947 template<
class DIMENSIONS>
948 void DTOMethodInterface<DIMENSIONS>::evalSparseJacobianCost(
double* val) {
950 Eigen::Map<Eigen::VectorXd> jacobcost(val,myNLP.lenG_cost);
952 jacobcost = _costFunction->evaluate_gradient();
956 template<
class DIMENSIONS>
957 void DTOMethodInterface<DIMENSIONS>::getStateControlIncrementsTrajectoriesFromDecisionVariables(
958 const Eigen::Map<Eigen::VectorXd> & x_local,
959 state_vector_array_t & y_trajectory,
960 control_vector_array_t & u_trajectory, Eigen::VectorXd & h_trajectory) {
962 h_trajectory = x_local.segment(0, n_inc);
964 y_trajectory.resize(_numberOfNodes);
965 u_trajectory.resize(_numberOfNodes);
967 for (
int k = 0; k < _numberOfNodes; k++) {
968 y_trajectory[k] = x_local.segment<DIMENSIONS::kTotalStates>(y_inds(0,k));
969 u_trajectory[k] = x_local.segment<DIMENSIONS::kTotalControls>(u_inds(0,k));
974 template<
class DIMENSIONS>
975 void DTOMethodInterface<DIMENSIONS>::getStateControlIncrementsTrajectoriesFromDecisionVariables(
976 const Eigen::VectorXd & x_local,
977 state_vector_array_t & y_trajectory,
978 control_vector_array_t & u_trajectory,
979 Eigen::VectorXd & h_trajectory) {
986 h_trajectory = x_local.segment(0, n_inc);
988 y_trajectory.resize(_numberOfNodes);
989 u_trajectory.resize(_numberOfNodes);
991 for (
int k = 0; k < _numberOfNodes; k++) {
993 y_trajectory[k] = x_local.segment
994 < DIMENSIONS::DimensionsSize::STATE_SIZE>(y_inds(0,k));
997 u_trajectory[k] = x_local.segment< DIMENSIONS::DimensionsSize::CONTROL_SIZE>(u_inds(0,k));
1002 template<
class DIMENSIONS>
1003 void DTOMethodInterface<DIMENSIONS>::UpdateDTOTrajectoriesFromDecisionVariables(
1004 const Eigen::Map<Eigen::VectorXd> & x_local) {
1006 _h_trajectory = x_local.segment(0, n_inc);
1008 for (
int k = 0; k < _numberOfNodes; k++) {
1010 _y_trajectory[k] = x_local.segment
1011 < DIMENSIONS::DimensionsSize::STATE_SIZE>(y_inds(0,k));
1012 _u_trajectory[k] = x_local.segment
1013 < DIMENSIONS::DimensionsSize::CONTROL_SIZE>(u_inds(0,k));
1017 template<
class DIMENSIONS>
1018 void DTOMethodInterface<DIMENSIONS>::SetDecisionVariablesFromStateControlIncrementsTrajectories(
1019 Eigen::VectorXd & x_vector,
1020 const state_vector_array_t & y_sol,
1021 const control_vector_array_t & u_sol,
1022 const Eigen::VectorXd & h_sol) {
1024 x_vector.resize(this->myNLP.num_vars);
1026 int solution_nodes = y_sol.size();
1028 if (solution_nodes != _numberOfNodes) {
1029 std::cout <<
"Wrong size of initialization solution!" << std::endl;
1030 std::exit (EXIT_FAILURE);
1033 x_vector.segment(0, n_inc) = h_sol;
1035 int aux = _numberOfNodes * _numStates;
1036 for (
int k = 0; k < _numberOfNodes; k++) {
1037 x_vector.segment< DIMENSIONS::kTotalStates> (n_inc + (k * _numStates)) = y_sol[k];
1038 x_vector.segment< DIMENSIONS::kTotalControls>(n_inc + aux + (k * _numControls)) = u_sol[k];
1043 template<
class DIMENSIONS>
1044 bool DTOMethodInterface<DIMENSIONS>::ValidateDuration() {
1046 if (_trajTimeRange[0] < min_traj_time
1047 || _trajTimeRange[1] < min_traj_time) {
1048 std::cout <<
"Minimum trajectory time is " << min_traj_time
1051 }
else if (_trajTimeRange[1] < _trajTimeRange[0]) {
1053 <<
"please use [t0 tf] to specify range of the trajectory time"
1056 }
else if (_verbose) {
1057 std::cout <<
"[VERBOSE] Time range : ok " << std::endl;
1063 template<
class DIMENSIONS>
1064 bool DTOMethodInterface<DIMENSIONS>::ValidateStateControlBounds() {
1067 if (y_lb.empty() || y_ub.empty()) {
1068 state_vector_t lb, ub;
1069 lb.setConstant(-infy);
1070 ub.setConstant(infy);
1072 SetStateBounds(lb, ub);
1074 if (u_lb.empty() || u_ub.empty()) {
1075 control_vector_t lb, ub;
1076 lb.setConstant(-infy);
1077 ub.setConstant(infy);
1079 SetControlBounds(lb, ub);
1083 state_vector_t error_s;
1084 error_s.setConstant(0);
1085 for (
int i = 0; i < num_phases; i++) {
1086 error_s += y_ub[i] - y_lb[i];
1088 control_vector_t error_c;
1089 error_c.setConstant(0);
1090 for (
int i = 0; i < num_phases; i++) {
1091 error_c += u_ub[i] - u_lb[i];
1095 std::cout <<
" [VERBOSE] states bounds : " << std::endl;
1096 for(
int i = 0; i < num_phases; i++) {
1097 std::cout <<
"ylb : " << y_lb[i].transpose() << std::endl;
1098 std::cout <<
"yub : " << y_ub[i].transpose() << std::endl;
1101 std::cout <<
" [VERBOSE] control bounds: " << std::endl;
1102 for(
int i = 0; i < num_phases; i++) {
1103 std::cout <<
"ulb : " << u_lb[i].transpose() << std::endl;
1104 std::cout <<
"uub : "<< u_ub[i].transpose() << std::endl;
1108 if ((error_s.array() < 0).any() || (error_c.array() < 0).any()) {
1109 std::cout <<
"Lower and Upper bounds are not consistent!" << std::endl;
1117 template<
class DIMENSIONS>
1118 void DTOMethodInterface<DIMENSIONS>::InitializeNLPvector(Eigen::VectorXd & x,
1119 const state_vector_array_t & state_initial,
1120 const control_vector_array_t & control_initial,
1121 const Eigen::VectorXd & h_initial) {
1123 int total_state_indexes = _numberOfNodes * _numStates + n_inc;
1125 x.segment(0, n_inc) = h_initial;
1127 for (
int i = 0; i < _numberOfNodes; i++) {
1128 int node_index = i * _numStates;
1130 for (
int j = 0; j < _numStates; j++) {
1131 x(n_inc + node_index + j) = state_initial[i](j);
1134 node_index = i * _numControls;
1136 for (
int j = 0; j < _numControls; j++) {
1137 x(total_state_indexes + node_index + j) = control_initial[i](j);
1141 std::cout <<
"[VERBOSE] state_initial : " << state_initial << std::endl;
1142 std::cout <<
"[VERBOSE] control_initial : " << control_initial << std::endl;
1143 std::cout <<
"[VERBOSE] h_initial : " << h_initial.transpose() << std::endl;
1144 std::cout <<
"[VERBOSE] x : " << x.transpose() << std::endl;
1148 template <
class DIMENSIONS>
1149 void DTOMethodInterface<DIMENSIONS>::setSparsityJacobianConstraint(){
1152 myNLP.iGfun.setZero();
1153 myNLP.jGvar.setZero();
1155 int constraint_row = 0;
1156 int nnz_per_row = 0;
1163 nnz_per_row = this->_numStates*2 + this->_numControls*2 + 1;
1166 int phase_first_node = 0;
1170 for (
int p = 0 ; p < this->num_phases ; p++) {
1172 for(
int i = 0 ; i < this->number_nodes_phase[p] - 1 ; i++) {
1174 node = phase_first_node + i;
1176 for (
int jj = 0 ; jj < this->_numStates ; jj++) {
1178 myNLP.iGfun.segment(G_index,nnz_per_row) = Eigen::VectorXi::Constant(nnz_per_row, constraint_row);
1181 myNLP.jGvar(G_index) = this->h_inds(inc_index);
1185 myNLP.jGvar.segment(G_index, this->_numStates) = this->y_inds.col(node);
1186 G_index += this->_numStates;
1188 myNLP.jGvar.segment(G_index, this->_numStates) = this->y_inds.col(node+1);
1189 G_index += this->_numStates;
1192 myNLP.jGvar.segment(G_index, this->_numControls) = this->u_inds.col(node);
1193 G_index += this->_numControls;
1195 myNLP.jGvar.segment(G_index, this->_numControls) = this->u_inds.col(node+1);
1196 G_index += this->_numControls;
1205 phase_first_node += this->number_nodes_phase[p];
1208 if (constraint_row != this->num_defects) {
1209 std::cout <<
"Error creating the indexes of constraint Jacobian" << std::endl;
1216 nnz_per_row = this->n_inc;
1218 myNLP.iGfun.segment(G_index,nnz_per_row) = Eigen::VectorXi::Constant(this->n_inc,constraint_row);
1219 myNLP.jGvar.segment(G_index,this->n_inc) = Eigen::VectorXi::LinSpaced(this->n_inc,0,this->n_inc-1);
1221 G_index += this->n_inc;
1226 if (this->_evenTimeIncr) {
1227 for (
int k = 0 ; k < this->n_inc -1 ; k++) {
1228 myNLP.iGfun.segment(G_index,nnz_per_row) = Eigen::VectorXi::Constant(nnz_per_row,constraint_row);
1230 Eigen::VectorXi aux_index(2);
1231 aux_index << this->h_inds(k) , this->h_inds(k+1);
1233 myNLP.jGvar.segment(G_index,nnz_per_row) = aux_index;
1235 G_index+=nnz_per_row;
1241 if (constraint_row != this->num_defects + this->num_parametric_constraints) {
1242 std::cout <<
"Error creating the indexes of Jacobian of constraints" << std::endl;
1250 int constant_offset = 0;
1251 int constraints_before_user_constraints = constraint_row;
1254 for (
int k = 0 ; k < this->_numberOfNodes ; k++) {
1257 Eigen::VectorXi iRow_user_per_node = this->_constraints[node_to_phase_map[k]]->getSparseRow();
1260 Eigen::VectorXi offsetRow = Eigen::VectorXi::Constant(this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]],
1261 constraints_before_user_constraints);
1264 iRow_user_per_node = iRow_user_per_node + offsetRow;
1266 Eigen::VectorXi node_offset = Eigen::VectorXi::Constant(this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]],
1269 constant_offset += this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]];
1271 Eigen::VectorXi iRow_user_updated = iRow_user_per_node + node_offset;
1274 myNLP.iGfun.segment(G_index,this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]]) = iRow_user_updated;
1276 int state_dependent_row = 0;
1277 for (
int state = 0 ; state < this->_numStates ; state++) {
1279 int current_index = G_index + state_dependent_row;
1280 myNLP.jGvar.segment(current_index,this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]]).setConstant(this->y_inds(state,k));
1281 state_dependent_row += this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]];
1283 for (
int control = 0 ; control < this->_numControls ; control++) {
1285 int current_index = G_index + state_dependent_row;
1286 myNLP.jGvar.segment(current_index,this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]]).setConstant(this->u_inds(control,k));
1287 state_dependent_row += this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]];
1290 if ((state_dependent_row) != this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]]) {
1291 std::cout <<
"**total added rows should be equal to num_nonzero_jacobian_user_per_node!" << std::endl;
1292 std::cout <<
"total added rows : " << state_dependent_row << std::endl;
1293 std::cout <<
"num_nonzero_jacobian_user_per_node : " << this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]] << std::endl;
1295 std::exit(EXIT_FAILURE);
1298 G_index+=this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]];
1300 constraint_row+=this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]];
1303 if (constraint_row != this->num_defects + this->num_parametric_constraints + this->num_user_constraints) {
1304 std::cout <<
"*** ERROR: wrong number of nonzero jacobian elements of G [USER - Sparsity]" << std::endl;
1308 if (this->_multiphaseproblem) {
1312 nnz_per_row = this->_numStates;
1317 for (
int i = 0; i < this->num_phases - 1; i++) {
1319 for(
int row = 0 ; row < this->size_guard[i]; row ++) {
1322 myNLP.iGfun.segment(G_index,nnz_per_row).setConstant(constraint_row);
1323 myNLP.jGvar.segment(G_index,nnz_per_row) = y_inds.col(leftphase_nodes(i));
1325 G_index += nnz_per_row;
1344 nnz_per_row = 2 * this->_numStates + 2* this->_numControls;
1348 Eigen::VectorXi x_f_v(_numStates);
1349 Eigen::VectorXi u_f_v(_numControls);
1350 Eigen::VectorXi x_s_v(_numStates);
1351 Eigen::VectorXi u_s_v(_numControls);
1353 for(
int i = 0 ; i < this->num_phases -1; i++) {
1355 x_f_v = y_inds.col(leftphase_nodes(i));
1356 u_f_v = u_inds.col(leftphase_nodes(i));
1358 x_s_v = y_inds.col(rightphase_nodes(i));
1359 u_s_v = u_inds.col(rightphase_nodes(i));
1361 for(
int c_row = 0 ; c_row < this->size_interphase_constraint[i]; c_row++) {
1363 myNLP.iGfun.segment(G_index,nnz_per_row).setConstant(constraint_row);
1365 myNLP.jGvar.segment(G_index,_numStates) = x_f_v;
1366 G_index += _numStates;
1367 myNLP.jGvar.segment(G_index,_numControls) = u_f_v;
1368 G_index += _numControls;
1370 myNLP.jGvar.segment(G_index,_numStates) = x_s_v;
1371 G_index += _numStates;
1372 myNLP.jGvar.segment(G_index,_numControls) = u_s_v;
1373 G_index += _numControls;
1380 if (G_index != myNLP.lenG) {
1381 std::cout <<
"lenG = " << myNLP.lenG <<
"G_index = " << G_index << std::endl;
1382 std::cout <<
"*** ERROR: wrong number of nonzero jacobian elements of G [USER - Sparsity]" << std::endl;
1386 if (this->_verbose) {
1388 <<
"[VERBOSE] lenG : " << myNLP.lenG << std::endl
1389 <<
"[VERBOSE] G_index : " << G_index << std::endl
1390 <<
"[VERBOSE] constraint_row : " << constraint_row << std::endl
1391 <<
"[VERBOSE] jGvar.size() : " << myNLP.jGvar.size() << std::endl
1392 <<
"[VERBOSE] iGfun.size() : " << myNLP.iGfun.size() << std::endl;
This class serves as a base interface for inheriting classes.
Definition: base_method_interface.hpp:60
Base class for TO constraints.
Definition: ConstraintsBase.hpp:46
DTOMethodInterface(std::vector< std::shared_ptr< DynamicsBase< DIMENSIONS > > > dynamics, std::vector< std::shared_ptr< DerivativesBaseDS< DIMENSIONS > > > derivatives, std::shared_ptr< BaseClass::CostFunctionBase< DIMENSIONS > > costFunction, std::vector< std::shared_ptr< BaseClass::ConstraintsBase< DIMENSIONS > > > constraints, Eigen::Vector2d duration, int number_of_nodes, bool methodVerbose)
Construct an instance of the DTOMethodInterface class.
Definition: bmi_implementation.hpp:35