z3-z3-4.13.0.src.util.basic_interval.h Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
basic_interval.h
Abstract:
Basic interval arithmetic template for precise numerals: mpz, mpq, mpbq.
Only basic support is provided.
There is no support for:
- minus and plus infinity bounds.
- mixed open/closed intervals such as (2, 3]
The main customer of this package is the algebraic_number module.
Author:
Leonardo de Moura (leonardo) 2012-12-04.
Revision History:
--*/
#pragma once
template
class basic_interval_manager {
public:
typedef typename numeral_manager::numeral bound;
class interval {
friend class basic_interval_manager;
bound m_lower;
bound m_upper;
public:
bound const & lower() const { return m_lower; }
bound const & upper() const { return m_upper; }
bound & lower() { return m_lower; }
bound & upper() { return m_upper; }
};
class scoped_interval {
basic_interval_manager & m_manager;
interval m_interval;
public:
scoped_interval(basic_interval_manager & m):m_manager(m) {}
~scoped_interval() { m_manager.del(m_interval); }
basic_interval_manager & m() const { return m_manager; }
operator interval const &() const { return m_interval; }
operator interval&() { return m_interval; }
interval const & get() const { return m_interval; }
interval & get() { return m_interval; }
void reset() { m().reset(m_interval); }
void swap(scoped_interval & a) noexcept { m().swap(m_interval, a.m_interval); }
void swap(interval & a) noexcept { m().swap(m_interval, a); }
bound const & lower() const { return m_interval.lower(); }
bound const & upper() const { return m_interval.upper(); }
bound & lower() { return m_interval.lower(); }
bound & upper() { return m_interval.upper(); }
friend std::ostream & operator<<(std::ostream & out, scoped_interval const & a) {
a.m().display(out, a.get());
return out;
}
};
protected:
numeral_manager & m_manager;
bound m_mul_curr;
bound m_mul_max;
bound m_mul_min;
public:
typedef interval numeral; // allow intervals to be used by algorithms parameterized by numeral_manager
basic_interval_manager(numeral_manager & m):
m_manager(m) {
}
~basic_interval_manager() {
m().del(m_mul_curr);
m().del(m_mul_max);
m().del(m_mul_min);
}
numeral_manager & m() const { return m_manager; }
/**
\brief Delete interval
*/
void del(interval & a) {
m().del(a.m_lower);
m().del(a.m_upper);
}
/**
\brief Delete and reset lower and upper bounds to 0
*/
void reset(interval & a) {
m().reset(a.m_lower);
m().reset(a.m_upper);
}
bound const & lower(interval const & a) {
return a.lower();
}
bound const & upper(interval const & a) {
return a.upper();
}
/**
\brief a <- (lower, upper)
*/
void set(interval & a, bound const & lower, bound const & upper) {
SASSERT(m().le(lower, upper));
m().set(a.m_lower, lower);
m().set(a.m_upper, upper);
}
/**
\brief a <- b
*/
void set(interval & a, interval const & b) {
set(a, b.m_lower, b.m_upper);
}
/**
\brief a <- (n, n)
Manager must be configured for closed intervals.
*/
void set(interval & a, bound const & n) {
m().set(a.m_lower, n);
m().set(a.m_upper, n);
}
void set_lower(interval & a, bound const & n) {
SASSERT(m().le(n, a.m_upper));
m().set(a.m_lower, n);
}
void set_upper(interval & a, bound const & n) {
SASSERT(m().le(a.m_lower, n));
m().set(a.m_upper, n);
}
void swap(interval & a, interval & b) noexcept {
m().swap(a.m_lower, b.m_lower);
m().swap(a.m_upper, b.m_upper);
}
/**
\brief a <- -a
*/
void neg(interval & a) {
m().neg(a.m_lower);
m().neg(a.m_upper);
m().swap(a.m_lower, a.m_upper);
}
/**
\brief Return true if a does not contain any value. We can
only have empty intervals if the manager is configured to used
open intervals.
*/
bool is_empty(interval const & a) {
return !closed && m().eq(a.m_lower, a.m_upper);
}
/**
\brief Return true if all values in the given interval are positive.
*/
bool is_pos(interval const & a) { return (closed && m().is_pos(a.m_lower)) || (!closed && m().is_nonneg(a.m_lower)); }
/**
\brief Return true if all values in the given interval are negative.
*/
bool is_neg(interval const & a) { return (closed && m().is_neg(a.m_upper)) || (!closed && m().is_nonpos(a.m_upper)); }
/**
\brief Return true if 0 is in the interval.
*/
bool contains_zero(interval const & a) {
return
(closed && m().is_nonpos(a.m_lower) && m().is_nonneg(a.m_upper)) ||
(!closed && m().is_neg(a.m_lower) && m().is_pos(a.m_upper));
}
/**
\brief Return true if all values in interval a are in interval b.
*/
bool is_subset(interval const & a, interval const & b) {
return m().le(b.m_lower, a.m_lower) && m().le(a.m_upper, b.m_upper);
}
/**
\brief Return true if there is no value v s.t. v \in a and v \in b.
*/
bool disjoint(interval const & a, interval const & b) {
return
(closed && (m().lt(a.m_upper, b.m_lower) || m().lt(b.m_upper, a.m_lower))) ||
(!closed && (m().le(a.m_upper, b.m_upper) || m().le(b.m_upper, a.m_lower)));
}
/**
\brief Return true if all elements in a are smaller than all elements in b.
*/
bool precedes(interval const & a, interval const & b) {
return
(closed && (m().lt(a.m_upper, b.m_lower))) ||
(!closed && (m().le(a.m_upper, b.m_lower)));
}
/**
\brief Return true if all elements in a are smaller than b.
*/
bool precedes(interval const & a, bound const & b) {
return
(closed && (m().lt(a.m_upper, b))) ||
(!closed && (m().le(a.m_upper, b)));
}
/**
\brief Return true if a is smaller than all elements in b.
*/
bool precedes(bound const & a, interval const & b) {
return
(closed && (m().lt(a, b.m_lower))) ||
(!closed && (m().le(a, b.m_lower)));
}
/**
\brief a <- 1/a
\pre a.m_lower and m_upper must not be 0.
\pre bound must be a field.
*/
void inv(interval & a) {
SASSERT(numeral_manager::field());
SASSERT(!contains_zero(a));
SASSERT(!m().is_zero(a.m_lower) && !m().is_zero(a.m_upper));
m().inv(a.m_lower);
m().inv(a.m_upper);
m().swap(a.m_lower, a.m_upper);
}
/**
\brief c <- a + b
*/
void add(interval const & a, interval const & b, interval & c) {
m().add(a.m_lower, b.m_lower, c.m_lower);
m().add(a.m_upper, b.m_upper, c.m_upper);
}
/**
\brief c <- a - b
*/
void sub(interval const & a, interval const & b, interval & c) {
m().sub(a.m_lower, b.m_upper, c.m_lower);
m().sub(a.m_upper, b.m_lower, c.m_upper);
}
private:
/**
\brief Init the value of m_mul_max and m_mul_min using m_mul_curr
*/
void init_mul_max_min() {
m().set(m_mul_min, m_mul_curr);
m().swap(m_mul_max, m_mul_curr);
}
/**
\brief Update the value of m_mul_max and m_mul_min using m_mul_curr
*/
void update_mul_max_min() {
if (m().lt(m_mul_curr, m_mul_min))
m().set(m_mul_min, m_mul_curr);
if (m().gt(m_mul_curr, m_mul_max))
m().swap(m_mul_max, m_mul_curr);
}
public:
/**
\brief c <- a * b
*/
void mul(interval const & a, interval const & b, interval & c) {
m().mul(a.m_lower, b.m_lower, m_mul_curr);
init_mul_max_min();
m().mul(a.m_lower, b.m_upper, m_mul_curr);
update_mul_max_min();
m().mul(a.m_upper, b.m_lower, m_mul_curr);
update_mul_max_min();
m().mul(a.m_upper, b.m_upper, m_mul_curr);
update_mul_max_min();
m().swap(c.m_lower, m_mul_min);
m().swap(c.m_upper, m_mul_max);
}
/**
\brief c <- a/b
\pre b m_lower and m_upper must not be 0
\pre bound must be a field.
*/
void div(interval const & a, interval const & b, interval & c) {
SASSERT(numeral_manager::field());
SASSERT(!contains_zero(b));
SASSERT(!m().is_zero(b.m_lower) && !m().is_zero(b.m_upper));
m().div(a.m_lower, b.m_lower, m_mul_curr);
init_mul_max_min();
m().div(a.m_lower, b.m_upper, m_mul_curr);
update_mul_max_min();
m().div(a.m_upper, b.m_lower, m_mul_curr);
update_mul_max_min();
m().div(a.m_upper, b.m_upper, m_mul_curr);
update_mul_max_min();
m().swap(c.m_lower, m_mul_min);
m().swap(c.m_upper, m_mul_max);
}
/**
\brief c <- a^n
*/
void power(interval const & a, unsigned n, interval & c) {
// Let a be of the form (l, u)
if (n % 2 == 1) {
// n is odd
// c <- (l^n, u^n)
m().power(a.m_lower, n, c.m_lower);
m().power(a.m_upper, n, c.m_upper);
}
else {
SASSERT(n % 2 == 0);
m().power(a.m_lower, n, c.m_lower);
m().power(a.m_upper, n, c.m_upper);
if (m().is_nonneg(a.m_lower)) {
// n is even and l >= 0
// c <- (l^n, u^n)
return;
}
if (m().is_neg(a.m_upper)) {
// n is even and u < 0
// c <- (u^n, l^n)
m().swap(c.m_lower, c.m_upper);
return;
}
// c <- (0, max(l^n, u^n))
if (m().gt(c.m_lower, c.m_upper))
m().swap(c.m_lower, c.m_upper);
m().reset(c.m_lower);
}
}
void display(std::ostream & out, interval const & a) {
out << (closed ? "[" : "(") << m().to_string(a.m_lower) << ", " << m().to_string(a.m_upper) << (closed ? "]" : ")");
}
};