full_discretization_grid_move_blocking_base.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: Maximilian Krämer, Christoph Rösmann
23  *********************************************************************/
24 
26 
27 namespace corbo {
28 
30 {
31  if (x_sequence) x_sequence->clear();
32  if (u_sequence) u_sequence->clear();
33 
34  if (isEmpty()) return;
35  assert(isValid());
36 
37  PRINT_ERROR_COND_NAMED(t_max < 0, "t_max >= 0 required");
38 
39  double dt = getDt();
40 
41  if (x_sequence)
42  {
43  double t = 0;
44  for (int i = 0; i < _x_seq.size(); ++i)
45  {
46  x_sequence->add(t, _x_seq[i].values());
47  t += dt;
48  if (t > t_max) break;
49  }
50  if (t <= t_max) x_sequence->add(t, _xf.values());
51  }
52 
53  if (u_sequence)
54  {
55  double t = 0;
56  for (int i = 0; i < _u_seq.size(); ++i)
57  {
58  // Use blocking vector to reconstruct valid time series
59  for (int j = 0; j < _blocking_vector(i); ++j)
60  {
61  u_sequence->add(t, _u_seq[i].values());
62  t += dt;
63  if (t > t_max) break;
64  }
65  }
66  // duplicate last u to have the sampe time stamps as x_sequence
67  if (t <= t_max) u_sequence->add(t, _u_seq.back().values());
68  }
69 }
70 
71 bool FullDiscretizationGridMoveBlockingBase::isValid() const
72 {
73  // Check for consistent blocking vector and correct, implicit u sequence
74  return (_u_seq.size() == _blocking_vector.size()) && (_blocking_vector.sum() == _x_seq.size());
75 }
76 
77 void FullDiscretizationGridMoveBlockingBase::initializeSequences(const Eigen::VectorXd& x0, const Eigen::VectorXd& xf,
78  ReferenceTrajectoryInterface& uref, NlpFunctions& nlp_fun)
79 {
80  // clear(); // make sure everything is cleared
81  _x_seq.clear();
82  _u_seq.clear();
83  _xf.clear();
84  _active_vertices.clear();
85 
86  // check or initalize bounds if empty
87  nlp_fun.checkAndInitializeBoundDimensions(x0.size(), uref.getDimension());
88 
89  // check x_fixed
90  checkAndInitializeXfFixedFlags(x0.size());
91 
92  int n_init = _n_adapt > 0 ? _n_adapt : _n_ref;
93 
94  int num_intervals = n_init - 1;
95 
96  // we initialize the state trajectory linearly
97  Eigen::VectorXd dir = xf - x0;
98  double dist = dir.norm();
99  if (dist != 0) dir /= dist;
100  double step = dist / num_intervals;
101 
102  for (int k = 0; k < num_intervals; ++k)
103  {
104  // add new state by linear interpolation
105  _x_seq.emplace_back(x0 + (double)k * step * dir, nlp_fun.x_lb, nlp_fun.x_ub);
106  }
107 
108  int ref_id = 0;
109  for (int k = 0; k < _blocking_vector.size(); ++k)
110  {
111  // add new control according to blocking vector
112  _u_seq.emplace_back(uref.getReferenceCached(ref_id), nlp_fun.u_lb, nlp_fun.u_ub);
113  ref_id += _blocking_vector(k);
114  }
115 
116  // add final state
117  _xf.set(xf, nlp_fun.x_lb, nlp_fun.x_ub, _xf_fixed);
118 
119  // set first state as fixed
120  _x_seq.front().setFixed(true);
121 
122  // set dt
123  _dt.set(_dt_ref, _dt_lb, _dt_ub, isDtFixedIntended());
124 
125  assert(_x_seq.size() > 0);
126 
127  // notify graph that vertices are changed
128  setModified(true);
129 }
130 
131 void FullDiscretizationGridMoveBlockingBase::initializeSequences(const Eigen::VectorXd& x0, const Eigen::VectorXd& xf,
132  ReferenceTrajectoryInterface& xref, ReferenceTrajectoryInterface& uref,
133  NlpFunctions& nlp_fun)
134 {
135  // clear(); // make sure everything is cleared
136  _x_seq.clear();
137  _u_seq.clear();
138  _xf.clear();
139  _active_vertices.clear();
140 
141  // TODO(roesmann): check if this is ever needed in any pracital realization:
142  // if ((x0 - xref.getReferenceCached(0)).norm() > _non_static_ref_dist_threshold)
143  // {
144  // initializeSequences(x0, xref.getReferenceCached(getN() - 1), uref, nlp_fun);
145  // }
146 
147  // check or initalize bounds if empty
148  nlp_fun.checkAndInitializeBoundDimensions(x0.size(), uref.getDimension());
149 
150  // check x_fixed
151  checkAndInitializeXfFixedFlags(x0.size());
152 
153  int n_init = _n_adapt > 0 ? _n_adapt : _n_ref;
154 
155  int num_intervals = n_init - 1;
156 
157  _x_seq.emplace_back(x0, nlp_fun.x_lb, nlp_fun.x_ub); // always add the (exact) x0
158  for (int k = 1; k < num_intervals; ++k)
159  {
160  // add new state by linear interpolation
161  _x_seq.emplace_back(xref.getReferenceCached(k), nlp_fun.x_lb, nlp_fun.x_ub);
162  }
163 
164  int ref_id = 0;
165  for (int k = 0; k < _blocking_vector.size(); ++k)
166  {
167  // add new control according to blocking vector
168  _u_seq.emplace_back(uref.getReferenceCached(ref_id), nlp_fun.u_lb, nlp_fun.u_ub);
169  ref_id += _blocking_vector(k);
170  }
171 
172  // add final state
173  _xf.set(xf, nlp_fun.x_lb, nlp_fun.x_ub, _xf_fixed);
174 
175  // set first state as fixed
176  _x_seq.front().setFixed(true);
177 
178  // set dt
179  _dt.set(_dt_ref, _dt_lb, _dt_ub, isDtFixedIntended());
180 
181  assert(_x_seq.size() > 1);
182 
183  // notify graph that vertices are changed
184  setModified(true);
185 }
186 
187 void FullDiscretizationGridMoveBlockingBase::warmStartShifting(const Eigen::VectorXd& x0)
188 {
189  // find nearest state to x0 (ideally it is the second one in _x_seq).
190  int num_shift = findNearestState(x0);
191  if (num_shift <= 0) return;
192 
193  if (num_shift > getN() - 2)
194  {
195  PRINT_ERROR_NAMED("Cannot shift if num_shift > N-2");
196  return;
197  }
198 
199  // the simplest strategy would be to just remove remove x_seq[0], append xf to x_seq and replace xf (num_shift=1)
200  // however, this requries to change the structure which always triggers an edge recreation and so the solver must reallocate memory.
201  // TOOD(roesmann): for time-optimal stuff, if we are sure that we resize the grid, it is then more efficent to implement the strategy above...
202 
203  // shift from end to front:
204  for (int i = 0; i < getN() - num_shift; ++i)
205  {
206  int idx = i + num_shift;
207  if (idx == getN() - 1)
208  {
209  // final state reached
210  _x_seq[i].values() = _xf.values();
211  }
212  else
213  {
214  _x_seq[i].values() = _x_seq[idx].values();
215  }
216  }
217 
218  if (_warm_start_shift_u)
219  {
220  int u_idx = 0;
221  int block_idx = 0;
222  int i = 0;
223  int k = 0;
224 
225  for (; block_idx < _blocking_vector.size(); ++block_idx)
226  {
227  for (; k < _blocking_vector.size(); ++k)
228  {
229  if (u_idx + _blocking_vector(k) > num_shift + i)
230  {
231  _u_seq[block_idx].values() = _u_seq[k].values();
232  break;
233  }
234  else
235  {
236  u_idx += _blocking_vector(k);
237  }
238  }
239  if (k == _blocking_vector.size())
240  {
241  break;
242  }
243 
244  i += _blocking_vector(block_idx);
245  }
246  for (int j = block_idx; j < _blocking_vector.size(); ++j)
247  {
248  _u_seq[j].values() = _u_seq[j - 1].values();
249  }
250  }
251 
252  int idx = getN() - num_shift;
253  if (idx < 0)
254  {
255  PRINT_ERROR_NAMED("idx < 0...");
256  return;
257  }
258  for (int i = 0; i < num_shift; ++i, ++idx)
259  {
260  // now extrapolate
261  assert(idx > 1);
262 
263  // linearly extrapolate states
264  if (i == num_shift - 1) // consider xf
265  {
266  _xf.values() = _x_seq[idx - 2].values() + 2.0 * (_x_seq[idx - 1].values() - _x_seq[idx - 2].values());
267  }
268  else
269  {
270  _x_seq[idx].values() = _x_seq[idx - 2].values() + 2.0 * (_x_seq[idx - 1].values() - _x_seq[idx - 2].values());
271  // TODO(roesmann) multiply by fraction of last dt and _dt
272  }
273  }
274 }
275 
276 void FullDiscretizationGridMoveBlockingBase::resampleTrajectory(int n_new) { PRINT_ERROR_NAMED("Not supported for move blocking"); }
277 
278 void FullDiscretizationGridMoveBlockingBase::computeActiveVertices()
279 {
280  _active_vertices.clear();
281  assert(isValid());
282  int n = getN();
283 
284  int u_idx = 0;
285  int block_idx = 0;
286  for (int i = 0; i < n - 1; ++i)
287  {
288  if (!_x_seq[i].isFixed()) _active_vertices.push_back(&_x_seq[i]);
289  if ((i == u_idx) && (!_u_seq[block_idx].isFixed()))
290  {
291  _active_vertices.push_back(&_u_seq[block_idx]);
292 
293  u_idx += _blocking_vector(block_idx);
294  ++block_idx; // TODO(kraemer) increment on fixed
295  }
296  }
297 
298  if (!_xf.isFixed()) _active_vertices.push_back(&_xf);
299  if (!_dt.isFixed()) _active_vertices.push_back(&_dt);
300 }
301 
302 } // namespace corbo
corbo
Definition: communication/include/corbo-communication/utilities.h:37
PRINT_ERROR_COND_NAMED
#define PRINT_ERROR_COND_NAMED(cond, msg)
Definition: console.h:262
N
static const int N
Definition: TensorIntDiv.h:84
corbo::FullDiscretizationGridMoveBlockingBase::getStateAndControlTimeSeries
void getStateAndControlTimeSeries(TimeSeries::Ptr x_sequence, TimeSeries::Ptr u_sequence, double t_max=CORBO_INF_DBL) const override
Return state and control trajectory as time series object (shared instance)
Definition: full_discretization_grid_move_blocking_base.cpp:51
corbo::FullDiscretizationGridBase::isEmpty
bool isEmpty() const override
Definition: full_discretization_grid_base.h:117
corbo::TimeSeries::Ptr
std::shared_ptr< TimeSeries > Ptr
Definition: time_series.h:108
corbo::FullDiscretizationGridMoveBlockingBase::isValid
bool isValid() const override
Definition: full_discretization_grid_move_blocking_base.cpp:93
full_discretization_grid_move_blocking_base.h


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Wed Mar 2 2022 00:05:45