summaryrefslogtreecommitdiff
path: root/src/theory
diff options
context:
space:
mode:
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>2021-02-22 14:15:43 -0600
committerGitHub <noreply@github.com>2021-02-22 14:15:43 -0600
commitddf647904de838e8e6ee266ad13de8a6a90250c8 (patch)
tree12105cab2b35dd303e04e7735d7923587b758af0 /src/theory
parent85d96c3668495fb087f059e5662072ae66d69e22 (diff)
Require length-in-conclusion form for strings inferences (#5953)
Previously, it was optional whether to put length constraints in conclusion for deq string inferences. However, due to optimizations in skolem caching, it is now required to guard these length constraints. It furthermore changes the policy to not ignore the lengths for the registered skolem, since it may be shared elsewhere. Fixes #5940. Notice that proof-new already requires this option to be enabled when proofs are enabled. Hence, this will simplify proof-new when merged.
Diffstat (limited to 'src/theory')
-rw-r--r--src/theory/strings/core_solver.cpp31
-rw-r--r--src/theory/strings/core_solver.h9
2 files changed, 12 insertions, 28 deletions
diff --git a/src/theory/strings/core_solver.cpp b/src/theory/strings/core_solver.cpp
index 7268a35e2..5446f67be 100644
--- a/src/theory/strings/core_solver.cpp
+++ b/src/theory/strings/core_solver.cpp
@@ -764,7 +764,7 @@ Node CoreSolver::getConclusion(Node x,
// make agnostic to x/y
conc = x < y ? nm->mkNode(OR, eq1, eq2) : nm->mkNode(OR, eq2, eq1);
}
- if (options::stringUnifiedVSpt() && options::stringLenConc())
+ if (options::stringUnifiedVSpt())
{
// we can assume its length is greater than zero
Node emp = Word::mkEmptyWord(sk1.getType());
@@ -842,7 +842,6 @@ size_t CoreSolver::getSufficientNonEmptyOverlap(Node c, Node d, bool isRev)
Node CoreSolver::getDecomposeConclusion(Node x,
Node l,
bool isRev,
- bool addLenConc,
SkolemCache* skc,
std::vector<Node>& newSkolems)
{
@@ -854,12 +853,9 @@ Node CoreSolver::getDecomposeConclusion(Node x,
Node sk2 = skc->mkSkolemCached(x, n, SkolemCache::SK_SUFFIX_REM, "dc_spt2");
newSkolems.push_back(sk2);
Node conc = x.eqNode(nm->mkNode(STRING_CONCAT, sk1, sk2));
- if (addLenConc)
- {
- Node lc = nm->mkNode(STRING_LENGTH, isRev ? sk2 : sk1).eqNode(l);
- conc = nm->mkNode(AND, conc, lc);
- }
- return conc;
+ // add the length constraint to the conclusion
+ Node lc = nm->mkNode(STRING_LENGTH, isRev ? sk2 : sk1).eqNode(l);
+ return nm->mkNode(AND, conc, lc);
}
void CoreSolver::getNormalForms(Node eqc,
@@ -1706,11 +1702,6 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
iinfo.setId(InferenceId::STRINGS_SSPLIT_VAR);
iinfo.d_conc =
getConclusion(x, y, PfRule::CONCAT_SPLIT, isRev, skc, newSkolems);
- if (options::stringUnifiedVSpt() && !options::stringLenConc())
- {
- Assert(newSkolems.size() == 1);
- iinfo.d_skolems[LENGTH_GEQ_ONE].push_back(newSkolems[0]);
- }
}
else if (lentTestSuccess == 0)
{
@@ -2180,16 +2171,8 @@ void CoreSolver::processDeq(Node ni, Node nj)
SkolemCache* skc = d_termReg.getSkolemCache();
std::vector<Node> newSkolems;
Node conc = getDecomposeConclusion(
- nck, d_one, false, options::stringLenConc(), skc, newSkolems);
+ nck, d_one, false, skc, newSkolems);
Assert(newSkolems.size() == 2);
- if (options::stringLenConc())
- {
- d_termReg.registerTermAtomic(newSkolems[0], LENGTH_IGNORE);
- }
- else
- {
- d_termReg.registerTermAtomic(newSkolems[0], LENGTH_ONE);
- }
std::vector<Node> antecLen;
antecLen.push_back(nm->mkNode(GEQ, nckLenTerm, d_one));
d_im.sendInference(antecLen,
@@ -2219,7 +2202,7 @@ void CoreSolver::processDeq(Node ni, Node nj)
Node uy = r == 0 ? y : x;
Node uxLen = nm->mkNode(STRING_LENGTH, ux);
Node uyLen = nm->mkNode(STRING_LENGTH, uy);
- // We always request the length constraint in the conclusion here
+ // We always add the length constraint in the conclusion here
// because the skolem needs to have length `uyLen`. If we only assert
// that the skolem's length is greater or equal to one, we can end up
// in a loop:
@@ -2232,7 +2215,7 @@ void CoreSolver::processDeq(Node ni, Node nj)
// variable. So we get `x` in the normal form again.
std::vector<Node> newSkolems;
Node conc =
- getDecomposeConclusion(ux, uyLen, false, true, skc, newSkolems);
+ getDecomposeConclusion(ux, uyLen, false, skc, newSkolems);
Assert(newSkolems.size() == 2);
d_termReg.registerTermAtomic(newSkolems[1], LENGTH_GEQ_ONE);
std::vector<Node> antecLen;
diff --git a/src/theory/strings/core_solver.h b/src/theory/strings/core_solver.h
index 8c4c28a96..a3909d11d 100644
--- a/src/theory/strings/core_solver.h
+++ b/src/theory/strings/core_solver.h
@@ -260,13 +260,15 @@ class CoreSolver
* a conjunction of splitting string x into pieces based on length l, e.g.:
* x = k_1 ++ k_2
* where k_1 (resp. k_2) is a skolem corresponding to a substring of x of
- * length l if isRev is false (resp. true). The function optionally adds a
- * length constraint len(k_1) = l (resp. len(k_2) = l).
+ * length l if isRev is false (resp. true). The function also adds a
+ * length constraint len(k_1) = l (resp. len(k_2) = l). Note that adding this
+ * constraint to the conclusion is *not* optional, since the skolems k_1 and
+ * k_2 may be shared, hence their length constraint must be guarded by the
+ * premises of this inference.
*
* @param x The string term
* @param l The length term
* @param isRev Whether the equation is in a reverse direction
- * @param addLenConc Whether to add the length constraint
* @param skc The skolem cache (to allocate fresh variables if necessary)
* @param newSkolems The vector to add new variables to
* @return The conclusion of the inference.
@@ -274,7 +276,6 @@ class CoreSolver
static Node getDecomposeConclusion(Node x,
Node l,
bool isRev,
- bool addLenConc,
SkolemCache* skc,
std::vector<Node>& newSkolems);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback