diff --git a/src/math/polysat/viable.cpp b/src/math/polysat/viable.cpp index ceefd7841..1b8c2f99c 100644 --- a/src/math/polysat/viable.cpp +++ b/src/math/polysat/viable.cpp @@ -327,10 +327,31 @@ namespace polysat { }; if (lhs > rhs || (e->src.is_negative() && lhs == rhs)) { - rational lo = val - delta_l(val); - rational hi = val + delta_u(val) + 1; + rational lo; + rational hi; + + // TODO: extract into separate function + if (e->src.is_negative() && a2.is_one() && b1.is_zero() && b2.is_zero()) { + // special case: v > -a*v for some numeral a + rational const& a = mod(-a1, mod_value); + if (val.is_zero()) { + lo = 0; + hi = ceil( (mod_value + 1) / (a + 1) ); + } else { + rational const y = mod(-a * val, mod_value); + lo = ceil( val + (y - max_value) / a ); + hi = ceil( (y + a*val + 1) / (a + 1) ); + // can always extend to 0 + if (lo.is_one()) + lo = 0; + } + } else { + // general case + lo = val - delta_l(val); + hi = val + delta_u(val) + 1; + // TODO: increase interval + } - // TODO: increase interval LOG("refine-disequal-lin: " << " [" << lo << ", " << hi << "["); SASSERT(0 <= lo && lo <= val); diff --git a/src/test/polysat.cpp b/src/test/polysat.cpp index b90321358..0d79452d4 100644 --- a/src/test/polysat.cpp +++ b/src/test/polysat.cpp @@ -1097,6 +1097,29 @@ public: s.check(); } + static void test_fi_disequal_mild() { + { + // small version + scoped_solver s(__func__); + auto a = s.var(s.add_var(6)); + auto b = s.var(s.add_var(6)); + // v > -3*v + s.add_eq(a - 3); + s.add_ult(-a*b, b); + s.check(); + } + { + // large version + scoped_solver s(__func__); + auto a = s.var(s.add_var(256)); + auto b = s.var(s.add_var(256)); + // v > -100*v + s.add_eq(a - 100); + s.add_ult(-a*b, b); + s.check(); + } + } + // Goal: we probably mix up polysat variables and PDD variables at several points; try to uncover such cases // NOTE: actually, add_var seems to keep them in sync, so this is not an issue at the moment (but we should still test it later) // static void test_mixed_vars() { @@ -1352,6 +1375,7 @@ void tst_polysat() { test_polysat::test_fi_zero(); test_polysat::test_fi_nonzero(); test_polysat::test_fi_nonmax(); + test_polysat::test_fi_disequal_mild(); return; test_polysat::test_l2();