codac 2.0.0
Loading...
Searching...
No Matches
codac2_SampledTraj.h
Go to the documentation of this file.
1
9
10#pragma once
11
12#include <map>
13#include "codac2_math.h"
14#include "codac2_TrajBase.h"
18
19namespace codac2
20{
21 template<typename T>
22 class SampledTraj : public TrajBase<T>, public std::map<double,T>
23 {
24 public:
25
26 using Type = typename ExprType<T>::Type;
27
28 SampledTraj()
29 : TrajBase<T>(), std::map<double,T>()
30 { }
31
32 SampledTraj(const std::list<double>& l_t, const std::list<T>& l_x)
33 : SampledTraj()
34 {
35 assert_release(l_t.size() == l_x.size());
36 auto it_t = l_t.begin(); auto it_x = l_x.begin();
37 while(it_t != l_t.end())
38 {
39 this->set(*it_x, *it_t);
40 it_t++; it_x++;
41 }
42 }
43
44 SampledTraj(const std::map<double,T>& m)
45 : TrajBase<T>(), std::map<double,T>(m)
46 { }
47
48 // size is not the std::map<double,T>::size() !
49 virtual Index size() const
50 {
51 if constexpr(std::is_same_v<Type,ScalarType>)
52 return 1;
53
54 else
55 {
56 if(this->empty())
57 return 0;
58 else
59 return this->begin()->second.size();
60 }
61 }
62
63 virtual std::pair<Index,Index> shape() const
64 {
65 if constexpr(std::is_same_v<Type,ScalarType>)
66 return {1,1};
67 else
68 {
69 if(this->empty())
70 return {0,0};
71 else
72 return {this->begin()->second.rows(),this->begin()->second.cols()};
73 }
74 }
75
76 size_t nb_samples() const
77 {
78 return std::map<double,T>::size();
79 }
80
81 virtual bool is_empty() const
82 {
83 return std::map<double,T>::empty();
84 }
85
86 virtual Interval tdomain() const
87 {
88 if(this->empty())
89 return Interval::empty();
90 else
91 return { this->begin()->first, this->rbegin()->first };
92 }
93
94 virtual void truncate_tdomain(const Interval& new_tdomain)
95 {
96 assert_release(this->tdomain().is_superset(new_tdomain));
97
98 // Interpolation on the limits of the new tdomain
99 T y_lb = (*this)(new_tdomain.lb());
100 T y_ub = (*this)(new_tdomain.ub());
101
102 auto it = this->begin();
103 while(it != this->end())
104 {
105 if(!new_tdomain.contains(it->first))
106 it = this->erase(it);
107 else
108 ++it;
109 }
110
111 this->set(y_lb, new_tdomain.lb()); // clean truncation
112 this->set(y_ub, new_tdomain.ub());
113 }
114
115 virtual typename Wrapper<T>::Domain codomain() const
116 {
117 if(is_empty())
118 {
119 if constexpr(std::is_same_v<T,double>)
120 return Interval::empty();
121 else if constexpr(std::is_same_v<T,Vector>)
122 return IntervalVector::empty(0);
123 else
124 return IntervalMatrix::empty(0,0);
125 }
126
127 typename Wrapper<T>::Domain hull(this->begin()->second);
128 for(const auto& [t,v] : *this)
129 hull |= v;
130 return hull;
131 }
132
133 virtual T operator()(double t) const
134 {
135 if(!this->tdomain().contains(t))
136 return this->nan_value();
137
138 auto it_lower = this->lower_bound(t);
139 if(it_lower->first == t)
140 return it_lower->second;
141
142 auto it_upper = it_lower;
143 it_lower--;
144
145 // Linear interpolation
146 return it_lower->second +
147 (t - it_lower->first) * (it_upper->second - it_lower->second) /
148 (it_upper->first - it_lower->first);
149 }
150
151 virtual typename Wrapper<T>::Domain operator()(const Interval& t) const
152 {
153 // We obtain the output dimension by an evalution...
154 typename Wrapper<T>::Domain hull(this->begin()->second);
155
156 if(!this->tdomain().is_superset(t))
157 return hull.init(Interval(-oo,oo));
158
159 else
160 {
161 hull = (*this)(t.lb());
162 for(auto it = this->lower_bound(t.lb()) ; it != this->upper_bound(t.ub()) ; it++)
163 hull |= it->second;
164 hull |= (*this)(t.ub());
165 return hull;
166 }
167 }
168
169 void set(const T& x, double t)
170 {
171 assert(this->empty() || size_of(x) == this->size());
172 std::map<double,T>::operator[](t) = x;
173 }
174
175 virtual SampledTraj<T> sampled(double dt) const
176 {
177 return sampled(dt, true);
178 }
179
180 SampledTraj<T> sampled(double dt, bool keep_original_values) const
181 {
182 assert(dt > 0.);
183 assert(!is_empty());
184
185 auto straj = TrajBase<T>::sampled(dt);
186
187 if(keep_original_values)
188 {
189 // Appending values from the initial map:
190 for(const auto& [ti,xi] : *this)
191 straj.set(xi, ti);
192 }
193
194 return straj;
195 }
196
197 template<typename Q>
198 SampledTraj<T> sampled_as(const SampledTraj<Q>& x) const
199 {
200 return TrajBase<T>::sampled_as(x);
201 }
202
203 template<typename Q>
204 SampledTraj<T> sampled_as(const SampledTraj<Q>& x, bool keep_original_values) const
205 {
206 SampledTraj<T> straj = TrajBase<T>::sampled_as(x);
207 if(keep_original_values)
208 for(const auto& [ti,xi] : *this)
209 straj.set(xi, ti);
210 return straj;
211 }
212
213 SampledTraj<T>& shift_tdomain(double shift)
214 {
215 std::map<double,T> save = *this;
216 this->clear();
217 for(const auto& [ti,xi] : save)
218 this->std::map<double,T>::operator[](ti+shift) = xi;
219 return *this;
220 }
221
222 SampledTraj<T>& stretch_tdomain(const Interval& tdomain)
223 {
224 Interval a = this->tdomain(), b = tdomain;
225 std::map<double,T> save = *this;
226 this->clear();
227 for(const auto& [ti,xi] : save)
228 this->std::map<double,T>::operator[]([&]() {
229 if(ti == a.ub())
230 return b.ub(); // due to floating point possible error
231 else
232 return ((ti-a.lb())*b.diam()/a.diam())+b.lb();
233 }()
234 ) = xi;
235 assert(this->tdomain() == tdomain);
236 return *this;
237 }
238
239 template<typename T_=T>
240 requires std::is_same_v<T_,Vector>
241 SampledTraj<double> operator[](Index i) const
242 {
243 assert_release(i >= 0 && i < size());
244 std::map<double,double> m;
245 for(const auto& [t,y] : *this)
246 {
247 assert(i < y.size());
248 m[t] = y[i];
249 }
250
251 return { m };
252 }
253
254 template<typename T_=T>
255 requires std::is_same_v<T_,Vector>
256 SampledTraj<Vector> subvector(Index i, Index j) const
257 {
258 assert_release(i >= 0 && i <= j && j < size());
259 std::map<double,Vector> m;
260 for(const auto& [t,y] : *this)
261 {
262 assert(j < y.size());
263 m[t] = y.subvector(i,j);
264 }
265
266 return { m };
267 }
268
269 AnalyticFunction<Type> as_function() const
270 {
271 ScalarVar t;
272 return {{t},
273 AnalyticExprWrapper<Type>(
274 std::make_shared<AnalyticOperationExpr<
275 TrajectoryOp<SampledTraj<T>>,Type,ScalarType>>(*this,t))
276 };
277 }
278
279 using TrajBase<T>::primitive;
280 SampledTraj<T> primitive() const
281 {
282 T s = [this]() {
283 if constexpr(std::is_same_v<T,double>)
284 return 0.;
285 else
286 return T(this->begin()->second).init(0.);
287 }();
288 SampledTraj<T> p;
289 p.set(s, this->begin()->first);
290
291 for(auto it = std::next(this->begin()) ; it != this->end() ; it++)
292 {
293 s += (prev(it)->second + it->second) * (it->first - prev(it)->first) / 2.;
294 p.set(s, it->first);
295 }
296
297 return p;
298 }
299
300 SampledTraj<T> derivative() const
301 {
302 SampledTraj<T> d;
303 assert_release(this->nb_samples() >= 3);
304
305 auto it1 = this->begin();
306 auto it2 = std::next(it1);
307
308 // First value (forward)
309 {
310 auto it3 = std::next(it2);
311 double t1 = it1->first, t2 = it2->first, t3 = it3->first;
312 const T& x1 = it1->second; const T& x2 = it2->second; const T& x3 = it3->second;
313 double dt1 = t2-t1, dt2 = t3-t2;
314
315 // Derivative at t1
316 T num = std::pow(dt1,2)*(x2-x1)/dt1 + std::pow(dt2,2)*(x3-x2)/dt2;
317 d.set(2*num/std::pow(dt1+dt2,2), t1);
318 }
319
320 // Intermediate values
321 {
322 auto it_prev = this->begin();
323 auto it = std::next(it_prev);
324 auto it_next = std::next(it);
325
326 for(; it_next != this->end(); ++it_prev, ++it, ++it_next)
327 {
328 double t_prev = it_prev->first;
329 double t = it->first;
330 double t_next = it_next->first;
331
332 const T& x_prev = it_prev->second;
333 const T& x = it->second;
334 const T& x_next = it_next->second;
335 double dt_prev = t-t_prev, dt_next = t_next-t;
336
337 T num = std::pow(dt_prev,2)*(x_next-x) / dt_next + std::pow(dt_next,2)*(x-x_prev) / dt_prev;
338 d.set(2*num/std::pow(dt_prev+dt_next,2), t);
339 }
340 }
341
342 // Last value (backward)
343 {
344 auto it3 = std::prev(this->end());
345 auto it2b = std::prev(it3);
346 auto it1b = std::prev(it2b);
347
348 double t1 = it1b->first, t2 = it2b->first, t3 = it3->first;
349 const T& x1 = it1b->second; const T& x2 = it2b->second; const T& x3 = it3->second;
350 double dt1 = t2-t1, dt2 = t3-t2;
351
352 // Derivative at t3 (t last)
353 T num = std::pow(dt2,2)*(x3-x2)/dt2 + std::pow(dt1,2)*(x2-x1)/dt1;
354 d.set(2*num/std::pow(dt1+dt2,2), t3);
355 }
356
357 return d;
358 }
359
360 T mean() const
361 {
362 if(this->empty())
363 return this->nan_value();
364
365 auto it = this->begin();
366 double t_prev = it->first;
367 T x_prev = it->second;
368
369 T sum = x_prev;
370 double total_time = 0.;
371
372 for(++it; it != this->end(); ++it)
373 {
374 double dt = it->first - t_prev;
375 sum += (x_prev + it->second) * 0.5 * dt;
376 total_time += dt;
377
378 t_prev = it->first;
379 x_prev = it->second;
380 }
381
382 return sum / total_time;
383 }
384
385 template<typename X1, typename X2>
386 static bool same_sampling(const SampledTraj<X1>& x1, const SampledTraj<X2>& x2)
387 {
388 auto it1 = x1.cbegin();
389 auto it2 = x2.cbegin();
390
391 while(it1 != x1.cend() && it2 != x2.cend())
392 {
393 if(it1->first != it2->first)
394 return false;
395 it1++; it2++;
396 }
397
398 return it1 == x1.cend() && it2 == x2.cend();
399 }
400 };
401
402 template<typename T>
403 inline std::ostream& operator<<(std::ostream& os, const SampledTraj<T>& x)
404 {
405 os << "SampledTraj. " << x.tdomain() << "↦" << x.codomain() << ", " << x.nb_samples() << " pts";
406 return os;
407 }
408
409 inline SampledTraj<double> continuous_traj(const SampledTraj<double>& x)
410 {
411 SampledTraj<double> x_continuous;
412 const Interval periodicity = x.codomain();
413
414 double prev_xi = 0., value_mod = 0.;
415
416 for(const auto& [ti,xi] : x)
417 {
418 if(!x_continuous.empty())
419 {
420 if(prev_xi - xi > periodicity.diam()*0.9)
421 value_mod += periodicity.diam();
422 else if(prev_xi - xi < -periodicity.diam()*0.9)
423 value_mod -= periodicity.diam();
424 }
425
426 prev_xi = xi;
427 x_continuous.set(xi+value_mod, ti);
428 }
429
430 return x_continuous;
431 }
432
433 inline std::vector<SampledTraj<double>> as_scalar_trajs(const SampledTraj<Vector>& x)
434 {
435 std::vector<SampledTraj<double>> v(x.size());
436 for(const auto& [ti,xi] : x)
437 for(Index i = 0 ; i < x.size() ; i++)
438 v[i].set(xi[i],ti);
439 return v;
440 }
441
442 template<typename... X>
443 requires ((std::is_same_v<SampledTraj<double>,X> || std::is_same_v<SampledTraj<Vector>,X>) && ...)
444 inline SampledTraj<Vector> cart_prod(const X&... x)
445 {
446 auto&& x0 = std::get<0>(std::forward_as_tuple(x...));
447 assert_release((SampledTraj<Vector>::same_sampling(x0, x) && ...));
448 SampledTraj<Vector> y;
449 for(auto it = x0.begin() ; it != x0.end() ; it++)
450 y.set(cart_prod(x.at(it->first)...), it->first);
451 return y;
452 }
453}
Interval class, for representing closed and connected subsets of .
Definition codac2_Interval.h:49
static Interval empty()
Provides an empty interval.
Definition codac2_Interval_impl.h:568
bool is_superset(const Matrix< codac2::Interval, RowsAtCompileTime, ColsAtCompileTime > &x) const
Checks whether this matrix is a superset of another interval matrix.
Definition codac2_MatrixBase_addons_IntervalMatrixBase.h:832
bool contains(const Matrix< double, RowsAtCompileTime, ColsAtCompileTime > &x) const
Checks if this interval matrix contains the specified matrix x.
Definition codac2_MatrixBase_addons_IntervalMatrixBase.h:382
Definition codac2_OctaSym.h:21
std::ostream & operator<<(std::ostream &os, const BoolInterval &x)
Streams out a BoolInterval.
Definition codac2_BoolInterval.h:131