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