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