This makes string proof construction more robust by maintaining two separate proof inference constructors, one for facts and one for lemmas/conflicts. This avoids issues where 2 lemmas with the same conclusion (but possibly different explanations) are added in the same call to check.
This fixes one of the two issues related to proofs for #6973.
d_lazyFactMap.insert(ii.d_conc, iic);
}
+void InferProofCons::notifyLemma(const InferInfo& ii)
+{
+ d_lazyFactMap[ii.d_conc] = std::make_shared<InferInfo>(ii);
+}
+
bool InferProofCons::addProofTo(CDProof* pf,
Node conc,
InferenceId infer,
* only for facts that are explained.
*/
void notifyFact(const InferInfo& ii);
+ /**
+ * Same as above, but always overwrites. This is used for lemmas and
+ * conflicts, which do not necessarily have unique conclusions.
+ */
+ void notifyLemma(const InferInfo& ii);
/**
* This returns the proof for fact. This is required for using this class as
d_termReg(tr),
d_extt(e),
d_statistics(statistics),
- d_ipc(pnm ? new InferProofCons(context(), pnm, d_statistics) : nullptr)
+ d_ipc(pnm ? new InferProofCons(context(), pnm, d_statistics) : nullptr),
+ d_ipcl(pnm ? new InferProofCons(context(), pnm, d_statistics) : nullptr)
{
NodeManager* nm = NodeManager::currentNM();
d_zero = nm->mkConst(Rational(0));
{
Assert(!d_state.isInConflict());
// setup the fact to reproduce the proof in the call below
- if (d_ipc != nullptr)
+ if (d_ipcl != nullptr)
{
- d_ipc->notifyFact(ii);
+ d_ipcl->notifyLemma(ii);
}
// make the trust node
- TrustNode tconf = mkConflictExp(ii.d_premises, d_ipc.get());
+ TrustNode tconf = mkConflictExp(ii.d_premises, d_ipcl.get());
Assert(tconf.getKind() == TrustNodeKind::CONFLICT);
Trace("strings-assert") << "(assert (not " << tconf.getNode()
<< ")) ; conflict " << ii.getId() << std::endl;
}
// ensure that the proof generator is ready to explain the final conclusion
// of the lemma (ii.d_conc).
- if (d_ipc != nullptr)
+ if (d_ipcl != nullptr)
{
- d_ipc->notifyFact(ii);
+ d_ipcl->notifyLemma(ii);
}
- TrustNode tlem = mkLemmaExp(ii.d_conc, exp, noExplain, d_ipc.get());
+ TrustNode tlem = mkLemmaExp(ii.d_conc, exp, noExplain, d_ipcl.get());
Trace("strings-pending") << "Process pending lemma : " << tlem.getNode()
<< std::endl;
ExtTheory& d_extt;
/** Reference to the statistics for the theory of strings/sequences. */
SequencesStatistics& d_statistics;
- /** Conversion from inferences to proofs */
+ /** Conversion from inferences to proofs for facts */
std::unique_ptr<InferProofCons> d_ipc;
+ /**
+ * Conversion from inferences to proofs for lemmas and conflicts. This is
+ * separate from the above proof generator to avoid rare cases where the
+ * conclusion of a lemma is a duplicate of the conclusion of another lemma,
+ * or is a fact in the current equality engine.
+ */
+ std::unique_ptr<InferProofCons> d_ipcl;
/** Common constants */
Node d_true;
Node d_false;
{
std::vector<Node> noExplain;
noExplain.push_back(atom);
- noExplain.push_back(x.eqNode(d_emptyString));
+ if (x != d_emptyString)
+ {
+ 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, InferenceId::STRINGS_RE_DELTA_CONF);
regress1/strings/issue6653-rre-small.smt2
regress1/strings/issue6777-seq-nth-eval-cm.smt2
regress1/strings/issue6913.smt2
+ regress1/strings/issue6973-dup-lemma-conc.smt2
regress1/strings/kaluza-fl.smt2
regress1/strings/loop002.smt2
regress1/strings/loop003.smt2
--- /dev/null
+(set-logic QF_SLIA)
+(set-info :status unsat)
+(declare-fun a () String)
+(assert
+ (str.in_re ""
+ (re.++ (re.diff (re.comp re.all) (re.++ (str.to_re a) (re.comp re.all)))
+ (str.to_re
+ (ite
+ (str.in_re ""
+ (re.++ (str.to_re (ite (str.in_re "" (re.++ (str.to_re a) (re.comp re.all))) a ""))
+ (re.inter (str.to_re a)
+ (re.++ (str.to_re a)
+ (re.comp (re.union (re.++ (str.to_re a) (re.comp re.all)) re.all))))))
+ a "")))))
+(check-sat)