1 /*++
2 Copyright (c) 2006 Microsoft Corporation
3 
4 Module Name:
5 
6     old_interval.cpp
7 
8 Abstract:
9 
10     <abstract>
11 
12 Author:
13 
14     Leonardo de Moura (leonardo) 2008-12-09.
15 
16 Revision History:
17 
18 --*/
19 
20 #include "smt/old_interval.h"
21 
neg()22 void ext_numeral::neg() {
23     switch (m_kind) {
24     case MINUS_INFINITY: m_kind = PLUS_INFINITY; break;
25     case FINITE:         m_value.neg(); break;
26     case PLUS_INFINITY:  m_kind = MINUS_INFINITY; break;
27     }
28 }
29 
operator +=(ext_numeral const & other)30 ext_numeral & ext_numeral::operator+=(ext_numeral const & other) {
31     SASSERT(!is_infinite() || !other.is_infinite() || m_kind == other.m_kind);
32     if (is_infinite())
33         return *this;
34     SASSERT(m_kind == FINITE);
35     switch (other.m_kind) {
36     case MINUS_INFINITY:
37         m_kind = MINUS_INFINITY;
38         m_value.reset();
39         return *this;
40     case FINITE:
41         m_value += other.m_value;
42         return *this;
43     case PLUS_INFINITY:
44         m_kind = PLUS_INFINITY;
45         m_value.reset();
46         return *this;
47     }
48     UNREACHABLE();
49     return *this;
50 }
51 
operator -=(ext_numeral const & other)52 ext_numeral & ext_numeral::operator-=(ext_numeral const & other) {
53     SASSERT(!is_infinite() || !other.is_infinite() || (m_kind != other.m_kind));
54     if (is_infinite())
55         return *this;
56     SASSERT(m_kind == FINITE);
57     switch (other.m_kind) {
58     case MINUS_INFINITY:
59         m_kind = PLUS_INFINITY;
60         m_value.reset();
61         return *this;
62     case FINITE:
63         m_value -= other.m_value;
64         return *this;
65     case PLUS_INFINITY:
66         m_kind = MINUS_INFINITY;
67         m_value.reset();
68         return *this;
69     }
70     UNREACHABLE();
71     return *this;
72 }
73 
operator *=(ext_numeral const & other)74 ext_numeral & ext_numeral::operator*=(ext_numeral const & other) {
75     if (is_zero()) {
76         m_kind = FINITE;
77         return *this;
78     }
79     if (other.is_zero()) {
80         m_kind = FINITE;
81         m_value.reset();
82         return *this;
83     }
84 
85     if (is_infinite() || other.is_infinite()) {
86         if (sign() == other.sign())
87             m_kind = PLUS_INFINITY;
88         else
89             m_kind = MINUS_INFINITY;
90         m_value.reset();
91         return *this;
92     }
93 
94     SASSERT(m_kind == FINITE);
95     m_value *= other.m_value;
96     return *this;
97 }
98 
expt(unsigned n)99 void ext_numeral::expt(unsigned n) {
100     switch (m_kind) {
101     case MINUS_INFINITY:
102         if (n % 2 == 0)
103             m_kind = PLUS_INFINITY;
104         return;
105     case FINITE:
106         m_value = m_value.expt(n);
107         break;
108     case PLUS_INFINITY:
109         // do nothing
110         break;
111     }
112 }
113 
inv()114 void ext_numeral::inv() {
115     SASSERT(!is_zero());
116     if (is_infinite()) {
117         m_kind = FINITE;
118         m_value.reset();
119     }
120     else {
121         m_value = rational(1) / m_value;
122     }
123 }
124 
display(std::ostream & out) const125 void ext_numeral::display(std::ostream & out) const {
126     switch (m_kind) {
127     case MINUS_INFINITY:
128         out << "-oo";
129         break;
130     case FINITE:
131         out << m_value;
132         break;
133     case PLUS_INFINITY:
134         out << "oo";
135         break;
136     }
137 }
138 
operator ==(ext_numeral const & n1,ext_numeral const & n2)139 bool operator==(ext_numeral const & n1, ext_numeral const & n2) {
140     return n1.m_kind == n2.m_kind && (n1.is_infinite() || n1.m_value == n2.m_value);
141 }
142 
operator <(ext_numeral const & n1,ext_numeral const & n2)143 bool operator<(ext_numeral const & n1, ext_numeral const & n2) {
144     if (n1.is_infinite())
145         return n1.m_kind == ext_numeral::MINUS_INFINITY && n2.m_kind != ext_numeral::MINUS_INFINITY;
146     if (n2.is_infinite())
147         return n2.m_kind != ext_numeral::MINUS_INFINITY;
148     return n1.m_value < n2.m_value;
149 }
150 
151 /**
152    \brief Create interval (-oo, oo)
153 */
interval(v_dependency_manager & m)154 interval::interval(v_dependency_manager & m):
155     m_manager(m),
156     m_lower(false),
157     m_upper(true),
158     m_lower_open(true),
159     m_upper_open(true),
160     m_lower_dep(nullptr),
161     m_upper_dep(nullptr) {
162 }
163 
164 /**
165    \brief Create intervals [l,u], (l,u], [l, u), (l,u), where l and u are numerals.
166 */
interval(v_dependency_manager & m,rational const & lower,bool l_open,v_dependency * l_dep,rational const & upper,bool u_open,v_dependency * u_dep)167 interval::interval(v_dependency_manager & m, rational const & lower, bool l_open, v_dependency * l_dep, rational const & upper, bool u_open, v_dependency * u_dep):
168     m_manager(m),
169     m_lower(lower),
170     m_upper(upper),
171     m_lower_open(l_open),
172     m_upper_open(u_open),
173     m_lower_dep(l_dep),
174     m_upper_dep(u_dep) {
175     SASSERT(lower <= upper);
176     SASSERT(lower != upper || !l_open || !u_open);
177 }
178 
179 /**
180    \brief Create intervals [l,u], (l,u], [l, u), (l,u), where l and u are ext_numerals.
181 */
interval(v_dependency_manager & m,ext_numeral const & lower,bool l_open,v_dependency * l_dep,ext_numeral const & upper,bool u_open,v_dependency * u_dep)182 interval::interval(v_dependency_manager & m, ext_numeral const & lower, bool l_open, v_dependency * l_dep, ext_numeral const & upper, bool u_open, v_dependency * u_dep):
183     m_manager(m),
184     m_lower(lower),
185     m_upper(upper),
186     m_lower_open(l_open),
187     m_upper_open(u_open),
188     m_lower_dep(l_dep),
189     m_upper_dep(u_dep) {
190     SASSERT(lower <= upper);
191     SASSERT(lower != upper || !l_open || !u_open);
192 }
193 
194 /**
195    \brief Create interval [val,val]
196 */
interval(v_dependency_manager & m,rational const & val,v_dependency * l_dep,v_dependency * u_dep)197 interval::interval(v_dependency_manager & m, rational const & val, v_dependency * l_dep, v_dependency * u_dep):
198     m_manager(m),
199     m_lower(val),
200     m_upper(val),
201     m_lower_open(false),
202     m_upper_open(false),
203     m_lower_dep(l_dep),
204     m_upper_dep(u_dep) {
205 }
206 
207 /**
208    \brief Create intervals (-oo, val], (-oo, val), [val, oo), (val, oo)
209 */
interval(v_dependency_manager & m,rational const & val,bool open,bool lower,v_dependency * d)210 interval::interval(v_dependency_manager & m, rational const & val, bool open, bool lower, v_dependency * d):
211     m_manager(m) {
212     if (lower) {
213         m_lower      = ext_numeral(val);
214         m_lower_open = open;
215         m_lower_dep  = d;
216         m_upper      = ext_numeral(true);
217         m_upper_open = true;
218         m_upper_dep  = nullptr;
219     }
220     else {
221         m_lower      = ext_numeral(false);
222         m_lower_open = true;
223         m_lower_dep  = nullptr;
224         m_upper      = ext_numeral(val);
225         m_upper_open = open;
226         m_upper_dep  = d;
227     }
228 }
229 
operator =(interval const & other)230 interval & interval::operator=(interval const & other) {
231     SASSERT(&m_manager == &other.m_manager);
232     m_lower = other.m_lower;
233     m_upper = other.m_upper;
234     m_lower_open = other.m_lower_open;
235     m_upper_open = other.m_upper_open;
236     m_lower_dep  = other.m_lower_dep;
237     m_upper_dep  = other.m_upper_dep;
238     return *this;
239 }
240 
operator =(interval && other)241 interval & interval::operator=(interval && other) {
242     SASSERT(&m_manager == &other.m_manager);
243     m_lower = std::move(other.m_lower);
244     m_upper = std::move(other.m_upper);
245     m_lower_open = other.m_lower_open;
246     m_upper_open = other.m_upper_open;
247     m_lower_dep  = other.m_lower_dep;
248     m_upper_dep  = other.m_upper_dep;
249     return *this;
250 }
251 
operator +=(interval const & other)252 interval & interval::operator+=(interval const & other) {
253     m_lower      += other.m_lower;
254     m_upper      += other.m_upper;
255     m_lower_open |= other.m_lower_open;
256     m_upper_open |= other.m_upper_open;
257     m_lower_dep   = m_lower.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, other.m_lower_dep);
258     m_upper_dep   = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_upper_dep, other.m_upper_dep);
259     return *this;
260 }
261 
neg()262 void interval::neg() {
263     std::swap(m_lower, m_upper);
264     std::swap(m_lower_open, m_upper_open);
265     std::swap(m_lower_dep, m_upper_dep);
266     m_lower.neg();
267     m_upper.neg();
268 }
269 
operator -=(interval const & other)270 interval & interval::operator-=(interval const & other) {
271     interval tmp(other);
272     tmp.neg();
273     return operator+=(tmp);
274 }
275 
join(v_dependency * d1,v_dependency * d2,v_dependency * d3,v_dependency * d4)276 v_dependency * interval::join(v_dependency * d1, v_dependency * d2, v_dependency * d3, v_dependency * d4) {
277     return m_manager.mk_join(m_manager.mk_join(d1, d2), m_manager.mk_join(d3,d4));
278 }
279 
280 /**
281    \brief Create a new v_dependency using d1, d2, and (opt1 or opt2).
282 */
join_opt(v_dependency * d1,v_dependency * d2,v_dependency * opt1,v_dependency * opt2)283 v_dependency * interval::join_opt(v_dependency * d1, v_dependency * d2, v_dependency * opt1, v_dependency * opt2) {
284     if (opt1 == d1 || opt1 == d2)
285         return join(d1, d2);
286     if (opt2 == d1 || opt2 == d2)
287         return join(d1, d2);
288     if (opt1 == nullptr || opt2 == nullptr)
289         return join(d1, d2);
290     // TODO: more opts...
291     return join(d1, d2, opt1);
292 }
293 
operator *=(interval const & other)294 interval & interval::operator*=(interval const & other) {
295 #if Z3DEBUG || _TRACE
296     bool contains_zero1 = contains_zero();
297     bool contains_zero2 = other.contains_zero();
298 #endif
299     if (is_zero()) {
300         return *this;
301     }
302     if (other.is_zero()) {
303         *this = other;
304         m_lower_dep = m_manager.mk_join(m_lower_dep, m_upper_dep);
305         m_upper_dep = m_lower_dep;
306         return *this;
307     }
308 
309     ext_numeral const & a = m_lower;
310     ext_numeral const & b = m_upper;
311     ext_numeral const & c = other.m_lower;
312     ext_numeral const & d = other.m_upper;
313     bool a_o = m_lower_open;
314     bool b_o = m_upper_open;
315     bool c_o = other.m_lower_open;
316     bool d_o = other.m_upper_open;
317     v_dependency * a_d = m_lower_dep;
318     v_dependency * b_d = m_upper_dep;
319     v_dependency * c_d = other.m_lower_dep;
320     v_dependency * d_d = other.m_upper_dep;
321 
322     TRACE("interval_bug", tout << "operator*= " << *this << " " << other << "\n";);
323 
324     if (is_N()) {
325         if (other.is_N()) {
326             // x <= b <= 0, y <= d <= 0 --> b*d <= x*y
327             // a <= x <= b <= 0, c <= y <= d <= 0 --> x*y <= a*c  (we can use the fact that x or y is always negative (i.e., b is neg or d is neg))
328             TRACE("interval_bug", tout << "(N, N)\n";);
329             ext_numeral new_lower = b * d;
330             ext_numeral new_upper = a * c;
331             // if b = 0 (and the interval is closed), then the lower bound is closed
332             m_lower_open = (is_N0() || other.is_N0()) ? false : (b_o || d_o);
333             m_upper_open = a_o || c_o; SASSERT(a.is_neg() && c.is_neg());
334             m_lower      = new_lower;
335             m_upper      = new_upper;
336             m_lower_dep  = m_lower.is_infinite() ? nullptr : join(b_d, d_d);
337             m_upper_dep  = m_upper.is_infinite() ? nullptr : join_opt(a_d, c_d, b_d, d_d);
338         }
339         else if (other.is_M()) {
340             // a <= x <= b <= 0,  y <= d, d > 0 --> a*d <= x*y (uses the fact that b is not positive)
341             // a <= x <= b <= 0,  c <= y, c < 0 --> x*y <= a*c (uses the fact that b is not positive)
342             TRACE("interval_bug", tout << "(N, M)\n";);
343             ext_numeral new_lower = a * d; SASSERT(new_lower.is_neg());
344             ext_numeral new_upper = a * c; SASSERT(new_upper.is_pos());
345             m_lower_open = a_o || d_o;
346             m_upper_open = a_o || c_o;
347             m_lower      = new_lower;
348             m_upper      = new_upper;
349             m_lower_dep  = m_lower.is_infinite() ? nullptr : join(a_d, d_d, b_d);
350             m_upper_dep  = m_upper.is_infinite() ? nullptr : join(a_d, c_d, b_d);
351         }
352         else {
353             // a <= x <= b <= 0, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that x is neg (b is not positive) or y is pos (c is not negative))
354             // x <= b <= 0,  0 <= c <= y --> x*y <= b*c
355             TRACE("interval_bug", tout << "(N, P)\n";);
356             SASSERT(other.is_P());
357             ext_numeral new_lower = a * d;
358             ext_numeral new_upper = b * c;
359             bool is_N0_old = is_N0(); // see comment in (P, N) case
360             m_lower_open = a_o || d_o; SASSERT(a.is_neg() && d.is_pos());
361             m_upper_open = (is_N0_old || other.is_P0()) ? false : (b_o || c_o);
362             m_lower      = new_lower;
363             m_upper      = new_upper;
364             m_lower_dep  = m_lower.is_infinite() ? nullptr : join_opt(a_d, d_d, b_d, c_d);
365             m_upper_dep  = m_upper.is_infinite() ? nullptr : join(b_d, c_d);
366         }
367     }
368     else if (is_M()) {
369         if (other.is_N()) {
370             // b > 0, x <= b,  c <= y <= d <= 0 --> b*c <= x*y (uses the fact that d is not positive)
371             // a < 0, a <= x,  c <= y <= d <= 0 --> x*y <= a*c (uses the fact that d is not positive)
372             TRACE("interval_bug", tout << "(M, N)\n";);
373             ext_numeral new_lower = b * c; SASSERT(new_lower.is_neg());
374             ext_numeral new_upper = a * c; SASSERT(new_upper.is_pos());
375             m_lower_open = b_o || c_o; SASSERT(b.is_pos() && c.is_neg());
376             m_upper_open = a_o || c_o; SASSERT(a.is_neg() && c.is_neg());
377             m_lower      = new_lower;
378             m_upper      = new_upper;
379             m_lower_dep  = m_lower.is_infinite() ? nullptr : join(b_d, c_d, d_d);
380             m_upper_dep  = m_upper.is_infinite() ? nullptr : join(a_d, c_d, d_d);
381         }
382         else if (other.is_M()) {
383             TRACE("interval_bug", tout << "(M, M)\n";);
384             SASSERT(!a.is_zero() && !b.is_zero() && !c.is_zero() && !d.is_zero());
385             ext_numeral ad = a*d; SASSERT(!ad.is_zero());
386             ext_numeral bc = b*c; SASSERT(!bc.is_zero());
387             ext_numeral ac = a*c; SASSERT(!ac.is_zero());
388             ext_numeral bd = b*d; SASSERT(!bd.is_zero());
389             bool        ad_o = a_o || d_o;
390             bool        bc_o = b_o || c_o;
391             bool        ac_o = a_o || c_o;
392             bool        bd_o = b_o || d_o;
393             if (ad < bc || (ad == bc && !ad_o && bc_o)) {
394                 m_lower       = ad;
395                 m_lower_open  = ad_o;
396             }
397             else {
398                 m_lower       = bc;
399                 m_lower_open  = bc_o;
400             }
401             if (ac > bd || (ac == bd && !ac_o && bd_o)) {
402                 m_upper       = ac;
403                 m_upper_open  = ac_o;
404             }
405             else {
406                 m_upper       = bd;
407                 m_upper_open  = bd_o;
408             }
409             m_lower_dep = m_lower.is_infinite() ? nullptr : join(a_d, b_d, c_d, d_d);
410             m_upper_dep = m_upper.is_infinite() ? nullptr : join(a_d, b_d, c_d, d_d);
411         }
412         else {
413             // a < 0, a <= x, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that c is not negative)
414             // b > 0, x <= b, 0 <= c <= y <= d --> x*y <= b*d (uses the fact that c is not negative)
415             TRACE("interval_bug", tout << "(M, P)\n";);
416             SASSERT(other.is_P());
417             ext_numeral new_lower = a * d; SASSERT(new_lower.is_neg());
418             ext_numeral new_upper = b * d; SASSERT(new_upper.is_pos());
419             m_lower_open = a_o || d_o; SASSERT(a.is_neg() && d.is_pos());
420             m_upper_open = b_o || d_o; SASSERT(b.is_pos() && d.is_pos());
421             m_lower      = new_lower;
422             m_upper      = new_upper;
423             m_lower_dep  = m_lower.is_infinite() ? nullptr : join(a_d, d_d, c_d);
424             m_upper_dep  = m_upper.is_infinite() ? nullptr : join(b_d, d_d, c_d);
425         }
426     }
427     else {
428         SASSERT(is_P());
429         if (other.is_N()) {
430             // 0 <= a <= x <= b,   c <= y <= d <= 0  -->  x*y <= b*c (uses the fact that x is pos (a is not neg) or y is neg (d is not pos))
431             // 0 <= a <= x,  y <= d <= 0  --> a*d <= x*y
432             TRACE("interval_bug", tout << "(P, N)\n";);
433             ext_numeral new_lower = b * c;
434             ext_numeral new_upper = a * d;
435             bool is_P0_old = is_P0(); // cache the value of is_P0(), since it may be affected by the next update.
436             m_lower_open = b_o || c_o; SASSERT(b.is_pos() && c.is_neg());
437             m_upper_open = (is_P0_old || other.is_N0()) ? false : a_o || d_o;
438             m_lower      = new_lower;
439             m_upper      = new_upper;
440             m_lower_dep  = m_lower.is_infinite() ? nullptr : join_opt(b_d, c_d, a_d, d_d);
441             m_upper_dep  = m_upper.is_infinite() ? nullptr : join(a_d, d_d);
442         }
443         else if (other.is_M()) {
444             // 0 <= a <= x <= b,  c <= y --> b*c <= x*y (uses the fact that a is not negative)
445             // 0 <= a <= x <= b,  y <= d --> x*y <= b*d (uses the fact that a is not negative)
446             TRACE("interval_bug", tout << "(P, M)\n";);
447             ext_numeral new_lower = b * c; SASSERT(new_lower.is_neg());
448             ext_numeral new_upper = b * d; SASSERT(new_upper.is_pos());
449             m_lower_open = b_o || c_o;
450             m_upper_open = b_o || d_o;
451             m_lower      = new_lower;
452             m_upper      = new_upper;
453             m_lower_dep  = m_lower.is_infinite() ? nullptr : join(b_d, c_d, a_d);
454             m_upper_dep  = m_upper.is_infinite() ? nullptr : join(b_d, d_d, a_d);
455         }
456         else {
457             // 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
458             // x <= b, y <= d --> x*y <= b*d (uses the fact that x is pos (a is not negative) or y is pos (c is not negative))
459             TRACE("interval_bug", tout << "(P, P)\n";);
460             SASSERT(other.is_P());
461             ext_numeral new_lower = a * c;
462             ext_numeral new_upper = b * d;
463             m_lower_open = (is_P0() || other.is_P0()) ? false : a_o || c_o;
464             m_upper_open = b_o || d_o; SASSERT(b.is_pos() && d.is_pos());
465             m_lower      = new_lower;
466             m_upper      = new_upper;
467             m_lower_dep  = m_lower.is_infinite() ? nullptr : join(a_d, c_d);
468             m_upper_dep  = m_upper.is_infinite() ? nullptr : join_opt(b_d, d_d, a_d, c_d);
469         }
470     }
471     TRACE("interval_bug", tout << "operator*= result: " << *this << "\n";);
472     CTRACE("interval", !(!(contains_zero1 || contains_zero2) || contains_zero()),
473            tout << "contains_zero1: " << contains_zero1 << ", contains_zero2: " << contains_zero2 << ", contains_zero(): " << contains_zero() << "\n";);
474     SASSERT(!(contains_zero1 || contains_zero2) || contains_zero());
475     return *this;
476 }
477 
empty() const478 bool interval::empty() const {
479     if (m_lower.is_infinite() || m_upper.is_infinite())
480         return false;
481     if (m_lower < m_upper)
482         return false;
483     return m_lower > m_upper || m_lower_open || m_upper_open;
484 }
485 
contains_zero() const486 bool interval::contains_zero() const {
487     TRACE("interval_zero_bug", tout << "contains_zero info: " << *this << "\n";
488           tout << "m_lower.is_neg(): " << m_lower.is_neg() << "\n";
489           tout << "m_lower.is_zero:  " << m_lower.is_zero() << "\n";
490           tout << "m_lower_open:     " << m_lower_open << "\n";
491           tout << "m_upper.is_pos(): " << m_upper.is_pos() << "\n";
492           tout << "m_upper.is_zero:  " << m_upper.is_zero() << "\n";
493           tout << "m_upper_open:     " << m_upper_open << "\n";
494           tout << "result:           " << ((m_lower.is_neg() || (m_lower.is_zero() && !m_lower_open)) && (m_upper.is_pos() || (m_upper.is_zero() && !m_upper_open))) << "\n";);
495     return
496         (m_lower.is_neg() || (m_lower.is_zero() && !m_lower_open)) &&
497         (m_upper.is_pos() || (m_upper.is_zero() && !m_upper_open));
498 }
499 
contains(rational const & v) const500 bool interval::contains(rational const& v) const {
501     if (!inf().is_infinite()) {
502         if (v < inf().to_rational()) return false;
503         if (v == inf().to_rational() && m_lower_open) return false;
504     }
505     if (!sup().is_infinite()) {
506         if (v > sup().to_rational()) return false;
507         if (v == sup().to_rational() && m_upper_open) return false;
508     }
509     return true;
510 }
511 
inv()512 interval & interval::inv() {
513     // If the interval [l,u] does not contain 0, then 1/[l,u] = [1/u, 1/l]
514     SASSERT(!contains_zero());
515     if (is_P1()) {
516         // 0 < a <= x --> 1/x <= 1/a
517         // 0 < a <= x <= b --> 1/b <= 1/x (use lower and upper bounds)
518         ext_numeral new_lower = m_upper; SASSERT(!m_upper.is_zero());
519         new_lower.inv();
520         ext_numeral new_upper;
521         if (m_lower.is_zero()) {
522             SASSERT(m_lower_open);
523             ext_numeral plus_infinity(true);
524             new_upper = plus_infinity;
525         }
526         else {
527             new_upper = m_lower;
528             new_upper.inv();
529         }
530         m_lower = new_lower;
531         m_upper = new_upper;
532         std::swap(m_lower_open, m_upper_open);
533         v_dependency * new_upper_dep = m_lower_dep;
534         SASSERT(!m_lower.is_infinite());
535         m_lower_dep = m_manager.mk_join(m_lower_dep, m_upper_dep);
536         m_upper_dep = new_upper_dep;
537     }
538     else if (is_N1()) {
539         // x <= a < 0 --> 1/a <= 1/x
540         // b <= x <= a < 0 --> 1/b <= 1/x (use lower and upper bounds)
541         ext_numeral new_upper = m_lower; SASSERT(!m_lower.is_zero());
542         new_upper.inv();
543         ext_numeral new_lower;
544         if (m_upper.is_zero()) {
545             SASSERT(m_upper_open);
546             ext_numeral minus_infinity(false);
547             new_lower = minus_infinity;
548         }
549         else {
550             new_lower = m_upper;
551             new_lower.inv();
552         }
553         m_lower = new_lower;
554         m_upper = new_upper;
555         std::swap(m_lower_open, m_upper_open);
556         v_dependency * new_lower_dep = m_upper_dep;
557         SASSERT(!m_upper.is_infinite());
558         m_upper_dep = m_manager.mk_join(m_lower_dep, m_upper_dep);
559         m_lower_dep = new_lower_dep;
560     }
561     else {
562         UNREACHABLE();
563     }
564     return *this;
565 }
566 
operator /=(interval const & other)567 interval & interval::operator/=(interval const & other) {
568     SASSERT(!other.contains_zero());
569     if (is_zero()) {
570         // 0/other = 0 if other != 0
571         TRACE("interval", other.display_with_dependencies(tout););
572         if (other.m_lower.is_pos() || (other.m_lower.is_zero() && other.m_lower_open)) {
573             // other.lower > 0
574             //     x in ([0, 0] / [other.lo, other.up]), for other.lo > 0
575             // <=>
576             //     x >= 0: because y*x >= 0 & y > 0
577             //     x <= 0: because y*x <= 0 & y > 0
578             m_lower_dep  = join(m_lower_dep, other.m_lower_dep);
579             m_upper_dep  = join(m_upper_dep, other.m_lower_dep);
580         }
581         else {
582             // assertion must hold since !other.contains_zero()
583             SASSERT(other.m_upper.is_neg() || (other.m_upper.is_zero() && other.m_upper_open));
584             // other.upper < 0
585             //     x in ([0, 0] / [other.lo, other.up]), for up < 0
586             // <=>
587             //     x >= 0: because y*x <= 0 & y < 0
588             //     x <= 0: because y*x >= 0 & y < 0
589             v_dependency* lower_dep = m_lower_dep;
590             m_lower_dep  = join(m_upper_dep, other.m_upper_dep);
591             m_upper_dep  = join(lower_dep, other.m_upper_dep);
592         }
593         return *this;
594     }
595     else {
596         interval tmp(other);
597         tmp.inv();
598         return operator*=(tmp);
599     }
600 }
601 
expt(unsigned n)602 void interval::expt(unsigned n) {
603     if (n == 1)
604         return;
605     if (n % 2 == 0) {
606         if (m_lower.is_pos()) {
607             // [l, u]^n = [l^n, u^n] if l > 0
608             // 0 < a <= x      --> a^n <= x^n (lower bound guarantees that is positive)
609             // 0 < a <= x <= b --> x^n <= b^n (use lower and upper bound -- need the fact that x is positive)
610             m_lower.expt(n);
611             m_upper.expt(n);
612             m_upper_dep = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, m_upper_dep);
613         }
614         else if (m_upper.is_neg()) {
615             // [l, u]^n = [u^n, l^n] if u < 0
616             // a <= x <= b < 0   -->  x^n <= a^n (use lower and upper bound -- need the fact that x is negative)
617             // x <= b < 0        -->  b^n <= x^n
618             std::swap(m_lower, m_upper);
619             std::swap(m_lower_open, m_upper_open);
620             std::swap(m_lower_dep, m_upper_dep);
621             m_lower.expt(n);
622             m_upper.expt(n);
623             m_upper_dep = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, m_upper_dep);
624         }
625         else {
626             // [l, u]^n = [0, max{l^n, u^n}] otherwise
627             // we need both bounds to justify upper bound
628             TRACE("interval", tout << "before: " << m_lower << " " << m_upper << " " << n << "\n";);
629             m_lower.expt(n);
630             m_upper.expt(n);
631             TRACE("interval", tout << "after: " << m_lower << " " << m_upper << "\n";);
632             if (m_lower > m_upper || (m_lower == m_upper && !m_lower_open && m_upper_open)) {
633                 m_upper      = m_lower;
634                 m_upper_open = m_lower_open;
635             }
636             m_upper_dep  = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, m_upper_dep);
637             m_lower      = ext_numeral(0);
638             m_lower_open = false;
639             m_lower_dep  = nullptr;
640         }
641     }
642     else {
643         // Remark: when n is odd x^n is monotonic.
644         m_lower.expt(n);
645         m_upper.expt(n);
646     }
647 }
648 
display(std::ostream & out) const649 void interval::display(std::ostream & out) const {
650     out << (m_lower_open ? "(" : "[") << m_lower << ", " << m_upper << (m_upper_open ? ")" : "]");
651 }
652 
display_with_dependencies(std::ostream & out) const653 void interval::display_with_dependencies(std::ostream & out) const {
654     ptr_vector<void> vs;
655     m_manager.linearize(m_lower_dep, vs);
656     m_manager.linearize(m_upper_dep, vs);
657     out << "[";
658     display(out);
659     out << ", ";
660     bool first = true;
661     ::display(out, vs.begin(), vs.end(), ", ", first);
662     out << "]";
663 }
664 
665 
666 
667 
668