DirectTrajectoryOptimization  v0.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
bmi_implementation.hpp
1 /***********************************************************************************
2 Copyright (c) 2017, Diego Pardo. All rights reserved.
3 
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright notice,
7  this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright notice,
9  this list of conditions and the following disclaimer in the documentation
10  and/or other materials provided with the distribution.
11  * Neither the name of ETH ZURICH nor the names of its contributors may be used
12  to endorse or promote products derived from this software without specific
13  prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
16 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
18 SHALL ETH ZURICH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 ***************************************************************************************/
25 /*
26  * bmi_implementation.hpp
27  *
28  * Created on: Aug 29, 2016
29  * Author: depardo
30  */
31 
32 namespace DirectTrajectoryOptimization {
33 
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,
39  std::vector<std::shared_ptr<BaseClass::ConstraintsBase<DIMENSIONS> > > constraints,
40  Eigen::Vector2d duration, int number_of_nodes, bool methodVerbose) :
41  _dynamics(dynamics),
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) {
50 
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");
59  }
60 
61  num_phases = _dynamics.size();
62 
63  if(num_phases > 1)
64  _multiphaseproblem = true;
65 
66  // not required?
67  _guardVector.clear(); // ToDo: Not use this anymore
68  _interphase_constraint.clear();
69  _guardVectorDerivative.clear(); // ToDo: Not required completely remove this
70  _guards.clear();
71 
72  // Default values for initial and final states/control flags
73  _flagInitialState = Eigen::VectorXi::Zero(_numStates);
74  _flagFinalState = Eigen::VectorXi::Zero(_numStates);
75  _flagInitialControl = Eigen::VectorXi::Zero(_numControls);
76  _flagFinalControl = Eigen::VectorXi::Zero(_numControls);
77 
78  // Default values of initial and final states
79  y_0.setConstant(0);
80  y_f.setConstant(0);
81 
82  if(_verbose){
83  std::cout << "[VERBOSE] num_phases : " << num_phases << std::endl;
84  std::cout << "[VERBOSE] multiphaseproblem : " << _multiphaseproblem << std::endl;
85  getchar();
86  }
87 
88 }
89 
90 /*user interfaces */
91 
92 template<typename DIMENSIONS>
93 void DTOMethodInterface<DIMENSIONS>::SetInitialState(const state_vector_t & y0) {
94  y_0 = y0;
95  _flagInitialState = Eigen::VectorXi::Constant(y0.size(),1);
96  return;
97 }
98 
99 template<typename DIMENSIONS>
100 void DTOMethodInterface<DIMENSIONS>::SetInitialControl(const control_vector_t & u0) {
101  u_0 = u0;
102  _flagInitialControl = Eigen::VectorXi::Constant(u0.size(),1);
103  return;
104 }
105 
106 template<typename DIMENSIONS>
107 void DTOMethodInterface<DIMENSIONS>::SetFinalControl(const control_vector_t & uf) {
108  u_f = uf;
109  _flagFinalControl = Eigen::VectorXi::Constant(uf.size(),1);
110  return;
111 }
112 
113 template<typename DIMENSIONS>
114 void DTOMethodInterface<DIMENSIONS>::SetFinalState(const state_vector_t & yF) {
115  y_f = yF;
116  _flagFinalState = Eigen::VectorXi::Constant(yF.size(),1);
117 
118  return;
119 }
120 
121 template<class DIMENSIONS>
122 void DTOMethodInterface<DIMENSIONS>::getTrajectoryIndexes(Eigen::VectorXi &hs,
123  Eigen::MatrixXi &ys, Eigen::MatrixXi &us) {
124  hs = h_inds;
125  ys = y_inds;
126  us = u_inds;
127 }
128 
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++) {
133  y_lb.push_back(ylb);
134  y_ub.push_back(yub);
135  }
136 }
137 
138 template<class DIMENSIONS>
139 void DTOMethodInterface<DIMENSIONS>::SetStateBounds(
140  const state_vector_array_t & ylb, const state_vector_array_t & yub) {
141 
142  assert(ylb.size() == num_phases);
143  assert(yub.size() == num_phases);
144 
145  y_lb = ylb;
146  y_ub = yub;
147 }
148 
149 template<class DIMENSIONS>
150 void DTOMethodInterface<DIMENSIONS>::SetControlBounds(const control_vector_t & ulb,
151  const control_vector_t & uub) {
152 
153  for (int i = 0; i < num_phases; i++) {
154  u_lb.push_back(ulb);
155  u_ub.push_back(uub);
156  }
157 
158 }
159 
160 template<class DIMENSIONS>
161 void DTOMethodInterface<DIMENSIONS>::SetControlBounds(
162  const control_vector_array_t & ulb, const control_vector_array_t & uub) {
163 
164  assert(ulb.size() == num_phases);
165  assert(uub.size() == num_phases);
166 
167  u_lb = ulb;
168  u_ub = uub;
169 }
170 
171 template<class DIMENSIONS>
172 void DTOMethodInterface<DIMENSIONS>::setTimeIncrementsBounds(
173  const double & h_min, const double & h_max) {
174 
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);
178  }
179  minimum_increment_size = h_min;
180  maximum_increment_size = h_max;
181 }
182 
183 template<class DIMENSIONS>
184 void DTOMethodInterface<DIMENSIONS>::SetFreeFinalState(int state_number) {
185  _flagFinalState(state_number) = 0;
186 }
187 
188 template<typename DIMENSIONS>
189 void DTOMethodInterface<DIMENSIONS>::Initialize() {
190 
191  if (ValidateDuration() == false) {
192  exit(EXIT_FAILURE);
193  }
194 
195  if (ValidateStateControlBounds() == false) {
196  exit(EXIT_FAILURE);
197  }
198 
199  if(_guards.size() != num_phases - 1) {
200  throw std::invalid_argument("Vector of guard functions does not match number of dynamics passed.");
201  }
202 
203  SetSizeOfVariables();
204  SetSizeOfConstraints();
205  SetTOConstraintsBounds();
206  SetTOVariablesBounds();
207  SetupJacobianVariables();
208  Method_specific_initialization();
209 
210  return;
211 }
212 
213 template<typename DIMENSIONS>
214 void DTOMethodInterface<DIMENSIONS>::SetPercentageNodesPerDynamics(Eigen::VectorXd nodeSplit) {
215  // make sure we have same number of dynamics as percentages
216  if (nodeSplit.size() != num_phases) {
217  throw std::invalid_argument("Mismatch between number of splits in percentage vector and number of dynamics.");
218  }
219 
220  // ensure that sum of percentages == 100
221  int total = 0;
222  for (int i = 0; i < nodeSplit.size(); i++) {
223  total += nodeSplit[i];
224  }
225 
226  if (total != 100) {
227  throw std::invalid_argument("Percentage split vector does not sum to 100%.");
228  return;
229  }
230 
231  // ToDo ensure that no single phase has less than _minNodesPerPhase amount of nodes
232 
233  _nodeSplitPercentage = nodeSplit;
234  _nodeSplitSet = true;
235 }
236 
237 template<typename DIMENSIONS>
238 void DTOMethodInterface<DIMENSIONS>::SetNodesPerPhase(const Eigen::VectorXi & nodes) {
239 
240  //check if values are valid
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);
244  }
245 
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;
249  }
250 
251  //for(auto n:number_nodes_phase) {
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);
255  //std::cout << node_to_phase_map[i] << std::endl;
256  }
257 // inc++;
258  }
259 
260  _nodeSplitSet = true;
261  _nodeDistribution = true;
262 }
263 
264 
265 /* Constructing the problem */
266 
267 template<typename DIMENSIONS>
268 void DTOMethodInterface<DIMENSIONS>::SetSizeOfVariables() {
269 
270  // setup size of the problem
271  n_inc = _numberOfNodes - num_phases; /* no increments in between phases */
272  /* n_inc and numberOfNodes are not interchangeable anymore*/
273  int num_vars = _numberOfNodes * (_numStates + _numControls) + n_inc;
274 
275  myNLP.SetVariablesSize(num_vars);
276 
277  //setup dto trajectories size (added for efficiency)
278  _y_trajectory.resize(_numberOfNodes);
279  _ydot_trajectory.resize(_numberOfNodes);
280  _u_trajectory.resize(_numberOfNodes);
281  _h_trajectory.resize(n_inc);
282 
283  // setup decision variables indexes
284  h_inds.resize(n_inc);
285  y_inds.resize(_numStates, _numberOfNodes);
286  u_inds.resize(_numControls, _numberOfNodes);
287 
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);
293  }
294 
295  //ToDo : Remove the interface to determine the No of nodes per phase.
296  // User should request enough number of nodes such that
297  // all phases use the same number of nodes.
298  // if user didn't set the splitting, use even allotments
299  if (!_nodeSplitSet) {
300  int sumAmt = 0;
301  _nodeSplitPercentage.resize(num_phases);
302 
303  for (int j = 0; j < num_phases - 1; j++) {
304  _nodeSplitPercentage[j] = 100.00/static_cast<double>(num_phases);
305  sumAmt += _nodeSplitPercentage[j];
306  }
307  _nodeSplitPercentage[num_phases - 1] = 100 - sumAmt;
308  }
309 
310  // now split up the phases
311  if (!_nodeDistribution) {
312  int startingNode = 0;
313  number_nodes_phase.clear();
314 
315  for (int i = 0; i < num_phases - 1; i++) {
316  std::cout << "_nodeSplitPercentage[i] : " << _nodeSplitPercentage[i] << std::endl;
317  //int numberNodesThisPhase =
318  // static_cast<int>(_nodeSplitPercentage[i])/100.0 * static_cast<double>(_numberOfNodes);
319  int numberNodesThisPhase = _numberOfNodes/num_phases;
320 
321  number_nodes_phase.push_back(numberNodesThisPhase);
322  for (int j = startingNode; j < numberNodesThisPhase + startingNode; j++) {
323  node_to_phase_map.push_back(i);
324  }
325  startingNode += numberNodesThisPhase;
326  }
327  // Last phase includes the remaining nodes
328  number_nodes_phase.push_back(_numberOfNodes-startingNode);
329  // ...and the corresponding node to phase
330  for (int j = startingNode; j < _numberOfNodes; j++) {
331  node_to_phase_map.push_back(num_phases - 1);
332  }
333  }
334 
335  assert(node_to_phase_map.size() == _numberOfNodes);
336 
337  // assigning the indexes
338  for (int i = 0; i < n_inc; i++)
339  h_inds(i) = i;
340 
341  int initial_index_y = n_inc;
342  int initial_index_u = n_inc + (_numberOfNodes * _numStates);
343 
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;
347  }
348  for (int control = 0; control < _numControls; control++) {
349  u_inds(control, node) = initial_index_u + node * _numControls + control;
350  }
351  }
352 
353  if(_multiphaseproblem) {
354  int first_node_this_phase = 0;
355  // nodes indexes at the boundary of the phases
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];
360  }
361  }
362 
363  increments_solution.resize(n_inc);
364  states_solution.resize(_numStates, _numberOfNodes);
365  controls_solution.resize(_numControls, _numberOfNodes);
366 
367  // default to -inf
368  increments_solution.setConstant(-infy);
369  states_solution.setConstant(-infy);
370  controls_solution.setConstant(-infy);
371 
372  if (_verbose) {
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;
381 
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;
386  }
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;
389  }
390  std::getchar();
391 
392  std::cout << "[VERBOSE] leftphase_nodes : " << leftphase_nodes.transpose() << std::endl;
393  std::cout << "[VERBOSE] rightphase_nodes: " << rightphase_nodes.transpose() << std::endl;
394  std::getchar();
395  }
396 
397  return;
398 }
399 
400 template<typename DIMENSIONS>
401 void DTOMethodInterface<DIMENSIONS>::SetSizeOfConstraints() {
402 
403  // defects bounds
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();
409 
410  // total time bounds
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();
416 
417  // user constraint bounds
418  num_user_constraints_per_node_in_phase.clear(); /*TO Problem variable*/
419  num_user_constraints = 0; /* NLP variable */
420 
421  for (int k = 0 ; k < this->num_phases ; k++) {
422 
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);
425 
426  //adding up the number of user constraints per phase projected to the nodes
427  num_user_constraints += num_user_constraints_per_phase * this->number_nodes_phase[k];
428  }
429  user_constraints_out_.resize(num_user_constraints);
430  user_constraints_out_.setZero();
431 
432  userConstraints_lb.resize(num_user_constraints);
433  userConstraints_ub.resize(num_user_constraints);
434 
435  // guard function bounds
436  if (_multiphaseproblem) {
437 
438  // guards are NOT necessarily scalar functions but user-defined
439  // each constraint is going to be evaluated only in 1 point!
440  for( int i = 0 ; i < num_phases - 1 ; i++) {
441  size_guard[i] = this->_guards[i]->GetSize();
442  num_guards += size_guard[i];
443  }
444  //num_guards = (num_phases - 1) * 2; // each guard should be evaluated in two nodes
445  guard_lb.resize(num_guards);
446  guard_ub.resize(num_guards);
447 
448  // interphase constraints are user-defined size (maybe state-size)
449  // each neighbor state has half interphase constraint
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];
453  }
454  interphase_lb.resize(num_interphase_constraints);
455  interphase_ub.resize(num_interphase_constraints);
456 
457  guard_vector_.resize(num_guards);
458  interface_vector_.resize(num_interphase_constraints);
459 
460  guard_vector_.setZero();
461  interface_vector_.setZero();
462  } else {
463  num_guards = 0;
464  }
465 
466  int num_F = num_defects + num_parametric_constraints + num_user_constraints + num_guards + num_interphase_constraints;
467 
468  myNLP.SetConstraintsSize(num_F);
469 
470  if (_verbose) {
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;
476  std::getchar();
477  }
478 }
479 
480 template<typename DIMENSIONS>
481 void DTOMethodInterface<DIMENSIONS>::SetTOConstraintsBounds() {
482 
483  // defects
484  defects_lb.setConstant(0);
485  defects_ub.setConstant(0);
486 
487  // parametric constraints
488  parametricConstraints_lb(0) = _trajTimeRange(0);
489  parametricConstraints_ub(0) = _trajTimeRange(1);
490 
491  if (_evenTimeIncr) {
492  parametricConstraints_lb.segment(1, n_inc - 1).setConstant(0);
493  parametricConstraints_ub.segment(1, n_inc - 1).setConstant(0);
494  }
495 
496  // user constraints
497  int aux_index = 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;
505  }
506 
507  // guard and interphase
508  if (_multiphaseproblem) {
509  int first_index = 0;
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];
515 
516  //left point
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];
520  }
521  }
522 
523  Eigen::VectorXd Flb,Fub;
524 
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;
530  } else {
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;
535  }
536 
537  myNLP.SetConstraintsBounds(Flb,Fub);
538 
539  if (_verbose) {
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;
548  std::getchar();
549  }
550 
551 }
552 
553 template<typename DIMENSIONS>
554 void DTOMethodInterface<DIMENSIONS>::SetTOVariablesBounds() {
555 
556  Eigen::VectorXd x_lb(myNLP.GetNumVars());
557  Eigen::VectorXd x_ub(myNLP.GetNumVars());
558 
559  // Bounds on Decision variables
560  x_lb.setConstant(-infy);
561  x_ub.setConstant(infy);
562 
563  // time increment bounds
564  x_lb.segment(0, n_inc).setConstant(minimum_increment_size);
565  x_ub.segment(0, n_inc).setConstant(maximum_increment_size);
566 
567  // state bounds
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);
573  }
574  }
575 
576  // control bounds
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);
582  }
583  }
584 
585  // initial and final STATES values if required
586  for (int i = 0; i < _numStates; i++) {
587 
588  if (_flagInitialState(i)) {
589  x_lb(y_inds(i, 0)) = y_0(i);
590  x_ub(y_inds(i, 0)) = y_0(i);
591  }
592 
593  if (_flagFinalState(i)) {
594  //ToDo : Add relaxation flag
595  int last_node = _numberOfNodes - 1;
596  x_lb(y_inds(i, last_node)) = y_f(i) - 0.01; //- (0.05 * fabs(y_f(i)));
597  x_ub(y_inds(i, last_node)) = y_f(i) + 0.01; //(0.05 * fabs(y_f(i)));
598  }
599  }
600 
601  // initial and final CONTROL values if required
602  for (int i = 0 ; i < _numControls ; i++) {
603 
604  if (_flagInitialControl(i)) {
605  x_lb(u_inds(i,0)) = u_0(i);
606  x_ub(u_inds(i,0)) = u_0(i);
607  }
608  if (_flagFinalControl(i)) {
609  int last_node = _numberOfNodes - 1;
610  x_lb(u_inds(i,last_node)) = u_f(i); // add relaxation
611  x_ub(u_inds(i,last_node)) = u_f(i); // add relaxation
612  }
613  }
614 
615  myNLP.SetVariablesBounds(x_lb,x_ub);
616 }
617 
618 template<typename DIMENSIONS>
619 void DTOMethodInterface<DIMENSIONS>::SetupJacobianVariables() {
620 
621  setNLPnnzConstraintJacobian();
622 
623  setSparsityJacobianConstraint();
624 
625  setSparsityJacobianCost();
626 }
627 
628 template<typename DIMENSIONS>
629 void DTOMethodInterface<DIMENSIONS>::setNLPnnzConstraintJacobian() {
630 
631  int nnz_jac_g = 0;
632 
633  // Nnz of defect constraints
634  // each defect is dependent on 5 variables: h, y_k, y_kp1, u_k, u_kp1,
635  int nnz_defects = this->num_defects * (1 + 2 * this->_numStates + 2 * this->_numControls);
636  nnz_jac_g += nnz_defects;
637 
638  // Nnz of parametric constraints
639  // time constraint depends on all increments
640  int nnz_parametric_constraints = this->n_inc;
641 
642  if (this->_evenTimeIncr) {
643  //each equality-increment constraint depends on two increments
644  nnz_parametric_constraints += 2 * (this->n_inc - 1);
645  }
646  nnz_jac_g += nnz_parametric_constraints;
647 
648  // Nnz of USER constraints
649  this->nnz_user_constraints = this->getNumNonZeroUserJacobian();
650  nnz_jac_g += this->nnz_user_constraints;
651 
652  // Nnz of GUARD 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;
658 
659  nnz_interphase_constraints= this->getNumNonZeroInterphaseJacobian();
660  nnz_jac_g += nnz_interphase_constraints;
661  }
662 
663  myNLP.SetGSize(nnz_jac_g);
664 
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;
672  std::getchar();
673  }
674 }
675 
676 template<typename DIMENSIONS>
677 int DTOMethodInterface<DIMENSIONS>::getNumNonZeroUserJacobian() {
678 
679  int user_non_zero_G = 0;
680 
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;
687  }
688 
689  return user_non_zero_G;
690 }
691 
692 template<typename DIMENSIONS>
693 int DTOMethodInterface<DIMENSIONS>::getNumNonZeroGuardFunctionJacobian() {
694 
695  // guard functions only depend on state vectors at particular locations
696  // and are scalar functions
697  int guard_nonZeroElements = num_guards * _numStates;
698 
699  return guard_nonZeroElements;
700 }
701 
702 template<typename DIMENSIONS>
703 int DTOMethodInterface<DIMENSIONS>::getNumNonZeroInterphaseJacobian() {
704 
705  int nnz_interphase = 0;
706  for (int i = 0 ; i < this->num_phases - 1; i++) {
707  nnz_interphase += _interphase_constraint[i]->GetNnzJacobian();
708  }
709  return nnz_interphase;
710 }
711 
712 template<class DIMENSIONS>
713 void DTOMethodInterface<DIMENSIONS>::setSparsityJacobianCost() {
714 
715  // states and controls at N nodes, plus increments (N-1)
716  setNLPnnzCostFunctionJacobian();
717 
718  int g_index = 0;
719  int inc_index = 0;
720  int index_of_fist_node = 0;
721 
722  // sparsity given all the nodes but last one
723 
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);
727  g_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;
732  inc_index++;
733  }
734  index_of_fist_node +=number_nodes_phase[p];
735 
736  }
737  //sparsity of the last node of the trajectory
738  myNLP.jG_cost.segment(g_index,this->_numStates) = y_inds.col(index_of_fist_node-1);
739  g_index += this->_numStates;
740 // myNLP.jG_cost.segment(g_index,this->_numControls) = u_inds.col(index_of_fist_node-1);
741 // g_index += this->_numControls;
742 
743 
744 
745  if (_verbose) {
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;
749  std::getchar();
750  }
751 }
752 
753 template<typename DIMENSIONS>
754 void DTOMethodInterface<DIMENSIONS>::setNLPnnzCostFunctionJacobian() {
755 
756  //ToDo : Read this from _costFunction, but it depends on all states, controls and increments
757  int cost_nonZeroElements = n_inc * (_numStates + _numControls) + _numStates + n_inc;
758  // (_numberOfNodes - (this->num_phases-1)) * (_numStates + _numControls) + n_inc;
759 
760  myNLP.setGcostSize(cost_nonZeroElements);
761 }
762 
763 /* System interface */
764 
765 template<typename DIMENSIONS>
766 void DTOMethodInterface<DIMENSIONS>::UpdateDecisionVariables(const double* x) {
767 
768  // mapping decision variables
769  const Eigen::Map<Eigen::VectorXd> x_local(
770  const_cast<double *>(x), myNLP.num_vars);
771 
772  UpdateDTOTrajectoriesFromDecisionVariables(x_local);
773 
774  //update all the dynamics and other structures before continuing
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]);
777  }
778 
779  _costFunction->setCurrentTrajectory(
780  _y_trajectory, _u_trajectory, _h_trajectory, leftphase_nodes);
781 }
782 
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 {
787 
788  int inc = 0;
789  int node = 0;
790  int phase_first_node = 0;
791  std::vector<double> h_inc;
792 
793  for(int p = 0; p < this->num_phases ; p++ ){
794 
795  for(int n = 0 ; n < this->number_nodes_phase[p] - 1 ; n++) {
796 
797  node = phase_first_node + n;
798 
799  //compute the center point and its derivative
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]);
802 
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]);
805 
806  control_vector_t u_mid = 0.5*(_u_trajectory[node] + _u_trajectory[node+1]);
807 
808  yTraj.push_back(_y_trajectory[node]);
809  yTraj.push_back(y_mid);
810 
811  ydotTraj.push_back(_ydot_trajectory[node]);
812  ydotTraj.push_back(ymid_dot);
813 
814  h_inc.push_back(_h_trajectory(inc) / 2);
815  h_inc.push_back(_h_trajectory(inc) / 2);
816 
817  phaseId.push_back(node_to_phase_map[node]);
818  phaseId.push_back(node_to_phase_map[node]);
819 
820  uTraj.push_back(_u_trajectory[node]);
821  uTraj.push_back(u_mid);
822 
823  inc++;
824  }
825 
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]);
830 
831  phase_first_node += this->number_nodes_phase[p];
832  }
833 
834  hTraj = Eigen::Map<Eigen::VectorXd>(h_inc.data(),h_inc.size());
835 
836 }
837 
838 template<typename DIMENSIONS>
839 void DTOMethodInterface<DIMENSIONS>::evalObjective(double *f) {
840 
841  *f = _costFunction->evaluate();
842 }
843 
844 template<typename DIMENSIONS>
845 void DTOMethodInterface<DIMENSIONS>::evalConstraintFct(
846  double* f_constraint_pointer,
847  const int & constraint_pointer_size) {
848 
849  // mapping the output
850  Eigen::Map<Eigen::VectorXd> constraints_fct(
851  f_constraint_pointer, constraint_pointer_size);
852 
853  evaluateDefects(defect_out_);
854  constraints_fct.segment(0, num_defects) = defect_out_;
855 
856  evaluateParametricConstraints(parametric_out_);
857  constraints_fct.segment(num_defects, num_parametric_constraints) = parametric_out_;
858 
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_;
862  }
863 
864  if (_multiphaseproblem) {
865 
866  evaluateGuardConstraints(guard_vector_);
867  constraints_fct.segment(num_defects + num_parametric_constraints + num_user_constraints, num_guards) = guard_vector_;
868 
869  evaluateInterphaseConstraints(interface_vector_);
870  constraints_fct.segment(num_defects+num_parametric_constraints+num_user_constraints+num_guards, num_interphase_constraints) = interface_vector_;
871  }
872 }
873 
874 template<class DIMENSIONS>
875 void DTOMethodInterface<DIMENSIONS>::evaluateParametricConstraints(
876  Eigen::VectorXd & parametric_vector) {
877 
878  parametric_vector.setZero();
879 
880  for (int i = 0; i < n_inc; i++) {
881  parametric_vector(0) += _h_trajectory(i);
882  }
883 
884  if (_evenTimeIncr) {
885  for (int i = 0; i < n_inc - 1; i++) {
886  parametric_vector(1 + i) =
887  _h_trajectory(i) - _h_trajectory(i + 1);
888  }
889  }
890 }
891 
892 template<class DIMENSIONS>
893 void DTOMethodInterface<DIMENSIONS>::evaluateUserConstraints(
894  Eigen::VectorXd & constraints_vector) {
895 
896  constraints_vector.setZero();
897 
898  int current_row = 0;
899  for (int k = 0; k < _numberOfNodes; k++) {
900 
901  int loca_num_constraints = this->num_user_constraints_per_node_in_phase[this->node_to_phase_map[k]];
902 
903  // at each point constraints depends on the whole trajectory
904  // ToDo : Add parameters
905  Eigen::VectorXd node_constraint = _constraints[this->node_to_phase_map[k]]->evalConstraintsFct(
906  _y_trajectory[k], _u_trajectory[k]);
907 
908  constraints_vector.segment(current_row,
909  loca_num_constraints) = node_constraint;
910 
911  current_row += loca_num_constraints;
912  }
913 }
914 
915 template<class DIMENSIONS>
916 void DTOMethodInterface<DIMENSIONS>::evaluateGuardConstraints(
917  Eigen::VectorXd & guardConstraint) {
918 
919  //guards only occur at the "leftphase nodes"
920  guardConstraint.setZero();
921 
922  int count = 0;
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];
926  }
927 }
928 
929 template<class DIMENSIONS>
930 void DTOMethodInterface<DIMENSIONS>::evaluateInterphaseConstraints(
931  Eigen::VectorXd &interphaseVector) {
932 
933  interphaseVector.setZero();
934 
935  int index = 0;
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)]);
941 
942  index += size_interphase_constraint[i];
943  }
944 
945 }
946 
947 template<class DIMENSIONS>
948 void DTOMethodInterface<DIMENSIONS>::evalSparseJacobianCost(double* val) {
949 
950  Eigen::Map<Eigen::VectorXd> jacobcost(val,myNLP.lenG_cost);
951 
952  jacobcost = _costFunction->evaluate_gradient();
953 }
954 
955 //TODO : Deprecated I dont think we need this anymore
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) {
961 
962  h_trajectory = x_local.segment(0, n_inc);
963 
964  y_trajectory.resize(_numberOfNodes);
965  u_trajectory.resize(_numberOfNodes);
966 
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));
970  }
971 }
972 
973 //TODO : Deprecated I dont think we need this anymore
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) {
980 
981 
982  // To Do: We know these sizes from the very beginning!!! use
983  // member variables instead
984  //h_trajectory.resize(n_inc);
985 
986  h_trajectory = x_local.segment(0, n_inc);
987 
988  y_trajectory.resize(_numberOfNodes);
989  u_trajectory.resize(_numberOfNodes);
990 
991  for (int k = 0; k < _numberOfNodes; k++) {
992 
993  y_trajectory[k] = x_local.segment
994  < DIMENSIONS::DimensionsSize::STATE_SIZE>(y_inds(0,k));
995  //> (n_inc + (k * _numStates));
996 
997  u_trajectory[k] = x_local.segment< DIMENSIONS::DimensionsSize::CONTROL_SIZE>(u_inds(0,k));
998  //> (n_inc + aux + (k * _numControls));
999  }
1000 }
1001 
1002 template<class DIMENSIONS>
1003 void DTOMethodInterface<DIMENSIONS>::UpdateDTOTrajectoriesFromDecisionVariables(
1004  const Eigen::Map<Eigen::VectorXd> & x_local) {
1005 
1006  _h_trajectory = x_local.segment(0, n_inc);
1007 
1008  for (int k = 0; k < _numberOfNodes; k++) {
1009 
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));
1014  }
1015 }
1016 
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) {
1023 
1024  x_vector.resize(this->myNLP.num_vars);
1025 
1026  int solution_nodes = y_sol.size();
1027 
1028  if (solution_nodes != _numberOfNodes) {
1029  std::cout << "Wrong size of initialization solution!" << std::endl;
1030  std::exit (EXIT_FAILURE);
1031  }
1032 
1033  x_vector.segment(0, n_inc) = h_sol;
1034 
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];
1039  }
1040 }
1041 
1042 // utilities
1043 template<class DIMENSIONS>
1044 bool DTOMethodInterface<DIMENSIONS>::ValidateDuration() {
1045 
1046  if (_trajTimeRange[0] < min_traj_time
1047  || _trajTimeRange[1] < min_traj_time) {
1048  std::cout << "Minimum trajectory time is " << min_traj_time
1049  << std::endl;
1050  return false;
1051  } else if (_trajTimeRange[1] < _trajTimeRange[0]) {
1052  std::cout
1053  << "please use [t0 tf] to specify range of the trajectory time"
1054  << std::endl;
1055  return false;
1056  } else if (_verbose) {
1057  std::cout << "[VERBOSE] Time range : ok " << std::endl;
1058  }
1059 
1060  return true;
1061 }
1062 
1063 template<class DIMENSIONS>
1064 bool DTOMethodInterface<DIMENSIONS>::ValidateStateControlBounds() {
1065 
1066  // if not provived set to infinity
1067  if (y_lb.empty() || y_ub.empty()) {
1068  state_vector_t lb, ub;
1069  lb.setConstant(-infy);
1070  ub.setConstant(infy);
1071 
1072  SetStateBounds(lb, ub);
1073  }
1074  if (u_lb.empty() || u_ub.empty()) {
1075  control_vector_t lb, ub;
1076  lb.setConstant(-infy);
1077  ub.setConstant(infy);
1078 
1079  SetControlBounds(lb, ub);
1080  }
1081 
1082  // upper bounds should be greater than lower bounds
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];
1087  }
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];
1092  }
1093 
1094  if (_verbose) {
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;
1099  }
1100 
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;
1105  }
1106  }
1107 
1108  if ((error_s.array() < 0).any() || (error_c.array() < 0).any()) {
1109  std::cout << "Lower and Upper bounds are not consistent!" << std::endl;
1110  return false;
1111  }
1112 
1113  return true;
1114 }
1115 
1116 /* check w.r.t initialization of solver */
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) {
1122 
1123  int total_state_indexes = _numberOfNodes * _numStates + n_inc;
1124 
1125  x.segment(0, n_inc) = h_initial;
1126 
1127  for (int i = 0; i < _numberOfNodes; i++) {
1128  int node_index = i * _numStates;
1129 
1130  for (int j = 0; j < _numStates; j++) {
1131  x(n_inc + node_index + j) = state_initial[i](j);
1132  }
1133 
1134  node_index = i * _numControls;
1135 
1136  for (int j = 0; j < _numControls; j++) {
1137  x(total_state_indexes + node_index + j) = control_initial[i](j);
1138  }
1139  }
1140  if (_verbose) {
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;
1145  }
1146 }
1147 
1148 template <class DIMENSIONS>
1149 void DTOMethodInterface<DIMENSIONS>::setSparsityJacobianConstraint(){
1150 
1151  // At this point these vectors should be at the right size
1152  myNLP.iGfun.setZero();
1153  myNLP.jGvar.setZero();
1154 
1155  int constraint_row = 0;
1156  int nnz_per_row = 0;
1157  int G_index = 0; // current index of the sparsity structure
1158 
1159  /* Indexes of defects */
1160  // each (this->_numStates-dimensional) defect is dependent on h_k, y_k, y_kp1, u_k, u_kp1 ...
1161  // this is for the "worst" case, when every 1-dim defect is dependent on the whole state and constraint vector y_k, y_kp1, u_k, u_kp1 and h
1162 
1163  nnz_per_row = this->_numStates*2 + this->_numControls*2 + 1; //+1 because of h
1164 
1165  int inc_index = 0;
1166  int phase_first_node = 0;
1167  int node = 0;
1168 
1169  // scanning by phase
1170  for (int p = 0 ; p < this->num_phases ; p++) {
1171  // all the v-defects in this phase
1172  for(int i = 0 ; i < this->number_nodes_phase[p] - 1 ; i++) {
1173 
1174  node = phase_first_node + i;
1175  // all the states in this v-defect
1176  for (int jj = 0 ; jj < this->_numStates ; jj++) {
1177 
1178  myNLP.iGfun.segment(G_index,nnz_per_row) = Eigen::VectorXi::Constant(nnz_per_row, constraint_row);
1179 
1180  //w.r.t h
1181  myNLP.jGvar(G_index) = this->h_inds(inc_index);
1182  G_index += 1;
1183 
1184  //w.r.t y_k
1185  myNLP.jGvar.segment(G_index, this->_numStates) = this->y_inds.col(node);
1186  G_index += this->_numStates;
1187  //w.r.t y_kp1s
1188  myNLP.jGvar.segment(G_index, this->_numStates) = this->y_inds.col(node+1);
1189  G_index += this->_numStates;
1190 
1191  //w.r.t u_k
1192  myNLP.jGvar.segment(G_index, this->_numControls) = this->u_inds.col(node);
1193  G_index += this->_numControls;
1194  //w.r.t u_kp1
1195  myNLP.jGvar.segment(G_index, this->_numControls) = this->u_inds.col(node+1);
1196  G_index += this->_numControls;
1197 
1198  constraint_row++;
1199  }
1200  // next v-defect, i.e., new h_index
1201  inc_index++;
1202  }
1203 
1204  // new phase, i.e., new first node (skipping defect between last node of this phase and next node)
1205  phase_first_node += this->number_nodes_phase[p];
1206  }
1207 
1208  if (constraint_row != this->num_defects) {
1209  std::cout << "Error creating the indexes of constraint Jacobian" << std::endl;
1210  exit(EXIT_FAILURE);
1211  }
1212 
1213  /* Indexes of parametric constraints */
1214 
1215  // Time constraint
1216  nnz_per_row = this->n_inc;
1217 
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);
1220 
1221  G_index += this->n_inc;
1222  constraint_row++;
1223 
1224  // increments constraint
1225  nnz_per_row = 2;
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);
1229 
1230  Eigen::VectorXi aux_index(2);
1231  aux_index << this->h_inds(k) , this->h_inds(k+1);
1232 
1233  myNLP.jGvar.segment(G_index,nnz_per_row) = aux_index;
1234 
1235  G_index+=nnz_per_row;
1236 
1237  constraint_row++;
1238  }
1239  }
1240 
1241  if (constraint_row != this->num_defects + this->num_parametric_constraints) {
1242  std::cout << "Error creating the indexes of Jacobian of constraints" << std::endl;
1243  exit(EXIT_FAILURE);
1244  }
1245 
1246  // Indexes of User Constraints
1247 
1248  //ToDO: assuming user constraints depend on ALL states and controls but NOT on h
1249 
1250  int constant_offset = 0;
1251  int constraints_before_user_constraints = constraint_row;
1252 
1253  // arrange iGfun and jGvar for each node
1254  for (int k = 0 ; k < this->_numberOfNodes ; k++) {
1255 
1256  // relative user's constraint rows (e.g, 192)
1257  Eigen::VectorXi iRow_user_per_node = this->_constraints[node_to_phase_map[k]]->getSparseRow();
1258 
1259  // auxiliary vector for adding offset
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);
1262 
1263  // adding offset,
1264  iRow_user_per_node = iRow_user_per_node + offsetRow;
1265 
1266  Eigen::VectorXi node_offset = Eigen::VectorXi::Constant(this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]],
1267  constant_offset);
1268 
1269  constant_offset += this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]];
1270 
1271  Eigen::VectorXi iRow_user_updated = iRow_user_per_node + node_offset;
1272 
1273  //the number of the constraints changes at each node
1274  myNLP.iGfun.segment(G_index,this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]]) = iRow_user_updated;
1275 
1276  int state_dependent_row = 0;
1277  for (int state = 0 ; state < this->_numStates ; state++) {
1278  // Repetition of the States
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]];
1282  }
1283  for (int control = 0 ; control < this->_numControls ; control++) {
1284  // Repetition of the Controls
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]];
1288  }
1289 
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;
1294 
1295  std::exit(EXIT_FAILURE);
1296  }
1297 
1298  G_index+=this->num_nonzero_jacobian_user_per_node_in_phase[node_to_phase_map[k]];
1299 
1300  constraint_row+=this->num_user_constraints_per_node_in_phase[node_to_phase_map[k]];
1301  }
1302 
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;
1305  exit(EXIT_FAILURE);
1306  }
1307 
1308  if (this->_multiphaseproblem) {
1309 
1310  /* Guard Constraints */
1311  // each guard constraint depends on the states at the given point
1312  nnz_per_row = this->_numStates;
1313  //Eigen::VectorXi jCol_guard(nnz_per_row);
1314 
1315  // at each phase border there are two guards constraints
1316  // now the guard is used-defined size
1317  for (int i = 0; i < this->num_phases - 1; i++) {
1318 
1319  for(int row = 0 ; row < this->size_guard[i]; row ++) {
1320 
1321  // left side
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));
1324  constraint_row +=1;
1325  G_index += nnz_per_row;
1326  }
1327 
1328 // for(int row = 0 ; row < this->size_guard[i]; row ++) {
1329 //
1330 // //right side (consider removing)
1331 // myNLP.iGfun.segment(G_index,nnz_per_row).setConstant(constraint_row);
1332 // myNLP.jGvar.segment(G_index,nnz_per_row) = y_inds.col(rightphase_nodes(i));
1333 // constraint_row += 1;
1334 // G_index += nnz_per_row;
1335 //
1336 // }
1337  }
1338 
1339  /* Interphase constraints */
1340 
1341  // at each phase border there is one vector-size 'InterPhase' constraint
1342  // the size of the InterPhase constraint is user-provided
1343  // each constraint depends on the state and control of k and k+1
1344  nnz_per_row = 2 * this->_numStates + 2* this->_numControls;
1345 
1346  // NOW assuming Interphase constraints depend on states and controls!
1347 
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);
1352 
1353  for(int i = 0 ; i < this->num_phases -1; i++) {
1354 
1355  x_f_v = y_inds.col(leftphase_nodes(i));
1356  u_f_v = u_inds.col(leftphase_nodes(i));
1357 
1358  x_s_v = y_inds.col(rightphase_nodes(i));
1359  u_s_v = u_inds.col(rightphase_nodes(i));
1360 
1361  for(int c_row = 0 ; c_row < this->size_interphase_constraint[i]; c_row++) {
1362 
1363  myNLP.iGfun.segment(G_index,nnz_per_row).setConstant(constraint_row);
1364 
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;
1369 
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;
1374 
1375  constraint_row++;
1376  }
1377  }
1378  }
1379 
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;
1383  exit(EXIT_FAILURE);
1384  }
1385 
1386  if (this->_verbose) {
1387  std::cout
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;
1393  getchar();
1394  }
1395 }
1396 
1397 } // namespace DirectTrajectoryOptimization
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