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