3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-13 12:28:44 +00:00

Simplify data-structures

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-01-05 11:51:58 -08:00
parent 14827e94f0
commit 322d355290
2 changed files with 193 additions and 132 deletions

View file

@ -93,6 +93,8 @@ namespace realclosure {
numeral const & upper() const { return m_upper; }
bool lower_is_inf() const { return m_lower_inf; }
bool upper_is_inf() const { return m_upper_inf; }
bool lower_is_open() const { return m_lower_open; }
bool upper_is_open() const { return m_upper_open; }
};
void set_rounding(bool to_plus_inf) { m_manager.m_to_plus_inf = to_plus_inf; }
@ -149,6 +151,7 @@ namespace realclosure {
value(bool rat):m_ref_count(0), m_rational(rat) {}
bool is_rational() const { return m_rational; }
mpbqi const & interval() const { return m_interval; }
mpbqi & interval() { return m_interval; }
};
struct rational_value : public value {
@ -160,52 +163,22 @@ namespace realclosure {
struct extension;
bool rank_lt(extension * r1, extension * r2);
struct polynomial_expr {
// The values occurring in this polynomial m_p may only contain extensions that are smaller than m_ext.
// The polynomial m_p must not be the constant polynomial on m_ext. That is,
// it contains a nonzero coefficient at position k > 0. It is not a constant polynomial on m_ext.
polynomial m_p;
extension * m_ext;
bool m_real; //!< True if the polynomial expression does not depend on infinitesimal values
mpbqi m_interval; //!< approximation as an interval with binary rational end-points
polynomial_expr():m_ext(0), m_real(false) {}
extension * ext() const { return m_ext; }
bool is_real() const { return m_real; }
polynomial const & p() const { return m_p; }
mpbqi const & interval() const { return m_interval; }
};
struct rational_function_value : public value {
// We assume that a null polynomial_expr denotes 1.
// m_numerator OR m_denominator must be different from NULL
polynomial_expr * m_numerator;
polynomial_expr * m_denominator;
polynomial m_numerator;
polynomial m_denominator;
extension * m_ext;
bool m_real; //!< True if the polynomial expression does not depend on infinitesimal values.
rational_function_value(extension * ext):value(false), m_ext(ext), m_real(false) {}
polynomial_expr * num() const { return m_numerator; }
polynomial_expr * den() const { return m_denominator; }
rational_function_value(polynomial_expr * num, polynomial_expr * den):value(false), m_numerator(num), m_denominator(den) {
SASSERT(num != 0 || den != 0);
}
polynomial const & num() const { return m_numerator; }
polynomial & num() { return m_numerator; }
polynomial const & den() const { return m_denominator; }
polynomial & den() { return m_denominator; }
extension * ext() const {
if (den() == 0)
return num()->ext();
else if (num() == 0 || rank_lt(num()->ext(), den()->ext()))
return den()->ext();
else
return num()->ext();
}
bool is_real() const {
if (den() == 0)
return num()->is_real();
else if (num() == 0)
return den()->is_real();
else
return num()->is_real() && den()->is_real();
}
extension * ext() const { return m_ext; }
bool is_real() const { return m_real; }
void set_real(bool f) { m_real = f; }
};
typedef ptr_vector<value> value_vector;
@ -244,6 +217,7 @@ namespace realclosure {
bool is_transcendental() const { return knd() == TRANSCENDENTAL; }
mpbqi const & interval() const { return m_interval; }
mpbqi & interval() { return m_interval; }
};
bool rank_lt(extension * r1, extension * r2) {
@ -417,18 +391,15 @@ namespace realclosure {
// TODO
}
void finalize_polynomial(polynomial & p) {
/**
\brief Reset the given polynomial.
That is, after the call p is the 0 polynomial.
*/
void reset_p(polynomial & p) {
dec_ref(p.size(), p.c_ptr());
p.finalize(allocator());
}
void del_polynomial_expr(polynomial_expr * p) {
finalize_polynomial(p->m_p);
bqim().del(p->m_interval);
dec_ref_ext(p->m_ext);
allocator().deallocate(sizeof(polynomial_expr), p);
}
void del_rational(rational_value * v) {
bqim().del(v->m_interval);
qm().del(v->m_value);
@ -437,10 +408,9 @@ namespace realclosure {
void del_rational_function(rational_function_value * v) {
bqim().del(v->m_interval);
if (v->num())
del_polynomial_expr(v->num());
if (v->den())
del_polynomial_expr(v->den());
reset_p(v->num());
reset_p(v->den());
dec_ref_ext(v->ext());
allocator().deallocate(sizeof(rational_function_value), v);
}
@ -452,11 +422,11 @@ namespace realclosure {
}
void del_algebraic(algebraic * a) {
finalize_polynomial(a->m_p);
reset_p(a->m_p);
bqim().del(a->m_interval);
unsigned sz = a->m_signs.size();
for (unsigned i = 0; i < sz; i++) {
finalize_polynomial(a->m_signs[i].first);
reset_p(a->m_signs[i].first);
}
allocator().deallocate(sizeof(algebraic), a);
}
@ -544,13 +514,22 @@ namespace realclosure {
}
/**
\brief Return true if v is one.
\brief Return true if v is represented as rational value one.
*/
bool is_one(value * v) const {
// TODO: make the check complete
bool is_rational_one(value * v) const {
return !is_zero(v) && is_nz_rational(v) && qm().is_one(to_mpq(v));
}
/**
\brief Return true if v is the value one;
*/
bool is_one(value * v) const {
if (is_rational_one(v))
return true;
// TODO: check if v is equal to one.
return false;
}
/**
\brief Return true if v is a represented as a rational function of the set of field extensions.
*/
@ -651,7 +630,22 @@ namespace realclosure {
SASSERT(ext->is_algebraic());
return static_cast<algebraic*>(ext);
}
/**
\brief Return True if the given extension is a Real value.
The result is approximate for algebraic extensions.
For algebraic extensions, we have
- true result is always correct (i.e., the extension is really a real value)
- false result is approximate (i.e., the extension may be a real value although it is a root of a polynomial that contains non-real coefficients)
Example: Assume eps is an infinitesimal, and pi is 3.14... .
Assume also that ext is the unique root between (3, 4) of the following polynomial:
x^2 - (pi + eps)*x + pi*ext
Thus, x is pi, but the system will return false, since its defining polynomial has infinitesimal
coefficients. In the future, to make everything precise, we should be able to factor the polynomial
above as
(x - eps)*(x - pi)
and then detect that x is actually the root of (x - pi).
*/
bool is_real(extension * ext) {
switch (ext->knd()) {
case extension::TRANSCENDENTAL: return true;
@ -663,48 +657,113 @@ namespace realclosure {
}
}
polynomial_expr * mk_polynomial_expr(unsigned sz, value * const * p, extension * ext, mpbqi & interval) {
SASSERT(sz > 1);
SASSERT(p[sz-1] != 0);
polynomial_expr * r = new (allocator()) polynomial_expr();
r->m_p.set(allocator(), sz, p);
inc_ref(sz, p);
inc_ref_ext(ext);
r->m_ext = ext;
realclosure::swap(r->m_interval, interval);
r->m_real = is_real(ext);
for (unsigned i = 0; i < sz && r->m_real; i++) {
/**
\brief Return true if v is definitely a real value.
*/
bool is_real(value * v) {
if (v->is_rational())
return true;
else
return to_rational_function(v)->is_real();
}
bool is_real(unsigned sz, value * const * p) {
for (unsigned i = 0; i < sz; i++)
if (!is_real(p[i]))
r->m_real = false;
}
return r;
return false;
return true;
}
void updt_interval(rational_function_value & v) {
if (v.den() == 0) {
bqim().set(v.m_interval, v.num()->interval());
}
else if (v.num() == 0) {
bqim().inv(v.den()->interval(), v.m_interval);
}
else {
bqim().div(v.num()->interval(), v.den()->interval(), v.m_interval);
}
/**
\brief Set the polynomial p with the given coefficients as[0], ..., as[n-1]
*/
void set_p(polynomial & p, unsigned n, value * const * as) {
SASSERT(n > 0);
SASSERT(!is_zero(as[n - 1]));
reset_p(p);
p.set(allocator(), n, as);
inc_ref(n, as);
}
/**
\brief Set the polynomial p as the constant polynomial 1.
*/
void set_p_one(polynomial & p) {
set_p(p, 1, &m_one);
}
/**
\brief Set the lower bound of the given interval.
*/
void set_lower_core(mpbqi & a, mpbq const & k, bool open, bool inf) {
bqm().set(a.lower(), k);
a.set_lower_is_open(open);
a.set_lower_is_inf(inf);
}
/**
\brief a.lower <- k
*/
void set_lower(mpbqi & a, mpbq const & k, bool open = true) {
set_lower_core(a, k, open, false);
}
/**
\brief Set the upper bound of the given interval.
*/
void set_upper_core(mpbqi & a, mpbq const & k, bool open, bool inf) {
bqm().set(a.upper(), k);
a.set_upper_is_open(open);
a.set_upper_is_inf(inf);
}
/**
\brief a.upper <- k
*/
void set_upper(mpbqi & a, mpbq const & k, bool open = true) {
set_upper_core(a, k, open, false);
}
/**
\brief a <- b
*/
void set_interval(mpbqi & a, mpbqi const & b) {
set_lower_core(a, b.lower(), b.lower_is_open(), b.lower_is_inf());
set_upper_core(a, b.upper(), b.upper_is_open(), b.upper_is_inf());
}
/**
\brief Create a value using the given extension.
*/
rational_function_value * mk_value(extension * ext) {
rational_function_value * v = alloc(rational_function_value, ext);
inc_ref_ext(ext);
value * num[2] = { 0, one() };
set_p(v->num(), 2, num);
set_p_one(v->den());
set_interval(v->interval(), ext->interval());
v->set_real(is_real(ext));
return v;
}
/**
\brief Create a new infinitesimal.
*/
void mk_infinitesimal(symbol const & n, numeral & r) {
unsigned idx = next_infinitesimal_idx();
infinitesimal * eps = alloc(infinitesimal, idx, n);
m_extensions[extension::INFINITESIMAL].push_back(eps);
value * p[2] = { 0, one() };
mpbq zero(0);
mpbq tiny(1, m_ini_precision);
mpbqi interval(zero, tiny);
polynomial_expr * numerator = mk_polynomial_expr(2, p, eps, interval);
rational_function_value * v = alloc(rational_function_value, numerator, 0);
r.m_value = v;
set_lower(eps->interval(), mpbq(0));
set_upper(eps->interval(), mpbq(1, m_ini_precision));
r.m_value = mk_value(eps);
inc_ref(r.m_value);
updt_interval(*v);
SASSERT(sign(r) > 0);
SASSERT(!is_real(r));
}
@ -738,17 +797,6 @@ namespace realclosure {
SASSERT(is_zero(a));
}
int sign(polynomial_expr * p) {
if (p == 0) {
// Remark: The null polynomial expression denotes 1
return 1;
}
else {
SASSERT(!bqim().contains_zero(p->m_interval));
return bqim().is_P(p->m_interval) ? 1 : -1;
}
}
int sign(numeral const & a) {
if (is_zero(a))
return 0;
@ -756,8 +804,9 @@ namespace realclosure {
return qm().is_pos(to_mpq(a)) ? 1 : -1;
}
else {
rational_function_value * v = to_rational_function(a);
return sign(v->num()) * sign(v->den());
value * v = a.m_value;
SASSERT(!bqim().contains_zero(v->interval()));
return bqim().is_P(v->interval()) ? 1 : -1;
}
}
@ -772,7 +821,7 @@ namespace realclosure {
}
}
bool is_real(value * v) {
bool is_real(value * v) const {
if (is_zero(v) || is_nz_rational(v))
return true;
else
@ -780,10 +829,7 @@ namespace realclosure {
}
bool is_real(numeral const & a) const {
if (is_zero(a) || is_nz_rational(a))
return true;
else
return to_rational_function(a)->is_real();
return is_real(a.m_value);
}
void mpq_to_mpbqi(mpq const & q, mpbqi & interval) {
@ -986,7 +1032,7 @@ namespace realclosure {
*/
void div(value_ref_buffer & p, value * a) {
SASSERT(!is_zero(a));
if (is_one(a))
if (is_rational_one(a))
return;
unsigned sz = p.size();
for (unsigned i = 0; i < sz; i++)
@ -1102,12 +1148,17 @@ namespace realclosure {
*/
void mk_monic(value_ref_buffer & p) {
unsigned sz = p.size();
if (sz > 0 && !is_one(p[sz-1])) {
if (sz > 0) {
SASSERT(p[sz-1] != 0);
for (unsigned i = 0; i < sz - 1; i++) {
p.set(i, div(p[i], p[sz-1]));
if (!is_one(p[sz-1])) {
for (unsigned i = 0; i < sz - 1; i++) {
p.set(i, div(p[i], p[sz-1]));
}
}
p.set(0, one());
// I perform the following assignment even when is_one(p[sz-1]) returns true,
// Reason: the leading coefficient may be equal to one but may not be encoded using
// the rational value 1.
p.set(sz-1, one());
}
}
@ -1339,7 +1390,8 @@ namespace realclosure {
}
else {
rational_function_value * v = to_rational_function(a);
std::swap(v->m_numerator, v->m_denominator);
v->num().swap(v->den());
// TODO: Invert interval
}
}
else {
@ -1385,13 +1437,6 @@ namespace realclosure {
}
}
void mark(polynomial_expr * p) {
if (p == 0)
return;
mark(p->ext());
mark(p->p());
}
void mark(polynomial const & p) {
for (unsigned i = 0; i < p.size(); i++) {
mark(p[i]);
@ -1402,6 +1447,7 @@ namespace realclosure {
if (v == 0 || is_nz_rational(v))
return;
rational_function_value * rf = to_rational_function(v);
mark(rf->ext());
mark(rf->num());
mark(rf->den());
}
@ -1423,7 +1469,7 @@ namespace realclosure {
if (i == 0)
display(out, p[i], compact);
else {
if (!is_one(p[i])) {
if (!is_rational_one(p[i])) {
out << "(";
display(out, p[i], compact);
out << ")*";
@ -1450,8 +1496,8 @@ namespace realclosure {
}
};
void display_polynomial_expr(std::ostream & out, polynomial_expr const & p, bool compact) const {
display_polynomial(out, p.p(), display_ext_proc(*this, p.ext()), compact);
void display_polynomial_expr(std::ostream & out, polynomial const & p, extension * ext, bool compact) const {
display_polynomial(out, p, display_ext_proc(*this, ext), compact);
}
static void display_poly_sign(std::ostream & out, int s) {
@ -1491,6 +1537,17 @@ namespace realclosure {
}
}
/**
\brief Return true if p is the constant polynomial where the coefficient is
the rational value 1.
\remark This is NOT checking whether p is actually equal to 1.
That is, it is just checking the representation.
*/
bool is_rational_one(polynomial const & p) const {
return p.size() == 1 && is_one(p[0]);
}
void display(std::ostream & out, value * v, bool compact) const {
if (v == 0)
out << "0";
@ -1498,19 +1555,19 @@ namespace realclosure {
qm().display(out, to_mpq(v));
else {
rational_function_value * rf = to_rational_function(v);
if (rf->den() == 0) {
display_polynomial_expr(out, *rf->num(), compact);
if (is_rational_one(rf->den())) {
display_polynomial_expr(out, rf->num(), rf->ext(), compact);
}
else if (rf->num() == 0) {
else if (is_rational_one(rf->num())) {
out << "1/(";
display_polynomial_expr(out, *rf->den(), compact);
display_polynomial_expr(out, rf->den(), rf->ext(), compact);
out << ")";
}
else {
out << "(";
display_polynomial_expr(out, *rf->num(), compact);
display_polynomial_expr(out, rf->num(), rf->ext(), compact);
out << ")/(";
display_polynomial_expr(out, *rf->den(), compact);
display_polynomial_expr(out, rf->den(), rf->ext(), compact);
out << ")";
}
}

View file

@ -176,6 +176,10 @@ public:
}
T * c_ptr() { return m_data; }
void swap(array & other) {
std::swap(m_data, other.m_data);
}
};
template<typename T>