codac 1.5.6
Loading...
Searching...
No Matches
codac2_IntervalMatrix.h
Go to the documentation of this file.
1
17#ifndef __CODAC2_INTERVALMATRIX_H__
18#define __CODAC2_INTERVALMATRIX_H__
19
20#include <math.h>
21#include <codac2_Interval.h>
22#include <codac2_eigen.h>
23#include <ibex_LargestFirst.h>
24#include <codac2_Matrix.h>
25
26namespace codac2
27{
28 using Eigen::Dynamic;
29
30 template<int R=Dynamic,int C=Dynamic>
31 class IntervalMatrix_ : public Eigen::Matrix<Interval,R,C>
32 {
33 public:
34
35 IntervalMatrix_()
36 : Eigen::Matrix<Interval,R,C>()
37 {
38
39 }
40
41 explicit IntervalMatrix_(size_t nb_rows, size_t nb_cols)
42 : Eigen::Matrix<Interval,R,C>(nb_rows, nb_cols)
43 {
44 assert(R == Dynamic || R == (int)nb_rows);
45 assert(C == Dynamic || C == (int)nb_cols);
46 }
47
48 explicit IntervalMatrix_(size_t nb_rows, size_t nb_cols, const Interval& x)
49 : IntervalMatrix_<R,C>(nb_rows, nb_cols)
50 {
51 init(x);
52 }
53
54 explicit IntervalMatrix_(size_t nb_rows, size_t nb_cols, const double bounds[][2])
55 : IntervalMatrix_<R,C>(nb_rows, nb_cols)
56 {
57 size_t k = 0;
58 for(size_t i = 0 ; i < nb_rows ; i++)
59 for(size_t j = 0 ; j < nb_cols ; j++)
60 {
61 if(bounds == 0) // in case the user called IntervalMatrix_(r,c,0) and 0 is interpreted as NULL!
62 (*this)(i,j) = Interval::zero();
63 else
64 (*this)(i,j) = Interval(bounds[k][0],bounds[k][1]);
65 k++;
66 }
67 assert(k == this->size());
68 }
69
70 explicit IntervalMatrix_(const double bounds[][2])
71 : IntervalMatrix_<R,C>(R, C, bounds)
72 { }
73
74 explicit IntervalMatrix_(const Matrix_<R,C>& lb, const Matrix_<R,C>& ub)
75 : IntervalMatrix_<R,C>(lb.rows(), lb.cols())
76 {
77 assert(lb.rows() == ub.rows() && lb.cols() == ub.cols());
78 for(size_t i = 0 ; i < this->rows() ; i++)
79 for(size_t j = 0 ; j < this->cols() ; j++)
80 (*this)(i,j) = Interval(lb(i,j),ub(i,j));
81 }
82
83 explicit IntervalMatrix_(const IntervalMatrix_<R,C>& x)
84 : IntervalMatrix_<R,C>(x.rows(), x.cols())
85 {
86 for(size_t i = 0 ; i < size() ; i++)
87 *(this->data()+i) = *(x.data()+i);
88 }
89
90 IntervalMatrix_(std::initializer_list<std::initializer_list<Interval>> l)
91 : IntervalMatrix_<R,C>()
92 {
93 assert((R == Dynamic || (int)l.size() == R) && "ill-formed matrix");
94 int cols = -1;
95 for(const auto& ri : l) {
96 assert((cols == -1 || cols == (int)ri.size()) && "ill-formed matrix");
97 cols = (int)ri.size();
98 }
99 this->resize(l.size(),cols);
100 size_t i = 0;
101 for(const auto& ri : l)
102 {
103 size_t j = 0;
104 for(const auto& ci : ri)
105 (*this)(i,j++) = ci;
106 i++;
107 }
108 }
109
110 // This constructor allows you to construct IntervalMatrix_ from Eigen expressions
111 template<typename OtherDerived>
112 IntervalMatrix_(const Eigen::MatrixBase<OtherDerived>& other)
113 : Eigen::Matrix<Interval,R,C>(other.template cast<Interval>())
114 { }
115
116 // This method allows you to assign Eigen expressions to IntervalMatrix_
117 template<typename OtherDerived>
118 IntervalMatrix_& operator=(const Eigen::MatrixBase<OtherDerived>& other)
119 {
120 this->Eigen::Matrix<Interval,R,C>::operator=(other);
121 return *this;
122 }
123
124 constexpr size_t size() const
125 {
126 return this->Eigen::Matrix<Interval,R,C>::size();
127 }
128
129 void resize(size_t nb_rows, size_t nb_cols)
130 {
131 // With resize of Eigen, the data is reallocated and all previous values are lost.
132 auto copy = *this;
133 this->Eigen::Matrix<Interval,R,C>::resize(nb_rows, nb_cols);
134 for(size_t i = 0 ; i < std::min((size_t)copy.rows(),nb_rows) ; i++)
135 for(size_t j = 0 ; j < std::min((size_t)copy.cols(),nb_cols) ; j++)
136 (*this)(i,j) = copy(i,j);
137 }
138
139 bool is_empty() const
140 {
141 for(size_t i = 0 ; i < size() ; i++)
142 if((this->data()+i)->is_empty())
143 return true;
144 return false;
145 }
146
147 static IntervalMatrix_<R,C> empty_set(size_t nb_rows = R, size_t nb_cols = C)
148 {
149 return IntervalMatrix_<R,C>(nb_rows, nb_cols, Interval::empty_set());
150 }
151
152 static IntervalMatrix_ eye()
153 {
154 return Eigen::Matrix<Interval,R,C>::Identity();
155 }
156
157 bool is_flat() const
158 {
159 if(is_empty()) return true;
160 for(size_t i = 0 ; i < size() ; i++)
161 if((this->data()+i)->is_degenerated()) // don't use diam() because of roundoff
162 return true;
163 return false;
164 }
165
166 bool is_unbounded() const
167 {
168 if(is_empty()) return false;
169 for(size_t i = 0 ; i < size() ; i++)
170 if((this->data()+i)->is_unbounded())
171 return true;
172 return false;
173 }
174
175 bool is_subset(const IntervalMatrix_<R,C>& x) const
176 {
177 if(is_empty()) return true;
178 if(x.is_empty()) return false;
179 for(size_t i = 0 ; i < size() ; i++)
180 if(!(this->data()+i)->is_subset(*(x.data()+i)))
181 return false;
182 return true;
183 }
184
185 bool is_strict_subset(const IntervalMatrix_<R,C>& x) const
186 {
187 if(x.is_empty()) return false;
188 if(is_empty()) return true;
189 bool one_dim_strict_subset = false;
190 for(size_t i = 0 ; i < size() ; i++)
191 {
192 if((this->data()+i)->is_strict_subset(*(x.data()+i)))
193 one_dim_strict_subset = true;
194 if(!(this->data()+i)->is_subset(*(x.data()+i)))
195 return false;
196 }
197 return one_dim_strict_subset;
198 }
199
200 bool is_superset(const IntervalMatrix_<R,C>& x) const
201 {
202 return x.is_subset(*this);
203 }
204
205 bool is_strict_superset(const IntervalMatrix_<R,C>& x) const
206 {
207 return x.is_strict_subset(*this);
208 }
209
210 bool contains(const Matrix_<R,C>& x) const
211 {
212 if(is_empty())
213 return false;
214 for(size_t i = 0 ; i < size() ; i++)
215 if(!(this->data()+i)->contains(*(x.data()+i)))
216 return false;
217 return true;
218 }
219
220 bool interior_contains(const IntervalMatrix_<R,C>& x) const
221 {
222 if(is_empty())
223 return false;
224 for(size_t i = 0 ; i < size() ; i++)
225 if(!(this->data()+i)->interior_contains(*(x.data()+i)))
226 return false;
227 return true;
228 }
229
230 bool intersects(const IntervalMatrix_<R,C>& x) const
231 {
232 if(is_empty() || x.is_empty())
233 return false;
234 for(size_t i = 0 ; i < size() ; i++)
235 if(!(this->data()+i)->intersects(*(x.data()+i)))
236 return false;
237 return true;
238 }
239
240 bool overlaps(const IntervalMatrix_<R,C>& x) const
241 {
242 if(is_empty() || x.is_empty())
243 return false;
244 for(size_t i = 0 ; i < size() ; i++)
245 if(!(this->data()+i)->overlaps(*(x.data()+i)))
246 return false;
247 return true;
248 }
249
250 bool is_disjoint(const IntervalMatrix_<R,C>& x) const
251 {
252 if(is_empty() || x.is_empty())
253 return true;
254 for(size_t i = 0 ; i < size() ; i++)
255 if((this->data()+i)->is_disjoint(*(x.data()+i)))
256 return true;
257 return false;
258 }
259
260 bool is_bisectable() const
261 {
262 for(size_t i = 0 ; i < size() ; i++)
263 if((this->data()+i)->is_bisectable())
264 return true;
265 return false;
266 }
267
268 double min_diam() const
269 {
270 return (this->data()+extr_diam_index(true))->diam();
271 }
272
273 double max_diam() const
274 {
275 return (this->data()+extr_diam_index(false))->diam();
276 }
277
278 size_t thinnest_diam_index() const
279 {
280 return extr_diam_index(true);
281 }
282
283 size_t largest_diam_index() const
284 {
285 return extr_diam_index(false);
286 }
287
288 size_t extr_diam_index(bool min) const
289 {
290 // This code originates from the ibex-lib
291 // See: ibex_TemplateVector.h
292 // Author: Gilles Chabert
293
294 double d = min ? POS_INFINITY : -1; // -1 to be sure that even a 0-diameter interval can be selected
295 int selected_index = -1;
296 bool unbounded = false;
297 assert(!this->is_empty() && "Diameter of an empty IntervalVector is undefined");
298
299 size_t i;
300
301 for(i = 0 ; i < this->size() ; i++)
302 {
303 if((this->data()+i)->is_unbounded())
304 {
305 unbounded = true;
306 if(!min) break;
307 }
308 else
309 {
310 double w = (this->data()+i)->diam();
311 if(min ? w<d : w>d)
312 {
313 selected_index = i;
314 d = w;
315 }
316 }
317 }
318
319 if(min && selected_index == -1)
320 {
321 assert(unbounded);
322 // the selected interval is the first one.
323 i = 0;
324 }
325
326 // The unbounded intervals are not considered if we look for the minimal diameter
327 // and some bounded intervals have been found (selected_index!=-1)
328 if(unbounded && (!min || selected_index == -1))
329 {
330 double pt = min ? NEG_INFINITY : POS_INFINITY; // keep the point less/most distant from +oo (we normalize if the lower bound is -oo)
331 selected_index = i;
332 for(; i < this->size() ; i++)
333 {
334 if((this->data()+i)->lb() == NEG_INFINITY)
335 {
336 if((this->data()+i)->ub() == POS_INFINITY)
337 {
338 if(!min)
339 {
340 selected_index = i;
341 break;
342 }
343 }
344 if((min && (-(this->data()+i)->ub() > pt)) || (!min && (-(this->data()+i)->ub() < pt)))
345 {
346 selected_index = i;
347 pt = -(this->data()+i)->ub();
348 }
349 }
350 else if((this->data()+i)->ub() == POS_INFINITY)
351 {
352 if((min && ((this->data()+i)->lb() > pt)) || (!min && ((this->data()+i)->lb() < pt)))
353 {
354 selected_index = i;
355 pt = (this->data()+i)->lb();
356 }
357 }
358 }
359 }
360
361 return selected_index;
362 }
363
364 auto bisect(float ratio = 0.49) const
365 {
366 size_t i = largest_diam_index();
367 assert((this->data()+i)->is_bisectable());
368 assert(Interval(0,1).interior_contains(ratio));
369
370 auto p = std::make_pair(*this,*this);
371 auto pi = (this->data()+i)->bisect(ratio);
372 *(p.first.data()+i) = pi.first;
373 *(p.second.data()+i) = pi.second;
374 return p;
375 }
376
377 double volume() const
378 {
379 if(this->is_empty())
380 return 0.;
381 double v = 0.;
382 for(size_t i = 0 ; i < this->size() ; i++)
383 {
384 if((this->data()+i)->is_unbounded()) return POS_INFINITY;
385 if((this->data()+i)->is_degenerated()) return 0.;
386 v += log((this->data()+i)->diam());
387 }
388 return exp(v);
389 }
390
391 Matrix_<R,C> lb() const
392 {
393 assert(!this->is_empty()); // todo: use nan instead of assert?
394 Matrix_<R,C> lb(this->rows(), this->cols());
395 for(size_t i = 0 ; i < this->size() ; i++)
396 *(lb.data()+i) = (this->data()+i)->lb();
397 return lb;
398 }
399
400 Matrix_<R,C> ub() const
401 {
402 assert(!this->is_empty()); // todo: use nan instead of assert?
403 Matrix_<R,C> ub(this->rows(), this->cols());
404 for(size_t i = 0 ; i < this->size() ; i++)
405 *(ub.data()+i) = (this->data()+i)->ub();
406 return ub;
407 }
408
409 Matrix_<R,C> mid() const
410 {
411 assert(!this->is_empty()); // todo: use nan instead of assert?
412 Matrix_<R,C> mid(this->rows(), this->cols());
413 for(size_t i = 0 ; i < this->size() ; i++)
414 *(mid.data()+i) = (this->data()+i)->mid();
415 return mid;
416 }
417
418 Matrix_<R,C> rad() const
419 {
420 assert(!this->is_empty()); // todo: use nan instead of assert?
421 Matrix_<R,C> rad(this->rows(), this->cols());
422 for(size_t i = 0 ; i < this->size() ; i++)
423 *(rad.data()+i) = (this->data()+i)->rad();
424 return rad;
425 }
426
427 Matrix_<R,C> diam() const
428 {
429 assert(!this->is_empty()); // todo: use nan instead of assert?
430 Matrix_<R,C> diam(this->rows(), this->cols());
431 for(size_t i = 0 ; i < this->size() ; i++)
432 *(diam.data()+i) = (this->data()+i)->diam();
433 return diam;
434 }
435
436 void init(const Interval& x)
437 {
438 for(size_t i = 0 ; i < this->size() ; i++)
439 *(this->data()+i) = x;
440 }
441
442 void set_empty()
443 {
444 init(Interval::empty_set());
445 }
446
447 auto& inflate(double r)
448 {
449 assert(r >= 0.);
450 for(size_t i = 0 ; i < this->size() ; i++)
451 (this->data()+i)->inflate(r);
452 return *this;
453 }
454
455 auto& inflate(const Matrix_<R,C>& r)
456 {
457 assert(r.minCoeff() >= 0.);
458 for(size_t i = 0 ; i < this->size() ; i++)
459 (this->data()+i)->inflate(*(r.data()+i));
460 return *this;
461 }
462
463 bool operator==(const IntervalMatrix_<R,C>& x) const
464 {
465 if(x.size() != this->size() || x.rows() != this->rows() || x.cols() != this->cols())
466 return false;
467 if(is_empty() || x.is_empty())
468 return is_empty() && x.is_empty();
469 for(size_t i = 0 ; i < this->size() ; i++)
470 if(*(this->data()+i) != *(x.data()+i))
471 return false;
472 return true;
473 }
474
475 bool operator!=(const IntervalMatrix_<R,C>& x) const
476 {
477 return !(*this == x);
478 }
479
480 auto& operator&=(const IntervalMatrix_<R,C>& x)
481 {
482 if(!this->is_empty())
483 {
484 if(x.is_empty())
485 this->set_empty();
486 else
487 for(size_t i = 0 ; i < this->size() ; i++)
488 *(this->data()+i) &= *(x.data()+i);
489 }
490 return *this;
491 }
492
493 auto& operator|=(const IntervalMatrix_<R,C>& x)
494 {
495 if(!x.is_empty())
496 {
497 if(this->is_empty())
498 *this = x;
499 else
500 for(size_t i = 0 ; i < this->size() ; i++)
501 *(this->data()+i) |= *(x.data()+i);
502 }
503 return *this;
504 }
505
506 auto operator+(const IntervalMatrix_<R,C>& x) const
507 {
508 auto y = *this;
509 return y += x;
510 }
511
512 auto operator-(const IntervalMatrix_<R,C>& x) const
513 {
514 auto y = *this;
515 return y -= x;
516 }
517
518 auto operator&(const IntervalMatrix_<R,C>& x) const
519 {
520 auto y = *this;
521 return y &= x;
522 }
523
524 auto operator|(const IntervalMatrix_<R,C>& x) const
525 {
526 auto y = *this;
527 return y |= x;
528 }
529
530 auto& operator+=(const IntervalMatrix_<R,C>& x)
531 {
532 (*this).noalias() += x;//.template cast<Interval>();
533 return *this;
534 }
535
536 auto& operator-=(const IntervalMatrix_<R,C>& x)
537 {
538 (*this).noalias() -= x;//.template cast<Interval>();
539 return *this;
540 }
541
542 auto& operator+=(const Matrix_<R,C>& x)
543 {
544 (*this).noalias() += x.template cast<Interval>();
545 return *this;
546 }
547
548 auto& operator-=(const Matrix_<R,C>& x)
549 {
550 (*this).noalias() -= x;//.template cast<Interval>();
551 return *this;
552 }
553 };
554
555 template<int R,int C>
556 std::ostream& operator<<(std::ostream& os, const IntervalMatrix_<R,C>& x)
557 {
558 if(x.is_empty()) return os << "empty matrix";
559 os << "(";
560 for(int i = 0 ; i < x.rows() ; i++)
561 {
562 os << "(";
563 for(int j = 0 ; j < x.cols() ; j++)
564 os << x(i,j) << (j<x.cols()-1 ? " ; " : "");
565 os << ")";
566 if(i < x.rows()-1) os << std::endl;
567 }
568 os << ")";
569 return os;
570 }
571
572 template<int R,int C>
573 auto operator-(const IntervalMatrix_<R,C>& x)
574 {
575 auto y = x;
576 y.init(0.);
577 return y -= x;
578 }
579
580 template<int R,int C>
581 auto operator*(double a, const IntervalMatrix_<R,C>& x)
582 {
583 return Interval(a)*x;
584 }
585
586 class IntervalMatrix : public IntervalMatrix_<>
587 {
588 public:
589
590 explicit IntervalMatrix(size_t nb_rows, size_t nb_cols)
591 : IntervalMatrix_<>(nb_rows, nb_cols)
592 { }
593
594
595 explicit IntervalMatrix(size_t nb_rows, size_t nb_cols, const Interval& x)
596 : IntervalMatrix_<>(nb_rows, nb_cols, x)
597 { }
598
599 explicit IntervalMatrix(size_t nb_rows, size_t nb_cols, const double bounds[][2])
600 : IntervalMatrix_<>(nb_rows, nb_cols, bounds)
601 { }
602
603 IntervalMatrix(const IntervalMatrix_<>& x)
604 : IntervalMatrix_<>(x)
605 { }
606
607 IntervalMatrix(std::initializer_list<std::initializer_list<Interval>> l)
608 : IntervalMatrix_<>(l)
609 { }
610
611 template<int R,int C>
612 explicit IntervalMatrix(const Matrix_<R,C>& v)
613 : IntervalMatrix_<>(v)
614 { }
615
616 static IntervalMatrix empty_set(size_t nb_rows, size_t nb_cols)
617 {
618 return IntervalMatrix_<>::empty_set(nb_rows,nb_cols);
619 }
620 };
621
622} // namespace codac
623
624#endif
const Trajectory log(const Trajectory &x)
const Trajectory min(const Trajectory &y, const Trajectory &x)
const Trajectory exp(const Trajectory &x)