The sixth input from #8159 revealed a subtle issue in our rewriting of arithmetic atoms. As real and integer atoms are rewritten differently, we check this and then call different functions. However, we check this on the original input, although this property can change during rewriting, e.g., when the only real variable vanishes.
This PR fixes this issue.
RewriteResponse ArithRewriter::postRewriteAtom(TNode atom)
{
Assert(rewriter::isAtom(atom));
+ Trace("arith-rewriter") << "postRewriteAtom: " << atom << std::endl;
if (atom.getKind() == kind::IS_INTEGER)
{
rewriter::addToSum(sum, left, negate);
rewriter::addToSum(sum, right, !negate);
- // Now we have (rsum <kind> 0)
- if (rewriter::isIntegral(atom))
+ // Now we have (sum <kind> 0)
+ if (rewriter::isIntegral(sum))
{
if (kind == Kind::EQUAL)
{
}
}
+bool isIntegral(const Sum& sum)
+{
+ std::vector<TNode> queue;
+ for (const auto& s: sum)
+ {
+ queue.emplace_back(s.first);
+ }
+ while (!queue.empty())
+ {
+ TNode cur = queue.back();
+ queue.pop_back();
+
+ if (cur.isConst()) continue;
+ switch (cur.getKind())
+ {
+ case Kind::ADD:
+ case Kind::NEG:
+ case Kind::SUB:
+ case Kind::MULT:
+ case Kind::NONLINEAR_MULT:
+ queue.insert(queue.end(), cur.begin(), cur.end());
+ break;
+ default:
+ if (!cur.getType().isInteger()) return false;
+ }
+ }
+ return true;
+}
+
void addToSum(Sum& sum, TNode n, bool negate)
{
if (n.getKind() == Kind::ADD)
*/
std::ostream& operator<<(std::ostream& os, const Sum& sum);
+/**
+ * Check whether the given sum can be rewritten as an integer expression. This
+ * differs from checking the node type in a major way: rational
+ * constants are always integral, as they are rewritten to integers by simple
+ * multiplication with their denominator.
+ */
+bool isIntegral(const Sum& sum);
+
/**
* Add the arithmetic term `n` to the given sum. If negate is true, actually add
* `-n`. If `n` is itself a sum, it automatically flattens it into `sum` (though
namespace arith {
namespace rewriter {
-bool isIntegral(TNode n)
-{
- std::vector<TNode> queue = {n};
- while (!queue.empty())
- {
- TNode cur = queue.back();
- queue.pop_back();
-
- if (cur.isConst()) continue;
- switch (cur.getKind())
- {
- case Kind::LT:
- case Kind::LEQ:
- case Kind::EQUAL:
- case Kind::DISTINCT:
- case Kind::GEQ:
- case Kind::GT:
- queue.emplace_back(n[0]);
- queue.emplace_back(n[1]);
- break;
- case Kind::ADD:
- case Kind::NEG:
- case Kind::SUB:
- case Kind::MULT:
- queue.insert(queue.end(), cur.begin(), cur.end());
- break;
- default:
- if (!cur.getType().isInteger()) return false;
- }
- }
- return true;
-}
-
Node mkMultTerm(const Rational& multiplicity, TNode monomial)
{
if (monomial.isConst())
}
}
-/**
- * Check whether the given node can be rewritten to an integer node. This
- * differs from checking the node type in two major ways: we consider relational
- * operators integral if both children are integral in this sense; rational
- * constants are always integral, as they are rewritten to integers by simple
- * multiplication with their denominator.
- */
-bool isIntegral(TNode n);
-
/** Check whether the node wraps a real algebraic number. */
inline bool isRAN(TNode n)
{
Node buildIntegerEquality(Sum&& sum)
{
+ Trace("arith-rewriter") << "building integer inequality from " << sum << std::endl;
normalizeGCDLCM(sum);
const auto& constant = *sum.begin();
Node buildRealEquality(Sum&& sum)
{
+ Trace("arith-rewriter") << "building real equality from " << sum << std::endl;
auto lterm = removeLTerm(sum);
if (isZero(lterm.second))
{
Node buildIntegerInequality(Sum&& sum, Kind k)
{
+ Trace("arith-rewriter") << "building integer equality from " << sum << std::endl;
bool negate = normalizeGCDLCM(sum, true);
if (negate)
Node buildRealInequality(Sum&& sum, Kind k)
{
+ Trace("arith-rewriter") << "building real inequality from " << sum << std::endl;
normalizeLCoeffAbsOne(sum);
Node rhs = mkConst(-removeConstant(sum));
return buildRelation(k, collectSum(sum), rhs);
regress0/arith/issue5219-conflict-rewrite.smt2
regress0/arith/issue5761-ppr.smt2
regress0/arith/issue8097-iid.smt2
+ regress0/arith/issue8159-rewrite-intreal.smt2
regress0/arith/ite-lift.smt2
regress0/arith/leq.01.smtv1.smt2
regress0/arith/miplib.cvc.smt2
--- /dev/null
+; EXPECT: sat
+(set-logic QF_LIRA)
+(declare-fun a () Real)
+(declare-fun b () Int)
+(assert (>= a (+ a b)))
+(check-sat)