Track instantiation reasons in proofs (#6935)
[cvc5.git] / src / theory / quantifiers / fmf / full_model_check.cpp
1 /******************************************************************************
2 * Top contributors (to current version):
3 * Andrew Reynolds, Mathias Preiner, Aina Niemetz
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 full model check class.
14 */
15
16 #include "theory/quantifiers/fmf/full_model_check.h"
17
18 #include "expr/skolem_manager.h"
19 #include "options/quantifiers_options.h"
20 #include "options/strings_options.h"
21 #include "options/theory_options.h"
22 #include "options/uf_options.h"
23 #include "theory/quantifiers/first_order_model.h"
24 #include "theory/quantifiers/fmf/bounded_integers.h"
25 #include "theory/quantifiers/instantiate.h"
26 #include "theory/quantifiers/quant_rep_bound_ext.h"
27 #include "theory/quantifiers/quantifiers_inference_manager.h"
28 #include "theory/quantifiers/quantifiers_registry.h"
29 #include "theory/quantifiers/quantifiers_state.h"
30 #include "theory/quantifiers/term_database.h"
31 #include "theory/quantifiers/term_util.h"
32 #include "theory/rewriter.h"
33
34 using namespace cvc5::kind;
35 using namespace cvc5::context;
36
37 namespace cvc5 {
38 namespace theory {
39 namespace quantifiers {
40 namespace fmcheck {
41
42 struct ModelBasisArgSort
43 {
44 std::vector< Node > d_terms;
45 // number of arguments that are model-basis terms
46 std::unordered_map<Node, unsigned> d_mba_count;
47 bool operator() (int i,int j) {
48 return (d_mba_count[d_terms[i]] < d_mba_count[d_terms[j]]);
49 }
50 };
51
52 bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
53 if (index==(int)c.getNumChildren()) {
54 return d_data!=-1;
55 }else{
56 TypeNode tn = c[index].getType();
57 Node st = m->getStar(tn);
58 if(d_child.find(st)!=d_child.end()) {
59 if( d_child[st].hasGeneralization(m, c, index+1) ){
60 return true;
61 }
62 }
63 if( c[index]!=st && d_child.find( c[index] )!=d_child.end() ){
64 if( d_child[ c[index] ].hasGeneralization(m, c, index+1) ){
65 return true;
66 }
67 }
68 if( c[index].getType().isSort() ){
69 //for star: check if all children are defined and have generalizations
70 if( c[index]==st ){ ///options::fmfFmcCoverSimplify()
71 //check if all children exist and are complete
72 unsigned num_child_def =
73 d_child.size() - (d_child.find(st) != d_child.end() ? 1 : 0);
74 if (num_child_def == m->getRepSet()->getNumRepresentatives(tn))
75 {
76 bool complete = true;
77 for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
78 if( !m->isStar(it->first) ){
79 if( !it->second.hasGeneralization(m, c, index+1) ){
80 complete = false;
81 break;
82 }
83 }
84 }
85 if( complete ){
86 return true;
87 }
88 }
89 }
90 }
91
92 return false;
93 }
94 }
95
96 int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index ) {
97 Debug("fmc-entry-trie") << "Get generalization index " << inst.size() << " " << index << std::endl;
98 if (index==(int)inst.size()) {
99 return d_data;
100 }else{
101 int minIndex = -1;
102 Node st = m->getStar(inst[index].getType());
103 if (d_child.find(st) != d_child.end())
104 {
105 minIndex = d_child[st].getGeneralizationIndex(m, inst, index + 1);
106 }
107 Node cc = inst[index];
108 if (cc != st && d_child.find(cc) != d_child.end())
109 {
110 int gindex = d_child[cc].getGeneralizationIndex(m, inst, index + 1);
111 if (minIndex == -1 || (gindex != -1 && gindex < minIndex))
112 {
113 minIndex = gindex;
114 }
115 }
116 return minIndex;
117 }
118 }
119
120 void EntryTrie::addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index ) {
121 if (index==(int)c.getNumChildren()) {
122 if(d_data==-1) {
123 d_data = data;
124 }
125 }
126 else {
127 d_child[ c[index] ].addEntry(m,c,v,data,index+1);
128 if( d_complete==0 ){
129 d_complete = -1;
130 }
131 }
132 }
133
134 void EntryTrie::getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index, bool is_gen ) {
135 if (index==(int)c.getNumChildren()) {
136 if( d_data!=-1) {
137 if( is_gen ){
138 gen.push_back(d_data);
139 }
140 compat.push_back(d_data);
141 }
142 }else{
143 if (m->isStar(c[index])) {
144 for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
145 it->second.getEntries(m, c, compat, gen, index+1, is_gen );
146 }
147 }else{
148 Node st = m->getStar(c[index].getType());
149 if(d_child.find(st)!=d_child.end()) {
150 d_child[st].getEntries(m, c, compat, gen, index+1, false);
151 }
152 if( d_child.find( c[index] )!=d_child.end() ){
153 d_child[ c[index] ].getEntries(m, c, compat, gen, index+1, is_gen);
154 }
155 }
156
157 }
158 }
159
160 bool Def::addEntry( FirstOrderModelFmc * m, Node c, Node v) {
161 if (d_et.hasGeneralization(m, c)) {
162 Trace("fmc-debug") << "Already has generalization, skip." << std::endl;
163 return false;
164 }
165 int newIndex = (int)d_cond.size();
166 if (!d_has_simplified) {
167 std::vector<int> compat;
168 std::vector<int> gen;
169 d_et.getEntries(m, c, compat, gen);
170 for( unsigned i=0; i<compat.size(); i++) {
171 if( d_status[compat[i]]==status_unk ){
172 if( d_value[compat[i]]!=v ){
173 d_status[compat[i]] = status_non_redundant;
174 }
175 }
176 }
177 for( unsigned i=0; i<gen.size(); i++) {
178 if( d_status[gen[i]]==status_unk ){
179 if( d_value[gen[i]]==v ){
180 d_status[gen[i]] = status_redundant;
181 }
182 }
183 }
184 d_status.push_back( status_unk );
185 }
186 d_et.addEntry(m, c, v, newIndex);
187 d_cond.push_back(c);
188 d_value.push_back(v);
189 return true;
190 }
191
192 Node Def::evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
193 int gindex = d_et.getGeneralizationIndex(m, inst);
194 if (gindex!=-1) {
195 return d_value[gindex];
196 }else{
197 Trace("fmc-warn") << "Warning : evaluation came up null!" << std::endl;
198 return Node::null();
199 }
200 }
201
202 int Def::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
203 return d_et.getGeneralizationIndex(m, inst);
204 }
205
206 void Def::basic_simplify( FirstOrderModelFmc * m ) {
207 d_has_simplified = true;
208 std::vector< Node > cond;
209 cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
210 d_cond.clear();
211 std::vector< Node > value;
212 value.insert( value.end(), d_value.begin(), d_value.end() );
213 d_value.clear();
214 d_et.reset();
215 for (unsigned i=0; i<d_status.size(); i++) {
216 if( d_status[i]!=status_redundant ){
217 addEntry(m, cond[i], value[i]);
218 }
219 }
220 d_status.clear();
221 }
222
223 void Def::simplify(FullModelChecker * mc, FirstOrderModelFmc * m) {
224 Trace("fmc-simplify") << "Simplify definition, #cond = " << d_cond.size() << std::endl;
225 basic_simplify( m );
226 Trace("fmc-simplify") << "post-basic simplify, #cond = " << d_cond.size() << std::endl;
227
228 //check if the last entry is not all star, if so, we can make the last entry all stars
229 if( !d_cond.empty() ){
230 bool last_all_stars = true;
231 Node cc = d_cond[d_cond.size()-1];
232 for( unsigned i=0; i<cc.getNumChildren(); i++ ){
233 if (!m->isStar(cc[i]))
234 {
235 last_all_stars = false;
236 break;
237 }
238 }
239 if( !last_all_stars ){
240 Trace("fmc-cover-simplify") << "Need to modify last entry to be all stars." << std::endl;
241 Trace("fmc-cover-simplify") << "Before: " << std::endl;
242 debugPrint("fmc-cover-simplify",Node::null(), mc);
243 Trace("fmc-cover-simplify") << std::endl;
244 std::vector< Node > cond;
245 cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
246 d_cond.clear();
247 std::vector< Node > value;
248 value.insert( value.end(), d_value.begin(), d_value.end() );
249 d_value.clear();
250 d_et.reset();
251 d_has_simplified = false;
252 //change the last to all star
253 std::vector< Node > nc;
254 nc.push_back( cc.getOperator() );
255 for( unsigned j=0; j< cc.getNumChildren(); j++){
256 nc.push_back(m->getStar(cc[j].getType()));
257 }
258 cond[cond.size()-1] = NodeManager::currentNM()->mkNode( APPLY_UF, nc );
259 //re-add the entries
260 for (unsigned i=0; i<cond.size(); i++) {
261 addEntry(m, cond[i], value[i]);
262 }
263 Trace("fmc-cover-simplify") << "Finished re-adding entries." << std::endl;
264 basic_simplify( m );
265 Trace("fmc-cover-simplify") << "After: " << std::endl;
266 debugPrint("fmc-cover-simplify",Node::null(), mc);
267 Trace("fmc-cover-simplify") << std::endl;
268 }
269 }
270 Trace("fmc-simplify") << "finish simplify, #cond = " << d_cond.size() << std::endl;
271 }
272
273 void Def::debugPrint(const char * tr, Node op, FullModelChecker * m) {
274 if (!op.isNull()) {
275 Trace(tr) << "Model for " << op << " : " << std::endl;
276 }
277 for( unsigned i=0; i<d_cond.size(); i++) {
278 //print the condition
279 if (!op.isNull()) {
280 Trace(tr) << op;
281 }
282 m->debugPrintCond(tr, d_cond[i], true);
283 Trace(tr) << " -> ";
284 m->debugPrint(tr, d_value[i]);
285 Trace(tr) << std::endl;
286 }
287 }
288
289 FullModelChecker::FullModelChecker(QuantifiersState& qs,
290 QuantifiersInferenceManager& qim,
291 QuantifiersRegistry& qr,
292 TermRegistry& tr)
293 : QModelBuilder(qs, qim, qr, tr), d_fm(new FirstOrderModelFmc(qs, qr, tr))
294 {
295 d_true = NodeManager::currentNM()->mkConst(true);
296 d_false = NodeManager::currentNM()->mkConst(false);
297 }
298
299 void FullModelChecker::finishInit() { d_model = d_fm.get(); }
300
301 bool FullModelChecker::preProcessBuildModel(TheoryModel* m) {
302 //standard pre-process
303 if( !preProcessBuildModelStd( m ) ){
304 return false;
305 }
306
307 Trace("fmc") << "---Full Model Check preprocess() " << std::endl;
308 d_preinitialized_eqc.clear();
309 d_preinitialized_types.clear();
310 //traverse equality engine
311 eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(m->getEqualityEngine());
312 while( !eqcs_i.isFinished() ){
313 Node r = *eqcs_i;
314 TypeNode tr = r.getType();
315 d_preinitialized_eqc[tr] = r;
316 ++eqcs_i;
317 }
318
319 //must ensure model basis terms exists in model for each relevant type
320 Trace("fmc") << "preInitialize types..." << std::endl;
321 d_fm->initialize();
322 for (std::pair<const Node, Def*>& mp : d_fm->d_models)
323 {
324 Node op = mp.first;
325 Trace("fmc") << "preInitialize types for " << op << std::endl;
326 TypeNode tno = op.getType();
327 for( unsigned i=0; i<tno.getNumChildren(); i++) {
328 Trace("fmc") << "preInitializeType " << tno[i] << std::endl;
329 preInitializeType(m, tno[i]);
330 Trace("fmc") << "finished preInitializeType " << tno[i] << std::endl;
331 }
332 }
333 Trace("fmc") << "Finish preInitialize types" << std::endl;
334 //do not have to introduce terms for sorts of domains of quantified formulas if we are allowed to assume empty sorts
335 for (unsigned i = 0, nquant = d_fm->getNumAssertedQuantifiers(); i < nquant;
336 i++)
337 {
338 Node q = d_fm->getAssertedQuantifier(i);
339 registerQuantifiedFormula(q);
340 if (!isHandled(q))
341 {
342 continue;
343 }
344 // make sure all types are set
345 for (const Node& v : q[0])
346 {
347 preInitializeType(m, v.getType());
348 }
349 }
350 return true;
351 }
352
353 bool FullModelChecker::processBuildModel(TheoryModel* m){
354 if (!m->areFunctionValuesEnabled())
355 {
356 // nothing to do if no functions
357 return true;
358 }
359 FirstOrderModelFmc* fm = d_fm.get();
360 Trace("fmc") << "---Full Model Check reset() " << std::endl;
361 d_quant_models.clear();
362 d_rep_ids.clear();
363 d_star_insts.clear();
364 //process representatives
365 RepSet* rs = m->getRepSetPtr();
366 for (std::map<TypeNode, std::vector<Node> >::iterator it =
367 rs->d_type_reps.begin();
368 it != rs->d_type_reps.end();
369 ++it)
370 {
371 if( it->first.isSort() ){
372 Trace("fmc") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
373 for( size_t a=0; a<it->second.size(); a++ ){
374 Node r = m->getRepresentative(it->second[a]);
375 if( Trace.isOn("fmc-model-debug") ){
376 std::vector< Node > eqc;
377 d_qstate.getEquivalenceClass(r, eqc);
378 Trace("fmc-model-debug") << " " << (it->second[a]==r);
379 Trace("fmc-model-debug") << " : " << it->second[a] << " : " << r << " : ";
380 //Trace("fmc-model-debug") << r2 << " : " << ir << " : ";
381 Trace("fmc-model-debug") << " {";
382 for( size_t i=0; i<eqc.size(); i++ ){
383 Trace("fmc-model-debug") << eqc[i] << ", ";
384 }
385 Trace("fmc-model-debug") << "}" << std::endl;
386 }
387 d_rep_ids[it->first][r] = (int)a;
388 }
389 Trace("fmc-model-debug") << std::endl;
390 }
391 }
392
393 //now, make models
394 for (std::pair<const Node, Def*>& fmm : d_fm->d_models)
395 {
396 Node op = fmm.first;
397 //reset the model
398 d_fm->d_models[op]->reset();
399
400 std::vector< Node > add_conds;
401 std::vector< Node > add_values;
402 bool needsDefault = true;
403 if (m->hasUfTerms(op))
404 {
405 const std::vector<Node>& uft = m->getUfTerms(op);
406 Trace("fmc-model-debug")
407 << uft.size() << " model values for " << op << " ... " << std::endl;
408 for (const Node& n : uft)
409 {
410 // only consider unique up to congruence (in model equality engine)?
411 add_conds.push_back( n );
412 add_values.push_back( n );
413 Node r = m->getRepresentative(n);
414 Trace("fmc-model-debug") << n << " -> " << r << std::endl;
415 }
416 }else{
417 Trace("fmc-model-debug") << "No model values for " << op << " ... " << std::endl;
418 }
419 Trace("fmc-model-debug") << std::endl;
420 //possibly get default
421 if( needsDefault ){
422 Node nmb = d_fm->getModelBasisOpTerm(op);
423 //add default value if necessary
424 if (m->hasTerm(nmb))
425 {
426 Trace("fmc-model-debug") << "Add default " << nmb << std::endl;
427 add_conds.push_back( nmb );
428 add_values.push_back( nmb );
429 }else{
430 Node vmb = getSomeDomainElement(d_fm.get(), nmb.getType());
431 Trace("fmc-model-debug") << "Add default to default representative " << nmb << " ";
432 Trace("fmc-model-debug")
433 << m->getRepSet()->getNumRepresentatives(nmb.getType())
434 << std::endl;
435 add_conds.push_back( nmb );
436 add_values.push_back( vmb );
437 }
438 }
439
440 std::vector< Node > conds;
441 std::vector< Node > values;
442 std::vector< Node > entry_conds;
443 //get the entries for the model
444 for( size_t i=0; i<add_conds.size(); i++ ){
445 Node c = add_conds[i];
446 Node v = add_values[i];
447 Trace("fmc-model-debug")
448 << "Add cond/value : " << c << " -> " << v << std::endl;
449 std::vector< Node > children;
450 std::vector< Node > entry_children;
451 children.push_back(op);
452 entry_children.push_back(op);
453 bool hasNonStar = false;
454 for (const Node& ci : c)
455 {
456 Node ri = fm->getRepresentative(ci);
457 children.push_back(ri);
458 bool isStar = false;
459 if (fm->isModelBasisTerm(ri))
460 {
461 ri = fm->getStar(ri.getType());
462 isStar = true;
463 }
464 else
465 {
466 hasNonStar = true;
467 }
468 if( !isStar && !ri.isConst() ){
469 Trace("fmc-warn") << "Warning : model for " << op
470 << " has non-constant argument in model " << ri
471 << " (from " << ci << ")" << std::endl;
472 Assert(false);
473 }
474 entry_children.push_back(ri);
475 }
476 Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
477 Node nv = fm->getRepresentative( v );
478 Trace("fmc-model-debug")
479 << "Representative of " << v << " is " << nv << std::endl;
480 if( !nv.isConst() ){
481 Trace("fmc-warn") << "Warning : model for " << op << " has non-constant value in model " << nv << std::endl;
482 Assert(false);
483 }
484 Node en = (useSimpleModels() && hasNonStar) ? n : NodeManager::currentNM()->mkNode( APPLY_UF, entry_children );
485 if( std::find(conds.begin(), conds.end(), n )==conds.end() ){
486 Trace("fmc-model-debug") << "- add " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
487 conds.push_back(n);
488 values.push_back(nv);
489 entry_conds.push_back(en);
490 }
491 else {
492 Trace("fmc-model-debug") << "Already have entry for : " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
493 }
494 }
495
496
497 //sort based on # default arguments
498 std::vector< int > indices;
499 ModelBasisArgSort mbas;
500 for (int i=0; i<(int)conds.size(); i++) {
501 mbas.d_terms.push_back(conds[i]);
502 mbas.d_mba_count[conds[i]] = fm->getModelBasisArg(conds[i]);
503 indices.push_back(i);
504 }
505 std::sort( indices.begin(), indices.end(), mbas );
506
507 for (int i=0; i<(int)indices.size(); i++) {
508 fm->d_models[op]->addEntry(fm, entry_conds[indices[i]], values[indices[i]]);
509 }
510
511 Trace("fmc-model-simplify") << "Before simplification : " << std::endl;
512 fm->d_models[op]->debugPrint("fmc-model-simplify", op, this);
513 Trace("fmc-model-simplify") << std::endl;
514
515 Trace("fmc-model-simplify") << "Simplifying " << op << "..." << std::endl;
516 fm->d_models[op]->simplify( this, fm );
517
518 fm->d_models[op]->debugPrint("fmc-model", op, this);
519 Trace("fmc-model") << std::endl;
520
521 //for debugging
522 /*
523 for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
524 std::vector< Node > inst;
525 for( unsigned j=0; j<fm->d_uf_terms[op][i].getNumChildren(); j++ ){
526 Node r = fm->getRepresentative( fm->d_uf_terms[op][i][j] );
527 inst.push_back( r );
528 }
529 Node ev = fm->d_models[op]->evaluate( fm, inst );
530 Trace("fmc-model-debug") << ".....Checking eval( " <<
531 fm->d_uf_terms[op][i] << " ) = " << ev << std::endl; AlwaysAssert(
532 fm->areEqual( ev, fm->d_uf_terms[op][i] ) );
533 }
534 */
535 }
536 Assert(d_addedLemmas == 0);
537
538 //make function values
539 for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ){
540 Node f_def = getFunctionValue( fm, it->first, "$x" );
541 m->assignFunctionDefinition( it->first, f_def );
542 }
543 return TheoryEngineModelBuilder::processBuildModel( m );
544 }
545
546 void FullModelChecker::preInitializeType(TheoryModel* m, TypeNode tn)
547 {
548 if( d_preinitialized_types.find( tn )==d_preinitialized_types.end() ){
549 d_preinitialized_types[tn] = true;
550 if (tn.isFirstClass())
551 {
552 Trace("fmc") << "Get model basis term " << tn << "..." << std::endl;
553 Node mb = d_fm->getModelBasisTerm(tn);
554 Trace("fmc") << "...return " << mb << std::endl;
555 // if the model basis term does not exist in the model,
556 // either add it directly to the model's equality engine if no other terms
557 // of this type exist, or otherwise assert that it is equal to the first
558 // equivalence class of its type.
559 if (!m->hasTerm(mb) && !mb.isConst())
560 {
561 std::map<TypeNode, Node>::iterator itpe = d_preinitialized_eqc.find(tn);
562 if (itpe == d_preinitialized_eqc.end())
563 {
564 Trace("fmc") << "...add model basis term to EE of model " << mb << " "
565 << tn << std::endl;
566 m->getEqualityEngine()->addTerm(mb);
567 }
568 else
569 {
570 Trace("fmc") << "...add model basis eqc equality to model " << mb
571 << " == " << itpe->second << " " << tn << std::endl;
572 bool ret = m->assertEquality(mb, itpe->second, true);
573 AlwaysAssert(ret);
574 }
575 }
576 }
577 }
578 }
579
580 void FullModelChecker::debugPrintCond(const char * tr, Node n, bool dispStar) {
581 Trace(tr) << "(";
582 for( unsigned j=0; j<n.getNumChildren(); j++) {
583 if( j>0 ) Trace(tr) << ", ";
584 debugPrint(tr, n[j], dispStar);
585 }
586 Trace(tr) << ")";
587 }
588
589 void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) {
590 if( n.isNull() ){
591 Trace(tr) << "null";
592 }
593 else if (FirstOrderModelFmc::isStar(n) && dispStar)
594 {
595 Trace(tr) << "*";
596 }
597 else
598 {
599 TypeNode tn = n.getType();
600 if( tn.isSort() && d_rep_ids.find(tn)!=d_rep_ids.end() ){
601 if (d_rep_ids[tn].find(n)!=d_rep_ids[tn].end()) {
602 Trace(tr) << d_rep_ids[tn][n];
603 }else{
604 Trace(tr) << n;
605 }
606 }else{
607 Trace(tr) << n;
608 }
609 }
610 }
611
612
613 int FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
614 Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl;
615 // register the quantifier
616 registerQuantifiedFormula(f);
617 Assert(!d_qstate.isInConflict());
618 // we do not do model-based quantifier instantiation if the option
619 // disables it, or if the quantified formula has an unhandled type.
620 if (!optUseModel() || !isHandled(f))
621 {
622 return 0;
623 }
624 FirstOrderModelFmc* fmfmc = static_cast<FirstOrderModelFmc*>(fm);
625 if (effort == 0)
626 {
627 if (options::mbqiMode() == options::MbqiMode::NONE)
628 {
629 // just exhaustive instantiate
630 Node c = mkCondDefault(fmfmc, f);
631 d_quant_models[f].addEntry(fmfmc, c, d_false);
632 if (!exhaustiveInstantiate(fmfmc, f, c))
633 {
634 return 0;
635 }
636 return 1;
637 }
638 // model check the quantifier
639 doCheck(fmfmc, f, d_quant_models[f], f[1]);
640 std::vector<Node>& mcond = d_quant_models[f].d_cond;
641 Trace("fmc") << "Definition for quantifier " << f << " is : " << std::endl;
642 Assert(!mcond.empty());
643 d_quant_models[f].debugPrint("fmc", Node::null(), this);
644 Trace("fmc") << std::endl;
645
646 // consider all entries going to non-true
647 Instantiate* instq = d_qim.getInstantiate();
648 for (unsigned i = 0, msize = mcond.size(); i < msize; i++)
649 {
650 if (d_quant_models[f].d_value[i] == d_true)
651 {
652 // already satisfied
653 continue;
654 }
655 Trace("fmc-inst") << "Instantiate based on " << mcond[i] << "..."
656 << std::endl;
657 bool hasStar = false;
658 std::vector<Node> inst;
659 for (unsigned j = 0, nchild = mcond[i].getNumChildren(); j < nchild; j++)
660 {
661 if (fmfmc->isStar(mcond[i][j]))
662 {
663 hasStar = true;
664 inst.push_back(fmfmc->getModelBasisTerm(mcond[i][j].getType()));
665 }
666 else
667 {
668 inst.push_back(mcond[i][j]);
669 }
670 }
671 bool addInst = true;
672 if (hasStar)
673 {
674 // try obvious (specified by inst)
675 Node ev = d_quant_models[f].evaluate(fmfmc, inst);
676 if (ev == d_true)
677 {
678 addInst = false;
679 Trace("fmc-debug")
680 << "...do not instantiate, evaluation was " << ev << std::endl;
681 }
682 }
683 else
684 {
685 // for debugging
686 if (Trace.isOn("fmc-test-inst"))
687 {
688 Node ev = d_quant_models[f].evaluate(fmfmc, inst);
689 if (ev == d_true)
690 {
691 CVC5Message() << "WARNING: instantiation was true! " << f << " "
692 << mcond[i] << std::endl;
693 AlwaysAssert(false);
694 }
695 else
696 {
697 Trace("fmc-test-inst")
698 << "...instantiation evaluated to false." << std::endl;
699 }
700 }
701 }
702 if (!addInst)
703 {
704 Trace("fmc-debug-inst")
705 << "** Instantiation was already true." << std::endl;
706 // might try it next effort level
707 d_star_insts[f].push_back(i);
708 continue;
709 }
710 if (options::fmfBound() || options::stringExp())
711 {
712 std::vector<Node> cond;
713 cond.push_back(d_quant_cond[f]);
714 cond.insert(cond.end(), inst.begin(), inst.end());
715 // need to do exhaustive instantiate algorithm to set things properly
716 // (should only add one instance)
717 Node c = mkCond(cond);
718 unsigned prevInst = d_addedLemmas;
719 exhaustiveInstantiate(fmfmc, f, c);
720 if (d_addedLemmas == prevInst)
721 {
722 d_star_insts[f].push_back(i);
723 }
724 continue;
725 }
726 // just add the instance
727 d_triedLemmas++;
728 if (instq->addInstantiation(f,
729 inst,
730 InferenceId::QUANTIFIERS_INST_FMF_FMC,
731 Node::null(),
732 true))
733 {
734 Trace("fmc-debug-inst") << "** Added instantiation." << std::endl;
735 d_addedLemmas++;
736 if (d_qstate.isInConflict() || options::fmfOneInstPerRound())
737 {
738 break;
739 }
740 }
741 else
742 {
743 Trace("fmc-debug-inst")
744 << "** Instantiation was duplicate." << std::endl;
745 // might try it next effort level
746 d_star_insts[f].push_back(i);
747 }
748 }
749 return 1;
750 }
751 // Get the list of instantiation regions (described by "star entries" in the
752 // definition) that were not tried at the previous effort level. For each
753 // of these, we add one instantiation.
754 std::vector<Node>& mcond = d_quant_models[f].d_cond;
755 if (!d_star_insts[f].empty())
756 {
757 if (Trace.isOn("fmc-exh"))
758 {
759 Trace("fmc-exh") << "Exhaustive instantiate " << f << std::endl;
760 Trace("fmc-exh") << "Definition was : " << std::endl;
761 d_quant_models[f].debugPrint("fmc-exh", Node::null(), this);
762 Trace("fmc-exh") << std::endl;
763 }
764 Def temp;
765 // simplify the exceptions?
766 for (int i = (d_star_insts[f].size() - 1); i >= 0; i--)
767 {
768 // get witness for d_star_insts[f][i]
769 int j = d_star_insts[f][i];
770 if (temp.addEntry(fmfmc, mcond[j], d_quant_models[f].d_value[j]))
771 {
772 if (!exhaustiveInstantiate(fmfmc, f, mcond[j]))
773 {
774 // something went wrong, resort to exhaustive instantiation
775 return 0;
776 }
777 }
778 }
779 }
780 return 1;
781 }
782
783 /** Representative bound fmc entry
784 *
785 * This bound information corresponds to one
786 * entry in a term definition (see terminology in
787 * Chapter 5 of Finite Model Finding for
788 * Satisfiability Modulo Theories thesis).
789 * For example, a term definition for the body
790 * of a quantified formula:
791 * forall xyz. P( x, y, z )
792 * may be:
793 * ( 0, 0, 0 ) -> false
794 * ( *, 1, 2 ) -> false
795 * ( *, *, * ) -> true
796 * Indicating that the quantified formula evaluates
797 * to false in the current model for x=0, y=0, z=0,
798 * or y=1, z=2 for any x, and evaluates to true
799 * otherwise.
800 * This class is used if we wish
801 * to iterate over all values corresponding to one
802 * of these entries. For example, for the second entry:
803 * (*, 1, 2 )
804 * we iterate over all values of x, but only {1}
805 * for y and {2} for z.
806 */
807 class RepBoundFmcEntry : public QRepBoundExt
808 {
809 public:
810 RepBoundFmcEntry(QuantifiersBoundInference& qbi,
811 Node e,
812 FirstOrderModelFmc* f)
813 : QRepBoundExt(qbi, f), d_entry(e), d_fm(f)
814 {
815 }
816 ~RepBoundFmcEntry() {}
817 /** set bound */
818 virtual RsiEnumType setBound(Node owner,
819 unsigned i,
820 std::vector<Node>& elements) override
821 {
822 if (!d_fm->isStar(d_entry[i]))
823 {
824 // only need to consider the single point
825 elements.push_back(d_entry[i]);
826 return ENUM_DEFAULT;
827 }
828 return QRepBoundExt::setBound(owner, i, elements);
829 }
830
831 private:
832 /** the entry for this bound */
833 Node d_entry;
834 /** the model builder associated with this bound */
835 FirstOrderModelFmc* d_fm;
836 };
837
838 bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc* fm,
839 Node f,
840 Node c)
841 {
842 Trace("fmc-exh") << "----Exhaustive instantiate based on " << c << " ";
843 debugPrintCond("fmc-exh", c, true);
844 Trace("fmc-exh")<< std::endl;
845 QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference();
846 RepBoundFmcEntry rbfe(qbi, c, fm);
847 RepSetIterator riter(fm->getRepSet(), &rbfe);
848 Trace("fmc-exh-debug") << "Set quantifier..." << std::endl;
849 //initialize
850 if (riter.setQuantifier(f))
851 {
852 Trace("fmc-exh-debug") << "Set element domains..." << std::endl;
853 int addedLemmas = 0;
854 //now do full iteration
855 Instantiate* ie = d_qim.getInstantiate();
856 while( !riter.isFinished() ){
857 d_triedLemmas++;
858 Trace("fmc-exh-debug") << "Inst : ";
859 std::vector< Node > ev_inst;
860 std::vector< Node > inst;
861 for (unsigned i = 0; i < riter.getNumTerms(); i++)
862 {
863 TypeNode tn = riter.getTypeOf(i);
864 // if the type is not closed enumerable (see
865 // TypeNode::isClosedEnumerable), then we must ensure that we are
866 // using a term and not a value. This ensures that e.g. uninterpreted
867 // constants do not appear in instantiations.
868 Node rr = riter.getCurrentTerm(i, !tn.isClosedEnumerable());
869 Node r = fm->getRepresentative(rr);
870 debugPrint("fmc-exh-debug", r);
871 Trace("fmc-exh-debug") << " (term : " << rr << ")";
872 ev_inst.push_back( r );
873 inst.push_back( rr );
874 }
875 int ev_index = d_quant_models[f].getGeneralizationIndex(fm, ev_inst);
876 Trace("fmc-exh-debug") << ", index = " << ev_index << " / " << d_quant_models[f].d_value.size();
877 Node ev = ev_index==-1 ? Node::null() : d_quant_models[f].d_value[ev_index];
878 if (ev!=d_true) {
879 Trace("fmc-exh-debug") << ", add!";
880 //add as instantiation
881 if (ie->addInstantiation(f,
882 inst,
883 InferenceId::QUANTIFIERS_INST_FMF_FMC_EXH,
884 Node::null(),
885 true))
886 {
887 Trace("fmc-exh-debug") << " ...success.";
888 addedLemmas++;
889 if (d_qstate.isInConflict() || options::fmfOneInstPerRound())
890 {
891 break;
892 }
893 }else{
894 Trace("fmc-exh-debug") << ", failed.";
895 }
896 }else{
897 Trace("fmc-exh-debug") << ", already true";
898 }
899 Trace("fmc-exh-debug") << std::endl;
900 int index = riter.increment();
901 Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
902 if( !riter.isFinished() ){
903 if (index >= 0 && riter.d_index[index] > 0 && addedLemmas > 0
904 && riter.d_enum_type[index] == ENUM_CUSTOM)
905 {
906 Trace("fmc-exh-debug")
907 << "Since this is a custom enumeration, skip to the next..."
908 << std::endl;
909 riter.incrementAtIndex(index - 1);
910 }
911 }
912 }
913 d_addedLemmas += addedLemmas;
914 Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.isIncomplete() << std::endl;
915 return addedLemmas>0 || !riter.isIncomplete();
916 }else{
917 Trace("fmc-exh") << "----Finished Exhaustive instantiate, failed." << std::endl;
918 return !riter.isIncomplete();
919 }
920 }
921
922 void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n ) {
923 Trace("fmc-debug") << "Check " << n << " " << n.getKind() << std::endl;
924 //first check if it is a bounding literal
925 if( n.hasAttribute(BoundIntLitAttribute()) ){
926 Trace("fmc-debug") << "It is a bounding literal, polarity = " << n.getAttribute(BoundIntLitAttribute()) << std::endl;
927 d.addEntry(fm, mkCondDefault(fm, f), n.getAttribute(BoundIntLitAttribute())==1 ? d_false : d_true );
928 }else if( n.getKind() == kind::BOUND_VARIABLE ){
929 Trace("fmc-debug") << "Add default entry..." << std::endl;
930 d.addEntry(fm, mkCondDefault(fm, f), n);
931 }
932 else if( n.getKind() == kind::NOT ){
933 //just do directly
934 doCheck( fm, f, d, n[0] );
935 doNegate( d );
936 }
937 else if( n.getKind() == kind::FORALL ){
938 d.addEntry(fm, mkCondDefault(fm, f), Node::null());
939 }
940 else if( n.getType().isArray() ){
941 //Trace("fmc-warn") << "WARNING : ARRAYS : Can't process base array " << r << std::endl;
942 //Trace("fmc-warn") << " Default value was : " << odefaultValue << std::endl;
943 //Trace("fmc-debug") << "Can't process base array " << r << std::endl;
944 //can't process this array
945 d.reset();
946 d.addEntry(fm, mkCondDefault(fm, f), Node::null());
947 }
948 else if( n.getNumChildren()==0 ){
949 Node r = n;
950 if( !n.isConst() ){
951 TypeNode tn = n.getType();
952 if( !fm->hasTerm(n) && tn.isFirstClass() ){
953 r = getSomeDomainElement(fm, tn );
954 }
955 r = fm->getRepresentative( r );
956 }
957 Trace("fmc-debug") << "Add constant entry..." << std::endl;
958 d.addEntry(fm, mkCondDefault(fm, f), r);
959 }
960 else{
961 std::vector< int > var_ch;
962 std::vector< Def > children;
963 for( int i=0; i<(int)n.getNumChildren(); i++) {
964 Def dc;
965 doCheck(fm, f, dc, n[i]);
966 children.push_back(dc);
967 if( n[i].getKind() == kind::BOUND_VARIABLE ){
968 var_ch.push_back(i);
969 }
970 }
971
972 if( n.getKind()==APPLY_UF ){
973 Trace("fmc-debug") << "Do uninterpreted compose " << n << std::endl;
974 //uninterpreted compose
975 doUninterpretedCompose( fm, f, d, n.getOperator(), children );
976 /*
977 } else if( n.getKind()==SELECT ){
978 Trace("fmc-debug") << "Do select compose " << n << std::endl;
979 std::vector< Def > children2;
980 children2.push_back( children[1] );
981 std::vector< Node > cond;
982 mkCondDefaultVec(fm, f, cond);
983 std::vector< Node > val;
984 doUninterpretedCompose(fm, f, d, children[0], children2, 0, cond, val );
985 */
986 } else {
987 if( !var_ch.empty() ){
988 if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
989 if( var_ch.size()==2 ){
990 Trace("fmc-debug") << "Do variable equality " << n << std::endl;
991 doVariableEquality( fm, f, d, n );
992 }else{
993 Trace("fmc-debug") << "Do variable relation " << n << std::endl;
994 doVariableRelation( fm, f, d, var_ch[0]==0 ? children[1] : children[0], var_ch[0]==0 ? n[0] : n[1] );
995 }
996 }else{
997 Trace("fmc-warn") << "Don't know how to check " << n << std::endl;
998 d.addEntry(fm, mkCondDefault(fm, f), Node::null());
999 }
1000 }else{
1001 Trace("fmc-debug") << "Do interpreted compose " << n << std::endl;
1002 std::vector< Node > cond;
1003 mkCondDefaultVec(fm, f, cond);
1004 std::vector< Node > val;
1005 //interpreted compose
1006 doInterpretedCompose( fm, f, d, n, children, 0, cond, val );
1007 }
1008 }
1009 Trace("fmc-debug") << "Simplify the definition..." << std::endl;
1010 d.debugPrint("fmc-debug", Node::null(), this);
1011 d.simplify(this, fm);
1012 Trace("fmc-debug") << "Done simplifying" << std::endl;
1013 }
1014 Trace("fmc-debug") << "Definition for " << n << " is : " << std::endl;
1015 d.debugPrint("fmc-debug", Node::null(), this);
1016 Trace("fmc-debug") << std::endl;
1017 }
1018
1019 void FullModelChecker::doNegate( Def & dc ) {
1020 for (unsigned i=0; i<dc.d_cond.size(); i++) {
1021 Node v = dc.d_value[i];
1022 if (!v.isNull())
1023 {
1024 // In the case that the value is not-constant, we cannot reason about
1025 // its value (since the range of this must be a constant or variable).
1026 // In particular, returning null here is important if we have (not x)
1027 // where x is a bound variable.
1028 dc.d_value[i] =
1029 v == d_true ? d_false : (v == d_false ? d_true : Node::null());
1030 }
1031 }
1032 }
1033
1034 void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq ) {
1035 std::vector<Node> cond;
1036 mkCondDefaultVec(fm, f, cond);
1037 if (eq[0]==eq[1]){
1038 d.addEntry(fm, mkCond(cond), d_true);
1039 }else{
1040 TypeNode tn = eq[0].getType();
1041 if( tn.isSort() ){
1042 int j = fm->getVariableId(f, eq[0]);
1043 int k = fm->getVariableId(f, eq[1]);
1044 const RepSet* rs = fm->getRepSet();
1045 if (!rs->hasType(tn))
1046 {
1047 getSomeDomainElement( fm, tn ); //to verify the type is initialized
1048 }
1049 unsigned nreps = rs->getNumRepresentatives(tn);
1050 for (unsigned i = 0; i < nreps; i++)
1051 {
1052 Node r = fm->getRepresentative(rs->getRepresentative(tn, i));
1053 cond[j+1] = r;
1054 cond[k+1] = r;
1055 d.addEntry( fm, mkCond(cond), d_true);
1056 }
1057 d.addEntry( fm, mkCondDefault(fm, f), d_false);
1058 }else{
1059 d.addEntry( fm, mkCondDefault(fm, f), Node::null());
1060 }
1061 }
1062 }
1063
1064 void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
1065 int j = fm->getVariableId(f, v);
1066 for (unsigned i=0; i<dc.d_cond.size(); i++) {
1067 Node val = dc.d_value[i];
1068 if( val.isNull() ){
1069 d.addEntry( fm, dc.d_cond[i], val);
1070 }else{
1071 if( dc.d_cond[i][j]!=val ){
1072 if (fm->isStar(dc.d_cond[i][j])) {
1073 std::vector<Node> cond;
1074 mkCondVec(dc.d_cond[i],cond);
1075 cond[j+1] = val;
1076 d.addEntry(fm, mkCond(cond), d_true);
1077 cond[j+1] = fm->getStar(val.getType());
1078 d.addEntry(fm, mkCond(cond), d_false);
1079 }else{
1080 d.addEntry( fm, dc.d_cond[i], d_false);
1081 }
1082 }else{
1083 d.addEntry( fm, dc.d_cond[i], d_true);
1084 }
1085 }
1086 }
1087 }
1088
1089 void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node op, std::vector< Def > & dc ) {
1090 Trace("fmc-uf-debug") << "Definition : " << std::endl;
1091 fm->d_models[op]->debugPrint("fmc-uf-debug", op, this);
1092 Trace("fmc-uf-debug") << std::endl;
1093
1094 std::vector< Node > cond;
1095 mkCondDefaultVec(fm, f, cond);
1096 std::vector< Node > val;
1097 doUninterpretedCompose( fm, f, d, *fm->d_models[op], dc, 0, cond, val);
1098 }
1099
1100 void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
1101 Def & df, std::vector< Def > & dc, int index,
1102 std::vector< Node > & cond, std::vector<Node> & val ) {
1103 Trace("fmc-uf-process") << "process at " << index << std::endl;
1104 for( unsigned i=1; i<cond.size(); i++) {
1105 debugPrint("fmc-uf-process", cond[i], true);
1106 Trace("fmc-uf-process") << " ";
1107 }
1108 Trace("fmc-uf-process") << std::endl;
1109 if (index==(int)dc.size()) {
1110 //we have an entry, now do actual compose
1111 std::map< int, Node > entries;
1112 doUninterpretedCompose2( fm, f, entries, 0, cond, val, df.d_et);
1113 if( entries.empty() ){
1114 d.addEntry(fm, mkCond(cond), Node::null());
1115 }else{
1116 //add them to the definition
1117 for( unsigned e=0; e<df.d_cond.size(); e++ ){
1118 if ( entries.find(e)!=entries.end() ){
1119 Trace("fmf-uf-process-debug") << "Add entry..." << std::endl;
1120 d.addEntry(fm, entries[e], df.d_value[e] );
1121 Trace("fmf-uf-process-debug") << "Done add entry." << std::endl;
1122 }
1123 }
1124 }
1125 }else{
1126 for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
1127 if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
1128 std::vector< Node > new_cond;
1129 new_cond.insert(new_cond.end(), cond.begin(), cond.end());
1130 if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
1131 Trace("fmc-uf-process") << "index " << i << " succeeded meet." << std::endl;
1132 val.push_back(dc[index].d_value[i]);
1133 doUninterpretedCompose(fm, f, d, df, dc, index+1, new_cond, val);
1134 val.pop_back();
1135 }else{
1136 Trace("fmc-uf-process") << "index " << i << " failed meet." << std::endl;
1137 }
1138 }
1139 }
1140 }
1141 }
1142
1143 void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
1144 std::map< int, Node > & entries, int index,
1145 std::vector< Node > & cond, std::vector< Node > & val,
1146 EntryTrie & curr ) {
1147 Trace("fmc-uf-process") << "compose " << index << " / " << val.size() << std::endl;
1148 for( unsigned i=1; i<cond.size(); i++) {
1149 debugPrint("fmc-uf-process", cond[i], true);
1150 Trace("fmc-uf-process") << " ";
1151 }
1152 Trace("fmc-uf-process") << std::endl;
1153 if (index==(int)val.size()) {
1154 Node c = mkCond(cond);
1155 Trace("fmc-uf-entry") << "Entry : " << c << " -> index[" << curr.d_data << "]" << std::endl;
1156 entries[curr.d_data] = c;
1157 }else{
1158 Node v = val[index];
1159 Trace("fmc-uf-process") << "Process " << v << std::endl;
1160 bool bind_var = false;
1161 if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
1162 int j = fm->getVariableId(f, v);
1163 Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
1164 if (!fm->isStar(cond[j + 1]))
1165 {
1166 v = cond[j+1];
1167 }else{
1168 bind_var = true;
1169 }
1170 }
1171 if (bind_var) {
1172 Trace("fmc-uf-process") << "bind variable..." << std::endl;
1173 int j = fm->getVariableId(f, v);
1174 Assert(fm->isStar(cond[j + 1]));
1175 for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin();
1176 it != curr.d_child.end();
1177 ++it)
1178 {
1179 cond[j + 1] = it->first;
1180 doUninterpretedCompose2(
1181 fm, f, entries, index + 1, cond, val, it->second);
1182 }
1183 cond[j + 1] = fm->getStar(v.getType());
1184 }else{
1185 if( !v.isNull() ){
1186 if (curr.d_child.find(v) != curr.d_child.end())
1187 {
1188 Trace("fmc-uf-process") << "follow value..." << std::endl;
1189 doUninterpretedCompose2(
1190 fm, f, entries, index + 1, cond, val, curr.d_child[v]);
1191 }
1192 Node st = fm->getStar(v.getType());
1193 if (curr.d_child.find(st) != curr.d_child.end())
1194 {
1195 Trace("fmc-uf-process") << "follow star..." << std::endl;
1196 doUninterpretedCompose2(
1197 fm, f, entries, index + 1, cond, val, curr.d_child[st]);
1198 }
1199 }
1200 }
1201 }
1202 }
1203
1204 void FullModelChecker::doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
1205 std::vector< Def > & dc, int index,
1206 std::vector< Node > & cond, std::vector<Node> & val ) {
1207 Trace("fmc-if-process") << "int compose " << index << " / " << dc.size() << std::endl;
1208 for( unsigned i=1; i<cond.size(); i++) {
1209 debugPrint("fmc-if-process", cond[i], true);
1210 Trace("fmc-if-process") << " ";
1211 }
1212 Trace("fmc-if-process") << std::endl;
1213 if ( index==(int)dc.size() ){
1214 Node c = mkCond(cond);
1215 Node v = evaluateInterpreted(n, val);
1216 d.addEntry(fm, c, v);
1217 }
1218 else {
1219 TypeNode vtn = n.getType();
1220 for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
1221 if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
1222 std::vector< Node > new_cond;
1223 new_cond.insert(new_cond.end(), cond.begin(), cond.end());
1224 if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
1225 bool process = true;
1226 if (vtn.isBoolean()) {
1227 //short circuit
1228 if( (n.getKind()==OR && dc[index].d_value[i]==d_true) ||
1229 (n.getKind()==AND && dc[index].d_value[i]==d_false) ){
1230 Node c = mkCond(new_cond);
1231 d.addEntry(fm, c, dc[index].d_value[i]);
1232 process = false;
1233 }
1234 }
1235 if (process) {
1236 val.push_back(dc[index].d_value[i]);
1237 doInterpretedCompose(fm, f, d, n, dc, index+1, new_cond, val);
1238 val.pop_back();
1239 }
1240 }
1241 }
1242 }
1243 }
1244 }
1245
1246 int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
1247 Trace("fmc-debug3") << "isCompat " << c << std::endl;
1248 Assert(cond.size() == c.getNumChildren() + 1);
1249 for (unsigned i=1; i<cond.size(); i++) {
1250 if (cond[i] != c[i - 1] && !fm->isStar(cond[i]) && !fm->isStar(c[i - 1]))
1251 {
1252 return 0;
1253 }
1254 }
1255 return 1;
1256 }
1257
1258 bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
1259 Trace("fmc-debug3") << "doMeet " << c << std::endl;
1260 Assert(cond.size() == c.getNumChildren() + 1);
1261 for (unsigned i=1; i<cond.size(); i++) {
1262 if( cond[i]!=c[i-1] ) {
1263 if (fm->isStar(cond[i]))
1264 {
1265 cond[i] = c[i - 1];
1266 }
1267 else if (!fm->isStar(c[i - 1]))
1268 {
1269 return false;
1270 }
1271 }
1272 }
1273 return true;
1274 }
1275
1276 Node FullModelChecker::mkCond( std::vector< Node > & cond ) {
1277 return NodeManager::currentNM()->mkNode(APPLY_UF, cond);
1278 }
1279
1280 Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
1281 std::vector< Node > cond;
1282 mkCondDefaultVec(fm, f, cond);
1283 return mkCond(cond);
1284 }
1285
1286 void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
1287 Trace("fmc-debug") << "Make default vec" << std::endl;
1288 //get function symbol for f
1289 cond.push_back(d_quant_cond[f]);
1290 for (unsigned i=0; i<f[0].getNumChildren(); i++) {
1291 Node ts = fm->getStar(f[0][i].getType());
1292 Assert(ts.getType() == f[0][i].getType());
1293 cond.push_back(ts);
1294 }
1295 }
1296
1297 void FullModelChecker::mkCondVec( Node n, std::vector< Node > & cond ) {
1298 cond.push_back(n.getOperator());
1299 for( unsigned i=0; i<n.getNumChildren(); i++ ){
1300 cond.push_back( n[i] );
1301 }
1302 }
1303
1304 Node FullModelChecker::evaluateInterpreted( Node n, std::vector< Node > & vals ) {
1305 if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
1306 if (!vals[0].isNull() && !vals[1].isNull()) {
1307 return vals[0]==vals[1] ? d_true : d_false;
1308 }else{
1309 return Node::null();
1310 }
1311 }else if( n.getKind()==ITE ){
1312 if( vals[0]==d_true ){
1313 return vals[1];
1314 }else if( vals[0]==d_false ){
1315 return vals[2];
1316 }else{
1317 return vals[1]==vals[2] ? vals[1] : Node::null();
1318 }
1319 }else if( n.getKind()==AND || n.getKind()==OR ){
1320 bool isNull = false;
1321 for (unsigned i=0; i<vals.size(); i++) {
1322 if((vals[i]==d_true && n.getKind()==OR) || (vals[i]==d_false && n.getKind()==AND)) {
1323 return vals[i];
1324 }else if( vals[i].isNull() ){
1325 isNull = true;
1326 }
1327 }
1328 return isNull ? Node::null() : vals[0];
1329 }else{
1330 std::vector<Node> children;
1331 if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
1332 children.push_back( n.getOperator() );
1333 }
1334 for (unsigned i=0; i<vals.size(); i++) {
1335 if( vals[i].isNull() ){
1336 return Node::null();
1337 }else{
1338 children.push_back( vals[i] );
1339 }
1340 }
1341 Node nc = NodeManager::currentNM()->mkNode(n.getKind(), children);
1342 Trace("fmc-eval") << "Evaluate " << nc << " to ";
1343 nc = Rewriter::rewrite(nc);
1344 Trace("fmc-eval") << nc << std::endl;
1345 return nc;
1346 }
1347 }
1348
1349 Node FullModelChecker::getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn ) {
1350 bool addRepId = !fm->getRepSet()->hasType(tn);
1351 Node de = fm->getSomeDomainElement(tn);
1352 if( addRepId ){
1353 d_rep_ids[tn][de] = 0;
1354 }
1355 return de;
1356 }
1357
1358 Node FullModelChecker::getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix ) {
1359 return fm->getFunctionValue(op, argPrefix);
1360 }
1361
1362
1363 bool FullModelChecker::useSimpleModels() {
1364 return options::fmfFmcSimple();
1365 }
1366 void FullModelChecker::registerQuantifiedFormula(Node q)
1367 {
1368 if (d_quant_cond.find(q) != d_quant_cond.end())
1369 {
1370 return;
1371 }
1372 NodeManager* nm = NodeManager::currentNM();
1373 SkolemManager* sm = nm->getSkolemManager();
1374 std::vector<TypeNode> types;
1375 for (const Node& v : q[0])
1376 {
1377 TypeNode tn = v.getType();
1378 if (tn.isFunction())
1379 {
1380 // we will not use model-based quantifier instantiation for q, since
1381 // the model-based instantiation algorithm does not handle (universally
1382 // quantified) functions
1383 d_unhandledQuant.insert(q);
1384 }
1385 types.push_back(tn);
1386 }
1387 TypeNode typ = nm->mkFunctionType(types, nm->booleanType());
1388 Node op = sm->mkDummySkolem("qfmc", typ, "op for full-model checking");
1389 d_quant_cond[q] = op;
1390 }
1391
1392 bool FullModelChecker::isHandled(Node q) const
1393 {
1394 return d_unhandledQuant.find(q) == d_unhandledQuant.end();
1395 }
1396
1397 } // namespace fmcheck
1398 } // namespace quantifiers
1399 } // namespace theory
1400 } // namespace cvc5