codac 2.0.0
Loading...
Searching...
No Matches
codac2_SlicedTube.h
Go to the documentation of this file.
1
9
10#pragma once
11
12#include "codac2_TDomain.h"
13#include "codac2_Slice.h"
16#include "codac2_CtcDeriv.h"
17
18namespace codac2
19{
20 template<typename T>
21 class SlicedTube : public SlicedTubeBase
22 {
23 public:
24
25 explicit SlicedTube(const std::shared_ptr<TDomain>& tdomain,
26 const T& codomain)
27 : SlicedTubeBase(tdomain)
28 {
29 for(auto it = _tdomain->begin(); it != _tdomain->end(); ++it)
30 it->_slices.insert({
31 this,
32 std::make_shared<Slice<T>>(*this, it, codomain)
33 });
34 }
35
36 explicit SlicedTube(const std::shared_ptr<TDomain>& tdomain,
37 const AnalyticFunction<typename ExprType<T>::Type>& f)
38 : SlicedTubeBase(tdomain)
39 {
40 assert_release(f.args().size() == 1
41 && "function's inputs must be limited to one system variable");
42
43 for(auto it = _tdomain->begin(); it != _tdomain->end(); ++it)
44 it->_slices.insert({
45 this,
46 std::make_shared<Slice<T>>(*this, it, f.eval((Interval)*it))
47 });
48 }
49
50 template<typename V>
51 requires std::is_same_v<typename Wrapper<V>::Domain,T>
52 explicit SlicedTube(const std::shared_ptr<TDomain>& tdomain,
53 const SampledTraj<V>& f)
54 : SlicedTubeBase(tdomain)
55 {
56 for(auto it = _tdomain->begin(); it != _tdomain->end(); ++it)
57 it->_slices.insert({
58 this,
59 std::make_shared<Slice<T>>(*this, it, f((Interval)*it))
60 });
61 }
62
63 SlicedTube(const SlicedTube<T>& x)
64 : SlicedTubeBase(x.tdomain())
65 {
66 for(auto it = _tdomain->begin(); it != _tdomain->end(); ++it)
67 it->_slices.insert({
68 this,
69 std::make_shared<Slice<T>>(*x(it), *this)
70 });
71 }
72
73 inline SlicedTube& operator=(const SlicedTube& x)
74 {
75 assert_release(_tdomain == x._tdomain);
76
77 for(auto it = _tdomain->begin(); it != _tdomain->end(); ++it)
78 (*this)(it)->set(x(it)->codomain(), false);
79
80 return *this;
81 }
82
83 inline Index size() const
84 {
85 return first_slice()->size();
86 }
87
88 inline double volume() const
89 {
90 double volume = 0.;
91 for(const auto& s : *this)
92 if(!s.is_gate())
93 volume += s.volume();
94 return volume;
95 }
96
97 inline std::shared_ptr<Slice<T>> first_slice()
98 {
99 return std::const_pointer_cast<Slice<T>>(
100 static_cast<const SlicedTube&>(*this).first_slice());
101 }
102
103 inline std::shared_ptr<const Slice<T>> first_slice() const
104 {
105 return std::static_pointer_cast<const Slice<T>>(
106 this->SlicedTubeBase::first_slice());
107 }
108
109 inline std::shared_ptr<Slice<T>> last_slice()
110 {
111 return std::const_pointer_cast<Slice<T>>(
112 static_cast<const SlicedTube&>(*this).last_slice());
113 }
114
115 inline std::shared_ptr<const Slice<T>> last_slice() const
116 {
117 return std::static_pointer_cast<const Slice<T>>(
118 this->SlicedTubeBase::last_slice());
119 }
120
121 inline bool is_empty() const
122 {
123 // Fast evaluation by considering gates first, then envelopes,
124 // which allows to quickly identify an empty set
125 for(const auto& s : *this)
126 if(s.is_gate() && s.is_empty())
127 return true;
128 for(const auto& s : *this)
129 if(!s.is_gate() && s.is_empty())
130 return true;
131 return false;
132 }
133
134 inline bool is_unbounded() const
135 {
136 for(const auto& s : *this)
137 if(s.is_unbounded())
138 return true;
139 return false;
140 }
141
142 inline T codomain() const
143 {
144 T x = first_slice()->codomain();
145 for(const auto& s : *this)
146 x |= s.codomain();
147 return x;
148 }
149
150 inline std::shared_ptr<Slice<T>> operator()(const std::list<TSlice>::iterator& it)
151 {
152 return std::const_pointer_cast<Slice<T>>(
153 static_cast<const SlicedTube&>(*this).operator()(it));
154 }
155
156 inline std::shared_ptr<const Slice<T>> operator()(const std::list<TSlice>::const_iterator& it) const
157 {
158 return std::static_pointer_cast<const Slice<T>>(
159 it->slices().at(this));
160 }
161
162 inline std::shared_ptr<Slice<T>> operator()(const std::list<TSlice>::reverse_iterator& it)
163 {
164 return std::const_pointer_cast<Slice<T>>(
165 static_cast<const SlicedTube&>(*this).operator()(it));
166 }
167
168 inline std::shared_ptr<const Slice<T>> operator()(const std::list<TSlice>::const_reverse_iterator& it) const
169 {
170 return std::static_pointer_cast<const Slice<T>>(
171 it->slices().at(this));
172 }
173
174 inline T operator()(double t) const
175 {
176 if(!tdomain()->t0_tf().contains(t))
177 return all_reals_codomain();
178
179 auto it_t = _tdomain->tslice(t);
180 assert(it_t != _tdomain->end());
181 T x = (*this)(it_t)->codomain();
182 if(!it_t->is_gate() && t==it_t->lb() && it_t!=_tdomain->begin())
183 x &= (*this)(--it_t)->codomain();
184 return x;
185 }
186
187 inline T operator()(const Interval& t) const
188 {
189 if(!tdomain()->t0_tf().is_superset(t))
190 return all_reals_codomain();
191
192 if(t.is_degenerated())
193 return (*this)(t.lb());
194
195 auto t_ = t & _tdomain->t0_tf();
196
197 auto it = _tdomain->tslice(t_.lb());
198 T codomain = (*this)(it)->codomain();
199
200 while(it != std::next(_tdomain->tslice(t_.ub())))
201 {
202 if(it->lb() == t_.ub()) break;
203 codomain |= (*this)(it)->codomain();
204 it++;
205 }
206
207 return codomain;
208 }
209
210 std::pair<T,T> enclosed_bounds(const Interval& t) const
211 {
212 auto x = this->empty_codomain();
213 auto bounds = std::make_pair(x,x);
214
215 if(t.lb() < _tdomain->t0_tf().lb() || t.ub() > _tdomain->t0_tf().ub())
216 {
217 x.init(Interval(-oo,0));
218 bounds.first |= x;
219 x.init(Interval(0,oo));
220 bounds.second |= x;
221 }
222
223 Interval t_inter = t & _tdomain->t0_tf();
224 auto si = (*this)(_tdomain->tslice(t_inter.lb()));
225
226 while(si && si->t0_tf().lb() <= t_inter.ub())
227 {
228 auto slice_bounds = si->enclosed_bounds(t_inter & si->t0_tf());
229 bounds.first |= slice_bounds.first;
230 bounds.second |= slice_bounds.second;
231 si = si->next_slice();
232 }
233
234 return bounds;
235 }
236
237 inline void set(const T& codomain)
238 {
239 assert_release(codomain.size() == this->size());
240
241 for(auto& s : *this)
242 if(!s.is_gate())
243 s.set(codomain, false);
244
245 for(auto& s : *this)
246 if(s.is_gate())
247 s.set(codomain, false);
248 }
249
250 inline void set(const T& codomain, double t)
251 {
252 assert_release(codomain.size() == this->size());
253 (*this)(_tdomain->sample(t,true))->set(codomain);
254 }
255
256 inline void set(const T& codomain, const Interval& t)
257 {
258 auto it_lb = _tdomain->sample(t.lb(), t.is_degenerated());
259 std::list<TSlice>::iterator it_ub;
260
261 if(!t.is_degenerated())
262 {
263 it_ub = _tdomain->sample(t.ub(), false);
264
265 if(it_ub->lb() == t.ub())
266 it_ub--; // pointing to the tslice [..,t.ub()]
267
268 if(it_lb->ub() == t.lb())
269 it_lb++;
270 }
271
272 else
273 it_ub = it_lb;
274
275 do
276 {
277 (*this)(it_lb)->set(codomain);
278 } while(it_lb != it_ub && (++it_lb) != _tdomain->end());
279 }
280
281 inline void set_ith_slice(const T& codomain, Index i)
282 {
283 Index j = 0;
284 for(auto& si : *this)
285 if(j++ == i)
286 {
287 si.set(codomain);
288 break;
289 }
290 }
291
292 const SlicedTube<T>& inflate(double rad)
293 {
294 assert_release(rad >= 0.);
295
296 for(auto& s : *this)
297 if(!s.is_gate())
298 s.set(T(s.codomain()).inflate(rad), false);
299
300 for(auto& s : *this)
301 if(s.is_gate())
302 s.set(T(s.codomain()).inflate(rad), false);
303
304 return *this;
305 }
306
307 SlicedTube<Interval> operator[](Index i) const
308 {
309 assert_release(i >= 0 && i < size());
310 SlicedTube<Interval> xi(tdomain(), Interval());
311 for(auto it = tdomain()->begin() ; it != tdomain()->end() ; it++)
312 xi(it)->codomain() = (*this)(it)->codomain()[i];
313 return xi;
314 }
315
316 SlicedTube<IntervalVector> subvector(Index i, Index j) const
317 {
318 assert_release(i >= 0 && i <= j && j < size());
319 SlicedTube<IntervalVector> xij(tdomain(), IntervalVector(j-i+1));
320 for(auto it = tdomain()->begin() ; it != tdomain()->end() ; it++)
321 xij(it)->codomain() = (*this)(it)->codomain().subvector(i,j);
322 return xij;
323 }
324
325 inline bool operator==(const SlicedTube& x) const
326 {
327 if(!TDomain::are_same(tdomain(), x.tdomain()))
328 return false;
329
330 auto it_this = _tdomain->begin();
331 auto it_x = x.tdomain()->cbegin();
332
333 while(it_this != _tdomain->end())
334 if(*(*this)(it_this++) != *x(it_x++))
335 return false;
336
337 return true;
338 }
339
340 inline SlicedTube operator&=(const SlicedTube& x)
341 {
342 assert(TDomain::are_same(tdomain(), x.tdomain()));
343 auto it_this = _tdomain->begin();
344 auto it_x = x.tdomain()->cbegin();
345
346 while(it_this != _tdomain->end())
347 {
348 auto s = (*this)(it_this);
349 s->set(s->codomain() & x(it_x)->codomain());
350 it_this++; it_x++;
351 }
352
353 assert(it_x == x.tdomain()->cend());
354 return *this;
355 }
356
357 friend inline std::ostream& operator<<(std::ostream& os, const SlicedTube<T>& x)
358 {
359 os << x.t0_tf()
360 << "↦" << x.codomain()
361 << ", " << x.nb_slices()
362 << " slice" << (x.nb_slices() > 1 ? "s" : "")
363 << std::flush;
364 return os;
365 }
366
367 // Integral related methods
368
369 T integral(const Interval& t) const;
370 T integral(const Interval& t1, const Interval& t2) const;
371 std::pair<T,T> partial_integral(const Interval& t) const;
372 std::pair<T,T> partial_integral(const Interval& t1, const Interval& t2) const;
373
374 inline SlicedTube<T> primitive() const
375 {
376 auto x = all_reals_codomain();
377 auto p = SlicedTube<T>(this->tdomain(), x);
378 x.init(0.);
379 p.set(x, this->tdomain()->t0_tf().lb()); // may create an unwanted gate
380 CtcDeriv c;
381 c.contract(p,*this);
382 return p;
383 }
384
385
386 public:
387
388 using base_container = std::list<TSlice>;
389
390 struct iterator : public base_container::iterator
391 {
392 public:
393
394 iterator(SlicedTube& x, base_container::iterator it)
395 : base_container::iterator(it), _x(x) { }
396
397 std::shared_ptr<Slice<T>> operator->()
398 {
399 return _x(*this);
400 }
401
402 Slice<T>& operator*()
403 {
404 return *operator->();
405 }
406
407 protected:
408
409 SlicedTube& _x;
410 };
411
412 iterator begin() { return { *this, _tdomain->begin() }; }
413 iterator end() { return { *this, _tdomain->end() }; }
414
415 struct reverse_iterator : public base_container::reverse_iterator
416 {
417 public:
418
419 reverse_iterator(SlicedTube& x, base_container::reverse_iterator it)
420 : base_container::reverse_iterator(it), _x(x) { }
421
422 std::shared_ptr<Slice<T>> operator->()
423 {
424 return _x(*this);
425 }
426
427 Slice<T>& operator*()
428 {
429 return *operator->();
430 }
431
432 protected:
433
434 SlicedTube& _x;
435 };
436
437 reverse_iterator rbegin() { return { *this, _tdomain->rbegin() }; }
438 reverse_iterator rend() { return { *this, _tdomain->rend() }; }
439
440 struct const_iterator : public base_container::const_iterator
441 {
442 public:
443
444 const_iterator(const SlicedTube& x, base_container::const_iterator it)
445 : base_container::const_iterator(it), _x(x) { }
446
447 std::shared_ptr<const Slice<T>> operator->()
448 {
449 return _x(*this);
450 }
451
452 const Slice<T>& operator*()
453 {
454 return *operator->();
455 }
456
457 protected:
458
459 const SlicedTube& _x;
460 };
461
462 const_iterator begin() const { return { *this, _tdomain->cbegin() }; }
463 const_iterator end() const { return { *this, _tdomain->cend() }; }
464
465 struct const_reverse_iterator : public base_container::const_reverse_iterator
466 {
467 public:
468
469 const_reverse_iterator(const SlicedTube& x, base_container::const_reverse_iterator it)
470 : base_container::const_reverse_iterator(it), _x(x) { }
471
472 std::shared_ptr<const Slice<T>> operator->()
473 {
474 return _x(*this);
475 }
476
477 const Slice<T>& operator*()
478 {
479 return *operator->();
480 }
481
482 protected:
483
484 const SlicedTube& _x;
485 };
486
487 const_reverse_iterator rbegin() const { return { *this, _tdomain->crbegin() }; }
488 const_reverse_iterator rend() const { return { *this, _tdomain->crend() }; }
489
490 protected:
491
492 inline T all_reals_codomain() const
493 {
494 T x = first_slice()->codomain();
495 x.init();
496 return x;
497 }
498
499 inline T empty_codomain() const
500 {
501 T x = first_slice()->codomain();
502 x.set_empty();
503 return x;
504 }
505 };
506
507
508 // Template deduction guide:
509
510 template<typename T>
511 SlicedTube(const std::shared_ptr<TDomain>& tdomain, const AnalyticFunction<T>& f) ->
512 SlicedTube<typename Wrapper<T>::Domain>;
513
514 template<typename T>
515 SlicedTube(const std::shared_ptr<TDomain>& tdomain, const SampledTraj<T>& f) ->
516 SlicedTube<typename Wrapper<T>::Domain>;
517}
518
Eigen::Matrix< Interval,-1, 1 > IntervalVector
Alias for a dynamic-size column vector of intervals.
Definition codac2_IntervalVector.h:25
auto lb() const
Returns a matrix containing the lower bounds of each interval element.
Definition codac2_MatrixBase_addons_IntervalMatrixBase.h:91
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:648
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:198
auto rad() const
Returns a matrix containing the radii of each interval element.
Definition codac2_MatrixBase_addons_IntervalMatrixBase.h:171