mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 02:15:19 +00:00
Merge branch 'master' of https://github.com/Z3Prover/z3
This commit is contained in:
commit
768bb84798
|
@ -8,8 +8,8 @@ Module Name:
|
|||
Abstract:
|
||||
|
||||
Translator from Z3 expressions into multivariate polynomials (and back).
|
||||
|
||||
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-12-23
|
||||
|
@ -23,6 +23,7 @@ Notes:
|
|||
#include"ast_smt2_pp.h"
|
||||
#include"z3_exception.h"
|
||||
#include"cooperate.h"
|
||||
#include"common_msgs.h"
|
||||
|
||||
struct expr2polynomial::imp {
|
||||
struct frame {
|
||||
|
@ -31,7 +32,7 @@ struct expr2polynomial::imp {
|
|||
frame():m_curr(0), m_idx(0) {}
|
||||
frame(app * t):m_curr(t), m_idx(0) {}
|
||||
};
|
||||
|
||||
|
||||
expr2polynomial & m_wrapper;
|
||||
ast_manager & m_am;
|
||||
arith_util m_autil;
|
||||
|
@ -39,7 +40,7 @@ struct expr2polynomial::imp {
|
|||
expr2var * m_expr2var;
|
||||
bool m_expr2var_owner;
|
||||
expr_ref_vector m_var2expr;
|
||||
|
||||
|
||||
obj_map<expr, unsigned> m_cache;
|
||||
expr_ref_vector m_cached_domain;
|
||||
polynomial::polynomial_ref_vector m_cached_polynomials;
|
||||
|
@ -52,7 +53,7 @@ struct expr2polynomial::imp {
|
|||
bool m_use_var_idxs;
|
||||
|
||||
volatile bool m_cancel;
|
||||
|
||||
|
||||
imp(expr2polynomial & w, ast_manager & am, polynomial::manager & pm, expr2var * e2v, bool use_var_idxs):
|
||||
m_wrapper(w),
|
||||
m_am(am),
|
||||
|
@ -94,7 +95,7 @@ struct expr2polynomial::imp {
|
|||
|
||||
void checkpoint() {
|
||||
if (m_cancel)
|
||||
throw default_exception("canceled");
|
||||
throw default_exception(Z3_CANCELED_MSG);
|
||||
cooperate("expr2polynomial");
|
||||
}
|
||||
|
||||
|
@ -114,7 +115,7 @@ struct expr2polynomial::imp {
|
|||
SASSERT(!m_cache.contains(t));
|
||||
SASSERT(m_cached_denominators.size() == m_cached_polynomials.size());
|
||||
SASSERT(m_cached_denominators.size() == m_cached_domain.size());
|
||||
if (t->get_ref_count() <= 1)
|
||||
if (t->get_ref_count() <= 1)
|
||||
return;
|
||||
unsigned idx = m_cached_polynomials.size();
|
||||
m_cache.insert(t, idx);
|
||||
|
@ -176,7 +177,7 @@ struct expr2polynomial::imp {
|
|||
case OP_NUM:
|
||||
store_const_poly(t);
|
||||
return true;
|
||||
case OP_ADD: case OP_SUB: case OP_MUL: case OP_UMINUS: case OP_TO_REAL:
|
||||
case OP_ADD: case OP_SUB: case OP_MUL: case OP_UMINUS: case OP_TO_REAL:
|
||||
push_frame(t);
|
||||
return false;
|
||||
case OP_POWER: {
|
||||
|
@ -215,7 +216,7 @@ struct expr2polynomial::imp {
|
|||
store_var_poly(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SASSERT(is_app(t));
|
||||
if (!m_autil.is_arith_expr(t)) {
|
||||
if (m_use_var_idxs)
|
||||
|
@ -223,7 +224,7 @@ struct expr2polynomial::imp {
|
|||
store_var_poly(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return visit_arith_app(to_app(t));
|
||||
}
|
||||
|
||||
|
@ -237,7 +238,7 @@ struct expr2polynomial::imp {
|
|||
polynomial::polynomial * const * polynomial_args(unsigned num_args) {
|
||||
SASSERT(m_presult_stack.size() >= num_args);
|
||||
return m_presult_stack.c_ptr() + m_presult_stack.size() - num_args;
|
||||
}
|
||||
}
|
||||
|
||||
polynomial::numeral const * denominator_args(unsigned num_args) {
|
||||
SASSERT(m_dresult_stack.size() >= num_args);
|
||||
|
@ -330,34 +331,34 @@ struct expr2polynomial::imp {
|
|||
// do nothing
|
||||
cache_result(t);
|
||||
}
|
||||
|
||||
|
||||
void process_app(app * t) {
|
||||
SASSERT(m_presult_stack.size() == m_dresult_stack.size());
|
||||
|
||||
|
||||
switch (t->get_decl_kind()) {
|
||||
case OP_ADD:
|
||||
case OP_ADD:
|
||||
process_add(t);
|
||||
return;
|
||||
case OP_SUB:
|
||||
process_sub(t);
|
||||
return;
|
||||
case OP_MUL:
|
||||
case OP_MUL:
|
||||
process_mul(t);
|
||||
return;
|
||||
case OP_POWER:
|
||||
process_power(t);
|
||||
return;
|
||||
case OP_UMINUS:
|
||||
case OP_UMINUS:
|
||||
process_uminus(t);
|
||||
return;
|
||||
case OP_TO_REAL:
|
||||
case OP_TO_REAL:
|
||||
process_to_real(t);
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool to_polynomial(expr * t, polynomial::polynomial_ref & p, polynomial::scoped_numeral & d) {
|
||||
if (!is_int_real(t))
|
||||
return false;
|
||||
|
@ -373,7 +374,7 @@ struct expr2polynomial::imp {
|
|||
while (fr.m_idx < num_args) {
|
||||
expr * arg = a->get_arg(fr.m_idx);
|
||||
fr.m_idx++;
|
||||
if (!visit(arg))
|
||||
if (!visit(arg))
|
||||
goto begin_loop;
|
||||
}
|
||||
process_app(a);
|
||||
|
@ -470,12 +471,12 @@ expr2polynomial::~expr2polynomial() {
|
|||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
ast_manager & expr2polynomial::m() const {
|
||||
return m_imp->m_am;
|
||||
ast_manager & expr2polynomial::m() const {
|
||||
return m_imp->m_am;
|
||||
}
|
||||
|
||||
polynomial::manager & expr2polynomial::pm() const {
|
||||
return m_imp->m_pm;
|
||||
polynomial::manager & expr2polynomial::pm() const {
|
||||
return m_imp->m_pm;
|
||||
}
|
||||
|
||||
bool expr2polynomial::to_polynomial(expr * t, polynomial::polynomial_ref & p, polynomial::scoped_numeral & d) {
|
||||
|
@ -486,14 +487,14 @@ void expr2polynomial::to_expr(polynomial::polynomial_ref const & p, bool use_pow
|
|||
m_imp->to_expr(p, use_power, r);
|
||||
}
|
||||
|
||||
bool expr2polynomial::is_var(expr * t) const {
|
||||
bool expr2polynomial::is_var(expr * t) const {
|
||||
SASSERT(!m_imp->m_use_var_idxs);
|
||||
return m_imp->m_expr2var->is_var(t);
|
||||
return m_imp->m_expr2var->is_var(t);
|
||||
}
|
||||
|
||||
expr2var const & expr2polynomial::get_mapping() const {
|
||||
|
||||
expr2var const & expr2polynomial::get_mapping() const {
|
||||
SASSERT(!m_imp->m_use_var_idxs);
|
||||
return *(m_imp->m_expr2var);
|
||||
return *(m_imp->m_expr2var);
|
||||
}
|
||||
|
||||
void expr2polynomial::set_cancel(bool f) {
|
||||
|
@ -511,8 +512,8 @@ bool default_expr2polynomial::is_int(polynomial::var x) const {
|
|||
return m_is_int[x];
|
||||
}
|
||||
|
||||
polynomial::var default_expr2polynomial::mk_var(bool is_int) {
|
||||
polynomial::var x = pm().mk_var();
|
||||
polynomial::var default_expr2polynomial::mk_var(bool is_int) {
|
||||
polynomial::var x = pm().mk_var();
|
||||
m_is_int.reserve(x+1, false);
|
||||
m_is_int[x] = is_int;
|
||||
return x;
|
||||
|
|
|
@ -24,14 +24,15 @@ Revision History:
|
|||
#include"trace.h"
|
||||
#include"scoped_numeral.h"
|
||||
#include"cooperate.h"
|
||||
#include"common_msgs.h"
|
||||
|
||||
#define DEFAULT_PI_PRECISION 2
|
||||
|
||||
// #define TRACE_NTH_ROOT
|
||||
|
||||
template<typename C>
|
||||
interval_manager<C>::interval_manager(reslimit& lim, C const & c): m_limit(lim), m_c(c) {
|
||||
m().set(m_minus_one, -1);
|
||||
interval_manager<C>::interval_manager(reslimit& lim, C const & c): m_limit(lim), m_c(c) {
|
||||
m().set(m_minus_one, -1);
|
||||
m().set(m_one, 1);
|
||||
m_pi_n = 0;
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ void interval_manager<C>::del(interval & a) {
|
|||
template<typename C>
|
||||
void interval_manager<C>::checkpoint() {
|
||||
if (!m_limit.inc())
|
||||
throw default_exception("canceled");
|
||||
throw default_exception(Z3_CANCELED_MSG);
|
||||
cooperate("interval");
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,7 @@ void interval_manager<C>::nth_root_slow(numeral const & a, unsigned n, numeral c
|
|||
static unsigned counter = 0;
|
||||
static unsigned loop_counter = 0;
|
||||
counter++;
|
||||
if (counter % 1000 == 0)
|
||||
if (counter % 1000 == 0)
|
||||
std::cerr << "[nth-root] " << counter << " " << loop_counter << " " << ((double)loop_counter)/((double)counter) << std::endl;
|
||||
#endif
|
||||
|
||||
|
@ -163,7 +164,7 @@ void interval_manager<C>::nth_root_slow(numeral const & a, unsigned n, numeral c
|
|||
|
||||
/**
|
||||
\brief Store in o a rough approximation of a^1/n.
|
||||
|
||||
|
||||
It uses 2^Floor[Floor(Log2(a))/n]
|
||||
|
||||
\pre is_pos(a)
|
||||
|
@ -179,7 +180,7 @@ void interval_manager<C>::rough_approx_nth_root(numeral const & a, unsigned n, n
|
|||
}
|
||||
|
||||
/*
|
||||
Compute the n-th root of \c a with (suggested) precision p.
|
||||
Compute the n-th root of \c a with (suggested) precision p.
|
||||
The only guarantee provided by this method is that a^(1/n) is in [lo, hi].
|
||||
|
||||
If n is even, then a is assumed to be nonnegative.
|
||||
|
@ -202,8 +203,8 @@ void interval_manager<C>::nth_root(numeral const & a, unsigned n, numeral const
|
|||
m().abs(A);
|
||||
|
||||
nth_root_pos(A, n, p, lo, hi);
|
||||
STRACE("nth_root_trace",
|
||||
tout << "[nth-root] ("; m().display(tout, A); tout << ")^(1/" << n << ") >= "; m().display(tout, lo); tout << "\n";
|
||||
STRACE("nth_root_trace",
|
||||
tout << "[nth-root] ("; m().display(tout, A); tout << ")^(1/" << n << ") >= "; m().display(tout, lo); tout << "\n";
|
||||
tout << "[nth-root] ("; m().display(tout, A); tout << ")^(1/" << n << ") <= "; m().display(tout, hi); tout << "\n";);
|
||||
if (is_neg) {
|
||||
m().swap(lo, hi);
|
||||
|
@ -214,7 +215,7 @@ void interval_manager<C>::nth_root(numeral const & a, unsigned n, numeral const
|
|||
|
||||
/**
|
||||
r <- A/(x^n)
|
||||
|
||||
|
||||
If to_plus_inf, then r >= A/(x^n)
|
||||
If not to_plus_inf, then r <= A/(x^n)
|
||||
|
||||
|
@ -251,7 +252,7 @@ void interval_manager<C>::A_div_x_n(numeral const & A, numeral const & x, unsign
|
|||
|
||||
The computation stops when the difference between current and new x is less than p.
|
||||
The procedure may not terminate if m() is not precise and p is very small.
|
||||
|
||||
|
||||
*/
|
||||
template<typename C>
|
||||
void interval_manager<C>::approx_nth_root(numeral const & A, unsigned n, numeral const & p, numeral & x) {
|
||||
|
@ -261,18 +262,18 @@ void interval_manager<C>::approx_nth_root(numeral const & A, unsigned n, numeral
|
|||
static unsigned counter = 0;
|
||||
static unsigned loop_counter = 0;
|
||||
counter++;
|
||||
if (counter % 1000 == 0)
|
||||
if (counter % 1000 == 0)
|
||||
std::cerr << "[nth-root] " << counter << " " << loop_counter << " " << ((double)loop_counter)/((double)counter) << std::endl;
|
||||
#endif
|
||||
|
||||
|
||||
_scoped_numeral<numeral_manager> x_prime(m()), d(m());
|
||||
|
||||
|
||||
m().set(d, 1);
|
||||
if (m().lt(A, d))
|
||||
if (m().lt(A, d))
|
||||
m().set(x, A);
|
||||
else
|
||||
rough_approx_nth_root(A, n, x);
|
||||
|
||||
|
||||
round_to_minus_inf();
|
||||
|
||||
if (n == 2) {
|
||||
|
@ -297,8 +298,8 @@ void interval_manager<C>::approx_nth_root(numeral const & A, unsigned n, numeral
|
|||
_scoped_numeral<numeral_manager> _n(m()), _n_1(m());
|
||||
m().set(_n, n); // _n contains n
|
||||
m().set(_n_1, n);
|
||||
m().dec(_n_1); // _n_1 contains n-1
|
||||
|
||||
m().dec(_n_1); // _n_1 contains n-1
|
||||
|
||||
while (true) {
|
||||
checkpoint();
|
||||
#ifdef TRACE_NTH_ROOT
|
||||
|
@ -311,7 +312,7 @@ void interval_manager<C>::approx_nth_root(numeral const & A, unsigned n, numeral
|
|||
m().div(x_prime, _n, x_prime);
|
||||
m().sub(x_prime, x, d);
|
||||
m().abs(d);
|
||||
TRACE("nth_root",
|
||||
TRACE("nth_root",
|
||||
tout << "A: "; m().display(tout, A); tout << "\n";
|
||||
tout << "x: "; m().display(tout, x); tout << "\n";
|
||||
tout << "x_prime: "; m().display(tout, x_prime); tout << "\n";
|
||||
|
@ -340,7 +341,7 @@ void interval_manager<C>::nth_root_pos(numeral const & A, unsigned n, numeral co
|
|||
else {
|
||||
// Check if hi is really a upper bound for A^(n-1)
|
||||
A_div_x_n(A, hi, n-1, true /* lo will be greater than the actual lower bound */, lo);
|
||||
TRACE("nth_root_bug",
|
||||
TRACE("nth_root_bug",
|
||||
tout << "Assuming upper\n";
|
||||
tout << "A: "; m().display(tout, A); tout << "\n";
|
||||
tout << "hi: "; m().display(tout, hi); tout << "\n";
|
||||
|
@ -397,12 +398,12 @@ template<typename C>
|
|||
void interval_manager<C>::sine_series(numeral const & a, unsigned k, bool upper, numeral & o) {
|
||||
SASSERT(k % 2 == 1);
|
||||
// Compute sine using taylor series up to k
|
||||
// x - x^3/3! + x^5/5! - x^7/7! + ...
|
||||
// x - x^3/3! + x^5/5! - x^7/7! + ...
|
||||
// The result should be greater than or equal to the actual value if upper == true
|
||||
// Otherwise it must be less than or equal to the actual value.
|
||||
// The argument upper only matter if the numeral_manager is not precise.
|
||||
|
||||
// Taylor series up to k with rounding to
|
||||
// Taylor series up to k with rounding to
|
||||
_scoped_numeral<numeral_manager> f(m());
|
||||
_scoped_numeral<numeral_manager> aux(m());
|
||||
m().set(o, a);
|
||||
|
@ -412,7 +413,7 @@ void interval_manager<C>::sine_series(numeral const & a, unsigned k, bool upper,
|
|||
TRACE("sine_bug", tout << "[begin-loop] o: " << m().to_rational_string(o) << "\ni: " << i << "\n";
|
||||
tout << "upper: " << upper << ", upper_factor: " << upper_factor << "\n";
|
||||
tout << "o (default): " << m().to_string(o) << "\n";);
|
||||
set_rounding(upper_factor);
|
||||
set_rounding(upper_factor);
|
||||
m().power(a, i, f);
|
||||
TRACE("sine_bug", tout << "a^i " << m().to_rational_string(f) << "\n";);
|
||||
set_rounding(!upper_factor);
|
||||
|
@ -441,15 +442,15 @@ void interval_manager<C>::sine(numeral const & a, unsigned k, numeral & lo, nume
|
|||
m().reset(hi);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Compute sine using taylor series
|
||||
// x - x^3/3! + x^5/5! - x^7/7! + ...
|
||||
//
|
||||
// Note that, the coefficient of even terms is 0.
|
||||
// So, we force k to be odd to make sure the error is minimized.
|
||||
if (k % 2 == 0)
|
||||
k++;
|
||||
|
||||
k++;
|
||||
|
||||
// Taylor series error = |x|^(k+1)/(k+1)!
|
||||
_scoped_numeral<numeral_manager> error(m());
|
||||
_scoped_numeral<numeral_manager> aux(m());
|
||||
|
@ -466,7 +467,7 @@ void interval_manager<C>::sine(numeral const & a, unsigned k, numeral & lo, nume
|
|||
m().div(error, aux, error);
|
||||
TRACE("sine", tout << "error: " << m().to_rational_string(error) << "\n";);
|
||||
|
||||
// Taylor series up to k with rounding to -oo
|
||||
// Taylor series up to k with rounding to -oo
|
||||
sine_series(a, k, false, lo);
|
||||
|
||||
if (m().precise()) {
|
||||
|
@ -508,7 +509,7 @@ void interval_manager<C>::cosine_series(numeral const & a, unsigned k, bool uppe
|
|||
// The argument upper only matter if the numeral_manager is not precise.
|
||||
|
||||
|
||||
// Taylor series up to k with rounding to -oo
|
||||
// Taylor series up to k with rounding to -oo
|
||||
_scoped_numeral<numeral_manager> f(m());
|
||||
_scoped_numeral<numeral_manager> aux(m());
|
||||
m().set(o, 1);
|
||||
|
@ -527,7 +528,7 @@ void interval_manager<C>::cosine_series(numeral const & a, unsigned k, bool uppe
|
|||
else
|
||||
m().add(o, f, o);
|
||||
sign = !sign;
|
||||
upper_factor = !upper_factor;
|
||||
upper_factor = !upper_factor;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,15 +541,15 @@ void interval_manager<C>::cosine(numeral const & a, unsigned k, numeral & lo, nu
|
|||
m().set(hi, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Compute cosine using taylor series
|
||||
// 1 - x^2/2! + x^4/4! - x^6/6! + ...
|
||||
//
|
||||
// Note that, the coefficient of odd terms is 0.
|
||||
// So, we force k to be even to make sure the error is minimized.
|
||||
if (k % 2 == 1)
|
||||
k++;
|
||||
|
||||
k++;
|
||||
|
||||
// Taylor series error = |x|^(k+1)/(k+1)!
|
||||
_scoped_numeral<numeral_manager> error(m());
|
||||
_scoped_numeral<numeral_manager> aux(m());
|
||||
|
@ -563,9 +564,9 @@ void interval_manager<C>::cosine(numeral const & a, unsigned k, numeral & lo, nu
|
|||
m().div(error, aux, error);
|
||||
TRACE("sine", tout << "error: "; m().display_decimal(tout, error, 32); tout << "\n";);
|
||||
|
||||
// Taylor series up to k with rounding to -oo
|
||||
// Taylor series up to k with rounding to -oo
|
||||
cosine_series(a, k, false, lo);
|
||||
|
||||
|
||||
if (m().precise()) {
|
||||
m().set(hi, lo);
|
||||
m().sub(lo, error, lo);
|
||||
|
@ -614,12 +615,12 @@ void interval_manager<C>::reset(interval & a) {
|
|||
|
||||
template<typename C>
|
||||
bool interval_manager<C>::contains_zero(interval const & n) const {
|
||||
return
|
||||
return
|
||||
(lower_is_neg(n) || (lower_is_zero(n) && !lower_is_open(n))) &&
|
||||
(upper_is_pos(n) || (upper_is_zero(n) && !upper_is_open(n)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename C>
|
||||
bool interval_manager<C>::contains(interval const & n, numeral const & v) const {
|
||||
if (!lower_is_inf(n)) {
|
||||
|
@ -688,7 +689,7 @@ void interval_manager<C>::set(interval & t, interval const & s) {
|
|||
|
||||
template<typename C>
|
||||
bool interval_manager<C>::eq(interval const & a, interval const & b) const {
|
||||
return
|
||||
return
|
||||
::eq(m(), lower(a), lower_kind(a), lower(b), lower_kind(b)) &&
|
||||
::eq(m(), upper(a), upper_kind(a), upper(b), upper_kind(b)) &&
|
||||
lower_is_open(a) == lower_is_open(b) &&
|
||||
|
@ -792,7 +793,7 @@ void interval_manager<C>::add(interval const & a, interval const & b, interval &
|
|||
add_jst(a, b, c_deps);
|
||||
add(a, b, c);
|
||||
}
|
||||
|
||||
|
||||
template<typename C>
|
||||
void interval_manager<C>::add(interval const & a, interval const & b, interval & c) {
|
||||
ext_numeral_kind new_l_kind, new_u_kind;
|
||||
|
@ -869,7 +870,7 @@ void interval_manager<C>::div_mul(numeral const & k, interval const & a, interva
|
|||
round_to_minus_inf();
|
||||
m().inv(k, m_inv_k);
|
||||
::mul(m(), l, l_k, m_inv_k, EN_NUMERAL, new_l_val, new_l_kind);
|
||||
|
||||
|
||||
round_to_plus_inf();
|
||||
m().inv(k, m_inv_k);
|
||||
::mul(m(), u, u_k, m_inv_k, EN_NUMERAL, new_u_val, new_u_kind);
|
||||
|
@ -975,7 +976,7 @@ void interval_manager<C>::mul_jst(interval const & i1, interval const & i2, inte
|
|||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(is_P(i1));
|
||||
SASSERT(is_P(i1));
|
||||
if (is_N(i2)) {
|
||||
// 0 <= a <= x <= b, c <= y <= d <= 0 --> x*y <= b*c (uses the fact that x is pos (a is not neg) or y is neg (d is not pos))
|
||||
// 0 <= a <= x, y <= d <= 0 --> a*d <= x*y
|
||||
|
@ -990,7 +991,7 @@ void interval_manager<C>::mul_jst(interval const & i1, interval const & i2, inte
|
|||
}
|
||||
else {
|
||||
SASSERT(is_P(i2));
|
||||
// 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
|
||||
// 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
|
||||
// x <= b, y <= d --> x*y <= b*d (uses the fact that x is pos (a is not negative) or y is pos (c is not negative))
|
||||
r_deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
|
||||
r_deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_UPPER2 | DEP_IN_LOWER1; // we can replace DEP_IN_LOWER1 with DEP_IN_LOWER2
|
||||
|
@ -1075,11 +1076,11 @@ void interval_manager<C>::mul(interval const & i1, interval const & i2, interval
|
|||
// x <= b <= 0, 0 <= c <= y --> x*y <= b*c
|
||||
TRACE("interval_bug", tout << "(N, P) #" << call_id << "\n";);
|
||||
SASSERT(is_P(i2));
|
||||
|
||||
// must update upper_is_open first, since value of is_N0(i1) and is_P0(i2) may be affected by update
|
||||
|
||||
// must update upper_is_open first, since value of is_N0(i1) and is_P0(i2) may be affected by update
|
||||
set_upper_is_open(r, (is_N0(i1) || is_P0(i2)) ? false : (b_o || c_o));
|
||||
set_lower_is_open(r, a_o || d_o);
|
||||
|
||||
|
||||
round_to_minus_inf();
|
||||
::mul(m(), a, a_k, d, d_k, new_l_val, new_l_kind);
|
||||
round_to_plus_inf();
|
||||
|
@ -1093,7 +1094,7 @@ void interval_manager<C>::mul(interval const & i1, interval const & i2, interval
|
|||
TRACE("interval_bug", tout << "(M, N) #" << call_id << "\n";);
|
||||
|
||||
set_lower_is_open(r, b_o || c_o);
|
||||
set_upper_is_open(r, a_o || c_o);
|
||||
set_upper_is_open(r, a_o || c_o);
|
||||
|
||||
round_to_minus_inf();
|
||||
::mul(m(), b, b_k, c, c_k, new_l_val, new_l_kind);
|
||||
|
@ -1110,7 +1111,7 @@ void interval_manager<C>::mul(interval const & i1, interval const & i2, interval
|
|||
bool bc_o = b_o || c_o;
|
||||
bool ac_o = a_o || c_o;
|
||||
bool bd_o = b_o || d_o;
|
||||
|
||||
|
||||
round_to_minus_inf();
|
||||
::mul(m(), a, a_k, d, d_k, ad, ad_k);
|
||||
::mul(m(), b, b_k, c, c_k, bc, bc_k);
|
||||
|
@ -1129,7 +1130,7 @@ void interval_manager<C>::mul(interval const & i1, interval const & i2, interval
|
|||
set_lower_is_open(r, bc_o);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (::gt(m(), ac, ac_k, bd, bd_k) || (::eq(m(), ac, ac_k, bd, bd_k) && !ac_o && bd_o)) {
|
||||
m().swap(new_u_val, ac);
|
||||
new_u_kind = ac_k;
|
||||
|
@ -1148,7 +1149,7 @@ void interval_manager<C>::mul(interval const & i1, interval const & i2, interval
|
|||
SASSERT(is_P(i2));
|
||||
|
||||
set_lower_is_open(r, a_o || d_o);
|
||||
set_upper_is_open(r, b_o || d_o);
|
||||
set_upper_is_open(r, b_o || d_o);
|
||||
|
||||
round_to_minus_inf();
|
||||
::mul(m(), a, a_k, d, d_k, new_l_val, new_l_kind);
|
||||
|
@ -1157,13 +1158,13 @@ void interval_manager<C>::mul(interval const & i1, interval const & i2, interval
|
|||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(is_P(i1));
|
||||
SASSERT(is_P(i1));
|
||||
if (is_N(i2)) {
|
||||
// 0 <= a <= x <= b, c <= y <= d <= 0 --> x*y <= b*c (uses the fact that x is pos (a is not neg) or y is neg (d is not pos))
|
||||
// 0 <= a <= x, y <= d <= 0 --> a*d <= x*y
|
||||
TRACE("interval_bug", tout << "(P, N) #" << call_id << "\n";);
|
||||
|
||||
// must update upper_is_open first, since value of is_P0(i1) and is_N0(i2) may be affected by update
|
||||
|
||||
// must update upper_is_open first, since value of is_P0(i1) and is_N0(i2) may be affected by update
|
||||
set_upper_is_open(r, (is_P0(i1) || is_N0(i2)) ? false : a_o || d_o);
|
||||
set_lower_is_open(r, b_o || c_o);
|
||||
|
||||
|
@ -1187,7 +1188,7 @@ void interval_manager<C>::mul(interval const & i1, interval const & i2, interval
|
|||
}
|
||||
else {
|
||||
SASSERT(is_P(i2));
|
||||
// 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
|
||||
// 0 <= a <= x, 0 <= c <= y --> a*c <= x*y
|
||||
// x <= b, y <= d --> x*y <= b*d (uses the fact that x is pos (a is not negative) or y is pos (c is not negative))
|
||||
TRACE("interval_bug", tout << "(P, P) #" << call_id << "\n";);
|
||||
|
||||
|
@ -1232,7 +1233,7 @@ void interval_manager<C>::power_jst(interval const & a, unsigned n, interval_dep
|
|||
else if (upper_is_neg(a)) {
|
||||
// [l, u]^n = [u^n, l^n] if u < 0
|
||||
// l <= x <= u < 0 --> x^n <= l^n (use lower and upper bound -- need the fact that x is negative)
|
||||
// x <= u < 0 --> u^n <= x^n
|
||||
// x <= u < 0 --> u^n <= x^n
|
||||
b_deps.m_lower_deps = DEP_IN_UPPER1;
|
||||
if (lower_is_inf(a))
|
||||
b_deps.m_upper_deps = 0;
|
||||
|
@ -1252,7 +1253,7 @@ void interval_manager<C>::power_jst(interval const & a, unsigned n, interval_dep
|
|||
b_deps.m_lower_deps = 0;
|
||||
else
|
||||
b_deps.m_lower_deps = DEP_IN_LOWER1;
|
||||
|
||||
|
||||
if (upper_is_inf(a))
|
||||
b_deps.m_upper_deps = 0;
|
||||
else
|
||||
|
@ -1298,15 +1299,15 @@ void interval_manager<C>::power(interval const & a, unsigned n, interval & b) {
|
|||
else if (upper_is_neg(a)) {
|
||||
// [l, u]^n = [u^n, l^n] if u < 0
|
||||
// l <= x <= u < 0 --> x^n <= l^n (use lower and upper bound -- need the fact that x is negative)
|
||||
// x <= u < 0 --> u^n <= x^n
|
||||
// x <= u < 0 --> u^n <= x^n
|
||||
SASSERT(!upper_is_inf(a));
|
||||
bool lower_a_open = lower_is_open(a), upper_a_open = upper_is_open(a);
|
||||
bool lower_a_inf = lower_is_inf(a);
|
||||
|
||||
|
||||
m().set(lower(b), lower(a));
|
||||
m().set(upper(b), upper(a));
|
||||
m().swap(lower(b), upper(b)); // we use a swap because a and b can be aliased
|
||||
|
||||
|
||||
|
||||
round_to_minus_inf();
|
||||
m().power(lower(b), n, lower(b));
|
||||
|
@ -1337,7 +1338,7 @@ void interval_manager<C>::power(interval const & a, unsigned n, interval & b) {
|
|||
round_to_plus_inf();
|
||||
::power(m(), un1, un1_kind, n);
|
||||
::power(m(), un2, un2_kind, n);
|
||||
|
||||
|
||||
if (::gt(m(), un1, un1_kind, un2, un2_kind) || (::eq(m(), un1, un1_kind, un2, un2_kind) && !lower_is_open(a) && upper_is_open(a))) {
|
||||
m().swap(upper(b), un1);
|
||||
set_upper_is_inf(b, un1_kind == EN_PLUS_INFINITY);
|
||||
|
@ -1348,7 +1349,7 @@ void interval_manager<C>::power(interval const & a, unsigned n, interval & b) {
|
|||
set_upper_is_inf(b, un2_kind == EN_PLUS_INFINITY);
|
||||
set_upper_is_open(b, upper_is_open(a));
|
||||
}
|
||||
|
||||
|
||||
m().reset(lower(b));
|
||||
set_lower_is_inf(b, false);
|
||||
set_lower_is_open(b, false);
|
||||
|
@ -1359,8 +1360,8 @@ void interval_manager<C>::power(interval const & a, unsigned n, interval & b) {
|
|||
if (lower_is_inf(a)) {
|
||||
reset_lower(b);
|
||||
}
|
||||
else {
|
||||
m().power(lower(a), n, lower(b));
|
||||
else {
|
||||
m().power(lower(a), n, lower(b));
|
||||
set_lower_is_inf(b, false);
|
||||
set_lower_is_open(b, lower_is_open(a));
|
||||
}
|
||||
|
@ -1409,7 +1410,7 @@ void interval_manager<C>::nth_root(interval const & a, unsigned n, numeral const
|
|||
set_lower_is_open(b, lower_is_open(a) && m().eq(lo, hi));
|
||||
m().set(lower(b), lo);
|
||||
}
|
||||
|
||||
|
||||
if (upper_is_inf(a)) {
|
||||
m().reset(upper(b));
|
||||
set_upper_is_inf(b, true);
|
||||
|
@ -1423,7 +1424,7 @@ void interval_manager<C>::nth_root(interval const & a, unsigned n, numeral const
|
|||
set_upper_is_open(b, upper_is_open(a) && m().eq(lo, hi));
|
||||
m().set(upper(b), hi);
|
||||
}
|
||||
TRACE("interval_nth_root", display(tout, a); tout << " --> "; display(tout, b); tout << "\n";);
|
||||
TRACE("interval_nth_root", display(tout, a); tout << " --> "; display(tout, b); tout << "\n";);
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
|
@ -1523,17 +1524,17 @@ void interval_manager<C>::inv(interval const & a, interval & b) {
|
|||
numeral & new_l_val = m_result_lower;
|
||||
numeral & new_u_val = m_result_upper;
|
||||
ext_numeral_kind new_l_kind, new_u_kind;
|
||||
|
||||
|
||||
if (is_P1(a)) {
|
||||
// 0 < l <= x --> 1/x <= 1/l
|
||||
// 0 < l <= x <= u --> 1/u <= 1/x (use lower and upper bounds)
|
||||
|
||||
|
||||
round_to_minus_inf();
|
||||
m().set(new_l_val, upper(a)); new_l_kind = upper_kind(a);
|
||||
::inv(m(), new_l_val, new_l_kind);
|
||||
SASSERT(new_l_kind == EN_NUMERAL);
|
||||
bool new_l_open = upper_is_open(a);
|
||||
|
||||
|
||||
if (lower_is_zero(a)) {
|
||||
SASSERT(lower_is_open(a));
|
||||
m().reset(upper(b));
|
||||
|
@ -1542,15 +1543,15 @@ void interval_manager<C>::inv(interval const & a, interval & b) {
|
|||
}
|
||||
else {
|
||||
round_to_plus_inf();
|
||||
m().set(new_u_val, lower(a));
|
||||
m().set(new_u_val, lower(a));
|
||||
m().inv(new_u_val);
|
||||
m().swap(upper(b), new_u_val);
|
||||
set_upper_is_inf(b, false);
|
||||
set_upper_is_open(b, lower_is_open(a));
|
||||
}
|
||||
|
||||
m().swap(lower(b), new_l_val);
|
||||
set_lower_is_inf(b, false);
|
||||
|
||||
m().swap(lower(b), new_l_val);
|
||||
set_lower_is_inf(b, false);
|
||||
set_lower_is_open(b, new_l_open);
|
||||
}
|
||||
else if (is_N1(a)) {
|
||||
|
@ -1577,8 +1578,8 @@ void interval_manager<C>::inv(interval const & a, interval & b) {
|
|||
set_lower_is_inf(b, false);
|
||||
set_lower_is_open(b, upper_is_open(a));
|
||||
}
|
||||
|
||||
m().swap(upper(b), new_u_val);
|
||||
|
||||
m().swap(upper(b), new_u_val);
|
||||
set_upper_is_inf(b, false);
|
||||
set_upper_is_open(b, new_u_open);
|
||||
}
|
||||
|
@ -1610,12 +1611,12 @@ void interval_manager<C>::div_jst(interval const & i1, interval const & i2, inte
|
|||
// x <= b <= 0, c <= y <= d < 0 --> b/c <= x/y
|
||||
// a <= x <= b <= 0, y <= d < 0 --> x/y <= a/d
|
||||
r_deps.m_lower_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
|
||||
r_deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2;
|
||||
r_deps.m_upper_deps = DEP_IN_LOWER1 | DEP_IN_UPPER2;
|
||||
}
|
||||
else {
|
||||
// a <= x, a < 0, 0 < c <= y --> a/c <= x/y
|
||||
// x <= b <= 0, 0 < c <= y <= d --> x/y <= b/d
|
||||
r_deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
|
||||
r_deps.m_lower_deps = DEP_IN_LOWER1 | DEP_IN_LOWER2;
|
||||
r_deps.m_upper_deps = DEP_IN_UPPER1 | DEP_IN_LOWER2 | DEP_IN_UPPER2;
|
||||
}
|
||||
}
|
||||
|
@ -1634,7 +1635,7 @@ void interval_manager<C>::div_jst(interval const & i1, interval const & i2, inte
|
|||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(is_P(i1));
|
||||
SASSERT(is_P(i1));
|
||||
if (is_N1(i2)) {
|
||||
// b > 0, x <= b, c <= y <= d < 0 --> b/d <= x/y
|
||||
// 0 <= a <= x, c <= y <= d < 0 --> x/y <= a/c
|
||||
|
@ -1665,7 +1666,7 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
#endif
|
||||
SASSERT(!contains_zero(i2));
|
||||
SASSERT(&i1 != &r);
|
||||
|
||||
|
||||
if (is_zero(i1)) {
|
||||
TRACE("interval_bug", tout << "div #" << call_id << "\n"; display(tout, i1); tout << "\n"; display(tout, i2); tout << "\n";);
|
||||
|
||||
|
@ -1682,12 +1683,12 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
numeral const & b = upper(i1); ext_numeral_kind b_k = upper_kind(i1);
|
||||
numeral const & c = lower(i2); ext_numeral_kind c_k = lower_kind(i2);
|
||||
numeral const & d = upper(i2); ext_numeral_kind d_k = upper_kind(i2);
|
||||
|
||||
|
||||
bool a_o = lower_is_open(i1);
|
||||
bool b_o = upper_is_open(i1);
|
||||
bool c_o = lower_is_open(i2);
|
||||
bool d_o = upper_is_open(i2);
|
||||
|
||||
|
||||
numeral & new_l_val = m_result_lower;
|
||||
numeral & new_u_val = m_result_upper;
|
||||
ext_numeral_kind new_l_kind, new_u_kind;
|
||||
|
@ -1698,7 +1699,7 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
tout << "c: "; m().display(tout, c); tout << "\n";
|
||||
tout << "d: "; m().display(tout, d); tout << "\n";
|
||||
);
|
||||
|
||||
|
||||
if (is_N(i1)) {
|
||||
if (is_N1(i2)) {
|
||||
// x <= b <= 0, c <= y <= d < 0 --> b/c <= x/y
|
||||
|
@ -1707,7 +1708,7 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
|
||||
set_lower_is_open(r, is_N0(i1) ? false : b_o || c_o);
|
||||
set_upper_is_open(r, a_o || d_o);
|
||||
|
||||
|
||||
round_to_minus_inf();
|
||||
::div(m(), b, b_k, c, c_k, new_l_val, new_l_kind);
|
||||
if (m().is_zero(d)) {
|
||||
|
@ -1725,10 +1726,10 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
// x <= b <= 0, 0 < c <= y <= d --> x/y <= b/d
|
||||
TRACE("interval_bug", tout << "(N, P) #" << call_id << "\n";);
|
||||
SASSERT(is_P1(i2));
|
||||
|
||||
|
||||
set_upper_is_open(r, is_N0(i1) ? false : (b_o || d_o));
|
||||
set_lower_is_open(r, a_o || c_o);
|
||||
|
||||
|
||||
if (m().is_zero(c)) {
|
||||
SASSERT(c_o);
|
||||
m().reset(new_l_val);
|
||||
|
@ -1747,10 +1748,10 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
// 0 < a <= x <= b < 0, y <= d < 0 --> b/d <= x/y
|
||||
// 0 < a <= x <= b < 0, y <= d < 0 --> x/y <= a/d
|
||||
TRACE("interval_bug", tout << "(M, N) #" << call_id << "\n";);
|
||||
|
||||
|
||||
set_lower_is_open(r, b_o || d_o);
|
||||
set_upper_is_open(r, a_o || d_o);
|
||||
|
||||
set_upper_is_open(r, a_o || d_o);
|
||||
|
||||
if (m().is_zero(d)) {
|
||||
SASSERT(d_o);
|
||||
m().reset(new_l_val); m().reset(new_u_val);
|
||||
|
@ -1771,10 +1772,10 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
|
||||
TRACE("interval_bug", tout << "(M, P) #" << call_id << "\n";);
|
||||
SASSERT(is_P1(i2));
|
||||
|
||||
|
||||
set_lower_is_open(r, a_o || c_o);
|
||||
set_upper_is_open(r, b_o || c_o);
|
||||
|
||||
set_upper_is_open(r, b_o || c_o);
|
||||
|
||||
if (m().is_zero(c)) {
|
||||
SASSERT(c_o);
|
||||
m().reset(new_l_val); m().reset(new_u_val);
|
||||
|
@ -1790,15 +1791,15 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(is_P(i1));
|
||||
SASSERT(is_P(i1));
|
||||
if (is_N1(i2)) {
|
||||
// b > 0, x <= b, c <= y <= d < 0 --> b/d <= x/y
|
||||
// 0 <= a <= x, c <= y <= d < 0 --> x/y <= a/c
|
||||
TRACE("interval_bug", tout << "(P, N) #" << call_id << "\n";);
|
||||
|
||||
|
||||
set_upper_is_open(r, is_P0(i1) ? false : a_o || c_o);
|
||||
set_lower_is_open(r, b_o || d_o);
|
||||
|
||||
|
||||
if (m().is_zero(d)) {
|
||||
SASSERT(d_o);
|
||||
m().reset(new_l_val);
|
||||
|
@ -1816,10 +1817,10 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
// 0 <= a <= x, 0 < c <= y <= d --> a/d <= x/y
|
||||
// b > 0 x <= b, 0 < c <= y --> x/y <= b/c
|
||||
TRACE("interval_bug", tout << "(P, P) #" << call_id << "\n";);
|
||||
|
||||
|
||||
set_lower_is_open(r, is_P0(i1) ? false : a_o || d_o);
|
||||
set_upper_is_open(r, b_o || c_o);
|
||||
|
||||
|
||||
round_to_minus_inf();
|
||||
::div(m(), a, a_k, d, d_k, new_l_val, new_l_kind);
|
||||
if (m().is_zero(c)) {
|
||||
|
@ -1833,7 +1834,7 @@ void interval_manager<C>::div(interval const & i1, interval const & i2, interval
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m().swap(lower(r), new_l_val);
|
||||
m().swap(upper(r), new_u_val);
|
||||
set_lower_is_inf(r, new_l_kind == EN_MINUS_INFINITY);
|
||||
|
@ -1851,16 +1852,16 @@ void interval_manager<C>::pi_series(int x, numeral & r, bool up) {
|
|||
_scoped_numeral<numeral_manager> f(m());
|
||||
set_rounding(up);
|
||||
m().set(r, 4, 8*x + 1);
|
||||
set_rounding(!up);
|
||||
set_rounding(!up);
|
||||
m().set(f, 2, 8*x + 4);
|
||||
set_rounding(up);
|
||||
m().sub(r, f, r);
|
||||
set_rounding(!up);
|
||||
set_rounding(!up);
|
||||
m().set(f, 1, 8*x + 5);
|
||||
set_rounding(up);
|
||||
m().sub(r, f, r);
|
||||
set_rounding(!up);
|
||||
m().set(f, 1, 8*x + 6);
|
||||
m().set(f, 1, 8*x + 6);
|
||||
set_rounding(up);
|
||||
m().sub(r, f, r);
|
||||
m().set(f, 1, 16);
|
||||
|
@ -1870,16 +1871,16 @@ void interval_manager<C>::pi_series(int x, numeral & r, bool up) {
|
|||
|
||||
template<typename C>
|
||||
void interval_manager<C>::pi(unsigned n, interval & r) {
|
||||
// Compute an interval that contains pi using the series
|
||||
// Compute an interval that contains pi using the series
|
||||
// P[0] + P[1] + ... + P[n]
|
||||
// where
|
||||
// P[n] := 1/16^x (4/(8x + 1) - 2/(8x + 4) - 1/(8x + 5) - 1/(8x + 6))
|
||||
//
|
||||
//
|
||||
// The size of the interval is 1/15 * 1/(16^n)
|
||||
//
|
||||
// Lower is P[0] + P[1] + ... + P[n]
|
||||
// Upper is Lower + 1/15 * 1/(16^n)
|
||||
|
||||
|
||||
// compute size of the resulting interval
|
||||
round_to_plus_inf(); // overestimate size of the interval
|
||||
_scoped_numeral<numeral_manager> len(m());
|
||||
|
@ -1888,7 +1889,7 @@ void interval_manager<C>::pi(unsigned n, interval & r) {
|
|||
m().power(len, n, len);
|
||||
m().set(p, 1, 15);
|
||||
m().mul(p, len, len);
|
||||
|
||||
|
||||
// compute lower bound
|
||||
numeral & l_val = m_result_lower;
|
||||
m().reset(l_val);
|
||||
|
@ -1897,7 +1898,7 @@ void interval_manager<C>::pi(unsigned n, interval & r) {
|
|||
round_to_minus_inf();
|
||||
m().add(l_val, p, l_val);
|
||||
}
|
||||
|
||||
|
||||
// computer upper bound
|
||||
numeral & u_val = m_result_upper;
|
||||
if (m().precise()) {
|
||||
|
@ -1959,7 +1960,7 @@ void interval_manager<C>::e_series(unsigned k, bool upper, numeral & o) {
|
|||
template<typename C>
|
||||
void interval_manager<C>::e(unsigned k, interval & r) {
|
||||
// Store in r lower and upper bounds for Euler's constant.
|
||||
//
|
||||
//
|
||||
// The procedure uses the series
|
||||
//
|
||||
// V = 1 + 1/1 + 1/2! + 1/3! + ... + 1/k!
|
||||
|
@ -1976,9 +1977,9 @@ void interval_manager<C>::e(unsigned k, interval & r) {
|
|||
fact(k+1, error);
|
||||
round_to_plus_inf();
|
||||
m().inv(error); // error == 1/(k+1)!
|
||||
m().set(aux, 4);
|
||||
m().set(aux, 4);
|
||||
m().mul(aux, error, error); // error == 4/(k+1)!
|
||||
|
||||
|
||||
if (m().precise()) {
|
||||
m().set(hi, lo);
|
||||
m().add(hi, error, hi);
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -8,12 +8,12 @@ Module Name:
|
|||
Abstract:
|
||||
|
||||
Goodies for creating and handling univariate polynomials.
|
||||
|
||||
A dense representation is much better for Root isolation algorithms,
|
||||
|
||||
A dense representation is much better for Root isolation algorithms,
|
||||
encoding algebraic numbers, factorization, etc.
|
||||
|
||||
We also use integers as the coefficients of univariate polynomials.
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2011-11-29
|
||||
|
@ -26,21 +26,22 @@ Notes:
|
|||
#include"polynomial_primes.h"
|
||||
#include"buffer.h"
|
||||
#include"cooperate.h"
|
||||
#include"common_msgs.h"
|
||||
|
||||
namespace upolynomial {
|
||||
|
||||
core_manager::factors::factors(core_manager & upm):
|
||||
m_upm(upm),
|
||||
m_total_factors(0),
|
||||
m_total_degree(0) {
|
||||
nm().set(m_constant, 1);
|
||||
core_manager::factors::factors(core_manager & upm):
|
||||
m_upm(upm),
|
||||
m_total_factors(0),
|
||||
m_total_degree(0) {
|
||||
nm().set(m_constant, 1);
|
||||
}
|
||||
|
||||
|
||||
core_manager::factors::~factors() {
|
||||
clear();
|
||||
nm().del(m_constant);
|
||||
}
|
||||
|
||||
|
||||
void core_manager::factors::clear() {
|
||||
for (unsigned i = 0; i < m_factors.size(); ++ i) {
|
||||
m_upm.reset(m_factors[i]);
|
||||
|
@ -104,19 +105,19 @@ namespace upolynomial {
|
|||
}
|
||||
}
|
||||
|
||||
numeral_manager & core_manager::factors::nm() const {
|
||||
return m_upm.m();
|
||||
}
|
||||
numeral_manager & core_manager::factors::nm() const {
|
||||
return m_upm.m();
|
||||
}
|
||||
|
||||
void core_manager::factors::set_constant(numeral const & constant) {
|
||||
nm().set(m_constant, constant);
|
||||
}
|
||||
void core_manager::factors::set_constant(numeral const & constant) {
|
||||
nm().set(m_constant, constant);
|
||||
}
|
||||
|
||||
void core_manager::factors::set_degree(unsigned i, unsigned degree) {
|
||||
void core_manager::factors::set_degree(unsigned i, unsigned degree) {
|
||||
m_total_degree -= m_upm.degree(m_factors[i])*m_degrees[i];
|
||||
m_total_factors -= m_degrees[i];
|
||||
m_degrees[i] = degree;
|
||||
m_total_factors += degree;
|
||||
m_total_factors -= m_degrees[i];
|
||||
m_degrees[i] = degree;
|
||||
m_total_factors += degree;
|
||||
m_total_degree += m_upm.degree(m_factors[i])*degree;
|
||||
}
|
||||
|
||||
|
@ -125,7 +126,7 @@ namespace upolynomial {
|
|||
m_total_degree += m_upm.degree(p)*m_degrees[i];
|
||||
m_factors[i].swap(p);
|
||||
}
|
||||
|
||||
|
||||
void core_manager::factors::swap(factors & other) {
|
||||
m_factors.swap(other.m_factors);
|
||||
m_degrees.swap(other.m_degrees);
|
||||
|
@ -154,8 +155,8 @@ namespace upolynomial {
|
|||
}
|
||||
|
||||
void core_manager::checkpoint() {
|
||||
if (!m_limit.inc())
|
||||
throw upolynomial_exception("canceled");
|
||||
if (!m_limit.inc())
|
||||
throw upolynomial_exception(Z3_CANCELED_MSG);
|
||||
cooperate("upolynomial");
|
||||
}
|
||||
|
||||
|
@ -209,7 +210,7 @@ namespace upolynomial {
|
|||
set_size(sz, buffer);
|
||||
}
|
||||
|
||||
void core_manager::get_primitive_and_content(unsigned f_sz, numeral const * f, numeral_vector & pp, numeral & cont) {
|
||||
void core_manager::get_primitive_and_content(unsigned f_sz, numeral const * f, numeral_vector & pp, numeral & cont) {
|
||||
SASSERT(f_sz > 0);
|
||||
m().gcd(f_sz, f, cont);
|
||||
SASSERT(m().is_pos(cont));
|
||||
|
@ -221,7 +222,7 @@ namespace upolynomial {
|
|||
for (unsigned i = 0; i < f_sz; i++) {
|
||||
if (!m().is_zero(f[i])) {
|
||||
m().div(f[i], cont, pp[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m().set(pp[i], 0);
|
||||
}
|
||||
|
@ -252,7 +253,7 @@ namespace upolynomial {
|
|||
neg_core(sz, p, m_basic_tmp);
|
||||
buffer.swap(m_basic_tmp);
|
||||
}
|
||||
|
||||
|
||||
// buffer := p1 + p2
|
||||
void core_manager::add_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer) {
|
||||
SASSERT(!is_alias(p1, buffer));
|
||||
|
@ -334,7 +335,7 @@ namespace upolynomial {
|
|||
numeral const & b_j = p2[j];
|
||||
if (m().is_zero(b_j))
|
||||
continue;
|
||||
m().addmul(buffer[i+j], a_i, b_j, buffer[i+j]);
|
||||
m().addmul(buffer[i+j], a_i, b_j, buffer[i+j]);
|
||||
}
|
||||
}
|
||||
set_size(new_sz, buffer);
|
||||
|
@ -378,7 +379,7 @@ namespace upolynomial {
|
|||
return;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
#ifdef Z3DEBUG
|
||||
scoped_numeral old_p_i(m());
|
||||
scoped_numeral old_p_i(m());
|
||||
old_p_i = p[i];
|
||||
#endif
|
||||
// Actual code
|
||||
|
@ -387,7 +388,7 @@ namespace upolynomial {
|
|||
#ifdef Z3DEBUG
|
||||
scoped_numeral tmp(m());
|
||||
m().mul(g, p[i], tmp);
|
||||
CTRACE("div_bug", !m().eq(tmp, old_p_i), tout << "old(p[i]): " << m().to_string(old_p_i) << ", g: " << m().to_string(g) << ", p[i]: " <<
|
||||
CTRACE("div_bug", !m().eq(tmp, old_p_i), tout << "old(p[i]): " << m().to_string(old_p_i) << ", g: " << m().to_string(g) << ", p[i]: " <<
|
||||
m().to_string(p[i]) << ", tmp: " << m().to_string(tmp) << "\n";);
|
||||
SASSERT(tmp == old_p_i);
|
||||
#endif
|
||||
|
@ -428,7 +429,7 @@ namespace upolynomial {
|
|||
}
|
||||
|
||||
// Pseudo division
|
||||
void core_manager::div_rem_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2,
|
||||
void core_manager::div_rem_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2,
|
||||
unsigned & d, numeral_vector & q, numeral_vector & r) {
|
||||
SASSERT(!is_alias(p1, q)); SASSERT(!is_alias(p2, q));
|
||||
SASSERT(!is_alias(p1, r)); SASSERT(!is_alias(p2, r));
|
||||
|
@ -438,7 +439,7 @@ namespace upolynomial {
|
|||
set(sz1, p1, q);
|
||||
if (field()) {
|
||||
div(q, *p2);
|
||||
}
|
||||
}
|
||||
reset(r);
|
||||
return;
|
||||
}
|
||||
|
@ -464,7 +465,7 @@ namespace upolynomial {
|
|||
set_size(qsz, q);
|
||||
return;
|
||||
}
|
||||
unsigned m_n = sz1 - sz2; // m-n
|
||||
unsigned m_n = sz1 - sz2; // m-n
|
||||
if (field()) {
|
||||
numeral & ratio = a_m;
|
||||
m().div(r[sz1 - 1], b_n, ratio);
|
||||
|
@ -492,7 +493,7 @@ namespace upolynomial {
|
|||
}
|
||||
|
||||
// Pseudo division
|
||||
void core_manager::div_rem(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, unsigned & d,
|
||||
void core_manager::div_rem(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, unsigned & d,
|
||||
numeral_vector & q, numeral_vector & r) {
|
||||
numeral_vector & _r = m_div_tmp1;
|
||||
numeral_vector & _q = m_div_tmp2;
|
||||
|
@ -677,15 +678,15 @@ namespace upolynomial {
|
|||
scoped_numeral a1(m());
|
||||
scoped_numeral a2(m());
|
||||
m().mul(b2, inv2, a1); // a1 is the multiplicator for coefficients of C1
|
||||
m().mul(b1, inv1, a2); // a2 is the multiplicator for coefficients of C2
|
||||
m().mul(b1, inv1, a2); // a2 is the multiplicator for coefficients of C2
|
||||
TRACE("CRA", tout << "a1: " << a1 << ", a2: " << a2 << "\n";);
|
||||
// new bound
|
||||
scoped_numeral new_bound(m());
|
||||
m().mul(b1, b2, new_bound);
|
||||
m().mul(b1, b2, new_bound);
|
||||
scoped_numeral lower(m());
|
||||
scoped_numeral upper(m());
|
||||
scoped_numeral new_a(m()), tmp1(m()), tmp2(m()), tmp3(m());
|
||||
m().div(new_bound, 2, upper);
|
||||
m().div(new_bound, 2, upper);
|
||||
m().set(lower, upper);
|
||||
m().neg(lower);
|
||||
TRACE("CRA", tout << "lower: " << lower << ", upper: " << upper << "\n";);
|
||||
|
@ -700,7 +701,7 @@ namespace upolynomial {
|
|||
R.push_back(numeral()); \
|
||||
m().set(R.back(), new_a); \
|
||||
}
|
||||
|
||||
|
||||
numeral zero(0);
|
||||
unsigned i = 0;
|
||||
unsigned sz1 = C1.size();
|
||||
|
@ -718,7 +719,7 @@ namespace upolynomial {
|
|||
m().set(b2, new_bound);
|
||||
R.swap(C2);
|
||||
}
|
||||
|
||||
|
||||
void core_manager::mod_gcd(unsigned sz_u, numeral const * u,
|
||||
unsigned sz_v, numeral const * v,
|
||||
numeral_vector & result) {
|
||||
|
@ -726,8 +727,8 @@ namespace upolynomial {
|
|||
SASSERT(sz_u > 0 && sz_v > 0);
|
||||
SASSERT(!m().modular());
|
||||
scoped_numeral c_u(m()), c_v(m());
|
||||
numeral_vector & pp_u = m_mgcd_tmp[0];
|
||||
numeral_vector & pp_v = m_mgcd_tmp[1];
|
||||
numeral_vector & pp_u = m_mgcd_tmp[0];
|
||||
numeral_vector & pp_v = m_mgcd_tmp[1];
|
||||
get_primitive_and_content(sz_u, u, pp_u, c_u);
|
||||
get_primitive_and_content(sz_v, v, pp_v, c_v);
|
||||
scoped_numeral c_g(m());
|
||||
|
@ -745,7 +746,7 @@ namespace upolynomial {
|
|||
numeral_vector & v_Zp = m_mgcd_tmp[3];
|
||||
numeral_vector & q = m_mgcd_tmp[4];
|
||||
numeral_vector & C = m_mgcd_tmp[5];
|
||||
|
||||
|
||||
for (unsigned i = 0; i < NUM_BIG_PRIMES; i++) {
|
||||
m().set(p, polynomial::g_big_primes[i]);
|
||||
TRACE("mgcd", tout << "trying prime: " << p << "\n";);
|
||||
|
@ -797,8 +798,8 @@ namespace upolynomial {
|
|||
TRACE("mgcd", tout << "candidate:\n"; display_star(tout, candidate); tout << "\n";);
|
||||
SASSERT(candidate.size() > 0);
|
||||
numeral const & lc_candidate = candidate[candidate.size() - 1];
|
||||
if (m().divides(lc_candidate, lc_g) &&
|
||||
divides(pp_u, candidate) &&
|
||||
if (m().divides(lc_candidate, lc_g) &&
|
||||
divides(pp_u, candidate) &&
|
||||
divides(pp_v, candidate)) {
|
||||
TRACE("mgcd", tout << "found GCD\n";);
|
||||
mul(candidate, c_g);
|
||||
|
@ -845,9 +846,9 @@ namespace upolynomial {
|
|||
else {
|
||||
flip_sign_if_lm_neg(buffer);
|
||||
}
|
||||
TRACE("upolynomial", tout << "GCD\n"; display(tout, sz1, p1); tout << "\n"; display(tout, sz2, p2); tout << "\n--->\n";
|
||||
TRACE("upolynomial", tout << "GCD\n"; display(tout, sz1, p1); tout << "\n"; display(tout, sz2, p2); tout << "\n--->\n";
|
||||
display(tout, buffer); tout << "\n";);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
rem(A.size(), A.c_ptr(), B.size(), B.c_ptr(), R);
|
||||
normalize(R);
|
||||
|
@ -868,7 +869,7 @@ namespace upolynomial {
|
|||
flip_sign_if_lm_neg(buffer);
|
||||
return;
|
||||
}
|
||||
if (!modular())
|
||||
if (!modular())
|
||||
mod_gcd(sz1, p1, sz2, p2, buffer);
|
||||
else
|
||||
euclid_gcd(sz1, p1, sz2, p2, buffer);
|
||||
|
@ -913,9 +914,9 @@ namespace upolynomial {
|
|||
else {
|
||||
flip_sign_if_lm_neg(buffer);
|
||||
}
|
||||
TRACE("upolynomial", tout << "subresultant GCD\n"; display(tout, sz1, p1); tout << "\n"; display(tout, sz2, p2); tout << "\n--->\n";
|
||||
TRACE("upolynomial", tout << "subresultant GCD\n"; display(tout, sz1, p1); tout << "\n"; display(tout, sz2, p2); tout << "\n--->\n";
|
||||
display(tout, buffer); tout << "\n";);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
rem(A.size(), A.c_ptr(), B.size(), B.c_ptr(), d, R);
|
||||
unsigned pseudo_div_d = A.size() - B.size();
|
||||
|
@ -928,7 +929,7 @@ namespace upolynomial {
|
|||
m().power(B[B.size() - 1], pseudo_div_d + 1 - d, aux);
|
||||
mul(R, aux);
|
||||
}
|
||||
d = pseudo_div_d;
|
||||
d = pseudo_div_d;
|
||||
TRACE("upolynomial", tout << "R: "; display(tout, R); tout << "\nd: " << d << "\n";);
|
||||
// aux <- g*h^d
|
||||
m().power(h, d, aux);
|
||||
|
@ -961,7 +962,7 @@ namespace upolynomial {
|
|||
|
||||
// buffer := square-free(p)
|
||||
void core_manager::square_free(unsigned sz, numeral const * p, numeral_vector & buffer) {
|
||||
SASSERT(!is_alias(p, buffer));
|
||||
SASSERT(!is_alias(p, buffer));
|
||||
if (sz <= 1) {
|
||||
set(sz, p, buffer);
|
||||
return;
|
||||
|
@ -1000,11 +1001,11 @@ namespace upolynomial {
|
|||
return;
|
||||
}
|
||||
|
||||
if (k == 1 || sz == 0 || (sz == 1 && m().is_one(p[0]))) {
|
||||
if (k == 1 || sz == 0 || (sz == 1 && m().is_one(p[0]))) {
|
||||
set(sz, p, r);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
numeral_vector & result = m_pw_tmp;
|
||||
set(sz, p, result);
|
||||
for (unsigned i = 1; i < k; i++)
|
||||
|
@ -1039,18 +1040,18 @@ namespace upolynomial {
|
|||
m().mul(p[d], lc_inv, p[d]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extended GCD
|
||||
void core_manager::ext_gcd(unsigned szA, numeral const * A, unsigned szB, numeral const * B,
|
||||
void core_manager::ext_gcd(unsigned szA, numeral const * A, unsigned szB, numeral const * B,
|
||||
numeral_vector & U, numeral_vector & V, numeral_vector & D) {
|
||||
SASSERT(!is_alias(A, U)); SASSERT(!is_alias(A, V)); SASSERT(!is_alias(A, D));
|
||||
SASSERT(!is_alias(B, U)); SASSERT(!is_alias(B, V)); SASSERT(!is_alias(B, D));
|
||||
|
||||
SASSERT(field());
|
||||
scoped_numeral_vector V1(m()), V3(m()), Q(m()), R(m()), T(m()), V1Q(m());
|
||||
|
||||
|
||||
// since we are in a field define gcd(A, B) to be monic
|
||||
// if AU + BV = D and D is not monic we make it monic, and then divide U and V by the same inverse
|
||||
|
||||
|
@ -1058,13 +1059,13 @@ namespace upolynomial {
|
|||
// U <- 1
|
||||
reset(U); U.push_back(numeral()); m().set(U.back(), 1);
|
||||
// D <- A
|
||||
set(szA, A, D);
|
||||
set(szA, A, D);
|
||||
mk_monic(szA, D.c_ptr());
|
||||
// V1 <- 0
|
||||
reset(V1);
|
||||
reset(V1);
|
||||
// V3 <- B
|
||||
set(szB, B, V3);
|
||||
|
||||
set(szB, B, V3);
|
||||
|
||||
while (true) {
|
||||
if (V3.empty()) {
|
||||
// V3 is the zero polynomial
|
||||
|
@ -1088,10 +1089,10 @@ namespace upolynomial {
|
|||
mul(V, lc_inv);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// D = QV3 + R
|
||||
div_rem(D.size(), D.c_ptr(), V3.size(), V3.c_ptr(), Q, R);
|
||||
|
||||
|
||||
// T <- U - V1Q
|
||||
mul(V1.size(), V1.c_ptr(), Q.size(), Q.c_ptr(), V1Q);
|
||||
sub(U.size(), U.c_ptr(), V1Q.size(), V1Q.c_ptr(), T);
|
||||
|
@ -1104,8 +1105,8 @@ namespace upolynomial {
|
|||
// V3 <- R
|
||||
V3.swap(R);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Display p
|
||||
void core_manager::display(std::ostream & out, unsigned sz, numeral const * p, char const * var_name, bool use_star) const {
|
||||
bool displayed = false;
|
||||
|
@ -1144,7 +1145,7 @@ namespace upolynomial {
|
|||
if (!displayed)
|
||||
out << "0";
|
||||
}
|
||||
|
||||
|
||||
static void display_smt2_mumeral(std::ostream & out, numeral_manager & m, mpz const & n) {
|
||||
if (m.is_neg(n)) {
|
||||
out << "(- ";
|
||||
|
@ -1172,7 +1173,7 @@ namespace upolynomial {
|
|||
out << "(^ " << var_name << " " << k << ")";
|
||||
}
|
||||
else {
|
||||
out << "(* ";
|
||||
out << "(* ";
|
||||
display_smt2_mumeral(out, m, n);
|
||||
out << " ";
|
||||
if (k == 1)
|
||||
|
@ -1189,12 +1190,12 @@ namespace upolynomial {
|
|||
out << "0";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (sz == 1) {
|
||||
display_smt2_mumeral(out, m(), p[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
unsigned non_zero_idx = UINT_MAX;
|
||||
unsigned num_non_zeros = 0;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
|
@ -1208,7 +1209,7 @@ namespace upolynomial {
|
|||
SASSERT(non_zero_idx != UINT_MAX && non_zero_idx >= 1);
|
||||
display_smt2_monomial(out, m(), p[non_zero_idx], non_zero_idx, var_name);
|
||||
}
|
||||
|
||||
|
||||
out << "(+";
|
||||
unsigned i = sz;
|
||||
while (i > 0) {
|
||||
|
@ -1230,7 +1231,7 @@ namespace upolynomial {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void upolynomial_sequence::push(unsigned sz, numeral * p) {
|
||||
m_begins.push_back(m_seq_coeffs.size());
|
||||
m_szs.push_back(sz);
|
||||
|
@ -1253,8 +1254,8 @@ namespace upolynomial {
|
|||
_scoped_numeral_vector<numeral_manager>(m.m()) {
|
||||
}
|
||||
|
||||
scoped_upolynomial_sequence::~scoped_upolynomial_sequence() {
|
||||
m_manager.reset(*this);
|
||||
scoped_upolynomial_sequence::~scoped_upolynomial_sequence() {
|
||||
m_manager.reset(*this);
|
||||
}
|
||||
|
||||
manager::~manager() {
|
||||
|
@ -1355,7 +1356,7 @@ namespace upolynomial {
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Return the descartes bound for (0, +oo)
|
||||
unsigned manager::descartes_bound(unsigned sz, numeral const * p) {
|
||||
return sign_changes(sz, p);
|
||||
|
@ -1382,9 +1383,9 @@ namespace upolynomial {
|
|||
unsigned num_vars = 0;
|
||||
// a0 a1 a2 a3
|
||||
// a0 a0+a1 a0+a1+a2 a0+a1+a2+a3
|
||||
// a0 2a0+a1 3a0+2a1+a2
|
||||
// a0 3a0+a1
|
||||
// a0
|
||||
// a0 2a0+a1 3a0+2a1+a2
|
||||
// a0 3a0+a1
|
||||
// a0
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
checkpoint();
|
||||
unsigned k;
|
||||
|
@ -1496,12 +1497,12 @@ namespace upolynomial {
|
|||
}
|
||||
|
||||
// Given b of the form c/(2^k)
|
||||
// p(x) := (2^k)^n * p(x + c/(2^k)) where b = c/2^k
|
||||
// p(x) := (2^k)^n * p(x + c/(2^k)) where b = c/2^k
|
||||
//
|
||||
// Given p: a_n * x^n + ... + a_0
|
||||
//
|
||||
//
|
||||
// buffer := a_n * (2^k * x + c)^n + a_{n-1} * 2^k * (2^k * x + c)^{n-1} + ... + a_1 * (2^k)^{n-1} * (2^k * x + c) + a_0 * (2^k)^n
|
||||
//
|
||||
//
|
||||
// We perform the transformation in two steps:
|
||||
// 1) a_n * x^n + a_{n-1} * 2^k * x^{n-1} + ... + a_1 * (2^k)^{n-1} + a_0 * (2^k)^n
|
||||
// Let d_n, ..., d_0 be the coefficients after this step
|
||||
|
@ -1509,33 +1510,33 @@ namespace upolynomial {
|
|||
// d_n * x^n + ... + d_0
|
||||
// 2) d_n * (2^k * x + c)^n + ... + d_0
|
||||
// This step is like the translation with integers, but the coefficients must be adjusted by 2^k in each iteration.
|
||||
//
|
||||
//
|
||||
// That is, it is a special translation such as:
|
||||
// a_n*(b*x + c)^n + a_{n-1}*(b*x + c)^{n-1} + ... + a_1*(b*x + c) + a_0
|
||||
// This kind of translation can be computed by applying the following recurrence:
|
||||
// To simplify the notation, we fix n = 4
|
||||
// Moreover we use a_i[k] to represent the coefficient a_i at iteration k
|
||||
// a_i[0] = a_i
|
||||
//
|
||||
//
|
||||
// a_4*(b*x + c)^4 + a_3*(b*x + c)^3 + a_2*(b*x + c)^2 + a_1*(b*x + c) + a_0
|
||||
// -->
|
||||
// a_4*b*x*(b*x + c)^3 + (a_3 + a_4*c)*(b*x + c)^3 + a_2*(b*x + c)^2 + a_1*(b*x + c) + a_0
|
||||
// Thus a_4[1] = a_4[0]*b, a_3[1] = a_3[0] + a_4[0]*c, a_2[1] = a_2[0], a_1[1] = a_1[0], a_0[1] = a_0[0]
|
||||
//
|
||||
//
|
||||
// a_4[1]*x*(b*x + c)^3 + a_3[1]*(b*x + c)^3 + a_2[1]*(b*x + c)^2 + a_1[1]*(b*x + c) + a_0[1]
|
||||
// -->
|
||||
// a_4[1]*b*x^2*(b*x + c)^2 + (a_3[1]*b + a_4[1]*c)*x*(b*x + c)^2 + (a_2[1] + a_3[1]*c)*(b*x + c)^2 + a_1[1]*(b*x + c) + a_0[1]
|
||||
// Thus a_4[2] = a_4[1]*b, a_3[2] = a_3[1]*b + a_4[1]*c, a_2[2] = a_2[1] + a_3[1]*c, a_1[2] = a_1[1], a_0[2] = a_0[1]
|
||||
//
|
||||
//
|
||||
// a_4[2]*x^2*(b*x + c)^2 + a_3[2]*x*(b*x + c)^2 + a_2[2]*(b*x + c)^2 + a_1[2]*(b*x + c) + a_0[2]
|
||||
// -->
|
||||
// a_4[2]*b*x^3*(b*x + c) + (a_3[2]*b + a_4[2]*c)*x^2*(b*x + c) + (a_2[2]*b + a_3[2]*c)*x*(b*x + c) + (a_1[2] + a_2[2]*c)*(b*x + c) + a_0[2]
|
||||
// Thus a_4[3] = a_4[2]*b, a_3[3] = a_3[2]*b + a_4[2]*c, a_2[3] = a_2[2]*b + a_3[2]*c, a_1[3] = a_1[2] + a_2[2]*c, a_0[3] = a_1[3]
|
||||
//
|
||||
//
|
||||
// a_4[3]*x^3*(b*x + c) + a_3[3]*x^2*(b*x + c) + a_2[3]*x*(b*x + c) + a_1[3]*(b*x + c) + a_0[3]
|
||||
// --->
|
||||
// a_4[3]*b*x^4 + (a_3[3]*b + a_4[3]*c)*x^3 + (a_2[3]*b + a_3[3]*c)*x^2 + (a_1[3]*b + a_2[3]*c)*x + (a_0[3] + a_1[3]*c)
|
||||
//
|
||||
// a_4[3]*b*x^4 + (a_3[3]*b + a_4[3]*c)*x^3 + (a_2[3]*b + a_3[3]*c)*x^2 + (a_1[3]*b + a_2[3]*c)*x + (a_0[3] + a_1[3]*c)
|
||||
//
|
||||
void manager::translate_bq(unsigned sz, numeral * p, mpbq const & b) {
|
||||
if (sz <= 1)
|
||||
return;
|
||||
|
@ -1617,7 +1618,7 @@ namespace upolynomial {
|
|||
}
|
||||
}
|
||||
|
||||
// p(x) := p(2^k * x)
|
||||
// p(x) := p(2^k * x)
|
||||
void manager::compose_p_2k_x(unsigned sz, numeral * p, unsigned k) {
|
||||
// (2^k)^n*a_n*x^n + (2^k)^(n-1)*x^{n-1} + ... + a_0
|
||||
if (sz <= 1)
|
||||
|
@ -1629,11 +1630,11 @@ namespace upolynomial {
|
|||
}
|
||||
}
|
||||
|
||||
// p(x) := (2^k)^n * p(x/2^k)
|
||||
// p(x) := (2^k)^n * p(x/2^k)
|
||||
//
|
||||
// Let old(p) be of the form:
|
||||
// a_n * x^n + a_{n-1}*x^{n-1} + ... + a_1 * x + a_0
|
||||
//
|
||||
//
|
||||
// Then p is of the form:
|
||||
// a_n * x^n + a_{n-1} * 2^k * x^{n-1} + a_{n-2} * (2^k)^2 * x^{n-2} + ... + a_0 * (2^k)^n
|
||||
void manager::compose_2kn_p_x_div_2k(unsigned sz, numeral * p, unsigned k) {
|
||||
|
@ -1646,7 +1647,7 @@ namespace upolynomial {
|
|||
m().mul2k(p[i], k_i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// p(x) := a^n * p(x/a)
|
||||
// See compose_2kn_p_x_div_2k
|
||||
void manager::compose_an_p_x_div_a(unsigned sz, numeral * p, numeral const & a) {
|
||||
|
@ -1675,13 +1676,13 @@ namespace upolynomial {
|
|||
m().mul(b_i, b, b_i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Let b be of the form c/(2^k), then this operation is equivalent to:
|
||||
// (2^k)^n*p(c*x/(2^k))
|
||||
//
|
||||
//
|
||||
// Let old(p) be of the form:
|
||||
// a_n * x^n + a_{n-1}*x^{n-1} + ... + a_1 * x + a_0
|
||||
//
|
||||
//
|
||||
// Then p is of the form:
|
||||
// a_n * c^n * x^n + a_{n-1} * c^{n-1} * 2^k * x^{n-1} + ... + a_1 * c * (2^k)^(n-1) * x + a_0 * (2^k)^n
|
||||
void manager::compose_p_b_x(unsigned sz, numeral * p, mpbq const & b) {
|
||||
|
@ -1705,12 +1706,12 @@ namespace upolynomial {
|
|||
|
||||
// Let q be of the form b/c, then this operation is equivalent to:
|
||||
// p(x) := c^n*p(b*x/c)
|
||||
//
|
||||
//
|
||||
// If u is a root of old(p), then u*(c/b) is a root of new p.
|
||||
//
|
||||
//
|
||||
// Let old(p) be of the form:
|
||||
// a_n * x^n + a_{n-1}*x^{n-1} + ... + a_1 * x + a_0
|
||||
//
|
||||
//
|
||||
// Then p is of the form:
|
||||
// a_n * b^n * x^n + a_{n-1} * b^{n-1} * c * x^{n-1} + ... + a_1 * b * c^(n-1) * x + a_0 * c^n
|
||||
void manager::compose_p_q_x(unsigned sz, numeral * p, mpq const & q) {
|
||||
|
@ -1730,14 +1731,14 @@ namespace upolynomial {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Evaluate the sign of p(b)
|
||||
int manager::eval_sign_at(unsigned sz, numeral const * p, mpbq const & b) {
|
||||
// Actually, given b = c/2^k, we compute the sign of (2^k)^n*p(b)
|
||||
// Original Horner Sequence
|
||||
// ((a_n * b + a_{n-1})*b + a_{n-2})*b + a_{n-3} ...
|
||||
// Variation of the Horner Sequence for (2^k)^n*p(b)
|
||||
// ((a_n * c + a_{n-1}*2_k)*c + a_{n-2}*(2_k)^2)*c + a_{n-3}*(2_k)^3 ... + a_0*(2_k)^n
|
||||
// ((a_n * c + a_{n-1}*2_k)*c + a_{n-2}*(2_k)^2)*c + a_{n-3}*(2_k)^3 ... + a_0*(2_k)^n
|
||||
if (sz == 0)
|
||||
return 0;
|
||||
if (sz == 1)
|
||||
|
@ -1770,7 +1771,7 @@ namespace upolynomial {
|
|||
// Original Horner Sequence
|
||||
// ((a_n * b + a_{n-1})*b + a_{n-2})*b + a_{n-3} ...
|
||||
// Variation of the Horner Sequence for (d^n)*p(b)
|
||||
// ((a_n * c + a_{n-1}*d)*c + a_{n-2}*d^2)*c + a_{n-3}*d^3 ... + a_0*d^n
|
||||
// ((a_n * c + a_{n-1}*d)*c + a_{n-2}*d^2)*c + a_{n-3}*d^3 ... + a_0*d^n
|
||||
if (sz == 0)
|
||||
return 0;
|
||||
if (sz == 1)
|
||||
|
@ -1797,7 +1798,7 @@ namespace upolynomial {
|
|||
}
|
||||
return sign_of(r);
|
||||
}
|
||||
|
||||
|
||||
// Evaluate the sign of p(b)
|
||||
int manager::eval_sign_at(unsigned sz, numeral const * p, mpz const & b) {
|
||||
// Using Horner Sequence
|
||||
|
@ -1906,7 +1907,7 @@ namespace upolynomial {
|
|||
|
||||
void manager::root_upper_bound(unsigned sz, numeral const * p, numeral & r) {
|
||||
// Using Cauchy's Inequality
|
||||
// We have that any root u of p must satisfy
|
||||
// We have that any root u of p must satisfy
|
||||
// |u| < (max(p) + min(p))/min(p)
|
||||
// |u| < (max(p) + |a_n|)/|a_n|
|
||||
// where: max(p) is the maximum coefficient in absolute value.
|
||||
|
@ -1932,7 +1933,7 @@ namespace upolynomial {
|
|||
init = true;
|
||||
continue;
|
||||
}
|
||||
if (m().gt(c, max))
|
||||
if (m().gt(c, max))
|
||||
m().set(max, c);
|
||||
if (m().lt(c, min))
|
||||
m().set(min, c);
|
||||
|
@ -1946,26 +1947,26 @@ namespace upolynomial {
|
|||
m().div(r2, a_n, r2);
|
||||
m().add(r2, numeral(1), r2);
|
||||
// use the best bound
|
||||
if (m().lt(r2, r))
|
||||
if (m().lt(r2, r))
|
||||
swap(r, r2);
|
||||
SASSERT(m().le(r, r2));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Find positive root upper bound using Knuth's approach.
|
||||
|
||||
|
||||
Given p(x) = a_n * x^n + a_{n-1} * x^{n-1} + ... + a_0
|
||||
|
||||
|
||||
If a_n is positive,
|
||||
Let B = max({ (-a_{n-k}/a_n)^{1/k} | 1 <= k <= n, a_{n-k} < 0 })
|
||||
Then, 2*B is a bound for the positive roots
|
||||
|
||||
|
||||
Similarly, if a_n is negative
|
||||
Let B = max({ (-a_{n-k}/a_n)^{1/k} | 1 <= k <= n, a_{n-k} > 0 })
|
||||
Then, 2*B is a bound for the positive roots
|
||||
|
||||
This procedure returns a k s.t. 2*B <= 2^k
|
||||
|
||||
|
||||
The procedure actually computes
|
||||
|
||||
max of log2(abs(a_{n-k})) + 1 - log2(abs(a_n))/k
|
||||
|
@ -1974,12 +1975,12 @@ namespace upolynomial {
|
|||
|
||||
Let u > 0 be a root of p(x).
|
||||
If u <= B, then we are done. So, let us assume u > B
|
||||
|
||||
|
||||
Assume, a_n > 0 (the proof is similar for a_n < 0)
|
||||
|
||||
Then: a_n * u^n + a_{n-1} * u^{n-1} + ... + a0 = 0
|
||||
u^n = 1/a_n (-a_{n-1} * u^{n-1} - ... - a_0)
|
||||
Note that, if we remove the monomials s.t. a_i is positive, then
|
||||
Note that, if we remove the monomials s.t. a_i is positive, then
|
||||
we are increasing the value of (-a_{n-1} * u^{n-1} - ... - a_0).
|
||||
Thus,
|
||||
u^n <= 1/a_n(SUM_{a_i < 0, 0 <= i < n} (-a_i * u^i))
|
||||
|
@ -1990,7 +1991,7 @@ namespace upolynomial {
|
|||
1 <= 1/a_n(SUM_{a_{n-k} < 0, n >= k > 0} (-a_{n-k} * u^{n-k})) = 1/a_n(SUM_{a_{n-k} < 0, 1 <= k <= n} (-a_i * u^{n-k})) < Sum_{1 <= k < +oo}(B/u)^k
|
||||
Since u > B, we have that Sum_{1 <= k < +oo}(B/u)^k = B/(u - B)
|
||||
Thus, we have
|
||||
1 < B/(u - B)
|
||||
1 < B/(u - B)
|
||||
and u < 2B
|
||||
*/
|
||||
unsigned manager::knuth_positive_root_upper_bound(unsigned sz, numeral const * p) {
|
||||
|
@ -2044,14 +2045,14 @@ namespace upolynomial {
|
|||
We essentially compute the upper bound for the roots of x^n*p(1/x) where n is the degree of p.
|
||||
Remark: alpha is a nonzero root of p(x) iff 1/alpha is a root of x^n*p(1/x).
|
||||
Thus, if 2^k is upper bound for the root of x^n*p(1/x). Then we have that
|
||||
-2^k < 1/alpha < 2^k
|
||||
-2^k < 1/alpha < 2^k
|
||||
and consequently
|
||||
alpha < -1/2^k or 1/2^k < alpha
|
||||
|
||||
/pre p is not the zero polynomial.
|
||||
*/
|
||||
unsigned manager::nonzero_root_lower_bound(unsigned sz, numeral const * p) {
|
||||
SASSERT(sz > 0);
|
||||
SASSERT(sz > 0);
|
||||
// consume zeros
|
||||
unsigned i = 0;
|
||||
while (true) {
|
||||
|
@ -2082,7 +2083,7 @@ namespace upolynomial {
|
|||
struct manager::drs_frame {
|
||||
unsigned m_parent_idx; // position of the parent frame, UINT_MAX if it doesn't have a parent frame
|
||||
unsigned m_size:30; // size of the polynomial associated with this frame
|
||||
unsigned m_first:1; // first time visiting the frame?
|
||||
unsigned m_first:1; // first time visiting the frame?
|
||||
unsigned m_left:1; // true if the frame is the left child of the parent frame.
|
||||
drs_frame(unsigned pidx, unsigned sz, bool left):
|
||||
m_parent_idx(pidx),
|
||||
|
@ -2115,14 +2116,14 @@ namespace upolynomial {
|
|||
// I don't really need the following test, because 0 - 1 == UINT_MAX
|
||||
unsigned parent_idx = frame_stack.empty() ? UINT_MAX : frame_stack.size() - 1;
|
||||
numeral_vector & p_aux = m_push_tmp;
|
||||
|
||||
|
||||
// Possible optimization: the coefficients of the parent frame are not needed anymore.
|
||||
// So, we could reuse/steal them.
|
||||
|
||||
// left child
|
||||
set(sz, p, p_aux);
|
||||
compose_2n_p_x_div_2(p_aux.size(), p_aux.c_ptr());
|
||||
normalize(p_aux);
|
||||
normalize(p_aux);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
p_stack.push_back(numeral());
|
||||
m().set(p_stack.back(), p_aux[i]);
|
||||
|
@ -2149,7 +2150,7 @@ namespace upolynomial {
|
|||
unsigned idx = frame_stack.size() - 1;
|
||||
while (idx != UINT_MAX) {
|
||||
drs_frame const & fr = frame_stack[idx];
|
||||
TRACE("upolynomial",
|
||||
TRACE("upolynomial",
|
||||
tout << "normalizing...\n";
|
||||
tout << "idx: " << idx << ", left: " << fr.m_left << ", l: " << bqm.to_string(l) << ", u: " << bqm.to_string(u) << "\n";);
|
||||
if (fr.m_left) {
|
||||
|
@ -2170,7 +2171,7 @@ namespace upolynomial {
|
|||
swap(lowers.back(), l);
|
||||
swap(uppers.back(), u);
|
||||
}
|
||||
|
||||
|
||||
// 1/2 is a root of the polynomial associated with the top frame.
|
||||
// Apply transformations for obtaining root of the original polynomial:
|
||||
// We use the following transformations:
|
||||
|
@ -2259,7 +2260,7 @@ namespace upolynomial {
|
|||
push_child_frames(q.size(), q.c_ptr(), p_stack, frame_stack);
|
||||
}
|
||||
else {
|
||||
push_child_frames(sz, p, p_stack, frame_stack);
|
||||
push_child_frames(sz, p, p_stack, frame_stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2314,7 +2315,7 @@ namespace upolynomial {
|
|||
TRACE("upolynomial", tout << "searching at (-1, 0) using:\n"; display(tout, sz, p); tout << "\n";);
|
||||
old_roots_sz = roots.size();
|
||||
old_lowers_sz = lowers.size();
|
||||
drs_isolate_0_1_roots(sz, p, bqm, roots, lowers, uppers);
|
||||
drs_isolate_0_1_roots(sz, p, bqm, roots, lowers, uppers);
|
||||
SASSERT(lowers.size() == uppers.size());
|
||||
adjust_neg(bqm, roots, old_roots_sz, neg_k);
|
||||
adjust_neg(bqm, lowers, old_lowers_sz, neg_k);
|
||||
|
@ -2390,7 +2391,7 @@ namespace upolynomial {
|
|||
}
|
||||
|
||||
// Isolate roots in an interval (-2^neg_k, 2^pos_k) using an approach based on Descartes rule of signs.
|
||||
void manager::sturm_isolate_roots_core(unsigned sz, numeral * p, unsigned neg_k, unsigned pos_k,
|
||||
void manager::sturm_isolate_roots_core(unsigned sz, numeral * p, unsigned neg_k, unsigned pos_k,
|
||||
mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers) {
|
||||
SASSERT(!has_zero_roots(sz, p));
|
||||
scoped_upolynomial_sequence seq(*this);
|
||||
|
@ -2450,10 +2451,10 @@ namespace upolynomial {
|
|||
bqm.swap(curr_lower, f.m_lower);
|
||||
bqm.swap(curr_upper, f.m_upper);
|
||||
pop_ss_frame(bqm, s);
|
||||
SASSERT(lower_sv > upper_sv + 1);
|
||||
SASSERT(lower_sv > upper_sv + 1);
|
||||
bqm.add(curr_lower, curr_upper, mid);
|
||||
bqm.div2(mid);
|
||||
TRACE("upolynomial",
|
||||
TRACE("upolynomial",
|
||||
tout << "depth: " << s.size() << "\n";
|
||||
tout << "lower_sv: " << lower_sv << "\n";
|
||||
tout << "upper_sv: " << upper_sv << "\n";
|
||||
|
@ -2492,8 +2493,8 @@ namespace upolynomial {
|
|||
}
|
||||
|
||||
void manager::sqf_isolate_roots(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers) {
|
||||
bqm.reset(roots);
|
||||
bqm.reset(lowers);
|
||||
bqm.reset(roots);
|
||||
bqm.reset(lowers);
|
||||
bqm.reset(uppers);
|
||||
if (has_zero_roots(sz, p)) {
|
||||
roots.push_back(mpbq(0));
|
||||
|
@ -2516,10 +2517,10 @@ namespace upolynomial {
|
|||
TRACE("upolynomial", tout << "square free part:\n"; display(tout, sqf_p); tout << "\n";);
|
||||
sqf_isolate_roots(sqf_p.size(), sqf_p.c_ptr(), bqm, roots, lowers, uppers);
|
||||
}
|
||||
|
||||
|
||||
// Keep expanding the Sturm sequence starting at seq
|
||||
void manager::sturm_seq_core(upolynomial_sequence & seq) {
|
||||
scoped_numeral_vector r(m());
|
||||
scoped_numeral_vector r(m());
|
||||
while (true) {
|
||||
unsigned sz = seq.size();
|
||||
srem(seq.size(sz-2), seq.coeffs(sz-2), seq.size(sz-1), seq.coeffs(sz-1), r);
|
||||
|
@ -2539,7 +2540,7 @@ namespace upolynomial {
|
|||
|
||||
void manager::sturm_seq(unsigned sz, numeral const * p, upolynomial_sequence & seq) {
|
||||
reset(seq);
|
||||
scoped_numeral_vector p_prime(m());
|
||||
scoped_numeral_vector p_prime(m());
|
||||
seq.push(m(), sz, p);
|
||||
derivative(sz, p, p_prime);
|
||||
seq.push(p_prime.size(), p_prime.c_ptr());
|
||||
|
@ -2548,7 +2549,7 @@ namespace upolynomial {
|
|||
|
||||
void manager::sturm_tarski_seq(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, upolynomial_sequence & seq) {
|
||||
reset(seq);
|
||||
scoped_numeral_vector p1p2(m());
|
||||
scoped_numeral_vector p1p2(m());
|
||||
seq.push(m(), sz1, p1);
|
||||
derivative(sz1, p1, p1p2);
|
||||
mul(p1p2.size(), p1p2.c_ptr(), sz2, p2, p1p2);
|
||||
|
@ -2558,7 +2559,7 @@ namespace upolynomial {
|
|||
|
||||
void manager::fourier_seq(unsigned sz, numeral const * p, upolynomial_sequence & seq) {
|
||||
reset(seq);
|
||||
scoped_numeral_vector p_prime(m());
|
||||
scoped_numeral_vector p_prime(m());
|
||||
seq.push(m(), sz, p);
|
||||
if (sz == 0)
|
||||
return;
|
||||
|
@ -2570,16 +2571,16 @@ namespace upolynomial {
|
|||
seq.push(p_prime.size(), p_prime.c_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
We say an interval (a, b) of a polynomial p is ISOLATING if p has only one root in the
|
||||
We say an interval (a, b) of a polynomial p is ISOLATING if p has only one root in the
|
||||
interval (a, b).
|
||||
|
||||
We say an isolating interval (a, b) of a square free polynomial p is REFINEABLE if
|
||||
sign(p(a)) = -sign(p(b))
|
||||
|
||||
|
||||
Not every isolating interval (a, b) of a square free polynomial p is refineable, because
|
||||
sign(p(a)) or sign(p(b)) may be zero.
|
||||
sign(p(a)) or sign(p(b)) may be zero.
|
||||
|
||||
Refinable intervals of square free polynomials are useful, because we can increase precision
|
||||
("squeeze" the interval) by just evaluating p at (a+b)/2
|
||||
|
@ -2590,7 +2591,7 @@ namespace upolynomial {
|
|||
The method returns TRUE if it produced a REFINABLE interval (a', b'). The new interval
|
||||
is stored in input variables a and b.
|
||||
|
||||
The method returns FALSE if it found the root a' in the interval (a, b). The root is
|
||||
The method returns FALSE if it found the root a' in the interval (a, b). The root is
|
||||
stored in the input variable a.
|
||||
|
||||
\pre p MUST BE SQUARE FREE.
|
||||
|
@ -2631,7 +2632,7 @@ namespace upolynomial {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (sign_a != 0 && sign_b == 0 ) {
|
||||
if (sign_a != 0 && sign_b == 0 ) {
|
||||
// CASE 3
|
||||
scoped_mpbq new_b(bqm);
|
||||
// new_b <- (a+b)/2
|
||||
|
@ -2671,7 +2672,7 @@ namespace upolynomial {
|
|||
// b1 <- (a+b)/2
|
||||
bqm.add(a, b, b1);
|
||||
bqm.div2(b1);
|
||||
// a2 <- (a+b)/2
|
||||
// a2 <- (a+b)/2
|
||||
bqm.set(a2, b1);
|
||||
int sign_b1 = eval_sign_at(sz, p, b1);
|
||||
int sign_a2 = sign_b1;
|
||||
|
@ -2691,13 +2692,13 @@ namespace upolynomial {
|
|||
bqm.div2(new_b2);
|
||||
|
||||
while (true) {
|
||||
TRACE("upolynomial",
|
||||
TRACE("upolynomial",
|
||||
tout << "CASE 4\na1: " << bqm.to_string(a1) << ", b1: " << bqm.to_string(b1) << ", new_a1: " << bqm.to_string(new_a1) << "\n";
|
||||
tout << "a2: " << bqm.to_string(a2) << ", b2: " << bqm.to_string(b2) << ", new_b2: " << bqm.to_string(new_b2) << "\n";);
|
||||
int sign_new_a1 = eval_sign_at(sz, p, new_a1);
|
||||
if (sign_new_a1 == 0) {
|
||||
// found root
|
||||
swap(new_a1, a);
|
||||
swap(new_a1, a);
|
||||
result = false;
|
||||
goto end;
|
||||
}
|
||||
|
@ -2716,7 +2717,7 @@ namespace upolynomial {
|
|||
result = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
if (sign_new_b2 == -sign_a2) {
|
||||
// found interval
|
||||
swap(a2, a);
|
||||
|
@ -2739,7 +2740,7 @@ namespace upolynomial {
|
|||
bqm.add(b2, a2, new_b2);
|
||||
bqm.div2(new_b2);
|
||||
}
|
||||
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
@ -2748,11 +2749,11 @@ namespace upolynomial {
|
|||
Given a square-free polynomial p, and a refinable interval (a,b), then "squeeze" (a,b).
|
||||
That is, return a new interval (a',b') s.t. b' - a' = (b - a)/2
|
||||
See isolating2refinable for a definition of refinable interval.
|
||||
|
||||
|
||||
Return TRUE, if interval was squeezed, and new interval is stored in (a,b).
|
||||
Return FALSE, if the actual root was found, it is stored in a.
|
||||
|
||||
The arguments sign_a and sign_b must contain the values returned by
|
||||
The arguments sign_a and sign_b must contain the values returned by
|
||||
eval_sign_at(sz, p, a) and eval_sign_at(sz, p, b).
|
||||
*/
|
||||
bool manager::refine_core(unsigned sz, numeral const * p, int sign_a, mpbq_manager & bqm, mpbq & a, mpbq & b) {
|
||||
|
@ -2786,7 +2787,7 @@ namespace upolynomial {
|
|||
}
|
||||
|
||||
// Keeps reducing the interval until b - a < 1/2^k or a root is found.
|
||||
// See comments in refine_core above.
|
||||
// See comments in refine_core above.
|
||||
//
|
||||
// Return TRUE, if interval was squeezed, and new interval is stored in (a,b).
|
||||
// Return FALSE, if the actual root was found, it is stored in a.
|
||||
|
@ -2821,7 +2822,7 @@ namespace upolynomial {
|
|||
SASSERT(sign_a != 0 && sign_b != 0);
|
||||
SASSERT(sign_a == -sign_b);
|
||||
bool found_d = false;
|
||||
TRACE("convert_bug",
|
||||
TRACE("convert_bug",
|
||||
tout << "a: " << m().to_string(a.numerator()) << "/" << m().to_string(a.denominator()) << "\n";
|
||||
tout << "b: " << m().to_string(b.numerator()) << "/" << m().to_string(b.denominator()) << "\n";
|
||||
tout << "sign_a: " << sign_a << "\n";
|
||||
|
@ -2839,7 +2840,7 @@ namespace upolynomial {
|
|||
bqm.mul2(upper);
|
||||
if (m_manager.is_neg(a.numerator()))
|
||||
::swap(lower, upper);
|
||||
TRACE("convert_bug",
|
||||
TRACE("convert_bug",
|
||||
tout << "a: "; m().display(tout, a.numerator()); tout << "/"; m().display(tout, a.denominator()); tout << "\n";
|
||||
tout << "lower: "; bqm.display(tout, lower); tout << ", upper: "; bqm.display(tout, upper); tout << "\n";);
|
||||
SASSERT(bqm.lt(lower, a));
|
||||
|
@ -2848,7 +2849,7 @@ namespace upolynomial {
|
|||
bqm.refine_upper(a, lower, upper);
|
||||
}
|
||||
SASSERT(bqm.lt(upper, b));
|
||||
while (true) {
|
||||
while (true) {
|
||||
int sign_upper = eval_sign_at(sz, p, upper);
|
||||
if (sign_upper == 0) {
|
||||
// found root
|
||||
|
@ -2872,7 +2873,7 @@ namespace upolynomial {
|
|||
bqm.refine_upper(a, lower, upper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!found_d) {
|
||||
if (bqm.to_mpbq(b, lower)) {
|
||||
// found d
|
||||
|
@ -2893,7 +2894,7 @@ namespace upolynomial {
|
|||
SASSERT(bqm.lt(c, lower));
|
||||
SASSERT(bqm.lt(lower, upper));
|
||||
SASSERT(bqm.lt(lower, b));
|
||||
while (true) {
|
||||
while (true) {
|
||||
int sign_lower = eval_sign_at(sz, p, lower);
|
||||
if (sign_lower == 0) {
|
||||
// found root
|
||||
|
@ -2946,8 +2947,8 @@ namespace upolynomial {
|
|||
|
||||
bool manager::normalize_interval(unsigned sz, numeral const * p, mpbq_manager & m, mpbq & a, mpbq & b) {
|
||||
return normalize_interval_core(sz, p, INT_MIN, m, a, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsigned manager::get_root_id(unsigned sz, numeral const * p, mpbq const & l) {
|
||||
scoped_upolynomial_sequence seq(*this);
|
||||
sturm_seq(sz, p, seq);
|
||||
|
@ -2963,7 +2964,7 @@ namespace upolynomial {
|
|||
m_manager.neg(new_c);
|
||||
r.set_constant(new_c);
|
||||
}
|
||||
|
||||
|
||||
void manager::factor_2_sqf_pp(numeral_vector & p, factors & r, unsigned k) {
|
||||
SASSERT(p.size() == 3); // p has degree 2
|
||||
TRACE("factor", tout << "factor square free (degree == 2):\n"; display(tout, p); tout << "\n";);
|
||||
|
@ -2980,7 +2981,7 @@ namespace upolynomial {
|
|||
m().mul(a, c, ac);
|
||||
m().addmul(b2, numeral(-4), ac, disc);
|
||||
// discriminant must be different from 0, since p is square free
|
||||
SASSERT(!m().is_zero(disc));
|
||||
SASSERT(!m().is_zero(disc));
|
||||
scoped_numeral disc_sqrt(m());
|
||||
if (!m().is_perfect_square(disc, disc_sqrt)) {
|
||||
// p is irreducible
|
||||
|
@ -3053,13 +3054,13 @@ namespace upolynomial {
|
|||
scoped_numeral_vector pp(m());
|
||||
get_primitive_and_content(sz, p, pp, content);
|
||||
r.set_constant(content);
|
||||
//
|
||||
//
|
||||
scoped_numeral_vector & C = pp;
|
||||
// Let C be a primitive polynomial of the form: P_1^1 * P_2^2 * ... * P_k^k, where each P_i is square free
|
||||
scoped_numeral_vector C_prime(m());
|
||||
derivative(C, C_prime);
|
||||
scoped_numeral_vector A(m()), B(m()), D(m());
|
||||
gcd(C, C_prime, B);
|
||||
gcd(C, C_prime, B);
|
||||
|
||||
bool result = true;
|
||||
if (is_const(B)) {
|
||||
|
@ -3071,7 +3072,7 @@ namespace upolynomial {
|
|||
}
|
||||
else {
|
||||
// B is of the form P_2 * P_3^2 * ... * P_k^{k-1}
|
||||
VERIFY(exact_div(C, B, A));
|
||||
VERIFY(exact_div(C, B, A));
|
||||
TRACE("factor_bug", tout << "C: "; display(tout, C); tout << "\nB: "; display(tout, B); tout << "\nA: "; display(tout, A); tout << "\n";);
|
||||
// A is of the form P_1 * P_2 * ... * P_k
|
||||
unsigned j = 1;
|
||||
|
@ -3084,7 +3085,7 @@ namespace upolynomial {
|
|||
// D is of the form P_{j+1} * P_{j+2} * ... * P_k
|
||||
VERIFY(exact_div(A, D, C));
|
||||
// C is of the form P_j
|
||||
if (!is_const(C)) {
|
||||
if (!is_const(C)) {
|
||||
flip_factor_sign_if_lm_neg(C, r, j);
|
||||
if (!factor_sqf_pp(C, r, j, params))
|
||||
result = false;
|
||||
|
@ -3111,7 +3112,7 @@ namespace upolynomial {
|
|||
|
||||
bool manager::factor(unsigned sz, numeral const * p, factors & r, factor_params const & params) {
|
||||
bool result = factor_core(sz, p, r, params);
|
||||
#ifndef _EXTERNAL_RELEASE
|
||||
#ifndef _EXTERNAL_RELEASE
|
||||
IF_VERBOSE(FACTOR_VERBOSE_LVL, verbose_stream() << "(polynomial-factorization :distinct-factors " << r.distinct_factors() << ")" << std::endl;);
|
||||
#endif
|
||||
return result;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,8 +31,8 @@ namespace subpaving {
|
|||
template<typename C>
|
||||
class breadth_first_node_selector : public context_t<C>::node_selector {
|
||||
typedef typename context_t<C>::node node;
|
||||
public:
|
||||
breadth_first_node_selector(context_t<C> * ctx):
|
||||
public:
|
||||
breadth_first_node_selector(context_t<C> * ctx):
|
||||
context_t<C>::node_selector(ctx) {
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,8 @@ public:
|
|||
template<typename C>
|
||||
class depth_first_node_selector : public context_t<C>::node_selector {
|
||||
typedef typename context_t<C>::node node;
|
||||
public:
|
||||
depth_first_node_selector(context_t<C> * ctx):
|
||||
public:
|
||||
depth_first_node_selector(context_t<C> * ctx):
|
||||
context_t<C>::node_selector(ctx) {
|
||||
}
|
||||
|
||||
|
@ -73,12 +73,12 @@ class round_robing_var_selector : public context_t<C>::var_selector {
|
|||
x = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
round_robing_var_selector(context_t<C> * ctx, bool only_non_def = true):
|
||||
context_t<C>::var_selector(ctx),
|
||||
m_only_non_def(only_non_def) {
|
||||
}
|
||||
|
||||
|
||||
// Return the next variable to branch.
|
||||
virtual var operator()(typename context_t<C>::node * n) {
|
||||
typename context_t<C>::numeral_manager & nm = this->ctx()->nm();
|
||||
|
@ -86,7 +86,7 @@ public:
|
|||
var x = this->ctx()->splitting_var(n);
|
||||
if (x == null_var)
|
||||
x = 0;
|
||||
else
|
||||
else
|
||||
next(x);
|
||||
var start = x;
|
||||
do {
|
||||
|
@ -112,13 +112,13 @@ public:
|
|||
- All variables x s.t. lower(x) == upper(x) are ignored.
|
||||
|
||||
- If node contains an unbounded variable (-oo, oo), then return the smallest unbounded variable.
|
||||
|
||||
|
||||
- Otherwise, select the smallest variable x with the largest width, where
|
||||
width is defined as:
|
||||
If x has lower and upper bound, then width = upper(x) - lower(x).
|
||||
If x has only lower, width = penalty/max(|lower(x)|, 1)
|
||||
If x has only upper, width = penalty/max(|upper(x)|, 1)
|
||||
penaly is a parameter of this class.
|
||||
If x has only upper, width = penalty/max(|upper(x)|, 1)
|
||||
penaly is a parameter of this class.
|
||||
|
||||
This strategy guarantees fairness.
|
||||
*/
|
||||
|
@ -127,13 +127,13 @@ class largest_interval_var_selector : public context_t<C>::var_selector {
|
|||
unsigned m_penalty;
|
||||
bool m_only_non_def;
|
||||
|
||||
public:
|
||||
public:
|
||||
largest_interval_var_selector(context_t<C> * ctx, unsigned unbounded_penalty = 10, bool only_non_def = true):
|
||||
context_t<C>::var_selector(ctx),
|
||||
m_penalty(unbounded_penalty),
|
||||
m_only_non_def(only_non_def) {
|
||||
}
|
||||
|
||||
|
||||
// Return the next variable to branch.
|
||||
virtual var operator()(typename context_t<C>::node * n) {
|
||||
var y = null_var;
|
||||
|
@ -149,7 +149,7 @@ public:
|
|||
typename context_t<C>::bound * u = n->upper(x);
|
||||
// variables without lower and upper bounds are selected immediately.
|
||||
if (l == 0 && u == 0)
|
||||
return x;
|
||||
return x;
|
||||
if (l != 0 && u != 0) {
|
||||
// ignore variables s.t. lower(x) == upper(x)
|
||||
if (nm.eq(l->value(), u->value()))
|
||||
|
@ -165,7 +165,7 @@ public:
|
|||
nm.set(width, l->value());
|
||||
else
|
||||
nm.set(width, u->value());
|
||||
C::round_to_plus_inf(nm);
|
||||
C::round_to_plus_inf(nm);
|
||||
if (nm.is_neg(width))
|
||||
nm.neg(width);
|
||||
if (nm.lt(width, one))
|
||||
|
@ -215,7 +215,7 @@ public:
|
|||
nm.set(delta, static_cast<int>(m_delta));
|
||||
nm.set(mid, upper->value());
|
||||
C::round_to_minus_inf(nm);
|
||||
nm.sub(mid, delta, mid);
|
||||
nm.sub(mid, delta, mid);
|
||||
// mid == upper - delta
|
||||
}
|
||||
else if (upper == 0) {
|
||||
|
@ -224,7 +224,7 @@ public:
|
|||
nm.set(delta, static_cast<int>(m_delta));
|
||||
nm.set(mid, lower->value());
|
||||
C::round_to_plus_inf(nm);
|
||||
nm.add(mid, delta, mid);
|
||||
nm.add(mid, delta, mid);
|
||||
// mid == lower + delta
|
||||
}
|
||||
else {
|
||||
|
@ -237,10 +237,10 @@ public:
|
|||
throw subpaving::exception();
|
||||
// mid == (lower + upper)/2
|
||||
}
|
||||
|
||||
|
||||
this->mk_decided_bound(x, mid, false, m_left_open, left);
|
||||
this->mk_decided_bound(x, mid, true, !m_left_open, right);
|
||||
TRACE("subpaving_int_split",
|
||||
TRACE("subpaving_int_split",
|
||||
tout << "LEFT:\n"; this->ctx()->display_bounds(tout, left);
|
||||
tout << "\nRIGHT:\n"; this->ctx()->display_bounds(tout, right););
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ void context_t<C>::node::push(bound * b) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
\brief Return the most recent variable that was used for splitting on node n.
|
||||
*/
|
||||
template<typename C>
|
||||
|
@ -395,11 +395,11 @@ void context_t<C>::polynomial::display(std::ostream & out, numeral_manager & nm,
|
|||
out << nm.to_rational_string(m_c);
|
||||
first = false;
|
||||
}
|
||||
|
||||
|
||||
for (unsigned i = 0; i < m_size; i++) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
else
|
||||
out << " + ";
|
||||
if (!nm.is_one(a(i))) {
|
||||
out << nm.to_rational_string(a(i));
|
||||
|
@ -460,7 +460,7 @@ context_t<C>::~context_t() {
|
|||
template<typename C>
|
||||
void context_t<C>::checkpoint() {
|
||||
if (!m_limit.inc())
|
||||
throw default_exception("canceled");
|
||||
throw default_exception(Z3_CANCELED_MSG);
|
||||
if (memory::get_allocation_size() > m_max_memory)
|
||||
throw default_exception(Z3_MAX_MEMORY_MSG);
|
||||
cooperate("subpaving");
|
||||
|
@ -497,7 +497,7 @@ void context_t<C>::updt_params(params_ref const & p) {
|
|||
m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
|
||||
|
||||
unsigned prec = p.get_uint("nth_root_precision", 8192);
|
||||
if (prec == 0)
|
||||
if (prec == 0)
|
||||
prec = 1;
|
||||
nm().set(m_nth_root_prec, static_cast<int>(prec));
|
||||
nm().inv(m_nth_root_prec);
|
||||
|
@ -513,7 +513,7 @@ void context_t<C>::collect_param_descrs(param_descrs & d) {
|
|||
}
|
||||
|
||||
template<typename C>
|
||||
void context_t<C>::display_params(std::ostream & out) const {
|
||||
void context_t<C>::display_params(std::ostream & out) const {
|
||||
out << "max_nodes " << m_max_nodes << "\n";
|
||||
out << "max_depth " << m_max_depth << "\n";
|
||||
out << "epsilon " << nm().to_rational_string(m_epsilon) << "\n";
|
||||
|
@ -626,7 +626,7 @@ void context_t<C>::display_definition(std::ostream & out, definition const * d,
|
|||
|
||||
template<typename C>
|
||||
void context_t<C>::display(std::ostream & out, constraint * c, bool use_star) const {
|
||||
if (c->get_kind() == constraint::CLAUSE)
|
||||
if (c->get_kind() == constraint::CLAUSE)
|
||||
static_cast<clause*>(c)->display(out, nm(), *m_display_proc);
|
||||
else
|
||||
display_definition(out, static_cast<definition*>(c), use_star);
|
||||
|
@ -639,7 +639,7 @@ void context_t<C>::display_bounds(std::ostream & out, node * n) const {
|
|||
bound * l = n->lower(x);
|
||||
bound * u = n->upper(x);
|
||||
if (l != 0) {
|
||||
display(out, l);
|
||||
display(out, l);
|
||||
out << " ";
|
||||
}
|
||||
if (u != 0) {
|
||||
|
@ -782,18 +782,18 @@ typename context_t<C>::ineq * context_t<C>::mk_ineq(var x, numeral const & k, bo
|
|||
}
|
||||
|
||||
template<typename C>
|
||||
void context_t<C>::inc_ref(ineq * a) {
|
||||
void context_t<C>::inc_ref(ineq * a) {
|
||||
TRACE("subpaving_ref_count", tout << "inc-ref: " << a << " " << a->m_ref_count << "\n";);
|
||||
if (a)
|
||||
a->m_ref_count++;
|
||||
if (a)
|
||||
a->m_ref_count++;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
void context_t<C>::dec_ref(ineq * a) {
|
||||
if (a) {
|
||||
TRACE("subpaving_ref_count",
|
||||
tout << "dec-ref: " << a << " " << a->m_ref_count << "\n";
|
||||
a->display(tout, nm());
|
||||
TRACE("subpaving_ref_count",
|
||||
tout << "dec-ref: " << a << " " << a->m_ref_count << "\n";
|
||||
a->display(tout, nm());
|
||||
tout << "\n";);
|
||||
SASSERT(a->m_ref_count > 0);
|
||||
a->m_ref_count--;
|
||||
|
@ -804,7 +804,7 @@ void context_t<C>::dec_ref(ineq * a) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename C>
|
||||
void context_t<C>::add_clause_core(unsigned sz, ineq * const * atoms, bool lemma, bool watch) {
|
||||
SASSERT(lemma || watch);
|
||||
|
@ -846,7 +846,7 @@ void context_t<C>::del_clause(clause * c) {
|
|||
SASSERT(c->m_num_jst == 0); // We cannot delete a clause that is being used to justify some bound
|
||||
bool watch = c->watched();
|
||||
var prev_x = null_var;
|
||||
unsigned sz = c->size();
|
||||
unsigned sz = c->size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
var x = c->m_atoms[i]->x();
|
||||
if (watch) {
|
||||
|
@ -883,10 +883,10 @@ typename context_t<C>::node * context_t<C>::mk_node(node * parent) {
|
|||
else
|
||||
r = new (mem) node(parent, m_node_id_gen.mk());
|
||||
m_var_selector->new_node_eh(r);
|
||||
|
||||
|
||||
// Add node in the leaf dlist
|
||||
push_front(r);
|
||||
|
||||
|
||||
m_num_nodes++;
|
||||
return r;
|
||||
}
|
||||
|
@ -903,9 +903,9 @@ void context_t<C>::del_node(node * n) {
|
|||
// recycle id
|
||||
m_node_id_gen.recycle(n->id());
|
||||
|
||||
// disconnect n from list of leaves.
|
||||
// disconnect n from list of leaves.
|
||||
remove_from_leaf_dlist(n);
|
||||
|
||||
|
||||
// disconnect n from parent
|
||||
node * p = n->parent();
|
||||
bound * b = n->trail_stack();
|
||||
|
@ -1118,7 +1118,7 @@ void context_t<C>::del_definitions() {
|
|||
if (d == 0)
|
||||
continue;
|
||||
switch (d->get_kind()) {
|
||||
case constraint::MONOMIAL:
|
||||
case constraint::MONOMIAL:
|
||||
del_monomial(static_cast<monomial*>(d));
|
||||
break;
|
||||
case constraint::POLYNOMIAL:
|
||||
|
@ -1130,7 +1130,7 @@ void context_t<C>::del_definitions() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename C>
|
||||
void context_t<C>::display_constraints(std::ostream & out, bool use_star) const {
|
||||
// display definitions
|
||||
|
@ -1160,9 +1160,9 @@ void context_t<C>::display_constraints(std::ostream & out, bool use_star) const
|
|||
// -----------------------------------
|
||||
|
||||
template<typename C>
|
||||
void context_t<C>::set_conflict(var x, node * n) {
|
||||
void context_t<C>::set_conflict(var x, node * n) {
|
||||
m_num_conflicts++;
|
||||
n->set_conflict(x);
|
||||
n->set_conflict(x);
|
||||
remove_from_leaf_dlist(n);
|
||||
}
|
||||
|
||||
|
@ -1222,12 +1222,12 @@ bool context_t<C>::relevant_new_bound(var x, numeral const & k, bool lower, bool
|
|||
if (m_zero_epsilon && curr_lower != 0 && (nm().lt(k, curr_lower->value()) || ((curr_lower->is_open() || !open) && nm().eq(k, curr_lower->value())))) {
|
||||
// new lower bound does not improve existing bound
|
||||
TRACE("subpaving_relevant_bound", tout << "irrelevant because does not improve existing bound.\n";);
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
if (curr_upper == 0 && nm().lt(m_max_bound, k)) {
|
||||
// new lower bound exceeds the :max-bound threshold
|
||||
TRACE("subpaving_relevant_bound", tout << "irrelevant because exceeds :max-bound threshold.\n";);
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
if (!m_zero_epsilon && curr_lower != 0) {
|
||||
// check if:
|
||||
|
@ -1250,10 +1250,10 @@ bool context_t<C>::relevant_new_bound(var x, numeral const & k, bool lower, bool
|
|||
nm().set(delta, min);
|
||||
nm().mul(delta, m_epsilon, delta);
|
||||
nm().add(curr_lower->value(), delta, delta);
|
||||
TRACE("subpaving_relevant_bound_bug",
|
||||
tout << "k: "; nm().display(tout, k);
|
||||
TRACE("subpaving_relevant_bound_bug",
|
||||
tout << "k: "; nm().display(tout, k);
|
||||
tout << ", delta: "; nm().display(tout, delta); tout << "\n";
|
||||
tout << "curr_lower: "; nm().display(tout, curr_lower->value());
|
||||
tout << "curr_lower: "; nm().display(tout, curr_lower->value());
|
||||
tout << ", min: "; nm().display(tout, min); tout << "\n";);
|
||||
if (nm().le(k, delta)) {
|
||||
TRACE("subpaving_relevant_bound", tout << "irrelevant because does not improve existing bound to at least ";
|
||||
|
@ -1272,7 +1272,7 @@ bool context_t<C>::relevant_new_bound(var x, numeral const & k, bool lower, bool
|
|||
if (m_zero_epsilon && curr_upper != 0 && (nm().lt(curr_upper->value(), k) || ((curr_upper->is_open() || !open) && nm().eq(k, curr_upper->value())))) {
|
||||
// new upper bound does not improve existing bound
|
||||
TRACE("subpaving_relevant_bound", tout << "irrelevant because does not improve existing bound.\n";);
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
if (curr_lower == 0 && nm().lt(k, m_minus_max_bound)) {
|
||||
// new upper bound exceeds the -:max-bound threshold
|
||||
|
@ -1343,7 +1343,7 @@ bool context_t<C>::conflicting_bounds(var x, node * n) const {
|
|||
|
||||
/**
|
||||
\brief Return the truth value of the inequality t in node n.
|
||||
|
||||
|
||||
The result may be l_true (True), l_false (False), or l_undef(Unknown).
|
||||
*/
|
||||
template<typename C>
|
||||
|
@ -1399,7 +1399,7 @@ void context_t<C>::propagate_clause(clause * c, node * n) {
|
|||
ineq * a = (*c)[j];
|
||||
TRACE("propagate_clause", tout << "propagating inequality: "; display(tout, a); tout << "\n";);
|
||||
propagate_bound(a->x(), a->value(), a->is_lower(), a->is_open(), n, justification(c));
|
||||
// A clause can propagate only once.
|
||||
// A clause can propagate only once.
|
||||
// So, we can safely set its timestamp again to avoid another useless visit.
|
||||
c->set_visited(m_timestamp);
|
||||
}
|
||||
|
@ -1411,7 +1411,7 @@ void context_t<C>::propagate_polynomial(var x, node * n, var y) {
|
|||
polynomial * p = get_polynomial(x);
|
||||
unsigned sz = p->size();
|
||||
interval & r = m_i_tmp1; r.set_mutable();
|
||||
interval & v = m_i_tmp2;
|
||||
interval & v = m_i_tmp2;
|
||||
interval & av = m_i_tmp3; av.set_mutable();
|
||||
if (x == y) {
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
|
@ -1482,7 +1482,7 @@ void context_t<C>::propagate_polynomial(var x, node * n) {
|
|||
}
|
||||
}
|
||||
TRACE("propagate_polynomial", tout << "unbounded_var: "; display(tout, unbounded_var); tout << "\n";);
|
||||
|
||||
|
||||
if (unbounded_var != null_var) {
|
||||
propagate_polynomial(x, n, unbounded_var);
|
||||
}
|
||||
|
@ -1528,10 +1528,10 @@ void context_t<C>::propagate_monomial(var x, node * n) {
|
|||
// x must be zero
|
||||
numeral & zero = m_tmp1;
|
||||
nm().set(zero, 0);
|
||||
propagate_bound(x, zero, true, false, n, justification(x));
|
||||
propagate_bound(x, zero, true, false, n, justification(x));
|
||||
if (inconsistent(n))
|
||||
return;
|
||||
propagate_bound(x, zero, false, false, n, justification(x));
|
||||
propagate_bound(x, zero, false, false, n, justification(x));
|
||||
}
|
||||
// no need to downward propagation
|
||||
return;
|
||||
|
@ -1572,11 +1572,11 @@ void context_t<C>::propagate_monomial_upward(var x, node * n) {
|
|||
monomial * m = get_monomial(x);
|
||||
unsigned sz = m->size();
|
||||
interval & r = m_i_tmp1; r.set_mutable();
|
||||
interval & y = m_i_tmp2;
|
||||
interval & y = m_i_tmp2;
|
||||
interval & yk = m_i_tmp3; yk.set_mutable();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
y.set_constant(n, m->x(i));
|
||||
im().power(y, m->degree(i), yk);
|
||||
im().power(y, m->degree(i), yk);
|
||||
if (i == 0)
|
||||
im().set(r, yk);
|
||||
else
|
||||
|
@ -1606,37 +1606,37 @@ void context_t<C>::propagate_monomial_downward(var x, node * n, unsigned j) {
|
|||
monomial * m = get_monomial(x);
|
||||
SASSERT(j < m->size());
|
||||
unsigned sz = m->size();
|
||||
|
||||
|
||||
interval & r = m_i_tmp3;
|
||||
if (sz > 1) {
|
||||
interval & d = m_i_tmp1; d.set_mutable();
|
||||
interval & y = m_i_tmp2;
|
||||
interval & y = m_i_tmp2;
|
||||
interval & yk = m_i_tmp3; yk.set_mutable();
|
||||
bool first = true;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
y.set_constant(n, m->x(i));
|
||||
im().power(y, m->degree(i), yk);
|
||||
im().power(y, m->degree(i), yk);
|
||||
if (first)
|
||||
im().set(d, yk);
|
||||
else
|
||||
im().mul(d, yk, r);
|
||||
}
|
||||
interval & aux = m_i_tmp2;
|
||||
interval & aux = m_i_tmp2;
|
||||
aux.set_constant(n, x);
|
||||
im().div(aux, d, r);
|
||||
}
|
||||
else {
|
||||
SASSERT(sz == 1);
|
||||
SASSERT(j == 0);
|
||||
interval & aux = m_i_tmp2;
|
||||
interval & aux = m_i_tmp2;
|
||||
aux.set_constant(n, x);
|
||||
im().set(r, aux);
|
||||
}
|
||||
unsigned d = m->degree(j);
|
||||
if (d > 1) {
|
||||
if (d % 2 == 0 && im().lower_is_neg(r))
|
||||
if (d % 2 == 0 && im().lower_is_neg(r))
|
||||
return; // If d is even, we can't take the nth-root when lower(r) is negative.
|
||||
im().xn_eq_y(r, d, m_nth_root_prec, r);
|
||||
}
|
||||
|
@ -1814,7 +1814,7 @@ void context_t<C>::operator()() {
|
|||
if (m_num_nodes > m_max_nodes)
|
||||
break;
|
||||
node * n = (*m_node_selector)(m_leaf_head, m_leaf_tail);
|
||||
if (n == 0)
|
||||
if (n == 0)
|
||||
break;
|
||||
TRACE("subpaving_main", tout << "selected node: #" << n->id() << ", depth: " << n->depth() << "\n";);
|
||||
remove_from_leaf_dlist(n);
|
||||
|
|
|
@ -8,8 +8,8 @@ Module Name:
|
|||
Abstract:
|
||||
|
||||
Translator from Z3 expressions into generic subpaving data-structure.
|
||||
|
||||
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2012-08-08
|
||||
|
@ -24,6 +24,7 @@ Notes:
|
|||
#include"cooperate.h"
|
||||
#include"arith_decl_plugin.h"
|
||||
#include"scoped_numeral_buffer.h"
|
||||
#include"common_msgs.h"
|
||||
|
||||
struct expr2subpaving::imp {
|
||||
struct frame {
|
||||
|
@ -43,9 +44,9 @@ struct expr2subpaving::imp {
|
|||
expr_ref_vector m_var2expr;
|
||||
|
||||
typedef svector<subpaving::var> var_vector;
|
||||
|
||||
|
||||
obj_map<expr, unsigned> m_cache;
|
||||
var_vector m_cached_vars;
|
||||
var_vector m_cached_vars;
|
||||
scoped_mpz_vector m_cached_numerators;
|
||||
scoped_mpz_vector m_cached_denominators;
|
||||
|
||||
|
@ -69,17 +70,17 @@ struct expr2subpaving::imp {
|
|||
m_expr2var = e2v;
|
||||
m_expr2var_owner = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
~imp() {
|
||||
reset_cache();
|
||||
if (m_expr2var_owner)
|
||||
dealloc(m_expr2var);
|
||||
}
|
||||
|
||||
|
||||
ast_manager & m() { return m_manager; }
|
||||
|
||||
|
||||
subpaving::context & s() { return m_subpaving; }
|
||||
|
||||
unsynch_mpq_manager & qm() const { return m_qm; }
|
||||
|
@ -94,7 +95,7 @@ struct expr2subpaving::imp {
|
|||
|
||||
void checkpoint() {
|
||||
if (m().canceled())
|
||||
throw default_exception("canceled");
|
||||
throw default_exception(Z3_CANCELED_MSG);
|
||||
cooperate("expr2subpaving");
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,7 @@ struct expr2subpaving::imp {
|
|||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void found_non_simplified() {
|
||||
throw default_exception("you must apply simplifier before internalizing expressions into the subpaving module.");
|
||||
}
|
||||
|
@ -128,7 +129,7 @@ struct expr2subpaving::imp {
|
|||
SASSERT(!m_cache.contains(t));
|
||||
SASSERT(m_cached_numerators.size() == m_cached_vars.size());
|
||||
SASSERT(m_cached_denominators.size() == m_cached_vars.size());
|
||||
if (t->get_ref_count() <= 1)
|
||||
if (t->get_ref_count() <= 1)
|
||||
return;
|
||||
unsigned idx = m_cached_vars.size();
|
||||
m_cache.insert(t, idx);
|
||||
|
@ -196,7 +197,7 @@ struct expr2subpaving::imp {
|
|||
sbuffer<subpaving::power> pws;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * arg = margs[i];
|
||||
unsigned k;
|
||||
unsigned k;
|
||||
as_power(arg, arg, k);
|
||||
subpaving::var x_arg = process(arg, depth+1, n_arg, d_arg);
|
||||
qm().power(n_arg, k, n_arg);
|
||||
|
@ -216,7 +217,7 @@ struct expr2subpaving::imp {
|
|||
cache_result(t, x, n, d);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
typedef _scoped_numeral_buffer<unsynch_mpz_manager> mpz_buffer;
|
||||
typedef sbuffer<subpaving::var> var_buffer;
|
||||
|
||||
|
@ -291,13 +292,13 @@ struct expr2subpaving::imp {
|
|||
switch (t->get_decl_kind()) {
|
||||
case OP_NUM:
|
||||
return process_num(t, depth, n, d);
|
||||
case OP_ADD:
|
||||
case OP_ADD:
|
||||
return process_add(t, depth, n, d);
|
||||
case OP_MUL:
|
||||
case OP_MUL:
|
||||
return process_mul(t, depth, n, d);
|
||||
case OP_POWER:
|
||||
return process_power(t, depth, n, d);
|
||||
case OP_TO_REAL:
|
||||
case OP_TO_REAL:
|
||||
return process(t->get_arg(0), depth+1, n, d);
|
||||
case OP_SUB:
|
||||
case OP_UMINUS:
|
||||
|
@ -310,7 +311,7 @@ struct expr2subpaving::imp {
|
|||
case OP_REM:
|
||||
case OP_IRRATIONAL_ALGEBRAIC_NUM:
|
||||
throw default_exception("you must apply arithmetic purifier before internalizing expressions into the subpaving module.");
|
||||
case OP_SIN:
|
||||
case OP_SIN:
|
||||
case OP_COS:
|
||||
case OP_TAN:
|
||||
case OP_ASIN:
|
||||
|
@ -350,12 +351,12 @@ struct expr2subpaving::imp {
|
|||
|
||||
return process_arith_app(to_app(t), depth, n, d);
|
||||
}
|
||||
|
||||
bool is_var(expr * t) const {
|
||||
return m_expr2var->is_var(t);
|
||||
|
||||
bool is_var(expr * t) const {
|
||||
return m_expr2var->is_var(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
subpaving::var internalize_term(expr * t, mpz & n, mpz & d) {
|
||||
return process(t, 0, n, d);
|
||||
}
|
||||
|
@ -376,11 +377,11 @@ ast_manager & expr2subpaving::m() const {
|
|||
subpaving::context & expr2subpaving::s() const {
|
||||
return m_imp->s();
|
||||
}
|
||||
|
||||
|
||||
bool expr2subpaving::is_var(expr * t) const {
|
||||
return m_imp->is_var(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
subpaving::var expr2subpaving::internalize_term(expr * t, mpz & n, mpz & d) {
|
||||
return m_imp->internalize_term(t, n, d);
|
||||
|
|
|
@ -60,11 +60,11 @@ namespace datalog {
|
|||
expr_ref fml(m.mk_app(q, T), m);
|
||||
b.assert_expr(fml);
|
||||
res = b.m_solver.check();
|
||||
|
||||
|
||||
if (res == l_true) {
|
||||
res = get_model();
|
||||
}
|
||||
b.m_solver.pop(1);
|
||||
b.m_solver.pop(1);
|
||||
++m_bit_width;
|
||||
}
|
||||
return res;
|
||||
|
@ -74,11 +74,11 @@ namespace datalog {
|
|||
sort_ref mk_index_sort() {
|
||||
return sort_ref(m_bv.mk_sort(m_bit_width), m);
|
||||
}
|
||||
|
||||
|
||||
var_ref mk_index_var() {
|
||||
return var_ref(m.mk_var(0, mk_index_sort()), m);
|
||||
}
|
||||
|
||||
|
||||
void compile() {
|
||||
sort_ref index_sort = mk_index_sort();
|
||||
var_ref var = mk_index_var();
|
||||
|
@ -92,17 +92,17 @@ namespace datalog {
|
|||
// Assert: forall level . p(T) => body of rule i + equalities for head of rule i
|
||||
func_decl_ref pr = mk_q_func_decl(p);
|
||||
expr_ref pred = expr_ref(m.mk_app(pr, var.get()), m);
|
||||
expr_ref_vector rules(m), sub(m), conjs(m);
|
||||
expr_ref_vector rules(m), sub(m), conjs(m);
|
||||
expr_ref trm(m), rule_body(m), rule_i(m);
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
sub.reset();
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
sub.reset();
|
||||
conjs.reset();
|
||||
rule& r = *rls[i];
|
||||
rule& r = *rls[i];
|
||||
rule_i = m.mk_app(mk_q_rule(p, i), var.get());
|
||||
rules.push_back(rule_i);
|
||||
|
||||
|
||||
mk_qrule_vars(r, i, sub);
|
||||
|
||||
|
||||
// apply substitution to body.
|
||||
var_subst vs(m, false);
|
||||
for (unsigned k = 0; k < p->get_arity(); ++k) {
|
||||
|
@ -137,21 +137,21 @@ namespace datalog {
|
|||
b.assert_expr(trm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
b.m_fparams.m_relevancy_lvl = 2;
|
||||
b.m_fparams.m_model = true;
|
||||
b.m_fparams.m_model_compact = true;
|
||||
b.m_fparams.m_mbqi = true;
|
||||
}
|
||||
|
||||
|
||||
void mk_qrule_vars(datalog::rule const& r, unsigned rule_id, expr_ref_vector& sub) {
|
||||
ptr_vector<sort> sorts;
|
||||
r.get_vars(m, sorts);
|
||||
// populate substitution of bound variables.
|
||||
sub.reset();
|
||||
sub.resize(sorts.size());
|
||||
|
||||
|
||||
for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
|
||||
expr* arg = r.get_head()->get_arg(k);
|
||||
if (is_var(arg)) {
|
||||
|
@ -177,52 +177,52 @@ namespace datalog {
|
|||
if (sorts[j] && !sub[j].get()) {
|
||||
sub[j] = mk_q_var(r.get_decl(), sorts[j], rule_id, idx++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_q_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx) {
|
||||
std::stringstream _name;
|
||||
_name << pred->get_name() << "#" << rule_id << "_" << idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
var_ref var = mk_index_var();
|
||||
return expr_ref(m.mk_app(m.mk_func_decl(nm, mk_index_sort(), s), var), m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
expr_ref mk_q_arg(func_decl* pred, unsigned idx, bool is_current) {
|
||||
SASSERT(idx < pred->get_arity());
|
||||
std::stringstream _name;
|
||||
_name << pred->get_name() << "#" << idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
expr_ref var(mk_index_var(), m);
|
||||
if (!is_current) {
|
||||
var = m_bv.mk_bv_sub(var, mk_q_one());
|
||||
}
|
||||
return expr_ref(m.mk_app(m.mk_func_decl(nm, mk_index_sort(), pred->get_domain(idx)), var), m);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_q_one() {
|
||||
return mk_q_num(1);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_q_num(unsigned i) {
|
||||
return expr_ref(m_bv.mk_numeral(i, m_bit_width), m);
|
||||
}
|
||||
|
||||
|
||||
func_decl_ref mk_q_func_decl(func_decl* f) {
|
||||
std::stringstream _name;
|
||||
_name << f->get_name() << "#";
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return func_decl_ref(m.mk_func_decl(nm, mk_index_sort(), f->get_range()), m);
|
||||
}
|
||||
|
||||
|
||||
func_decl_ref mk_q_rule(func_decl* f, unsigned rule_id) {
|
||||
std::stringstream _name;
|
||||
_name << f->get_name() << "#" << rule_id;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return func_decl_ref(m.mk_func_decl(nm, mk_index_sort(), m.mk_bool_sort()), m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
expr_ref eval_q(model_ref& model, func_decl* f, unsigned i) {
|
||||
func_decl_ref fn = mk_q_func_decl(f);
|
||||
expr_ref t(m), result(m);
|
||||
|
@ -230,7 +230,7 @@ namespace datalog {
|
|||
model->eval(t, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
expr_ref eval_q(model_ref& model, expr* t, unsigned i) {
|
||||
expr_ref tmp(m), result(m), num(m);
|
||||
var_subst vs(m, false);
|
||||
|
@ -239,8 +239,8 @@ namespace datalog {
|
|||
vs(t, 1, nums, tmp);
|
||||
model->eval(tmp, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lbool get_model() {
|
||||
rule_manager& rm = b.m_ctx.get_rule_manager();
|
||||
func_decl_ref q = mk_q_func_decl(b.m_query_pred);
|
||||
|
@ -250,7 +250,7 @@ namespace datalog {
|
|||
rule_unifier unifier(b.m_ctx);
|
||||
rational num;
|
||||
unsigned level, bv_size;
|
||||
|
||||
|
||||
b.m_solver.get_model(md);
|
||||
func_decl* pred = b.m_query_pred;
|
||||
dl_decl_util util(m);
|
||||
|
@ -261,7 +261,7 @@ namespace datalog {
|
|||
level = num.get_unsigned();
|
||||
SASSERT(m.is_true(eval_q(md, b.m_query_pred, level)));
|
||||
TRACE("bmc", model_smt2_pp(tout, m, *md, 0););
|
||||
|
||||
|
||||
rule_ref r0(rm), r1(rm), r2(rm);
|
||||
while (true) {
|
||||
TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
|
||||
|
@ -269,8 +269,8 @@ namespace datalog {
|
|||
rule_vector const& rls = b.m_rules.get_predicate_rules(pred);
|
||||
rule* r = 0;
|
||||
unsigned i = 0;
|
||||
for (; i < rls.size(); ++i) {
|
||||
rule_i = m.mk_app(mk_q_rule(pred, i), mk_q_num(level).get());
|
||||
for (; i < rls.size(); ++i) {
|
||||
rule_i = m.mk_app(mk_q_rule(pred, i), mk_q_num(level).get());
|
||||
TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
|
||||
if (m.is_true(eval_q(md, rule_i, level))) {
|
||||
r = rls[i];
|
||||
|
@ -280,13 +280,13 @@ namespace datalog {
|
|||
SASSERT(r);
|
||||
mk_qrule_vars(*r, i, sub);
|
||||
// we have rule, we have variable names of rule.
|
||||
|
||||
|
||||
// extract values for the variables in the rule.
|
||||
for (unsigned j = 0; j < sub.size(); ++j) {
|
||||
expr_ref vl = eval_q(md, sub[j].get(), i);
|
||||
if (vl) {
|
||||
// vl can be 0 if the interpretation does not assign a value to it.
|
||||
sub[j] = vl;
|
||||
sub[j] = vl;
|
||||
}
|
||||
else {
|
||||
sub[j] = m.mk_var(j, m.get_sort(sub[j].get()));
|
||||
|
@ -295,7 +295,7 @@ namespace datalog {
|
|||
svector<std::pair<unsigned, unsigned> > positions;
|
||||
vector<expr_ref_vector> substs;
|
||||
expr_ref fml(m), concl(m);
|
||||
|
||||
|
||||
rm.to_formula(*r, fml);
|
||||
r2 = r;
|
||||
rm.substitute(r2, sub.size(), sub.c_ptr());
|
||||
|
@ -308,15 +308,15 @@ namespace datalog {
|
|||
unifier.apply(*r0.get(), 0, *r2.get(), r1);
|
||||
rm.to_formula(*r1.get(), concl);
|
||||
scoped_proof _sp(m);
|
||||
|
||||
|
||||
p = r->get_proof();
|
||||
if (!p) {
|
||||
p = m.mk_asserted(fml);
|
||||
}
|
||||
proof* premises[2] = { pr, p };
|
||||
|
||||
|
||||
positions.push_back(std::make_pair(0, 1));
|
||||
|
||||
|
||||
substs.push_back(sub1);
|
||||
substs.push_back(sub);
|
||||
pr = m.mk_hyper_resolve(2, premises, concl, positions, substs);
|
||||
|
@ -339,7 +339,7 @@ namespace datalog {
|
|||
}
|
||||
r0 = r2;
|
||||
}
|
||||
|
||||
|
||||
if (level == 0) {
|
||||
SASSERT(r->get_uninterpreted_tail_size() == 0);
|
||||
break;
|
||||
|
@ -370,7 +370,7 @@ namespace datalog {
|
|||
lbool check() {
|
||||
setup();
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";);
|
||||
IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";);
|
||||
b.checkpoint();
|
||||
expr_ref_vector fmls(m);
|
||||
compile(b.m_rules, fmls, i);
|
||||
|
@ -392,12 +392,12 @@ namespace datalog {
|
|||
for (unsigned i = 0; i < level_p->get_arity(); ++i) {
|
||||
std::stringstream _name;
|
||||
_name << query_pred->get_name() << "#" << level << "_" << i;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
vars.push_back(m.mk_const(nm, level_p->get_domain(i)));
|
||||
}
|
||||
return expr_ref(m.mk_app(level_p, vars.size(), vars.c_ptr()), m);
|
||||
}
|
||||
|
||||
|
||||
void compile(rule_set const& rules, expr_ref_vector& result, unsigned level) {
|
||||
bool_rewriter br(m);
|
||||
rule_set::decl2rules::iterator it = rules.begin_grouped_rules();
|
||||
|
@ -405,16 +405,16 @@ namespace datalog {
|
|||
for (; it != end; ++it) {
|
||||
func_decl* p = it->m_key;
|
||||
rule_vector const& rls = *it->m_value;
|
||||
|
||||
|
||||
// Assert: p_level(vars) => r1_level(vars) \/ r2_level(vars) \/ r3_level(vars) \/ ...
|
||||
// Assert: r_i_level(vars) => exists aux_vars . body of rule i for level
|
||||
|
||||
// Assert: r_i_level(vars) => exists aux_vars . body of rule i for level
|
||||
|
||||
func_decl_ref level_pred = mk_level_predicate(p, level);
|
||||
expr_ref_vector rules(m);
|
||||
expr_ref body(m), head(m);
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
rule& r = *rls[i];
|
||||
func_decl_ref rule_i = mk_level_rule(p, i, level);
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
rule& r = *rls[i];
|
||||
func_decl_ref rule_i = mk_level_rule(p, i, level);
|
||||
rules.push_back(apply_vars(rule_i));
|
||||
|
||||
ptr_vector<sort> rule_vars;
|
||||
|
@ -440,10 +440,10 @@ namespace datalog {
|
|||
head = m.mk_app(rule_i, args.size(), args.c_ptr());
|
||||
for (unsigned i = 0; i < r.get_tail_size(); ++i) {
|
||||
conjs.push_back(r.get_tail(i));
|
||||
}
|
||||
}
|
||||
br.mk_and(conjs.size(), conjs.c_ptr(), body);
|
||||
|
||||
replace_by_level_predicates(level, body);
|
||||
|
||||
replace_by_level_predicates(level, body);
|
||||
body = skolemize_vars(r, args, rule_vars, body);
|
||||
body = m.mk_implies(head, body);
|
||||
body = bind_vars(body, head);
|
||||
|
@ -496,7 +496,7 @@ namespace datalog {
|
|||
// find the rule that was triggered by evaluating the arguments to prop.
|
||||
rule_vector const& rls = b.m_rules.get_predicate_rules(pred);
|
||||
rule* r = 0;
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
func_decl_ref rule_i = mk_level_rule(pred, i, level);
|
||||
TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
|
||||
prop_r = m.mk_app(rule_i, prop->get_num_args(), prop->get_args());
|
||||
|
@ -537,7 +537,7 @@ namespace datalog {
|
|||
prs.push_back(get_proof(md, head_j, to_app(prop_body), level-1));
|
||||
positions.push_back(std::make_pair(j+1,0));
|
||||
substs.push_back(expr_ref_vector(m));
|
||||
}
|
||||
}
|
||||
pr = m.mk_hyper_resolve(sz+1, prs.c_ptr(), prop, positions, substs);
|
||||
return pr;
|
||||
}
|
||||
|
@ -557,16 +557,16 @@ namespace datalog {
|
|||
func_decl_ref mk_level_predicate(func_decl* p, unsigned level) {
|
||||
std::stringstream _name;
|
||||
_name << p->get_name() << "#" << level;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return func_decl_ref(m.mk_func_decl(nm, p->get_arity(), p->get_domain(), m.mk_bool_sort()), m);
|
||||
}
|
||||
|
||||
func_decl_ref mk_level_rule(func_decl* p, unsigned rule_idx, unsigned level) {
|
||||
std::stringstream _name;
|
||||
_name << "rule:" << p->get_name() << "#" << level << "_" << rule_idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return func_decl_ref(m.mk_func_decl(nm, p->get_arity(), p->get_domain(), m.mk_bool_sort()), m);
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref apply_vars(func_decl* p) {
|
||||
expr_ref_vector vars(m);
|
||||
|
@ -617,7 +617,7 @@ namespace datalog {
|
|||
func_decl_ref mk_body_func(rule& r, ptr_vector<sort> const& args, unsigned index, sort* s) {
|
||||
std::stringstream _name;
|
||||
_name << r.get_decl()->get_name() << "@" << index;
|
||||
symbol name(_name.str().c_str());
|
||||
symbol name(_name.str().c_str());
|
||||
func_decl* f = m.mk_func_decl(name, args.size(), args.c_ptr(), s);
|
||||
return func_decl_ref(f, m);
|
||||
}
|
||||
|
@ -689,16 +689,16 @@ namespace datalog {
|
|||
struct level_replacer_cfg : public default_rewriter_cfg {
|
||||
level_replacer m_r;
|
||||
|
||||
level_replacer_cfg(nonlinear& nl, unsigned level):
|
||||
level_replacer_cfg(nonlinear& nl, unsigned level):
|
||||
m_r(nl, level) {}
|
||||
|
||||
bool rewrite_patterns() const { return false; }
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
return m_r.mk_app_core(f, num, args, result);
|
||||
}
|
||||
bool reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
bool reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
expr * const * new_patterns,
|
||||
expr * const * new_no_patterns,
|
||||
expr_ref & result,
|
||||
proof_ref & result_pr) {
|
||||
|
@ -725,9 +725,9 @@ namespace datalog {
|
|||
fml = tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Basic non-linear BMC based on compiling into data-types (it is inefficient)
|
||||
|
||||
|
@ -747,7 +747,7 @@ namespace datalog {
|
|||
setup();
|
||||
declare_datatypes();
|
||||
compile();
|
||||
return check_query();
|
||||
return check_query();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -765,7 +765,7 @@ namespace datalog {
|
|||
func_decl_ref mk_predicate(func_decl* pred) {
|
||||
std::stringstream _name;
|
||||
_name << pred->get_name() << "#";
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
sort* pred_trace_sort = m_pred2sort.find(pred);
|
||||
return func_decl_ref(m.mk_func_decl(nm, pred_trace_sort, m_path_sort, m.mk_bool_sort()), m);
|
||||
}
|
||||
|
@ -773,30 +773,30 @@ namespace datalog {
|
|||
func_decl_ref mk_rule(func_decl* p, unsigned rule_idx) {
|
||||
std::stringstream _name;
|
||||
_name << "rule:" << p->get_name() << "#" << rule_idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
sort* pred_trace_sort = m_pred2sort.find(p);
|
||||
return func_decl_ref(m.mk_func_decl(nm, pred_trace_sort, m_path_sort, m.mk_bool_sort()), m);
|
||||
return func_decl_ref(m.mk_func_decl(nm, pred_trace_sort, m_path_sort, m.mk_bool_sort()), m);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_var(func_decl* pred, sort*s, unsigned idx, expr* path_arg, expr* trace_arg) {
|
||||
std::stringstream _name;
|
||||
_name << pred->get_name() << "#V_" << idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
func_decl_ref fn(m);
|
||||
fn = m.mk_func_decl(nm, m_pred2sort.find(pred), m_path_sort, s);
|
||||
return expr_ref(m.mk_app(fn, trace_arg, path_arg), m);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_arg(func_decl* pred, unsigned idx, expr* path_arg, expr* trace_arg) {
|
||||
SASSERT(idx < pred->get_arity());
|
||||
std::stringstream _name;
|
||||
_name << pred->get_name() << "#X_" << idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
func_decl_ref fn(m);
|
||||
fn = m.mk_func_decl(nm, m_pred2sort.find(pred), m_path_sort, pred->get_domain(idx));
|
||||
return expr_ref(m.mk_app(fn, trace_arg, path_arg), m);
|
||||
}
|
||||
|
||||
|
||||
void mk_subst(datalog::rule& r, expr* path, app* trace, expr_ref_vector& sub) {
|
||||
datatype_util dtu(m);
|
||||
ptr_vector<sort> sorts;
|
||||
|
@ -840,52 +840,52 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief compile Horn rule into co-Horn implication.
|
||||
forall args . R(path_var, rule_i(trace_vars)) => Body[X(path_var, rule_i(trace_vars)), Y(S_j(path_var), trace_vars_j)]
|
||||
*/
|
||||
*/
|
||||
void compile() {
|
||||
datatype_util dtu(m);
|
||||
|
||||
|
||||
rule_set::decl2rules::iterator it = b.m_rules.begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator end = b.m_rules.end_grouped_rules();
|
||||
for (; it != end; ++it) {
|
||||
func_decl* p = it->m_key;
|
||||
rule_vector const& rls = *it->m_value;
|
||||
|
||||
|
||||
// Assert: p_level => r1_level \/ r2_level \/ r3_level \/ ...
|
||||
// where: r_i_level = body of rule i for level + equalities for head of rule i
|
||||
|
||||
|
||||
expr_ref rule_body(m), tmp(m), pred(m), trace_arg(m), fml(m);
|
||||
var_ref path_var(m), trace_var(m);
|
||||
expr_ref_vector rules(m), sub(m), conjs(m), vars(m), patterns(m);
|
||||
sort* pred_sort = m_pred2sort.find(p);
|
||||
path_var = m.mk_var(0, m_path_sort);
|
||||
trace_var = m.mk_var(1, pred_sort);
|
||||
trace_var = m.mk_var(1, pred_sort);
|
||||
// sort* sorts[2] = { pred_sort, m_path_sort };
|
||||
ptr_vector<func_decl> const& cnstrs = *dtu.get_datatype_constructors(pred_sort);
|
||||
ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m_path_sort);
|
||||
SASSERT(cnstrs.size() == rls.size());
|
||||
pred = m.mk_app(mk_predicate(p), trace_var.get(), path_var.get());
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
sub.reset();
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
sub.reset();
|
||||
conjs.reset();
|
||||
vars.reset();
|
||||
rule& r = *rls[i];
|
||||
rule& r = *rls[i];
|
||||
func_decl_ref rule_pred_i = mk_rule(p, i);
|
||||
|
||||
|
||||
// Create cnstr_rule_i(Vars)
|
||||
func_decl* cnstr = cnstrs[i];
|
||||
rules.push_back(m.mk_app(rule_pred_i, trace_var.get(), path_var.get()));
|
||||
unsigned arity = cnstr->get_arity();
|
||||
for (unsigned j = 0; j < arity; ++j) {
|
||||
vars.push_back(m.mk_var(arity-j,cnstr->get_domain(j)));
|
||||
vars.push_back(m.mk_var(arity-j,cnstr->get_domain(j)));
|
||||
}
|
||||
trace_arg = m.mk_app(cnstr, vars.size(), vars.c_ptr());
|
||||
|
||||
|
||||
mk_subst(r, path_var, to_app(trace_arg), sub);
|
||||
|
||||
|
||||
// apply substitution to body.
|
||||
var_subst vs(m, false);
|
||||
for (unsigned k = 0; k < p->get_arity(); ++k) {
|
||||
|
@ -926,28 +926,28 @@ namespace datalog {
|
|||
names.push_back(symbol("path"));
|
||||
SASSERT(names.size() == q_sorts.size());
|
||||
SASSERT(vars.size() == names.size());
|
||||
symbol qid = r.name(), skid;
|
||||
symbol qid = r.name(), skid;
|
||||
tmp = m.mk_app(mk_predicate(p), trace_arg.get(), path_var.get());
|
||||
patterns.reset();
|
||||
patterns.push_back(m.mk_pattern(to_app(tmp)));
|
||||
fml = m.mk_implies(tmp, rule_body);
|
||||
fml = m.mk_forall(vars.size(), q_sorts.c_ptr(), names.c_ptr(), fml, 1, qid, skid, 1, patterns.c_ptr());
|
||||
b.assert_expr(fml);
|
||||
b.assert_expr(fml);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void declare_datatypes() {
|
||||
rule_set::decl2rules::iterator it = b.m_rules.begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator end = b.m_rules.end_grouped_rules();
|
||||
datatype_util dtu(m);
|
||||
ptr_vector<datatype_decl> dts;
|
||||
|
||||
|
||||
obj_map<func_decl, unsigned> pred_idx;
|
||||
for (unsigned i = 0; it != end; ++it, ++i) {
|
||||
pred_idx.insert(it->m_key, i);
|
||||
}
|
||||
|
||||
|
||||
it = b.m_rules.begin_grouped_rules();
|
||||
for (; it != end; ++it) {
|
||||
rule_vector const& rls = *it->m_value;
|
||||
|
@ -971,27 +971,27 @@ namespace datalog {
|
|||
_name << "?";
|
||||
symbol is_name(_name.str().c_str());
|
||||
cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr()));
|
||||
}
|
||||
}
|
||||
dts.push_back(mk_datatype_decl(pred->get_name(), cnstrs.size(), cnstrs.c_ptr()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sort_ref_vector new_sorts(m);
|
||||
family_id dfid = m.mk_family_id("datatype");
|
||||
datatype_decl_plugin* dtp = static_cast<datatype_decl_plugin*>(m.get_plugin(dfid));
|
||||
VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), new_sorts));
|
||||
|
||||
|
||||
it = b.m_rules.begin_grouped_rules();
|
||||
for (unsigned i = 0; it != end; ++it, ++i) {
|
||||
for (unsigned i = 0; it != end; ++it, ++i) {
|
||||
m_pred2sort.insert(it->m_key, new_sorts[i].get());
|
||||
m_sort2pred.insert(new_sorts[i].get(), it->m_key);
|
||||
m_pinned.push_back(new_sorts[i].get());
|
||||
m_pinned.push_back(new_sorts[i].get());
|
||||
}
|
||||
if (new_sorts.size() > 0) {
|
||||
TRACE("bmc", dtu.display_datatype(new_sorts[0].get(), tout););
|
||||
}
|
||||
del_datatype_decls(dts.size(), dts.c_ptr());
|
||||
|
||||
|
||||
// declare path data-type.
|
||||
{
|
||||
new_sorts.reset();
|
||||
|
@ -1004,9 +1004,9 @@ namespace datalog {
|
|||
rule* r = *it;
|
||||
unsigned sz = r->get_uninterpreted_tail_size();
|
||||
max_arity = std::max(sz, max_arity);
|
||||
}
|
||||
}
|
||||
cnstrs.push_back(mk_constructor_decl(symbol("Z#"), symbol("Z#?"), 0, 0));
|
||||
|
||||
|
||||
for (unsigned i = 0; i + 1 < max_arity; ++i) {
|
||||
std::stringstream _name;
|
||||
_name << "succ#" << i;
|
||||
|
@ -1019,13 +1019,13 @@ namespace datalog {
|
|||
type_ref tr(0);
|
||||
accs.push_back(mk_accessor_decl(name, tr));
|
||||
cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr()));
|
||||
}
|
||||
}
|
||||
dts.push_back(mk_datatype_decl(symbol("Path"), cnstrs.size(), cnstrs.c_ptr()));
|
||||
VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), new_sorts));
|
||||
m_path_sort = new_sorts[0].get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
proof_ref get_proof(model_ref& md, app* trace, app* path) {
|
||||
datatype_util dtu(m);
|
||||
rule_manager& rm = b.m_ctx.get_rule_manager();
|
||||
|
@ -1044,7 +1044,7 @@ namespace datalog {
|
|||
proof_ref pr(m);
|
||||
expr_ref fml(m), head(m), tmp(m);
|
||||
app_ref path1(m);
|
||||
|
||||
|
||||
var_subst vs(m, false);
|
||||
mk_subst(*rules[i], path, trace, sub);
|
||||
rm.to_formula(*rules[i], fml);
|
||||
|
@ -1061,30 +1061,30 @@ namespace datalog {
|
|||
rule_ref rl(b.m_ctx.get_rule_manager());
|
||||
rl = rules[i];
|
||||
b.m_ctx.get_rule_manager().substitute(rl, sub.size(), sub.c_ptr());
|
||||
|
||||
|
||||
substs.push_back(sub);
|
||||
|
||||
|
||||
for (unsigned j = 0; j < sz; ++j) {
|
||||
if (j == 0) {
|
||||
path1 = path;
|
||||
path1 = path;
|
||||
}
|
||||
else {
|
||||
path1 = m.mk_app(succs[j], path);
|
||||
}
|
||||
|
||||
|
||||
prs.push_back(get_proof(md, to_app(trace->get_arg(j)), path1));
|
||||
positions.push_back(std::make_pair(j+1,0));
|
||||
substs.push_back(expr_ref_vector(m));
|
||||
substs.push_back(expr_ref_vector(m));
|
||||
}
|
||||
head = rl->get_head();
|
||||
pr = m.mk_hyper_resolve(sz+1, prs.c_ptr(), head, positions, substs);
|
||||
pr = m.mk_hyper_resolve(sz+1, prs.c_ptr(), head, positions, substs);
|
||||
return pr;
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return proof_ref(0, m);
|
||||
}
|
||||
|
||||
|
||||
// instantiation of algebraic data-types takes care of the rest.
|
||||
lbool check_query() {
|
||||
sort* trace_sort = m_pred2sort.find(b.m_query_pred);
|
||||
|
@ -1102,10 +1102,10 @@ namespace datalog {
|
|||
}
|
||||
b.m_solver.get_model(md);
|
||||
mk_answer(md, trace, path);
|
||||
return l_true;
|
||||
return l_true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool check_model(model_ref& md, expr* trace) {
|
||||
expr_ref trace_val(m), eq(m);
|
||||
md->eval(trace, trace_val);
|
||||
|
@ -1122,10 +1122,10 @@ namespace datalog {
|
|||
eq = m.mk_not(eq);
|
||||
b.assert_expr(eq);
|
||||
}
|
||||
return is_sat != l_false;
|
||||
return is_sat != l_false;
|
||||
}
|
||||
|
||||
void mk_answer(model_ref& md, expr_ref& trace, expr_ref& path) {
|
||||
|
||||
void mk_answer(model_ref& md, expr_ref& trace, expr_ref& path) {
|
||||
IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0););
|
||||
md->eval(trace, trace);
|
||||
md->eval(path, path);
|
||||
|
@ -1139,7 +1139,7 @@ namespace datalog {
|
|||
apply(m, b.m_ctx.get_proof_converter().get(), pr);
|
||||
b.m_answer = pr;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
@ -1155,7 +1155,7 @@ namespace datalog {
|
|||
lbool check() {
|
||||
setup();
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";);
|
||||
IF_VERBOSE(1, verbose_stream() << "level: " << i << "\n";);
|
||||
b.checkpoint();
|
||||
compile(i);
|
||||
lbool res = check(i);
|
||||
|
@ -1183,9 +1183,9 @@ namespace datalog {
|
|||
b.m_solver.get_model(md);
|
||||
func_decl* pred = b.m_query_pred;
|
||||
SASSERT(m.is_true(md->get_const_interp(to_app(level_query)->get_decl())));
|
||||
|
||||
|
||||
TRACE("bmc", model_smt2_pp(tout, m, *md, 0););
|
||||
|
||||
|
||||
rule_ref r0(rm), r1(rm), r2(rm);
|
||||
while (true) {
|
||||
TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";);
|
||||
|
@ -1193,7 +1193,7 @@ namespace datalog {
|
|||
rule_vector const& rls = b.m_rules.get_predicate_rules(pred);
|
||||
rule* r = 0;
|
||||
unsigned i = 0;
|
||||
for (; i < rls.size(); ++i) {
|
||||
for (; i < rls.size(); ++i) {
|
||||
expr_ref rule_i = mk_level_rule(pred, i, level);
|
||||
TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " "););
|
||||
if (m.is_true(md->get_const_interp(to_app(rule_i)->get_decl()))) {
|
||||
|
@ -1204,13 +1204,13 @@ namespace datalog {
|
|||
SASSERT(r);
|
||||
mk_rule_vars(*r, level, i, sub);
|
||||
// we have rule, we have variable names of rule.
|
||||
|
||||
|
||||
// extract values for the variables in the rule.
|
||||
for (unsigned j = 0; j < sub.size(); ++j) {
|
||||
expr* vl = md->get_const_interp(to_app(sub[j].get())->get_decl());
|
||||
if (vl) {
|
||||
// vl can be 0 if the interpretation does not assign a value to it.
|
||||
sub[j] = vl;
|
||||
sub[j] = vl;
|
||||
}
|
||||
else {
|
||||
sub[j] = m.mk_var(j, m.get_sort(sub[j].get()));
|
||||
|
@ -1219,7 +1219,7 @@ namespace datalog {
|
|||
svector<std::pair<unsigned, unsigned> > positions;
|
||||
vector<expr_ref_vector> substs;
|
||||
expr_ref fml(m), concl(m);
|
||||
|
||||
|
||||
rm.to_formula(*r, fml);
|
||||
r2 = r;
|
||||
rm.substitute(r2, sub.size(), sub.c_ptr());
|
||||
|
@ -1239,12 +1239,12 @@ namespace datalog {
|
|||
apply_subst(sub, sub2);
|
||||
unifier.apply(*r0.get(), 0, *r2.get(), r1);
|
||||
rm.to_formula(*r1.get(), concl);
|
||||
|
||||
|
||||
scoped_proof _sp(m);
|
||||
proof* premises[2] = { pr, p };
|
||||
|
||||
|
||||
positions.push_back(std::make_pair(0, 1));
|
||||
|
||||
|
||||
substs.push_back(sub1);
|
||||
substs.push_back(sub);
|
||||
pr = m.mk_hyper_resolve(2, premises, concl, positions, substs);
|
||||
|
@ -1263,7 +1263,7 @@ namespace datalog {
|
|||
}
|
||||
r0 = r2;
|
||||
}
|
||||
|
||||
|
||||
if (level == 0) {
|
||||
SASSERT(r->get_uninterpreted_tail_size() == 0);
|
||||
break;
|
||||
|
@ -1276,8 +1276,8 @@ namespace datalog {
|
|||
apply(m, b.m_ctx.get_proof_converter().get(), pr);
|
||||
b.m_answer = pr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
b.m_fparams.m_relevancy_lvl = 0;
|
||||
b.m_fparams.m_model = true;
|
||||
|
@ -1285,54 +1285,54 @@ namespace datalog {
|
|||
b.m_fparams.m_mbqi = false;
|
||||
// m_fparams.m_auto_config = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
lbool check(unsigned level) {
|
||||
expr_ref level_query = mk_level_predicate(b.m_query_pred, level);
|
||||
expr* q = level_query.get();
|
||||
return b.m_solver.check(1, &q);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_level_predicate(func_decl* p, unsigned level) {
|
||||
return mk_level_predicate(p->get_name(), level);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_level_predicate(symbol const& name, unsigned level) {
|
||||
std::stringstream _name;
|
||||
_name << name << "#" << level;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return expr_ref(m.mk_const(nm, m.mk_bool_sort()), m);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_level_arg(func_decl* pred, unsigned idx, unsigned level) {
|
||||
SASSERT(idx < pred->get_arity());
|
||||
std::stringstream _name;
|
||||
_name << pred->get_name() << "#" << level << "_" << idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return expr_ref(m.mk_const(nm, pred->get_domain(idx)), m);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_level_var(func_decl* pred, sort* s, unsigned rule_id, unsigned idx, unsigned level) {
|
||||
std::stringstream _name;
|
||||
_name << pred->get_name() << "#" << level << "_" << rule_id << "_" << idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return expr_ref(m.mk_const(nm, s), m);
|
||||
}
|
||||
|
||||
|
||||
expr_ref mk_level_rule(func_decl* p, unsigned rule_idx, unsigned level) {
|
||||
std::stringstream _name;
|
||||
_name << "rule:" << p->get_name() << "#" << level << "_" << rule_idx;
|
||||
symbol nm(_name.str().c_str());
|
||||
symbol nm(_name.str().c_str());
|
||||
return expr_ref(m.mk_const(nm, m.mk_bool_sort()), m);
|
||||
}
|
||||
|
||||
|
||||
void mk_rule_vars(rule& r, unsigned level, unsigned rule_id, expr_ref_vector& sub) {
|
||||
ptr_vector<sort> sorts;
|
||||
r.get_vars(m, sorts);
|
||||
// populate substitution of bound variables.
|
||||
sub.reset();
|
||||
sub.resize(sorts.size());
|
||||
|
||||
|
||||
for (unsigned k = 0; k < r.get_decl()->get_arity(); ++k) {
|
||||
expr* arg = r.get_head()->get_arg(k);
|
||||
if (is_var(arg)) {
|
||||
|
@ -1361,34 +1361,34 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void compile(unsigned level) {
|
||||
rule_set::decl2rules::iterator it = b.m_rules.begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator end = b.m_rules.end_grouped_rules();
|
||||
for (; it != end; ++it) {
|
||||
func_decl* p = it->m_key;
|
||||
rule_vector const& rls = *it->m_value;
|
||||
|
||||
|
||||
// Assert: p_level => r1_level \/ r2_level \/ r3_level \/ ...
|
||||
// Assert: r_i_level => body of rule i for level + equalities for head of rule i
|
||||
|
||||
|
||||
expr_ref level_pred = mk_level_predicate(p, level);
|
||||
expr_ref_vector rules(m), sub(m), conjs(m);
|
||||
expr_ref rule_body(m), tmp(m);
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
sub.reset();
|
||||
for (unsigned i = 0; i < rls.size(); ++i) {
|
||||
sub.reset();
|
||||
conjs.reset();
|
||||
rule& r = *rls[i];
|
||||
expr_ref rule_i = mk_level_rule(p, i, level);
|
||||
rule& r = *rls[i];
|
||||
expr_ref rule_i = mk_level_rule(p, i, level);
|
||||
rules.push_back(rule_i);
|
||||
if (level == 0 && r.get_uninterpreted_tail_size() > 0) {
|
||||
tmp = m.mk_not(rule_i);
|
||||
b.assert_expr(tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
mk_rule_vars(r, level, i, sub);
|
||||
|
||||
|
||||
// apply substitution to body.
|
||||
var_subst vs(m, false);
|
||||
for (unsigned k = 0; k < p->get_arity(); ++k) {
|
||||
|
@ -1418,11 +1418,11 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
bmc::bmc(context& ctx):
|
||||
|
||||
bmc::bmc(context& ctx):
|
||||
engine_base(ctx.get_manager(), "bmc"),
|
||||
m_ctx(ctx),
|
||||
m(ctx.get_manager()),
|
||||
m_ctx(ctx),
|
||||
m(ctx.get_manager()),
|
||||
m_solver(m, m_fparams),
|
||||
m_rules(ctx),
|
||||
m_query_pred(m),
|
||||
|
@ -1440,9 +1440,9 @@ namespace datalog {
|
|||
rule_set& rules0 = m_ctx.get_rules();
|
||||
datalog::rule_set old_rules(rules0);
|
||||
rule_manager.mk_query(query, rules0);
|
||||
expr_ref bg_assertion = m_ctx.get_background_assertion();
|
||||
expr_ref bg_assertion = m_ctx.get_background_assertion();
|
||||
apply_default_transformation(m_ctx);
|
||||
|
||||
|
||||
if (m_ctx.xform_slice()) {
|
||||
datalog::rule_transformer transformer(m_ctx);
|
||||
datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx);
|
||||
|
@ -1490,7 +1490,7 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
void bmc::assert_expr(expr* e) {
|
||||
void bmc::assert_expr(expr* e) {
|
||||
TRACE("bmc", tout << mk_pp(e, m) << "\n";);
|
||||
m_solver.assert_expr(e);
|
||||
}
|
||||
|
@ -1510,7 +1510,7 @@ namespace datalog {
|
|||
|
||||
void bmc::checkpoint() {
|
||||
if (m.canceled()) {
|
||||
throw default_exception("bmc canceled");
|
||||
throw default_exception(Z3_CANCELED_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1526,7 +1526,7 @@ namespace datalog {
|
|||
m_solver.reset_statistics();
|
||||
}
|
||||
|
||||
expr_ref bmc::get_answer() {
|
||||
expr_ref bmc::get_answer() {
|
||||
return m_answer;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace Duality {
|
|||
context ctx;
|
||||
RPFP::LogicSolver *ls;
|
||||
RPFP *rpfp;
|
||||
|
||||
|
||||
DualityStatus status;
|
||||
std::vector<expr> clauses;
|
||||
std::vector<std::vector<RPFP::label_struct> > clause_labels;
|
||||
|
@ -104,14 +104,14 @@ namespace Duality {
|
|||
|
||||
|
||||
//
|
||||
// Check if the new rules are weaker so that we can
|
||||
// Check if the new rules are weaker so that we can
|
||||
// re-use existing context.
|
||||
//
|
||||
//
|
||||
#if 0
|
||||
void dl_interface::check_reset() {
|
||||
// TODO
|
||||
datalog::rule_ref_vector const& new_rules = m_ctx.get_rules().get_rules();
|
||||
datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules();
|
||||
datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules();
|
||||
bool is_subsumed = !old_rules.empty();
|
||||
for (unsigned i = 0; is_subsumed && i < new_rules.size(); ++i) {
|
||||
is_subsumed = false;
|
||||
|
@ -155,7 +155,7 @@ namespace Duality {
|
|||
|
||||
|
||||
expr_ref_vector rules(m_ctx.get_manager());
|
||||
svector< ::symbol> names;
|
||||
svector< ::symbol> names;
|
||||
unsigned_vector bounds;
|
||||
// m_ctx.get_rules_as_formulas(rules, names);
|
||||
|
||||
|
@ -189,7 +189,7 @@ namespace Duality {
|
|||
rules.push_back(f);
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
m_ctx.get_raw_rule_formulas(rules, names, bounds);
|
||||
|
||||
// get all the rules as clauses
|
||||
|
@ -199,7 +199,7 @@ namespace Duality {
|
|||
expr e(_d->ctx,rules[i].get());
|
||||
clauses.push_back(e);
|
||||
}
|
||||
|
||||
|
||||
std::vector<sort> b_sorts;
|
||||
std::vector<symbol> b_names;
|
||||
used_vars uv;
|
||||
|
@ -216,7 +216,7 @@ namespace Duality {
|
|||
#if 0
|
||||
// turn the query into a clause
|
||||
expr q(_d->ctx,m_ctx.bind_variables(query,false));
|
||||
|
||||
|
||||
std::vector<sort> b_sorts;
|
||||
std::vector<symbol> b_names;
|
||||
if (q.is_quantifier() && !q.is_quantifier_forall()) {
|
||||
|
@ -235,14 +235,14 @@ namespace Duality {
|
|||
qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc);
|
||||
clauses.push_back(qc);
|
||||
bounds.push_back(UINT_MAX);
|
||||
|
||||
|
||||
// get the background axioms
|
||||
unsigned num_asserts = m_ctx.get_num_assertions();
|
||||
for (unsigned i = 0; i < num_asserts; ++i) {
|
||||
expr e(_d->ctx,m_ctx.get_assertion(i));
|
||||
_d->rpfp->AssertAxiom(e);
|
||||
}
|
||||
|
||||
|
||||
// make sure each predicate is the head of at least one clause
|
||||
func_decl_set heads;
|
||||
for(unsigned i = 0; i < clauses.size(); i++){
|
||||
|
@ -297,14 +297,14 @@ namespace Duality {
|
|||
// populate the edge-to-clause map
|
||||
for(unsigned i = 0; i < _d->rpfp->edges.size(); ++i)
|
||||
_d->map[_d->rpfp->edges[i]] = i;
|
||||
|
||||
|
||||
// create a solver object
|
||||
|
||||
Solver *rs = Solver::Create("duality", _d->rpfp);
|
||||
|
||||
if(old_rs)
|
||||
rs->LearnFrom(old_rs); // new solver gets hints from old solver
|
||||
|
||||
|
||||
// set its options
|
||||
IF_VERBOSE(1, rs->SetOption("report","1"););
|
||||
rs->SetOption("full_expand",m_ctx.get_params().duality_full_expand() ? "1" : "0");
|
||||
|
@ -328,12 +328,12 @@ namespace Duality {
|
|||
ans = rs->Solve();
|
||||
}
|
||||
catch (Duality::solver::cancel_exception &exn){
|
||||
throw default_exception("duality canceled");
|
||||
throw default_exception(Z3_CANCELED_MSG);
|
||||
}
|
||||
catch (Duality::Solver::Incompleteness &exn){
|
||||
throw default_exception("incompleteness");
|
||||
}
|
||||
|
||||
|
||||
// profile!
|
||||
|
||||
if(m_ctx.get_params().duality_profile())
|
||||
|
@ -343,7 +343,7 @@ namespace Duality {
|
|||
_d->status = ans ? StatusModel : StatusRefutation;
|
||||
_d->cex.swap(rs->GetCounterexample()); // take ownership of cex
|
||||
_d->old_rs = rs; // save this for later hints
|
||||
|
||||
|
||||
if(old_data){
|
||||
dealloc(old_data); // this deallocates the old solver if there is one
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ namespace Duality {
|
|||
context &ctx = d->dd()->ctx;
|
||||
RPFP::Node &node = *root;
|
||||
RPFP::Edge &edge = *node.Outgoing;
|
||||
|
||||
|
||||
// first, prove the children (that are actually used)
|
||||
|
||||
for(unsigned i = 0; i < edge.Children.size(); i++){
|
||||
|
@ -434,19 +434,19 @@ namespace Duality {
|
|||
}
|
||||
}
|
||||
out << " )\n";
|
||||
|
||||
|
||||
out << " (labels";
|
||||
std::vector<symbol> labels;
|
||||
tree->GetLabels(&edge,labels);
|
||||
for(unsigned j = 0; j < labels.size(); j++){
|
||||
out << " " << labels[j];
|
||||
}
|
||||
|
||||
|
||||
out << " )\n";
|
||||
|
||||
// reference the proofs of all the children, in syntactic order
|
||||
// "true" means the child is not needed
|
||||
|
||||
|
||||
out << " (ref ";
|
||||
for(unsigned i = 0; i < edge.Children.size(); i++){
|
||||
if(!tree->Empty(edge.Children[i]))
|
||||
|
@ -468,7 +468,7 @@ namespace Duality {
|
|||
ast_manager &m = m_ctx.get_manager();
|
||||
model_ref md = get_model();
|
||||
out << "(fixedpoint \n";
|
||||
model_smt2_pp(out, m, *md.get(), 0);
|
||||
model_smt2_pp(out, m, *md.get(), 0);
|
||||
out << ")\n";
|
||||
}
|
||||
else if(_d->status == StatusRefutation){
|
||||
|
@ -550,22 +550,22 @@ namespace Duality {
|
|||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
|
||||
static proof_ref extract_proof(dl_interface *d, RPFP *tree, RPFP::Node *root) {
|
||||
context &ctx = d->dd()->ctx;
|
||||
ast_manager &mgr = ctx.m();
|
||||
RPFP::Node &node = *root;
|
||||
RPFP::Edge &edge = *node.Outgoing;
|
||||
RPFP::Edge *orig_edge = edge.map;
|
||||
|
||||
|
||||
// first, prove the children (that are actually used)
|
||||
|
||||
|
||||
proof_ref_vector prems(mgr);
|
||||
::vector<expr_ref_vector> substs;
|
||||
int orig_clause = d->dd()->map[orig_edge];
|
||||
expr &t = d->dd()->clauses[orig_clause];
|
||||
prems.push_back(mgr.mk_asserted(ctx.uncook(t)));
|
||||
|
||||
|
||||
substs.push_back(expr_ref_vector(mgr));
|
||||
if (t.is_quantifier() && t.is_quantifier_forall()) {
|
||||
int bound = t.get_quantifier_num_bound();
|
||||
|
@ -599,12 +599,12 @@ namespace Duality {
|
|||
for(unsigned i = 0; i < edge.F.IndParams.size(); i++)
|
||||
args.push_back(tree->Eval(&edge,edge.F.IndParams[i]));
|
||||
expr conc = f(args);
|
||||
|
||||
|
||||
|
||||
::vector< ::proof *> pprems;
|
||||
for(unsigned i = 0; i < prems.size(); i++)
|
||||
pprems.push_back(prems[i].get());
|
||||
|
||||
|
||||
proof_ref res(mgr.mk_hyper_resolve(pprems.size(),&pprems[0], ctx.uncook(conc), pos, substs),mgr);
|
||||
return res;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -59,7 +59,7 @@ void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clause
|
|||
clause.push_back(m.mk_not(d));
|
||||
}
|
||||
else {
|
||||
// must normalize assumption
|
||||
// must normalize assumption
|
||||
expr * b = 0;
|
||||
if (!dep2bool.find(d, b)) {
|
||||
b = m.mk_fresh_const(0, m.mk_bool_sort());
|
||||
|
@ -79,7 +79,7 @@ void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clause
|
|||
cls = mk_or(m, clause.size(), clause.c_ptr());
|
||||
clauses.push_back(cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class smt_tactic : public tactic {
|
||||
|
@ -96,7 +96,7 @@ class smt_tactic : public tactic {
|
|||
public:
|
||||
smt_tactic(params_ref const & p):
|
||||
m_params_ref(p),
|
||||
m_ctx(0),
|
||||
m_ctx(0),
|
||||
m_callback(0) {
|
||||
updt_params_core(p);
|
||||
TRACE("smt_tactic", tout << this << "\np: " << p << "\n";);
|
||||
|
@ -118,20 +118,20 @@ public:
|
|||
m_candidate_models = p.get_bool("candidate_models", false);
|
||||
m_fail_if_inconclusive = p.get_bool("fail_if_inconclusive", true);
|
||||
}
|
||||
|
||||
|
||||
virtual void updt_params(params_ref const & p) {
|
||||
TRACE("smt_tactic", tout << this << "\nupdt_params: " << p << "\n";);
|
||||
updt_params_core(p);
|
||||
fparams().updt_params(p);
|
||||
SASSERT(p.get_bool("auto_config", fparams().m_auto_config) == fparams().m_auto_config);
|
||||
}
|
||||
|
||||
|
||||
virtual void collect_param_descrs(param_descrs & r) {
|
||||
r.insert("candidate_models", CPK_BOOL, "(default: false) create candidate models even when quantifier or theory reasoning is incomplete.");
|
||||
r.insert("fail_if_inconclusive", CPK_BOOL, "(default: true) fail if found unsat (sat) for under (over) approximated goal.");
|
||||
smt_params_helper::collect_param_descrs(r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void collect_statistics(statistics & st) const {
|
||||
if (m_ctx)
|
||||
|
@ -146,7 +146,7 @@ public:
|
|||
virtual void reset_statistics() {
|
||||
m_stats.reset();
|
||||
}
|
||||
|
||||
|
||||
virtual void set_logic(symbol const & l) {
|
||||
m_logic = l;
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public:
|
|||
virtual void set_progress_callback(progress_callback * callback) {
|
||||
m_callback = callback;
|
||||
}
|
||||
|
||||
|
||||
struct scoped_init_ctx {
|
||||
smt_tactic & m_owner;
|
||||
smt_params m_params; // smt-setup overwrites parameters depending on the current assertions.
|
||||
|
@ -168,41 +168,41 @@ public:
|
|||
new_ctx->set_progress_callback(o.m_callback);
|
||||
}
|
||||
o.m_ctx = new_ctx;
|
||||
|
||||
|
||||
}
|
||||
|
||||
~scoped_init_ctx() {
|
||||
smt::kernel * d = m_owner.m_ctx;
|
||||
m_owner.m_ctx = 0;
|
||||
|
||||
|
||||
if (d)
|
||||
dealloc(d);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
virtual void operator()(goal_ref const & in,
|
||||
goal_ref_buffer & result,
|
||||
model_converter_ref & mc,
|
||||
proof_converter_ref & pc,
|
||||
expr_dependency_ref & core) {
|
||||
try {
|
||||
SASSERT(in->is_well_sorted());
|
||||
ast_manager & m = in->m();
|
||||
TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " "
|
||||
TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " "
|
||||
<< " PREPROCESS: " << fparams().m_preprocess << "\n";
|
||||
tout << "RELEVANCY: " << fparams().m_relevancy_lvl << "\n";
|
||||
tout << "fail-if-inconclusive: " << m_fail_if_inconclusive << "\n";
|
||||
tout << "params_ref: " << m_params_ref << "\n";
|
||||
tout << "nnf: " << fparams().m_nnf_cnf << "\n";);
|
||||
TRACE("smt_tactic_detail", in->display(tout););
|
||||
TRACE("smt_tactic_memory", tout << "wasted_size: " << m.get_allocator().get_wasted_size() << "\n";);
|
||||
TRACE("smt_tactic_memory", tout << "wasted_size: " << m.get_allocator().get_wasted_size() << "\n";);
|
||||
scoped_init_ctx init(*this, m);
|
||||
SASSERT(m_ctx != 0);
|
||||
|
||||
expr_ref_vector clauses(m);
|
||||
expr2expr_map bool2dep;
|
||||
ptr_vector<expr> assumptions;
|
||||
expr2expr_map bool2dep;
|
||||
ptr_vector<expr> assumptions;
|
||||
ref<filter_model_converter> fmc;
|
||||
if (in->unsat_core_enabled()) {
|
||||
extract_clauses_and_dependencies(in, clauses, assumptions, bool2dep, fmc);
|
||||
|
@ -225,9 +225,9 @@ public:
|
|||
}
|
||||
}
|
||||
if (m_ctx->canceled()) {
|
||||
throw tactic_exception("smt_tactic canceled");
|
||||
throw tactic_exception(Z3_CANCELED_MSG);
|
||||
}
|
||||
|
||||
|
||||
lbool r;
|
||||
if (assumptions.empty())
|
||||
r = m_ctx->setup_and_check();
|
||||
|
@ -315,7 +315,7 @@ tactic * mk_smt_tactic(params_ref const & p) {
|
|||
}
|
||||
|
||||
tactic * mk_smt_tactic_using(bool auto_config, params_ref const & _p) {
|
||||
params_ref p = _p;
|
||||
params_ref p = _p;
|
||||
p.set_bool("auto_config", auto_config);
|
||||
tactic * r = mk_smt_tactic(p);
|
||||
TRACE("smt_tactic", tout << "auto_config: " << auto_config << "\nr: " << r << "\np: " << p << "\n";);
|
||||
|
|
|
@ -289,7 +289,7 @@ private:
|
|||
|
||||
void check_point() {
|
||||
if (m.canceled()) {
|
||||
throw tactic_exception("canceled");
|
||||
throw tactic_exception(Z3_CANCELED_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue