summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/theory/strings/core_solver.cpp64
-rw-r--r--src/theory/strings/extf_solver.cpp61
-rw-r--r--src/theory/strings/extf_solver.h4
-rw-r--r--src/theory/strings/infer_info.cpp17
-rw-r--r--src/theory/strings/infer_info.h17
-rw-r--r--src/theory/strings/inference_manager.cpp41
-rw-r--r--src/theory/strings/inference_manager.h48
-rw-r--r--src/theory/strings/regexp_solver.cpp61
-rw-r--r--src/theory/strings/theory_strings.cpp12
9 files changed, 198 insertions, 127 deletions
diff --git a/src/theory/strings/core_solver.cpp b/src/theory/strings/core_solver.cpp
index 438a559b8..371bb020f 100644
--- a/src/theory/strings/core_solver.cpp
+++ b/src/theory/strings/core_solver.cpp
@@ -440,7 +440,7 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
// is conflicting by arithmetic len(a.b)=len(a)+len(b)!=len(a)
// when len(b)!=0. Although if we do not infer this conflict eagerly,
// it may be applied (see #3272).
- d_im.sendInference(exp, conc, infType);
+ d_im.sendInference(exp, conc, infType, isRev);
if (d_state.isInConflict())
{
return;
@@ -1269,7 +1269,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// can infer that this string must be empty
Node eq = nfkv[index_k].eqNode(emp);
Assert(!d_state.areEqual(emp, nfkv[index_k]));
- d_im.sendInference(curr_exp, eq, Inference::N_ENDPOINT_EMP);
+ d_im.sendInference(curr_exp, eq, Inference::N_ENDPOINT_EMP, isRev);
index_k++;
}
break;
@@ -1312,7 +1312,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
if (x.isConst() && y.isConst())
{
// if both are constant, it's just a constant conflict
- d_im.sendInference(ant, d_false, Inference::N_CONST, true);
+ d_im.sendInference(ant, d_false, Inference::N_CONST, isRev, true);
return;
}
// `x` and `y` have the same length. We infer that the two components
@@ -1327,7 +1327,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// set the explanation for length
Node lant = utils::mkAnd(lenExp);
ant.push_back(lant);
- d_im.sendInference(ant, eq, Inference::N_UNIFY);
+ d_im.sendInference(ant, eq, Inference::N_UNIFY, isRev);
break;
}
else if ((!x.isConst() && index == nfiv.size() - rproc - 1)
@@ -1363,8 +1363,11 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
{
std::vector<Node> antec;
NormalForm::getExplanationForPrefixEq(nfi, nfj, -1, -1, antec);
- d_im.sendInference(
- antec, eqn[0].eqNode(eqn[1]), Inference::N_ENDPOINT_EQ, true);
+ d_im.sendInference(antec,
+ eqn[0].eqNode(eqn[1]),
+ Inference::N_ENDPOINT_EQ,
+ isRev,
+ true);
}
else
{
@@ -1424,7 +1427,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// E.g. "abc" ++ ... = "bc" ++ ... ---> conflict
std::vector<Node> antec;
NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, antec);
- d_im.sendInference(antec, d_false, Inference::N_CONST, true);
+ d_im.sendInference(antec, d_false, Inference::N_CONST, isRev, true);
break;
}
}
@@ -1466,8 +1469,11 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
if (detectLoop(nfi, nfj, index, lhsLoopIdx, rhsLoopIdx, rproc))
{
// We are dealing with a looping word equation.
+ // Note we could make this code also run in the reverse direction, but
+ // this is not implemented currently.
if (!isRev)
- { // FIXME
+ {
+ // add temporarily to the antecedant of iinfo.
NormalForm::getExplanationForPrefixEq(nfi, nfj, -1, -1, iinfo.d_ant);
ProcessLoopResult plr =
processLoop(lhsLoopIdx != -1 ? nfi : nfj,
@@ -1485,6 +1491,8 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
break;
}
Assert(plr == ProcessLoopResult::SKIPPED);
+ // not processing an inference here, undo changes to ant
+ iinfo.d_ant.clear();
}
}
@@ -1637,13 +1645,20 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
<< " explanation was : " << et.second << std::endl;
lentTestSuccess = e;
lenConstraint = entLit;
- // its not explained by the equality engine of this class
- iinfo.d_antn.push_back(lenConstraint);
+ // Its not explained by the equality engine of this class, so its
+ // marked as not being explained. The length constraint is
+ // additionally being saved and added to the length constraint
+ // vector lcVec below, which is added to iinfo.d_ant below. Length
+ // constraints are being added as the last antecedant for the sake
+ // of proof reconstruction, which expect length constraints to come
+ // last.
+ iinfo.d_noExplain.push_back(lenConstraint);
break;
}
}
}
}
+ // lcVec stores the length constraint portion of the antecedant.
std::vector<Node> lcVec;
if (lenConstraint.isNull())
{
@@ -1651,6 +1666,10 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
lenConstraint = nm->mkNode(EQUAL, xLenTerm, yLenTerm).negate();
lcVec.push_back(lenConstraint);
}
+ else
+ {
+ utils::flattenOp(AND, lenConstraint, lcVec);
+ }
NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, iinfo.d_ant);
// Add premises for x != "" ^ y != ""
@@ -1665,8 +1684,8 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
else
{
tnz = x.eqNode(emp).negate();
- // lcVec.push_back(tnz);
- iinfo.d_antn.push_back(tnz);
+ lcVec.push_back(tnz);
+ iinfo.d_noExplain.push_back(tnz);
}
}
SkolemCache* skc = d_termReg.getSkolemCache();
@@ -1696,6 +1715,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
iinfo.d_conc =
getConclusion(y, x, PfRule::CONCAT_LPROP, isRev, skc, newSkolems);
}
+ // add the length constraint(s) as the last antecedant
Node lc = utils::mkAnd(lcVec);
iinfo.d_ant.push_back(lc);
iinfo.d_idRev = isRev;
@@ -1804,7 +1824,8 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
{
Trace("strings-loop") << "Strings::Loop: tails are different."
<< std::endl;
- d_im.sendInference(iinfo.d_ant, conc, Inference::FLOOP_CONFLICT, true);
+ d_im.sendInference(
+ iinfo.d_ant, conc, Inference::FLOOP_CONFLICT, false, true);
return ProcessLoopResult::CONFLICT;
}
}
@@ -1821,6 +1842,8 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
Node expNonEmpty = d_state.explainNonEmpty(t);
if (expNonEmpty.isNull())
{
+ // no antecedants necessary
+ iinfo.d_ant.clear();
// try to make t equal to empty to avoid loop
iinfo.d_conc = nm->mkNode(kind::OR, split_eq, split_eq.negate());
iinfo.d_id = Inference::LEN_SPLIT_EMP;
@@ -2098,10 +2121,11 @@ void CoreSolver::processDeq(Node ni, Node nj)
}
std::vector<Node> antecLen;
antecLen.push_back(nm->mkNode(GEQ, nckLenTerm, d_one));
- d_im.sendInference({},
+ d_im.sendInference(antecLen,
antecLen,
conc,
Inference::DEQ_DISL_FIRST_CHAR_STRING_SPLIT,
+ false,
true);
return;
}
@@ -2142,8 +2166,12 @@ void CoreSolver::processDeq(Node ni, Node nj)
d_termReg.registerTermAtomic(newSkolems[1], LENGTH_GEQ_ONE);
std::vector<Node> antecLen;
antecLen.push_back(nm->mkNode(GT, uxLen, uyLen));
- d_im.sendInference(
- {}, antecLen, conc, Inference::DEQ_DISL_STRINGS_SPLIT, true);
+ d_im.sendInference(antecLen,
+ antecLen,
+ conc,
+ Inference::DEQ_DISL_STRINGS_SPLIT,
+ false,
+ true);
}
return;
@@ -2238,7 +2266,7 @@ bool CoreSolver::processSimpleDeq(std::vector<Node>& nfi,
Node conc = cc.size() == 1
? cc[0]
: NodeManager::currentNM()->mkNode(kind::AND, cc);
- d_im.sendInference(ant, conc, Inference::DEQ_NORM_EMP, true);
+ d_im.sendInference(ant, conc, Inference::DEQ_NORM_EMP, isRev, true);
return true;
}
@@ -2523,7 +2551,7 @@ void CoreSolver::checkLengthsEqc() {
{
Node eq = llt.eqNode(lc);
ei->d_normalizedLength.set(eq);
- d_im.sendInference(ant, eq, Inference::LEN_NORM, true);
+ d_im.sendInference(ant, eq, Inference::LEN_NORM, false, true);
}
}
}
diff --git a/src/theory/strings/extf_solver.cpp b/src/theory/strings/extf_solver.cpp
index eff0b3d74..b028da38a 100644
--- a/src/theory/strings/extf_solver.cpp
+++ b/src/theory/strings/extf_solver.cpp
@@ -27,9 +27,7 @@ namespace CVC4 {
namespace theory {
namespace strings {
-ExtfSolver::ExtfSolver(context::Context* c,
- context::UserContext* u,
- SolverState& s,
+ExtfSolver::ExtfSolver(SolverState& s,
InferenceManager& im,
TermRegistry& tr,
StringsRewriter& rewriter,
@@ -45,10 +43,10 @@ ExtfSolver::ExtfSolver(context::Context* c,
d_csolver(cs),
d_extt(et),
d_statistics(statistics),
- d_preproc(d_termReg.getSkolemCache(), u, statistics),
- d_hasExtf(c, false),
- d_extfInferCache(c),
- d_reduced(u)
+ d_preproc(d_termReg.getSkolemCache(), s.getUserContext(), statistics),
+ d_hasExtf(s.getSatContext(), false),
+ d_extfInferCache(s.getSatContext()),
+ d_reduced(s.getUserContext())
{
d_extt.addFunctionKind(kind::STRING_SUBSTR);
d_extt.addFunctionKind(kind::STRING_UPDATE);
@@ -128,7 +126,8 @@ bool ExtfSolver::doReduction(int effort, Node n)
lexp.push_back(lenx.eqNode(lens));
lexp.push_back(n.negate());
Node xneqs = x.eqNode(s).negate();
- d_im.sendInference(lexp, xneqs, Inference::CTN_NEG_EQUAL, true);
+ d_im.sendInference(
+ lexp, xneqs, Inference::CTN_NEG_EQUAL, false, true);
}
// this depends on the current assertions, so this
// inference is context-dependent
@@ -169,12 +168,13 @@ bool ExtfSolver::doReduction(int effort, Node n)
Node s = n[1];
// positive contains reduces to a equality
SkolemCache* skc = d_termReg.getSkolemCache();
- Node sk1 = skc->mkSkolemCached(x, s, SkolemCache::SK_FIRST_CTN_PRE, "sc1");
- Node sk2 = skc->mkSkolemCached(x, s, SkolemCache::SK_FIRST_CTN_POST, "sc2");
- Node eq = Rewriter::rewrite(x.eqNode(utils::mkNConcat(sk1, s, sk2)));
- std::vector<Node> exp_vec;
- exp_vec.push_back(n);
- d_im.sendInference(d_emptyVec, exp_vec, eq, Inference::CTN_POS, true);
+ Node eq = d_termReg.eagerReduce(n, skc);
+ Assert(!eq.isNull());
+ Assert(eq.getKind() == ITE && eq[0] == n);
+ eq = eq[1];
+ std::vector<Node> expn;
+ expn.push_back(n);
+ d_im.sendInference(expn, expn, eq, Inference::CTN_POS, false, true);
Trace("strings-extf-debug")
<< " resolve extf : " << n << " based on positive contain reduction."
<< std::endl;
@@ -195,14 +195,13 @@ bool ExtfSolver::doReduction(int effort, Node n)
std::vector<Node> new_nodes;
Node res = d_preproc.simplify(n, new_nodes);
Assert(res != n);
- new_nodes.push_back(res.eqNode(n));
+ new_nodes.push_back(n.eqNode(res));
Node nnlem =
new_nodes.size() == 1 ? new_nodes[0] : nm->mkNode(AND, new_nodes);
- nnlem = Rewriter::rewrite(nnlem);
Trace("strings-red-lemma")
<< "Reduction_" << effort << " lemma : " << nnlem << std::endl;
Trace("strings-red-lemma") << "...from " << n << std::endl;
- d_im.sendInference(d_emptyVec, nnlem, Inference::REDUCTION, true);
+ d_im.sendInference(d_emptyVec, nnlem, Inference::REDUCTION, false, true);
Trace("strings-extf-debug")
<< " resolve extf : " << n << " based on reduction." << std::endl;
// add as reduction lemma
@@ -277,7 +276,8 @@ void ExtfSolver::checkExtfEval(int effort)
}
// If there is information involving the children, attempt to do an
// inference and/or mark n as reduced.
- Node to_reduce;
+ bool reduced = false;
+ Node to_reduce = n;
if (schanged)
{
Node sn = nm->mkNode(n.getKind(), schildren);
@@ -383,7 +383,7 @@ void ExtfSolver::checkExtfEval(int effort)
Trace("strings-extf")
<< " resolve extf : " << sn << " -> " << nrc << std::endl;
Inference inf = effort == 0 ? Inference::EXTF : Inference::EXTF_N;
- d_im.sendInference(einfo.d_exp, conc, inf, true);
+ d_im.sendInference(einfo.d_exp, conc, inf, false, true);
d_statistics.d_cdSimplifications << n.getKind();
if (d_state.isInConflict())
{
@@ -404,6 +404,7 @@ void ExtfSolver::checkExtfEval(int effort)
einfo.d_modelActive = false;
}
}
+ reduced = true;
}
else
{
@@ -427,28 +428,26 @@ void ExtfSolver::checkExtfEval(int effort)
effort == 0 ? Inference::EXTF_D : Inference::EXTF_D_N;
d_im.sendInternalInference(einfo.d_exp, nrcAssert, infer);
}
- // We must use the original n here to avoid circular justifications for
- // why extended functions are reduced below. In particular, to_reduce
- // should never be a duplicate of another term considered in the block
- // of code for checkExtfInference below.
- to_reduce = n;
+ to_reduce = nrc;
}
}
- else
- {
- to_reduce = n;
- }
+ // We must use the original n here to avoid circular justifications for
+ // why extended functions are reduced. In particular, n should never be a
+ // duplicate of another term considered in the block of code for
+ // checkExtfInference below.
// if not reduced and not processed
- if (!to_reduce.isNull()
- && inferProcessed.find(to_reduce) == inferProcessed.end())
+ if (!reduced && !n.isNull()
+ && inferProcessed.find(n) == inferProcessed.end())
{
- inferProcessed.insert(to_reduce);
+ inferProcessed.insert(n);
Assert(effort < 3);
if (effort == 1)
{
Trace("strings-extf")
<< " cannot rewrite extf : " << to_reduce << std::endl;
}
+ // we take to_reduce to be the (partially) reduced version of n, which
+ // is justified by the explanation in einfo.
checkExtfInference(n, to_reduce, einfo, effort);
if (Trace.isOn("strings-extf-list"))
{
diff --git a/src/theory/strings/extf_solver.h b/src/theory/strings/extf_solver.h
index 80921550e..4ba38bfc6 100644
--- a/src/theory/strings/extf_solver.h
+++ b/src/theory/strings/extf_solver.h
@@ -83,9 +83,7 @@ class ExtfSolver
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
public:
- ExtfSolver(context::Context* c,
- context::UserContext* u,
- SolverState& s,
+ ExtfSolver(SolverState& s,
InferenceManager& im,
TermRegistry& tr,
StringsRewriter& rewriter,
diff --git a/src/theory/strings/infer_info.cpp b/src/theory/strings/infer_info.cpp
index 174bbe2b7..ca5e8320d 100644
--- a/src/theory/strings/infer_info.cpp
+++ b/src/theory/strings/infer_info.cpp
@@ -14,6 +14,8 @@
#include "theory/strings/infer_info.h"
+#include "theory/strings/theory_strings_utils.h"
+
namespace CVC4 {
namespace theory {
namespace strings {
@@ -85,6 +87,7 @@ const char* toString(Inference i)
case Inference::CTN_NEG_EQUAL: return "CTN_NEG_EQUAL";
case Inference::CTN_POS: return "CTN_POS";
case Inference::REDUCTION: return "REDUCTION";
+ case Inference::PREFIX_CONFLICT: return "PREFIX_CONFLICT";
default: return "?";
}
}
@@ -106,14 +109,20 @@ bool InferInfo::isTrivial() const
bool InferInfo::isConflict() const
{
Assert(!d_conc.isNull());
- return d_conc.isConst() && !d_conc.getConst<bool>() && d_antn.empty();
+ return d_conc.isConst() && !d_conc.getConst<bool>() && d_noExplain.empty();
}
bool InferInfo::isFact() const
{
Assert(!d_conc.isNull());
TNode atom = d_conc.getKind() == kind::NOT ? d_conc[0] : d_conc;
- return !atom.isConst() && atom.getKind() != kind::OR && d_antn.empty();
+ return !atom.isConst() && atom.getKind() != kind::OR && d_noExplain.empty();
+}
+
+Node InferInfo::getAntecedant() const
+{
+ // d_noExplain is a subset of d_ant
+ return utils::mkAnd(d_ant);
}
std::ostream& operator<<(std::ostream& out, const InferInfo& ii)
@@ -127,9 +136,9 @@ std::ostream& operator<<(std::ostream& out, const InferInfo& ii)
{
out << " :ant (" << ii.d_ant << ")";
}
- if (!ii.d_antn.empty())
+ if (!ii.d_noExplain.empty())
{
- out << " :antn (" << ii.d_antn << ")";
+ out << " :no-explain (" << ii.d_noExplain << ")";
}
out << ")";
return out;
diff --git a/src/theory/strings/infer_info.h b/src/theory/strings/infer_info.h
index 7d41dca98..31a74784e 100644
--- a/src/theory/strings/infer_info.h
+++ b/src/theory/strings/infer_info.h
@@ -38,6 +38,7 @@ namespace strings {
*/
enum class Inference : uint32_t
{
+ BEGIN,
//-------------------------------------- base solver
// initial normalize singular
// x1 = "" ^ ... ^ x_{i-1} = "" ^ x_{i+1} = "" ^ ... ^ xn = "" =>
@@ -295,6 +296,10 @@ enum class Inference : uint32_t
// (see theory_strings_preprocess).
REDUCTION,
//-------------------------------------- end extended function solver
+ //-------------------------------------- prefix conflict
+ // prefix conflict (coarse-grained)
+ PREFIX_CONFLICT,
+ //-------------------------------------- end prefix conflict
NONE,
};
@@ -359,9 +364,11 @@ class InferInfo
/**
* The "new literal" antecedant(s) of the inference, interpreted
* conjunctively. These are literals that were needed to show the conclusion
- * but do not currently hold in the equality engine.
+ * but do not currently hold in the equality engine. These should be a subset
+ * of d_ant. In other words, antecedants that are not explained are stored
+ * in *both* d_ant and d_noExplain.
*/
- std::vector<Node> d_antn;
+ std::vector<Node> d_noExplain;
/**
* A list of new skolems introduced as a result of this inference. They
* are mapped to by a length status, indicating the length constraint that
@@ -372,15 +379,17 @@ class InferInfo
bool isTrivial() const;
/**
* Does this infer info correspond to a conflict? True if d_conc is false
- * and it has no new antecedants (d_antn).
+ * and it has no new antecedants (d_noExplain).
*/
bool isConflict() const;
/**
* Does this infer info correspond to a "fact". A fact is an inference whose
* conclusion should be added as an equality or predicate to the equality
- * engine with no new external antecedants (d_antn).
+ * engine with no new external antecedants (d_noExplain).
*/
bool isFact() const;
+ /** Get antecedant */
+ Node getAntecedant() const;
};
/**
diff --git a/src/theory/strings/inference_manager.cpp b/src/theory/strings/inference_manager.cpp
index 91af2a434..88cf6d958 100644
--- a/src/theory/strings/inference_manager.cpp
+++ b/src/theory/strings/inference_manager.cpp
@@ -117,9 +117,10 @@ bool InferenceManager::sendInternalInference(std::vector<Node>& exp,
}
void InferenceManager::sendInference(const std::vector<Node>& exp,
- const std::vector<Node>& expn,
+ const std::vector<Node>& noExplain,
Node eq,
Inference infer,
+ bool isRev,
bool asLemma)
{
eq = eq.isNull() ? d_false : Rewriter::rewrite(eq);
@@ -130,19 +131,21 @@ void InferenceManager::sendInference(const std::vector<Node>& exp,
// wrap in infer info and send below
InferInfo ii;
ii.d_id = infer;
+ ii.d_idRev = isRev;
ii.d_conc = eq;
ii.d_ant = exp;
- ii.d_antn = expn;
+ ii.d_noExplain = noExplain;
sendInference(ii, asLemma);
}
void InferenceManager::sendInference(const std::vector<Node>& exp,
Node eq,
Inference infer,
+ bool isRev,
bool asLemma)
{
- std::vector<Node> expn;
- sendInference(exp, expn, eq, infer, asLemma);
+ std::vector<Node> noExplain;
+ sendInference(exp, noExplain, eq, infer, isRev, asLemma);
}
void InferenceManager::sendInference(const InferInfo& ii, bool asLemma)
@@ -277,7 +280,7 @@ void InferenceManager::doPendingFacts()
InferInfo& ii = d_pending[i];
// At this point, ii should be a "fact", i.e. something whose conclusion
// should be added as a normal equality or predicate to the equality engine
- // with no new external assumptions (ii.d_antn).
+ // with no new external assumptions (ii.d_noExplain).
Assert(ii.isFact());
Node facts = ii.d_conc;
Node exp = utils::mkAnd(ii.d_ant);
@@ -336,13 +339,12 @@ void InferenceManager::doPendingLemmas()
Node eqExp;
if (options::stringRExplainLemmas())
{
- eqExp = mkExplain(ii.d_ant, ii.d_antn);
+ eqExp = mkExplain(ii.d_ant, ii.d_noExplain);
}
else
{
std::vector<Node> ev;
ev.insert(ev.end(), ii.d_ant.begin(), ii.d_ant.end());
- ev.insert(ev.end(), ii.d_antn.begin(), ii.d_antn.end());
eqExp = utils::mkAnd(ev);
}
// make the lemma node
@@ -455,12 +457,12 @@ bool InferenceManager::hasProcessed() const
Node InferenceManager::mkExplain(const std::vector<Node>& a) const
{
- std::vector<Node> an;
- return mkExplain(a, an);
+ std::vector<Node> noExplain;
+ return mkExplain(a, noExplain);
}
Node InferenceManager::mkExplain(const std::vector<Node>& a,
- const std::vector<Node>& an) const
+ const std::vector<Node>& noExplain) const
{
std::vector<TNode> antec_exp;
// copy to processing vector
@@ -472,6 +474,16 @@ Node InferenceManager::mkExplain(const std::vector<Node>& a,
eq::EqualityEngine* ee = d_state.getEqualityEngine();
for (const Node& apc : aconj)
{
+ if (std::find(noExplain.begin(), noExplain.end(), apc) != noExplain.end())
+ {
+ if (std::find(antec_exp.begin(), antec_exp.end(), apc) == antec_exp.end())
+ {
+ Debug("strings-explain")
+ << "Add to explanation (new literal) " << apc << std::endl;
+ antec_exp.push_back(apc);
+ }
+ continue;
+ }
Assert(apc.getKind() != AND);
Debug("strings-explain") << "Add to explanation " << apc << std::endl;
if (apc.getKind() == NOT && apc[0].getKind() == EQUAL)
@@ -485,15 +497,6 @@ Node InferenceManager::mkExplain(const std::vector<Node>& a,
// now, explain
explain(apc, antec_exp);
}
- for (const Node& anc : an)
- {
- if (std::find(antec_exp.begin(), antec_exp.end(), anc) == antec_exp.end())
- {
- Debug("strings-explain")
- << "Add to explanation (new literal) " << anc << std::endl;
- antec_exp.push_back(anc);
- }
- }
Node ant;
if (antec_exp.empty())
{
diff --git a/src/theory/strings/inference_manager.h b/src/theory/strings/inference_manager.h
index 4e50a6cb7..016891737 100644
--- a/src/theory/strings/inference_manager.h
+++ b/src/theory/strings/inference_manager.h
@@ -109,26 +109,27 @@ class InferenceManager
bool sendInternalInference(std::vector<Node>& exp,
Node conc,
Inference infer);
+
/** send inference
*
- * This function should be called when ( exp ^ exp_n ) => eq. The set exp
+ * This function should be called when exp => eq. The set exp
* contains literals that are explainable, i.e. those that hold in the
* equality engine of the theory of strings. On the other hand, the set
- * exp_n ("explanations new") contain nodes that are not explainable by the
- * theory of strings. This method may call sendLemma or otherwise add a
- * InferInfo to d_pending, indicating a fact should be asserted to the
- * equality engine. Overall, the result of this method is one of the
- * following:
+ * noExplain contains nodes that are not explainable by the theory of strings.
+ * This method may call sendLemma or otherwise add a InferInfo to d_pending,
+ * indicating a fact should be asserted to the equality engine. Overall, the
+ * result of this method is one of the following:
*
- * [1] (No-op) Do nothing if eq is true,
+ * [1] (No-op) Do nothing if eq is equivalent to true,
*
* [2] (Infer) Indicate that eq should be added to the equality engine of this
* class with explanation exp, where exp is a set of literals that currently
* hold in the equality engine. We add this to the pending vector d_pending.
*
- * [3] (Lemma) Indicate that the lemma ( EXPLAIN(exp) ^ exp_n ) => eq should
- * be sent on the output channel of the theory of strings, where EXPLAIN
- * returns the explanation of the node in exp in terms of the literals
+ * [3] (Lemma) Indicate that the lemma
+ * ( EXPLAIN(exp \ noExplain) ^ noExplain ) => eq
+ * should be sent on the output channel of the theory of strings, where
+ * EXPLAIN returns the explanation of the node in exp in terms of the literals
* asserted to the theory of strings, as computed by the equality engine.
* This is also added to a pending vector, d_pendingLem.
*
@@ -136,25 +137,33 @@ class InferenceManager
* channel of the theory of strings.
*
* Determining which case to apply depends on the form of eq and whether
- * exp_n is empty. In particular, lemmas must be used whenever exp_n is
- * non-empty, conflicts are used when exp_n is empty and eq is false.
+ * noExplain is empty. In particular, lemmas must be used whenever noExplain
+ * is non-empty, conflicts are used when noExplain is empty and eq is false.
*
- * The argument infer identifies the reason for inference, used for
+ * @param exp The explanation of eq.
+ * @param noExplain The subset of exp that cannot be explained by the
+ * equality engine. This may impact whether we are processing this call as a
+ * fact or as a lemma.
+ * @param eq The conclusion.
+ * @param infer Identifies the reason for inference, used for
* debugging. This updates the statistics about the number of inferences made
* of each type.
- *
- * If the flag asLemma is true, then this method will send a lemma instead
+ * @param isRev Whether this is the "reverse variant" of the inference, which
+ * is used as a hint for proof reconstruction.
+ * @param asLemma If true, then this method will send a lemma instead
* of a fact whenever applicable.
*/
void sendInference(const std::vector<Node>& exp,
- const std::vector<Node>& exp_n,
+ const std::vector<Node>& noExplain,
Node eq,
Inference infer,
+ bool isRev = false,
bool asLemma = false);
- /** same as above, but where exp_n is empty */
+ /** same as above, but where noExplain is empty */
void sendInference(const std::vector<Node>& exp,
Node eq,
Inference infer,
+ bool isRev = false,
bool asLemma = false);
/** Send inference
@@ -258,8 +267,9 @@ class InferenceManager
* that have been asserted to the equality engine.
*/
Node mkExplain(const std::vector<Node>& a) const;
- /** Same as above, but the new literals an are append to the result */
- Node mkExplain(const std::vector<Node>& a, const std::vector<Node>& an) const;
+ /** Same as above, but with a subset noExplain that should not be explained */
+ Node mkExplain(const std::vector<Node>& a,
+ const std::vector<Node>& noExplain) const;
/**
* Explain literal l, add conjuncts to assumptions vector instead of making
* the node corresponding to their conjunction.
diff --git a/src/theory/strings/regexp_solver.cpp b/src/theory/strings/regexp_solver.cpp
index c5d6df601..62127d5c0 100644
--- a/src/theory/strings/regexp_solver.cpp
+++ b/src/theory/strings/regexp_solver.cpp
@@ -221,10 +221,13 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
else
{
// we have a conflict
- std::vector<Node> exp_n;
- exp_n.push_back(assertion);
+ std::vector<Node> iexp = nfexp;
+ std::vector<Node> noExplain;
+ iexp.push_back(assertion);
+ noExplain.push_back(assertion);
Node conc = Node::null();
- d_im.sendInference(nfexp, exp_n, conc, Inference::RE_NF_CONFLICT);
+ d_im.sendInference(
+ iexp, noExplain, conc, Inference::RE_NF_CONFLICT);
addedLemma = true;
break;
}
@@ -266,8 +269,10 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
// if simplifying successfully generated a lemma
if (!conc.isNull())
{
- std::vector<Node> exp_n;
- exp_n.push_back(assertion);
+ std::vector<Node> iexp = rnfexp;
+ std::vector<Node> noExplain;
+ iexp.push_back(assertion);
+ noExplain.push_back(assertion);
Assert(atom.getKind() == STRING_IN_REGEXP);
if (polarity)
{
@@ -279,7 +284,7 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
}
Inference inf =
polarity ? Inference::RE_UNFOLD_POS : Inference::RE_UNFOLD_NEG;
- d_im.sendInference(rnfexp, exp_n, conc, inf);
+ d_im.sendInference(iexp, noExplain, conc, inf);
addedLemma = true;
if (changed)
{
@@ -399,7 +404,7 @@ bool RegExpSolver::checkEqcInclusion(std::vector<Node>& mems)
Node conc;
d_im.sendInference(
- vec_nodes, conc, Inference::RE_INTER_INCLUDE, true);
+ vec_nodes, conc, Inference::RE_INTER_INCLUDE, false, true);
return false;
}
}
@@ -480,19 +485,21 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
vec_nodes.push_back(mi[0].eqNode(m[0]));
}
Node conc;
- d_im.sendInference(vec_nodes, conc, Inference::RE_INTER_CONF, true);
+ d_im.sendInference(
+ vec_nodes, conc, Inference::RE_INTER_CONF, false, true);
// conflict, return
return false;
}
// rewrite to ensure the equality checks below are precise
- Node mres = Rewriter::rewrite(nm->mkNode(STRING_IN_REGEXP, mi[0], resR));
- if (mres == mi)
+ Node mres = nm->mkNode(STRING_IN_REGEXP, mi[0], resR);
+ Node mresr = Rewriter::rewrite(mres);
+ if (mresr == mi)
{
// if R1 = intersect( R1, R2 ), then x in R1 ^ x in R2 is equivalent
// to x in R1, hence x in R2 can be marked redundant.
d_im.markReduced(m);
}
- else if (mres == m)
+ else if (mresr == m)
{
// same as above, opposite direction
d_im.markReduced(mi);
@@ -508,7 +515,8 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
{
vec_nodes.push_back(mi[0].eqNode(m[0]));
}
- d_im.sendInference(vec_nodes, mres, Inference::RE_INTER_INFER, true);
+ d_im.sendInference(
+ vec_nodes, mres, Inference::RE_INTER_INFER, false, true);
// both are reduced
d_im.markReduced(m);
d_im.markReduced(mi);
@@ -529,10 +537,12 @@ bool RegExpSolver::checkPDerivative(
{
case 0:
{
- std::vector<Node> exp_n;
- exp_n.push_back(atom);
- exp_n.push_back(x.eqNode(d_emptyString));
- d_im.sendInference(nf_exp, exp_n, exp, Inference::RE_DELTA);
+ std::vector<Node> noExplain;
+ noExplain.push_back(atom);
+ noExplain.push_back(x.eqNode(d_emptyString));
+ std::vector<Node> iexp = nf_exp;
+ iexp.insert(iexp.end(), noExplain.begin(), noExplain.end());
+ d_im.sendInference(iexp, noExplain, exp, Inference::RE_DELTA);
addedLemma = true;
d_regexp_ccached.insert(atom);
return false;
@@ -544,11 +554,12 @@ bool RegExpSolver::checkPDerivative(
}
case 2:
{
- std::vector<Node> exp_n;
- exp_n.push_back(atom);
- exp_n.push_back(x.eqNode(d_emptyString));
- Node conc;
- d_im.sendInference(nf_exp, exp_n, conc, Inference::RE_DELTA_CONF);
+ std::vector<Node> noExplain;
+ noExplain.push_back(atom);
+ noExplain.push_back(x.eqNode(d_emptyString));
+ std::vector<Node> iexp = nf_exp;
+ iexp.insert(iexp.end(), noExplain.begin(), noExplain.end());
+ d_im.sendInference(iexp, noExplain, d_false, Inference::RE_DELTA_CONF);
addedLemma = true;
d_regexp_ccached.insert(atom);
return false;
@@ -637,9 +648,11 @@ bool RegExpSolver::deriveRegExp(Node x,
conc = NodeManager::currentNM()->mkNode(STRING_IN_REGEXP, left, dc);
}
}
- std::vector<Node> exp_n;
- exp_n.push_back(atom);
- d_im.sendInference(ant, exp_n, conc, Inference::RE_DERIVE);
+ std::vector<Node> iexp = ant;
+ std::vector<Node> noExplain;
+ noExplain.push_back(atom);
+ iexp.push_back(atom);
+ d_im.sendInference(iexp, noExplain, conc, Inference::RE_DERIVE);
return true;
}
return false;
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 142b0006b..0ad887d2f 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -51,9 +51,7 @@ TheoryStrings::TheoryStrings(context::Context* c,
d_rewriter(&d_statistics.d_rewrites),
d_bsolver(d_state, d_im),
d_csolver(d_state, d_im, d_termReg, d_bsolver),
- d_esolver(c,
- u,
- d_state,
+ d_esolver(d_state,
d_im,
d_termReg,
d_rewriter,
@@ -61,8 +59,12 @@ TheoryStrings::TheoryStrings(context::Context* c,
d_csolver,
d_extTheory,
d_statistics),
- d_rsolver(d_state, d_im, d_termReg.getSkolemCache(),
- d_csolver, d_esolver, d_statistics),
+ d_rsolver(d_state,
+ d_im,
+ d_termReg.getSkolemCache(),
+ d_csolver,
+ d_esolver,
+ d_statistics),
d_stringsFmf(c, u, valuation, d_termReg)
{
bool eagerEval = options::stringEagerEval();
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback