1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, Kshitij Bansal |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
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. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Implementation of model engine class. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/fmf/model_engine.h" |
17 |
|
|
18 |
|
#include "options/quantifiers_options.h" |
19 |
|
#include "theory/quantifiers/first_order_model.h" |
20 |
|
#include "theory/quantifiers/fmf/full_model_check.h" |
21 |
|
#include "theory/quantifiers/instantiate.h" |
22 |
|
#include "theory/quantifiers/quant_rep_bound_ext.h" |
23 |
|
#include "theory/quantifiers/quantifiers_attributes.h" |
24 |
|
#include "theory/quantifiers/term_database.h" |
25 |
|
|
26 |
|
using namespace cvc5::kind; |
27 |
|
using namespace cvc5::context; |
28 |
|
|
29 |
|
namespace cvc5 { |
30 |
|
namespace theory { |
31 |
|
namespace quantifiers { |
32 |
|
|
33 |
|
//Model Engine constructor |
34 |
1427 |
ModelEngine::ModelEngine(QuantifiersState& qs, |
35 |
|
QuantifiersInferenceManager& qim, |
36 |
|
QuantifiersRegistry& qr, |
37 |
|
TermRegistry& tr, |
38 |
1427 |
QModelBuilder* builder) |
39 |
|
: QuantifiersModule(qs, qim, qr, tr), |
40 |
|
d_incomplete_check(true), |
41 |
|
d_addedLemmas(0), |
42 |
|
d_triedLemmas(0), |
43 |
|
d_totalLemmas(0), |
44 |
1427 |
d_builder(builder) |
45 |
|
{ |
46 |
|
|
47 |
1427 |
} |
48 |
|
|
49 |
2854 |
ModelEngine::~ModelEngine() { |
50 |
|
|
51 |
2854 |
} |
52 |
|
|
53 |
23372 |
bool ModelEngine::needsCheck( Theory::Effort e ) { |
54 |
23372 |
return e==Theory::EFFORT_LAST_CALL; |
55 |
|
} |
56 |
|
|
57 |
1737 |
QuantifiersModule::QEffort ModelEngine::needsModel(Theory::Effort e) |
58 |
|
{ |
59 |
8658 |
if( options::mbqiInterleave() ){ |
60 |
|
return QEFFORT_STANDARD; |
61 |
|
}else{ |
62 |
1737 |
return QEFFORT_MODEL; |
63 |
|
} |
64 |
|
} |
65 |
|
|
66 |
12842 |
void ModelEngine::reset_round( Theory::Effort e ) { |
67 |
12842 |
d_incomplete_check = true; |
68 |
12842 |
} |
69 |
5184 |
void ModelEngine::check(Theory::Effort e, QEffort quant_e) |
70 |
|
{ |
71 |
5184 |
bool doCheck = false; |
72 |
5184 |
if( options::mbqiInterleave() ){ |
73 |
|
doCheck = quant_e == QEFFORT_STANDARD && d_qim.hasPendingLemma(); |
74 |
|
} |
75 |
5184 |
if( !doCheck ){ |
76 |
5184 |
doCheck = quant_e == QEFFORT_MODEL; |
77 |
|
} |
78 |
5184 |
if( doCheck ){ |
79 |
1635 |
Assert(!d_qstate.isInConflict()); |
80 |
1635 |
int addedLemmas = 0; |
81 |
|
|
82 |
|
//the following will test that the model satisfies all asserted universal quantifiers by |
83 |
|
// (model-based) exhaustive instantiation. |
84 |
1635 |
double clSet = 0; |
85 |
1635 |
if( Trace.isOn("model-engine") ){ |
86 |
|
Trace("model-engine") << "---Model Engine Round---" << std::endl; |
87 |
|
clSet = double(clock())/double(CLOCKS_PER_SEC); |
88 |
|
} |
89 |
1635 |
Trace("model-engine-debug") << "Check model..." << std::endl; |
90 |
1635 |
d_incomplete_check = false; |
91 |
|
// print debug |
92 |
1635 |
if (Trace.isOn("fmf-model-complete")) |
93 |
|
{ |
94 |
|
Trace("fmf-model-complete") << std::endl; |
95 |
|
debugPrint("fmf-model-complete"); |
96 |
|
} |
97 |
|
// successfully built an acceptable model, now check it |
98 |
1635 |
addedLemmas += checkModel(); |
99 |
|
|
100 |
1635 |
if( Trace.isOn("model-engine") ){ |
101 |
|
double clSet2 = double(clock())/double(CLOCKS_PER_SEC); |
102 |
|
Trace("model-engine") << "Finished model engine, time = " << (clSet2-clSet) << std::endl; |
103 |
|
} |
104 |
|
|
105 |
1635 |
if( addedLemmas==0 ){ |
106 |
996 |
Trace("model-engine-debug") |
107 |
498 |
<< "No lemmas added, incomplete = " |
108 |
498 |
<< (d_incomplete_check || !d_incompleteQuants.empty()) << std::endl; |
109 |
|
// cvc5 will answer SAT or unknown |
110 |
498 |
if( Trace.isOn("fmf-consistent") ){ |
111 |
|
Trace("fmf-consistent") << std::endl; |
112 |
|
debugPrint("fmf-consistent"); |
113 |
|
} |
114 |
|
} |
115 |
|
} |
116 |
5184 |
} |
117 |
|
|
118 |
434 |
bool ModelEngine::checkComplete(IncompleteId& incId) |
119 |
|
{ |
120 |
434 |
if (d_incomplete_check) |
121 |
|
{ |
122 |
|
incId = IncompleteId::QUANTIFIERS_FMF; |
123 |
|
return false; |
124 |
|
} |
125 |
434 |
return true; |
126 |
|
} |
127 |
|
|
128 |
1159 |
bool ModelEngine::checkCompleteFor( Node q ) { |
129 |
1159 |
return d_incompleteQuants.find(q) == d_incompleteQuants.end(); |
130 |
|
} |
131 |
|
|
132 |
3055 |
void ModelEngine::registerQuantifier( Node f ){ |
133 |
3055 |
if( Trace.isOn("fmf-warn") ){ |
134 |
|
bool canHandle = true; |
135 |
|
for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ |
136 |
|
TypeNode tn = f[0][i].getType(); |
137 |
|
if( !tn.isSort() ){ |
138 |
|
if (!d_qstate.isFiniteType(tn)) |
139 |
|
{ |
140 |
|
if( tn.isInteger() ){ |
141 |
|
if( !options::fmfBound() ){ |
142 |
|
canHandle = false; |
143 |
|
} |
144 |
|
}else{ |
145 |
|
canHandle = false; |
146 |
|
} |
147 |
|
} |
148 |
|
} |
149 |
|
} |
150 |
|
if( !canHandle ){ |
151 |
|
Trace("fmf-warn") << "Warning : Model Engine : may not be able to answer SAT because of formula : " << f << std::endl; |
152 |
|
} |
153 |
|
} |
154 |
3055 |
} |
155 |
|
|
156 |
1635 |
int ModelEngine::checkModel(){ |
157 |
1635 |
FirstOrderModel* fm = d_treg.getModel(); |
158 |
|
|
159 |
|
//for debugging, setup |
160 |
7637 |
for (std::map<TypeNode, std::vector<Node> >::iterator it = |
161 |
1635 |
fm->getRepSetPtr()->d_type_reps.begin(); |
162 |
9272 |
it != fm->getRepSetPtr()->d_type_reps.end(); |
163 |
|
++it) |
164 |
|
{ |
165 |
7637 |
if( it->first.isSort() ){ |
166 |
1912 |
Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl; |
167 |
1912 |
Trace("model-engine-debug") << " Reps : "; |
168 |
5414 |
for( size_t i=0; i<it->second.size(); i++ ){ |
169 |
3502 |
Trace("model-engine-debug") << it->second[i] << " "; |
170 |
|
} |
171 |
1912 |
Trace("model-engine-debug") << std::endl; |
172 |
1912 |
Trace("model-engine-debug") << " Term reps : "; |
173 |
5414 |
for( size_t i=0; i<it->second.size(); i++ ){ |
174 |
7004 |
Node r = fm->getInternalRepresentative(it->second[i], Node::null(), 0); |
175 |
3502 |
if (r.isNull()) |
176 |
|
{ |
177 |
|
// there was an invalid equivalence class |
178 |
|
d_incomplete_check = true; |
179 |
|
} |
180 |
3502 |
Trace("model-engine-debug") << r << " "; |
181 |
|
} |
182 |
1912 |
Trace("model-engine-debug") << std::endl; |
183 |
3824 |
Node mbt = fm->getModelBasisTerm(it->first); |
184 |
1912 |
Trace("model-engine-debug") << " Basis term : " << mbt << std::endl; |
185 |
|
} |
186 |
|
} |
187 |
|
|
188 |
1635 |
d_triedLemmas = 0; |
189 |
1635 |
d_addedLemmas = 0; |
190 |
1635 |
d_totalLemmas = 0; |
191 |
|
//for statistics |
192 |
1635 |
if( Trace.isOn("model-engine") ){ |
193 |
|
for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ |
194 |
|
Node f = fm->getAssertedQuantifier( i ); |
195 |
|
if (fm->isQuantifierActive(f) && shouldProcess(f)) |
196 |
|
{ |
197 |
|
int totalInst = 1; |
198 |
|
for( unsigned j=0; j<f[0].getNumChildren(); j++ ){ |
199 |
|
TypeNode tn = f[0][j].getType(); |
200 |
|
if (fm->getRepSet()->hasType(tn)) |
201 |
|
{ |
202 |
|
totalInst = |
203 |
|
totalInst * (int)fm->getRepSet()->getNumRepresentatives(tn); |
204 |
|
} |
205 |
|
} |
206 |
|
d_totalLemmas += totalInst; |
207 |
|
} |
208 |
|
} |
209 |
|
} |
210 |
|
|
211 |
1635 |
Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl; |
212 |
|
// FMC uses two sub-effort levels |
213 |
1635 |
int e_max = options::mbqiMode() == options::MbqiMode::FMC |
214 |
1984 |
? 2 |
215 |
1984 |
: (options::mbqiMode() == options::MbqiMode::TRUST ? 0 : 1); |
216 |
2970 |
for( int e=0; e<e_max; e++) { |
217 |
2472 |
d_incompleteQuants.clear(); |
218 |
14075 |
for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){ |
219 |
22782 |
Node q = fm->getAssertedQuantifier( i, true ); |
220 |
11603 |
Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << q << ", effort = " << e << "..." << std::endl; |
221 |
|
//determine if we should check this quantifier |
222 |
11613 |
if (!fm->isQuantifierActive(q)) |
223 |
|
{ |
224 |
10 |
Trace("fmf-exh-inst") << "-> Inactive : " << q << std::endl; |
225 |
10 |
continue; |
226 |
|
} |
227 |
12007 |
if (!shouldProcess(q)) |
228 |
|
{ |
229 |
414 |
Trace("fmf-exh-inst") << "-> Not processed : " << q << std::endl; |
230 |
414 |
d_incompleteQuants.insert(q); |
231 |
414 |
continue; |
232 |
|
} |
233 |
11179 |
exhaustiveInstantiate(q, e); |
234 |
11179 |
if (d_qstate.isInConflict()) |
235 |
|
{ |
236 |
|
break; |
237 |
|
} |
238 |
|
} |
239 |
2472 |
if( d_addedLemmas>0 ){ |
240 |
1137 |
break; |
241 |
|
}else{ |
242 |
1335 |
Assert(!d_qstate.isInConflict()); |
243 |
|
} |
244 |
|
} |
245 |
|
|
246 |
|
//print debug information |
247 |
1635 |
if (d_qstate.isInConflict()) |
248 |
|
{ |
249 |
|
Trace("model-engine") << "Conflict, added lemmas = "; |
250 |
|
}else{ |
251 |
1635 |
Trace("model-engine") << "Added Lemmas = "; |
252 |
|
} |
253 |
1635 |
Trace("model-engine") << d_addedLemmas << " / " << d_triedLemmas << " / "; |
254 |
1635 |
Trace("model-engine") << d_totalLemmas << std::endl; |
255 |
1635 |
return d_addedLemmas; |
256 |
|
} |
257 |
|
|
258 |
|
|
259 |
|
|
260 |
11179 |
void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ |
261 |
|
//first check if the builder can do the exhaustive instantiation |
262 |
11179 |
unsigned prev_alem = d_builder->getNumAddedLemmas(); |
263 |
11179 |
unsigned prev_tlem = d_builder->getNumTriedLemmas(); |
264 |
11179 |
FirstOrderModel* fm = d_treg.getModel(); |
265 |
11179 |
int retEi = d_builder->doExhaustiveInstantiation(fm, f, effort); |
266 |
11179 |
if( retEi!=0 ){ |
267 |
10955 |
if( retEi<0 ){ |
268 |
|
Trace("fmf-exh-inst") << "-> Builder determined complete instantiation was impossible." << std::endl; |
269 |
|
d_incompleteQuants.insert(f); |
270 |
|
}else{ |
271 |
10955 |
Trace("fmf-exh-inst") << "-> Builder determined instantiation(s)." << std::endl; |
272 |
|
} |
273 |
10955 |
d_triedLemmas += d_builder->getNumTriedLemmas() - prev_tlem; |
274 |
10955 |
d_addedLemmas += d_builder->getNumAddedLemmas() - prev_alem; |
275 |
|
}else{ |
276 |
224 |
if( Trace.isOn("fmf-exh-inst-debug") ){ |
277 |
|
Trace("fmf-exh-inst-debug") << " Instantiation Constants: "; |
278 |
|
for( size_t i=0; i<f[0].getNumChildren(); i++ ){ |
279 |
|
Trace("fmf-exh-inst-debug") |
280 |
|
<< d_qreg.getInstantiationConstant(f, i) << " "; |
281 |
|
} |
282 |
|
Trace("fmf-exh-inst-debug") << std::endl; |
283 |
|
} |
284 |
224 |
QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference(); |
285 |
|
//create a rep set iterator and iterate over the (relevant) domain of the quantifier |
286 |
448 |
QRepBoundExt qrbe(qbi, fm); |
287 |
448 |
RepSetIterator riter(fm->getRepSet(), &qrbe); |
288 |
224 |
if( riter.setQuantifier( f ) ){ |
289 |
224 |
Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.isIncomplete() << "..." << std::endl; |
290 |
224 |
if( !riter.isIncomplete() ){ |
291 |
210 |
int triedLemmas = 0; |
292 |
210 |
int addedLemmas = 0; |
293 |
210 |
Instantiate* inst = d_qim.getInstantiate(); |
294 |
1536 |
while( !riter.isFinished() && ( addedLemmas==0 || !options::fmfOneInstPerRound() ) ){ |
295 |
|
//instantiation was not shown to be true, construct the match |
296 |
1326 |
InstMatch m( f ); |
297 |
1983 |
for (unsigned i = 0; i < riter.getNumTerms(); i++) |
298 |
|
{ |
299 |
1320 |
m.set(d_qstate, i, riter.getCurrentTerm(i)); |
300 |
|
} |
301 |
663 |
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl; |
302 |
663 |
triedLemmas++; |
303 |
|
//add as instantiation |
304 |
1326 |
if (inst->addInstantiation(f, |
305 |
|
m.d_vals, |
306 |
|
InferenceId::QUANTIFIERS_INST_FMF_EXH, |
307 |
1326 |
Node::null(), |
308 |
|
true)) |
309 |
|
{ |
310 |
317 |
addedLemmas++; |
311 |
317 |
if (d_qstate.isInConflict()) |
312 |
|
{ |
313 |
|
break; |
314 |
|
} |
315 |
|
}else{ |
316 |
346 |
Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl; |
317 |
|
} |
318 |
663 |
riter.increment(); |
319 |
|
} |
320 |
210 |
d_addedLemmas += addedLemmas; |
321 |
210 |
d_triedLemmas += triedLemmas; |
322 |
|
} |
323 |
|
}else{ |
324 |
|
Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter.isIncomplete() << "..." << std::endl; |
325 |
|
} |
326 |
|
//if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round |
327 |
224 |
if( riter.isIncomplete() ){ |
328 |
22 |
d_incompleteQuants.insert(f); |
329 |
|
} |
330 |
|
} |
331 |
11179 |
} |
332 |
|
|
333 |
|
void ModelEngine::debugPrint( const char* c ){ |
334 |
|
if (Trace.isOn(c)) |
335 |
|
{ |
336 |
|
Trace(c) << "Quantifiers: " << std::endl; |
337 |
|
FirstOrderModel* m = d_treg.getModel(); |
338 |
|
for (size_t i = 0, nquant = m->getNumAssertedQuantifiers(); i < nquant; i++) |
339 |
|
{ |
340 |
|
Node q = m->getAssertedQuantifier(i); |
341 |
|
if (d_qreg.hasOwnership(q, this)) |
342 |
|
{ |
343 |
|
Trace(c) << " "; |
344 |
|
if (!m->isQuantifierActive(q)) |
345 |
|
{ |
346 |
|
Trace(c) << "*Inactive* "; |
347 |
|
} |
348 |
|
else |
349 |
|
{ |
350 |
|
Trace(c) << " "; |
351 |
|
} |
352 |
|
Trace(c) << q << std::endl; |
353 |
|
} |
354 |
|
} |
355 |
|
} |
356 |
|
} |
357 |
|
|
358 |
11593 |
bool ModelEngine::shouldProcess(Node q) |
359 |
|
{ |
360 |
11593 |
if (!d_qreg.hasOwnership(q, this)) |
361 |
|
{ |
362 |
404 |
return false; |
363 |
|
} |
364 |
|
// if finite model finding or fmf bound is on, we process everything |
365 |
11189 |
if (options::finiteModelFind() || options::fmfBound()) |
366 |
|
{ |
367 |
9586 |
return true; |
368 |
|
} |
369 |
|
// otherwise, we are only using model-based instantiation for internal |
370 |
|
// quantified formulas |
371 |
1603 |
QuantAttributes& qattr = d_qreg.getQuantAttributes(); |
372 |
1603 |
return qattr.isInternal(q); |
373 |
|
} |
374 |
|
|
375 |
|
} // namespace quantifiers |
376 |
|
} // namespace theory |
377 |
36207 |
} // namespace cvc5 |