void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
}
-void ArithCongruenceManager::raiseConflict(Node conflict){
+void ArithCongruenceManager::raiseConflict(Node conflict,
+ std::shared_ptr<ProofNode> pf)
+{
Assert(!inConflict());
Debug("arith::conflict") << "difference manager conflict " << conflict << std::endl;
d_inConflict.raise();
- d_raiseConflict.raiseEEConflict(conflict);
+ d_raiseConflict.raiseEEConflict(conflict, pf);
}
bool ArithCongruenceManager::inConflict() const{
return d_inConflict.isRaised();
if(rewritten.getConst<bool>()){
return true;
}else{
+ // x rewrites to false.
++(d_statistics.d_conflicts);
-
- Node conf = flattenAnd(explainInternal(x));
- raiseConflict(conf);
+ TrustNode trn = explainInternal(x);
+ Node conf = flattenAnd(trn.getNode());
Debug("arith::congruenceManager") << "rewritten to false "<<x<<" with explanation "<< conf << std::endl;
+ if (isProofEnabled())
+ {
+ auto pf = trn.getGenerator()->getProofFor(trn.getProven());
+ auto confPf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {conf.negate()});
+ raiseConflict(conf, confPf);
+ }
+ else
+ {
+ raiseConflict(conf);
+ }
return false;
}
}
<< c->negationHasProof() << std::endl;
if(c->negationHasProof()){
- Node expC = explainInternal(x);
+ TrustNode texpC = explainInternal(x);
+ Node expC = texpC.getNode();
ConstraintCP negC = c->getNegation();
- Node neg = negC->externalExplainByAssertions();
+ Node neg = Constraint::externalExplainByAssertions({negC});
Node conf = expC.andNode(neg);
Node final = flattenAnd(conf);
}
}
-Node ArithCongruenceManager::explainInternal(TNode internal){
- std::vector<TNode> assumptions;
- explain(internal, assumptions);
-
- std::set<TNode> assumptionSet;
- assumptionSet.insert(assumptions.begin(), assumptions.end());
-
- if (assumptionSet.size() == 1) {
- // All the same, or just one
- return assumptions[0];
- }else{
- NodeBuilder<> conjunction(kind::AND);
- enqueueIntoNB(assumptionSet, conjunction);
- return conjunction;
+TrustNode ArithCongruenceManager::explainInternal(TNode internal)
+{
+ if (isProofEnabled())
+ {
+ return d_pfee->explain(internal);
}
+ // otherwise, explain without proof generator
+ Node exp = d_ee->mkExplainLit(internal);
+ return TrustNode::mkTrustPropExp(internal, exp, nullptr);
}
TrustNode ArithCongruenceManager::explain(TNode external)
Trace("arith-ee") << "Ask for explanation of " << external << std::endl;
Node internal = externalToInternal(external);
Trace("arith-ee") << "...internal = " << internal << std::endl;
- Node exp = explainInternal(internal);
- if (isProofEnabled())
+ TrustNode trn = explainInternal(internal);
+ if (isProofEnabled() && trn.getProven()[1] != external)
{
- Node impl = NodeManager::currentNM()->mkNode(Kind::IMPLIES, exp, external);
- // For now, we just trust
- auto pfOfImpl = d_pnm->mkNode(PfRule::INT_TRUST, {}, {impl});
- return d_pfGenExplain->mkTrustNode(impl, pfOfImpl);
+ Assert(trn.getKind() == TrustNodeKind::PROP_EXP);
+ Assert(trn.getProven().getKind() == Kind::IMPLIES);
+ Assert(trn.getGenerator() != nullptr);
+ Trace("arith-ee") << "tweaking proof to prove " << external << " not "
+ << trn.getProven()[1] << std::endl;
+ std::vector<std::shared_ptr<ProofNode>> assumptionPfs;
+ std::vector<Node> assumptions = andComponents(trn.getNode());
+ assumptionPfs.push_back(trn.toProofNode());
+ for (const auto& a : assumptions)
+ {
+ assumptionPfs.push_back(
+ d_pnm->mkNode(PfRule::TRUE_INTRO, {d_pnm->mkAssume(a)}, {}));
+ }
+ auto litPf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {assumptionPfs}, {external});
+ auto extPf = d_pnm->mkScope(litPf, assumptions);
+ return d_pfGenExplain->mkTrustedPropagation(external, trn.getNode(), extPf);
}
- return TrustNode::mkTrustPropExp(external, exp, nullptr);
+ return trn;
}
void ArithCongruenceManager::explain(TNode external, NodeBuilder<>& out){
/** Pointer to the proof equality engine of TheoryArith */
theory::eq::ProofEqEngine* d_pfee;
-
- void raiseConflict(Node conflict);
+ /** Raise a conflict node `conflict` to the theory of arithmetic.
+ *
+ * When proofs are enabled, a (closed) proof of the conflict should be
+ * provided.
+ */
+ void raiseConflict(Node conflict, std::shared_ptr<ProofNode> pf = nullptr);
/**
* Are proofs enabled? This is true if a non-null proof manager was provided
* to the constructor of this class.
void enqueueIntoNB(const std::set<TNode> all, NodeBuilder<>& nb);
- Node explainInternal(TNode internal);
-public:
+ /**
+ * Determine an explaination for `internal`. That is a conjunction of theory
+ * literals which imply `internal`.
+ *
+ * The TrustNode here is a trusted propagation.
+ */
+ TrustNode explainInternal(TNode internal);
public:
ArithCongruenceManager(context::Context* satContext,
void finishInit(eq::EqualityEngine* ee, eq::ProofEqEngine* pfee);
//--------------------------------- end initialization
+ /**
+ * Return the trust node for the explanation of literal. The returned
+ * trust node is generated by the proof equality engine of this class.
+ */
TrustNode explain(TNode literal);
+
void explain(TNode lit, NodeBuilder<>& out);
void addWatchedPair(ArithVar s, TNode x, TNode y);