// 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());
Node CoreSolver::getDecomposeConclusion(Node x,
Node l,
bool isRev,
- bool addLenConc,
SkolemCache* skc,
std::vector<Node>& newSkolems)
{
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,
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)
{
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,
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:
// 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;
* 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.
static Node getDecomposeConclusion(Node x,
Node l,
bool isRev,
- bool addLenConc,
SkolemCache* skc,
std::vector<Node>& newSkolems);