mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 17:45:32 +00:00
na
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
43cc0e6575
commit
0b6c7cd7b4
3 changed files with 142 additions and 28 deletions
|
@ -54,12 +54,13 @@ namespace polysat {
|
|||
interval(Numeral const& l, Numeral const& h): lo(l), hi(h) {}
|
||||
static interval free() { return interval(0, 0); }
|
||||
static interval empty() { interval i(0, 0); i.emp = true; return i; }
|
||||
bool is_free() const { return lo == hi; }
|
||||
bool is_free() const { return !emp && lo == hi; }
|
||||
bool is_empty() const { return emp; }
|
||||
bool contains(Numeral const& n) const;
|
||||
interval operator&(interval const& other) const;
|
||||
interval operator+(interval const& other) const;
|
||||
interval operator-(interval const& other) const;
|
||||
interval operator*(interval const& other) const;
|
||||
interval operator-() const;
|
||||
interval operator*(Numeral const& n) const;
|
||||
interval operator+(Numeral const& n) const { return interval(lo + n, hi + n); }
|
||||
|
@ -192,10 +193,7 @@ namespace polysat {
|
|||
|
||||
row get_infeasible_row();
|
||||
|
||||
#if 0
|
||||
// TBD
|
||||
void del_row(var_t base_var) {}
|
||||
#endif
|
||||
void del_row(var_t base_var);
|
||||
|
||||
|
||||
private:
|
||||
|
@ -252,10 +250,11 @@ namespace polysat {
|
|||
bool well_formed() const;
|
||||
bool well_formed_row(row const& r) const;
|
||||
|
||||
void del_row(row const& r);
|
||||
|
||||
|
||||
#if 0
|
||||
// TBD:
|
||||
void del_row(row const& r) {}
|
||||
void move_to_bound(var_t x, bool to_lower) {}
|
||||
var_t select_pivot(var_t x_i, bool is_below, numeral& out_a_ij) { throw nullptr; }
|
||||
var_t select_pivot_blands(var_t x_i, bool is_below, numeral& out_a_ij) { throw nullptr; }
|
||||
|
@ -269,7 +268,6 @@ namespace polysat {
|
|||
|
||||
struct uint64_ext {
|
||||
typedef uint64_t numeral;
|
||||
static const uint64_t max_numeral = 0; // std::limits<uint64_t>::max();
|
||||
|
||||
struct manager {
|
||||
typedef uint64_t numeral;
|
||||
|
@ -289,7 +287,7 @@ namespace polysat {
|
|||
bool is_zero(numeral const& n) const { return n == 0; }
|
||||
bool is_one(numeral const& n) const { return n == 1; }
|
||||
bool is_even(numeral const& n) const { return (n & 1) == 0; }
|
||||
bool is_minus_one(numeral const& n) const { return max_numeral == n; }
|
||||
bool is_minus_one(numeral const& n) const { return n + 1 == 0; }
|
||||
void add(numeral const& a, numeral const& b, numeral& r) { r = a + b; }
|
||||
void sub(numeral const& a, numeral const& b, numeral& r) { r = a - b; }
|
||||
void mul(numeral const& a, numeral const& b, numeral& r) { r = a * b; }
|
||||
|
@ -298,18 +296,47 @@ namespace polysat {
|
|||
numeral inv(numeral const& a) { return 0 - a; }
|
||||
void swap(numeral& a, numeral& b) { std::swap(a, b); }
|
||||
unsigned trailing_zeros(numeral const& a) const { return ::trailing_zeros(a); }
|
||||
numeral mul_inverse(numeral const& x) {
|
||||
if (x == 0)
|
||||
return 0;
|
||||
numeral t0 = 1, t1 = 0 - 1;
|
||||
numeral r0 = x, r1 = 0 - x;
|
||||
while (r1 != 0) {
|
||||
numeral q = r0 / r1;
|
||||
numeral tmp = t1;
|
||||
t1 = t0 - q * t1;
|
||||
t0 = tmp;
|
||||
tmp = r1;
|
||||
r1 = r0 - q * r1;
|
||||
r0 = tmp;
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
numeral gcd(numeral x, numeral y) {
|
||||
if (x == 0)
|
||||
return y;
|
||||
if (y == 0)
|
||||
return x;
|
||||
unsigned tz = trailing_zeros(x);
|
||||
numeral shift = std::min(trailing_zeros(y), tz);
|
||||
x >>= tz;
|
||||
if (x == 1)
|
||||
return x << shift;
|
||||
if (y == 1)
|
||||
return y << shift;
|
||||
if (x == y)
|
||||
return x << shift;
|
||||
do {
|
||||
tz = trailing_zeros(y);
|
||||
y >>= tz;
|
||||
if (x > y)
|
||||
swap(x, y);
|
||||
y -= x;
|
||||
}
|
||||
while (y != 0);
|
||||
return x << shift;
|
||||
}
|
||||
|
||||
// treat numerals as signed and check for overflow/underflow
|
||||
bool signed_mul(numeral& r, numeral const& x, numeral const& y) {
|
||||
r = x * y;
|
||||
if (y != 0 && x != r / y)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool signed_add(numeral& r, numeral const& x, numeral const& y) {
|
||||
r = x + y;
|
||||
return x <= r;
|
||||
}
|
||||
std::ostream& display(std::ostream& out, numeral const& x) const {
|
||||
return out << pp(x);
|
||||
}
|
||||
|
|
|
@ -215,6 +215,57 @@ namespace polysat {
|
|||
return r;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void fixplex<Ext>::del_row(row const& r) {
|
||||
var_t var = m_row2base[r.id()];
|
||||
m_vars[var].m_is_base = false;
|
||||
m_vars[var].lo = 0;
|
||||
m_vars[var].hi = 0;
|
||||
m_row2base[r.id()] = null_var;
|
||||
M.del(r);
|
||||
SASSERT(M.col_begin(var) == M.col_end(var));
|
||||
SASSERT(well_formed());
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void fixplex<Ext>::del_row(var_t var) {
|
||||
TRACE("polysat", tout << var << "\n";);
|
||||
row r;
|
||||
if (is_base(var)) {
|
||||
r = row(m_vars[var].m_base2row);
|
||||
}
|
||||
else {
|
||||
unsigned tz = UINT_MAX;
|
||||
numeral coeff;
|
||||
for (auto c : M.col_entries(var)) {
|
||||
unsigned tzc = m.trailing_zeros(c.get_row_entry().coeff());
|
||||
if (tzc < tz) {
|
||||
r = c.get_row_entry();
|
||||
tz = tzc;
|
||||
coeff = c.get_row_entry().coeff();
|
||||
if (tz == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tz == UINT_MAX)
|
||||
return;
|
||||
var_t old_base = m_row2base[r.id()];
|
||||
numeral new_value;
|
||||
var_info& vi = m_vars[old_base];
|
||||
if (!vi.contains(value(old_base)))
|
||||
new_value = vi.lo;
|
||||
else
|
||||
new_value = value(old_base);
|
||||
// need to move var such that old_base comes in bound.
|
||||
pivot(old_base, var, coeff, new_value);
|
||||
SASSERT(is_base(var));
|
||||
SASSERT(m_vars[var].m_base2row == r.id());
|
||||
SASSERT(vi.contains(value(old_base)));
|
||||
}
|
||||
del_row(r);
|
||||
TRACE("polysat", display(tout););
|
||||
SASSERT(well_formed());
|
||||
}
|
||||
|
||||
/**
|
||||
* increment v by delta
|
||||
|
@ -454,11 +505,8 @@ namespace polysat {
|
|||
* with bounds
|
||||
* x : [lo_x, hi_x[, y : [lo_y, hi_y[, z : [lo_z : hi_z[
|
||||
*
|
||||
* Claim. The row is infeasible if the following conditions are met:
|
||||
*
|
||||
* - 0 < a*lo_x + b*lo_y + c*lo_z <= a*hi_x + b*hi_y + c*hi_z mod 2^k
|
||||
* - a*(hi_x - lo_x) + b*(hi_y - lo_y) + c*(hi_z - lo_z) < 2^k
|
||||
* - lo_x != hi_x, lo_y != hi_y, lo_z != hi_z
|
||||
* Let range = [lo_x, hi_x[ + [lo_y, hi_y[ + [lo_z : hi_z[
|
||||
* Claim. If range does not contain 0, then the row is infeasible.
|
||||
*
|
||||
*/
|
||||
template<typename Ext>
|
||||
|
@ -473,7 +521,7 @@ namespace polysat {
|
|||
if (range.is_free())
|
||||
return false;
|
||||
}
|
||||
return 0 < range.lo && range.lo < range.hi;
|
||||
return !range.contains(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -693,6 +741,30 @@ namespace polysat {
|
|||
return (value(row2base(r)) * row2base_coeff(r)) + row2value(r) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* solve for c * x + row_value = 0
|
||||
* Cases
|
||||
* c = 1: x = -row_value
|
||||
* c = -1: x = row_value
|
||||
* row_value = 0
|
||||
* Analytic solutions:
|
||||
* trailing_zeros(c) <= trailing_zeros(row_value):
|
||||
* x = - inverse(c >> trailing_zeros(c)) * row_value << (trailing_zeros(row_value) - trailing_zeros(c))
|
||||
* trailing_zeros(c) > trailing_zeros(row_value):
|
||||
* There is no feasible (integral) solution for x
|
||||
* Possible approximation:
|
||||
* x = - inverse(c >> trailing_zeros(c)) * row_value >> (trailing_zeros(c) - trailing_zeros(row_value))
|
||||
*
|
||||
* Approximate approaches:
|
||||
* 0 - c >= c:
|
||||
* * - row_value / c or (0 - row_value) / c
|
||||
* 0 - c < c
|
||||
* * row_value / (0 - c) or - (0 - row_value) / (0 - c)
|
||||
*
|
||||
* Analytic solution requires computing inverse (uses gcd, so multiple divisions).
|
||||
* Approximation can be used to suppress rows that are feasible in a relaxation.
|
||||
* Characteristics of the relaxation(s) requires further analysis.
|
||||
*/
|
||||
template<typename Ext>
|
||||
typename fixplex<Ext>::numeral
|
||||
fixplex<Ext>::solve_for(numeral const& row_value, numeral const& c) {
|
||||
|
@ -700,7 +772,8 @@ namespace polysat {
|
|||
return 0 - row_value;
|
||||
if (c + 1 == 0)
|
||||
return row_value;
|
||||
// TBD: fix this to use proper inverse
|
||||
if (0 - c < c)
|
||||
return row_value / (0 - c);
|
||||
return 0 - row_value / c;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace polysat {
|
|||
fp.reset();
|
||||
}
|
||||
|
||||
static void test_interval1() {
|
||||
static void test_interval() {
|
||||
interval<uint64_t> i1(1, 2);
|
||||
interval<uint64_t> i2(3, 6);
|
||||
std::cout << i1 << " " << i2 << "\n";
|
||||
|
@ -92,6 +92,19 @@ namespace polysat {
|
|||
std::cout << "-" << i2 << " := " << (-i2) << "\n";
|
||||
}
|
||||
|
||||
static void test_gcd() {
|
||||
std::cout << "gcd\n";
|
||||
uint64_ext::manager e;
|
||||
uint64_t x = 0, y = 0, z = 0, a = 0, b = 0;
|
||||
uint64_t g = e.gcd(15, 27);
|
||||
std::cout << g << "\n";
|
||||
std::cout << 15 << " " << e.mul_inverse(15) << " " << 15*e.mul_inverse(15) << "\n";
|
||||
std::cout << 30 << " " << e.mul_inverse(30) << " " << 30*e.mul_inverse(30) << "\n";
|
||||
std::cout << 60 << " " << e.mul_inverse(60) << " " << 60*e.mul_inverse(60) << "\n";
|
||||
std::cout << 29 << " " << e.mul_inverse(29) << " " << 29*e.mul_inverse(29) << "\n";
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void tst_fixplex() {
|
||||
|
@ -99,5 +112,6 @@ void tst_fixplex() {
|
|||
polysat::test2();
|
||||
polysat::test3();
|
||||
polysat::test4();
|
||||
polysat::test_interval1();
|
||||
polysat::test_interval();
|
||||
polysat::test_gcd();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue