Remove unwanted side effects in `SPLIT_EQ_STRIP_L` (#6689)
authorAndres Noetzli <andres.noetzli@gmail.com>
Sat, 5 Jun 2021 03:22:57 +0000 (20:22 -0700)
committerGitHub <noreply@github.com>
Sat, 5 Jun 2021 03:22:57 +0000 (03:22 +0000)
Fixes #6681. When checking whether SPLIT_EQ_STRIP_L applies, we were
using sripSymbolicLength, which changes its inputs depending on how
many elements of the concatenation it could strip. However, one of the
arguments, pfxv0, was reused across multiple checks if the strip did
not result in a rewrite. Later invocations were wrong as a result. This
commit changes the call to stripSymbolicLength() to use a new copy of
the vector instead.

src/theory/strings/sequences_rewriter.cpp
test/regress/CMakeLists.txt
test/regress/regress0/strings/issue6681-split-eq-strip-l.smt2 [new file with mode: 0644]

index 7ef1242c6dded7b6aeaa59088d288c326ee6eac1..f63b416ff812053f980b7a0022144a5b338f5e25 100644 (file)
@@ -437,7 +437,7 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
     size_t startRhs = 0;
     for (size_t i = 0, size0 = v0.size(); i <= size0; i++)
     {
-      std::vector<Node> pfxv0(v0.begin(), v0.begin() + i);
+      const std::vector<Node> pfxv0(v0.begin(), v0.begin() + i);
       Node pfx0 = utils::mkConcat(pfxv0, stype);
       for (size_t j = startRhs, size1 = v1.size(); j <= size1; j++)
       {
@@ -502,21 +502,22 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
             // Example:
             // (= (str.++ x "AB" z) (str.++ "A" x y)) --->
             //   (and (= (str.++ x "A") (str.++ "A" x)) (= (str.++ "B" z) y))
+            std::vector<Node> sfxv0 = pfxv0;
             std::vector<Node> rpfxv0;
             if (StringsEntail::stripSymbolicLength(
-                    pfxv0, rpfxv0, 1, lenPfx1, true))
+                    sfxv0, rpfxv0, 1, lenPfx1, true))
             {
               // The rewrite requires the full right-hand prefix length to be
               // stripped (otherwise we would have to keep parts of the
               // right-hand prefix).
               if (lenPfx1.isConst() && lenPfx1.getConst<Rational>().isZero())
               {
-                pfxv0.insert(pfxv0.end(), v0.begin() + i, v0.end());
+                sfxv0.insert(sfxv0.end(), v0.begin() + i, v0.end());
                 std::vector<Node> sfxv1(v1.begin() + j, v1.end());
                 Node ret =
                     nm->mkNode(kind::AND,
                                utils::mkConcat(rpfxv0, stype).eqNode(pfx1),
-                               utils::mkConcat(pfxv0, stype)
+                               utils::mkConcat(sfxv0, stype)
                                    .eqNode(utils::mkConcat(sfxv1, stype)));
                 return returnRewrite(node, ret, Rewrite::SPLIT_EQ_STRIP_L);
               }
index 707e5e43dc91f231b064b351f4416ac14fb99e1c..237ca77ddfdd0ef141acbb09bcfeb3790cfc141a 100644 (file)
@@ -1156,6 +1156,7 @@ set(regress_0_tests
   regress0/strings/issue6560-indexof-reduction.smt2
   regress0/strings/issue6604-re-elim.smt2
   regress0/strings/issue6643-ctn-decompose-conflict.smt2
+  regress0/strings/issue6681-split-eq-strip-l.smt2
   regress0/strings/itos-entail.smt2
   regress0/strings/large-model.smt2
   regress0/strings/leadingzero001.smt2
diff --git a/test/regress/regress0/strings/issue6681-split-eq-strip-l.smt2 b/test/regress/regress0/strings/issue6681-split-eq-strip-l.smt2
new file mode 100644 (file)
index 0000000..213d973
--- /dev/null
@@ -0,0 +1,8 @@
+(set-logic QF_SLIA)
+(declare-fun a () String)
+(declare-fun b () String)
+(declare-fun c () String)
+(declare-fun d () String)
+(assert (= (str.++ "A" a "CBA" b "BA" d) (str.++ b "BA" d a "CBA" c)))
+(set-info :status sat)
+(check-sat)