structured_optimal_control_problem.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement
4  *
5  * Copyright (c) 2020,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  *
22  * Authors: Christoph Rösmann
23  *********************************************************************/
24 
26 
28 
30 
36 
37 #include <memory>
38 
39 namespace corbo {
40 
42 
45  : _grid(grid), _optim_prob(optim_prob), _dynamics(dynamics), _solver(solver)
46 {
47  _optim_prob->setGraph(_edges, _grid);
48 }
49 
51 
52 bool StructuredOptimalControlProblem::providesFutureStates() const { return _grid ? _grid->providesStateTrajectory() : false; }
53 
55 {
56  if (!_optim_prob)
57  {
58  PRINT_ERROR("StructuredOptimalControlProblem::initialize(): no hyper-graph optimization problem strategy specified.");
59  return false;
60  }
61  if (!_solver || !_solver->initialize(_optim_prob.get()))
62  {
63  PRINT_ERROR("StructuredOptimalControlProblem::initialize(): no solver specified or solver initialization failed.");
64  return false;
65  }
66 
67  if (_u_prev.size() == 0)
68  {
69  // Default setting for previous control and dt if nothing specified
70  _u_prev.setZero(_dynamics->getInputDimension());
71  _u_prev_dt = _grid->getInitialDt();
72  }
73 
74  return true;
75 }
76 
78  ReferenceTrajectoryInterface* sref, const Time& t, bool new_run, SignalTargetInterface* signal_target,
79  ReferenceTrajectoryInterface* xinit, ReferenceTrajectoryInterface* uinit, const std::string& ns)
80 {
81  if (!_grid)
82  {
83  PRINT_ERROR("StructuredOptimalControlProblem::compute(): no discretization grid specified.");
84  return false;
85  }
86 
87  if (!_dynamics)
88  {
89  PRINT_ERROR("StructuredOptimalControlProblem::compute(): no system dynamics model specified.");
90  return false;
91  }
92  if (!_optim_prob)
93  {
94  PRINT_ERROR("StructuredOptimalControlProblem::compute(): no hyper-graph optimization strategy specified.");
95  return false;
96  }
97  if (!_solver)
98  {
99  PRINT_ERROR("StructuredOptimalControlProblem::compute(): no solver specified.");
100  return false;
101  }
103  {
104  PRINT_WARNING("StructuredOptimalControlProblem::compute(): no cost function specified.");
105  }
106 
107  bool success = false;
108 
109  // reset ts caches
110  _ts_x_cache.reset();
111  _ts_u_cache.reset();
112  _ts_dt_cache = 0;
113 
114  if (_statistics) _statistics->clear();
115 
116  Time t1 = Time::now();
117 
118  GridUpdateResult grid_udpate_result =
119  _grid->update(x, xref, uref, _functions, *_edges, _dynamics, new_run, t, sref, &_u_prev, _u_prev_dt, xinit, uinit);
120 
121  if (grid_udpate_result.vertices_updated)
122  {
123  _optim_prob->precomputeVertexQuantities();
124  }
125  if (grid_udpate_result.updated())
126  {
127  _optim_prob->precomputeEdgeQuantities();
128  }
129 
130  assert(_optim_prob->getGraph().checkGraphConsistency());
131 
132  Time t2 = Time::now();
133 
134  SolverStatus status = _solver->solve(*_optim_prob, grid_udpate_result.updated(), new_run, &_objective_value);
135  if (status == SolverStatus::Converged || status == SolverStatus::EarlyTerminated)
136  success = true;
137  else if (_increase_n_if_infeas)
138  {
139  PRINT_WARNING("infeasible solution found. Increasing n for next ocp iteration.");
140  _grid->setN(_grid->getN() + 1);
141  }
142 
143  Time t3 = Time::now();
144 
145  if (_statistics)
146  {
147  _statistics->preparation_time = t2 - t1;
148  _statistics->solving_time = t3 - t2;
149  }
150 
151  // PRINT_INFO("CPU time of only the solving phase: " << (t2 - t1).toSec() * 1000.0 << " ms.");
152 
153  return success;
154 }
155 
157 {
158  if (!_grid) return false;
159  if (_grid->getFirstControlInput(u0))
160  return true;
161  else
162  return false;
163 }
164 
165 void StructuredOptimalControlProblem::setBounds(const Eigen::VectorXd& x_lb, const Eigen::VectorXd& x_ub, const Eigen::VectorXd& u_lb,
166  const Eigen::VectorXd& u_ub)
167 {
168  _functions.x_lb = x_lb;
169  _functions.x_ub = x_ub;
170  _functions.u_lb = u_lb;
171  _functions.u_ub = u_ub;
172  // TODO(roesmann): ocp modified?! we just changed bounds and not dimensions
173 }
174 
175 void StructuredOptimalControlProblem::setStateBounds(const Eigen::VectorXd& x_lb, const Eigen::VectorXd& x_ub)
176 {
177  _functions.x_lb = x_lb;
178  _functions.x_ub = x_ub;
179  // TODO(roesmann): ocp modified?! we just changed bounds and not dimensions
180 }
181 
182 void StructuredOptimalControlProblem::setControlBounds(const Eigen::VectorXd& u_lb, const Eigen::VectorXd& u_ub)
183 {
184  _functions.u_lb = u_lb;
185  _functions.u_ub = u_ub;
186  // TODO(roesmann): ocp modified?! we just changed bounds and not dimensions
187 }
188 
190 {
191  if (!_grid)
192  {
193  PRINT_ERROR_NAMED("No grid loaded.");
194  return;
195  }
196  _grid->getStateAndControlTimeSeries(x_sequence, u_sequence);
197 }
198 
200 {
201  if (_grid) _grid->clear();
202  if (_optim_prob) _optim_prob->clear();
203  if (_dynamics) _dynamics->reset();
204  if (_solver) _solver->clear();
205  if (_statistics) _statistics->clear();
206 
207  _u_prev.setZero(); // TODO(roesmann): should we set this to zero here=
208 
209  _ocp_modified = true;
210  _objective_value = -1;
211 }
212 
213 #ifdef MESSAGE_SUPPORT
214 void StructuredOptimalControlProblem::toMessage(corbo::messages::OptimalControlProblem& message) const
215 {
216  messages::StructuredOptimalControlProblem* msg = message.mutable_structured_optimal_control_problem();
217 
218  if (_dynamics) _dynamics->toMessage(*msg->mutable_system_model());
219  if (_optim_prob) _optim_prob->toMessage(*msg->mutable_hyper_graph_strategy());
220  if (_solver) _solver->toMessage(*msg->mutable_nlp_solver());
221  if (_grid) _grid->toMessage(*msg->mutable_discretization_grid());
222  if (_functions.stage_cost) _functions.stage_cost->toMessage(*msg->mutable_stage_cost());
223  if (_functions.final_stage_cost) _functions.final_stage_cost->toMessage(*msg->mutable_final_stage_cost());
224  if (_functions.stage_equalities) _functions.stage_equalities->toMessage(*msg->mutable_stage_equalities());
225  if (_functions.stage_inequalities) _functions.stage_inequalities->toMessage(*msg->mutable_stage_inequalities());
226  if (_functions.final_stage_constraints) _functions.final_stage_constraints->toMessage(*msg->mutable_final_stage_constraints());
227  if (_functions.stage_preprocessor) _functions.stage_preprocessor->toMessage(*msg->mutable_stage_preprocessors());
228 
229  msg->set_increase_n_if_infeas(_increase_n_if_infeas);
230 
231  // bounds
232  msg->mutable_x_min()->Resize(_functions.x_lb.size(), 0);
233  Eigen::Map<Eigen::VectorXd>(msg->mutable_x_min()->mutable_data(), _functions.x_lb.size()) = _functions.x_lb;
234  msg->mutable_x_max()->Resize(_functions.x_ub.size(), 0);
235  Eigen::Map<Eigen::VectorXd>(msg->mutable_x_max()->mutable_data(), _functions.x_ub.size()) = _functions.x_ub;
236  msg->mutable_u_min()->Resize(_functions.u_lb.size(), 0);
237  Eigen::Map<Eigen::VectorXd>(msg->mutable_u_min()->mutable_data(), _functions.u_lb.size()) = _functions.u_lb;
238  msg->mutable_u_max()->Resize(_functions.u_ub.size(), 0);
239  Eigen::Map<Eigen::VectorXd>(msg->mutable_u_max()->mutable_data(), _functions.u_ub.size()) = _functions.u_ub;
240 }
241 
242 void StructuredOptimalControlProblem::fromMessage(const corbo::messages::OptimalControlProblem& message, std::stringstream* issues)
243 {
244  _dynamics.reset();
245  _solver.reset();
246  _grid.reset();
247  _optim_prob.reset();
248 
249  reset();
250  // _graph.clear();
251 
252  const messages::StructuredOptimalControlProblem& msg = message.structured_optimal_control_problem();
253 
254  // system model
255  if (!msg.has_system_model())
256  {
257  if (issues) *issues << "StructuredOptimalControlProblem: no system model specified.\n";
258  return;
259  }
260  // construct object
261  std::string type;
262  util::get_oneof_field_type_expand_isolated(msg.system_model(), "system_dynamics", type, false, 1);
264  // import parameters
265  if (dynamics)
266  {
267  dynamics->fromMessage(msg.system_model(), issues);
268  setSystemDynamics(dynamics);
269  }
270  else
271  {
272  if (issues) *issues << "StructuredOptimalControlProblem: unknown system model specified.\n";
273  return;
274  }
275  int dim_x = dynamics->getStateDimension();
276  int dim_u = dynamics->getInputDimension();
277 
278  // grid
279  if (!msg.has_discretization_grid())
280  {
281  if (issues) *issues << "StructuredOptimalControlProblem: no discretization grid specified.\n";
282  return;
283  }
284  // construct object
285  util::get_oneof_field_type(msg.discretization_grid(), "discretization_grid", type, false);
287  // import parameters
288  if (grid)
289  {
290  grid->fromMessage(msg.discretization_grid(), issues);
291  setDiscretizationGrid(grid);
292  }
293  else
294  {
295  if (issues) *issues << "StructuredOptimalControlProblem: unknown discretization grid specified.\n";
296  return;
297  }
298 
299  // stage cost
300  if (msg.has_stage_cost() && !msg.stage_cost().has_no_function())
301  {
302  // construct object
303  util::get_oneof_field_type_expand_isolated(msg.stage_cost(), "stage_cost", type, false, 1);
304  StageCost::Ptr stage_cost = StageCostFactory::instance().create(type);
305  // import parameters
306  if (stage_cost)
307  {
308  if (!stage_cost->fromMessage(msg.stage_cost(), issues)) return;
309  if (!stage_cost->checkParameters(_dynamics->getStateDimension(), _dynamics->getInputDimension(), issues)) return;
310  setStageCost(stage_cost);
311  }
312  else
313  {
314  if (issues) *issues << "StructuredOptimalControlProblem: unknown stage_cost specified.\n";
315  return;
316  }
317  }
318  else
319  setStageCost({});
320 
321  // final stage cost
322  if (msg.has_final_stage_cost() && !msg.final_stage_cost().has_no_function())
323  {
324  // construct object
325  util::get_oneof_field_type_expand_isolated(msg.final_stage_cost(), "final_stage_cost", type, false, 1);
327  // import parameters
328  if (final_stage_cost)
329  {
330  if (!final_stage_cost->fromMessage(msg.final_stage_cost(), issues)) return;
331  if (!final_stage_cost->checkParameters(_dynamics->getStateDimension(), _dynamics->getInputDimension(), issues)) return;
332  setFinalStageCost(final_stage_cost);
333  }
334  else
335  {
336  if (issues) *issues << "StructuredOptimalControlProblem: unknown final_stage_cost specified.\n";
337  return;
338  }
339  }
340  else
341  setFinalStageCost({});
342 
343  // stage equalities
344  if (msg.has_stage_equalities() && !msg.stage_equalities().has_no_function())
345  {
346  // construct object
347  util::get_oneof_field_type_expand_isolated(msg.stage_equalities(), "stage_equalities", type, false, 1);
349  // import parameters
350  if (stage_equalities)
351  {
352  if (!stage_equalities->fromMessage(msg.stage_equalities(), issues)) return;
353  if (!stage_equalities->checkParameters(_dynamics->getStateDimension(), _dynamics->getInputDimension(), issues)) return;
354 
355  setStageEqualityConstraint(stage_equalities);
356  }
357  else
358  {
359  if (issues) *issues << "StructuredOptimalControlProblem: unknown stage_equalities specified.\n";
360  return;
361  }
362  }
363  else
365 
366  // stage inequalities
367  if (msg.has_stage_inequalities() && !msg.stage_inequalities().has_no_function())
368  {
369  // construct object
370  util::get_oneof_field_type_expand_isolated(msg.stage_inequalities(), "stage_inequalities", type, false, 1);
372  // import parameters
373  if (stage_inequalities)
374  {
375  if (!stage_inequalities->fromMessage(msg.stage_inequalities(), issues)) return;
376  if (!stage_inequalities->checkParameters(_dynamics->getStateDimension(), _dynamics->getInputDimension(), issues)) return;
377 
378  setStageInequalityConstraint(stage_inequalities);
379  }
380  else
381  {
382  if (issues) *issues << "StructuredOptimalControlProblem: unknown stage_inequalities specified.\n";
383  return;
384  }
385  }
386  else
388 
389  // final stage constraints
390  if (msg.has_final_stage_constraints() && !msg.final_stage_constraints().has_no_function())
391  {
392  // construct object
393  util::get_oneof_field_type_expand_isolated(msg.final_stage_constraints(), "final_stage_constraints", type, false, 1);
395  // import parameters
396  if (final_stage_constraint)
397  {
398  if (!final_stage_constraint->fromMessage(msg.final_stage_constraints(), issues)) return;
399  if (!final_stage_constraint->checkParameters(_dynamics->getStateDimension(), _dynamics->getInputDimension(), _functions.final_stage_cost,
400  issues))
401  return;
402  setFinalStageConstraint(final_stage_constraint);
403  }
404  else
405  {
406  if (issues) *issues << "StructuredOptimalControlProblem: unknown final_stage_constraints specified.\n";
407  return;
408  }
409  }
410  else
412 
413  // stage preprocessor
414  if (msg.has_stage_preprocessors() && !msg.stage_preprocessors().has_no_function())
415  {
416  // construct object
417  util::get_oneof_field_type_expand_isolated(msg.stage_preprocessors(), "stage_preprocessors", type, false, 1);
418 
420  // import parameters
421  if (stage_preprocessor)
422  {
423  if (!stage_preprocessor->fromMessage(msg.stage_preprocessors(), issues)) return;
424  setStagePreprocessor(stage_preprocessor);
425  }
426  else
427  {
428  if (issues) *issues << "StructuredOptimalControlProblem: unknown stage_processors specified.\n";
429  return;
430  }
431  }
432  else
434 
435  // bounds
436  assert(dynamics); // should be loaded before, otherwise return ...
437  Eigen::VectorXd x_lb, x_ub, u_lb, u_ub;
438  if (msg.x_min_size() > 0 && msg.x_min_size() != dim_x && issues)
439  {
440  *issues << "StructuredOptimalControlProblem: x_min size does not match dimension of the system dynamics object" << dim_x << ".\n";
441  }
442  else
443  {
444  x_lb = Eigen::Map<const Eigen::VectorXd>(msg.x_min().data(), msg.x_min_size());
445  }
446 
447  if (msg.x_max_size() > 0 && msg.x_max_size() != dim_x && issues)
448  {
449  *issues << "StructuredOptimalControlProblem: x_max size does not match dimension of the system dynamics object " << dim_x << ".\n";
450  }
451  else
452  {
453  x_ub = Eigen::Map<const Eigen::VectorXd>(msg.x_max().data(), msg.x_max_size());
454  }
455 
456  if (msg.u_min_size() > 0 && msg.u_min_size() != dim_u && issues)
457  {
458  *issues << "StructuredOptimalControlProblem: u_min size does not match dimension of the system dynamics object" << dim_u << ".\n";
459  }
460  else
461  {
462  u_lb = Eigen::Map<const Eigen::VectorXd>(msg.u_min().data(), msg.u_min_size());
463  }
464 
465  if (msg.u_max_size() > 0 && msg.u_max_size() != dim_u && issues)
466  {
467  *issues << "StructuredOptimalControlProblem: u_max size does not match dimension of the system dynamics object " << dim_u << ".\n";
468  }
469  else
470  {
471  u_ub = Eigen::Map<const Eigen::VectorXd>(msg.u_max().data(), msg.u_max_size());
472  }
473  setBounds(x_lb, x_ub, u_lb, u_ub);
474 
475  // hyper-graph optimization problem
476  if (!msg.has_hyper_graph_strategy())
477  {
478  if (issues) *issues << "StructuredOptimalControlProblem: no hyper_graph_strategy specified.\n";
479  return;
480  }
481  // construct object
482  util::get_oneof_field_type(msg.hyper_graph_strategy(), "hyper_graph_optimization_problem", type, false);
484  // import parameters
485  if (optim_prob)
486  {
487  optim_prob->fromMessage(msg.hyper_graph_strategy(), issues);
489  }
490  else
491  {
492  if (issues) *issues << "StructuredOptimalControlProblem: unknown hyper_graph_strategy specified.\n";
493  return;
494  }
495 
496  // solver
497  if (!msg.has_nlp_solver())
498  {
499  if (issues) *issues << "StructuredOptimalControlProblem: no solver specified.\n";
500  return;
501  }
502  // construct object
503  util::get_oneof_field_type(msg.nlp_solver(), "solver", type, false);
505  // import parameters
506  if (solver)
507  {
508  solver->fromMessage(msg.nlp_solver(), issues);
509  setSolver(solver);
510  }
511  else
512  {
513  if (issues) *issues << "StructuredOptimalControlProblem: unknown solver specified.\n";
514  return;
515  }
516 
517  _increase_n_if_infeas = msg.increase_n_if_infeas();
518 }
519 #endif
520 
521 } // namespace corbo
#define PRINT_ERROR_NAMED(msg)
Definition: console.h:260
Scalar * x
Eigen::VectorXd x_lb
Definition: nlp_functions.h:46
void setSystemDynamics(SystemDynamicsInterface::Ptr dynamics)
#define PRINT_WARNING(msg)
Print msg-stream.
Definition: console.h:145
static Time now()
Retrieve current system time.
Definition: time.h:275
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:94
Eigen::VectorXd u_ub
Definition: nlp_functions.h:49
std::shared_ptr< BaseHyperGraphOptimizationProblem > Ptr
FinalStageConstraint::Ptr final_stage_constraints
Definition: nlp_functions.h:43
void setHyperGraphOptimizationProblem(BaseHyperGraphOptimizationProblem::Ptr optim_prob)
StageCost::Ptr stage_cost
Definition: nlp_functions.h:39
Eigen::VectorXd u_lb
Definition: nlp_functions.h:48
Interface class for signal targets.
Representation of time stamps.
Definition: time.h:251
void setStageInequalityConstraint(StageInequalityConstraint::Ptr stage_ineq)
std::shared_ptr< StageEqualityConstraint > Ptr
std::shared_ptr< StageInequalityConstraint > Ptr
void getTimeSeries(TimeSeries::Ptr x_sequence, TimeSeries::Ptr u_sequence, double t_max=CORBO_INF_DBL) override
Eigen::VectorXd x_ub
Definition: nlp_functions.h:47
std::shared_ptr< FinalStageConstraint > Ptr
void setFinalStageConstraint(FinalStageConstraint::Ptr final_stage_constraint)
void setBounds(const Eigen::VectorXd &x_lb, const Eigen::VectorXd &x_ub, const Eigen::VectorXd &u_lb, const Eigen::VectorXd &u_ub)
bool getFirstControlInput(ControlVector &u0) const override
FinalStageCost::Ptr final_stage_cost
Definition: nlp_functions.h:40
void setDiscretizationGrid(DiscretizationGridInterface::Ptr grid)
static Factory & instance()
< Retrieve static instance of the factory
Definition: factory.h:72
bool compute(const StateVector &x, ReferenceTrajectoryInterface &xref, ReferenceTrajectoryInterface &uref, ReferenceTrajectoryInterface *sref, const Time &t, bool new_run, SignalTargetInterface *signal_target=nullptr, ReferenceTrajectoryInterface *xinit=nullptr, ReferenceTrajectoryInterface *uinit=nullptr, const std::string &ns="") override
void setStageEqualityConstraint(StageEqualityConstraint::Ptr stage_eq)
BaseHyperGraphOptimizationProblem::Ptr _optim_prob
void setStateBounds(const Eigen::VectorXd &x_lb, const Eigen::VectorXd &x_ub)
Interface class for reference trajectories.
std::shared_ptr< DiscretizationGridInterface > Ptr
void setStagePreprocessor(StagePreprocessor::Ptr stage_preprocessor)
std::shared_ptr< NlpSolverInterface > Ptr
std::shared_ptr< StagePreprocessor > Ptr
std::shared_ptr< StageCost > Ptr
StageInequalityConstraint::Ptr stage_inequalities
Definition: nlp_functions.h:42
std::shared_ptr< TimeSeries > Ptr
Definition: time_series.h:64
std::shared_ptr< FinalStageCost > Ptr
std::shared_ptr< Derived > create(const std::string &name, bool print_error=true) const
Create a shared instance of the desired object.
Definition: factory.h:93
StageEqualityConstraint::Ptr stage_equalities
Definition: nlp_functions.h:41
StagePreprocessor::Ptr stage_preprocessor
Definition: nlp_functions.h:44
void setControlBounds(const Eigen::VectorXd &u_lb, const Eigen::VectorXd &u_ub)
std::shared_ptr< SystemDynamicsInterface > Ptr
void setFinalStageCost(FinalStageCost::Ptr final_stage_cost)
#define PRINT_ERROR(msg)
Print msg-stream as error msg.
Definition: console.h:173


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Mon Feb 28 2022 22:07:30