summaryrefslogtreecommitdiff
path: root/src/theory/strings/term_registry.cpp
diff options
context:
space:
mode:
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>2020-06-19 17:40:18 -0500
committerGitHub <noreply@github.com>2020-06-19 17:40:18 -0500
commita517757f04e519259dde9ed7309168e7475354e3 (patch)
tree504775b98d19c878e5ec77119c623b006f5a6378 /src/theory/strings/term_registry.cpp
parent22780596b561dff9b0eb5b0620252280a678944e (diff)
(proof-new) Updates to strings term registry (#4599)
This makes it so that methods for constructing term registration lemmas are made into static methods, so that they can be used by both the term registry and proof checker.
Diffstat (limited to 'src/theory/strings/term_registry.cpp')
-rw-r--r--src/theory/strings/term_registry.cpp137
1 files changed, 85 insertions, 52 deletions
diff --git a/src/theory/strings/term_registry.cpp b/src/theory/strings/term_registry.cpp
index 90ebc4f8b..b4fbbed98 100644
--- a/src/theory/strings/term_registry.cpp
+++ b/src/theory/strings/term_registry.cpp
@@ -15,6 +15,7 @@
#include "theory/strings/term_registry.h"
#include "expr/attribute.h"
+#include "options/smt_options.h"
#include "options/strings_options.h"
#include "smt/logic_exception.h"
#include "theory/rewriter.h"
@@ -35,23 +36,25 @@ struct StringsProxyVarAttributeId
typedef expr::Attribute<StringsProxyVarAttributeId, bool>
StringsProxyVarAttribute;
-TermRegistry::TermRegistry(context::Context* c,
- context::UserContext* u,
+TermRegistry::TermRegistry(SolverState& s,
eq::EqualityEngine& ee,
OutputChannel& out,
- SequencesStatistics& statistics)
- : d_ee(ee),
+ SequencesStatistics& statistics,
+ ProofNodeManager* pnm)
+ : d_state(s),
+ d_ee(ee),
d_out(out),
d_statistics(statistics),
d_hasStrCode(false),
- d_functionsTerms(c),
- d_inputVars(u),
- d_preregisteredTerms(u),
- d_registeredTerms(u),
- d_registeredTypes(u),
- d_proxyVar(u),
- d_proxyVarToLength(u),
- d_lengthLemmaTermsCache(u)
+ d_functionsTerms(s.getSatContext()),
+ d_inputVars(s.getUserContext()),
+ d_preregisteredTerms(s.getUserContext()),
+ d_registeredTerms(s.getUserContext()),
+ d_registeredTypes(s.getUserContext()),
+ d_proxyVar(s.getUserContext()),
+ d_proxyVarToLength(s.getUserContext()),
+ d_lengthLemmaTermsCache(s.getUserContext()),
+ d_epg(nullptr)
{
NodeManager* nm = NodeManager::currentNM();
d_zero = nm->mkConst(Rational(0));
@@ -62,6 +65,64 @@ TermRegistry::TermRegistry(context::Context* c,
TermRegistry::~TermRegistry() {}
+Node TermRegistry::eagerReduce(Node t, SkolemCache* sc)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Node lemma;
+ Kind tk = t.getKind();
+ if (tk == STRING_TO_CODE)
+ {
+ // ite( str.len(s)==1, 0 <= str.code(s) < |A|, str.code(s)=-1 )
+ Node code_len = utils::mkNLength(t[0]).eqNode(nm->mkConst(Rational(1)));
+ Node code_eq_neg1 = t.eqNode(nm->mkConst(Rational(-1)));
+ Node code_range = nm->mkNode(
+ AND,
+ nm->mkNode(GEQ, t, nm->mkConst(Rational(0))),
+ nm->mkNode(
+ LT, t, nm->mkConst(Rational(utils::getAlphabetCardinality()))));
+ lemma = nm->mkNode(ITE, code_len, code_range, code_eq_neg1);
+ }
+ else if (tk == STRING_STRIDOF)
+ {
+ // (and (>= (str.indexof x y n) (- 1)) (<= (str.indexof x y n) (str.len
+ // x)))
+ Node l = utils::mkNLength(t[0]);
+ lemma = nm->mkNode(AND,
+ nm->mkNode(GEQ, t, nm->mkConst(Rational(-1))),
+ nm->mkNode(LEQ, t, l));
+ }
+ else if (tk == STRING_STOI)
+ {
+ // (>= (str.to_int x) (- 1))
+ lemma = nm->mkNode(GEQ, t, nm->mkConst(Rational(-1)));
+ }
+ else if (tk == STRING_STRCTN)
+ {
+ // ite( (str.contains s r), (= s (str.++ sk1 r sk2)), (not (= s r)))
+ Node sk1 =
+ sc->mkSkolemCached(t[0], t[1], SkolemCache::SK_FIRST_CTN_PRE, "sc1");
+ Node sk2 =
+ sc->mkSkolemCached(t[0], t[1], SkolemCache::SK_FIRST_CTN_POST, "sc2");
+ lemma = t[0].eqNode(utils::mkNConcat(sk1, t[1], sk2));
+ lemma = nm->mkNode(ITE, t, lemma, t[0].eqNode(t[1]).notNode());
+ }
+ return lemma;
+}
+
+Node TermRegistry::lengthPositive(Node t)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Node zero = nm->mkConst(Rational(0));
+ Node emp = Word::mkEmptyWord(t.getType());
+ Node tlen = nm->mkNode(STRING_LENGTH, t);
+ Node tlenEqZero = tlen.eqNode(zero);
+ Node tEqEmp = t.eqNode(emp);
+ Node caseEmpty = nm->mkNode(AND, tlenEqZero, tEqEmp);
+ Node caseNEmpty = nm->mkNode(GT, tlen, zero);
+ // (or (and (= (str.len t) 0) (= t "")) (> (str.len t) 0))
+ return nm->mkNode(OR, caseEmpty, caseNEmpty);
+}
+
void TermRegistry::preRegisterTerm(TNode n)
{
if (d_preregisteredTerms.find(n) != d_preregisteredTerms.end())
@@ -202,7 +263,6 @@ void TermRegistry::registerTerm(Node n, int effort)
d_registeredTerms.insert(n);
// ensure the type is registered
registerType(tn);
- NodeManager* nm = NodeManager::currentNM();
Debug("strings-register") << "TheoryStrings::registerTerm() " << n
<< ", effort = " << effort << std::endl;
Node regTermLem;
@@ -213,28 +273,10 @@ void TermRegistry::registerTerm(Node n, int effort)
// for concat/const/replace, introduce proxy var and state length relation
regTermLem = getRegisterTermLemma(n);
}
- else if (n.getKind() == STRING_TO_CODE)
- {
- // ite( str.len(s)==1, 0 <= str.code(s) < |A|, str.code(s)=-1 )
- Node code_len = utils::mkNLength(n[0]).eqNode(d_one);
- Node code_eq_neg1 = n.eqNode(d_negOne);
- Node code_range = nm->mkNode(
- AND,
- nm->mkNode(GEQ, n, d_zero),
- nm->mkNode(
- LT, n, nm->mkConst(Rational(utils::getAlphabetCardinality()))));
- regTermLem = nm->mkNode(ITE, code_len, code_range, code_eq_neg1);
- }
- else if (n.getKind() == STRING_STRIDOF)
+ else if (n.getKind() != STRING_STRCTN)
{
- Node len = utils::mkNLength(n[0]);
- regTermLem = nm->mkNode(AND,
- nm->mkNode(GEQ, n, nm->mkConst(Rational(-1))),
- nm->mkNode(LEQ, n, len));
- }
- else if (n.getKind() == STRING_STOI)
- {
- regTermLem = nm->mkNode(GEQ, n, nm->mkConst(Rational(-1)));
+ // we don't send out eager reduction lemma for str.contains currently
+ regTermLem = eagerReduce(n, &d_skCache);
}
if (!regTermLem.isNull())
{
@@ -324,7 +366,9 @@ Node TermRegistry::getRegisterTermLemma(Node n)
d_proxyVarToLength[sk] = lsum;
Node ceq = Rewriter::rewrite(skl.eqNode(lsum));
- return nm->mkNode(AND, eq, ceq);
+ Node ret = nm->mkNode(AND, eq, ceq);
+
+ return ret;
}
void TermRegistry::registerTermAtomic(Node n, LengthStatus s)
@@ -407,17 +451,15 @@ Node TermRegistry::getRegisterTermAtomicLemma(Node n,
}
Assert(s == LENGTH_SPLIT);
- std::vector<Node> lems;
+ // get the positive length lemma
+ Node lenLemma = lengthPositive(n);
// split whether the string is empty
Node n_len_eq_z = n_len.eqNode(d_zero);
Node n_len_eq_z_2 = n.eqNode(emp);
Node case_empty = nm->mkNode(AND, n_len_eq_z, n_len_eq_z_2);
- case_empty = Rewriter::rewrite(case_empty);
- Node case_nempty = nm->mkNode(GT, n_len, d_zero);
- if (!case_empty.isConst())
+ Node case_emptyr = Rewriter::rewrite(case_empty);
+ if (!case_emptyr.isConst())
{
- Node lem = nm->mkNode(OR, case_empty, case_nempty);
- lems.push_back(lem);
// prefer trying the empty case first
// notice that requirePhase must only be called on rewritten literals that
// occur in the CNF stream.
@@ -428,24 +470,15 @@ Node TermRegistry::getRegisterTermAtomicLemma(Node n,
Assert(!n_len_eq_z_2.isConst());
reqPhase[n_len_eq_z_2] = true;
}
- else if (!case_empty.getConst<bool>())
- {
- // the rewriter knows that n is non-empty
- lems.push_back(case_nempty);
- }
else
{
// If n = "" ---> true or len( n ) = 0 ----> true, then we expect that
// n ---> "". Since this method is only called on non-constants n, it must
// be that n = "" ^ len( n ) = 0 does not rewrite to true.
- Assert(false);
+ Assert(!case_emptyr.getConst<bool>());
}
- if (lems.empty())
- {
- return Node::null();
- }
- return lems.size() == 1 ? lems[0] : nm->mkNode(AND, lems);
+ return lenLemma;
}
Node TermRegistry::getSymbolicDefinition(Node n, std::vector<Node>& exp) const
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback