ZonoOpt v2.0.1
Loading...
Searching...
No Matches
Intervals.hpp
Go to the documentation of this file.
1#ifndef ZONOOPT_INTERVAL_UTILITIES_HPP_
2#define ZONOOPT_INTERVAL_UTILITIES_HPP_
3
15#include <limits>
16#include <string>
17#include <vector>
18#include <set>
19#include <cmath>
20#include <cassert>
21#include <Eigen/Dense>
22#include <Eigen/Sparse>
23
24/*
25Reference:
26"Applied Interval Analysis"
27Luc Jaulin, Michel Kieffer, Olivier Didrit, Eric Walter
28*/
29
30namespace ZonoOpt {
31
32 using namespace detail;
33
34 // forward declarations
35 struct Interval;
36 struct IntervalView;
37
38
46 template <typename Derived>
48 {
53 zono_float& y_min() { return static_cast<Derived*>(this)->get_y_min(); }
54
59 zono_float& y_max() { return static_cast<Derived*>(this)->get_y_max(); }
60
65 const zono_float& y_min() const { return static_cast<const Derived*>(this)->get_y_min(); }
66
71 const zono_float& y_max() const { return static_cast<const Derived*>(this)->get_y_max(); }
72
78 void set(const zono_float min, const zono_float max)
79 {
80 y_min() = min;
81 y_max() = max;
82 }
83
89 void add_assign(const Derived& x1, const Derived& x2)
90 {
91 y_min() = x1.y_min() + x2.y_min();
92 y_max() = x1.y_max() + x2.y_max();
93 }
94
100 void subtract_assign(const Derived& x1, const Derived& x2)
101 {
102 y_min() = x1.y_min() - x2.y_max();
103 y_max() = x1.y_max() - x2.y_min();
104 }
105
111 void multiply_assign(const Derived& x1, const Derived& x2)
112 {
113 zono_float a = x1.y_min() * x2.y_min();
114 zono_float b = x1.y_min() * x2.y_max();
115 zono_float c = x1.y_max() * x2.y_min();
116 zono_float d = x1.y_max() * x2.y_max();
117
118 y_min() = std::min({a, b, c, d});
119 y_max() = std::max({a, b, c, d});
120 }
121
128 {
129 if (alpha >= 0)
130 {
131 y_min() = x1.y_min() * alpha;
132 y_max() = x1.y_max() * alpha;
133 }
134 else
135 {
136 y_min() = x1.y_max() * alpha;
137 y_max() = x1.y_min() * alpha;
138 }
139 }
140
144 void inverse()
145 {
146 auto& min = y_min();
147 auto& max = y_max();
148
149 if (std::abs(min) < zono_eps && std::abs(max) < zono_eps)
150 {
151 min = std::numeric_limits<zono_float>::infinity();
152 max = -std::numeric_limits<zono_float>::infinity();
153 }
154 else if (min > 0 || max < 0)
155 {
156 min = one / max;
157 max = one / min;
158 }
159 else if (std::abs(min) < zono_eps && max > 0)
160 {
161 min = one / max;
162 max = std::numeric_limits<zono_float>::infinity();
163 }
164 else if (min < 0 && std::abs(max) < zono_eps)
165 {
166 max = one / min;
167 min = -std::numeric_limits<zono_float>::infinity();
168 }
169 else
170 {
171 min = -std::numeric_limits<zono_float>::infinity();
172 max = std::numeric_limits<zono_float>::infinity();
173 }
174 }
175
181 void divide_assign(const Derived& x1, const Derived& x2)
182 {
183 Derived inv = x2;
184 inv.inverse();
185 multiply_assign(x1, inv);
186 }
187
193 void intersect_assign(const Derived& x1, const Derived& x2)
194 {
195 y_min() = std::max(x1.y_min(), x2.y_min());
196 y_max() = std::min(x1.y_max(), x2.y_max());
197 }
198
203 bool is_empty() const
204 {
205 return y_min() - y_max() > zono_eps;
206 }
207
214 {
215 return y >= y_min() - zono_eps && y <= y_max() + zono_eps;
216 }
217
222 bool is_single_valued() const
223 {
224 return std::abs(y_max() - y_min()) < zono_eps;
225 }
226
232 {
233 return std::abs(y_max() - y_min());
234 }
235
240 void sin_assign(const Derived& x)
241 {
242 if (x.y_max() - x.y_min() >= two*pi)
243 {
244 y_max() = one;
245 y_min() = -one;
246 }
247 else
248 {
249 // shift domain to [-pi, pi]
250 zono_float u = x.y_max(); // init
251 zono_float l = x.y_min(); // init
252 while (u > pi)
253 {
254 u -= two*pi;
255 l -= two*pi;
256 }
257 while (l < -pi)
258 {
259 u += two*pi;
260 l += two*pi;
261 }
262
263 // get bounds
264 y_max() = ((l < pi/two && pi/two < u) || (l < -3*pi/two && -3*pi/two < u)) ? one : std::max(std::sin(u), std::sin(l));
265 y_min() = ((l < -pi/two && -pi/two < u) || (l < 3*pi/two && 3*pi/two < u)) ? -one : std::min(std::sin(u), std::sin(l));
266 }
267 }
268
273 void cos_assign(const Derived& x)
274 {
276 x_sin.set(x.y_min() + pi/two, x.y_max() + pi/two);
278 }
279
284 void tan_assign(const Derived& x)
285 {
286 if (x.y_max() - x.y_min() >= pi)
287 {
288 y_max() = std::numeric_limits<zono_float>::infinity();
289 y_min() = -std::numeric_limits<zono_float>::infinity();
290 }
291 else
292 {
293 // shift domain to [-pi, pi]
294 zono_float u = x.y_max(); // init
295 zono_float l = x.y_min(); // init
296 while (u > pi)
297 {
298 u -= two*pi;
299 l -= two*pi;
300 }
301 while (l < -pi)
302 {
303 u += two*pi;
304 l += two*pi;
305 }
306
307 // get bounds
308 if ((l < -pi/two && -pi/two < u) || (l < pi/two && pi/two < u))
309 {
310 y_max() = std::numeric_limits<zono_float>::infinity();
311 y_min() = -std::numeric_limits<zono_float>::infinity();
312 }
313 else
314 {
315 y_max() = std::tan(u);
316 y_min() = std::tan(l);
317 }
318 }
319 }
320
325 void arcsin_assign(const Derived& x)
326 {
327 assert(x.y_min() >= -one && x.y_min() <= one);
328 assert(x.y_max() >= -one && x.y_max() <= one);
329 y_min() = std::asin(x.y_min());
330 y_max() = std::asin(x.y_max());
331 }
332
337 void arccos_assign(const Derived& x)
338 {
339 assert(x.y_min() >= -one && x.y_min() <= one);
340 assert(x.y_max() >= -one && x.y_max() <= one);
341 y_min() = std::acos(x.y_max());
342 y_max() = std::acos(x.y_min());
343 }
344
349 void arctan_assign(const Derived& x)
350 {
351 y_min() = std::atan(x.y_min());
352 y_max() = std::atan(x.y_max());
353 }
354
359 void exp_assign(const Derived& x)
360 {
361 y_min() = std::exp(x.y_min());
362 y_max() = std::exp(x.y_max());
363 }
364 };
365
371 struct Interval : IntervalBase<Interval>
372 {
373 // members
376
379
380 // constructor
384 Interval() : lb(0), ub(0) {}
385
392
398 {
399 return new Interval(*this);
400 }
401
402 // get methods
403
408 zono_float& get_y_min() { return lb; }
409
414 zono_float& get_y_max() { return ub; }
415
420 const zono_float& get_y_min() const { return lb; }
421
426 const zono_float& get_y_max() const { return ub; }
427
428 // operators
429
436 {
438 result.add_assign(*this, other);
439 return result;
440 }
441
448 {
451 return result;
452 }
453
460 {
463 return result;
464 }
465
472 {
475 return result;
476 }
477
482 Interval inv() const
483 {
484 Interval result = *this;
485 result.inverse();
486 return result;
487 }
488
495 {
497 result.divide_assign(*this, other);
498 return result;
499 }
500
507 {
510 return result;
511 }
512
518 {
519 return (ub + lb) / two;
520 }
521
522 // as interval view
528
529 // print methods
534 std::string print() const
535 {
536 return "Interval: [" + std::to_string(lb) + ", " + std::to_string(ub) + "]";
537 }
538
545 friend std::ostream& operator<<(std::ostream& os, const Interval& interval)
546 {
547 os << interval.print();
548 return os;
549 }
550
555 Interval sin() const
556 {
558 result.sin_assign(*this);
559 return result;
560 }
561
566 Interval cos() const
567 {
569 result.cos_assign(*this);
570 return result;
571 }
572
577 Interval tan() const
578 {
580 result.tan_assign(*this);
581 return result;
582 }
583
589 {
591 result.arcsin_assign(*this);
592 return result;
593 }
594
600 {
602 result.arccos_assign(*this);
603 return result;
604 }
605
611 {
613 result.arctan_assign(*this);
614 return result;
615 }
616
621 Interval exp() const
622 {
624 result.exp_assign(*this);
625 return result;
626 }
627 };
628
634 struct IntervalView : IntervalBase<IntervalView>
635 {
636 // members
637
639 zono_float* lb_ptr = nullptr;
640
642 zono_float* ub_ptr = nullptr;
643
644 // constructor
645
652
653 // assignment
654
661 template <typename Derived>
663 {
664 y_min() = other.y_min();
665 y_max() = other.y_max();
666 return *this;
667 }
668
669 // to Interval
674 Interval to_interval() const;
675
676 // methods
677
683
689
694 const zono_float& get_y_min() const { return *lb_ptr; }
695
700 const zono_float& get_y_max() const { return *ub_ptr; }
701 };
702
703 // implementations
705 {
706 return Interval(*lb_ptr, *ub_ptr);
707 }
708
710 {
711 return IntervalView(&lb, &ub);
712 }
713
717 class Box
718 {
719 public:
720
721 // constructors
722
726 Box() = default;
727
732 explicit Box(const size_t size);
733
738 explicit Box(const std::vector<Interval>& vals);
739
745 Box(const Eigen::Vector<zono_float, -1>& x_lb, const Eigen::Vector<zono_float, -1>& x_ub);
746
747 // virtual destructor
751 virtual ~Box() = default;
752
753 // copy assignment
759 Box& operator=(const Box& other);
760
761 // copy constructor
766 Box(const Box& other);
767
768 // element-wise assignment, access
769
775 IntervalView operator[](size_t i);
776
782 Interval operator[](size_t i) const;
787 size_t size() const;
788
789 // project onto box
790
795 virtual void project(Eigen::Ref<Eigen::Vector<zono_float, -1>> x) const;
796
801 virtual Box* clone() const;
802
803 // access bounds
808 const Eigen::Vector<zono_float, -1>& lower() const { return x_lb; }
809
814 const Eigen::Vector<zono_float, -1>& upper() const { return x_ub; }
815
816 // width of box
823 zono_float width() const;
824
829 Eigen::Vector<zono_float, -1> center() const;
830
831 // operator overloading
832
838 Box operator+(const Box& other) const;
839
845 Box operator-(const Box& other) const;
846
852 Box operator*(const Box& other) const;
853
859 Box operator*(zono_float alpha) const;
860
866 Box operator/(const Box& other) const;
867
868 // interval contractors
869
881 bool contract(const Eigen::SparseMatrix<zono_float, Eigen::RowMajor>& A, const Eigen::Vector<zono_float, -1>& b, int iter);
882
896 bool contract_subset(const Eigen::SparseMatrix<zono_float, Eigen::RowMajor>& A_rm, const Eigen::Vector<zono_float, -1>& b, int iter,
897 const Eigen::SparseMatrix<zono_float>& A, const std::set<int>& inds, int tree_search_depth);
898
904 Box linear_map(const Eigen::Matrix<zono_float, -1, -1>& A) const;
905
911 Box linear_map(const Eigen::SparseMatrix<zono_float, Eigen::RowMajor>& A) const;
912
918 Interval dot(const Eigen::Vector<zono_float, -1>& x) const;
919
924 void permute(const Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic>& P);
925
930 std::string print() const;
931
938 friend std::ostream& operator<<(std::ostream& os, const Box& box);
939
940 protected:
941
942 // members
944 Eigen::Vector<zono_float, -1> x_lb;
945
947 Eigen::Vector<zono_float, -1> x_ub;
948
949 private:
950
951 // back end for contraction operator
952
961 bool contract_helper(const Eigen::SparseMatrix<zono_float, Eigen::RowMajor>& A, const Eigen::Vector<zono_float, -1>& b, const int iter,
962 const std::set<int>& constraints);
963
974 void get_vars_cons(const Eigen::SparseMatrix<zono_float>& A, const Eigen::SparseMatrix<zono_float, Eigen::RowMajor>& A_rm,
975 std::set<int>& constraints, std::set<int>& vars, const std::set<int>& new_vars, int depth, int max_depth);
976 };
977
978} // namespace ZonoOpt
979
980
981#endif
Box (i.e., interval vector) class.
Definition Intervals.hpp:718
IntervalView operator[](size_t i)
Element-wise access, used for assignment.
Definition Intervals.cpp:49
Interval dot(const Eigen::Vector< zono_float, -1 > &x) const
Linear map with vector.
Definition Intervals.cpp:233
std::string print() const
Print method.
Definition Intervals.cpp:254
Box linear_map(const Eigen::Matrix< zono_float, -1, -1 > &A) const
Linear map of box based on interval arithmetic.
Definition Intervals.cpp:191
Eigen::Vector< zono_float, -1 > x_ub
vector of upper bounds
Definition Intervals.hpp:947
Eigen::Vector< zono_float, -1 > x_lb
vector of lower bounds
Definition Intervals.hpp:944
Box operator/(const Box &other) const
elementwise division
Definition Intervals.cpp:146
Box & operator=(const Box &other)
Copy assignment.
Definition Intervals.cpp:33
Box()=default
Default constructor.
virtual void project(Eigen::Ref< Eigen::Vector< zono_float, -1 > > x) const
Projects vector onto the Box.
Definition Intervals.cpp:68
const Eigen::Vector< zono_float, -1 > & upper() const
Get upper bounds.
Definition Intervals.hpp:814
bool contract_subset(const Eigen::SparseMatrix< zono_float, Eigen::RowMajor > &A_rm, const Eigen::Vector< zono_float, -1 > &b, int iter, const Eigen::SparseMatrix< zono_float > &A, const std::set< int > &inds, int tree_search_depth)
Interval contractor over a subset of the dimensions of the box.
Definition Intervals.cpp:174
Eigen::Vector< zono_float, -1 > center() const
get center of box
Definition Intervals.cpp:90
void permute(const Eigen::PermutationMatrix< Eigen::Dynamic, Eigen::Dynamic > &P)
Permutes in place using permutation matrix, i.e., [x] <- P*[x].
Definition Intervals.cpp:248
size_t size() const
get size of Box object
Definition Intervals.cpp:63
friend std::ostream & operator<<(std::ostream &os, const Box &box)
print to ostream
Definition Intervals.cpp:265
Box operator-(const Box &other) const
elementwise subtraction
Definition Intervals.cpp:112
virtual Box * clone() const
Clone operation.
Definition Intervals.cpp:75
Box operator*(const Box &other) const
elementwise multiplication
Definition Intervals.cpp:124
zono_float width() const
Get width of box.
Definition Intervals.cpp:80
bool contract(const Eigen::SparseMatrix< zono_float, Eigen::RowMajor > &A, const Eigen::Vector< zono_float, -1 > &b, int iter)
Interval contractor.
Definition Intervals.cpp:158
virtual ~Box()=default
Virtual destructor.
const Eigen::Vector< zono_float, -1 > & lower() const
Get lower bounds.
Definition Intervals.hpp:808
Box operator+(const Box &other) const
elementwise addition
Definition Intervals.cpp:100
#define zono_float
Defines the floating-point type used in ZonoOpt.
Definition ZonoOpt.hpp:45
#define zono_eps
Defines the precision used for floating point comparisons in ZonoOpt.
Definition ZonoOpt.hpp:53
Definition ZonoOpt.hpp:58
Base class for Interval and IntervalView.
Definition Intervals.hpp:48
void add_assign(const Derived &x1, const Derived &x2)
sets interval to x1 + x2
Definition Intervals.hpp:89
void arccos_assign(const Derived &x)
compute interval containing arccos(x) over x
Definition Intervals.hpp:337
void cos_assign(const Derived &x)
compute interval containing cos(x) over x
Definition Intervals.hpp:273
void inverse()
sets interval to its inverse
Definition Intervals.hpp:144
void subtract_assign(const Derived &x1, const Derived &x2)
sets interval to x1 - x2
Definition Intervals.hpp:100
void divide_assign(const Derived &x1, const Derived &x2)
sets interval to x1 / x2
Definition Intervals.hpp:181
void arctan_assign(const Derived &x)
compute interval containing arctan(x) over x
Definition Intervals.hpp:349
void set(const zono_float min, const zono_float max)
Sets interval bounds.
Definition Intervals.hpp:78
zono_float & y_max()
Returns reference to interval upper bound.
Definition Intervals.hpp:59
void sin_assign(const Derived &x)
compute interval containing sin(x) over x
Definition Intervals.hpp:240
void intersect_assign(const Derived &x1, const Derived &x2)
sets interval to intersection of x1 and x2
Definition Intervals.hpp:193
void exp_assign(const Derived &x)
compute interval containing exp(x) over x
Definition Intervals.hpp:359
void multiply_assign(const Derived &x1, const Derived &x2)
sets interval to x1 * x2
Definition Intervals.hpp:111
zono_float & y_min()
Returns reference to interval lower bound.
Definition Intervals.hpp:53
void tan_assign(const Derived &x)
compute interval containing tan(x) over x
Definition Intervals.hpp:284
void arcsin_assign(const Derived &x)
compute interval containing arcsin(x) over x
Definition Intervals.hpp:325
bool is_single_valued() const
checks whether interval is single-valued (i.e., width is 0 within numerical tolerance)
Definition Intervals.hpp:222
zono_float width() const
get width of interval (ub - lb)
Definition Intervals.hpp:231
const zono_float & y_min() const
Returns const reference to interval lower bound.
Definition Intervals.hpp:65
void multiply_assign(const Derived &x1, zono_float alpha)
sets interval to alpha * x1
Definition Intervals.hpp:127
bool contains(zono_float y) const
checks whether interval contains a value
Definition Intervals.hpp:213
bool is_empty() const
checks whether interval is empty
Definition Intervals.hpp:203
const zono_float & y_max() const
Returns const reference to interval upper bound.
Definition Intervals.hpp:71
IntervalView class.
Definition Intervals.hpp:635
zono_float & get_y_min()
get reference to lower bound
Definition Intervals.hpp:682
IntervalView & operator=(const IntervalBase< Derived > &other)
Assignment operator.
Definition Intervals.hpp:662
const zono_float & get_y_max() const
get const reference to upper bound
Definition Intervals.hpp:700
zono_float & get_y_max()
get reference to upper bound
Definition Intervals.hpp:688
Interval to_interval() const
convert to Interval class
Definition Intervals.hpp:704
const zono_float & get_y_min() const
get const reference to lower bound
Definition Intervals.hpp:694
zono_float * lb_ptr
pointer to lower bound
Definition Intervals.hpp:639
IntervalView(zono_float *y_min, zono_float *y_max)
constructor for IntervalView
Definition Intervals.hpp:651
zono_float * ub_ptr
pointer to upper bound
Definition Intervals.hpp:642
Interval class.
Definition Intervals.hpp:372
Interval(zono_float y_min, zono_float y_max)
Interval constructor.
Definition Intervals.hpp:391
const zono_float & get_y_max() const
get const reference to upper bound
Definition Intervals.hpp:426
std::string print() const
print method for Interval
Definition Intervals.hpp:534
zono_float & get_y_max()
get reference to upper bound
Definition Intervals.hpp:414
Interval()
default constructor
Definition Intervals.hpp:384
Interval intersect(const Interval &other) const
interval intersection
Definition Intervals.hpp:506
Interval arctan() const
compute interval containing arctan(x) for all x in interval
Definition Intervals.hpp:610
Interval exp() const
compute interval containing exp(x) for all x in interval
Definition Intervals.hpp:621
Interval operator+(const Interval &other) const
interval addition
Definition Intervals.hpp:435
Interval arcsin() const
compute interval containing arcsin(x) for all x in interval
Definition Intervals.hpp:588
Interval operator*(zono_float alpha) const
interval multiplication with scalar
Definition Intervals.hpp:471
zono_float lb
lower bound
Definition Intervals.hpp:375
Interval operator*(const Interval &other) const
interval multiplication
Definition Intervals.hpp:459
IntervalView as_view()
IntervalView interface for Interval.
Definition Intervals.hpp:709
const zono_float & get_y_min() const
get const reference to lower bound
Definition Intervals.hpp:420
friend std::ostream & operator<<(std::ostream &os, const Interval &interval)
print to ostream
Definition Intervals.hpp:545
Interval tan() const
compute interval containing tan(x) for all x in interval
Definition Intervals.hpp:577
Interval inv() const
interval inverse
Definition Intervals.hpp:482
Interval operator-(const Interval &other) const
interval subtraction
Definition Intervals.hpp:447
Interval operator/(const Interval &other) const
interval division
Definition Intervals.hpp:494
zono_float center() const
get center of interval
Definition Intervals.hpp:517
zono_float ub
upper bound
Definition Intervals.hpp:378
zono_float & get_y_min()
get reference to lower bound
Definition Intervals.hpp:408
Interval sin() const
compute interval containing sin(x) for all x in interval
Definition Intervals.hpp:555
Interval cos() const
compute interval containing cos(x) for all x in interval
Definition Intervals.hpp:566
Interval * clone() const
Clone Interval object.
Definition Intervals.hpp:397
Interval arccos() const
compute interval containing arccos(x) for all x in interval
Definition Intervals.hpp:599