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

Add refine interval infrastructure

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-01-06 18:30:41 -08:00
parent c01f27fe13
commit f1d47f35b2
3 changed files with 563 additions and 32 deletions

View file

@ -371,6 +371,9 @@ public:
interval * operator->() { interval * operator->() {
return &m_interval; return &m_interval;
} }
interval const * operator->() const {
return &m_interval;
}
}; };
#endif #endif

View file

@ -309,7 +309,8 @@ namespace realclosure {
typedef ref_vector<value, imp> value_ref_vector; typedef ref_vector<value, imp> value_ref_vector;
typedef ref_buffer<value, imp, REALCLOSURE_INI_BUFFER_SIZE> value_ref_buffer; typedef ref_buffer<value, imp, REALCLOSURE_INI_BUFFER_SIZE> value_ref_buffer;
typedef obj_ref<value, imp> value_ref; typedef obj_ref<value, imp> value_ref;
typedef _scoped_interval<mpqi_manager> scoped_mpqi; typedef _scoped_interval<mpqi_manager> scoped_mpqi;
typedef _scoped_interval<mpbqi_manager> scoped_mpbqi;
small_object_allocator * m_allocator; small_object_allocator * m_allocator;
bool m_own_allocator; bool m_own_allocator;
@ -328,6 +329,9 @@ namespace realclosure {
// Parameters // Parameters
unsigned m_ini_precision; //!< initial precision for transcendentals, infinitesimals, etc. unsigned m_ini_precision; //!< initial precision for transcendentals, infinitesimals, etc.
int m_min_magnitude; int m_min_magnitude;
unsigned m_inf_precision; //!< 2^m_inf_precision is used as the lower bound of oo and -2^m_inf_precision is used as the upper_bound of -oo
scoped_mpbq m_plus_inf_approx; // lower bound for binary rational intervals used to approximate an infinite positive value
scoped_mpbq m_minus_inf_approx; // upper bound for binary rational intervals used to approximate an infinite negative value
volatile bool m_cancel; volatile bool m_cancel;
@ -379,7 +383,9 @@ namespace realclosure {
m_qm(qm), m_qm(qm),
m_bqm(m_qm), m_bqm(m_qm),
m_qim(m_qm), m_qim(m_qm),
m_bqim(m_bqm) { m_bqim(m_bqm),
m_plus_inf_approx(m_bqm),
m_minus_inf_approx(m_bqm) {
mpq one(1); mpq one(1);
m_one = mk_rational(one); m_one = mk_rational(one);
inc_ref(m_one); inc_ref(m_one);
@ -400,7 +406,7 @@ namespace realclosure {
} }
unsynch_mpq_manager & qm() const { return m_qm; } unsynch_mpq_manager & qm() const { return m_qm; }
mpbq_manager & bqm() { return m_bqm; } mpbq_config::numeral_manager & bqm() { return m_bqm; }
mpqi_manager & qim() { return m_qim; } mpqi_manager & qim() { return m_qim; }
mpbqi_manager & bqim() { return m_bqim; } mpbqi_manager & bqim() { return m_bqim; }
mpbqi_manager const & bqim() const { return m_bqim; } mpbqi_manager const & bqim() const { return m_bqim; }
@ -421,23 +427,43 @@ namespace realclosure {
The magnitude is an approximation of the size of the interval. The magnitude is an approximation of the size of the interval.
*/ */
int magnitude(mpbq const & l, mpbq const & u) { int magnitude(mpbq const & l, mpbq const & u) {
SASSERT(bqm().is_nonneg(l) || bqm().is_nonpos(u)); SASSERT(bqm().ge(u, l));
int l_k = l.k(); scoped_mpbq w(bqm());
int u_k = u.k(); bqm().sub(u, l, w);
if (l_k == u_k) if (bqm().is_zero(w))
return bqm().magnitude_ub(l); return INT_MIN;
if (bqm().is_nonneg(l)) SASSERT(bqm().is_pos(w));
return qm().log2(u.numerator()) - qm().log2(l.numerator()) - u_k + l_k - u_k; return bqm().magnitude_ub(w);
else }
return qm().mlog2(u.numerator()) - qm().mlog2(l.numerator()) - u_k + l_k - u_k;
/**
\brief Return the magnitude of the given interval.
The magnitude is an approximation of the size of the interval.
*/
int magnitude(mpbqi const & i) {
if (i.lower_is_inf() || i.upper_is_inf())
return INT_MAX;
else
return magnitude(i.lower(), i.upper());
} }
/** /**
\brief Return the magnitude of the given interval. \brief Return the magnitude of the given interval.
The magnitude is an approximation of the size of the interval. The magnitude is an approximation of the size of the interval.
*/ */
int magnitude(mpbqi const & i) { int magnitude(mpq const & l, mpq const & u) {
return magnitude(i.lower(), i.upper()); SASSERT(qm().ge(u, l));
scoped_mpq w(qm());
qm().sub(u, l, w);
if (qm().is_zero(w))
return INT_MIN;
SASSERT(qm().is_pos(w));
return static_cast<int>(qm().log2(w.get().numerator())) + 1 - static_cast<int>(qm().log2(w.get().denominator()));
}
int magnitude(scoped_mpqi const & i) {
SASSERT(!i->m_lower_inf && !i->m_upper_inf);
return magnitude(i->m_lower, i->m_upper);
} }
/** /**
@ -447,6 +473,34 @@ namespace realclosure {
return magnitude(i) < m_min_magnitude; return magnitude(i) < m_min_magnitude;
} }
#define SMALL_UNSIGNED 1 << 16
static unsigned inc_precision(unsigned prec, unsigned inc) {
if (prec < SMALL_UNSIGNED)
return prec + inc;
else
return prec;
}
struct scoped_set_div_precision {
mpbq_config::numeral_manager & m_bqm;
unsigned m_old_precision;
scoped_set_div_precision(mpbq_config::numeral_manager & bqm, unsigned prec):m_bqm(bqm) {
m_old_precision = m_bqm.m_div_precision;
m_bqm.m_div_precision = prec;
}
~scoped_set_div_precision() {
m_bqm.m_div_precision = m_old_precision;
}
};
/**
\brief c <- a/b with precision prec.
*/
void div(mpbqi const & a, mpbqi const & b, unsigned prec, mpbqi & c) {
scoped_set_div_precision set(bqm(), prec);
bqim().div(a, b, c);
}
/** /**
\brief Save the current interval (i.e., approximation) of the given value. \brief Save the current interval (i.e., approximation) of the given value.
*/ */
@ -507,8 +561,11 @@ namespace realclosure {
void updt_params(params_ref const & p) { void updt_params(params_ref const & p) {
m_ini_precision = p.get_uint("initial_precision", 24); m_ini_precision = p.get_uint("initial_precision", 24);
m_inf_precision = p.get_uint("inf_precision", 24);
m_min_magnitude = -static_cast<int>(p.get_uint("min_mag", 64)); m_min_magnitude = -static_cast<int>(p.get_uint("min_mag", 64));
// TODO bqm().power(mpbq(2), m_inf_precision, m_plus_inf_approx);
bqm().set(m_minus_inf_approx, m_plus_inf_approx);
bqm().neg(m_minus_inf_approx);
} }
/** /**
@ -831,6 +888,20 @@ namespace realclosure {
inc_ref(n, as); inc_ref(n, as);
} }
/**
\brief Return true if a is an open interval.
*/
static bool is_open_interval(mpbqi const & a) {
return a.lower_is_inf() && a.upper_is_inf();
}
/**
\brief Return true if the interval contains zero.
*/
bool contains_zero(mpbqi const & a) const {
return bqim().contains_zero(a);
}
/** /**
\brief Set the lower bound of the given interval. \brief Set the lower bound of the given interval.
*/ */
@ -847,6 +918,15 @@ namespace realclosure {
set_lower_core(a, k, open, false); set_lower_core(a, k, open, false);
} }
/**
\brief a.lower <- -oo
*/
void set_lower_inf(mpbqi & a) {
bqm().reset(a.lower());
a.set_lower_is_open(true);
a.set_lower_is_inf(true);
}
/** /**
\brief Set the upper bound of the given interval. \brief Set the upper bound of the given interval.
*/ */
@ -863,6 +943,15 @@ namespace realclosure {
set_upper_core(a, k, open, false); set_upper_core(a, k, open, false);
} }
/**
\brief a.upper <- oo
*/
void set_upper_inf(mpbqi & a) {
bqm().reset(a.upper());
a.set_upper_is_open(true);
a.set_upper_is_inf(true);
}
/** /**
\brief a <- b \brief a <- b
*/ */
@ -920,11 +1009,19 @@ namespace realclosure {
mk_infinitesimal(symbol(next_infinitesimal_idx()), r); mk_infinitesimal(symbol(next_infinitesimal_idx()), r);
} }
void refine_transcedental_interval(transcendental * t) { void refine_transcendental_interval(transcendental * t) {
scoped_mpqi i(qim()); scoped_mpqi i(qim());
t->m_k++; t->m_k++;
t->m_proc(t->m_k, qim(), i); t->m_proc(t->m_k, qim(), i);
unsigned k = std::max(t->m_k, m_ini_precision); int m = magnitude(i);
TRACE("rcf",
tout << "refine_transcendental_interval rational: " << m << "\nrational interval: ";
qim().display(tout, i); tout << std::endl;);
unsigned k;
if (m >= 0)
k = m_ini_precision;
else
k = inc_precision(-m, 8);
scoped_mpbq l(bqm()); scoped_mpbq l(bqm());
mpq_to_mpbqi(i->m_lower, t->interval(), k); mpq_to_mpbqi(i->m_lower, t->interval(), k);
// save lower // save lower
@ -933,14 +1030,22 @@ namespace realclosure {
bqm().set(t->interval().lower(), l); bqm().set(t->interval().lower(), l);
} }
void refine_transcendental_interval(transcendental * t, unsigned prec) {
while (!check_precision(t->interval(), prec)) {
TRACE("rcf", tout << "refine_transcendental_interval: " << magnitude(t->interval()) << std::endl;);
checkpoint();
refine_transcendental_interval(t);
}
}
void mk_transcendental(symbol const & n, mk_interval & proc, numeral & r) { void mk_transcendental(symbol const & n, mk_interval & proc, numeral & r) {
unsigned idx = next_transcendental_idx(); unsigned idx = next_transcendental_idx();
transcendental * t = alloc(transcendental, idx, n, proc); transcendental * t = alloc(transcendental, idx, n, proc);
m_extensions[extension::TRANSCENDENTAL].push_back(t); m_extensions[extension::TRANSCENDENTAL].push_back(t);
while (bqim().contains_zero(t->interval())) { while (contains_zero(t->interval())) {
checkpoint(); checkpoint();
refine_transcedental_interval(t); refine_transcendental_interval(t);
} }
set(r, mk_rational_function_value(t)); set(r, mk_rational_function_value(t));
@ -993,7 +1098,7 @@ namespace realclosure {
return qm().is_pos(to_mpq(a)) ? 1 : -1; return qm().is_pos(to_mpq(a)) ? 1 : -1;
} }
else { else {
SASSERT(!bqim().contains_zero(a->interval())); SASSERT(!contains_zero(a->interval()));
return bqim().is_P(a->interval()) ? 1 : -1; return bqim().is_P(a->interval()) ? 1 : -1;
} }
} }
@ -1040,7 +1145,7 @@ namespace realclosure {
if (qm().is_neg(q)) { if (qm().is_neg(q)) {
::swap(interval.lower(), interval.upper()); ::swap(interval.lower(), interval.upper());
} }
while (bqim().contains_zero(interval) || !check_precision(interval, k)) { while (contains_zero(interval) || !check_precision(interval, k) || bqm().is_zero(interval.lower()) || bqm().is_zero(interval.upper())) {
checkpoint(); checkpoint();
bqm().refine_lower(q, interval.lower(), interval.upper()); bqm().refine_lower(q, interval.lower(), interval.upper());
bqm().refine_upper(q, interval.lower(), interval.upper()); bqm().refine_upper(q, interval.lower(), interval.upper());
@ -1054,9 +1159,9 @@ namespace realclosure {
mpq_to_mpbqi(to_mpq(a), a->m_interval, m_ini_precision); mpq_to_mpbqi(to_mpq(a), a->m_interval, m_ini_precision);
} }
mpbqi const & interval(value * a) const { mpbqi & interval(value * a) const {
SASSERT(a != 0); SASSERT(a != 0);
if (bqim().contains_zero(a->m_interval)) { if (contains_zero(a->m_interval)) {
SASSERT(is_nz_rational(a)); SASSERT(is_nz_rational(a));
const_cast<imp*>(this)->initialize_rational_value_interval(a); const_cast<imp*>(this)->initialize_rational_value_interval(a);
} }
@ -1131,7 +1236,25 @@ namespace realclosure {
} }
void root(numeral const & a, unsigned k, numeral & b) { void root(numeral const & a, unsigned k, numeral & b) {
// TODO if (k == 0)
throw exception("0-th root is indeterminate");
if (k == 1 || is_zero(a)) {
set(b, a);
return;
}
if (sign(a) < 0 && k % 2 == 0)
throw exception("even root of negative number");
// create the polynomial p of the form x^k - a
value_ref_buffer p(*this);
p.push_back(neg(a.m_value));
for (unsigned i = 0; i < k - 1; i++)
p.push_back(0);
p.push_back(one());
// TODO: invoke isolate_roots
} }
void power(numeral const & a, unsigned k, numeral & b) { void power(numeral const & a, unsigned k, numeral & b) {
@ -1530,6 +1653,379 @@ namespace realclosure {
sturm_seq_core(seq); sturm_seq_core(seq);
} }
void refine_rational_interval(rational_value * v, unsigned prec) {
mpbqi & i = interval(v);
if (!i.lower_is_open() && !i.lower_is_open()) {
SASSERT(bqm().eq(i.lower(), i.upper()));
return;
}
while (!check_precision(i, prec)) {
checkpoint();
bqm().refine_lower(to_mpq(v), i.lower(), i.upper());
bqm().refine_upper(to_mpq(v), i.lower(), i.upper());
}
}
/**
\brief Refine the interval for each coefficient of in the polynomial p.
*/
bool refine_coeffs_interval(polynomial const & p, unsigned prec) {
unsigned sz = p.size();
for (unsigned i = 0; i < sz; i++) {
if (p[i] != 0 && !refine_interval(p[i], prec))
return false;
}
return true;
}
/**
\brief Store in r the interval p(v).
*/
void polynomial_interval(polynomial const & p, mpbqi const & v, mpbqi & r) {
// We compute r using the Horner Sequence
// ((a_n * v + a_{n-1})*v + a_{n-2})*v + a_{n-3} ...
// where a_i's are the coefficients of p.
unsigned sz = p.size();
if (sz == 1) {
bqim().set(r, interval(p[0]));
}
else {
SASSERT(sz > 0);
SASSERT(p[sz - 1] != 0);
// r <- a_n * v
bqim().mul(interval(p[sz-1]), v, r);
unsigned i = sz - 1;
while (i > 0) {
--i;
if (p[i] != 0)
bqim().add(r, interval(p[i]), r);
if (i > 0)
bqim().mul(r, v, r);
}
}
}
/**
\brief Update the interval of v by using the intervals of
extension and coefficients of the rational function.
*/
void update_rf_interval(rational_function_value * v, unsigned prec) {
if (is_rational_one(v->den())) {
polynomial_interval(v->num(), v->ext()->interval(), v->interval());
}
else {
scoped_mpbqi num_i(bqim()), den_i(bqim());
polynomial_interval(v->num(), v->ext()->interval(), num_i);
polynomial_interval(v->den(), v->ext()->interval(), den_i);
div(num_i, den_i, inc_precision(prec, 2), v->interval());
}
}
void refine_transcendental_interval(rational_function_value * v, unsigned prec) {
SASSERT(v->ext()->is_transcendental());
polynomial const & n = v->num();
polynomial const & d = v->den();
unsigned _prec = prec;
while (true) {
VERIFY(refine_coeffs_interval(n, _prec)); // must return true because a transcendental never depends on an infinitesimal
VERIFY(refine_coeffs_interval(d, _prec)); // must return true because a transcendental never depends on an infinitesimal
refine_transcendental_interval(to_transcendental(v->ext()), _prec);
update_rf_interval(v, prec);
TRACE("rcf", tout << "after update_rf_interval: " << magnitude(v->interval()) << " ";
bqim().display(tout, v->interval()); tout << std::endl;);
if (check_precision(v->interval(), prec))
return;
_prec++;
}
}
bool refine_infinitesimal_interval(rational_function_value * v, unsigned prec) {
SASSERT(v->ext()->is_infinitesimal());
polynomial const & numerator = v->num();
polynomial const & denominator = v->den();
unsigned num_idx = first_non_zero(numerator);
unsigned den_idx = first_non_zero(denominator);
if (num_idx == 0 && den_idx == 0) {
unsigned _prec = prec;
while (true) {
refine_interval(numerator[num_idx], _prec);
refine_interval(denominator[num_idx], _prec);
mpbqi const & num_i = interval(numerator[num_idx]);
mpbqi const & den_i = interval(denominator[num_idx]);
SASSERT(!contains_zero(num_i));
SASSERT(!contains_zero(den_i));
if (is_open_interval(num_i) && is_open_interval(den_i)) {
// This case is simple because adding/subtracting infinitesimal quantities, will
// not change the interval.
div(num_i, den_i, inc_precision(prec, 2), v->interval());
}
else {
// The intervals num_i and den_i may not be open.
// Example: numerator[num_idx] or denominator[num_idx] are rationals
// that can be precisely represented as binary rationals.
scoped_mpbqi new_num_i(bqim());
scoped_mpbqi new_den_i(bqim());
mpbq tiny_value(1, _prec*2);
if (numerator.size() > 1)
add_infinitesimal(num_i, sign_of_first_non_zero(numerator, 1) > 0, tiny_value, new_num_i);
else
bqim().set(new_num_i, num_i);
if (denominator.size() > 1)
add_infinitesimal(den_i, sign_of_first_non_zero(denominator, 1) > 0, tiny_value, new_den_i);
else
bqim().set(new_den_i, den_i);
div(new_num_i, new_den_i, inc_precision(prec, 2), v->interval());
}
if (check_precision(v->interval(), prec))
return true;
_prec++;
}
}
else {
// The following condition must hold because gcd(numerator, denominator) == 1
// If num_idx > 0 and den_idx > 0, eps^{min(num_idx, den_idx)} is a factor of gcd(numerator, denominator)
SASSERT(num_idx == 0 || den_idx == 0);
int s = sign(numerator[num_idx]) * sign(denominator[den_idx]);
// The following must hold since numerator[num_idx] and denominator[den_idx] are not zero.
SASSERT(s != 0);
if (num_idx == 0) {
SASSERT(den_idx > 0);
// |v| is bigger than any binary rational
// Interval can't be refined. There is no way to isolate an infinity with an interval with binary rational end points.
return false;
}
else {
SASSERT(num_idx > 0);
SASSERT(den_idx == 0);
// |v| is infinitely close to zero.
if (s == 1) {
// it is close from above
set_lower(v->interval(), mpbq(0));
set_upper(v->interval(), mpbq(1, prec));
}
else {
// it is close from below
set_lower(v->interval(), mpbq(-1, prec));
set_upper(v->interval(), mpbq(0));
}
return true;
}
}
}
bool refine_algebraic_interval(rational_function_value * v, unsigned prec) {
// TODO
return false;
}
/**
\brief Refine the interval of v to the desired precision (1/2^k).
Return false in case of failure. A failure can only happen if v depends on infinitesimal values.
*/
bool refine_interval(value * v, unsigned prec) {
checkpoint();
SASSERT(!is_zero(v));
int m = magnitude(interval(v));
if (m == INT_MIN || (m < 0 && static_cast<unsigned>(-m) > prec))
return true;
save_interval_if_too_small(v);
if (is_nz_rational(v)) {
refine_rational_interval(to_nz_rational(v), prec);
return true;
}
else {
rational_function_value * rf = to_rational_function(v);
if (rf->ext()->is_transcendental()) {
refine_transcendental_interval(rf, prec);
return true;
}
else if (rf->ext()->is_infinitesimal())
return refine_infinitesimal_interval(rf, prec);
else
return refine_algebraic_interval(rf, prec);
}
}
/**
\brief Return the position of the first non-zero coefficient of p.
*/
static unsigned first_non_zero(polynomial const & p) {
unsigned sz = p.size();
for (unsigned i = 0; i < sz; i++) {
if (p[i] != 0)
return i;
}
UNREACHABLE();
return UINT_MAX;
}
/**
\brief Return the sign of the first non zero coefficient starting at position start_idx
*/
int sign_of_first_non_zero(polynomial const & p, unsigned start_idx) {
unsigned sz = p.size();
SASSERT(start_idx < sz);
for (unsigned i = start_idx; i < sz; i++) {
if (p[i] != 0)
return sign(p[i]);
}
UNREACHABLE();
return 0;
}
/**
out <- in + infinitesimal (if plus_eps == true)
out <- in - infinitesimal (if plus_eps == false)
We use the following rules for performing the assignment
If plus_eps == True
If lower(in) == v (closed or open), then lower(out) == v and open
If upper(in) == v and open, then upper(out) == v and open
If upper(in) == v and closed, then upper(out) == new_v and open
where new_v is v + tiny_value / 2^k, where k is the smallest natural such that sign(new_v) == sign(v)
If plus_eps == False
If lower(in) == v and open, then lower(out) == v and open
If lower(in) == v and closed, then lower(out) == new_v and open
If upper(in) == v (closed or open), then upper(out) == v and open
where new_v is v - tiny_value / 2^k, where k is the smallest natural such that sign(new_v) == sign(v)
*/
void add_infinitesimal(mpbqi const & in, bool plus_eps, mpbq const & tiny_value, mpbqi & out) {
set_interval(out, in);
out.set_lower_is_open(true);
out.set_upper_is_open(true);
if (plus_eps) {
if (!in.upper_is_open()) {
scoped_mpbq tval(bqm());
tval = tiny_value;
while (true) {
bqm().add(in.upper(), tval, out.upper());
if (bqm().is_pos(in.upper()) == bqm().is_pos(out.upper()))
return;
bqm().div2(tval);
checkpoint();
}
}
}
else {
if (!in.lower_is_open()) {
scoped_mpbq tval(bqm());
tval = tiny_value;
while (true) {
bqm().sub(in.lower(), tval, out.lower());
if (bqm().is_pos(in.lower()) == bqm().is_pos(out.lower()))
return;
bqm().div2(tval);
checkpoint();
}
}
}
}
/**
\brief Determine the sign of an element of Q(trans_0, ..., trans_n)
*/
void determine_transcendental_sign(rational_function_value * v) {
// Remark: the sign of a rational function value on an transcendental is never zero.
// Reason: The transcendental can be the root of a polynomial.
SASSERT(v->ext()->is_transcendental());
int m = magnitude(v->interval());
unsigned prec = 1;
if (m < 0)
prec = static_cast<unsigned>(-m) + 1;
while (contains_zero(v->interval())) {
refine_transcendental_interval(v, prec);
prec++;
}
}
/**
\brief Determine the sign of an element of Q(trans_0, ..., trans_n, eps_0, ..., eps_m)
*/
void determine_infinitesimal_sign(rational_function_value * v) {
// Remark: the sign of a rational function value on an infinitesimal is never zero.
// Reason: An infinitesimal eps is transcendental in any field K. So, it can't be the root
// of a polynomial.
SASSERT(v->ext()->is_infinitesimal());
polynomial const & numerator = v->num();
polynomial const & denominator = v->den();
unsigned num_idx = first_non_zero(numerator);
unsigned den_idx = first_non_zero(denominator);
if (num_idx == 0 && den_idx == 0) {
mpbqi const & num_i = interval(numerator[num_idx]);
mpbqi const & den_i = interval(denominator[num_idx]);
SASSERT(!contains_zero(num_i));
SASSERT(!contains_zero(den_i));
if (is_open_interval(num_i) && is_open_interval(den_i)) {
// This case is simple because adding/subtracting infinitesimal quantities, will
// not change the interval.
div(num_i, den_i, m_ini_precision, v->interval());
}
else {
// The intervals num_i and den_i may not be open.
// Example: numerator[num_idx] or denominator[num_idx] are rationals
// that can be precisely represented as binary rationals.
scoped_mpbqi new_num_i(bqim());
scoped_mpbqi new_den_i(bqim());
mpbq tiny_value(1, m_ini_precision); // 1/2^{m_ini_precision}
if (numerator.size() > 1)
add_infinitesimal(num_i, sign_of_first_non_zero(numerator, 1) > 0, tiny_value, new_num_i);
else
bqim().set(new_num_i, num_i);
if (denominator.size() > 1)
add_infinitesimal(den_i, sign_of_first_non_zero(denominator, 1) > 0, tiny_value, new_den_i);
else
bqim().set(new_den_i, den_i);
div(new_num_i, new_den_i, m_ini_precision, v->interval());
}
}
else {
// The following condition must hold because gcd(numerator, denominator) == 1
// If num_idx > 0 and den_idx > 0, eps^{min(num_idx, den_idx)} is a factor of gcd(numerator, denominator)
SASSERT(num_idx == 0 || den_idx == 0);
int s = sign(numerator[num_idx]) * sign(denominator[den_idx]);
// The following must hold since numerator[num_idx] and denominator[den_idx] are not zero.
SASSERT(s != 0);
if (num_idx == 0) {
SASSERT(den_idx > 0);
// |v| is bigger than any binary rational
if (s == 1) {
// it is "oo"
set_lower(v->interval(), m_plus_inf_approx);
set_upper_inf(v->interval());
}
else {
// it is "-oo"
set_lower_inf(v->interval());
set_upper(v->interval(), m_minus_inf_approx);
}
}
else {
SASSERT(num_idx > 0);
SASSERT(den_idx == 0);
// |v| is infinitely close to zero.
if (s == 1) {
// it is close from above
set_lower(v->interval(), mpbq(0));
set_upper(v->interval(), mpbq(1, m_ini_precision));
}
else {
// it is close from below
set_lower(v->interval(), mpbq(-1, m_ini_precision));
set_upper(v->interval(), mpbq(0));
}
}
}
SASSERT(!contains_zero(v->interval()));
}
bool determine_algebraic_sign(rational_function_value * v) {
// TODO
return false;
}
/** /**
\brief Determine the sign of the new rational function value. \brief Determine the sign of the new rational function value.
The idea is to keep refinining the interval until interval of v does not contain 0. The idea is to keep refinining the interval until interval of v does not contain 0.
@ -1538,8 +2034,16 @@ namespace realclosure {
Return false if v is actually zero. Return false if v is actually zero.
*/ */
bool determine_sign(rational_function_value * v) { bool determine_sign(rational_function_value * v) {
// TODO if (!contains_zero(v->interval()))
return true; return true;
switch (v->ext()->knd()) {
case extension::TRANSCENDENTAL: determine_transcendental_sign(v); return true; // it is never zero
case extension::INFINITESIMAL: determine_infinitesimal_sign(v); return true; // it is never zero
case extension::ALGEBRAIC: return determine_algebraic_sign(v);
default:
UNREACHABLE();
return false;
}
} }
/** /**
@ -1932,7 +2436,7 @@ namespace realclosure {
polynomial const & ad = a->den(); polynomial const & ad = a->den();
rational_function_value * r = mk_rational_function_value_core(a->ext(), ad.size(), ad.c_ptr(), an.size(), an.c_ptr()); rational_function_value * r = mk_rational_function_value_core(a->ext(), ad.size(), ad.c_ptr(), an.size(), an.c_ptr());
bqim().inv(interval(a), r->interval()); bqim().inv(interval(a), r->interval());
SASSERT(!bqim().contains_zero(r->interval())); SASSERT(!contains_zero(r->interval()));
return r; return r;
} }
@ -2190,7 +2694,7 @@ namespace realclosure {
SASSERT(!is_zero(a)); SASSERT(!is_zero(a));
SASSERT(!is_nz_rational(a)); SASSERT(!is_nz_rational(a));
mpbqi const & i = interval(a.m_value); mpbqi const & i = interval(a.m_value);
if (check_precision(i, precision*4)) { if (refine_interval(a.m_value, precision*4)) {
// hack // hack
if (bqm().is_int(i.lower())) if (bqm().is_int(i.lower()))
bqm().display_decimal(out, i.upper(), precision); bqm().display_decimal(out, i.upper(), precision);
@ -2198,7 +2702,10 @@ namespace realclosure {
bqm().display_decimal(out, i.lower(), precision); bqm().display_decimal(out, i.lower(), precision);
} }
else { else {
out << "?"; if (sign(a.m_value) > 0)
out << "?";
else
out << "-?";
} }
} }
@ -2473,3 +2980,22 @@ void pp(realclosure::manager::imp * imp, realclosure::manager::imp::value_ref_bu
pp(imp, p[i]); pp(imp, p[i]);
} }
void pp(realclosure::manager::imp * imp, realclosure::mpbqi const & i) {
imp->bqim().display(std::cout, i);
std::cout << std::endl;
}
void pp(realclosure::manager::imp * imp, realclosure::manager::imp::scoped_mpqi const & i) {
imp->qim().display(std::cout, i);
std::cout << std::endl;
}
void pp(realclosure::manager::imp * imp, mpbq const & n) {
imp->bqm().display(std::cout, n);
std::cout << std::endl;
}
void pp(realclosure::manager::imp * imp, mpq const & n) {
imp->qm().display(std::cout, n);
std::cout << std::endl;
}

View file

@ -55,13 +55,15 @@ static void tst1() {
scoped_rcnumeral pi(m); scoped_rcnumeral pi(m);
m.mk_pi(pi); m.mk_pi(pi);
std::cout << pi + 1 << std::endl; std::cout << pi + 1 << std::endl;
std::cout << decimal_pp(pi + 1, 1) << std::endl; std::cout << decimal_pp(pi) << std::endl;
std::cout << decimal_pp(pi + 1) << std::endl;
scoped_rcnumeral e(m); scoped_rcnumeral e(m);
m.mk_e(e); m.mk_e(e);
t = e + (pi + 1)*2; t = e + (pi + 1)*2;
std::cout << t << std::endl; std::cout << t << std::endl;
std::cout << decimal_pp(t, 1) << std::endl; std::cout << decimal_pp(t, 10) << std::endl;
std::cout << (eps + 1 > 1) << std::endl;
std::cout << interval_pp((a + eps)/(a - eps)) << std::endl;
} }
void tst_rcf() { void tst_rcf() {