3c2f9903eda7482f93997e88aabe72dc7e8c3600
1 /********************* */
2 /*! \file model_engine.cpp
4 ** Original author: Morgan Deters
5 ** Major contributors: Andrew Reynolds
6 ** Minor contributors (to current version): Francois Bobot
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2014 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
12 ** \brief Implementation of model engine class
15 #include "theory/quantifiers/model_engine.h"
16 #include "theory/theory_engine.h"
17 #include "theory/uf/equality_engine.h"
18 #include "theory/uf/theory_uf.h"
19 #include "theory/uf/theory_uf_strong_solver.h"
20 #include "theory/quantifiers/options.h"
21 #include "theory/quantifiers/first_order_model.h"
22 #include "theory/quantifiers/term_database.h"
23 #include "theory/quantifiers/quantifiers_attributes.h"
24 #include "theory/quantifiers/full_model_check.h"
25 #include "theory/quantifiers/qinterval_builder.h"
26 #include "theory/quantifiers/ambqi_builder.h"
30 using namespace CVC4::kind
;
31 using namespace CVC4::context
;
32 using namespace CVC4::theory
;
33 using namespace CVC4::theory::quantifiers
;
34 using namespace CVC4::theory::inst
;
36 //Model Engine constructor
37 ModelEngine::ModelEngine( context::Context
* c
, QuantifiersEngine
* qe
) :
38 QuantifiersModule( qe
),
39 d_incomplete_check(false),
45 Trace("model-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl
;
46 if( options::mbqiMode()==MBQI_FMC
|| options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL
||
47 options::mbqiMode()==MBQI_TRUST
|| options::fmfBoundInt() ){
48 Trace("model-engine-debug") << "...make fmc builder." << std::endl
;
49 d_builder
= new fmcheck::FullModelChecker( c
, qe
);
50 }else if( options::mbqiMode()==MBQI_INTERVAL
){
51 Trace("model-engine-debug") << "...make interval builder." << std::endl
;
52 d_builder
= new QIntervalBuilder( c
, qe
);
53 }else if( options::mbqiMode()==MBQI_ABS
){
54 Trace("model-engine-debug") << "...make abs mbqi builder." << std::endl
;
55 d_builder
= new AbsMbqiBuilder( c
, qe
);
56 }else if( options::mbqiMode()==MBQI_INST_GEN
){
57 Trace("model-engine-debug") << "...make inst-gen builder." << std::endl
;
58 d_builder
= new QModelBuilderInstGen( c
, qe
);
60 Trace("model-engine-debug") << "...make default model builder." << std::endl
;
61 d_builder
= new QModelBuilderDefault( c
, qe
);
65 ModelEngine::~ModelEngine() {
69 void ModelEngine::check( Theory::Effort e
){
70 if( e
==Theory::EFFORT_LAST_CALL
&& !d_quantEngine
->hasAddedLemma() ){
72 bool needsBuild
= true;
73 FirstOrderModel
* fm
= d_quantEngine
->getModel();
74 if( fm
->getNumAssertedQuantifiers()>0 ){
75 //the following will attempt to build a model and test that it satisfies all asserted universal quantifiers
76 //quantifiers are initialized, we begin an instantiation round
78 if( Trace
.isOn("model-engine") ){
79 clSet
= double(clock())/double(CLOCKS_PER_SEC
);
81 ++(d_statistics
.d_inst_rounds
);
82 bool buildAtFullModel
= d_builder
->optBuildAtFullModel();
83 needsBuild
= !buildAtFullModel
;
84 //two effort levels: first try exhaustive instantiation without axioms, then with.
85 int startEffort
= ( !fm
->isAxiomAsserted() || options::axiomInstMode()==AXIOM_INST_MODE_DEFAULT
) ? 1 : 0;
86 for( int effort
=startEffort
; effort
<2; effort
++ ){
87 // for effort = 0, we only instantiate non-axioms
88 // for effort = 1, we instantiate everything
90 Trace("model-engine") << "---Model Engine Round---" << std::endl
;
91 //initialize the model
92 Trace("model-engine-debug") << "Build model..." << std::endl
;
93 d_builder
->d_considerAxioms
= effort
>=1;
94 d_builder
->d_addedLemmas
= 0;
95 d_builder
->buildModel( fm
, buildAtFullModel
);
96 addedLemmas
+= (int)d_builder
->d_addedLemmas
;
97 //if builder has lemmas, add and return
99 Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl
;
100 //let the strong solver verify that the model is minimal
101 //for debugging, this will if there are terms in the model that the strong solver was not notified of
102 if( ((uf::TheoryUF
*)d_quantEngine
->getTheoryEngine()->theoryOf( THEORY_UF
))->getStrongSolver()->debugModel( fm
) ){
103 Trace("model-engine-debug") << "Check model..." << std::endl
;
104 d_incomplete_check
= false;
106 Debug("fmf-model-complete") << std::endl
;
107 debugPrint("fmf-model-complete");
108 //successfully built an acceptable model, now check it
109 addedLemmas
+= checkModel();
115 if( addedLemmas
==0 ){
116 //if we have not added lemmas yet and axiomInstMode=trust, then we are done
117 if( options::axiomInstMode()==AXIOM_INST_MODE_TRUST
){
118 //we must return unknown if an axiom is asserted
120 d_incomplete_check
= true;
126 if( Trace
.isOn("model-engine") ){
127 double clSet2
= double(clock())/double(CLOCKS_PER_SEC
);
128 Trace("model-engine") << "Finished model engine, time = " << (clSet2
-clSet
) << std::endl
;
131 Trace("model-engine-debug") << "No quantified formulas asserted." << std::endl
;
133 if( addedLemmas
==0 ){
134 Trace("model-engine-debug") << "No lemmas added, incomplete = " << d_incomplete_check
<< std::endl
;
135 //CVC4 will answer SAT or unknown
136 Trace("fmf-consistent") << std::endl
;
137 debugPrint("fmf-consistent");
138 if( options::produceModels() && needsBuild
){
139 // finish building the model
140 d_builder
->buildModel( fm
, true );
142 //if the check was incomplete, we must set incomplete flag
143 if( d_incomplete_check
){
144 d_quantEngine
->getOutputChannel().setIncomplete();
147 //otherwise, the search will continue
148 d_quantEngine
->flushLemmas( &d_quantEngine
->getOutputChannel() );
153 void ModelEngine::registerQuantifier( Node f
){
154 if( Trace
.isOn("fmf-warn") ){
155 bool canHandle
= true;
156 for( unsigned i
=0; i
<f
[0].getNumChildren(); i
++ ){
157 TypeNode tn
= f
[0][i
].getType();
159 if( !tn
.getCardinality().isFinite() ){
160 if( tn
.isInteger() ){
161 if( !options::fmfBoundInt() ){
171 Trace("fmf-warn") << "Warning : Model Engine : may not be able to answer SAT because of formula : " << f
<< std::endl
;
176 void ModelEngine::assertNode( Node f
){
180 bool ModelEngine::optOneQuantPerRound(){
181 return options::fmfOneQuantPerRound();
185 int ModelEngine::checkModel(){
186 FirstOrderModel
* fm
= d_quantEngine
->getModel();
188 //flatten the representatives
189 //Trace("model-engine-debug") << "Flattening representatives...." << std::endl;
190 //d_quantEngine->getEqualityQuery()->flattenRepresentatives( fm->d_rep_set.d_type_reps );
193 if( Trace
.isOn("model-engine") || Trace
.isOn("model-engine-debug") ){
194 for( std::map
< TypeNode
, std::vector
< Node
> >::iterator it
= fm
->d_rep_set
.d_type_reps
.begin();
195 it
!= fm
->d_rep_set
.d_type_reps
.end(); ++it
){
196 if( it
->first
.isSort() ){
197 Trace("model-engine") << "Cardinality( " << it
->first
<< " )" << " = " << it
->second
.size() << std::endl
;
198 if( Trace
.isOn("model-engine-debug") ){
199 Trace("model-engine-debug") << " ";
200 Node mbt
= d_quantEngine
->getTermDatabase()->getModelBasisTerm(it
->first
);
201 for( size_t i
=0; i
<it
->second
.size(); i
++ ){
202 //Trace("model-engine-debug") << it->second[i] << " ";
203 Node r
= d_quantEngine
->getEqualityQuery()->getInternalRepresentative( it
->second
[i
], Node::null(), 0 );
204 Trace("model-engine-debug") << r
<< " ";
206 Trace("model-engine-debug") << std::endl
;
207 Trace("model-engine-debug") << " Model basis term : " << mbt
<< std::endl
;
217 for( int i
=0; i
<fm
->getNumAssertedQuantifiers(); i
++ ){
218 Node f
= fm
->getAssertedQuantifier( i
);
220 for( size_t i
=0; i
<f
[0].getNumChildren(); i
++ ){
221 TypeNode tn
= f
[0][i
].getType();
222 if( fm
->d_rep_set
.hasType( tn
) ){
223 totalInst
= totalInst
* (int)fm
->d_rep_set
.d_type_reps
[ tn
].size();
226 d_totalLemmas
+= totalInst
;
229 Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl
;
230 int e_max
= options::mbqiMode()==MBQI_FMC
|| options::mbqiMode()==MBQI_FMC_INTERVAL
? 2 : ( options::mbqiMode()==MBQI_TRUST
? 0 : 1 );
231 for( int e
=0; e
<e_max
; e
++) {
232 if (d_addedLemmas
==0) {
233 for( int i
=0; i
<fm
->getNumAssertedQuantifiers(); i
++ ){
234 Node f
= fm
->getAssertedQuantifier( i
);
235 //determine if we should check this quantifier
236 if( d_builder
->isQuantifierActive( f
) ){
237 exhaustiveInstantiate( f
, e
);
238 if( Trace
.isOn("model-engine-warn") ){
239 if( d_addedLemmas
>10000 ){
240 Debug("fmf-exit") << std::endl
;
241 debugPrint("fmf-exit");
245 if( optOneQuantPerRound() && d_addedLemmas
>0 ){
249 Trace("inst-fmf-ei") << "-> Inactive : " << f
<< std::endl
;
254 //print debug information
255 Trace("model-engine-debug") << "Instantiate axioms : " << ( d_builder
->d_considerAxioms
? "yes" : "no" ) << std::endl
;
256 Trace("model-engine") << "Added Lemmas = " << d_addedLemmas
<< " / " << d_triedLemmas
<< " / ";
257 Trace("model-engine") << d_totalLemmas
<< std::endl
;
258 return d_addedLemmas
;
261 void ModelEngine::exhaustiveInstantiate( Node f
, int effort
){
262 //first check if the builder can do the exhaustive instantiation
263 d_builder
->d_triedLemmas
= 0;
264 d_builder
->d_addedLemmas
= 0;
265 d_builder
->d_incomplete_check
= false;
266 if( d_builder
->doExhaustiveInstantiation( d_quantEngine
->getModel(), f
, effort
) ){
267 Trace("inst-fmf-ei") << "-> Builder determined instantiation(s)." << std::endl
;
268 d_triedLemmas
+= d_builder
->d_triedLemmas
;
269 d_addedLemmas
+= d_builder
->d_addedLemmas
;
270 d_incomplete_check
= d_incomplete_check
|| d_builder
->d_incomplete_check
;
271 d_statistics
.d_mbqi_inst_lemmas
+= d_builder
->d_addedLemmas
;
273 Trace("inst-fmf-ei") << "-> Exhaustive instantiate " << f
<< ", effort = " << effort
<< "..." << std::endl
;
274 Debug("inst-fmf-ei") << " Instantiation Constants: ";
275 for( size_t i
=0; i
<f
[0].getNumChildren(); i
++ ){
276 Debug("inst-fmf-ei") << d_quantEngine
->getTermDatabase()->getInstantiationConstant( f
, i
) << " ";
278 Debug("inst-fmf-ei") << std::endl
;
279 //create a rep set iterator and iterate over the (relevant) domain of the quantifier
280 RepSetIterator
riter( d_quantEngine
, &(d_quantEngine
->getModel()->d_rep_set
) );
281 if( riter
.setQuantifier( f
) ){
282 Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl
;
285 while( !riter
.isFinished() && ( addedLemmas
==0 || !options::fmfOneInstPerRound() ) ){
286 //instantiation was not shown to be true, construct the match
288 for( int i
=0; i
<riter
.getNumTerms(); i
++ ){
289 m
.set( d_quantEngine
, riter
.d_index_order
[i
], riter
.getTerm( i
) );
291 Debug("fmf-model-eval") << "* Add instantiation " << m
<< std::endl
;
293 //add as instantiation
294 if( d_quantEngine
->addInstantiation( f
, m
) ){
297 Debug("fmf-model-eval") << "* Failed Add instantiation " << m
<< std::endl
;
301 d_addedLemmas
+= addedLemmas
;
302 d_triedLemmas
+= triedLemmas
;
303 d_statistics
.d_exh_inst_lemmas
+= addedLemmas
;
305 //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
306 d_incomplete_check
= d_incomplete_check
|| riter
.d_incomplete
;
310 void ModelEngine::debugPrint( const char* c
){
311 Trace( c
) << "Quantifiers: " << std::endl
;
312 for( int i
=0; i
<(int)d_quantEngine
->getModel()->getNumAssertedQuantifiers(); i
++ ){
313 Node f
= d_quantEngine
->getModel()->getAssertedQuantifier( i
);
315 if( !d_builder
->isQuantifierActive( f
) ){
316 Trace( c
) << "*Inactive* ";
320 Trace( c
) << f
<< std::endl
;
322 //d_quantEngine->getModel()->debugPrint( c );
325 ModelEngine::Statistics::Statistics():
326 d_inst_rounds("ModelEngine::Inst_Rounds", 0),
327 d_exh_inst_lemmas("ModelEngine::Instantiations_Exhaustive", 0 ),
328 d_mbqi_inst_lemmas("ModelEngine::Instantiations_Mbqi", 0 )
330 StatisticsRegistry::registerStat(&d_inst_rounds
);
331 StatisticsRegistry::registerStat(&d_exh_inst_lemmas
);
332 StatisticsRegistry::registerStat(&d_mbqi_inst_lemmas
);
335 ModelEngine::Statistics::~Statistics(){
336 StatisticsRegistry::unregisterStat(&d_inst_rounds
);
337 StatisticsRegistry::unregisterStat(&d_exh_inst_lemmas
);
338 StatisticsRegistry::unregisterStat(&d_mbqi_inst_lemmas
);