diff options
-rw-r--r-- | src/theory/strings/kinds | 4 | ||||
-rw-r--r-- | src/theory/strings/theory_strings.cpp | 15 | ||||
-rw-r--r-- | src/theory/strings/theory_strings.h | 2 | ||||
-rw-r--r-- | src/theory/strings/theory_strings_preprocess.cpp | 9 | ||||
-rw-r--r-- | src/theory/strings/theory_strings_rewriter.cpp | 61 | ||||
-rw-r--r-- | src/theory/strings/theory_strings_type_rules.h | 60 |
6 files changed, 148 insertions, 3 deletions
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds index df6085422..9629f0a8a 100644 --- a/src/theory/strings/kinds +++ b/src/theory/strings/kinds @@ -28,6 +28,8 @@ operator STRING_SUFFIX 2 "string suffixof" operator STRING_ITOS 1 "integer to string" operator STRING_STOI 1 "string to integer (total function)" operator STRING_CODE 1 "string to code, returns the code of the first character of the string if it has length one, -1 otherwise" +operator STRING_FST_OCC_PRE 2 "string prefixof" +operator STRING_FST_OCC_POST 2 "string suffixof" sort STRING_TYPE \ Cardinality::INTEGERS \ @@ -100,6 +102,8 @@ typerule STRING_SUFFIX ::CVC4::theory::strings::StringSuffixOfTypeRule typerule STRING_ITOS ::CVC4::theory::strings::StringIntToStrTypeRule typerule STRING_STOI ::CVC4::theory::strings::StringStrToIntTypeRule typerule STRING_CODE ::CVC4::theory::strings::StringStrToIntTypeRule +typerule STRING_FST_OCC_PRE ::CVC4::theory::strings::StringFstOccPreTypeRule +typerule STRING_FST_OCC_POST ::CVC4::theory::strings::StringFstOccPostTypeRule typerule STRING_IN_REGEXP ::CVC4::theory::strings::StringInRegExpTypeRule diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp index 5179ddab3..88fc3e36d 100644 --- a/src/theory/strings/theory_strings.cpp +++ b/src/theory/strings/theory_strings.cpp @@ -154,6 +154,8 @@ TheoryStrings::TheoryStrings(context::Context* c, d_equalityEngine.addFunctionKind(kind::STRING_CONCAT); d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP); d_equalityEngine.addFunctionKind(kind::STRING_CODE); + d_equalityEngine.addFunctionKind(kind::STRING_FST_OCC_PRE); + d_equalityEngine.addFunctionKind(kind::STRING_FST_OCC_POST); if( options::stringLazyPreproc() ){ d_equalityEngine.addFunctionKind(kind::STRING_STRCTN); d_equalityEngine.addFunctionKind(kind::STRING_LEQ); @@ -262,6 +264,14 @@ void TheoryStrings::setMasterEqualityEngine(eq::EqualityEngine* eq) { d_equalityEngine.setMasterEqualityEngine(eq); } +void TheoryStrings::finishInit() +{ + TheoryModel* tm = d_valuation.getModel(); + Assert(tm != nullptr); + tm->setSemiEvaluatedKind(kind::STRING_FST_OCC_PRE); + tm->setSemiEvaluatedKind(kind::STRING_FST_OCC_POST); +} + void TheoryStrings::addSharedTerm(TNode t) { Debug("strings") << "TheoryStrings::addSharedTerm(): " << t << " " << t.getType().isBoolean() << endl; @@ -480,6 +490,7 @@ bool TheoryStrings::doReduction(int effort, Node n, bool& isCd) << "Process reduction for " << n << ", pol = " << pol << std::endl; if (k == STRING_STRCTN && pol == 1) { + NodeManager* nm = NodeManager::currentNM(); Node x = n[0]; Node s = n[1]; // positive contains reduces to a equality @@ -487,7 +498,9 @@ bool TheoryStrings::doReduction(int effort, Node n, bool& isCd) d_sk_cache.mkSkolemCached(x, s, SkolemCache::SK_FIRST_CTN_PRE, "sc1"); Node sk2 = d_sk_cache.mkSkolemCached(x, s, SkolemCache::SK_FIRST_CTN_POST, "sc2"); - Node eq = Rewriter::rewrite(x.eqNode(mkConcat(sk1, s, sk2))); + Node sk1EqPre = sk1.eqNode(nm->mkNode(kind::STRING_FST_OCC_PRE, x, s)); + Node sk2EqPost = sk2.eqNode(nm->mkNode(kind::STRING_FST_OCC_POST, x, s)); + Node eq = Rewriter::rewrite(nm->mkNode(AND, x.eqNode(mkConcat(sk1, s, sk2)), sk1EqPre, sk2EqPost)); std::vector<Node> exp_vec; exp_vec.push_back(n); sendInference(d_empty_vec, exp_vec, eq, "POS-CTN", true); diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h index aa86f1bc1..8aa9bea6b 100644 --- a/src/theory/strings/theory_strings.h +++ b/src/theory/strings/theory_strings.h @@ -147,6 +147,8 @@ class TheoryStrings : public Theory { void setMasterEqualityEngine(eq::EqualityEngine* eq) override; + void finishInit() override; + std::string identify() const override { return std::string("TheoryStrings"); } public: diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp index d095d6801..8ee9e3afa 100644 --- a/src/theory/strings/theory_strings_preprocess.cpp +++ b/src/theory/strings/theory_strings_preprocess.cpp @@ -170,8 +170,10 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) { // ~contains( str.++( io2, substr( y, 0, len( y ) - 1) ), y ) ^ // skk = n + len( io2 ) // for fresh io2, io4. + Node io2EqPre = io2.eqNode(nm->mkNode(kind::STRING_FST_OCC_PRE, Rewriter::rewrite(st), Rewriter::rewrite(y))); + Node io4EqPost = io4.eqNode(nm->mkNode(kind::STRING_FST_OCC_POST, Rewriter::rewrite(st), Rewriter::rewrite(y))); Node rr = nm->mkNode(ITE, cond1, cc1, nm->mkNode(ITE, cond2, cc2, cc3)); - new_nodes.push_back( rr ); + new_nodes.push_back(nm->mkNode(AND, rr, io2EqPre, io4EqPost)); // Thus, indexof( x, y, n ) = skk. retNode = skk; @@ -390,6 +392,9 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) { y) .negate(); + Node rp1EqPre = rp1.eqNode(nm->mkNode(kind::STRING_FST_OCC_PRE, Rewriter::rewrite(x), Rewriter::rewrite(y))); + Node rp2EqPost = rp2.eqNode(nm->mkNode(kind::STRING_FST_OCC_POST, Rewriter::rewrite(x), Rewriter::rewrite(y))); + // assert: // IF y="" // THEN: rpw = str.++( z, x ) @@ -406,7 +411,7 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) { cond2, nm->mkNode(kind::AND, c21, c22, c23), rpw.eqNode(x))); - new_nodes.push_back( rr ); + new_nodes.push_back( nm->mkNode(AND, rr, rp1EqPre, rp2EqPost) ); // Thus, replace( x, y, z ) = rpw. retNode = rpw; diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp index 57a99532e..0841eb810 100644 --- a/src/theory/strings/theory_strings_rewriter.cpp +++ b/src/theory/strings/theory_strings_rewriter.cpp @@ -1497,6 +1497,59 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) { } } } + else if (nk == kind::STRING_FST_OCC_PRE) + { + Node empty = nm->mkConst(String("")); + if (node[0] == node[1]) + { + retNode = empty; + } + else if (node[1].isConst()) + { + if (node[1] == empty) + { + retNode = empty; + } + else if (node[0].isConst()) + { + String x = node[0].getConst<String>(); + String y = node[1].getConst<String>(); + + size_t i = x.find(y); + if (i != std::string::npos) + { + retNode = nm->mkConst(x.substr(0, i)); + } + } + } + } + else if (nk == kind::STRING_FST_OCC_POST) + { + Node empty = nm->mkConst(String("")); + if (node[0] == node[1]) + { + retNode = empty; + } + else if (node[1].isConst()) + { + if (node[1] == empty) + { + retNode = node[0]; + } + else if (node[0].isConst()) + { + String x = node[0].getConst<String>(); + String y = node[1].getConst<String>(); + + size_t i = x.find(y); + if (i != std::string::npos) + { + retNode = + nm->mkConst(x.substr(i + y.size(), x.size() - i - y.size())); + } + } + } + } else if (nk == kind::STRING_IN_REGEXP) { retNode = rewriteMembership(node); @@ -2224,6 +2277,14 @@ Node TheoryStringsRewriter::rewriteContains( Node node ) { } } } + else if (node[0].getKind() == kind::STRING_FST_OCC_PRE) + { + if (node[0][1] == node[1]) + { + Node ret = nm->mkConst(false); + return returnRewrite(node, ret, "ctn-fst-occ-pre-false"); + } + } if (node[1].getKind() == kind::STRING_STRREPL) { diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h index 9357a8f98..3e99add13 100644 --- a/src/theory/strings/theory_strings_type_rules.h +++ b/src/theory/strings/theory_strings_type_rules.h @@ -240,6 +240,66 @@ public: } }; +class StringFstOccPreTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { + TypeNode t = n[0].getType(check); + if (!t.isString()) + { + throw TypeCheckingExceptionPrivate( + n, + "expecting a string term as the first argument to first occurence " + "pre"); + } + t = n[1].getType(check); + if (!t.isString()) + { + throw TypeCheckingExceptionPrivate( + n, + "expecting a string term as the second argument to first occurence " + "pre"); + } + } + return nodeManager->stringType(); + } +}; + +class StringFstOccPostTypeRule +{ + public: + inline static TypeNode computeType(NodeManager* nodeManager, + TNode n, + bool check) + { + if (check) + { + TypeNode t = n[0].getType(check); + if (!t.isString()) + { + throw TypeCheckingExceptionPrivate( + n, + "expecting a string term as the first argument to first occurence " + "post"); + } + t = n[1].getType(check); + if (!t.isString()) + { + throw TypeCheckingExceptionPrivate( + n, + "expecting a string term as the second argument to first occurence " + "post"); + } + } + return nodeManager->stringType(); + } +}; + class RegExpConcatTypeRule { public: inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) |