This adds optional arguments to INSTANTIATE steps in proofs to track fine-grained reasons for relevant instantiations.
Also simplifies an old argument modEq which was unused.
FYI @MikolasJanota
SKOLEMIZE,
// ======== Instantiate
// Children: (P:(forall ((x1 T1) ... (xn Tn)) F))
- // Arguments: (t1 ... tn)
+ // Arguments: (t1 ... tn, (id (t)?)? )
// ----------------------------------------
// Conclusion: F*sigma
- // sigma maps x1 ... xn to t1 ... tn.
+ // where sigma maps x1 ... xn to t1 ... tn.
+ //
+ // The optional argument id indicates the inference id that caused the
+ // instantiation. The term t indicates an additional term (e.g. the trigger)
+ // associated with the instantiation, which depends on the id. If the id
+ // has prefix "QUANTIFIERS_INST_E_MATCHING", then t is the trigger that
+ // generated the instantiation.
INSTANTIATE,
// ======== (Trusted) quantifiers preprocess
// Children: ?
const std::vector<Node>& instTerms = cur->getArguments();
Assert(cs.size() == 1);
Node q = cs[0]->getResult();
- insts[q].push_back({instTerms.begin(), instTerms.end()});
+ // the instantiation is a prefix of the arguments up to the number of
+ // variables
+ insts[q].push_back(
+ {instTerms.begin(), instTerms.begin() + q[0].getNumChildren()});
}
for (const std::shared_ptr<ProofNode>& cp : cs)
{
#include "theory/inference_id.h"
#include <iostream>
+#include "util/rational.h"
namespace cvc5 {
namespace theory {
return out;
}
+Node mkInferenceIdNode(InferenceId i)
+{
+ return NodeManager::currentNM()->mkConst(Rational(static_cast<uint32_t>(i)));
+}
+
} // namespace theory
} // namespace cvc5
#include <iosfwd>
+#include "expr/node.h"
+
namespace cvc5 {
namespace theory {
*/
std::ostream& operator<<(std::ostream& out, InferenceId i);
+/** Make node from inference id */
+Node mkInferenceIdNode(InferenceId i);
+
} // namespace theory
} // namespace cvc5
else if (inst->addInstantiation(d_curr_quant,
subs,
InferenceId::QUANTIFIERS_INST_CEGQI,
- false,
+ Node::null(),
false,
usedVts))
{
Node np = ensureGroundTermPreprocessed(val, n, d_groundTerms);
d_nodes.push_back(np);
}
+ d_trNode = NodeManager::currentNM()->mkNode(SEXPR, d_nodes);
if (Trace.isOn("trigger"))
{
QuantAttributes& qa = d_qreg.getQuantAttributes();
bool Trigger::sendInstantiation(std::vector<Node>& m, InferenceId id)
{
- return d_qim.getInstantiate()->addInstantiation(d_quant, m, id);
+ return d_qim.getInstantiate()->addInstantiation(d_quant, m, id, d_trNode);
}
bool Trigger::sendInstantiation(InstMatch& m, InferenceId id)
std::vector<Node>& gts);
/** The nodes comprising this trigger. */
std::vector<Node> d_nodes;
+ /** The nodes as a single s-expression */
+ Node d_trNode;
/**
* The preprocessed ground terms in the nodes of the trigger, which as an
* optimization omits variables and constant subterms. These terms are
}
// just add the instance
d_triedLemmas++;
- if (instq->addInstantiation(
- f, inst, InferenceId::QUANTIFIERS_INST_FMF_FMC, true))
+ if (instq->addInstantiation(f,
+ inst,
+ InferenceId::QUANTIFIERS_INST_FMF_FMC,
+ Node::null(),
+ true))
{
Trace("fmc-debug-inst") << "** Added instantiation." << std::endl;
d_addedLemmas++;
if (ev!=d_true) {
Trace("fmc-exh-debug") << ", add!";
//add as instantiation
- if (ie->addInstantiation(
- f, inst, InferenceId::QUANTIFIERS_INST_FMF_FMC_EXH, true))
+ if (ie->addInstantiation(f,
+ inst,
+ InferenceId::QUANTIFIERS_INST_FMF_FMC_EXH,
+ Node::null(),
+ true))
{
Trace("fmc-exh-debug") << " ...success.";
addedLemmas++;
virtual int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { return false; }
//whether to construct model
virtual bool optUseModel();
- /** exist instantiation ? */
- virtual bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ) { return false; }
//debug model
void debugModel(TheoryModel* m) override;
//statistics
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
triedLemmas++;
//add as instantiation
- if (inst->addInstantiation(
- f, m.d_vals, InferenceId::QUANTIFIERS_INST_FMF_EXH, true))
+ if (inst->addInstantiation(f,
+ m.d_vals,
+ InferenceId::QUANTIFIERS_INST_FMF_EXH,
+ Node::null(),
+ true))
{
addedLemmas++;
if (d_qstate.isInConflict())
bool Instantiate::addInstantiation(Node q,
std::vector<Node>& terms,
InferenceId id,
+ Node pfArg,
bool mkRep,
- bool modEq,
bool doVts)
{
// For resource-limiting (also does a time check).
}
// record the instantiation
- bool recorded = recordInstantiationInternal(q, terms, modEq);
+ bool recorded = recordInstantiationInternal(q, terms);
if (!recorded)
{
Trace("inst-add-debug") << " --> Already exists (no record)." << std::endl;
Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
Assert(d_qreg.d_vars[q].size() == terms.size());
// get the instantiation
- Node body = getInstantiation(q, d_qreg.d_vars[q], terms, doVts, pfTmp.get());
+ Node body = getInstantiation(
+ q, d_qreg.d_vars[q], terms, id, pfArg, doVts, pfTmp.get());
Node orig_body = body;
// now preprocess, storing the trust node for the rewrite
TrustNode tpBody = QuantifiersRewriter::preprocess(body, true);
std::vector<Node>& terms,
std::vector<bool>& failMask,
InferenceId id,
+ Node pfArg,
bool mkRep,
- bool modEq,
bool doVts,
bool expFull)
{
- if (addInstantiation(q, terms, id, mkRep, modEq, doVts))
+ if (addInstantiation(q, terms, id, pfArg, mkRep, doVts))
{
return true;
}
subs[vars[i]] = terms[i];
}
// get the instantiation body
- Node ibody = getInstantiation(q, vars, terms, doVts);
+ InferenceId idNone = InferenceId::UNKNOWN;
+ Node nulln;
+ Node ibody = getInstantiation(q, vars, terms, idNone, nulln, doVts);
ibody = Rewriter::rewrite(ibody);
for (size_t i = 0; i < tsize; i++)
{
// check whether the instantiation rewrites to the same thing
if (!success)
{
- Node ibodyc = getInstantiation(q, vars, terms, doVts);
+ Node ibodyc = getInstantiation(q, vars, terms, idNone, nulln, doVts);
ibodyc = Rewriter::rewrite(ibodyc);
success = (ibodyc == ibody);
Trace("inst-exp-fail") << " rewrite invariant: " << success << std::endl;
Node Instantiate::getInstantiation(Node q,
std::vector<Node>& vars,
std::vector<Node>& terms,
+ InferenceId id,
+ Node pfArg,
bool doVts,
LazyCDProof* pf)
{
// store the proof of the instantiated body, with (open) assumption q
if (pf != nullptr)
{
- pf->addStep(body, PfRule::INSTANTIATE, {q}, terms);
+ // additional arguments: if the inference id is not unknown, include it,
+ // followed by the proof argument if non-null. The latter is used e.g.
+ // to track which trigger caused an instantiation.
+ std::vector<Node> pfTerms = terms;
+ if (id != InferenceId::UNKNOWN)
+ {
+ pfTerms.push_back(mkInferenceIdNode(id));
+ if (!pfArg.isNull())
+ {
+ pfTerms.push_back(pfArg);
+ }
+ }
+ pf->addStep(body, PfRule::INSTANTIATE, {q}, pfTerms);
}
// run rewriters to rewrite the instantiation in sequence.
Node Instantiate::getInstantiation(Node q, std::vector<Node>& terms, bool doVts)
{
Assert(d_qreg.d_vars.find(q) != d_qreg.d_vars.end());
- return getInstantiation(q, d_qreg.d_vars[q], terms, doVts);
+ return getInstantiation(
+ q, d_qreg.d_vars[q], terms, InferenceId::UNKNOWN, Node::null(), doVts);
}
-bool Instantiate::recordInstantiationInternal(Node q,
- std::vector<Node>& terms,
- bool modEq)
+bool Instantiate::recordInstantiationInternal(Node q, std::vector<Node>& terms)
{
if (options::incrementalSolving())
{
Trace("inst-add-debug")
- << "Adding into context-dependent inst trie, modEq = " << modEq
- << std::endl;
+ << "Adding into context-dependent inst trie" << std::endl;
CDInstMatchTrie* imt;
std::map<Node, CDInstMatchTrie*>::iterator it = d_c_inst_match_trie.find(q);
if (it != d_c_inst_match_trie.end())
d_c_inst_match_trie[q] = imt;
}
d_c_inst_match_trie_dom.insert(q);
- return imt->addInstMatch(d_qstate, q, terms, modEq);
+ return imt->addInstMatch(d_qstate, q, terms);
}
Trace("inst-add-debug") << "Adding into inst trie" << std::endl;
- return d_inst_match_trie[q].addInstMatch(d_qstate, q, terms, modEq);
+ return d_inst_match_trie[q].addInstMatch(d_qstate, q, terms);
}
bool Instantiate::removeInstantiationInternal(Node q, std::vector<Node>& terms)
* @param terms the terms to instantiate with
* @param id the identifier of the instantiation lemma sent via the inference
* manager
+ * @param pfArg an additional node to add to the arguments of the INSTANTIATE
+ * step
* @param mkRep whether to take the representatives of the terms in the
* range of the substitution m,
- * @param modEq whether to check for duplication modulo equality in
- * instantiation tries (for performance),
* @param doVts whether we must apply virtual term substitution to the
* instantiation lemma.
*
bool addInstantiation(Node q,
std::vector<Node>& terms,
InferenceId id,
+ Node pfArg = Node::null(),
bool mkRep = false,
- bool modEq = false,
bool doVts = false);
/**
* Same as above, but we also compute a vector failMask indicating which
std::vector<Node>& terms,
std::vector<bool>& failMask,
InferenceId id,
+ Node pfArg = Node::null(),
bool mkRep = false,
- bool modEq = false,
bool doVts = false,
bool expFull = true);
/** record instantiation
Node getInstantiation(Node q,
std::vector<Node>& vars,
std::vector<Node>& terms,
+ InferenceId id = InferenceId::UNKNOWN,
+ Node pfArg = Node::null(),
bool doVts = false,
LazyCDProof* pf = nullptr);
/** get instantiation
Statistics d_statistics;
private:
- /** record instantiation, return true if it was not a duplicate
- *
- * modEq : whether to check for duplication modulo equality in instantiation
- * tries (for performance),
- */
- bool recordInstantiationInternal(Node q,
- std::vector<Node>& terms,
- bool modEq = false);
+ /** record instantiation, return true if it was not a duplicate */
+ bool recordInstantiationInternal(Node q, std::vector<Node>& terms);
/** remove instantiation from the cache */
bool removeInstantiationInternal(Node q, std::vector<Node>& terms);
/**
else if (id == PfRule::INSTANTIATE)
{
Assert(children.size() == 1);
+ // note we may have more arguments than just the term vector
if (children[0].getKind() != FORALL
- || args.size() != children[0][0].getNumChildren())
+ || args.size() < children[0][0].getNumChildren())
{
return Node::null();
}
Node body = children[0][1];
std::vector<Node> vars;
std::vector<Node> subs;
- for (unsigned i = 0, nargs = args.size(); i < nargs; i++)
+ for (size_t i = 0, nc = children[0][0].getNumChildren(); i < nc; i++)
{
vars.push_back(children[0][0][i]);
subs.push_back(args[i]);