1 /********************* */
2 /*! \file synth_engine.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Haniel Barbosa, Gereon Kremer
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8 ** in the top-level source directory and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief Implementation of the quantifiers module for managing all approaches
13 ** to synthesis, in particular, those described in Reynolds et al CAV 2015.
16 #include "theory/quantifiers/sygus/synth_engine.h"
18 #include "expr/node_algorithm.h"
19 #include "options/quantifiers_options.h"
20 #include "theory/quantifiers/quantifiers_attributes.h"
21 #include "theory/quantifiers/sygus/term_database_sygus.h"
22 #include "theory/quantifiers/term_util.h"
23 #include "theory/quantifiers_engine.h"
25 using namespace CVC4::kind
;
30 namespace quantifiers
{
32 SynthEngine::SynthEngine(QuantifiersEngine
* qe
,
34 QuantifiersInferenceManager
& qim
,
35 QuantifiersRegistry
& qr
)
36 : QuantifiersModule(qs
, qim
, qr
, qe
),
37 d_tds(qe
->getTermDatabaseSygus()),
41 d_conjs
.push_back(std::unique_ptr
<SynthConjecture
>(
42 new SynthConjecture(d_quantEngine
, qs
, qim
, qr
, d_statistics
)));
43 d_conj
= d_conjs
.back().get();
46 SynthEngine::~SynthEngine() {}
48 void SynthEngine::presolve()
50 Trace("sygus-engine") << "SynthEngine::presolve" << std::endl
;
51 for (unsigned i
= 0, size
= d_conjs
.size(); i
< size
; i
++)
53 d_conjs
[i
]->presolve();
55 Trace("sygus-engine") << "SynthEngine::presolve finished" << std::endl
;
58 bool SynthEngine::needsCheck(Theory::Effort e
)
60 return e
>= Theory::EFFORT_LAST_CALL
;
63 QuantifiersModule::QEffort
SynthEngine::needsModel(Theory::Effort e
)
68 void SynthEngine::check(Theory::Effort e
, QEffort quant_e
)
70 // are we at the proper effort level?
71 if (quant_e
!= QEFFORT_MODEL
)
76 // if we are waiting to assign the conjecture, do it now
77 bool assigned
= !d_waiting_conj
.empty();
78 while (!d_waiting_conj
.empty())
80 Node q
= d_waiting_conj
.back();
81 d_waiting_conj
.pop_back();
82 Trace("sygus-engine") << "--- Conjecture waiting to assign: " << q
88 // assign conjecture always uses the output channel, either by reducing a
89 // quantified formula to another, or adding initial lemmas during
90 // SynthConjecture::assign. Thus, we return here and re-check.
94 Trace("sygus-engine") << "---Counterexample Guided Instantiation Engine---"
96 Trace("sygus-engine-debug") << std::endl
;
97 Valuation
& valuation
= d_qstate
.getValuation();
98 std::vector
<SynthConjecture
*> activeCheckConj
;
99 for (unsigned i
= 0, size
= d_conjs
.size(); i
< size
; i
++)
101 SynthConjecture
* sc
= d_conjs
[i
].get();
104 if (valuation
.hasSatValue(sc
->getConjecture(), value
))
110 Trace("sygus-engine-debug") << "...no value for quantified formula."
113 Trace("sygus-engine-debug")
114 << "Current conjecture status : active : " << active
<< std::endl
;
115 if (active
&& sc
->needsCheck())
117 activeCheckConj
.push_back(sc
);
120 std::vector
<SynthConjecture
*> acnext
;
123 Trace("sygus-engine-debug") << "Checking " << activeCheckConj
.size()
124 << " active conjectures..." << std::endl
;
125 for (unsigned i
= 0, size
= activeCheckConj
.size(); i
< size
; i
++)
127 SynthConjecture
* sc
= activeCheckConj
[i
];
128 if (!checkConjecture(sc
))
130 if (!sc
->needsRefinement())
132 acnext
.push_back(sc
);
136 activeCheckConj
.clear();
137 activeCheckConj
= acnext
;
139 } while (!activeCheckConj
.empty() && !d_qstate
.getValuation().needCheck());
140 Trace("sygus-engine")
141 << "Finished Counterexample Guided Instantiation engine." << std::endl
;
144 void SynthEngine::assignConjecture(Node q
)
146 Trace("sygus-engine") << "SynthEngine::assignConjecture " << q
<< std::endl
;
147 if (options::sygusQePreproc())
149 Node lem
= d_sqp
.preprocess(q
);
152 Trace("cegqi-lemma") << "Cegqi::Lemma : qe-preprocess : " << lem
154 d_qim
.lemma(lem
, InferenceId::QUANTIFIERS_SYGUS_QE_PREPROC
);
155 // we've reduced the original to a preprocessed version, return
159 // allocate a new synthesis conjecture if not assigned
160 if (d_conjs
.back()->isAssigned())
162 d_conjs
.push_back(std::unique_ptr
<SynthConjecture
>(new SynthConjecture(
163 d_quantEngine
, d_qstate
, d_qim
, d_qreg
, d_statistics
)));
165 d_conjs
.back()->assign(q
);
168 void SynthEngine::checkOwnership(Node q
)
170 // take ownership of quantified formulas with sygus attribute, and function
171 // definitions when options::sygusRecFun is true.
172 QuantAttributes
& qa
= d_qreg
.getQuantAttributes();
173 if (qa
.isSygus(q
) || (options::sygusRecFun() && qa
.isFunDef(q
)))
175 d_qreg
.setOwner(q
, this, 2);
179 void SynthEngine::registerQuantifier(Node q
)
181 Trace("cegqi-debug") << "SynthEngine: Register quantifier : " << q
183 if (d_qreg
.getOwner(q
) != this)
187 if (d_qreg
.getQuantAttributes().isFunDef(q
))
189 Assert(options::sygusRecFun());
190 // If it is a recursive function definition, add it to the function
191 // definition evaluator class.
192 Trace("cegqi") << "Registering function definition : " << q
<< "\n";
193 FunDefEvaluator
* fde
= d_tds
->getFunDefEvaluator();
194 fde
->assertDefinition(q
);
197 Trace("cegqi") << "Register conjecture : " << q
<< std::endl
;
198 if (options::sygusQePreproc())
200 d_waiting_conj
.push_back(q
);
209 bool SynthEngine::checkConjecture(SynthConjecture
* conj
)
211 if (Trace
.isOn("sygus-engine-debug"))
213 conj
->debugPrint("sygus-engine-debug");
214 Trace("sygus-engine-debug") << std::endl
;
217 if (!conj
->needsRefinement())
219 Trace("sygus-engine-debug") << "Do conjecture check..." << std::endl
;
220 Trace("sygus-engine-debug")
221 << " *** Check candidate phase..." << std::endl
;
222 std::vector
<Node
> cclems
;
223 bool ret
= conj
->doCheck(cclems
);
224 bool addedLemma
= false;
225 for (const Node
& lem
: cclems
)
227 if (d_qim
.addPendingLemma(lem
, InferenceId::UNKNOWN
))
229 ++(d_statistics
.d_cegqi_lemmas_ce
);
234 // this may happen if we eagerly unfold, simplify to true
235 Trace("sygus-engine-debug")
236 << " ...FAILED to add candidate!" << std::endl
;
241 Trace("sygus-engine-debug")
242 << " ...check for counterexample." << std::endl
;
245 if (!conj
->needsRefinement())
249 // otherwise, immediately go to refine candidate
251 Trace("sygus-engine-debug") << " *** Refine candidate phase..." << std::endl
;
252 return conj
->doRefine();
255 void SynthEngine::printSynthSolution(std::ostream
& out
)
257 Assert(!d_conjs
.empty());
258 for (unsigned i
= 0, size
= d_conjs
.size(); i
< size
; i
++)
260 if (d_conjs
[i
]->isAssigned())
262 d_conjs
[i
]->printSynthSolution(out
);
267 bool SynthEngine::getSynthSolutions(
268 std::map
<Node
, std::map
<Node
, Node
> >& sol_map
)
271 for (unsigned i
= 0, size
= d_conjs
.size(); i
< size
; i
++)
273 if (d_conjs
[i
]->isAssigned())
275 if (!d_conjs
[i
]->getSynthSolutions(sol_map
))
277 // if one conjecture fails, we fail overall
286 void SynthEngine::preregisterAssertion(Node n
)
288 // check if it sygus conjecture
289 if (QuantAttributes::checkSygusConjecture(n
))
291 // this is a sygus conjecture
292 Trace("cegqi") << "Preregister sygus conjecture : " << n
<< std::endl
;
293 d_conj
->preregisterConjecture(n
);
297 } // namespace quantifiers
298 } // namespace theory
299 } /* namespace CVC4 */