From 10707e3ec6f2cab793919f2d1a159e13cdd032a9 Mon Sep 17 00:00:00 2001 From: Andrew Reynolds Date: Thu, 18 Oct 2018 12:51:42 -0500 Subject: [PATCH] Non-contributing find replace rewrite (#2652) --- .../strings/theory_strings_rewriter.cpp | 47 +++++++++++++++++++ test/regress/CMakeLists.txt | 1 + .../regress0/strings/ncontrib-rewrites.smt2 | 15 ++++++ 3 files changed, 63 insertions(+) create mode 100644 test/regress/regress0/strings/ncontrib-rewrites.smt2 diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp index c38a5e838..7c008dc14 100644 --- a/src/theory/strings/theory_strings_rewriter.cpp +++ b/src/theory/strings/theory_strings_rewriter.cpp @@ -2845,6 +2845,53 @@ Node TheoryStringsRewriter::rewriteReplace( Node node ) { } } } + // miniscope based on components that do not contribute to contains + // for example, + // str.replace( x ++ y ++ x ++ y, "A", z ) --> + // str.replace( x ++ y, "A", z ) ++ x ++ y + // since if "A" occurs in x ++ y ++ x ++ y, then it must occur in x ++ y. + if (node[1].isConst() && node[1].getConst().size() == 1) + { + Node lastLhs; + unsigned lastCheckIndex = 0; + for (unsigned i = 1, iend = children0.size(); i < iend; i++) + { + unsigned checkIndex = children0.size() - i; + std::vector checkLhs; + checkLhs.insert( + checkLhs.end(), children0.begin(), children0.begin() + checkIndex); + Node lhs = mkConcat(STRING_CONCAT, checkLhs); + Node rhs = children0[checkIndex]; + Node ctn = nm->mkNode(STRING_STRCTN, lhs, rhs); + ctn = Rewriter::rewrite(ctn); + if (ctn.isConst() && ctn.getConst()) + { + lastLhs = lhs; + lastCheckIndex = checkIndex; + } + else + { + break; + } + } + if (!lastLhs.isNull()) + { + std::vector remc(children0.begin() + lastCheckIndex, + children0.end()); + Node rem = mkConcat(STRING_CONCAT, remc); + Node ret = + nm->mkNode(STRING_CONCAT, + nm->mkNode(STRING_STRREPL, lastLhs, node[1], node[2]), + rem); + // for example: + // str.replace( x ++ x, "A", y ) ---> str.replace( x, "A", y ) ++ x + // Since we know that the first occurrence of "A" cannot be in the + // second occurrence of x. Notice this is specific to single characters + // due to complications with finds that span multiple components for + // non-characters. + return returnRewrite(node, ret, "repl-char-ncontrib-find"); + } + } // TODO (#1180) incorporate these? // contains( t, s ) => diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt index 59edb6986..a41108a71 100644 --- a/test/regress/CMakeLists.txt +++ b/test/regress/CMakeLists.txt @@ -807,6 +807,7 @@ set(regress_0_tests regress0/strings/leadingzero001.smt2 regress0/strings/loop001.smt2 regress0/strings/model001.smt2 + regress0/strings/ncontrib-rewrites.smt2 regress0/strings/norn-31.smt2 regress0/strings/norn-simp-rew.smt2 regress0/strings/repl-rewrites2.smt2 diff --git a/test/regress/regress0/strings/ncontrib-rewrites.smt2 b/test/regress/regress0/strings/ncontrib-rewrites.smt2 new file mode 100644 index 000000000..6b2e68794 --- /dev/null +++ b/test/regress/regress0/strings/ncontrib-rewrites.smt2 @@ -0,0 +1,15 @@ +(set-logic ALL) +(set-info :status unsat) +(declare-fun x () String) +(declare-fun y () String) +(declare-fun z () String) + +(assert (or + +(not (= (str.replace (str.++ x x) "A" "B") (str.replace x "" (str.replace x "A" "B")))) + +(not (= (str.replace (str.++ x y "B" x y) "A" z) (str.++ (str.replace (str.++ x y) "A" z) "B" x y))) + +)) + +(check-sat) -- 2.30.2