3
0
Fork 0
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:
Jakob Rath 2023-02-01 16:28:57 +01:00
commit 20b5455d08
669 changed files with 26145 additions and 20652 deletions

View file

@ -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>

View file

@ -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);
}