integrator.hpp
Go to the documentation of this file.
1 /*********************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2020 Northwestern University
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *********************************************************************/
38 #ifndef INTEGRATOR_HPP
39 #define INTEGRATOR_HPP
40 
41 #include <cmath>
42 #include <functional>
43 #include <armadillo>
44 
47 
48 namespace ergodic_exploration
49 {
50 using arma::linspace;
51 using arma::mat;
52 using arma::span;
53 using arma::vec;
54 
60 typedef std::function<vec(const vec&, const vec&, const vec&, const mat&)> CoStateFunc;
61 
64 {
65 public:
70  RungeKutta(double dt);
71 
81  template <class ModelT>
82  mat solve(const ModelT& model, const vec& x0, const mat& ut, double horizon) const;
83 
98  template <class ModelT>
99  mat solve(const CoStateFunc& func, const ModelT& model, const vec& rhoT, const mat& xt,
100  const mat& ut, const mat& edx, const mat& bdx, double horizon) const;
101 
109  template <class ModelT>
110  vec step(const ModelT& model, const vec& x, const vec& u) const;
111 
124  vec step(const CoStateFunc& func, const vec& rho, const vec& gdx, const vec& dbar,
125  const mat& fdx) const;
126 
127 private:
128  double dt_; // time step
129 };
130 
131 RungeKutta::RungeKutta(double dt) : dt_(dt)
132 {
133 }
134 
135 template <class ModelT>
136 mat RungeKutta::solve(const ModelT& model, const vec& x0, const mat& ut,
137  double horizon) const
138 {
139  // TODO: Add terminal x0?
140  vec x = x0;
141  const auto steps = static_cast<unsigned int>(std::abs(horizon / dt_));
142  mat xt(x.n_rows, steps);
143 
144  for (unsigned int i = 0; i < steps; i++)
145  {
146  x = step(model, x, ut.col(i));
147  x(2) = normalize_angle_PI(x(2));
148  xt.col(i) = x;
149  }
150 
151  return xt;
152 }
153 
154 template <class ModelT>
155 mat RungeKutta::solve(const CoStateFunc& func, const ModelT& model, const vec& rhoT,
156  const mat& xt, const mat& ut, const mat& edx, const mat& bdx,
157  double horizon) const
158 {
159  // TODO: Add terminal p(T)?
160  vec rho = rhoT;
161  const auto steps = static_cast<unsigned int>(std::abs(horizon / dt_));
162  mat rhot(rho.n_rows, steps);
163 
164  // Iterate backwards
165  // this way rhot from t0 to tf in the returned matrix
166  for (unsigned int i = steps; i-- > 0;)
167  {
168  // Index states, controls, and ergodic measures at end of array
169  rho = step(func, rho, edx.col(i), bdx.col(i), model.fdx(xt.col(i), ut.col(i)));
170  rhot.col(i) = rho;
171  }
172 
173  return rhot;
174 }
175 
176 template <class ModelT>
177 vec RungeKutta::step(const ModelT& model, const vec& x, const vec& u) const
178 {
179  const vec k1 = model(x, u);
180  const vec k2 = model(x + dt_ * (0.5 * k1), u);
181  const vec k3 = model(x + dt_ * (0.5 * k2), u);
182  const vec k4 = model(x + dt_ * k3, u);
183  return x + (dt_ / 6.0) * (k1 + 2.0 * k2 + 2.0 * k3 + k4);
184 }
185 
186 vec RungeKutta::step(const CoStateFunc& func, const vec& rho, const vec& gdx,
187  const vec& dbar, const mat& fdx) const
188 {
189  const vec k1 = func(rho, gdx, dbar, fdx);
190  const vec k2 = func(rho - dt_ * (0.5 * k1), gdx, dbar, fdx);
191  const vec k3 = func(rho - dt_ * (0.5 * k2), gdx, dbar, fdx);
192  const vec k4 = func(rho - dt_ * k3, gdx, dbar, fdx);
193  return rho - dt_ / 6.0 * (k1 + 2.0 * k2 + 2.0 * k3 + k4);
194 }
195 
197 {
198 public:
199  RungeKutta45(double hmax, double hmin, double epsilon, unsigned int max_iter);
200 
201  template <class ModelT>
202  bool solve(mat& xt, const ModelT& model, const vec& x0, const mat& ut, double dt,
203  double horizon) const;
204 
205  template <class ModelT>
206  bool solve(mat& rhot, const CoStateFunc& func, const ModelT& model, const vec& rhoT,
207  const mat& xt, const mat& ut, const mat& edx, const mat& bdx, double dt,
208  double horizon) const;
209 
210  template <class ModelT>
211  double step(vec& x_new, const ModelT& model, const vec& x, const vec& u, double h) const;
212 
213  double step(vec& rho_new, const CoStateFunc& func, const vec& rho, const vec& gdx,
214  const vec& dbar, const mat& fdx, double h) const;
215 
216 private:
217  double hmin_, hmax_;
218  double epsilon_;
219  unsigned int max_iter_;
220 };
221 
222 RungeKutta45::RungeKutta45(double hmin, double hmax, double epsilon, unsigned int max_iter)
223  : hmin_(hmin), hmax_(hmax), epsilon_(epsilon), max_iter_(max_iter)
224 {
225 }
226 
227 template <class ModelT>
228 bool RungeKutta45::solve(mat& xt, const ModelT& model, const vec& x0, const mat& ut,
229  double dt, double horizon) const
230 {
231  // TODO: how to initialize h?
232  auto h = (hmax_ + hmin_) / 2.0;
233  // auto h = hmin_;
234  vec x = x0;
235 
236  // desired length of trajectory
237  const auto steps = static_cast<unsigned int>(std::abs(horizon / dt));
238  const vec tvec = linspace(0.0, horizon, steps);
239 
240  // allocate memory for trajectory based on max possible steps
241  const auto max_steps = static_cast<unsigned int>(horizon / hmin_) + 1;
242  mat xt_max(x0.n_rows, max_steps);
243  vec tvec_max(max_steps);
244 
245  // add x0
246  xt_max.col(0) = x0;
247  tvec_max(0) = 0.0;
248 
249  vec x_new;
250  auto t = 0.0;
251  unsigned int stored = 1;
252  unsigned int iter = 0;
253  bool flag = 0;
254  while (!flag)
255  {
256  const auto i = static_cast<unsigned int>(
257  std::floor(std::round(static_cast<double>(steps - 1) * std::abs(t / horizon))));
258  // std::cout << "i: " << i << std::endl;
259 
260  const auto r = step(x_new, model, x, ut.col(i), h);
261  // std::cout << "r: " << r << std::endl;
262 
263  if (r < epsilon_ || almost_equal(r, epsilon_))
264  {
265  x = x_new;
266  xt_max.col(stored) = x;
267 
268  t += h;
269  tvec_max(stored) = t;
270 
271  stored++;
272  }
273 
274  h *= 0.84 * std::pow(epsilon_ / r, 0.25);
275  h = std::clamp(h, hmin_, hmax_);
276 
277  if (t > horizon || almost_equal(t, horizon))
278  {
279  flag = 1;
280  }
281 
282  // detect final time
283  else if (t + h > horizon)
284  {
285  h = horizon - t;
286  }
287 
288  // std::cout << "t: " << t << std::endl;
289  // std::cout << "h: " << h << std::endl;
290 
291  if (iter == max_iter_)
292  {
293  std::cout << "WARNING: max iterations reached " << std::endl;
294  return false;
295  }
296 
297  iter++;
298  }
299 
300  // xt_max.cols(0, stored-1).t().print("traj");
301  // tvec_max.rows(0, stored - 1).print("t rk45");
302  // tvec.print("t desired");
303  //
304  // std::cout << "tvec_max: " << tvec_max.n_rows << std::endl;
305  // std::cout << "tvec: " << tvec.n_rows << std::endl;
306  //
307  // std::cout << "steps: " << steps << std::endl;
308  // std::cout << "stored: " << stored << std::endl;
309 
310  // fit quartic polynomials
311  xt.resize(x0.n_rows, steps);
312  for (unsigned int i = 0; i < x0.n_rows; i++)
313  {
314  const vec p =
315  polyfit(tvec_max.rows(0, stored - 1), xt_max(span(i, i), span(0, stored - 1)), 4);
316  // p.print("p");
317  xt.row(i) = polyval(p, tvec).t();
318  }
319 
320  return true;
321 }
322 
323 template <class ModelT>
324 double RungeKutta45::step(vec& x_new, const ModelT& model, const vec& x, const vec& u,
325  double h) const
326 {
327  const vec k1 = h * model(x, u);
328 
329  const vec k2 = h * model(x + ((1.0 / 4.0) * k1), u);
330 
331  const vec k3 = h * model(x + ((3.0 / 32.0) * k1) + ((9.0 / 32.0) * k2), u);
332 
333  const vec k4 = h * model(x + ((1932.0 / 2197.0) * k1) - ((7200.0 / 2197.0) * k2) +
334  ((7296.0 / 2197.0) * k3),
335  u);
336  const vec k5 = h * model(x + ((439.0 / 216.0) * k1) - (8.0 * k2) +
337  ((3680.0 / 513.0) * k3) - ((845.0 / 4104.0) * k4),
338  u);
339  const vec k6 =
340  h * model(x - ((8.0 / 27.0) * k1) + (2.0 * k2) - ((3544.0 / 2565.0) * k3) +
341  ((1859.0 / 4104.0) * k4) - ((11.0 / 40.0) * k5),
342  u);
343 
344  x_new = x + ((25.0 / 216.0) * k1) + ((1408.0 / 2565.0) * k3) +
345  ((2197.0 / 4101.0) * k4) - ((1.0 / 5.0) * k5);
346 
347  const vec z = x + ((16.0 / 135.0) * k1) + ((6656.0 / 12825.0) * k3) +
348  ((28561.0 / 56430.0) * k4) - ((9.0 / 50.0) * k5) + ((2.0 / 55.0) * k6);
349 
350  // std::cout << "max diff: " << max(abs(z - x_new)) << std::endl;
351  // std::cout << "error norm: " << norm(z - x_new, 2) << std::endl;
352 
353  return max(abs(z - x_new)) / h;
354  // return min(abs(z - x_new)) / h;
355 }
356 
357 template <class ModelT>
358 bool RungeKutta45::solve(mat& rhot, const CoStateFunc& func, const ModelT& model,
359  const vec& rhoT, const mat& xt, const mat& ut, const mat& edx,
360  const mat& bdx, double dt, double horizon) const
361 {
362  // TODO: how to initialize h?
363  // auto h = (hmax_ + hmin_) / 2.0;
364  auto h = hmin_;
365  vec rho = rhoT;
366 
367  // desired length of trajectory
368  const auto steps = static_cast<unsigned int>(std::abs(horizon / dt));
369  const vec tvec = linspace(0.0, horizon, steps);
370 
371  // allocate memory for trajectory based on max possible steps
372  const auto max_steps = static_cast<unsigned int>(horizon / hmin_) + 1;
373  mat rhot_max(rhoT.n_rows, max_steps);
374  vec tvec_max(max_steps);
375 
376  // add x0
377  rhot_max.col(0) = rhoT;
378  tvec_max(0) = horizon;
379 
380  vec rho_new;
381  auto t = horizon;
382  unsigned int stored = 1;
383  unsigned int iter = 0;
384  bool flag = 0;
385  while (!flag)
386  {
387  const auto i = static_cast<unsigned int>(
388  std::floor(std::round(static_cast<double>(steps - 1) * std::abs(t / horizon))));
389  // std::cout << "i: " << i << std::endl;
390 
391  const auto r = step(rho_new, func, rho, edx.col(i), bdx.col(i),
392  model.fdx(xt.col(i), ut.col(i)), h);
393  // std::cout << "r: " << r << std::endl;
394 
395  if (r < epsilon_ || almost_equal(r, epsilon_))
396  {
397  rho = rho_new;
398  rhot_max.col(stored) = rho;
399 
400  t -= h;
401  tvec_max(stored) = t;
402 
403  stored++;
404  }
405 
406  h *= 0.84 * std::pow(epsilon_ / r, 0.25);
407  h = std::clamp(h, hmin_, hmax_);
408 
409  if (t < 0.0 || almost_equal(t, 0.0))
410  {
411  flag = 1;
412  }
413 
414  // detect final time
415  else if (t - h < 0.0)
416  {
417  h = t;
418  }
419 
420  // std::cout << "t: " << t << std::endl;
421  // std::cout << "h: " << h << std::endl;
422 
423  if (iter == max_iter_)
424  {
425  std::cout << "WARNING: max iterations reached " << std::endl;
426  return false;
427  }
428 
429  iter++;
430  }
431 
432  // rhot_max.cols(0, stored-1).t().print("rho traj");
433  // tvec_max.rows(0, stored - 1).print("t rk45");
434  // tvec.print("t desired");
435  //
436  // std::cout << "tvec_max: " << tvec_max.n_rows << std::endl;
437  // std::cout << "tvec: " << tvec.n_rows << std::endl;
438  //
439  // std::cout << "steps: " << steps << std::endl;
440  // std::cout << "stored: " << stored << std::endl;
441 
442  // fit quartic polynomials
443  rhot.resize(rho.n_rows, steps);
444  for (unsigned int i = 0; i < rhoT.n_rows; i++)
445  {
446  const vec p = polyfit(tvec_max.rows(0, stored - 1),
447  rhot_max(span(i, i), span(0, stored - 1)), 4);
448  // p.print("p");
449  rhot.row(i) = polyval(p, tvec).t();
450  }
451 
452  return true;
453 }
454 
455 double RungeKutta45::step(vec& rho_new, const CoStateFunc& func, const vec& rho,
456  const vec& gdx, const vec& dbar, const mat& fdx, double h) const
457 {
458  const vec k1 = -h * func(rho, gdx, dbar, fdx);
459 
460  const vec k2 = -h * func(rho + ((1.0 / 4.0) * k1), gdx, dbar, fdx);
461 
462  const vec k3 =
463  -h * func(rho + ((3.0 / 32.0) * k1) + ((9.0 / 32.0) * k2), gdx, dbar, fdx);
464 
465  const vec k4 = -h * func(rho + ((1932.0 / 2197.0) * k1) - ((7200.0 / 2197.0) * k2) +
466  ((7296.0 / 2197.0) * k3),
467  gdx, dbar, fdx);
468 
469  const vec k5 = -h * func(rho + ((439.0 / 216.0) * k1) - (8.0 * k2) +
470  ((3680.0 / 513.0) * k3) - ((845.0 / 4104.0) * k4),
471  gdx, dbar, fdx);
472 
473  const vec k6 =
474  -h * func(rho - ((8.0 / 27.0) * k1) + (2.0 * k2) - ((3544.0 / 2565.0) * k3) +
475  ((1859.0 / 4104.0) * k4) - ((11.0 / 40.0) * k5),
476  gdx, dbar, fdx);
477 
478  rho_new = rho + ((25.0 / 216.0) * k1) + ((1408.0 / 2565.0) * k3) +
479  ((2197.0 / 4101.0) * k4) - ((1.0 / 5.0) * k5);
480 
481  const vec z = rho + ((16.0 / 135.0) * k1) + ((6656.0 / 12825.0) * k3) +
482  ((28561.0 / 56430.0) * k4) - ((9.0 / 50.0) * k5) + ((2.0 / 55.0) * k6);
483 
484  // std::cout << "max diff: " << max(abs(z - rho_new)) << std::endl;
485  // std::cout << "error norm: " << norm(z - rho_new, 2) << std::endl;
486 
487  return max(abs(z - rho_new)) / h;
488 }
489 
490 } // namespace ergodic_exploration
491 #endif
epsilon
double epsilon
collision.hpp
Collision checking in 2D.
ergodic_exploration::RungeKutta::solve
mat solve(const ModelT &model, const vec &x0, const mat &ut, double horizon) const
Simulate the dynamics forward in time.
Definition: integrator.hpp:136
ergodic_exploration::RungeKutta45::solve
bool solve(mat &xt, const ModelT &model, const vec &x0, const mat &ut, double dt, double horizon) const
Definition: integrator.hpp:228
ergodic_exploration::normalize_angle_PI
double normalize_angle_PI(double rad)
Wraps angle between -pi and pi.
Definition: numerics.hpp:77
ergodic_exploration
Definition: basis.hpp:43
ergodic_exploration::RungeKutta::dt_
double dt_
Definition: integrator.hpp:128
ergodic_exploration::RungeKutta45::step
double step(vec &x_new, const ModelT &model, const vec &x, const vec &u, double h) const
Definition: integrator.hpp:324
ergodic_exploration::RungeKutta45::epsilon_
double epsilon_
Definition: integrator.hpp:218
ergodic_exploration::almost_equal
bool almost_equal(double d1, double d2, double epsilon=1.0e-12)
approximately compare two floating-point numbers
Definition: numerics.hpp:67
numerics.hpp
Useful numerical utilities.
ergodic_exploration::CoStateFunc
std::function< vec(const vec &, const vec &, const vec &, const mat &)> CoStateFunc
Function representing the time derivatve of the co-state variable.
Definition: integrator.hpp:60
ergodic_exploration::RungeKutta45::hmax_
double hmax_
Definition: integrator.hpp:217
ergodic_exploration::RungeKutta::RungeKutta
RungeKutta(double dt)
Constructor.
Definition: integrator.hpp:131
ergodic_exploration::RungeKutta45::max_iter_
unsigned int max_iter_
Definition: integrator.hpp:219
ergodic_exploration::RungeKutta
4th order Runge-Kutta integration
Definition: integrator.hpp:63
ergodic_exploration::RungeKutta45::hmin_
double hmin_
Definition: integrator.hpp:217
ergodic_exploration::RungeKutta45
Definition: integrator.hpp:196
ergodic_exploration::RungeKutta45::RungeKutta45
RungeKutta45(double hmax, double hmin, double epsilon, unsigned int max_iter)
Definition: integrator.hpp:222
ergodic_exploration::RungeKutta::step
vec step(const ModelT &model, const vec &x, const vec &u) const
Performs one step of RK4 forward in time.
Definition: integrator.hpp:177
t
geometry_msgs::TransformStamped t


ergodic_exploration
Author(s): bostoncleek
autogenerated on Wed Mar 2 2022 00:17:13