}
}
- if (tot_len == nm->mkConst(Rational(1)))
+ // (str.substr s x y) --> "" if x < len(s) |= 0 >= y
+ Node n1_lt_tot_len =
+ Rewriter::rewrite(nm->mkNode(kind::LT, node[1], tot_len));
+ if (checkEntailArithWithAssumption(n1_lt_tot_len, zero, node[2], false))
{
- Node n1_eq_zero =
- Rewriter::rewrite(nm->mkNode(kind::EQUAL, node[1], zero));
- if (checkEntailArithWithAssumption(n1_eq_zero, zero, node[2], false))
- {
- Node ret = nm->mkConst(::CVC4::String(""));
- return returnRewrite(node, ret, "ss-len-one-unsat");
- }
+ Node ret = nm->mkConst(::CVC4::String(""));
+ return returnRewrite(node, ret, "ss-start-entails-zero-len");
}
}
if (!curr.isNull())
toVisit.push_back(currChild);
}
}
- else if (curr.getKind() == kind::VARIABLE
- && Theory::theoryOf(curr) == THEORY_ARITH)
+ else if (curr.isVar() && Theory::theoryOf(curr) == THEORY_ARITH)
{
candVars.insert(curr);
}
toVisit.push_back(currChild);
}
- if (curr.getKind() == kind::VARIABLE
- && Theory::theoryOf(curr) == THEORY_ARITH
+ if (curr.isVar() && Theory::theoryOf(curr) == THEORY_ARITH
&& candVars.find(curr) != candVars.end())
{
v = curr;
Node b,
bool strict)
{
- // TODO: Add support for inequality assumptions.
- Assert(assumption.getKind() == kind::EQUAL);
Assert(Rewriter::rewrite(assumption) == assumption);
NodeManager* nm = NodeManager::currentNM();
+ if (!assumption.isConst() && assumption.getKind() != kind::EQUAL)
+ {
+ // We rewrite inequality assumptions from x <= y to x + (str.len s) = y
+ // where s is some fresh string variable. We use (str.len s) because
+ // (str.len s) must be non-negative for the equation to hold.
+ Node x, y;
+ if (assumption.getKind() == kind::GEQ)
+ {
+ x = assumption[0];
+ y = assumption[1];
+ }
+ else
+ {
+ // (not (>= s t)) --> (>= (t - 1) s)
+ Assert(assumption.getKind() == kind::NOT
+ && assumption[0].getKind() == kind::GEQ);
+ x = nm->mkNode(kind::MINUS, assumption[0][1], nm->mkConst(Rational(1)));
+ y = assumption[0][0];
+ }
+
+ Node s = nm->mkBoundVar("s", nm->stringType());
+ Node slen = nm->mkNode(kind::STRING_LENGTH, s);
+ assumption = Rewriter::rewrite(
+ nm->mkNode(kind::EQUAL, x, nm->mkNode(kind::PLUS, y, slen)));
+ }
+
Node diff = nm->mkNode(kind::MINUS, a, b);
- return checkEntailArithWithEqAssumption(assumption, diff, strict);
+ bool res = false;
+ if (assumption.isConst())
+ {
+ bool assumptionBool = assumption.getConst<bool>();
+ if (assumptionBool)
+ {
+ res = checkEntailArith(diff, strict);
+ }
+ else
+ {
+ res = true;
+ }
+ }
+ else
+ {
+ res = checkEntailArithWithEqAssumption(assumption, diff, strict);
+ }
+ return res;
}
bool TheoryStringsRewriter::checkEntailArithWithAssumptions(
bool res = false;
for (const auto& assumption : assumptions)
{
- Assert(assumption.getKind() == kind::EQUAL);
Assert(Rewriter::rewrite(assumption) == assumption);
if (checkEntailArithWithAssumption(assumption, a, b, strict))
Node x_plus_slen_y_eq_zero =
Rewriter::rewrite(d_nm->mkNode(kind::EQUAL, x_plus_slen_y, zero));
- // x + (str.len y) = 0 /\ 0 >= x --> true
+ // x + (str.len y) = 0 |= 0 >= x --> true
TS_ASSERT(TheoryStringsRewriter::checkEntailArithWithAssumption(
x_plus_slen_y_eq_zero, zero, x, false));
- // x + (str.len y) = 0 /\ 0 > x --> false
+ // x + (str.len y) = 0 |= 0 > x --> false
TS_ASSERT(!TheoryStringsRewriter::checkEntailArithWithAssumption(
x_plus_slen_y_eq_zero, zero, x, true));
Node x_plus_slen_y_plus_z_eq_zero = Rewriter::rewrite(d_nm->mkNode(
kind::EQUAL, d_nm->mkNode(kind::PLUS, x_plus_slen_y, z), zero));
- // x + (str.len y) + z = 0 /\ 0 > x --> false
+ // x + (str.len y) + z = 0 |= 0 > x --> false
TS_ASSERT(!TheoryStringsRewriter::checkEntailArithWithAssumption(
x_plus_slen_y_plus_z_eq_zero, zero, x, true));
Node x_plus_slen_y_plus_slen_y_eq_zero = Rewriter::rewrite(d_nm->mkNode(
kind::EQUAL, d_nm->mkNode(kind::PLUS, x_plus_slen_y, slen_y), zero));
- // x + (str.len y) + (str.len y) = 0 /\ 0 >= x --> true
+ // x + (str.len y) + (str.len y) = 0 |= 0 >= x --> true
TS_ASSERT(TheoryStringsRewriter::checkEntailArithWithAssumption(
x_plus_slen_y_plus_slen_y_eq_zero, zero, x, false));
+
+ Node five = d_nm->mkConst(Rational(5));
+ Node six = d_nm->mkConst(Rational(6));
+ Node x_plus_five = d_nm->mkNode(kind::PLUS, x, five);
+ Node x_plus_five_lt_six =
+ Rewriter::rewrite(d_nm->mkNode(kind::LT, x_plus_five, six));
+
+ // x + 5 < 6 |= 0 >= x --> true
+ TS_ASSERT(TheoryStringsRewriter::checkEntailArithWithAssumption(
+ x_plus_five_lt_six, zero, x, false));
+
+ // x + 5 < 6 |= 0 > x --> false
+ TS_ASSERT(!TheoryStringsRewriter::checkEntailArithWithAssumption(
+ x_plus_five_lt_six, zero, x, true));
+
+ Node neg_x = d_nm->mkNode(kind::UMINUS, x);
+ Node x_plus_five_lt_five =
+ Rewriter::rewrite(d_nm->mkNode(kind::LT, x_plus_five, five));
+
+ // x + 5 < 5 |= -x >= 0 --> true
+ TS_ASSERT(TheoryStringsRewriter::checkEntailArithWithAssumption(
+ x_plus_five_lt_five, neg_x, zero, false));
+
+ // x + 5 < 5 |= 0 > x --> true
+ TS_ASSERT(TheoryStringsRewriter::checkEntailArithWithAssumption(
+ x_plus_five_lt_five, zero, x, false));
}
void testRewriteSubstr()
Node empty = d_nm->mkConst(::CVC4::String(""));
Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node abcd = d_nm->mkConst(::CVC4::String("ABCD"));
+ Node two = d_nm->mkConst(Rational(2));
+ Node three = d_nm->mkConst(Rational(3));
+
Node s = d_nm->mkVar("s", strType);
Node x = d_nm->mkVar("x", intType);
Node y = d_nm->mkVar("y", intType);
n = d_nm->mkNode(kind::STRING_SUBSTR, a, x, y);
res = TheoryStringsRewriter::rewriteSubstr(n);
TS_ASSERT_EQUALS(res, n);
+
+ // (str.substr "ABCD" (+ x 3) x) -> ""
+ n = d_nm->mkNode(
+ kind::STRING_SUBSTR, abcd, d_nm->mkNode(kind::PLUS, x, three), x);
+ res = TheoryStringsRewriter::rewriteSubstr(n);
+ TS_ASSERT_EQUALS(res, empty);
+
+ // (str.substr "ABCD" (+ x 2) x) -> (str.substr "ABCD" (+ x 2) x)
+ n = d_nm->mkNode(
+ kind::STRING_SUBSTR, abcd, d_nm->mkNode(kind::PLUS, x, two), x);
+ res = TheoryStringsRewriter::rewriteSubstr(n);
+ TS_ASSERT_EQUALS(res, n);
}
};