This adds an option to limit the number of instantiation rounds used by quantifiers engine.
This option may be generally useful for making quantifiers terminating. It also is necessary to update the new default behavior of SyGuS + recursive functions. A followup PR will make sygus verification calls set the option added on this PR automatically, so that we use incomplete + termination strategies for (non-PBE) sygus in the presence of recursive functions.
This PR also makes minor improvements to the quantifier utility infrastructure.
default = "true"
help = "only input terms are assigned instantiation level zero"
+[[option]]
+ name = "instMaxRounds"
+ category = "regular"
+ long = "inst-max-rounds=N"
+ type = "int"
+ default = "-1"
+ help = "maximum number of instantiation rounds (-1 == no limit, default)"
+
[[option]]
name = "quantRepMode"
category = "regular"
case IncompleteId::QUANTIFIERS_FMF: return "QUANTIFIERS_FMF";
case IncompleteId::QUANTIFIERS_RECORDED_INST:
return "QUANTIFIERS_RECORDED_INST";
+ case IncompleteId::QUANTIFIERS_MAX_INST_ROUNDS:
+ return "QUANTIFIERS_MAX_INST_ROUNDS";
case IncompleteId::SEP: return "SEP";
case IncompleteId::SETS_RELS_CARD: return "SETS_RELS_CARD";
case IncompleteId::STRINGS_LOOP_SKIP: return "STRINGS_LOOP_SKIP";
QUANTIFIERS_FMF,
// incomplete due to explicitly recorded instantiations
QUANTIFIERS_RECORDED_INST,
+ // incomplete due to limited number of allowed instantiation rounds
+ QUANTIFIERS_MAX_INST_ROUNDS,
// incomplete due to separation logic
SEP,
// relations were used in combination with set cardinality constraints
#include "proof/lazy_proof.h"
#include "proof/proof_node_manager.h"
#include "smt/logic_exception.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
#include "smt/smt_statistics_registry.h"
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
#include "theory/quantifiers/first_order_model.h"
Trace("inst-debug") << "Reset, effort " << e << std::endl;
// clear explicitly recorded instantiations
d_recordedInst.clear();
+ d_instDebugTemp.clear();
return true;
}
InstLemmaList* ill = getOrMkInstLemmaList(q);
ill->d_list.push_back(body);
// add to temporary debug statistics (# inst on this round)
- d_temp_inst_debug[q]++;
+ d_instDebugTemp[q]++;
if (Trace.isOn("inst"))
{
Trace("inst") << "*** Instantiate " << q << " with " << std::endl;
bool Instantiate::isProofEnabled() const { return d_pfInst != nullptr; }
-void Instantiate::debugPrint(std::ostream& out)
+void Instantiate::notifyEndRound()
{
- // debug information
- if (Trace.isOn("inst-per-quant-round"))
+ bool debugInstTrace = Trace.isOn("inst-per-quant-round");
+ if (options::debugInst() || debugInstTrace)
{
- for (std::pair<const Node, uint32_t>& i : d_temp_inst_debug)
+ Options& sopts = smt::currentSmtEngine()->getOptions();
+ std::ostream& out = *sopts.base.out;
+ // debug information
+ if (debugInstTrace)
{
- Trace("inst-per-quant-round") << " * " << i.second << " for " << i.first
- << std::endl;
- d_temp_inst_debug[i.first] = 0;
+ for (std::pair<const Node, uint32_t>& i : d_instDebugTemp)
+ {
+ Trace("inst-per-quant-round")
+ << " * " << i.second << " for " << i.first << std::endl;
+ }
}
- }
- if (options::debugInst())
- {
- bool req = !options::printInstFull();
- for (std::pair<const Node, uint32_t>& i : d_temp_inst_debug)
+ if (options::debugInst())
{
- Node name;
- if (!d_qreg.getNameForQuant(i.first, name, req))
+ bool req = !options::printInstFull();
+ for (std::pair<const Node, uint32_t>& i : d_instDebugTemp)
{
- continue;
+ Node name;
+ if (!d_qreg.getNameForQuant(i.first, name, req))
+ {
+ continue;
+ }
+ out << "(num-instantiations " << name << " " << i.second << ")"
+ << std::endl;
}
- out << "(num-instantiations " << name << " " << i.second << ")"
- << std::endl;
}
}
}
TermRegistry& tr,
ProofNodeManager* pnm = nullptr);
~Instantiate();
-
/** reset */
bool reset(Theory::Effort e) override;
/** register quantifier */
//--------------------------------------end general utilities
/**
- * Debug print, called once per instantiation round. This prints
+ * Called once at the end of each instantiation round. This prints
* instantiations added this round to trace inst-per-quant-round, if
* applicable, and prints to out if the option debug-inst is enabled.
*/
- void debugPrint(std::ostream& out);
+ void notifyEndRound();
/** debug print model, called once, before we terminate with sat/unknown. */
void debugPrintModel();
*/
std::map<Node, std::vector<Node> > d_recordedInst;
/** statistics for debugging total instantiations per quantifier per round */
- std::map<Node, uint32_t> d_temp_inst_debug;
+ std::map<Node, uint32_t> d_instDebugTemp;
/** list of all instantiations produced for each quantifier
*
public:
QuantifiersUtil(){}
virtual ~QuantifiersUtil(){}
+ /** Called at the beginning of check-sat call. */
+ virtual void presolve() {}
/* reset
* Called at the beginning of an instantiation round
* Returns false if the reset failed. When reset fails, the utility should
/** Finish init, which sets the inference manager */
void finishInit(QuantifiersInferenceManager* qim);
/** presolve (called once per user check-sat) */
- void presolve();
+ void presolve() override;
/** reset (calculate which terms are active) */
bool reset(Theory::Effort effort) override;
/** register quantified formula */
void TermRegistry::presolve()
{
- d_termDb->presolve();
d_presolve = false;
// add all terms to database
if (options::incrementalSolving() && !options::termDbCd())
d_treg(tr),
d_model(nullptr),
d_quants_prereg(qs.getUserContext()),
- d_quants_red(qs.getUserContext())
+ d_quants_red(qs.getUserContext()),
+ d_numInstRoundsLemma(0)
{
Trace("quant-init-debug")
<< "Initialize model engine, mbqi : " << options::mbqiMode() << " "
void QuantifiersEngine::presolve() {
Trace("quant-engine-proc") << "QuantifiersEngine : presolve " << std::endl;
+ d_numInstRoundsLemma = 0;
d_qim.clearPending();
- for( unsigned i=0; i<d_modules.size(); i++ ){
- d_modules[i]->presolve();
+ for (QuantifiersUtil*& u : d_util)
+ {
+ u->presolve();
+ }
+ for (QuantifiersModule*& mdl : d_modules)
+ {
+ mdl->presolve();
}
// presolve with term registry, which populates the term database based on
// terms registered before presolve when in incremental mode
d_qim.reset();
bool setIncomplete = false;
IncompleteId setIncompleteId = IncompleteId::QUANTIFIERS;
+ if (options::instMaxRounds() >= 0
+ && d_numInstRoundsLemma >= static_cast<uint32_t>(options::instMaxRounds()))
+ {
+ needsCheck = false;
+ setIncomplete = true;
+ setIncompleteId = IncompleteId::QUANTIFIERS_MAX_INST_ROUNDS;
+ }
Trace("quant-engine-debug2") << "Quantifiers Engine call to check, level = " << e << ", needsCheck=" << needsCheck << std::endl;
if( needsCheck ){
// debug print
if (d_qim.hasSentLemma())
{
- bool debugInstTrace = Trace.isOn("inst-per-quant-round");
- if (options::debugInst() || debugInstTrace)
- {
- Options& sopts = smt::currentSmtEngine()->getOptions();
- std::ostream& out = *sopts.base.out;
- d_qim.getInstantiate()->debugPrint(out);
- }
+ d_qim.getInstantiate()->notifyEndRound();
+ d_numInstRoundsLemma++;
}
if( Trace.isOn("quant-engine") ){
double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
/** quantifiers reduced */
BoolMap d_quants_red;
std::map<Node, Node> d_quants_red_lem;
+ /** Number of rounds we have instantiated */
+ uint32_t d_numInstRoundsLemma;
};/* class QuantifiersEngine */
} // namespace theory