#pragma once
template<typename numeral_manager, bool closed>
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;
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; }
void del(interval & a) {
m().del(a.m_lower);
m().del(a.m_upper);
}
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();
}
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);
}
void set(interval & a, interval const & b) {
set(a, b.m_lower, b.m_upper);
}
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);
}
void neg(interval & a) {
m().neg(a.m_lower);
m().neg(a.m_upper);
m().swap(a.m_lower, a.m_upper);
}
bool is_empty(interval const & a) {
return !closed && m().eq(a.m_lower, a.m_upper);
}
bool is_pos(interval const & a) { return (closed && m().is_pos(a.m_lower)) || (!closed && m().is_nonneg(a.m_lower)); }
bool is_neg(interval const & a) { return (closed && m().is_neg(a.m_upper)) || (!closed && m().is_nonpos(a.m_upper)); }
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));
}
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);
}
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)));
}
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)));
}
bool precedes(interval const & a, bound const & b) {
return
(closed && (m().lt(a.m_upper, b))) ||
(!closed && (m().le(a.m_upper, b)));
}
bool precedes(bound const & a, interval const & b) {
return
(closed && (m().lt(a, b.m_lower))) ||
(!closed && (m().le(a, b.m_lower)));
}
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);
}
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);
}
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:
void init_mul_max_min() {
m().set(m_mul_min, m_mul_curr);
m().swap(m_mul_max, 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:
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);
}
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);
}
void power(interval const & a, unsigned n, interval & c) {
if (n % 2 == 1) {
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)) {
return;
}
if (m().is_neg(a.m_upper)) {
m().swap(c.m_lower, c.m_upper);
return;
}
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 ? "]" : ")");
}
};