mirror of
https://github.com/Z3Prover/z3
synced 2025-08-05 02:40:24 +00:00
parent
9b979b6e1e
commit
4e37821dde
13 changed files with 1632 additions and 1625 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue