mirror of
https://github.com/Z3Prover/z3
synced 2025-08-20 18:20:22 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
20b5455d08
669 changed files with 26145 additions and 20652 deletions
|
@ -172,6 +172,7 @@ public:
|
|||
void set_upper_is_inf(interval& a, bool inf) const { m_config.set_upper_is_inf(a, inf); }
|
||||
void set_lower_dep(interval& a, u_dependency* d) const { m_config.set_lower_dep(a, d); }
|
||||
void set_upper_dep(interval& a, u_dependency* d) const { m_config.set_upper_dep(a, d); }
|
||||
void reset(interval& a) const { set_lower_is_inf(a, true); set_upper_is_inf(a, true); }
|
||||
void set_value(interval& a, rational const& n) const {
|
||||
set_lower(a, n);
|
||||
set_upper(a, n);
|
||||
|
@ -331,6 +332,7 @@ public:
|
|||
}
|
||||
mpq const& lower(interval const& a) const { return m_config.lower(a); }
|
||||
mpq const& upper(interval const& a) const { return m_config.upper(a); }
|
||||
|
||||
bool is_empty(interval const& a) const;
|
||||
void set_interval_for_scalar(interval&, const rational&);
|
||||
template <typename T>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
|
@ -7,105 +7,235 @@ Module Name:
|
|||
|
||||
Abstract:
|
||||
|
||||
Intervals over fixed precision modular arithmetic
|
||||
Modular interval for bit-vector comparisons
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2021-03-19
|
||||
Jakob Rath 2021-04-6
|
||||
Nikolaj and Nuno
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/rational.h"
|
||||
namespace bv {
|
||||
|
||||
template<typename T, typename Base>
|
||||
struct interval_tpl : public Base {
|
||||
T l, h;
|
||||
unsigned sz = 0;
|
||||
bool tight = true;
|
||||
|
||||
interval_tpl(T const& l, T const& h, unsigned sz, bool tight = false): l(l), h(h), sz(sz), tight(tight) {}
|
||||
interval_tpl() {}
|
||||
|
||||
bool invariant() const {
|
||||
return
|
||||
0 <= l && (l <= Base::bound(sz)) &&
|
||||
0 <= h && (h <= Base::bound(sz)) &&
|
||||
(!is_wrapped() || l != h + 1);
|
||||
}
|
||||
|
||||
bool is_full() const {
|
||||
return l == 0 && h == Base::bound(sz);
|
||||
}
|
||||
bool is_wrapped() const { return l > h; }
|
||||
bool is_singleton() const { return l == h; }
|
||||
|
||||
bool operator==(const interval_tpl<T, Base>& b) const {
|
||||
SASSERT(sz == b.sz);
|
||||
return l == b.l && h == b.h && tight == b.tight;
|
||||
}
|
||||
bool operator!=(const interval_tpl& b) const { return !(*this == b); }
|
||||
|
||||
bool implies(const interval_tpl<T, Base>& b) const {
|
||||
if (b.is_full())
|
||||
return true;
|
||||
else if (is_full())
|
||||
return false;
|
||||
else if (is_wrapped())
|
||||
// l >= b.l >= b.h >= h
|
||||
return b.is_wrapped() && h <= b.h && l >= b.l;
|
||||
else if (b.is_wrapped())
|
||||
// b.l > b.h >= h >= l
|
||||
// h >= l >= b.l > b.h
|
||||
return h <= b.h || l >= b.l;
|
||||
else
|
||||
return l >= b.l && h <= b.h;
|
||||
}
|
||||
|
||||
/// return false if intersection is unsat
|
||||
bool intersect(const interval_tpl<T, Base>& b, interval_tpl& result) const {
|
||||
if (is_full() || *this == b) {
|
||||
result = b;
|
||||
return true;
|
||||
}
|
||||
if (b.is_full()) {
|
||||
result = *this;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_wrapped()) {
|
||||
if (b.is_wrapped()) {
|
||||
if (h >= b.l)
|
||||
result = b;
|
||||
else if (b.h >= l)
|
||||
result = *this;
|
||||
else
|
||||
result = interval_tpl(std::max(l, b.l), std::min(h, b.h), sz);
|
||||
}
|
||||
else
|
||||
return b.intersect(*this, result);
|
||||
}
|
||||
else if (b.is_wrapped()) {
|
||||
// ... b.h ... l ... h ... b.l ..
|
||||
if (h < b.l && l > b.h)
|
||||
return false;
|
||||
// ... l ... b.l ... h ...
|
||||
if (h >= b.l && l <= b.h)
|
||||
result = b;
|
||||
else if (h >= b.l)
|
||||
result = interval_tpl(b.l, h, sz);
|
||||
else {
|
||||
// ... l .. b.h .. h .. b.l ...
|
||||
SASSERT(l <= b.h);
|
||||
result = interval_tpl(l, std::min(h, b.h), sz);
|
||||
}
|
||||
} else {
|
||||
if (l > b.h || h < b.l)
|
||||
return false;
|
||||
|
||||
// 0 .. l.. l' ... h ... h'
|
||||
result = interval_tpl(std::max(l, b.l), std::min(h, b.h), sz, tight && b.tight);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// return false if negation is empty
|
||||
bool negate(interval_tpl<T, Base>& result) const {
|
||||
if (!tight)
|
||||
result = interval_tpl(Base::zero(), Base::bound(sz), sz, true);
|
||||
else if (is_full())
|
||||
return false;
|
||||
else if (l == 0 && Base::bound(sz) == h)
|
||||
result = interval_tpl(Base::zero(), Base::bound(sz), sz);
|
||||
else if (l == 0)
|
||||
result = interval_tpl(h + 1, Base::bound(sz), sz);
|
||||
else if (Base::bound(sz) == h)
|
||||
result = interval_tpl(Base::zero(), l - 1, sz);
|
||||
else
|
||||
result = interval_tpl(h + 1, l - 1, sz);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename Numeral>
|
||||
struct pp {
|
||||
Numeral n;
|
||||
pp(Numeral const& n):n(n) {}
|
||||
};
|
||||
};
|
||||
|
||||
struct rinterval_base {
|
||||
static rational bound(unsigned sz) {
|
||||
return rational::power_of_two(sz) - 1;
|
||||
}
|
||||
|
||||
static rational zero() { return rational::zero(); }
|
||||
};
|
||||
|
||||
struct rinterval : public interval_tpl<rational, rinterval_base> {
|
||||
rinterval(rational const& l, rational const& h, unsigned sz, bool tight = false) {
|
||||
this->l = l; this->h = h; this->sz = sz; this->tight = tight;
|
||||
}
|
||||
rinterval() { l = 0; h = 0; tight = true; }
|
||||
};
|
||||
|
||||
struct iinterval_base {
|
||||
static uint64_t uMaxInt(unsigned sz) {
|
||||
SASSERT(sz <= 64);
|
||||
return ULLONG_MAX >> (64u - sz);
|
||||
}
|
||||
|
||||
static uint64_t bound(unsigned sz) { return uMaxInt(sz); }
|
||||
static uint64_t zero() { return 0; }
|
||||
};
|
||||
|
||||
struct iinterval : public interval_tpl<uint64_t, iinterval_base> {
|
||||
iinterval(uint64_t l, uint64_t h, unsigned sz, bool tight = false) {
|
||||
this->l = l; this->h = h; this->sz = sz; this->tight = tight;
|
||||
}
|
||||
iinterval() { l = 0; h = 0; sz = 0; tight = true; }
|
||||
};
|
||||
|
||||
struct interval {
|
||||
bool is_small = true;
|
||||
iinterval i;
|
||||
rinterval r;
|
||||
|
||||
interval() {}
|
||||
|
||||
interval(rational const& l, rational const& h, unsigned sz, bool tight = false) {
|
||||
if (sz <= 64) {
|
||||
is_small = true;
|
||||
i.l = l.get_uint64();
|
||||
i.h = h.get_uint64();
|
||||
i.tight = tight;
|
||||
i.sz = sz;
|
||||
}
|
||||
else {
|
||||
is_small = false;
|
||||
r.l = l;
|
||||
r.h = h;
|
||||
r.tight = tight;
|
||||
r.sz = sz;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return is_small ? i.sz : r.sz;
|
||||
}
|
||||
|
||||
bool negate(interval& result) const {
|
||||
result.is_small = is_small;
|
||||
if (is_small)
|
||||
return i.negate(result.i);
|
||||
else
|
||||
return r.negate(result.r);
|
||||
}
|
||||
|
||||
bool intersect(interval const& b, interval & result) const {
|
||||
result.is_small = is_small;
|
||||
SASSERT(b.is_small == is_small);
|
||||
if (is_small)
|
||||
return i.intersect(b.i, result.i);
|
||||
else
|
||||
return r.intersect(b.r, result.r);
|
||||
}
|
||||
|
||||
bool operator==(interval const& other) const {
|
||||
SASSERT(is_small == other.is_small);
|
||||
return is_small ? i == other.i : r == other.r;
|
||||
}
|
||||
|
||||
bool operator!=(interval const& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool is_singleton() const { return is_small ? i.is_singleton() : r.is_singleton(); }
|
||||
|
||||
bool is_full() const { return is_small ? i.is_full() : r.is_full(); }
|
||||
|
||||
bool tight() const { return is_small ? i.tight : r.tight; }
|
||||
|
||||
bool implies(const interval& b) const {
|
||||
SASSERT(is_small == b.is_small);
|
||||
return is_small ? i.implies(b.i) : r.implies(b.r);
|
||||
}
|
||||
|
||||
rational lo() const { return is_small ? rational(i.l, rational::ui64()) : r.l; }
|
||||
rational hi() const { return is_small ? rational(i.h, rational::ui64()) : r.h; }
|
||||
};
|
||||
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, pp<uint8_t> const& p) {
|
||||
return out << (unsigned)p.n;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
inline std::ostream& operator<<(std::ostream& out, pp<Numeral> const& p) {
|
||||
if ((Numeral)(0 - p.n) < p.n)
|
||||
return out << "-" << (Numeral)(0 - p.n);
|
||||
return out << p.n;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, pp<rational> const& p) {
|
||||
return out << p.n;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
class mod_interval {
|
||||
bool emp = false;
|
||||
public:
|
||||
Numeral lo { 0 };
|
||||
Numeral hi { 0 };
|
||||
mod_interval() {}
|
||||
mod_interval(Numeral const& l, Numeral const& h): lo(l), hi(h) {}
|
||||
virtual ~mod_interval() {}
|
||||
static mod_interval free() { return mod_interval(0, 0); }
|
||||
static mod_interval empty() { mod_interval i(0, 0); i.emp = true; return i; }
|
||||
|
||||
bool is_free() const { return !emp && lo == hi; }
|
||||
bool is_empty() const { return emp; }
|
||||
bool is_singleton() const { return !is_empty() && (lo + 1 == hi || (hi == 0 && is_max(lo))); }
|
||||
bool contains(Numeral const& n) const;
|
||||
bool contains(mod_interval const& other) const;
|
||||
virtual bool is_max(Numeral const& n) const { return (Numeral)(n + 1) == 0; }
|
||||
Numeral max() const;
|
||||
Numeral min() const;
|
||||
|
||||
void set_free() { lo = hi = 0; emp = false; }
|
||||
void set_bounds(Numeral const& l, Numeral const& h) { lo = l; hi = h; }
|
||||
void set_empty() { emp = true; }
|
||||
|
||||
mod_interval& intersect_ule(Numeral const& h);
|
||||
mod_interval& intersect_uge(Numeral const& l);
|
||||
mod_interval& intersect_ult(Numeral const& h);
|
||||
mod_interval& intersect_ugt(Numeral const& l);
|
||||
mod_interval& intersect_fixed(Numeral const& n);
|
||||
mod_interval& intersect_diff(Numeral const& n);
|
||||
mod_interval& update_lo(Numeral const& new_lo);
|
||||
mod_interval& update_hi(Numeral const& new_hi);
|
||||
|
||||
mod_interval operator&(mod_interval const& other) const;
|
||||
mod_interval operator+(mod_interval const& other) const;
|
||||
mod_interval operator-(mod_interval const& other) const;
|
||||
mod_interval operator*(mod_interval const& other) const;
|
||||
mod_interval operator-() const;
|
||||
mod_interval operator*(Numeral const& n) const;
|
||||
mod_interval operator+(Numeral const& n) const { return mod_interval(lo + n, hi + n); }
|
||||
mod_interval operator-(Numeral const& n) const { return mod_interval(lo - n, hi - n); }
|
||||
mod_interval& operator+=(mod_interval const& other) { *this = *this + other; return *this; }
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
if (is_empty()) return out << "empty";
|
||||
if (is_free()) return out << "free";
|
||||
return out << "[" << pp(lo) << ", " << pp(hi) << "[";
|
||||
inline std::ostream& operator<<(std::ostream& o, const interval& I) {
|
||||
if (I.is_small)
|
||||
return o << "[" << I.i.l << ", " << I.i.h << "]";
|
||||
else
|
||||
return o << "[" << I.r.l << ", " << I.r.h << "]";
|
||||
}
|
||||
Numeral closest_value(Numeral const& n) const;
|
||||
bool operator==(mod_interval const& other) const {
|
||||
if (is_empty())
|
||||
return other.is_empty();
|
||||
if (is_free())
|
||||
return other.is_free();
|
||||
return lo == other.lo && hi == other.hi;
|
||||
}
|
||||
bool operator!=(mod_interval const& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Numeral>
|
||||
inline std::ostream& operator<<(std::ostream& out, mod_interval<Numeral> const& i) {
|
||||
return i.display(out);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue