mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 18:05:21 +00:00
289 lines
11 KiB
C++
289 lines
11 KiB
C++
/*++
|
|
Copyright (c) 2012 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
subpaving.cpp
|
|
|
|
Abstract:
|
|
|
|
Subpaving for non-linear arithmetic.
|
|
This is a wrapper for the different implementations
|
|
of the subpaving module.
|
|
This wrapper is the main interface between Z3 other modules and subpaving.
|
|
Thus, it assumes that polynomials have precise integer coefficients, and
|
|
bounds are rationals. If a particular implementation uses floats, then
|
|
internally the bounds are approximated.
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2012-08-07.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include"subpaving.h"
|
|
#include"subpaving_types.h"
|
|
#include"subpaving_mpq.h"
|
|
#include"subpaving_mpf.h"
|
|
#include"subpaving_hwf.h"
|
|
#include"subpaving_mpff.h"
|
|
#include"subpaving_mpfx.h"
|
|
|
|
namespace subpaving {
|
|
|
|
template<typename CTX>
|
|
class context_wrapper : public context {
|
|
protected:
|
|
CTX m_ctx;
|
|
public:
|
|
context_wrapper(typename CTX::numeral_manager & m, params_ref const & p, small_object_allocator * a):m_ctx(m, p, a) {}
|
|
virtual ~context_wrapper() {}
|
|
virtual unsigned num_vars() const { return m_ctx.num_vars(); }
|
|
virtual var mk_var(bool is_int) { return m_ctx.mk_var(is_int); }
|
|
virtual bool is_int(var x) const { return m_ctx.is_int(x); }
|
|
virtual var mk_monomial(unsigned sz, power const * pws) { return m_ctx.mk_monomial(sz, pws); }
|
|
virtual void inc_ref(ineq * a) { m_ctx.inc_ref(reinterpret_cast<typename CTX::ineq*>(a)); }
|
|
virtual void dec_ref(ineq * a) { m_ctx.dec_ref(reinterpret_cast<typename CTX::ineq*>(a)); }
|
|
virtual void add_clause(unsigned sz, ineq * const * atoms) { m_ctx.add_clause(sz, reinterpret_cast<typename CTX::ineq * const *>(atoms)); }
|
|
virtual void display_constraints(std::ostream & out, bool use_star) const { m_ctx.display_constraints(out, use_star); }
|
|
virtual void set_cancel(bool f) { m_ctx.set_cancel(f); }
|
|
virtual void set_display_proc(display_var_proc * p) { m_ctx.set_display_proc(p); }
|
|
virtual void reset_statistics() { m_ctx.reset_statistics(); }
|
|
virtual void collect_statistics(statistics & st) const { m_ctx.collect_statistics(st); }
|
|
virtual void collect_param_descrs(param_descrs & r) { m_ctx.collect_param_descrs(r); }
|
|
virtual void updt_params(params_ref const & p) { m_ctx.updt_params(p); }
|
|
virtual void operator()() { m_ctx(); }
|
|
virtual void display_bounds(std::ostream & out) const { m_ctx.display_bounds(out); }
|
|
};
|
|
|
|
class context_mpq_wrapper : public context_wrapper<context_mpq> {
|
|
scoped_mpq m_c;
|
|
scoped_mpq_vector m_as;
|
|
public:
|
|
context_mpq_wrapper(unsynch_mpq_manager & m, params_ref const & p, small_object_allocator * a):
|
|
context_wrapper<context_mpq>(m, p, a),
|
|
m_c(m),
|
|
m_as(m)
|
|
{}
|
|
|
|
virtual ~context_mpq_wrapper() {}
|
|
|
|
virtual unsynch_mpq_manager & qm() const { return m_ctx.nm(); }
|
|
|
|
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
|
|
m_as.reserve(sz);
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
m_ctx.nm().set(m_as[i], as[i]);
|
|
}
|
|
m_ctx.nm().set(m_c, c);
|
|
return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
|
|
}
|
|
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
|
|
return reinterpret_cast<ineq*>(m_ctx.mk_ineq(x, k, lower, open));
|
|
}
|
|
};
|
|
|
|
class context_mpf_wrapper : public context_wrapper<context_mpf> {
|
|
f2n<mpf_manager> & m_fm;
|
|
unsynch_mpq_manager & m_qm;
|
|
scoped_mpf m_c;
|
|
scoped_mpf_vector m_as;
|
|
scoped_mpq m_q1, m_q2;
|
|
|
|
// Convert the mpz (integer) into a mpf, and throws an exception if the conversion is not precise.
|
|
void int2mpf(mpz const & a, mpf & o) {
|
|
m_qm.set(m_q1, a);
|
|
m_ctx.nm().set(o, m_q1);
|
|
m_ctx.nm().m().to_rational(o, m_q2);
|
|
if (!m_qm.eq(m_q1, m_q2))
|
|
throw subpaving::exception();
|
|
}
|
|
|
|
public:
|
|
context_mpf_wrapper(f2n<mpf_manager> & fm, params_ref const & p, small_object_allocator * a):
|
|
context_wrapper<context_mpf>(fm, p, a),
|
|
m_fm(fm),
|
|
m_qm(fm.m().mpq_manager()),
|
|
m_c(fm.m()),
|
|
m_as(fm.m()),
|
|
m_q1(m_qm),
|
|
m_q2(m_qm) {
|
|
}
|
|
|
|
virtual ~context_mpf_wrapper() {}
|
|
|
|
virtual unsynch_mpq_manager & qm() const { return m_qm; }
|
|
|
|
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
|
|
try {
|
|
m_as.reserve(sz);
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
int2mpf(as[i], m_as[i]);
|
|
}
|
|
int2mpf(c, m_c);
|
|
return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
|
|
}
|
|
catch (f2n<mpf_manager>::exception) {
|
|
throw subpaving::exception();
|
|
}
|
|
}
|
|
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
|
|
try {
|
|
f2n<mpf_manager> & m = m_ctx.nm();
|
|
if (lower)
|
|
m.round_to_minus_inf();
|
|
else
|
|
m.round_to_plus_inf();
|
|
m.set(m_c, k);
|
|
return reinterpret_cast<ineq*>(m_ctx.mk_ineq(x, m_c, lower, open));
|
|
}
|
|
catch (f2n<mpf_manager>::exception) {
|
|
throw subpaving::exception();
|
|
}
|
|
}
|
|
};
|
|
|
|
class context_hwf_wrapper : public context_wrapper<context_hwf> {
|
|
f2n<hwf_manager> & m_fm;
|
|
unsynch_mpq_manager & m_qm;
|
|
hwf m_c;
|
|
svector<hwf> m_as;
|
|
|
|
// Convert the mpz (integer) into a hwf, and throws an exception if the conversion is not precise.
|
|
void int2hwf(mpz const & a, hwf & o) {
|
|
if (!m_qm.is_int64(a))
|
|
throw subpaving::exception();
|
|
int64 val = m_qm.get_int64(a);
|
|
double dval = static_cast<double>(val);
|
|
m_ctx.nm().set(o, dval);
|
|
double _dval = m_ctx.nm().m().to_double(o);
|
|
// TODO check the following test
|
|
if (static_cast<int64>(_dval) != val)
|
|
throw subpaving::exception();
|
|
}
|
|
|
|
public:
|
|
context_hwf_wrapper(f2n<hwf_manager> & fm, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a):
|
|
context_wrapper<context_hwf>(fm, p, a),
|
|
m_fm(fm),
|
|
m_qm(qm) {
|
|
}
|
|
|
|
virtual ~context_hwf_wrapper() {}
|
|
|
|
virtual unsynch_mpq_manager & qm() const { return m_qm; }
|
|
|
|
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
|
|
try {
|
|
m_as.reserve(sz);
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
int2hwf(as[i], m_as[i]);
|
|
}
|
|
int2hwf(c, m_c);
|
|
return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
|
|
}
|
|
catch (f2n<mpf_manager>::exception) {
|
|
throw subpaving::exception();
|
|
}
|
|
}
|
|
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
|
|
try {
|
|
f2n<hwf_manager> & m = m_ctx.nm();
|
|
if (lower)
|
|
m.round_to_minus_inf();
|
|
else
|
|
m.round_to_plus_inf();
|
|
m.set(m_c, k);
|
|
return reinterpret_cast<ineq*>(m_ctx.mk_ineq(x, m_c, lower, open));
|
|
}
|
|
catch (f2n<mpf_manager>::exception) {
|
|
throw subpaving::exception();
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename context_fpoint>
|
|
class context_fpoint_wrapper : public context_wrapper<context_fpoint> {
|
|
unsynch_mpq_manager & m_qm;
|
|
_scoped_numeral<typename context_fpoint::numeral_manager> m_c;
|
|
_scoped_numeral_vector<typename context_fpoint::numeral_manager> m_as;
|
|
scoped_mpz m_z1, m_z2;
|
|
|
|
void int2fpoint(mpz const & a, typename context_fpoint::numeral & o) {
|
|
m_qm.set(m_z1, a);
|
|
this->m_ctx.nm().set(o, m_qm, m_z1);
|
|
this->m_ctx.nm().to_mpz(o, m_qm, m_z2);
|
|
if (!m_qm.eq(m_z1, m_z2))
|
|
throw subpaving::exception();
|
|
}
|
|
|
|
public:
|
|
context_fpoint_wrapper(typename context_fpoint::numeral_manager & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a):
|
|
context_wrapper<context_fpoint>(m, p, a),
|
|
m_qm(qm),
|
|
m_c(m),
|
|
m_as(m),
|
|
m_z1(m_qm),
|
|
m_z2(m_qm) {
|
|
}
|
|
|
|
virtual ~context_fpoint_wrapper() {}
|
|
|
|
virtual unsynch_mpq_manager & qm() const { return m_qm; }
|
|
|
|
virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) {
|
|
try {
|
|
m_as.reserve(sz);
|
|
for (unsigned i = 0; i < sz; i++) {
|
|
int2fpoint(as[i], m_as[i]);
|
|
}
|
|
int2fpoint(c, m_c);
|
|
return this->m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs);
|
|
}
|
|
catch (typename context_fpoint::numeral_manager::exception) {
|
|
throw subpaving::exception();
|
|
}
|
|
}
|
|
|
|
virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) {
|
|
try {
|
|
typename context_fpoint::numeral_manager & m = this->m_ctx.nm();
|
|
if (lower)
|
|
m.round_to_minus_inf();
|
|
else
|
|
m.round_to_plus_inf();
|
|
m.set(m_c, m_qm, k);
|
|
return reinterpret_cast<ineq*>(this->m_ctx.mk_ineq(x, m_c, lower, open));
|
|
}
|
|
catch (typename context_fpoint::numeral_manager::exception) {
|
|
throw subpaving::exception();
|
|
}
|
|
}
|
|
};
|
|
|
|
typedef context_fpoint_wrapper<context_mpff> context_mpff_wrapper;
|
|
typedef context_fpoint_wrapper<context_mpfx> context_mpfx_wrapper;
|
|
|
|
context * mk_mpq_context(unsynch_mpq_manager & m, params_ref const & p, small_object_allocator * a) {
|
|
return alloc(context_mpq_wrapper, m, p, a);
|
|
}
|
|
|
|
context * mk_mpf_context(f2n<mpf_manager> & m, params_ref const & p, small_object_allocator * a) {
|
|
return alloc(context_mpf_wrapper, m, p, a);
|
|
}
|
|
|
|
context * mk_hwf_context(f2n<hwf_manager> & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a) {
|
|
return alloc(context_hwf_wrapper, m, qm, p, a);
|
|
}
|
|
|
|
context * mk_mpff_context(mpff_manager & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a) {
|
|
return alloc(context_mpff_wrapper, m, qm, p, a);
|
|
}
|
|
|
|
context * mk_mpfx_context(mpfx_manager & m, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a) {
|
|
return alloc(context_mpfx_wrapper, m, qm, p, a);
|
|
}
|
|
|
|
};
|