Skip to content

Commit 39edf73

Browse files
fix #2613 fix #2612
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent 016732a commit 39edf73

16 files changed

+219
-159
lines changed

src/ast/arith_decl_plugin.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,3 +779,20 @@ expr_ref arith_util::mk_add_simplify(unsigned sz, expr* const* args) {
779779
}
780780
return result;
781781
}
782+
783+
bool arith_util::is_considered_uninterpreted(func_decl* f, unsigned n, expr* const* args) {
784+
rational r;
785+
if (is_decl_of(f, m_afid, OP_DIV) && is_numeral(args[1], r) && r.is_zero()) {
786+
return true;
787+
}
788+
if (is_decl_of(f, m_afid, OP_IDIV) && is_numeral(args[1], r) && r.is_zero()) {
789+
return true;
790+
}
791+
if (is_decl_of(f, m_afid, OP_MOD) && is_numeral(args[1], r) && r.is_zero()) {
792+
return true;
793+
}
794+
if (is_decl_of(f, m_afid, OP_REM) && is_numeral(args[1], r) && r.is_zero()) {
795+
return true;
796+
}
797+
return plugin().is_considered_uninterpreted(f);
798+
}

src/ast/arith_decl_plugin.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,9 @@ class arith_util : public arith_recognizers {
442442

443443
expr_ref mk_add_simplify(expr_ref_vector const& args);
444444
expr_ref mk_add_simplify(unsigned sz, expr* const* args);
445+
446+
bool is_considered_uninterpreted(func_decl* f, unsigned n, expr* const* args);
447+
445448
};
446449

447450

