summaryrefslogtreecommitdiff
path: root/test/unit/theory/sequences_rewriter_white.h
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit/theory/sequences_rewriter_white.h')
-rw-r--r--test/unit/theory/sequences_rewriter_white.h1578
1 files changed, 1578 insertions, 0 deletions
diff --git a/test/unit/theory/sequences_rewriter_white.h b/test/unit/theory/sequences_rewriter_white.h
new file mode 100644
index 000000000..200a36d0b
--- /dev/null
+++ b/test/unit/theory/sequences_rewriter_white.h
@@ -0,0 +1,1578 @@
+/********************* */
+/*! \file sequences_rewriter_white.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andres Noetzli
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Unit tests for the strings/sequences rewriter
+ **
+ ** Unit tests for the strings/sequences rewriter.
+ **/
+
+#include "expr/node.h"
+#include "expr/node_manager.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
+#include "theory/quantifiers/extended_rewrite.h"
+#include "theory/rewriter.h"
+#include "theory/strings/sequences_rewriter.h"
+
+#include <cxxtest/TestSuite.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+
+using namespace CVC4;
+using namespace CVC4::smt;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::strings;
+
+class SequencesRewriterWhite : public CxxTest::TestSuite
+{
+ public:
+ SequencesRewriterWhite() {}
+
+ void setUp() override
+ {
+ Options opts;
+ opts.setOutputLanguage(language::output::LANG_SMTLIB_V2);
+ d_em = new ExprManager(opts);
+ d_smt = new SmtEngine(d_em);
+ d_scope = new SmtScope(d_smt);
+ d_rewriter = new ExtendedRewriter(true);
+
+ d_nm = NodeManager::currentNM();
+ }
+
+ void tearDown() override
+ {
+ delete d_rewriter;
+ delete d_scope;
+ delete d_smt;
+ delete d_em;
+ }
+
+ void inNormalForm(Node t)
+ {
+ Node res_t = d_rewriter->extendedRewrite(t);
+
+ std::cout << std::endl;
+ std::cout << t << " ---> " << res_t << std::endl;
+ TS_ASSERT_EQUALS(t, res_t);
+ }
+
+ void sameNormalForm(Node t1, Node t2)
+ {
+ Node res_t1 = d_rewriter->extendedRewrite(t1);
+ Node res_t2 = d_rewriter->extendedRewrite(t2);
+
+ std::cout << std::endl;
+ std::cout << t1 << " ---> " << res_t1 << std::endl;
+ std::cout << t2 << " ---> " << res_t2 << std::endl;
+ TS_ASSERT_EQUALS(res_t1, res_t2);
+ }
+
+ void differentNormalForms(Node t1, Node t2)
+ {
+ Node res_t1 = d_rewriter->extendedRewrite(t1);
+ Node res_t2 = d_rewriter->extendedRewrite(t2);
+
+ std::cout << std::endl;
+ std::cout << t1 << " ---> " << res_t1 << std::endl;
+ std::cout << t2 << " ---> " << res_t2 << std::endl;
+ TS_ASSERT_DIFFERS(res_t1, res_t2);
+ }
+
+ void testCheckEntailLengthOne()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node abcd = d_nm->mkConst(::CVC4::String("ABCD"));
+ Node aaad = d_nm->mkConst(::CVC4::String("AAAD"));
+ Node b = d_nm->mkConst(::CVC4::String("B"));
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node negOne = d_nm->mkConst(Rational(-1));
+ Node zero = d_nm->mkConst(Rational(0));
+ Node one = d_nm->mkConst(Rational(1));
+ Node two = d_nm->mkConst(Rational(2));
+ Node three = d_nm->mkConst(Rational(3));
+ Node i = d_nm->mkVar("i", intType);
+
+ TS_ASSERT(SequencesRewriter::checkEntailLengthOne(a));
+ TS_ASSERT(SequencesRewriter::checkEntailLengthOne(a, true));
+
+ Node substr = d_nm->mkNode(kind::STRING_SUBSTR, x, zero, one);
+ TS_ASSERT(SequencesRewriter::checkEntailLengthOne(substr));
+ TS_ASSERT(!SequencesRewriter::checkEntailLengthOne(substr, true));
+
+ substr = d_nm->mkNode(kind::STRING_SUBSTR,
+ d_nm->mkNode(kind::STRING_CONCAT, a, x),
+ zero,
+ one);
+ TS_ASSERT(SequencesRewriter::checkEntailLengthOne(substr));
+ TS_ASSERT(SequencesRewriter::checkEntailLengthOne(substr, true));
+
+ substr = d_nm->mkNode(kind::STRING_SUBSTR, x, zero, two);
+ TS_ASSERT(!SequencesRewriter::checkEntailLengthOne(substr));
+ TS_ASSERT(!SequencesRewriter::checkEntailLengthOne(substr, true));
+ }
+
+ void testCheckEntailArith()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node z = d_nm->mkVar("z", strType);
+ Node n = d_nm->mkVar("n", intType);
+ Node one = d_nm->mkConst(Rational(1));
+
+ // 1 >= (str.len (str.substr z n 1)) ---> true
+ Node substr_z = d_nm->mkNode(kind::STRING_LENGTH,
+ d_nm->mkNode(kind::STRING_SUBSTR, z, n, one));
+ TS_ASSERT(SequencesRewriter::checkEntailArith(one, substr_z));
+
+ // (str.len (str.substr z n 1)) >= 1 ---> false
+ TS_ASSERT(!SequencesRewriter::checkEntailArith(substr_z, one));
+ }
+
+ void testCheckEntailArithWithAssumption()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node x = d_nm->mkVar("x", intType);
+ Node y = d_nm->mkVar("y", strType);
+ Node z = d_nm->mkVar("z", intType);
+
+ Node zero = d_nm->mkConst(Rational(0));
+ Node one = d_nm->mkConst(Rational(1));
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+
+ Node slen_y = d_nm->mkNode(kind::STRING_LENGTH, y);
+ Node x_plus_slen_y = d_nm->mkNode(kind::PLUS, x, slen_y);
+ 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
+ TS_ASSERT(SequencesRewriter::checkEntailArithWithAssumption(
+ x_plus_slen_y_eq_zero, zero, x, false));
+
+ // x + (str.len y) = 0 |= 0 > x --> false
+ TS_ASSERT(!SequencesRewriter::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
+ TS_ASSERT(!SequencesRewriter::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
+ TS_ASSERT(SequencesRewriter::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(SequencesRewriter::checkEntailArithWithAssumption(
+ x_plus_five_lt_six, zero, x, false));
+
+ // x + 5 < 6 |= 0 > x --> false
+ TS_ASSERT(!SequencesRewriter::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(SequencesRewriter::checkEntailArithWithAssumption(
+ x_plus_five_lt_five, neg_x, zero, false));
+
+ // x + 5 < 5 |= 0 > x --> true
+ TS_ASSERT(SequencesRewriter::checkEntailArithWithAssumption(
+ x_plus_five_lt_five, zero, x, false));
+
+ // 0 < x |= x >= (str.len (int.to.str x))
+ Node assm = Rewriter::rewrite(d_nm->mkNode(kind::LT, zero, x));
+ TS_ASSERT(SequencesRewriter::checkEntailArithWithAssumption(
+ assm,
+ x,
+ d_nm->mkNode(kind::STRING_LENGTH, d_nm->mkNode(kind::STRING_ITOS, x)),
+ false));
+ }
+
+ void testRewriteSubstr()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node b = d_nm->mkConst(::CVC4::String("B"));
+ Node abcd = d_nm->mkConst(::CVC4::String("ABCD"));
+ Node negone = d_nm->mkConst(Rational(-1));
+ Node zero = d_nm->mkConst(Rational(0));
+ Node one = d_nm->mkConst(Rational(1));
+ Node two = d_nm->mkConst(Rational(2));
+ Node three = d_nm->mkConst(Rational(3));
+
+ Node s = d_nm->mkVar("s", strType);
+ Node s2 = d_nm->mkVar("s2", strType);
+ Node x = d_nm->mkVar("x", intType);
+ Node y = d_nm->mkVar("y", intType);
+
+ // (str.substr "A" x x) --> ""
+ Node n = d_nm->mkNode(kind::STRING_SUBSTR, a, x, x);
+ Node res = SequencesRewriter::rewriteSubstr(n);
+ TS_ASSERT_EQUALS(res, empty);
+
+ // (str.substr "A" (+ x 1) x) -> ""
+ n = d_nm->mkNode(kind::STRING_SUBSTR,
+ a,
+ d_nm->mkNode(kind::PLUS, x, d_nm->mkConst(Rational(1))),
+ x);
+ res = SequencesRewriter::rewriteSubstr(n);
+ TS_ASSERT_EQUALS(res, empty);
+
+ // (str.substr "A" (+ x (str.len s2)) x) -> ""
+ n = d_nm->mkNode(
+ kind::STRING_SUBSTR,
+ a,
+ d_nm->mkNode(kind::PLUS, x, d_nm->mkNode(kind::STRING_LENGTH, s)),
+ x);
+ res = SequencesRewriter::rewriteSubstr(n);
+ TS_ASSERT_EQUALS(res, empty);
+
+ // (str.substr "A" x y) -> (str.substr "A" x y)
+ n = d_nm->mkNode(kind::STRING_SUBSTR, a, x, y);
+ res = SequencesRewriter::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 = SequencesRewriter::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 = SequencesRewriter::rewriteSubstr(n);
+ TS_ASSERT_EQUALS(res, n);
+
+ // (str.substr (str.substr s x x) x x) -> ""
+ n = d_nm->mkNode(
+ kind::STRING_SUBSTR, d_nm->mkNode(kind::STRING_SUBSTR, s, x, x), x, x);
+ sameNormalForm(n, empty);
+
+ // Same normal form for:
+ //
+ // (str.substr (str.replace "" s "B") x x)
+ //
+ // (str.replace "" s (str.substr "B" x x)))
+ Node lhs = d_nm->mkNode(kind::STRING_SUBSTR,
+ d_nm->mkNode(kind::STRING_STRREPL, empty, s, b),
+ x,
+ x);
+ Node rhs = d_nm->mkNode(kind::STRING_STRREPL,
+ empty,
+ s,
+ d_nm->mkNode(kind::STRING_SUBSTR, b, x, x));
+ sameNormalForm(lhs, rhs);
+
+ // Same normal form:
+ //
+ // (str.substr (str.replace s "A" "B") 0 x)
+ //
+ // (str.replace (str.substr s 0 x) "A" "B")
+ Node substr_repl = d_nm->mkNode(kind::STRING_SUBSTR,
+ d_nm->mkNode(kind::STRING_STRREPL, s, a, b),
+ zero,
+ x);
+ Node repl_substr =
+ d_nm->mkNode(kind::STRING_STRREPL,
+ d_nm->mkNode(kind::STRING_SUBSTR, s, zero, x),
+ a,
+ b);
+ sameNormalForm(substr_repl, repl_substr);
+
+ // Same normal form:
+ //
+ // (str.substr (str.replace s (str.substr (str.++ s2 "A") 0 1) "B") 0 x)
+ //
+ // (str.replace (str.substr s 0 x) (str.substr (str.++ s2 "A") 0 1) "B")
+ Node substr_y = d_nm->mkNode(kind::STRING_SUBSTR,
+ d_nm->mkNode(kind::STRING_CONCAT, s2, a),
+ zero,
+ one);
+ substr_repl =
+ d_nm->mkNode(kind::STRING_SUBSTR,
+ d_nm->mkNode(kind::STRING_STRREPL, s, substr_y, b),
+ zero,
+ x);
+ repl_substr = d_nm->mkNode(kind::STRING_STRREPL,
+ d_nm->mkNode(kind::STRING_SUBSTR, s, zero, x),
+ substr_y,
+ b);
+ sameNormalForm(substr_repl, repl_substr);
+
+ // (str.substr (str.int.to.str x) x x) ---> empty
+ Node substr_itos = d_nm->mkNode(
+ kind::STRING_SUBSTR, d_nm->mkNode(kind::STRING_ITOS, x), x, x);
+ sameNormalForm(substr_itos, empty);
+
+ // (str.substr s (* (- 1) (str.len s)) 1) ---> empty
+ Node substr = d_nm->mkNode(
+ kind::STRING_SUBSTR,
+ s,
+ d_nm->mkNode(kind::MULT, negone, d_nm->mkNode(kind::STRING_LENGTH, s)),
+ one);
+ sameNormalForm(substr, empty);
+ }
+
+ void testRewriteConcat()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node zero = d_nm->mkConst(Rational(0));
+ Node three = d_nm->mkConst(Rational(3));
+
+ Node i = d_nm->mkVar("i", intType);
+ Node s = d_nm->mkVar("s", strType);
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+
+ // Same normal form for:
+ //
+ // (str.++ (str.replace "A" x "") "A")
+ //
+ // (str.++ "A" (str.replace "A" x ""))
+ Node repl_a_x_e = d_nm->mkNode(kind::STRING_STRREPL, a, x, empty);
+ Node repl_a = d_nm->mkNode(kind::STRING_CONCAT, repl_a_x_e, a);
+ Node a_repl = d_nm->mkNode(kind::STRING_CONCAT, a, repl_a_x_e);
+ sameNormalForm(repl_a, a_repl);
+
+ // Same normal form for:
+ //
+ // (str.++ y (str.replace "" x (str.substr y 0 3)) (str.substr y 0 3) "A" (str.substr y 0 3))
+ //
+ // (str.++ y (str.substr y 0 3) (str.replace "" x (str.substr y 0 3)) "A" (str.substr y 0 3))
+ Node z = d_nm->mkNode(kind::STRING_SUBSTR, y, zero, three);
+ Node repl_e_x_z = d_nm->mkNode(kind::STRING_STRREPL, empty, x, z);
+ repl_a = d_nm->mkNode(kind::STRING_CONCAT, y, repl_e_x_z, z, a, z);
+ a_repl = d_nm->mkNode(kind::STRING_CONCAT, y, z, repl_e_x_z, a, z);
+ sameNormalForm(repl_a, a_repl);
+
+ // Same normal form for:
+ //
+ // (str.++ "A" (str.replace "A" x "") (str.substr "A" 0 i))
+ //
+ // (str.++ (str.substr "A" 0 i) (str.replace "A" x "") "A")
+ Node substr_a = d_nm->mkNode(kind::STRING_SUBSTR, a, zero, i);
+ Node a_substr_repl =
+ d_nm->mkNode(kind::STRING_CONCAT, a, substr_a, repl_a_x_e);
+ Node substr_repl_a =
+ d_nm->mkNode(kind::STRING_CONCAT, substr_a, repl_a_x_e, a);
+ sameNormalForm(a_substr_repl, substr_repl_a);
+
+ // Same normal form for:
+ //
+ // (str.++ (str.replace "" x (str.substr "A" 0 i)) (str.substr "A" 0 i) (str.at "A" i))
+ //
+ // (str.++ (str.at "A" i) (str.replace "" x (str.substr "A" 0 i)) (str.substr "A" 0 i))
+ Node charat_a = d_nm->mkNode(kind::STRING_CHARAT, a, i);
+ Node repl_e_x_s = d_nm->mkNode(kind::STRING_STRREPL, empty, x, substr_a);
+ Node repl_substr_a =
+ d_nm->mkNode(kind::STRING_CONCAT, repl_e_x_s, substr_a, charat_a);
+ Node a_repl_substr =
+ d_nm->mkNode(kind::STRING_CONCAT, charat_a, repl_e_x_s, substr_a);
+ sameNormalForm(repl_substr_a, a_repl_substr);
+ }
+
+ void testLengthPreserveRewrite()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node abcd = d_nm->mkConst(::CVC4::String("ABCD"));
+ Node f = d_nm->mkConst(::CVC4::String("F"));
+ Node gh = d_nm->mkConst(::CVC4::String("GH"));
+ Node ij = d_nm->mkConst(::CVC4::String("IJ"));
+
+ Node i = d_nm->mkVar("i", intType);
+ Node s = d_nm->mkVar("s", strType);
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+
+ // Same length preserving rewrite for:
+ //
+ // (str.++ "ABCD" (str.++ x x))
+ //
+ // (str.++ "GH" (str.repl "GH" "IJ") "IJ")
+ Node concat1 = d_nm->mkNode(
+ kind::STRING_CONCAT, abcd, d_nm->mkNode(kind::STRING_CONCAT, x, x));
+ Node concat2 = d_nm->mkNode(kind::STRING_CONCAT,
+ gh,
+ x,
+ d_nm->mkNode(kind::STRING_STRREPL, x, gh, ij),
+ ij);
+ Node res_concat1 = SequencesRewriter::lengthPreserveRewrite(concat1);
+ Node res_concat2 = SequencesRewriter::lengthPreserveRewrite(concat2);
+ TS_ASSERT_EQUALS(res_concat1, res_concat2);
+ }
+
+ void testRewriteIndexOf()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node abcd = d_nm->mkConst(::CVC4::String("ABCD"));
+ Node aaad = d_nm->mkConst(::CVC4::String("AAAD"));
+ Node b = d_nm->mkConst(::CVC4::String("B"));
+ Node c = d_nm->mkConst(::CVC4::String("C"));
+ Node ccc = d_nm->mkConst(::CVC4::String("CCC"));
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node negOne = d_nm->mkConst(Rational(-1));
+ Node zero = d_nm->mkConst(Rational(0));
+ Node one = d_nm->mkConst(Rational(1));
+ Node two = d_nm->mkConst(Rational(2));
+ Node three = d_nm->mkConst(Rational(3));
+ Node i = d_nm->mkVar("i", intType);
+ Node j = d_nm->mkVar("j", intType);
+
+ // Same normal form for:
+ //
+ // (str.to.int (str.indexof "A" x 1))
+ //
+ // (str.to.int (str.indexof "B" x 1))
+ Node a_idof_x = d_nm->mkNode(kind::STRING_STRIDOF, a, x, two);
+ Node itos_a_idof_x = d_nm->mkNode(kind::STRING_ITOS, a_idof_x);
+ Node b_idof_x = d_nm->mkNode(kind::STRING_STRIDOF, b, x, two);
+ Node itos_b_idof_x = d_nm->mkNode(kind::STRING_ITOS, b_idof_x);
+ sameNormalForm(itos_a_idof_x, itos_b_idof_x);
+
+ // Same normal form for:
+ //
+ // (str.indexof (str.++ "ABCD" x) y 3)
+ //
+ // (str.indexof (str.++ "AAAD" x) y 3)
+ Node idof_abcd = d_nm->mkNode(kind::STRING_STRIDOF,
+ d_nm->mkNode(kind::STRING_CONCAT, abcd, x),
+ y,
+ three);
+ Node idof_aaad = d_nm->mkNode(kind::STRING_STRIDOF,
+ d_nm->mkNode(kind::STRING_CONCAT, aaad, x),
+ y,
+ three);
+ sameNormalForm(idof_abcd, idof_aaad);
+
+ // (str.indexof (str.substr x 1 i) "A" i) ---> -1
+ Node idof_substr =
+ d_nm->mkNode(kind::STRING_STRIDOF,
+ d_nm->mkNode(kind::STRING_SUBSTR, x, one, i),
+ a,
+ i);
+ sameNormalForm(idof_substr, negOne);
+
+ {
+ // Same normal form for:
+ //
+ // (str.indexof (str.++ "B" (str.substr "CCC" i j) x "A") "A" 0)
+ //
+ // (+ 1 (str.len (str.substr "CCC" i j))
+ // (str.indexof (str.++ "A" x y) "A" 0))
+ Node lhs = d_nm->mkNode(
+ kind::STRING_STRIDOF,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ b,
+ d_nm->mkNode(kind::STRING_SUBSTR, ccc, i, j),
+ x,
+ a),
+ a,
+ zero);
+ Node rhs = d_nm->mkNode(
+ kind::PLUS,
+ one,
+ d_nm->mkNode(kind::STRING_LENGTH,
+ d_nm->mkNode(kind::STRING_SUBSTR, ccc, i, j)),
+ d_nm->mkNode(kind::STRING_STRIDOF,
+ d_nm->mkNode(kind::STRING_CONCAT, x, a),
+ a,
+ zero));
+ sameNormalForm(lhs, rhs);
+ }
+
+ {
+ // Same normal form for:
+ //
+ // (str.indexof (str.++ "B" "C" "A" x y) "A" 0)
+ //
+ // (+ 2 (str.indexof (str.++ "A" x y) "A" 0))
+ Node lhs = d_nm->mkNode(kind::STRING_STRIDOF,
+ d_nm->mkNode(kind::STRING_CONCAT, b, c, a, x, y),
+ a,
+ zero);
+ Node rhs =
+ d_nm->mkNode(kind::PLUS,
+ two,
+ d_nm->mkNode(kind::STRING_STRIDOF,
+ d_nm->mkNode(kind::STRING_CONCAT, a, x, y),
+ a,
+ zero));
+ sameNormalForm(lhs, rhs);
+ }
+ }
+
+ void testRewriteReplace()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node ab = d_nm->mkConst(::CVC4::String("AB"));
+ Node b = d_nm->mkConst(::CVC4::String("B"));
+ Node c = d_nm->mkConst(::CVC4::String("C"));
+ Node d = d_nm->mkConst(::CVC4::String("D"));
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node z = d_nm->mkVar("z", strType);
+ Node zero = d_nm->mkConst(Rational(0));
+ Node one = d_nm->mkConst(Rational(1));
+ Node n = d_nm->mkVar("n", intType);
+
+ // (str.replace (str.replace x "B" x) x "A") -->
+ // (str.replace (str.replace x "B" "A") x "A")
+ Node repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ d_nm->mkNode(kind::STRING_STRREPL, x, b, x),
+ x,
+ a);
+ Node repl_repl_short =
+ d_nm->mkNode(kind::STRING_STRREPL,
+ d_nm->mkNode(kind::STRING_STRREPL, x, b, a),
+ x,
+ a);
+ sameNormalForm(repl_repl, repl_repl_short);
+
+ // (str.replace "A" (str.replace "B", x, "C") "D") --> "A"
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ a,
+ d_nm->mkNode(kind::STRING_STRREPL, b, x, c),
+ d);
+ sameNormalForm(repl_repl, a);
+
+ // (str.replace "A" (str.replace "B", x, "A") "D") -/-> "A"
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ a,
+ d_nm->mkNode(kind::STRING_STRREPL, b, x, a),
+ d);
+ differentNormalForms(repl_repl, a);
+
+ // Same normal form for:
+ //
+ // (str.replace x (str.++ x y z) y)
+ //
+ // (str.replace x (str.++ x y z) z)
+ Node xyz = d_nm->mkNode(kind::STRING_CONCAT, x, y, z);
+ Node repl_x_xyz = d_nm->mkNode(kind::STRING_STRREPL, x, xyz, y);
+ Node repl_x_zyx = d_nm->mkNode(kind::STRING_STRREPL, x, xyz, z);
+ sameNormalForm(repl_x_xyz, repl_x_zyx);
+
+ // (str.replace "" (str.++ x x) x) --> ""
+ Node repl_empty_xx = d_nm->mkNode(kind::STRING_STRREPL,
+ empty,
+ d_nm->mkNode(kind::STRING_CONCAT, x, x),
+ x);
+ sameNormalForm(repl_empty_xx, empty);
+
+ // (str.replace "AB" (str.++ x "A") x) --> (str.replace "AB" (str.++ x "A")
+ // "")
+ Node repl_ab_xa_x = d_nm->mkNode(kind::STRING_STRREPL,
+ d_nm->mkNode(kind::STRING_CONCAT, a, b),
+ d_nm->mkNode(kind::STRING_CONCAT, x, a),
+ x);
+ Node repl_ab_xa_e = d_nm->mkNode(kind::STRING_STRREPL,
+ d_nm->mkNode(kind::STRING_CONCAT, a, b),
+ d_nm->mkNode(kind::STRING_CONCAT, x, a),
+ empty);
+ sameNormalForm(repl_ab_xa_x, repl_ab_xa_e);
+
+ // (str.replace "AB" (str.++ x "A") x) -/-> (str.replace "AB" (str.++ "A" x)
+ // "")
+ Node repl_ab_ax_e = d_nm->mkNode(kind::STRING_STRREPL,
+ d_nm->mkNode(kind::STRING_CONCAT, a, b),
+ d_nm->mkNode(kind::STRING_CONCAT, a, x),
+ empty);
+ differentNormalForms(repl_ab_ax_e, repl_ab_xa_e);
+
+ // (str.replace "" (str.replace y x "A") y) ---> ""
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ empty,
+ d_nm->mkNode(kind::STRING_STRREPL, y, x, a),
+ y);
+ sameNormalForm(repl_repl, empty);
+
+ // (str.replace "" (str.replace x y x) x) ---> ""
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ empty,
+ d_nm->mkNode(kind::STRING_STRREPL, x, y, x),
+ x);
+ sameNormalForm(repl_repl, empty);
+
+ // (str.replace "" (str.substr x 0 1) x) ---> ""
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ empty,
+ d_nm->mkNode(kind::STRING_SUBSTR, x, zero, one),
+ x);
+ sameNormalForm(repl_repl, empty);
+
+ // Same normal form for:
+ //
+ // (str.replace "" (str.replace x y x) y)
+ //
+ // (str.replace "" x y)
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ empty,
+ d_nm->mkNode(kind::STRING_STRREPL, x, y, x),
+ y);
+ Node repl = d_nm->mkNode(kind::STRING_STRREPL, empty, x, y);
+ sameNormalForm(repl_repl, repl);
+
+ // Same normal form:
+ //
+ // (str.replace "B" (str.replace x "A" "B") "B")
+ //
+ // (str.replace "B" x "B"))
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ b,
+ d_nm->mkNode(kind::STRING_STRREPL, x, a, b),
+ b);
+ repl = d_nm->mkNode(kind::STRING_STRREPL, b, x, b);
+ sameNormalForm(repl_repl, repl);
+
+ // Different normal forms for:
+ //
+ // (str.replace "B" (str.replace "" x "A") "B")
+ //
+ // (str.replace "B" x "B")
+ repl_repl = d_nm->mkNode(kind::STRING_STRREPL,
+ b,
+ d_nm->mkNode(kind::STRING_STRREPL, empty, x, a),
+ b);
+ repl = d_nm->mkNode(kind::STRING_STRREPL, b, x, b);
+ differentNormalForms(repl_repl, repl);
+
+ {
+ // Same normal form:
+ //
+ // (str.replace (str.++ "AB" x) "C" y)
+ //
+ // (str.++ "AB" (str.replace x "C" y))
+ Node lhs = d_nm->mkNode(
+ kind::STRING_STRREPL, d_nm->mkNode(kind::STRING_CONCAT, ab, x), c, y);
+ Node rhs = d_nm->mkNode(
+ kind::STRING_CONCAT, ab, d_nm->mkNode(kind::STRING_STRREPL, x, c, y));
+ sameNormalForm(lhs, rhs);
+ }
+ }
+
+ void testRewriteContains()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node ab = d_nm->mkConst(::CVC4::String("AB"));
+ Node b = d_nm->mkConst(::CVC4::String("B"));
+ Node c = d_nm->mkConst(::CVC4::String("C"));
+ Node e = d_nm->mkConst(::CVC4::String("E"));
+ Node h = d_nm->mkConst(::CVC4::String("H"));
+ Node j = d_nm->mkConst(::CVC4::String("J"));
+ Node p = d_nm->mkConst(::CVC4::String("P"));
+ Node abc = d_nm->mkConst(::CVC4::String("ABC"));
+ Node def = d_nm->mkConst(::CVC4::String("DEF"));
+ Node ghi = d_nm->mkConst(::CVC4::String("GHI"));
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node xy = d_nm->mkNode(kind::STRING_CONCAT, x, y);
+ Node yx = d_nm->mkNode(kind::STRING_CONCAT, y, x);
+ Node z = d_nm->mkVar("z", strType);
+ Node n = d_nm->mkVar("n", intType);
+ Node m = d_nm->mkVar("m", intType);
+ Node one = d_nm->mkConst(Rational(1));
+ Node two = d_nm->mkConst(Rational(2));
+ Node three = d_nm->mkConst(Rational(3));
+ Node four = d_nm->mkConst(Rational(4));
+ Node t = d_nm->mkConst(true);
+ Node f = d_nm->mkConst(false);
+
+ // Same normal form for:
+ //
+ // (str.replace "A" (str.substr x 1 3) y z)
+ //
+ // (str.replace "A" (str.substr x 1 4) y z)
+ Node substr_3 =
+ d_nm->mkNode(kind::STRING_STRREPL,
+ a,
+ d_nm->mkNode(kind::STRING_SUBSTR, x, one, three),
+ z);
+ Node substr_4 =
+ d_nm->mkNode(kind::STRING_STRREPL,
+ a,
+ d_nm->mkNode(kind::STRING_SUBSTR, x, one, four),
+ z);
+ sameNormalForm(substr_3, substr_4);
+
+ // Same normal form for:
+ //
+ // (str.replace "A" (str.++ y (str.substr x 1 3)) y z)
+ //
+ // (str.replace "A" (str.++ y (str.substr x 1 4)) y z)
+ Node concat_substr_3 = d_nm->mkNode(
+ kind::STRING_STRREPL,
+ a,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ y,
+ d_nm->mkNode(kind::STRING_SUBSTR, x, one, three)),
+ z);
+ Node concat_substr_4 = d_nm->mkNode(
+ kind::STRING_STRREPL,
+ a,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ y,
+ d_nm->mkNode(kind::STRING_SUBSTR, x, one, four)),
+ z);
+ sameNormalForm(concat_substr_3, concat_substr_4);
+
+ // (str.contains "A" (str.++ a (str.replace "B", x, "C")) --> false
+ Node ctn_repl =
+ d_nm->mkNode(kind::STRING_STRCTN,
+ a,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ a,
+ d_nm->mkNode(kind::STRING_STRREPL, b, x, c)));
+ sameNormalForm(ctn_repl, f);
+
+ // (str.contains x (str.++ x x)) --> (= x "")
+ Node x_cnts_x_x = d_nm->mkNode(
+ kind::STRING_STRCTN, x, d_nm->mkNode(kind::STRING_CONCAT, x, x));
+ sameNormalForm(x_cnts_x_x, d_nm->mkNode(kind::EQUAL, x, empty));
+
+ // Same normal form for:
+ //
+ // (str.contains (str.++ y x) (str.++ x z y))
+ //
+ // (and (str.contains (str.++ y x) (str.++ x y)) (= z ""))
+ Node yx_cnts_xzy = d_nm->mkNode(
+ kind::STRING_STRCTN, yx, d_nm->mkNode(kind::STRING_CONCAT, x, z, y));
+ Node yx_cnts_xy = d_nm->mkNode(kind::AND,
+ d_nm->mkNode(kind::EQUAL, z, empty),
+ d_nm->mkNode(kind::STRING_STRCTN, yx, xy));
+ sameNormalForm(yx_cnts_xzy, yx_cnts_xy);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.substr x n (str.len y)) y)
+ //
+ // (= (str.substr x n (str.len y)) y)
+ Node ctn_substr = d_nm->mkNode(
+ kind::STRING_STRCTN,
+ d_nm->mkNode(
+ kind::STRING_SUBSTR, x, n, d_nm->mkNode(kind::STRING_LENGTH, y)),
+ y);
+ Node substr_eq = d_nm->mkNode(
+ kind::EQUAL,
+ d_nm->mkNode(
+ kind::STRING_SUBSTR, x, n, d_nm->mkNode(kind::STRING_LENGTH, y)),
+ y);
+ sameNormalForm(ctn_substr, substr_eq);
+
+ // Same normal form for:
+ //
+ // (str.contains x (str.replace y x y))
+ //
+ // (str.contains x y)
+ Node ctn_repl_y_x_y = d_nm->mkNode(
+ kind::STRING_STRCTN, x, d_nm->mkNode(kind::STRING_STRREPL, y, x, y));
+ Node ctn_x_y = d_nm->mkNode(kind::STRING_STRCTN, x, y);
+ sameNormalForm(ctn_repl_y_x_y, ctn_repl_y_x_y);
+
+ // Same normal form for:
+ //
+ // (str.contains x (str.replace x y x))
+ //
+ // (= x (str.replace x y x))
+ Node ctn_repl_self = d_nm->mkNode(
+ kind::STRING_STRCTN, x, d_nm->mkNode(kind::STRING_STRREPL, x, y, x));
+ Node eq_repl = d_nm->mkNode(
+ kind::EQUAL, x, d_nm->mkNode(kind::STRING_STRREPL, x, y, x));
+ sameNormalForm(ctn_repl_self, eq_repl);
+
+ // (str.contains x (str.++ "A" (str.replace x y x))) ---> false
+ Node ctn_repl_self_f =
+ d_nm->mkNode(kind::STRING_STRCTN,
+ x,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ a,
+ d_nm->mkNode(kind::STRING_STRREPL, x, y, x)));
+ sameNormalForm(ctn_repl_self_f, f);
+
+ // Same normal form for:
+ //
+ // (str.contains x (str.replace "" x y))
+ //
+ // (= "" (str.replace "" x y))
+ Node ctn_repl_empty =
+ d_nm->mkNode(kind::STRING_STRCTN,
+ x,
+ d_nm->mkNode(kind::STRING_STRREPL, empty, x, y));
+ Node eq_repl_empty = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_STRREPL, empty, x, y));
+ sameNormalForm(ctn_repl_empty, eq_repl_empty);
+
+ // Same normal form for:
+ //
+ // (str.contains x (str.++ x y))
+ //
+ // (= "" y)
+ Node ctn_x_x_y = d_nm->mkNode(
+ kind::STRING_STRCTN, x, d_nm->mkNode(kind::STRING_CONCAT, x, y));
+ Node eq_emp_y = d_nm->mkNode(kind::EQUAL, empty, y);
+ sameNormalForm(ctn_x_x_y, eq_emp_y);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.++ y x) (str.++ x y))
+ //
+ // (= (str.++ y x) (str.++ x y))
+ Node ctn_yxxy = d_nm->mkNode(kind::STRING_STRCTN, yx, xy);
+ Node eq_yxxy = d_nm->mkNode(kind::EQUAL, yx, xy);
+ sameNormalForm(ctn_yxxy, eq_yxxy);
+
+ // (str.contains (str.replace x y x) x) ---> true
+ ctn_repl = d_nm->mkNode(
+ kind::STRING_STRCTN, d_nm->mkNode(kind::STRING_STRREPL, x, y, x), x);
+ sameNormalForm(ctn_repl, t);
+
+ // (str.contains (str.replace (str.++ x y) z (str.++ y x)) x) ---> true
+ ctn_repl = d_nm->mkNode(
+ kind::STRING_STRCTN, d_nm->mkNode(kind::STRING_STRREPL, xy, z, yx), x);
+ sameNormalForm(ctn_repl, t);
+
+ // (str.contains (str.++ z (str.replace (str.++ x y) z (str.++ y x))) x)
+ // ---> true
+ ctn_repl = d_nm->mkNode(
+ kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ z,
+ d_nm->mkNode(kind::STRING_STRREPL, xy, z, yx)),
+ x);
+ sameNormalForm(ctn_repl, t);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.replace x y x) y)
+ //
+ // (str.contains x y)
+ Node lhs = d_nm->mkNode(
+ kind::STRING_STRCTN, d_nm->mkNode(kind::STRING_STRREPL, x, y, x), y);
+ Node rhs = d_nm->mkNode(kind::STRING_STRCTN, x, y);
+ sameNormalForm(lhs, rhs);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.replace x y x) "B")
+ //
+ // (str.contains x "B")
+ lhs = d_nm->mkNode(
+ kind::STRING_STRCTN, d_nm->mkNode(kind::STRING_STRREPL, x, y, x), b);
+ rhs = d_nm->mkNode(kind::STRING_STRCTN, x, b);
+ sameNormalForm(lhs, rhs);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.replace x y x) (str.substr z n 1))
+ //
+ // (str.contains x (str.substr z n 1))
+ Node substr_z = d_nm->mkNode(kind::STRING_SUBSTR, z, n, one);
+ lhs = d_nm->mkNode(kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_STRREPL, x, y, x),
+ substr_z);
+ rhs = d_nm->mkNode(kind::STRING_STRCTN, x, substr_z);
+ sameNormalForm(lhs, rhs);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.replace x y z) z)
+ //
+ // (str.contains (str.replace x z y) y)
+ lhs = d_nm->mkNode(
+ kind::STRING_STRCTN, d_nm->mkNode(kind::STRING_STRREPL, x, y, z), z);
+ rhs = d_nm->mkNode(
+ kind::STRING_STRCTN, d_nm->mkNode(kind::STRING_STRREPL, x, z, y), y);
+ sameNormalForm(lhs, rhs);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.replace x "A" "B") "A")
+ //
+ // (str.contains (str.replace x "A" "") "A")
+ lhs = d_nm->mkNode(
+ kind::STRING_STRCTN, d_nm->mkNode(kind::STRING_STRREPL, x, a, b), a);
+ rhs = d_nm->mkNode(kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_STRREPL, x, a, empty),
+ a);
+ sameNormalForm(lhs, rhs);
+
+ {
+ // (str.contains (str.++ x "A") (str.++ "B" x)) ---> false
+ Node ctn = d_nm->mkNode(kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_CONCAT, x, a),
+ d_nm->mkNode(kind::STRING_CONCAT, b, x));
+ sameNormalForm(ctn, f);
+ }
+
+ {
+ // Same normal form for:
+ //
+ // (str.contains (str.replace x "ABC" "DEF") "GHI")
+ //
+ // (str.contains x "GHI")
+ lhs = d_nm->mkNode(kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_STRREPL, x, abc, def),
+ ghi);
+ rhs = d_nm->mkNode(kind::STRING_STRCTN, x, ghi);
+ sameNormalForm(lhs, rhs);
+ }
+
+ {
+ // Different normal forms for:
+ //
+ // (str.contains (str.replace x "ABC" "DEF") "B")
+ //
+ // (str.contains x "B")
+ lhs = d_nm->mkNode(kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_STRREPL, x, abc, def),
+ b);
+ rhs = d_nm->mkNode(kind::STRING_STRCTN, x, b);
+ differentNormalForms(lhs, rhs);
+ }
+
+ {
+ // Different normal forms for:
+ //
+ // (str.contains (str.replace x "B" "DEF") "ABC")
+ //
+ // (str.contains x "ABC")
+ lhs = d_nm->mkNode(kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_STRREPL, x, b, def),
+ abc);
+ rhs = d_nm->mkNode(kind::STRING_STRCTN, x, abc);
+ differentNormalForms(lhs, rhs);
+ }
+
+ {
+ // Same normal form for:
+ //
+ // (str.contains (str.++ (str.substr "DEF" n m) x) "AB")
+ //
+ // (str.contains x "AB")
+ lhs = d_nm->mkNode(
+ kind::STRING_STRCTN,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ d_nm->mkNode(kind::STRING_SUBSTR, def, n, m),
+ x),
+ ab);
+ rhs = d_nm->mkNode(kind::STRING_STRCTN, x, ab);
+ sameNormalForm(lhs, rhs);
+ }
+
+ {
+ // Same normal form for:
+ //
+ // (str.contains "ABC" (str.at x n))
+ //
+ // (or (= x "")
+ // (= x "A") (= x "B") (= x "C"))
+ Node cat = d_nm->mkNode(kind::STRING_CHARAT, x, n);
+ lhs = d_nm->mkNode(kind::STRING_STRCTN, abc, cat);
+ rhs = d_nm->mkNode(kind::OR,
+ d_nm->mkNode(kind::EQUAL, cat, empty),
+ d_nm->mkNode(kind::EQUAL, cat, a),
+ d_nm->mkNode(kind::EQUAL, cat, b),
+ d_nm->mkNode(kind::EQUAL, cat, c));
+ sameNormalForm(lhs, rhs);
+ }
+ }
+
+ void testInferEqsFromContains()
+ {
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node b = d_nm->mkConst(::CVC4::String("B"));
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node xy = d_nm->mkNode(kind::STRING_CONCAT, x, y);
+ Node f = d_nm->mkConst(false);
+
+ // inferEqsFromContains("", (str.++ x y)) returns something equivalent to
+ // (= "" y)
+ Node empty_x_y = d_nm->mkNode(kind::AND,
+ d_nm->mkNode(kind::EQUAL, empty, x),
+ d_nm->mkNode(kind::EQUAL, empty, y));
+ sameNormalForm(SequencesRewriter::inferEqsFromContains(empty, xy),
+ empty_x_y);
+
+ // inferEqsFromContains(x, (str.++ x y)) returns false
+ Node bxya = d_nm->mkNode(kind::STRING_CONCAT, b, y, x, a);
+ sameNormalForm(SequencesRewriter::inferEqsFromContains(x, bxya), f);
+
+ // inferEqsFromContains(x, y) returns null
+ Node n = SequencesRewriter::inferEqsFromContains(x, y);
+ TS_ASSERT(n.isNull());
+
+ // inferEqsFromContains(x, x) returns something equivalent to (= x x)
+ Node eq_x_x = d_nm->mkNode(kind::EQUAL, x, x);
+ sameNormalForm(SequencesRewriter::inferEqsFromContains(x, x), eq_x_x);
+
+ // inferEqsFromContains((str.replace x "B" "A"), x) returns something
+ // equivalent to (= (str.replace x "B" "A") x)
+ Node repl = d_nm->mkNode(kind::STRING_STRREPL, x, b, a);
+ Node eq_repl_x = d_nm->mkNode(kind::EQUAL, repl, x);
+ sameNormalForm(SequencesRewriter::inferEqsFromContains(repl, x),
+ eq_repl_x);
+
+ // inferEqsFromContains(x, (str.replace x "B" "A")) returns something
+ // equivalent to (= (str.replace x "B" "A") x)
+ Node eq_x_repl = d_nm->mkNode(kind::EQUAL, x, repl);
+ sameNormalForm(SequencesRewriter::inferEqsFromContains(x, repl),
+ eq_x_repl);
+ }
+
+ void testRewritePrefixSuffix()
+ {
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node xx = d_nm->mkNode(kind::STRING_CONCAT, x, x);
+ Node xxa = d_nm->mkNode(kind::STRING_CONCAT, x, x, a);
+ Node xy = d_nm->mkNode(kind::STRING_CONCAT, x, y);
+ Node f = d_nm->mkConst(false);
+
+ // Same normal form for:
+ //
+ // (str.prefix (str.++ x y) x)
+ //
+ // (= y "")
+ Node p_xy = d_nm->mkNode(kind::STRING_PREFIX, xy, x);
+ Node empty_y = d_nm->mkNode(kind::EQUAL, y, empty);
+ sameNormalForm(p_xy, empty_y);
+
+ // Same normal form for:
+ //
+ // (str.suffix (str.++ x x) x)
+ //
+ // (= x "")
+ Node p_xx = d_nm->mkNode(kind::STRING_SUFFIX, xx, x);
+ Node empty_x = d_nm->mkNode(kind::EQUAL, x, empty);
+ sameNormalForm(p_xx, empty_x);
+
+ // (str.suffix x (str.++ x x "A")) ---> false
+ Node p_xxa = d_nm->mkNode(kind::STRING_SUFFIX, xxa, x);
+ sameNormalForm(p_xxa, f);
+ }
+
+ void testRewriteEqualityExt()
+ {
+ TypeNode strType = d_nm->stringType();
+ TypeNode intType = d_nm->integerType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node aaa = d_nm->mkConst(::CVC4::String("AAA"));
+ Node b = d_nm->mkConst(::CVC4::String("B"));
+ Node ba = d_nm->mkConst(::CVC4::String("BA"));
+ Node w = d_nm->mkVar("w", strType);
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node z = d_nm->mkVar("z", strType);
+ Node xxa = d_nm->mkNode(kind::STRING_CONCAT, x, x, a);
+ Node f = d_nm->mkConst(false);
+ Node n = d_nm->mkVar("n", intType);
+ Node zero = d_nm->mkConst(Rational(0));
+ Node one = d_nm->mkConst(Rational(1));
+ Node three = d_nm->mkConst(Rational(3));
+
+ // Same normal form for:
+ //
+ // (= "" (str.replace "" x "B"))
+ //
+ // (not (= x ""))
+ Node empty_repl = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_STRREPL, empty, x, b));
+ Node empty_x = d_nm->mkNode(kind::NOT, d_nm->mkNode(kind::EQUAL, x, empty));
+ sameNormalForm(empty_repl, empty_x);
+
+ // Same normal form for:
+ //
+ // (= "" (str.replace x y (str.++ x x "A")))
+ //
+ // (and (= x "") (not (= y "")))
+ Node empty_repl_xaa = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_STRREPL, x, y, xxa));
+ Node empty_xy = d_nm->mkNode(
+ kind::AND,
+ d_nm->mkNode(kind::EQUAL, x, empty),
+ d_nm->mkNode(kind::NOT, d_nm->mkNode(kind::EQUAL, y, empty)));
+ sameNormalForm(empty_repl_xaa, empty_xy);
+
+ // (= "" (str.replace (str.++ x x "A") x y)) ---> false
+ Node empty_repl_xxaxy = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_STRREPL, xxa, x, y));
+ Node eq_xxa_repl = d_nm->mkNode(
+ kind::EQUAL, xxa, d_nm->mkNode(kind::STRING_STRREPL, empty, y, x));
+ sameNormalForm(empty_repl_xxaxy, f);
+
+ // Same normal form for:
+ //
+ // (= "" (str.replace "A" x y))
+ //
+ // (= "A" (str.replace "" y x))
+ Node empty_repl_axy = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_STRREPL, a, x, y));
+ Node eq_a_repl = d_nm->mkNode(
+ kind::EQUAL, a, d_nm->mkNode(kind::STRING_STRREPL, empty, y, x));
+ sameNormalForm(empty_repl_axy, eq_a_repl);
+
+ // Same normal form for:
+ //
+ // (= "" (str.replace x "A" ""))
+ //
+ // (str.prefix x "A")
+ Node empty_repl_a = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_STRREPL, x, a, empty));
+ Node prefix_a = d_nm->mkNode(kind::STRING_PREFIX, x, a);
+ sameNormalForm(empty_repl_a, prefix_a);
+
+ // Same normal form for:
+ //
+ // (= "" (str.substr x 1 2))
+ //
+ // (<= (str.len x) 1)
+ Node empty_substr = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_SUBSTR, x, one, three));
+ Node leq_len_x =
+ d_nm->mkNode(kind::LEQ, d_nm->mkNode(kind::STRING_LENGTH, x), one);
+ sameNormalForm(empty_substr, leq_len_x);
+
+ // Different normal form for:
+ //
+ // (= "" (str.substr x 0 n))
+ //
+ // (<= n 0)
+ Node empty_substr_x = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_SUBSTR, x, zero, n));
+ Node leq_n = d_nm->mkNode(kind::LEQ, n, zero);
+ differentNormalForms(empty_substr_x, leq_n);
+
+ // Same normal form for:
+ //
+ // (= "" (str.substr "A" 0 n))
+ //
+ // (<= n 0)
+ Node empty_substr_a = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_SUBSTR, a, zero, n));
+ sameNormalForm(empty_substr_a, leq_n);
+
+ // Same normal form for:
+ //
+ // (= (str.++ x x a) (str.replace y (str.++ x x a) y))
+ //
+ // (= (str.++ x x a) y)
+ Node eq_xxa_repl_y = d_nm->mkNode(
+ kind::EQUAL, xxa, d_nm->mkNode(kind::STRING_STRREPL, y, xxa, y));
+ Node eq_xxa_y = d_nm->mkNode(kind::EQUAL, xxa, y);
+ sameNormalForm(eq_xxa_repl_y, eq_xxa_y);
+
+ // (= (str.++ x x a) (str.replace (str.++ x x a) "A" "B")) ---> false
+ Node eq_xxa_repl_xxa = d_nm->mkNode(
+ kind::EQUAL, xxa, d_nm->mkNode(kind::STRING_STRREPL, xxa, a, b));
+ sameNormalForm(eq_xxa_repl_xxa, f);
+
+ // Same normal form for:
+ //
+ // (= (str.replace x "A" "B") "")
+ //
+ // (= x "")
+ Node eq_repl = d_nm->mkNode(
+ kind::EQUAL, d_nm->mkNode(kind::STRING_STRREPL, x, a, b), empty);
+ Node eq_x = d_nm->mkNode(kind::EQUAL, x, empty);
+ sameNormalForm(eq_repl, eq_x);
+
+ {
+ // Same normal form for:
+ //
+ // (= (str.replace y "A" "B") "B")
+ //
+ // (= (str.replace y "B" "A") "A")
+ Node lhs = d_nm->mkNode(
+ kind::EQUAL, d_nm->mkNode(kind::STRING_STRREPL, x, a, b), b);
+ Node rhs = d_nm->mkNode(
+ kind::EQUAL, d_nm->mkNode(kind::STRING_STRREPL, x, b, a), a);
+ sameNormalForm(lhs, rhs);
+ }
+
+ {
+ // Same normal form for:
+ //
+ // (= (str.++ x "A" y) (str.++ "A" "A" (str.substr "AAA" 0 n)))
+ //
+ // (= (str.++ y x) (str.++ (str.substr "AAA" 0 n) "A"))
+ Node lhs = d_nm->mkNode(
+ kind::EQUAL,
+ d_nm->mkNode(kind::STRING_CONCAT, x, a, y),
+ d_nm->mkNode(kind::STRING_CONCAT,
+ a,
+ a,
+ d_nm->mkNode(kind::STRING_SUBSTR, aaa, zero, n)));
+ Node rhs = d_nm->mkNode(
+ kind::EQUAL,
+ d_nm->mkNode(kind::STRING_CONCAT, x, y),
+ d_nm->mkNode(kind::STRING_CONCAT,
+ d_nm->mkNode(kind::STRING_SUBSTR, aaa, zero, n),
+ a));
+ sameNormalForm(lhs, rhs);
+ }
+
+ {
+ // Same normal form for:
+ //
+ // (= (str.++ "A" x) "A")
+ //
+ // (= x "")
+ Node lhs =
+ d_nm->mkNode(kind::EQUAL, d_nm->mkNode(kind::STRING_CONCAT, a, x), a);
+ Node rhs = d_nm->mkNode(kind::EQUAL, x, empty);
+ sameNormalForm(lhs, rhs);
+ }
+
+ {
+ // (= (str.++ x "A") "") ---> false
+ Node eq = d_nm->mkNode(
+ kind::EQUAL, d_nm->mkNode(kind::STRING_CONCAT, x, a), empty);
+ sameNormalForm(eq, f);
+ }
+
+ {
+ // (= (str.++ x "B") "AAA") ---> false
+ Node eq = d_nm->mkNode(
+ kind::EQUAL, d_nm->mkNode(kind::STRING_CONCAT, x, b), aaa);
+ sameNormalForm(eq, f);
+ }
+
+ {
+ // (= (str.++ x "AAA") "A") ---> false
+ Node eq = d_nm->mkNode(
+ kind::EQUAL, d_nm->mkNode(kind::STRING_CONCAT, x, aaa), a);
+ sameNormalForm(eq, f);
+ }
+
+ {
+ // (= (str.++ "AAA" (str.substr "A" 0 n)) (str.++ x "B")) ---> false
+ Node eq = d_nm->mkNode(
+ kind::EQUAL,
+ d_nm->mkNode(
+ kind::STRING_CONCAT,
+ aaa,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ a,
+ a,
+ d_nm->mkNode(kind::STRING_SUBSTR, x, zero, n))),
+ d_nm->mkNode(kind::STRING_CONCAT, x, b));
+ sameNormalForm(eq, f);
+ }
+
+ {
+ // (= (str.++ "A" (int.to.str n)) "A") -/-> false
+ Node eq = d_nm->mkNode(
+ kind::EQUAL,
+ d_nm->mkNode(
+ kind::STRING_CONCAT, a, d_nm->mkNode(kind::STRING_ITOS, n)),
+ a);
+ differentNormalForms(eq, f);
+ }
+
+ {
+ // (= (str.++ "A" x y) (str.++ x "B" z)) --> false
+ Node eq = d_nm->mkNode(
+ kind::EQUAL,
+ d_nm->mkNode(kind::STRING_CONCAT, a, x, y),
+ d_nm->mkNode(kind::STRING_CONCAT, x, b, z));
+ sameNormalForm(eq, f);
+ }
+
+ {
+ // (= (str.++ "B" x y) (str.++ x "AAA" z)) --> false
+ Node eq = d_nm->mkNode(kind::EQUAL,
+ d_nm->mkNode(kind::STRING_CONCAT, b, x, y),
+ d_nm->mkNode(kind::STRING_CONCAT, x, aaa, z));
+ sameNormalForm(eq, f);
+ }
+
+ {
+ Node xrepl = d_nm->mkNode(kind::STRING_STRREPL, x, a, b);
+
+ // Same normal form for:
+ //
+ // (= (str.++ "B" (str.replace x "A" "B") z y w)
+ // (str.++ z x "BA" z))
+ //
+ // (and (= (str.++ "B" (str.replace x "A" "B") z)
+ // (str.++ z x "B"))
+ // (= (str.++ y w) (str.++ "A" z)))
+ Node lhs =
+ d_nm->mkNode(kind::EQUAL,
+ d_nm->mkNode(kind::STRING_CONCAT, b, xrepl, z, y, w),
+ d_nm->mkNode(kind::STRING_CONCAT, z, x, ba, z));
+ Node rhs = d_nm->mkNode(
+ kind::AND,
+ d_nm->mkNode(kind::EQUAL,
+ d_nm->mkNode(kind::STRING_CONCAT, b, xrepl, z),
+ d_nm->mkNode(kind::STRING_CONCAT, z, x, b)),
+ d_nm->mkNode(kind::EQUAL,
+ d_nm->mkNode(kind::STRING_CONCAT, y, w),
+ d_nm->mkNode(kind::STRING_CONCAT, a, z)));
+ sameNormalForm(lhs, rhs);
+ }
+ }
+
+ void testStripConstantEndpoints()
+ {
+ TypeNode intType = d_nm->integerType();
+ TypeNode strType = d_nm->stringType();
+
+ Node empty = d_nm->mkConst(::CVC4::String(""));
+ Node a = d_nm->mkConst(::CVC4::String("A"));
+ Node ab = d_nm->mkConst(::CVC4::String("AB"));
+ Node abc = d_nm->mkConst(::CVC4::String("ABC"));
+ Node abcd = d_nm->mkConst(::CVC4::String("ABCD"));
+ Node bc = d_nm->mkConst(::CVC4::String("BC"));
+ Node c = d_nm->mkConst(::CVC4::String("C"));
+ Node cd = d_nm->mkConst(::CVC4::String("CD"));
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node n = d_nm->mkVar("n", intType);
+
+ {
+ // stripConstantEndpoints({ "" }, { "A" }, {}, {}, 0) ---> false
+ std::vector<Node> n1 = {empty};
+ std::vector<Node> n2 = {a};
+ std::vector<Node> nb;
+ std::vector<Node> ne;
+ bool res =
+ SequencesRewriter::stripConstantEndpoints(n1, n2, nb, ne, 0);
+ TS_ASSERT(!res);
+ }
+
+ {
+ // stripConstantEndpoints({ "A" }, { "A". (int.to.str n) }, {}, {}, 0)
+ // ---> false
+ std::vector<Node> n1 = {a};
+ std::vector<Node> n2 = {a, d_nm->mkNode(kind::STRING_ITOS, n)};
+ std::vector<Node> nb;
+ std::vector<Node> ne;
+ bool res =
+ SequencesRewriter::stripConstantEndpoints(n1, n2, nb, ne, 0);
+ TS_ASSERT(!res);
+ }
+
+ {
+ // stripConstantEndpoints({ "ABCD" }, { "C" }, {}, {}, 1)
+ // ---> true
+ // n1 is updated to { "CD" }
+ // nb is updated to { "AB" }
+ std::vector<Node> n1 = {abcd};
+ std::vector<Node> n2 = {c};
+ std::vector<Node> nb;
+ std::vector<Node> ne;
+ std::vector<Node> n1r = {cd};
+ std::vector<Node> nbr = {ab};
+ bool res =
+ SequencesRewriter::stripConstantEndpoints(n1, n2, nb, ne, 1);
+ TS_ASSERT(res);
+ TS_ASSERT_EQUALS(n1, n1r);
+ TS_ASSERT_EQUALS(nb, nbr);
+ }
+
+ {
+ // stripConstantEndpoints({ "ABC", x }, { "CD" }, {}, {}, 1)
+ // ---> true
+ // n1 is updated to { "C", x }
+ // nb is updated to { "AB" }
+ std::vector<Node> n1 = {abc, x};
+ std::vector<Node> n2 = {cd};
+ std::vector<Node> nb;
+ std::vector<Node> ne;
+ std::vector<Node> n1r = {c, x};
+ std::vector<Node> nbr = {ab};
+ bool res =
+ SequencesRewriter::stripConstantEndpoints(n1, n2, nb, ne, 1);
+ TS_ASSERT(res);
+ TS_ASSERT_EQUALS(n1, n1r);
+ TS_ASSERT_EQUALS(nb, nbr);
+ }
+
+ {
+ // stripConstantEndpoints({ "ABC" }, { "A" }, {}, {}, -1)
+ // ---> true
+ // n1 is updated to { "A" }
+ // nb is updated to { "BC" }
+ std::vector<Node> n1 = {abc};
+ std::vector<Node> n2 = {a};
+ std::vector<Node> nb;
+ std::vector<Node> ne;
+ std::vector<Node> n1r = {a};
+ std::vector<Node> ner = {bc};
+ bool res =
+ SequencesRewriter::stripConstantEndpoints(n1, n2, nb, ne, -1);
+ TS_ASSERT(res);
+ TS_ASSERT_EQUALS(n1, n1r);
+ TS_ASSERT_EQUALS(ne, ner);
+ }
+
+ {
+ // stripConstantEndpoints({ x, "ABC" }, { y, "A" }, {}, {}, -1)
+ // ---> true
+ // n1 is updated to { x, "A" }
+ // nb is updated to { "BC" }
+ std::vector<Node> n1 = {x, abc};
+ std::vector<Node> n2 = {y, a};
+ std::vector<Node> nb;
+ std::vector<Node> ne;
+ std::vector<Node> n1r = {x, a};
+ std::vector<Node> ner = {bc};
+ bool res =
+ SequencesRewriter::stripConstantEndpoints(n1, n2, nb, ne, -1);
+ TS_ASSERT(res);
+ TS_ASSERT_EQUALS(n1, n1r);
+ TS_ASSERT_EQUALS(ne, ner);
+ }
+ }
+
+ void testRewriteMembership()
+ {
+ TypeNode strType = d_nm->stringType();
+
+ std::vector<Node> vec_empty;
+ Node abc = d_nm->mkConst(::CVC4::String("ABC"));
+ Node re_abc = d_nm->mkNode(kind::STRING_TO_REGEXP, abc);
+ Node x = d_nm->mkVar("x", strType);
+
+ {
+ // Same normal form for:
+ //
+ // (str.in.re x (re.++ (re.* re.allchar)
+ // (re.* re.allchar)
+ // (str.to.re "ABC")
+ // (re.* re.allchar)))
+ //
+ // (str.contains x "ABC")
+ Node sig_star = d_nm->mkNode(kind::REGEXP_STAR,
+ d_nm->mkNode(kind::REGEXP_SIGMA, vec_empty));
+ Node lhs = d_nm->mkNode(
+ kind::STRING_IN_REGEXP,
+ x,
+ d_nm->mkNode(
+ kind::REGEXP_CONCAT, sig_star, sig_star, re_abc, sig_star));
+ Node rhs = d_nm->mkNode(kind::STRING_STRCTN, x, abc);
+ sameNormalForm(lhs, rhs);
+ }
+
+ {
+ // Different normal forms for:
+ //
+ // (str.in.re x (re.++ (re.* re.allchar) (str.to.re "ABC")))
+ //
+ // (str.contains x "ABC")
+ Node sig_star = d_nm->mkNode(kind::REGEXP_STAR,
+ d_nm->mkNode(kind::REGEXP_SIGMA, vec_empty));
+ Node lhs =
+ d_nm->mkNode(kind::STRING_IN_REGEXP,
+ x,
+ d_nm->mkNode(kind::REGEXP_CONCAT, sig_star, re_abc));
+ Node rhs = d_nm->mkNode(kind::STRING_STRCTN, x, abc);
+ differentNormalForms(lhs, rhs);
+ }
+ }
+
+ void testRewriteRegexpConcat()
+ {
+ TypeNode strType = d_nm->stringType();
+
+ std::vector<Node> emptyArgs;
+ Node x = d_nm->mkVar("x", strType);
+ Node y = d_nm->mkVar("y", strType);
+ Node allStar = d_nm->mkNode(kind::REGEXP_STAR,
+ d_nm->mkNode(kind::REGEXP_SIGMA, emptyArgs));
+ Node xReg = d_nm->mkNode(kind::STRING_TO_REGEXP, x);
+ Node yReg = d_nm->mkNode(kind::STRING_TO_REGEXP, y);
+
+ {
+ // In normal form:
+ //
+ // (re.++ (re.* re.allchar) (re.union (str.to.re x) (str.to.re y)))
+ Node n = d_nm->mkNode(kind::REGEXP_CONCAT,
+ allStar,
+ d_nm->mkNode(kind::REGEXP_UNION, xReg, yReg));
+ inNormalForm(n);
+ }
+
+ {
+ // In normal form:
+ //
+ // (re.++ (str.to.re x) (re.* re.allchar))
+ Node n = d_nm->mkNode(kind::REGEXP_CONCAT, xReg, allStar);
+ inNormalForm(n);
+ }
+ }
+
+ private:
+ ExprManager* d_em;
+ SmtEngine* d_smt;
+ SmtScope* d_scope;
+ ExtendedRewriter* d_rewriter;
+
+ NodeManager* d_nm;
+};
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback