1 /********************* */
2 /*! \file model_engine.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Morgan Deters, Kshitij Bansal
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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 model engine class
15 #include "theory/quantifiers/fmf/model_engine.h"
17 #include "options/quantifiers_options.h"
18 #include "theory/quantifiers/first_order_model.h"
19 #include "theory/quantifiers/fmf/full_model_check.h"
20 #include "theory/quantifiers/instantiate.h"
21 #include "theory/quantifiers/quant_rep_bound_ext.h"
22 #include "theory/quantifiers/quantifiers_attributes.h"
23 #include "theory/quantifiers/term_database.h"
24 #include "theory/quantifiers/term_util.h"
25 #include "theory/quantifiers_engine.h"
26 #include "theory/theory_engine.h"
27 #include "theory/uf/equality_engine.h"
31 using namespace CVC4::kind
;
32 using namespace CVC4::context
;
33 using namespace CVC4::theory
;
34 using namespace CVC4::theory::quantifiers
;
35 using namespace CVC4::theory::inst
;
37 //Model Engine constructor
38 ModelEngine::ModelEngine(QuantifiersEngine
* qe
,
40 QuantifiersInferenceManager
& qim
)
41 : QuantifiersModule(qs
, qim
, qe
),
42 d_incomplete_check(true),
50 ModelEngine::~ModelEngine() {
54 bool ModelEngine::needsCheck( Theory::Effort e
) {
55 return e
==Theory::EFFORT_LAST_CALL
;
58 QuantifiersModule::QEffort
ModelEngine::needsModel(Theory::Effort e
)
60 if( options::mbqiInterleave() ){
61 return QEFFORT_STANDARD
;
67 void ModelEngine::reset_round( Theory::Effort e
) {
68 d_incomplete_check
= true;
70 void ModelEngine::check(Theory::Effort e
, QEffort quant_e
)
73 if( options::mbqiInterleave() ){
74 doCheck
= quant_e
== QEFFORT_STANDARD
&& d_quantEngine
->hasAddedLemma();
77 doCheck
= quant_e
== QEFFORT_MODEL
;
80 Assert(!d_qstate
.isInConflict());
83 //the following will test that the model satisfies all asserted universal quantifiers by
84 // (model-based) exhaustive instantiation.
86 if( Trace
.isOn("model-engine") ){
87 Trace("model-engine") << "---Model Engine Round---" << std::endl
;
88 clSet
= double(clock())/double(CLOCKS_PER_SEC
);
90 Trace("model-engine-debug") << "Check model..." << std::endl
;
91 d_incomplete_check
= false;
93 if (Trace
.isOn("fmf-model-complete"))
95 Trace("fmf-model-complete") << std::endl
;
96 debugPrint("fmf-model-complete");
98 // successfully built an acceptable model, now check it
99 addedLemmas
+= checkModel();
101 if( Trace
.isOn("model-engine") ){
102 double clSet2
= double(clock())/double(CLOCKS_PER_SEC
);
103 Trace("model-engine") << "Finished model engine, time = " << (clSet2
-clSet
) << std::endl
;
106 if( addedLemmas
==0 ){
107 Trace("model-engine-debug") << "No lemmas added, incomplete = " << ( d_incomplete_check
|| !d_incomplete_quants
.empty() ) << std::endl
;
108 //CVC4 will answer SAT or unknown
109 if( Trace
.isOn("fmf-consistent") ){
110 Trace("fmf-consistent") << std::endl
;
111 debugPrint("fmf-consistent");
117 bool ModelEngine::checkComplete() {
118 return !d_incomplete_check
;
121 bool ModelEngine::checkCompleteFor( Node q
) {
122 return std::find( d_incomplete_quants
.begin(), d_incomplete_quants
.end(), q
)==d_incomplete_quants
.end();
125 void ModelEngine::registerQuantifier( Node f
){
126 if( Trace
.isOn("fmf-warn") ){
127 bool canHandle
= true;
128 for( unsigned i
=0; i
<f
[0].getNumChildren(); i
++ ){
129 TypeNode tn
= f
[0][i
].getType();
131 if (!tn
.isInterpretedFinite())
133 if( tn
.isInteger() ){
134 if( !options::fmfBound() ){
144 Trace("fmf-warn") << "Warning : Model Engine : may not be able to answer SAT because of formula : " << f
<< std::endl
;
149 void ModelEngine::assertNode( Node f
){
153 int ModelEngine::checkModel(){
154 FirstOrderModel
* fm
= d_quantEngine
->getModel();
156 //for debugging, setup
157 for (std::map
<TypeNode
, std::vector
<Node
> >::iterator it
=
158 fm
->getRepSetPtr()->d_type_reps
.begin();
159 it
!= fm
->getRepSetPtr()->d_type_reps
.end();
162 if( it
->first
.isSort() ){
163 Trace("model-engine") << "Cardinality( " << it
->first
<< " )" << " = " << it
->second
.size() << std::endl
;
164 Trace("model-engine-debug") << " Reps : ";
165 for( size_t i
=0; i
<it
->second
.size(); i
++ ){
166 Trace("model-engine-debug") << it
->second
[i
] << " ";
168 Trace("model-engine-debug") << std::endl
;
169 Trace("model-engine-debug") << " Term reps : ";
170 for( size_t i
=0; i
<it
->second
.size(); i
++ ){
171 Node r
= d_quantEngine
->getInternalRepresentative( it
->second
[i
], Node::null(), 0 );
174 // there was an invalid equivalence class
175 d_incomplete_check
= true;
177 Trace("model-engine-debug") << r
<< " ";
179 Trace("model-engine-debug") << std::endl
;
180 Node mbt
= fm
->getModelBasisTerm(it
->first
);
181 Trace("model-engine-debug") << " Basis term : " << mbt
<< std::endl
;
189 if( Trace
.isOn("model-engine") ){
190 for( unsigned i
=0; i
<fm
->getNumAssertedQuantifiers(); i
++ ){
191 Node f
= fm
->getAssertedQuantifier( i
);
192 if( d_quantEngine
->getModel()->isQuantifierActive( f
) && d_quantEngine
->hasOwnership( f
, this ) ){
194 for( unsigned j
=0; j
<f
[0].getNumChildren(); j
++ ){
195 TypeNode tn
= f
[0][j
].getType();
196 if (fm
->getRepSet()->hasType(tn
))
199 totalInst
* (int)fm
->getRepSet()->getNumRepresentatives(tn
);
202 d_totalLemmas
+= totalInst
;
207 Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl
;
208 // FMC uses two sub-effort levels
209 int e_max
= options::mbqiMode() == options::MbqiMode::FMC
211 : (options::mbqiMode() == options::MbqiMode::TRUST
? 0 : 1);
212 for( int e
=0; e
<e_max
; e
++) {
213 d_incomplete_quants
.clear();
214 for( unsigned i
=0; i
<fm
->getNumAssertedQuantifiers(); i
++ ){
215 Node q
= fm
->getAssertedQuantifier( i
, true );
216 Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << q
<< ", effort = " << e
<< "..." << std::endl
;
217 //determine if we should check this quantifier
218 if( d_quantEngine
->getModel()->isQuantifierActive( q
) && d_quantEngine
->hasOwnership( q
, this ) ){
219 exhaustiveInstantiate( q
, e
);
220 if (d_qstate
.isInConflict())
225 Trace("fmf-exh-inst") << "-> Inactive : " << q
<< std::endl
;
228 if( d_addedLemmas
>0 ){
231 Assert(!d_qstate
.isInConflict());
235 //print debug information
236 if (d_qstate
.isInConflict())
238 Trace("model-engine") << "Conflict, added lemmas = ";
240 Trace("model-engine") << "Added Lemmas = ";
242 Trace("model-engine") << d_addedLemmas
<< " / " << d_triedLemmas
<< " / ";
243 Trace("model-engine") << d_totalLemmas
<< std::endl
;
244 return d_addedLemmas
;
249 void ModelEngine::exhaustiveInstantiate( Node f
, int effort
){
250 //first check if the builder can do the exhaustive instantiation
251 quantifiers::QModelBuilder
* mb
= d_quantEngine
->getModelBuilder();
252 unsigned prev_alem
= mb
->getNumAddedLemmas();
253 unsigned prev_tlem
= mb
->getNumTriedLemmas();
254 int retEi
= mb
->doExhaustiveInstantiation( d_quantEngine
->getModel(), f
, effort
);
257 Trace("fmf-exh-inst") << "-> Builder determined complete instantiation was impossible." << std::endl
;
258 d_incomplete_quants
.push_back( f
);
260 Trace("fmf-exh-inst") << "-> Builder determined instantiation(s)." << std::endl
;
262 d_triedLemmas
+= mb
->getNumTriedLemmas()-prev_tlem
;
263 d_addedLemmas
+= mb
->getNumAddedLemmas()-prev_alem
;
264 d_quantEngine
->d_statistics
.d_instantiations_fmf_mbqi
+=
265 (mb
->getNumAddedLemmas() - prev_alem
);
267 if( Trace
.isOn("fmf-exh-inst-debug") ){
268 Trace("fmf-exh-inst-debug") << " Instantiation Constants: ";
269 for( size_t i
=0; i
<f
[0].getNumChildren(); i
++ ){
270 Trace("fmf-exh-inst-debug") << d_quantEngine
->getTermUtil()->getInstantiationConstant( f
, i
) << " ";
272 Trace("fmf-exh-inst-debug") << std::endl
;
274 //create a rep set iterator and iterate over the (relevant) domain of the quantifier
275 QRepBoundExt
qrbe(d_quantEngine
);
276 RepSetIterator
riter(d_quantEngine
->getModel()->getRepSet(), &qrbe
);
277 if( riter
.setQuantifier( f
) ){
278 Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter
.isIncomplete() << "..." << std::endl
;
279 if( !riter
.isIncomplete() ){
282 EqualityQuery
* qy
= d_quantEngine
->getEqualityQuery();
283 Instantiate
* inst
= d_quantEngine
->getInstantiate();
284 while( !riter
.isFinished() && ( addedLemmas
==0 || !options::fmfOneInstPerRound() ) ){
285 //instantiation was not shown to be true, construct the match
287 for (unsigned i
= 0; i
< riter
.getNumTerms(); i
++)
289 m
.set(qy
, i
, riter
.getCurrentTerm(i
));
291 Debug("fmf-model-eval") << "* Add instantiation " << m
<< std::endl
;
293 //add as instantiation
294 if (inst
->addInstantiation(f
, m
, true))
297 if (d_qstate
.isInConflict())
302 Debug("fmf-model-eval") << "* Failed Add instantiation " << m
<< std::endl
;
306 d_addedLemmas
+= addedLemmas
;
307 d_triedLemmas
+= triedLemmas
;
308 d_quantEngine
->d_statistics
.d_instantiations_fmf_exh
+= addedLemmas
;
311 Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter
.isIncomplete() << "..." << std::endl
;
313 //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
314 if( riter
.isIncomplete() ){
315 d_incomplete_quants
.push_back( f
);
320 void ModelEngine::debugPrint( const char* c
){
321 Trace( c
) << "Quantifiers: " << std::endl
;
322 for( unsigned i
=0; i
<d_quantEngine
->getModel()->getNumAssertedQuantifiers(); i
++ ){
323 Node q
= d_quantEngine
->getModel()->getAssertedQuantifier( i
);
324 if( d_quantEngine
->hasOwnership( q
, this ) ){
326 if( !d_quantEngine
->getModel()->isQuantifierActive( q
) ){
327 Trace( c
) << "*Inactive* ";
331 Trace( c
) << q
<< std::endl
;
334 //d_quantEngine->getModel()->debugPrint( c );