src/math/polynomial/algebraic_numbers.cpp

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ namespace algebraic_numbers {
257257

258258
SASSERT(bqm().ge(upper(c), candidate));
259259

260-
if (bqm().lt(lower(c), candidate) && upm().eval_sign_at(c->m_p_sz, c->m_p, candidate) == 0) {
260+
if (bqm().lt(lower(c), candidate) && upm().eval_sign_at(c->m_p_sz, c->m_p, candidate) == polynomial::sign_zero) {
261261
m_wrapper.set(a, candidate);
262262
return true;
263263
}
@@ -320,7 +320,7 @@ namespace algebraic_numbers {
320320
SASSERT(bqm().ge(upper(c), candidate));
321321

322322
// Find if candidate is an actual root
323-
if (bqm().lt(lower(c), candidate) && upm().eval_sign_at(c->m_p_sz, c->m_p, candidate) == 0) {
323+
if (bqm().lt(lower(c), candidate) && upm().eval_sign_at(c->m_p_sz, c->m_p, candidate) == polynomial::sign_zero) {
324324
saved_a.restore_if_too_small();
325325
set(a, candidate);
326326
return true;
@@ -379,11 +379,11 @@ namespace algebraic_numbers {
379379
}
380380

381381
void update_sign_lower(algebraic_cell * c) {
382-
int sl = upm().eval_sign_at(c->m_p_sz, c->m_p, lower(c));
382+
polynomial::sign sl = upm().eval_sign_at(c->m_p_sz, c->m_p, lower(c));
383383
// The isolating intervals are refinable. Thus, the polynomial has opposite signs at lower and upper.
384-
SASSERT(sl != 0);
384+
SASSERT(sl != polynomial::sign_zero);
385385
SASSERT(upm().eval_sign_at(c->m_p_sz, c->m_p, upper(c)) == -sl);
386-
c->m_sign_lower = sl < 0;
386+
c->m_sign_lower = sl == polynomial::sign_neg;
387387
}
388388

389389
// Make sure the GCD of the coefficients is one and the leading coefficient is positive
@@ -1594,8 +1594,8 @@ namespace algebraic_numbers {
15941594
#define REFINE_LOOP(BOUND, TARGET_SIGN) \
15951595
while (true) { \
15961596
bqm().div2(BOUND); \
1597-
int new_sign = upm().eval_sign_at(cell_a->m_p_sz, cell_a->m_p, BOUND); \
1598-
if (new_sign == 0) { \
1597+
polynomial::sign new_sign = upm().eval_sign_at(cell_a->m_p_sz, cell_a->m_p, BOUND); \
1598+
if (new_sign == polynomial::sign_zero) { \
15991599
/* found actual root */ \
16001600
scoped_mpq r(qm()); \
16011601
to_mpq(qm(), BOUND, r); \
@@ -1695,8 +1695,8 @@ namespace algebraic_numbers {
16951695
if (bqm().ge(l, b))
16961696
return 1;
16971697
// b is in the isolating interval (l, u)
1698-
int sign_b = upm().eval_sign_at(c->m_p_sz, c->m_p, b);
1699-
if (sign_b == 0)
1698+
auto sign_b = upm().eval_sign_at(c->m_p_sz, c->m_p, b);
1699+
if (sign_b == polynomial::sign_zero)
17001700
return 0;
17011701
return sign_b == sign_lower(c) ? 1 : -1;
17021702
}
@@ -1979,7 +1979,7 @@ namespace algebraic_numbers {
19791979
};
19801980

19811981
polynomial::var_vector m_eval_sign_vars;
1982-
int eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v) {
1982+
polynomial::sign eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v) {
19831983
polynomial::manager & ext_pm = p.m();
19841984
TRACE("anum_eval_sign", tout << "evaluating sign of: " << p << "\n";);
19851985
while (true) {
@@ -1990,7 +1990,7 @@ namespace algebraic_numbers {
19901990
scoped_mpq r(qm());
19911991
ext_pm.eval(p, x2v_basic, r);
19921992
TRACE("anum_eval_sign", tout << "all variables are assigned to rationals, value of p: " << r << "\n";);
1993-
return qm().sign(r);
1993+
return polynomial::to_sign(qm().sign(r));
19941994
}
19951995
catch (const opt_var2basic::failed &) {
19961996
// continue
@@ -2004,13 +2004,13 @@ namespace algebraic_numbers {
20042004

20052005
if (ext_pm.is_zero(p_prime)) {
20062006
// polynomial vanished after substituting rational values.
2007-
return 0;
2007+
return polynomial::sign_zero;
20082008
}
20092009

20102010
if (is_const(p_prime)) {
20112011
// polynomial became the constant polynomial after substitution.
20122012
SASSERT(size(p_prime) == 1);
2013-
return ext_pm.m().sign(ext_pm.coeff(p_prime, 0));
2013+
return polynomial::to_sign(ext_pm.m().sign(ext_pm.coeff(p_prime, 0)));
20142014
}
20152015

20162016
// Try to find sign using intervals
@@ -2026,7 +2026,7 @@ namespace algebraic_numbers {
20262026
ext_pm.eval(p_prime, x2v_interval, ri);
20272027
TRACE("anum_eval_sign", tout << "evaluating using intervals: " << ri << "\n";);
20282028
if (!bqim().contains_zero(ri)) {
2029-
return bqim().is_pos(ri) ? 1 : -1;
2029+
return bqim().is_pos(ri) ? polynomial::sign_pos : polynomial::sign_neg;
20302030
}
20312031
// refine intervals if magnitude > m_min_magnitude
20322032
bool refined = false;
@@ -2067,7 +2067,7 @@ namespace algebraic_numbers {
20672067
// Remark: m_zero_accuracy == 0 means use precise computation.
20682068
if (m_zero_accuracy > 0) {
20692069
// assuming the value is 0, since the result is in (-1/2^k, 1/2^k), where m_zero_accuracy = k
2070-
return 0;
2070+
return polynomial::sign_zero;
20712071
}
20722072
#if 0
20732073
// Evaluating sign using algebraic arithmetic
@@ -2143,7 +2143,7 @@ namespace algebraic_numbers {
21432143
bqm().div2k(mL, k);
21442144
bqm().div2k(L, k);
21452145
if (bqm().lt(mL, ri.lower()) && bqm().lt(ri.upper(), L))
2146-
return 0;
2146+
return polynomial::sign_zero;
21472147
// keep refining ri until ri is inside (-L, L) or
21482148
// ri does not contain zero.
21492149

@@ -2166,14 +2166,13 @@ namespace algebraic_numbers {
21662166
TRACE("anum_eval_sign", tout << "evaluating using intervals: " << ri << "\n";
21672167
tout << "zero lower bound is: " << L << "\n";);
21682168
if (!bqim().contains_zero(ri)) {
2169-
return bqim().is_pos(ri) ? 1 : -1;
2169+
return bqim().is_pos(ri) ? polynomial::sign_pos : polynomial::sign_neg;
21702170
}
21712171

21722172
if (bqm().lt(mL, ri.lower()) && bqm().lt(ri.upper(), L))
2173-
return 0;
2173+
return polynomial::sign_zero;
21742174

2175-
for (unsigned i = 0; i < xs.size(); i++) {
2176-
polynomial::var x = xs[i];
2175+
for (auto x : xs) {
21772176
SASSERT(x2v.contains(x));
21782177
anum const & v = x2v(x);
21792178
SASSERT(!v.is_basic());
@@ -2242,18 +2241,14 @@ namespace algebraic_numbers {
22422241

22432242
unsigned sz = roots.size();
22442243
unsigned j = 0;
2245-
// std::cout << "p: " << p << "\n";
2246-
// std::cout << "sz: " << sz << "\n";
22472244
for (unsigned i = 0; i < sz; i++) {
22482245
checkpoint();
2249-
// display_root(std::cout, roots[i]); std::cout << std::endl;
22502246
ext_var2num ext_x2v(m_wrapper, x2v, x, roots[i]);
22512247
TRACE("isolate_roots", tout << "filter_roots i: " << i << ", ext_x2v: x" << x << " -> "; display_root(tout, roots[i]); tout << "\n";);
2252-
int sign = eval_sign_at(p, ext_x2v);
2248+
polynomial::sign sign = eval_sign_at(p, ext_x2v);
22532249
TRACE("isolate_roots", tout << "filter_roots i: " << i << ", result sign: " << sign << "\n";);
22542250
if (sign != 0)
22552251
continue;
2256-
// display_decimal(std::cout, roots[i], 10); std::cout << " is root" << std::endl;
22572252
if (i != j)
22582253
set(roots[j], roots[i]);
22592254
j++;
@@ -2453,7 +2448,7 @@ namespace algebraic_numbers {
24532448
}
24542449
}
24552450

2456-
int eval_at_mpbq(polynomial_ref const & p, polynomial::var2anum const & x2v, polynomial::var x, mpbq const & v) {
2451+
polynomial::sign eval_at_mpbq(polynomial_ref const & p, polynomial::var2anum const & x2v, polynomial::var x, mpbq const & v) {
24572452
scoped_mpq qv(qm());
24582453
to_mpq(qm(), v, qv);
24592454
scoped_anum av(m_wrapper);
@@ -2568,13 +2563,13 @@ namespace algebraic_numbers {
25682563

25692564
#define DEFAULT_PRECISION 2
25702565

2571-
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<int> & signs) {
2566+
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<polynomial::sign> & signs) {
25722567
isolate_roots(p, x2v, roots);
25732568
unsigned num_roots = roots.size();
25742569
if (num_roots == 0) {
25752570
anum zero;
25762571
ext2_var2num ext_x2v(m_wrapper, x2v, zero);
2577-
int s = eval_sign_at(p, ext_x2v);
2572+
polynomial::sign s = eval_sign_at(p, ext_x2v);
25782573
signs.push_back(s);
25792574
}
25802575
else {
@@ -2601,8 +2596,8 @@ namespace algebraic_numbers {
26012596
TRACE("isolate_roots_bug", tout << "w: "; display_root(tout, w); tout << "\n";);
26022597
{
26032598
ext2_var2num ext_x2v(m_wrapper, x2v, w);
2604-
int s = eval_sign_at(p, ext_x2v);
2605-
SASSERT(s != 0);
2599+
auto s = eval_sign_at(p, ext_x2v);
2600+
SASSERT(s != polynomial::sign_zero);
26062601
signs.push_back(s);
26072602
}
26082603

@@ -2611,16 +2606,16 @@ namespace algebraic_numbers {
26112606
numeral & curr = roots[i];
26122607
select(prev, curr, w);
26132608
ext2_var2num ext_x2v(m_wrapper, x2v, w);
2614-
int s = eval_sign_at(p, ext_x2v);
2615-
SASSERT(s != 0);
2609+
auto s = eval_sign_at(p, ext_x2v);
2610+
SASSERT(s != polynomial::sign_zero);
26162611
signs.push_back(s);
26172612
}
26182613

26192614
int_gt(roots[num_roots - 1], w);
26202615
{
26212616
ext2_var2num ext_x2v(m_wrapper, x2v, w);
2622-
int s = eval_sign_at(p, ext_x2v);
2623-
SASSERT(s != 0);
2617+
auto s = eval_sign_at(p, ext_x2v);
2618+
SASSERT(s != polynomial::sign_zero);
26242619
signs.push_back(s);
26252620
}
26262621
}
@@ -2879,7 +2874,7 @@ namespace algebraic_numbers {
28792874
m_imp->isolate_roots(p, x2v, roots);
28802875
}
28812876

2882-
void manager::isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<int> & signs) {
2877+
void manager::isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<polynomial::sign> & signs) {
28832878
m_imp->isolate_roots(p, x2v, roots, signs);
28842879
}
28852880

@@ -3037,7 +3032,7 @@ namespace algebraic_numbers {
30373032
l = rational(_l);
30383033
}
30393034

3040-
int manager::eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v) {
3035+
polynomial::sign manager::eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v) {
30413036
SASSERT(&(x2v.m()) == this);
30423037
return m_imp->eval_sign_at(p, x2v);
30433038
}

src/math/polynomial/algebraic_numbers.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ namespace algebraic_numbers {
173173
/**
174174
\brief Isolate the roots of the given polynomial, and compute its sign between them.
175175
*/
176-
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<int> & signs);
176+
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<polynomial::sign> & signs);
177177

178178
/**
179179
\brief Store in r the i-th root of p.
@@ -304,7 +304,7 @@ namespace algebraic_numbers {
304304
Return 0 if p(alpha_1, ..., alpha_n) == 0
305305
Return positive number if p(alpha_1, ..., alpha_n) > 0
306306
*/
307-
int eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v);
307+
polynomial::sign eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v);
308308

309309
void get_polynomial(numeral const & a, svector<mpz> & r);
310310

src/math/polynomial/polynomial.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,12 +1068,12 @@ namespace polynomial {
10681068
g.reserve(std::min(sz1, sz2));
10691069
r1.reserve(sz2); // r1 has at most num_args2 arguments
10701070
r2.reserve(sz1); // r2 has at most num_args1 arguments
1071-
bool found = false;
1072-
unsigned i1 = 0;
1073-
unsigned i2 = 0;
1074-
unsigned j1 = 0;
1075-
unsigned j2 = 0;
1076-
unsigned j3 = 0;
1071+
bool found = false;
1072+
unsigned i1 = 0;
1073+
unsigned i2 = 0;
1074+
unsigned j1 = 0;
1075+
unsigned j2 = 0;
1076+
unsigned j3 = 0;
10771077
while (true) {
10781078
if (i1 == sz1) {
10791079
if (found) {
@@ -2501,6 +2501,32 @@ namespace polynomial {
25012501
return p;
25022502
}
25032503

2504+
void gcd_simplify(polynomial * p) {
2505+
if (m_manager.finite()) return;
2506+
auto& m = m_manager.m();
2507+
unsigned sz = p->size();
2508+
if (sz == 0)
2509+
return;
2510+
unsigned g = 0;
2511+
for (unsigned i = 0; i < sz; i++) {
2512+
if (!m.is_int(p->a(i))) {
2513+
return;
2514+
}
2515+
int j = m.get_int(p->a(i));
2516+
if (j == INT_MIN || j == 1 || j == -1)
2517+
return;
2518+
g = u_gcd(abs(j), g);
2519+
if (g == 1)
2520+
return;
2521+
}
2522+
scoped_mpz r(m), gg(m);
2523+
m.set(gg, g);
2524+
for (unsigned i = 0; i < sz; ++i) {
2525+
m.div_gcd(p->a(i), gg, r);
2526+
m.set(p->a(i), r);
2527+
}
2528+
}
2529+
25042530
polynomial * mk_zero() {
25052531
return m_zero;
25062532
}
@@ -7041,6 +7067,10 @@ namespace polynomial {
70417067
return m_imp->hash(p);
70427068
}
70437069

7070+
void manager::gcd_simplify(polynomial * p) {
7071+
m_imp->gcd_simplify(p);
7072+
}
7073+
70447074
polynomial * manager::coeff(polynomial const * p, var x, unsigned k) {
70457075
return m_imp->coeff(p, x, k);
70467076
}

src/math/polynomial/polynomial.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ namespace polynomial {
4444
typedef svector<var> var_vector;
4545
class monomial;
4646

47+
typedef enum { sign_neg = -1, sign_zero = 0, sign_pos = 1} sign;
48+
inline sign operator-(sign s) { switch (s) { case sign_neg: return sign_pos; case sign_pos: return sign_neg; default: return sign_zero; } };
49+
inline sign to_sign(int s) { return s == 0 ? sign_zero : (s > 0 ? sign_pos : sign_neg); }
50+
inline sign operator*(sign a, sign b) { return to_sign((int)a * (int)b); }
51+
4752
int lex_compare(monomial const * m1, monomial const * m2);
4853
int lex_compare2(monomial const * m1, monomial const * m2, var min_var);
4954
int graded_lex_compare(monomial const * m1, monomial const * m2);
@@ -278,6 +283,12 @@ namespace polynomial {
278283
*/
279284
static unsigned id(polynomial const * p);
280285

286+
287+
/**
288+
\brief Normalize coefficients by dividing by their gcd
289+
*/
290+
void gcd_simplify(polynomial* p);
291+
281292
/**
282293
\brief Return true if \c m is the unit monomial.
283294
*/

src/math/polynomial/polynomial_cache.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ namespace polynomial {
139139
polynomial * mk_unique(polynomial * p) {
140140
if (m_in_cache.get(pid(p), false))
141141
return p;
142+
// m.gcd_simplify(p);
142143
polynomial * p_prime = m_poly_table.insert_if_not_there(p);
143144
if (p == p_prime) {
144145
m_cached_polys.push_back(p_prime);

0 commit comments

Comments
 (0)