codac  1.5.7
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 
26 namespace 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 += std::log((this->data()+i)->diam());
387  }
388  return std::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 IntervalMatrix operator&(const IntervalMatrix &x, const IntervalMatrix &y)
const Trajectory log(const Trajectory &x)
const Trajectory min(const Trajectory &y, const Trajectory &x)
const Trajectory exp(const Trajectory &x)
const IntervalMatrix operator|(const IntervalMatrix &x, const IntervalMatrix &y)