GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/fmf/full_model_check.cpp Lines: 763 802 95.1 %
Date: 2021-08-14 Branches: 1665 3243 51.3 %

Line Exec Source
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
183588
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
56896
  bool operator() (int i,int j) {
48
56896
    return (d_mba_count[d_terms[i]] < d_mba_count[d_terms[j]]);
49
  }
50
};
51
52
410144
bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
53
410144
  if (index==(int)c.getNumChildren()) {
54
16308
    return d_data!=-1;
55
  }else{
56
787672
    TypeNode tn = c[index].getType();
57
787672
    Node st = m->getStar(tn);
58
393836
    if(d_child.find(st)!=d_child.end()) {
59
40488
      if( d_child[st].hasGeneralization(m, c, index+1) ){
60
15186
        return true;
61
      }
62
    }
63
378650
    if( c[index]!=st && d_child.find( c[index] )!=d_child.end() ){
64
56476
      if( d_child[ c[index] ].hasGeneralization(m, c, index+1) ){
65
21558
        return true;
66
      }
67
    }
68
357092
    if( c[index].getType().isSort() ){
69
      //for star: check if all children are defined and have generalizations
70
266609
      if( c[index]==st ){     ///options::fmfFmcCoverSimplify()
71
        //check if all children exist and are complete
72
        unsigned num_child_def =
73
153951
            d_child.size() - (d_child.find(st) != d_child.end() ? 1 : 0);
74
153951
        if (num_child_def == m->getRepSet()->getNumRepresentatives(tn))
75
        {
76
8583
          bool complete = true;
77
14783
          for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
78
12534
            if( !m->isStar(it->first) ){
79
12032
              if( !it->second.hasGeneralization(m, c, index+1) ){
80
6334
                complete = false;
81
6334
                break;
82
              }
83
            }
84
          }
85
8583
          if( complete ){
86
2249
            return true;
87
          }
88
        }
89
      }
90
    }
91
92
354843
    return false;
93
  }
94
}
95
96
129574
int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index ) {
97
129574
  Debug("fmc-entry-trie") << "Get generalization index " << inst.size() << " " << index << std::endl;
98
129574
  if (index==(int)inst.size()) {
99
36635
    return d_data;
100
  }else{
101
92939
    int minIndex = -1;
102
185878
    Node st = m->getStar(inst[index].getType());
103
92939
    if (d_child.find(st) != d_child.end())
104
    {
105
86469
      minIndex = d_child[st].getGeneralizationIndex(m, inst, index + 1);
106
    }
107
185878
    Node cc = inst[index];
108
92939
    if (cc != st && d_child.find(cc) != d_child.end())
109
    {
110
12821
      int gindex = d_child[cc].getGeneralizationIndex(m, inst, index + 1);
111
12821
      if (minIndex == -1 || (gindex != -1 && gindex < minIndex))
112
      {
113
8794
        minIndex = gindex;
114
      }
115
    }
116
92939
    return minIndex;
117
  }
118
}
119
120
758298
void EntryTrie::addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index ) {
121
758298
  if (index==(int)c.getNumChildren()) {
122
288289
    if(d_data==-1) {
123
288289
      d_data = data;
124
    }
125
  }
126
  else {
127
470009
    d_child[ c[index] ].addEntry(m,c,v,data,index+1);
128
470009
    if( d_complete==0 ){
129
      d_complete = -1;
130
    }
131
  }
132
758298
}
133
134
328178
void EntryTrie::getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index, bool is_gen ) {
135
328178
  if (index==(int)c.getNumChildren()) {
136
70013
    if( d_data!=-1) {
137
70013
      if( is_gen ){
138
64221
        gen.push_back(d_data);
139
      }
140
70013
      compat.push_back(d_data);
141
    }
142
  }else{
143
258165
    if (m->isStar(c[index])) {
144
266210
      for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
145
111070
        it->second.getEntries(m, c, compat, gen, index+1, is_gen );
146
      }
147
    }else{
148
206050
      Node st = m->getStar(c[index].getType());
149
103025
      if(d_child.find(st)!=d_child.end()) {
150
7748
        d_child[st].getEntries(m, c, compat, gen, index+1, false);
151
      }
152
103025
      if( d_child.find( c[index] )!=d_child.end() ){
153
30166
        d_child[ c[index] ].getEntries(m, c, compat, gen, index+1, is_gen);
154
      }
155
    }
156
157
  }
158
328178
}
159
160
301148
bool Def::addEntry( FirstOrderModelFmc * m, Node c, Node v) {
161
301148
  if (d_et.hasGeneralization(m, c)) {
162
12859
    Trace("fmc-debug") << "Already has generalization, skip." << std::endl;
163
12859
    return false;
164
  }
165
288289
  int newIndex = (int)d_cond.size();
166
288289
  if (!d_has_simplified) {
167
358388
    std::vector<int> compat;
168
358388
    std::vector<int> gen;
169
179194
    d_et.getEntries(m, c, compat, gen);
170
249207
    for( unsigned i=0; i<compat.size(); i++) {
171
70013
      if( d_status[compat[i]]==status_unk ){
172
61101
        if( d_value[compat[i]]!=v ){
173
38339
          d_status[compat[i]] = status_non_redundant;
174
        }
175
      }
176
    }
177
243415
    for( unsigned i=0; i<gen.size(); i++) {
178
64221
      if( d_status[gen[i]]==status_unk ){
179
19098
        if( d_value[gen[i]]==v ){
180
19098
          d_status[gen[i]] = status_redundant;
181
        }
182
      }
183
    }
184
179194
    d_status.push_back( status_unk );
185
  }
186
288289
  d_et.addEntry(m, c, v, newIndex);
187
288289
  d_cond.push_back(c);
188
288289
  d_value.push_back(v);
189
288289
  return true;
190
}
191
192
2951
Node Def::evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
193
2951
  int gindex = d_et.getGeneralizationIndex(m, inst);
194
2951
  if (gindex!=-1) {
195
2947
    return d_value[gindex];
196
  }else{
197
4
    Trace("fmc-warn") << "Warning : evaluation came up null!" << std::endl;
198
4
    return Node::null();
199
  }
200
}
201
202
27333
int Def::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
203
27333
  return d_et.getGeneralizationIndex(m, inst);
204
}
205
206
65305
void Def::basic_simplify( FirstOrderModelFmc * m ) {
207
65305
  d_has_simplified = true;
208
130610
  std::vector< Node > cond;
209
65305
  cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
210
65305
  d_cond.clear();
211
130610
  std::vector< Node > value;
212
65305
  value.insert( value.end(), d_value.begin(), d_value.end() );
213
65305
  d_value.clear();
214
65305
  d_et.reset();
215
193498
  for (unsigned i=0; i<d_status.size(); i++) {
216
128193
    if( d_status[i]!=status_redundant ){
217
109095
      addEntry(m, cond[i], value[i]);
218
    }
219
  }
220
65305
  d_status.clear();
221
65305
}
222
223
59262
void Def::simplify(FullModelChecker * mc, FirstOrderModelFmc * m) {
224
59262
  Trace("fmc-simplify") << "Simplify definition, #cond = " << d_cond.size() << std::endl;
225
59262
  basic_simplify( m );
226
59262
  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
59262
  if( !d_cond.empty() ){
230
59262
    bool last_all_stars = true;
231
118524
    Node cc = d_cond[d_cond.size()-1];
232
138851
    for( unsigned i=0; i<cc.getNumChildren(); i++ ){
233
85632
      if (!m->isStar(cc[i]))
234
      {
235
6043
        last_all_stars = false;
236
6043
        break;
237
      }
238
    }
239
59262
    if( !last_all_stars ){
240
6043
      Trace("fmc-cover-simplify") << "Need to modify last entry to be all stars." << std::endl;
241
6043
      Trace("fmc-cover-simplify") << "Before: " << std::endl;
242
6043
      debugPrint("fmc-cover-simplify",Node::null(), mc);
243
6043
      Trace("fmc-cover-simplify") << std::endl;
244
12086
      std::vector< Node > cond;
245
6043
      cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
246
6043
      d_cond.clear();
247
12086
      std::vector< Node > value;
248
6043
      value.insert( value.end(), d_value.begin(), d_value.end() );
249
6043
      d_value.clear();
250
6043
      d_et.reset();
251
6043
      d_has_simplified = false;
252
      //change the last to all star
253
12086
      std::vector< Node > nc;
254
6043
      nc.push_back( cc.getOperator() );
255
15694
      for( unsigned j=0; j< cc.getNumChildren(); j++){
256
9651
        nc.push_back(m->getStar(cc[j].getType()));
257
      }
258
6043
      cond[cond.size()-1] = NodeManager::currentNM()->mkNode( APPLY_UF, nc );
259
      //re-add the entries
260
17645
      for (unsigned i=0; i<cond.size(); i++) {
261
11602
        addEntry(m, cond[i], value[i]);
262
      }
263
6043
      Trace("fmc-cover-simplify") << "Finished re-adding entries." << std::endl;
264
6043
      basic_simplify( m );
265
6043
      Trace("fmc-cover-simplify") << "After: " << std::endl;
266
6043
      debugPrint("fmc-cover-simplify",Node::null(), mc);
267
6043
      Trace("fmc-cover-simplify") << std::endl;
268
    }
269
  }
270
59262
  Trace("fmc-simplify") << "finish simplify, #cond = " << d_cond.size() << std::endl;
271
59262
}
272
273
216529
void Def::debugPrint(const char * tr, Node op, FullModelChecker * m) {
274
216529
  if (!op.isNull()) {
275
38122
    Trace(tr) << "Model for " << op << " : " << std::endl;
276
  }
277
571984
  for( unsigned i=0; i<d_cond.size(); i++) {
278
    //print the condition
279
355455
    if (!op.isNull()) {
280
95242
      Trace(tr) << op;
281
    }
282
355455
    m->debugPrintCond(tr, d_cond[i], true);
283
355455
    Trace(tr) << " -> ";
284
355455
    m->debugPrint(tr, d_value[i]);
285
355455
    Trace(tr) << std::endl;
286
  }
287
216529
}
288
289
1444
FullModelChecker::FullModelChecker(QuantifiersState& qs,
290
                                   QuantifiersInferenceManager& qim,
291
                                   QuantifiersRegistry& qr,
292
1444
                                   TermRegistry& tr)
293
1444
    : QModelBuilder(qs, qim, qr, tr), d_fm(new FirstOrderModelFmc(qs, qr, tr))
294
{
295
1444
  d_true = NodeManager::currentNM()->mkConst(true);
296
1444
  d_false = NodeManager::currentNM()->mkConst(false);
297
1444
}
298
299
1444
void FullModelChecker::finishInit() { d_model = d_fm.get(); }
300
301
1979
bool FullModelChecker::preProcessBuildModel(TheoryModel* m) {
302
  //standard pre-process
303
1979
  if( !preProcessBuildModelStd( m ) ){
304
    return false;
305
  }
306
307
1979
  Trace("fmc") << "---Full Model Check preprocess() " << std::endl;
308
1979
  d_preinitialized_eqc.clear();
309
1979
  d_preinitialized_types.clear();
310
  //traverse equality engine
311
1979
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(m->getEqualityEngine());
312
78347
  while( !eqcs_i.isFinished() ){
313
76368
    Node r = *eqcs_i;
314
76368
    TypeNode tr = r.getType();
315
38184
    d_preinitialized_eqc[tr] = r;
316
38184
    ++eqcs_i;
317
  }
318
319
  //must ensure model basis terms exists in model for each relevant type
320
1979
  Trace("fmc") << "preInitialize types..." << std::endl;
321
1979
  d_fm->initialize();
322
9108
  for (std::pair<const Node, Def*>& mp : d_fm->d_models)
323
  {
324
14258
    Node op = mp.first;
325
7129
    Trace("fmc") << "preInitialize types for " << op << std::endl;
326
14258
    TypeNode tno = op.getType();
327
26190
    for( unsigned i=0; i<tno.getNumChildren(); i++) {
328
19061
      Trace("fmc") << "preInitializeType " << tno[i] << std::endl;
329
19061
      preInitializeType(m, tno[i]);
330
19061
      Trace("fmc") << "finished preInitializeType " << tno[i] << std::endl;
331
    }
332
  }
333
1979
  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
10830
  for (unsigned i = 0, nquant = d_fm->getNumAssertedQuantifiers(); i < nquant;
336
       i++)
337
  {
338
17591
    Node q = d_fm->getAssertedQuantifier(i);
339
8851
    registerQuantifiedFormula(q);
340
8851
    if (!isHandled(q))
341
    {
342
111
      continue;
343
    }
344
    // make sure all types are set
345
22333
    for (const Node& v : q[0])
346
    {
347
13593
      preInitializeType(m, v.getType());
348
    }
349
  }
350
1979
  return true;
351
}
352
353
1979
bool FullModelChecker::processBuildModel(TheoryModel* m){
354
1979
  if (!m->areFunctionValuesEnabled())
355
  {
356
    // nothing to do if no functions
357
    return true;
358
  }
359
1979
  FirstOrderModelFmc* fm = d_fm.get();
360
1979
  Trace("fmc") << "---Full Model Check reset() " << std::endl;
361
1979
  d_quant_models.clear();
362
1979
  d_rep_ids.clear();
363
1979
  d_star_insts.clear();
364
  //process representatives
365
1979
  RepSet* rs = m->getRepSetPtr();
366
8501
  for (std::map<TypeNode, std::vector<Node> >::iterator it =
367
1979
           rs->d_type_reps.begin();
368
10480
       it != rs->d_type_reps.end();
369
       ++it)
370
  {
371
8501
    if( it->first.isSort() ){
372
1948
      Trace("fmc") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
373
5605
      for( size_t a=0; a<it->second.size(); a++ ){
374
7314
        Node r = m->getRepresentative(it->second[a]);
375
3657
        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
3657
        d_rep_ids[it->first][r] = (int)a;
388
      }
389
1948
      Trace("fmc-model-debug") << std::endl;
390
    }
391
  }
392
393
  //now, make models
394
9108
  for (std::pair<const Node, Def*>& fmm : d_fm->d_models)
395
  {
396
14258
    Node op = fmm.first;
397
    //reset the model
398
7129
    d_fm->d_models[op]->reset();
399
400
14258
    std::vector< Node > add_conds;
401
14258
    std::vector< Node > add_values;
402
7129
    bool needsDefault = true;
403
7129
    if (m->hasUfTerms(op))
404
    {
405
5351
      const std::vector<Node>& uft = m->getUfTerms(op);
406
10702
      Trace("fmc-model-debug")
407
5351
          << uft.size() << " model values for " << op << " ... " << std::endl;
408
36578
      for (const Node& n : uft)
409
      {
410
        // only consider unique up to congruence (in model equality engine)?
411
31227
        add_conds.push_back( n );
412
31227
        add_values.push_back( n );
413
62454
        Node r = m->getRepresentative(n);
414
31227
        Trace("fmc-model-debug") << n << " -> " << r << std::endl;
415
      }
416
    }else{
417
1778
      Trace("fmc-model-debug") << "No model values for " << op << " ... " << std::endl;
418
    }
419
7129
    Trace("fmc-model-debug") << std::endl;
420
    //possibly get default
421
7129
    if( needsDefault ){
422
14258
      Node nmb = d_fm->getModelBasisOpTerm(op);
423
      //add default value if necessary
424
7129
      if (m->hasTerm(nmb))
425
      {
426
3795
        Trace("fmc-model-debug") << "Add default " << nmb << std::endl;
427
3795
        add_conds.push_back( nmb );
428
3795
        add_values.push_back( nmb );
429
      }else{
430
6668
        Node vmb = getSomeDomainElement(d_fm.get(), nmb.getType());
431
3334
        Trace("fmc-model-debug") << "Add default to default representative " << nmb << " ";
432
6668
        Trace("fmc-model-debug")
433
6668
            << m->getRepSet()->getNumRepresentatives(nmb.getType())
434
3334
            << std::endl;
435
3334
        add_conds.push_back( nmb );
436
3334
        add_values.push_back( vmb );
437
      }
438
    }
439
440
14258
    std::vector< Node > conds;
441
14258
    std::vector< Node > values;
442
14258
    std::vector< Node > entry_conds;
443
    //get the entries for the model
444
45485
    for( size_t i=0; i<add_conds.size(); i++ ){
445
76712
      Node c = add_conds[i];
446
76712
      Node v = add_values[i];
447
76712
      Trace("fmc-model-debug")
448
38356
          << "Add cond/value : " << c << " -> " << v << std::endl;
449
76712
      std::vector< Node > children;
450
76712
      std::vector< Node > entry_children;
451
38356
      children.push_back(op);
452
38356
      entry_children.push_back(op);
453
38356
      bool hasNonStar = false;
454
112901
      for (const Node& ci : c)
455
      {
456
149090
        Node ri = fm->getRepresentative(ci);
457
74545
        children.push_back(ri);
458
74545
        bool isStar = false;
459
74545
        if (fm->isModelBasisTerm(ri))
460
        {
461
21428
          ri = fm->getStar(ri.getType());
462
21428
          isStar = true;
463
        }
464
        else
465
        {
466
53117
          hasNonStar = true;
467
        }
468
74545
        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
74545
        entry_children.push_back(ri);
475
      }
476
76712
      Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
477
76712
      Node nv = fm->getRepresentative( v );
478
76712
      Trace("fmc-model-debug")
479
38356
          << "Representative of " << v << " is " << nv << std::endl;
480
38356
      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
76712
      Node en = (useSimpleModels() && hasNonStar) ? n : NodeManager::currentNM()->mkNode( APPLY_UF, entry_children );
485
38356
      if( std::find(conds.begin(), conds.end(), n )==conds.end() ){
486
24149
        Trace("fmc-model-debug") << "- add " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
487
24149
        conds.push_back(n);
488
24149
        values.push_back(nv);
489
24149
        entry_conds.push_back(en);
490
      }
491
      else {
492
14207
        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
14258
    std::vector< int > indices;
499
14258
    ModelBasisArgSort mbas;
500
31278
    for (int i=0; i<(int)conds.size(); i++) {
501
24149
      mbas.d_terms.push_back(conds[i]);
502
24149
      mbas.d_mba_count[conds[i]] = fm->getModelBasisArg(conds[i]);
503
24149
      indices.push_back(i);
504
    }
505
7129
    std::sort( indices.begin(), indices.end(), mbas );
506
507
31278
    for (int i=0; i<(int)indices.size(); i++) {
508
24149
      fm->d_models[op]->addEntry(fm, entry_conds[indices[i]], values[indices[i]]);
509
    }
510
511
7129
    Trace("fmc-model-simplify") << "Before simplification : " << std::endl;
512
7129
    fm->d_models[op]->debugPrint("fmc-model-simplify", op, this);
513
7129
    Trace("fmc-model-simplify") << std::endl;
514
515
7129
    Trace("fmc-model-simplify") << "Simplifying " << op << "..." << std::endl;
516
7129
    fm->d_models[op]->simplify( this, fm );
517
518
7129
    fm->d_models[op]->debugPrint("fmc-model", op, this);
519
7129
    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
1979
  Assert(d_addedLemmas == 0);
537
538
  //make function values
539
9108
  for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ){
540
14258
    Node f_def = getFunctionValue( fm, it->first, "$x" );
541
7129
    m->assignFunctionDefinition( it->first, f_def );
542
  }
543
1979
  return TheoryEngineModelBuilder::processBuildModel( m );
544
}
545
546
32654
void FullModelChecker::preInitializeType(TheoryModel* m, TypeNode tn)
547
{
548
32654
  if( d_preinitialized_types.find( tn )==d_preinitialized_types.end() ){
549
4797
    d_preinitialized_types[tn] = true;
550
4797
    if (tn.isFirstClass())
551
    {
552
4791
      Trace("fmc") << "Get model basis term " << tn << "..." << std::endl;
553
9582
      Node mb = d_fm->getModelBasisTerm(tn);
554
4791
      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
4791
      if (!m->hasTerm(mb) && !mb.isConst())
560
      {
561
556
        std::map<TypeNode, Node>::iterator itpe = d_preinitialized_eqc.find(tn);
562
556
        if (itpe == d_preinitialized_eqc.end())
563
        {
564
524
          Trace("fmc") << "...add model basis term to EE of model " << mb << " "
565
262
                       << tn << std::endl;
566
262
          m->getEqualityEngine()->addTerm(mb);
567
        }
568
        else
569
        {
570
588
          Trace("fmc") << "...add model basis eqc equality to model " << mb
571
294
                       << " == " << itpe->second << " " << tn << std::endl;
572
294
          bool ret = m->assertEquality(mb, itpe->second, true);
573
294
          AlwaysAssert(ret);
574
        }
575
      }
576
    }
577
  }
578
32654
}
579
580
360090
void FullModelChecker::debugPrintCond(const char * tr, Node n, bool dispStar) {
581
360090
  Trace(tr) << "(";
582
933637
  for( unsigned j=0; j<n.getNumChildren(); j++) {
583
573547
    if( j>0 ) Trace(tr) << ", ";
584
573547
    debugPrint(tr, n[j], dispStar);
585
  }
586
360090
  Trace(tr) << ")";
587
360090
}
588
589
1435373
void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) {
590
1435373
  if( n.isNull() ){
591
28052
    Trace(tr) << "null";
592
  }
593
1407321
  else if (FirstOrderModelFmc::isStar(n) && dispStar)
594
  {
595
677389
    Trace(tr) << "*";
596
  }
597
  else
598
  {
599
1459864
    TypeNode tn = n.getType();
600
729932
    if( tn.isSort() && d_rep_ids.find(tn)!=d_rep_ids.end() ){
601
347040
      if (d_rep_ids[tn].find(n)!=d_rep_ids[tn].end()) {
602
324830
        Trace(tr) << d_rep_ids[tn][n];
603
      }else{
604
22210
        Trace(tr) << n;
605
      }
606
    }else{
607
382892
      Trace(tr) << n;
608
    }
609
  }
610
1435373
}
611
612
613
11008
int FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
614
11008
  Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl;
615
  // register the quantifier
616
11008
  registerQuantifiedFormula(f);
617
11008
  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
11008
  if (!optUseModel() || !isHandled(f))
621
  {
622
    return 0;
623
  }
624
11008
  FirstOrderModelFmc* fmfmc = static_cast<FirstOrderModelFmc*>(fm);
625
11008
  if (effort == 0)
626
  {
627
8470
    if (options::mbqiMode() == options::MbqiMode::NONE)
628
    {
629
      // just exhaustive instantiate
630
4332
      Node c = mkCondDefault(fmfmc, f);
631
2166
      d_quant_models[f].addEntry(fmfmc, c, d_false);
632
2166
      if (!exhaustiveInstantiate(fmfmc, f, c))
633
      {
634
20
        return 0;
635
      }
636
2146
      return 1;
637
    }
638
    // model check the quantifier
639
6304
    doCheck(fmfmc, f, d_quant_models[f], f[1]);
640
6304
    std::vector<Node>& mcond = d_quant_models[f].d_cond;
641
6304
    Trace("fmc") << "Definition for quantifier " << f << " is : " << std::endl;
642
6304
    Assert(!mcond.empty());
643
6304
    d_quant_models[f].debugPrint("fmc", Node::null(), this);
644
6304
    Trace("fmc") << std::endl;
645
646
    // consider all entries going to non-true
647
6304
    Instantiate* instq = d_qim.getInstantiate();
648
14588
    for (unsigned i = 0, msize = mcond.size(); i < msize; i++)
649
    {
650
8284
      if (d_quant_models[f].d_value[i] == d_true)
651
      {
652
        // already satisfied
653
10962
        continue;
654
      }
655
6660
      Trace("fmc-inst") << "Instantiate based on " << mcond[i] << "..."
656
3330
                        << std::endl;
657
3330
      bool hasStar = false;
658
5606
      std::vector<Node> inst;
659
8419
      for (unsigned j = 0, nchild = mcond[i].getNumChildren(); j < nchild; j++)
660
      {
661
5089
        if (fmfmc->isStar(mcond[i][j]))
662
        {
663
4097
          hasStar = true;
664
4097
          inst.push_back(fmfmc->getModelBasisTerm(mcond[i][j].getType()));
665
        }
666
        else
667
        {
668
992
          inst.push_back(mcond[i][j]);
669
        }
670
      }
671
3330
      bool addInst = true;
672
3330
      if (hasStar)
673
      {
674
        // try obvious (specified by inst)
675
5902
        Node ev = d_quant_models[f].evaluate(fmfmc, inst);
676
2951
        if (ev == d_true)
677
        {
678
9
          addInst = false;
679
18
          Trace("fmc-debug")
680
9
              << "...do not instantiate, evaluation was " << ev << std::endl;
681
        }
682
      }
683
      else
684
      {
685
        // for debugging
686
379
        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
3339
      if (!addInst)
703
      {
704
18
        Trace("fmc-debug-inst")
705
9
            << "** Instantiation was already true." << std::endl;
706
        // might try it next effort level
707
9
        d_star_insts[f].push_back(i);
708
9
        continue;
709
      }
710
3321
      if (options::fmfBound() || options::stringExp())
711
      {
712
2090
        std::vector<Node> cond;
713
1045
        cond.push_back(d_quant_cond[f]);
714
1045
        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
2090
        Node c = mkCond(cond);
718
1045
        unsigned prevInst = d_addedLemmas;
719
1045
        exhaustiveInstantiate(fmfmc, f, c);
720
1045
        if (d_addedLemmas == prevInst)
721
        {
722
763
          d_star_insts[f].push_back(i);
723
        }
724
1045
        continue;
725
      }
726
      // just add the instance
727
2276
      d_triedLemmas++;
728
4552
      if (instq->addInstantiation(f,
729
                                  inst,
730
                                  InferenceId::QUANTIFIERS_INST_FMF_FMC,
731
4552
                                  Node::null(),
732
                                  true))
733
      {
734
758
        Trace("fmc-debug-inst") << "** Added instantiation." << std::endl;
735
758
        d_addedLemmas++;
736
758
        if (d_qstate.isInConflict() || options::fmfOneInstPerRound())
737
        {
738
          break;
739
        }
740
      }
741
      else
742
      {
743
3036
        Trace("fmc-debug-inst")
744
1518
            << "** Instantiation was duplicate." << std::endl;
745
        // might try it next effort level
746
1518
        d_star_insts[f].push_back(i);
747
      }
748
    }
749
6304
    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
2538
  std::vector<Node>& mcond = d_quant_models[f].d_cond;
755
2538
  if (!d_star_insts[f].empty())
756
  {
757
1352
    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
2671
    Def temp;
765
    // simplify the exceptions?
766
2797
    for (int i = (d_star_insts[f].size() - 1); i >= 0; i--)
767
    {
768
      // get witness for d_star_insts[f][i]
769
1478
      int j = d_star_insts[f][i];
770
1478
      if (temp.addEntry(fmfmc, mcond[j], d_quant_models[f].d_value[j]))
771
      {
772
1424
        if (!exhaustiveInstantiate(fmfmc, f, mcond[j]))
773
        {
774
          // something went wrong, resort to exhaustive instantiation
775
33
          return 0;
776
        }
777
      }
778
    }
779
  }
780
2505
  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
4635
  RepBoundFmcEntry(QuantifiersBoundInference& qbi,
811
                   Node e,
812
                   FirstOrderModelFmc* f)
813
4635
      : QRepBoundExt(qbi, f), d_entry(e), d_fm(f)
814
  {
815
4635
  }
816
4635
  ~RepBoundFmcEntry() {}
817
  /** set bound */
818
6504
  virtual RsiEnumType setBound(Node owner,
819
                               unsigned i,
820
                               std::vector<Node>& elements) override
821
  {
822
6504
    if (!d_fm->isStar(d_entry[i]))
823
    {
824
      // only need to consider the single point
825
1451
      elements.push_back(d_entry[i]);
826
1451
      return ENUM_DEFAULT;
827
    }
828
5053
    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
4635
bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc* fm,
839
                                             Node f,
840
                                             Node c)
841
{
842
4635
  Trace("fmc-exh") << "----Exhaustive instantiate based on " << c << " ";
843
4635
  debugPrintCond("fmc-exh", c, true);
844
4635
  Trace("fmc-exh")<< std::endl;
845
4635
  QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference();
846
9270
  RepBoundFmcEntry rbfe(qbi, c, fm);
847
9270
  RepSetIterator riter(fm->getRepSet(), &rbfe);
848
4635
  Trace("fmc-exh-debug") << "Set quantifier..." << std::endl;
849
  //initialize
850
4635
  if (riter.setQuantifier(f))
851
  {
852
4635
    Trace("fmc-exh-debug") << "Set element domains..." << std::endl;
853
4635
    int addedLemmas = 0;
854
    //now do full iteration
855
4635
    Instantiate* ie = d_qim.getInstantiate();
856
59301
    while( !riter.isFinished() ){
857
27333
      d_triedLemmas++;
858
27333
      Trace("fmc-exh-debug") << "Inst : ";
859
54666
      std::vector< Node > ev_inst;
860
54666
      std::vector< Node > inst;
861
99836
      for (unsigned i = 0; i < riter.getNumTerms(); i++)
862
      {
863
145006
        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
145006
        Node rr = riter.getCurrentTerm(i, !tn.isClosedEnumerable());
869
145006
        Node r = fm->getRepresentative(rr);
870
72503
        debugPrint("fmc-exh-debug", r);
871
72503
        Trace("fmc-exh-debug") << " (term : " << rr << ")";
872
72503
        ev_inst.push_back( r );
873
72503
        inst.push_back( rr );
874
      }
875
27333
      int ev_index = d_quant_models[f].getGeneralizationIndex(fm, ev_inst);
876
27333
      Trace("fmc-exh-debug") << ", index = " << ev_index << " / " << d_quant_models[f].d_value.size();
877
54666
      Node ev = ev_index==-1 ? Node::null() : d_quant_models[f].d_value[ev_index];
878
27333
      if (ev!=d_true) {
879
24613
        Trace("fmc-exh-debug") << ", add!";
880
        //add as instantiation
881
49226
        if (ie->addInstantiation(f,
882
                                 inst,
883
                                 InferenceId::QUANTIFIERS_INST_FMF_FMC_EXH,
884
49226
                                 Node::null(),
885
                                 true))
886
        {
887
4751
          Trace("fmc-exh-debug")  << " ...success.";
888
4751
          addedLemmas++;
889
4751
          if (d_qstate.isInConflict() || options::fmfOneInstPerRound())
890
          {
891
            break;
892
          }
893
        }else{
894
19862
          Trace("fmc-exh-debug") << ", failed.";
895
        }
896
      }else{
897
2720
        Trace("fmc-exh-debug") << ", already true";
898
      }
899
27333
      Trace("fmc-exh-debug") << std::endl;
900
27333
      int index = riter.increment();
901
27333
      Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
902
27333
      if( !riter.isFinished() ){
903
70401
        if (index >= 0 && riter.d_index[index] > 0 && addedLemmas > 0
904
29824
            && riter.d_enum_type[index] == ENUM_CUSTOM)
905
        {
906
2402
          Trace("fmc-exh-debug")
907
1201
              << "Since this is a custom enumeration, skip to the next..."
908
1201
              << std::endl;
909
1201
          riter.incrementAtIndex(index - 1);
910
        }
911
      }
912
    }
913
4635
    d_addedLemmas += addedLemmas;
914
4635
    Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.isIncomplete() << std::endl;
915
4635
    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
107884
void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n ) {
923
107884
  Trace("fmc-debug") << "Check " << n << " " << n.getKind() << std::endl;
924
  //first check if it is a bounding literal
925
107884
  if( n.hasAttribute(BoundIntLitAttribute()) ){
926
2216
    Trace("fmc-debug") << "It is a bounding literal, polarity = " << n.getAttribute(BoundIntLitAttribute()) << std::endl;
927
2216
    d.addEntry(fm, mkCondDefault(fm, f), n.getAttribute(BoundIntLitAttribute())==1 ? d_false : d_true );
928
105668
  }else if( n.getKind() == kind::BOUND_VARIABLE ){
929
25253
    Trace("fmc-debug") << "Add default entry..." << std::endl;
930
25253
    d.addEntry(fm, mkCondDefault(fm, f), n);
931
  }
932
80415
  else if( n.getKind() == kind::NOT ){
933
    //just do directly
934
8340
    doCheck( fm, f, d, n[0] );
935
8340
    doNegate( d );
936
  }
937
72075
  else if( n.getKind() == kind::FORALL ){
938
1990
    d.addEntry(fm, mkCondDefault(fm, f), Node::null());
939
  }
940
70085
  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
452
    d.reset();
946
452
    d.addEntry(fm, mkCondDefault(fm, f), Node::null());
947
  }
948
69633
  else if( n.getNumChildren()==0 ){
949
35000
    Node r = n;
950
17500
    if( !n.isConst() ){
951
15684
      TypeNode tn = n.getType();
952
7842
      if( !fm->hasTerm(n) && tn.isFirstClass() ){
953
185
        r = getSomeDomainElement(fm, tn );
954
      }
955
7842
      r = fm->getRepresentative( r );
956
    }
957
17500
    Trace("fmc-debug") << "Add constant entry..." << std::endl;
958
17500
    d.addEntry(fm, mkCondDefault(fm, f), r);
959
  }
960
  else{
961
104266
    std::vector< int > var_ch;
962
104266
    std::vector< Def > children;
963
145373
    for( int i=0; i<(int)n.getNumChildren(); i++) {
964
186480
      Def dc;
965
93240
      doCheck(fm, f, dc, n[i]);
966
93240
      children.push_back(dc);
967
93240
      if( n[i].getKind() == kind::BOUND_VARIABLE ){
968
25249
        var_ch.push_back(i);
969
      }
970
    }
971
972
52133
    if( n.getKind()==APPLY_UF ){
973
23864
      Trace("fmc-debug") << "Do uninterpreted compose " << n << std::endl;
974
      //uninterpreted compose
975
23864
      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
28269
      if( !var_ch.empty() ){
988
3621
        if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
989
786
          if( var_ch.size()==2 ){
990
300
            Trace("fmc-debug") << "Do variable equality " << n << std::endl;
991
300
            doVariableEquality( fm, f, d, n );
992
          }else{
993
486
            Trace("fmc-debug") << "Do variable relation " << n << std::endl;
994
486
            doVariableRelation( fm, f, d, var_ch[0]==0 ? children[1] : children[0], var_ch[0]==0 ? n[0] : n[1] );
995
          }
996
        }else{
997
2835
          Trace("fmc-warn") << "Don't know how to check " << n << std::endl;
998
2835
          d.addEntry(fm, mkCondDefault(fm, f), Node::null());
999
        }
1000
      }else{
1001
24648
        Trace("fmc-debug") << "Do interpreted compose " << n << std::endl;
1002
49296
        std::vector< Node > cond;
1003
24648
        mkCondDefaultVec(fm, f, cond);
1004
49296
        std::vector< Node > val;
1005
        //interpreted compose
1006
24648
        doInterpretedCompose( fm, f, d, n, children, 0, cond, val );
1007
      }
1008
    }
1009
52133
    Trace("fmc-debug") << "Simplify the definition..." << std::endl;
1010
52133
    d.debugPrint("fmc-debug", Node::null(), this);
1011
52133
    d.simplify(this, fm);
1012
52133
    Trace("fmc-debug") << "Done simplifying" << std::endl;
1013
  }
1014
107884
  Trace("fmc-debug") << "Definition for " << n << " is : " << std::endl;
1015
107884
  d.debugPrint("fmc-debug", Node::null(), this);
1016
107884
  Trace("fmc-debug") << std::endl;
1017
107884
}
1018
1019
8340
void FullModelChecker::doNegate( Def & dc ) {
1020
19288
  for (unsigned i=0; i<dc.d_cond.size(); i++) {
1021
21896
    Node v = dc.d_value[i];
1022
10948
    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
8029
      dc.d_value[i] =
1029
16058
          v == d_true ? d_false : (v == d_false ? d_true : Node::null());
1030
    }
1031
  }
1032
8340
}
1033
1034
300
void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq ) {
1035
600
  std::vector<Node> cond;
1036
300
  mkCondDefaultVec(fm, f, cond);
1037
300
  if (eq[0]==eq[1]){
1038
    d.addEntry(fm, mkCond(cond), d_true);
1039
  }else{
1040
600
    TypeNode tn = eq[0].getType();
1041
300
    if( tn.isSort() ){
1042
300
      int j = fm->getVariableId(f, eq[0]);
1043
300
      int k = fm->getVariableId(f, eq[1]);
1044
300
      const RepSet* rs = fm->getRepSet();
1045
300
      if (!rs->hasType(tn))
1046
      {
1047
        getSomeDomainElement( fm, tn );  //to verify the type is initialized
1048
      }
1049
300
      unsigned nreps = rs->getNumRepresentatives(tn);
1050
876
      for (unsigned i = 0; i < nreps; i++)
1051
      {
1052
1152
        Node r = fm->getRepresentative(rs->getRepresentative(tn, i));
1053
576
        cond[j+1] = r;
1054
576
        cond[k+1] = r;
1055
576
        d.addEntry( fm, mkCond(cond), d_true);
1056
      }
1057
300
      d.addEntry( fm, mkCondDefault(fm, f), d_false);
1058
    }else{
1059
      d.addEntry( fm, mkCondDefault(fm, f), Node::null());
1060
    }
1061
  }
1062
300
}
1063
1064
486
void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
1065
486
  int j = fm->getVariableId(f, v);
1066
1106
  for (unsigned i=0; i<dc.d_cond.size(); i++) {
1067
1240
    Node val = dc.d_value[i];
1068
620
    if( val.isNull() ){
1069
9
      d.addEntry( fm, dc.d_cond[i], val);
1070
    }else{
1071
611
      if( dc.d_cond[i][j]!=val ){
1072
489
        if (fm->isStar(dc.d_cond[i][j])) {
1073
954
          std::vector<Node> cond;
1074
477
          mkCondVec(dc.d_cond[i],cond);
1075
477
          cond[j+1] = val;
1076
477
          d.addEntry(fm, mkCond(cond), d_true);
1077
477
          cond[j+1] = fm->getStar(val.getType());
1078
477
          d.addEntry(fm, mkCond(cond), d_false);
1079
        }else{
1080
12
          d.addEntry( fm, dc.d_cond[i], d_false);
1081
        }
1082
      }else{
1083
122
        d.addEntry( fm, dc.d_cond[i], d_true);
1084
      }
1085
    }
1086
  }
1087
486
}
1088
1089
23864
void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node op, std::vector< Def > & dc ) {
1090
23864
  Trace("fmc-uf-debug") << "Definition : " << std::endl;
1091
23864
  fm->d_models[op]->debugPrint("fmc-uf-debug", op, this);
1092
23864
  Trace("fmc-uf-debug") << std::endl;
1093
1094
47728
  std::vector< Node > cond;
1095
23864
  mkCondDefaultVec(fm, f, cond);
1096
47728
  std::vector< Node > val;
1097
23864
  doUninterpretedCompose( fm, f, d, *fm->d_models[op], dc, 0, cond, val);
1098
23864
}
1099
1100
66098
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
66098
  Trace("fmc-uf-process") << "process at " << index << std::endl;
1104
180441
  for( unsigned i=1; i<cond.size(); i++) {
1105
114343
    debugPrint("fmc-uf-process", cond[i], true);
1106
114343
    Trace("fmc-uf-process") << " ";
1107
  }
1108
66098
  Trace("fmc-uf-process") << std::endl;
1109
66098
  if (index==(int)dc.size()) {
1110
    //we have an entry, now do actual compose
1111
59664
    std::map< int, Node > entries;
1112
29832
    doUninterpretedCompose2( fm, f, entries, 0, cond, val, df.d_et);
1113
29832
    if( entries.empty() ){
1114
925
      d.addEntry(fm, mkCond(cond), Node::null());
1115
    }else{
1116
      //add them to the definition
1117
95772
      for( unsigned e=0; e<df.d_cond.size(); e++ ){
1118
66865
        if ( entries.find(e)!=entries.end() ){
1119
47949
          Trace("fmf-uf-process-debug") << "Add entry..." << std::endl;
1120
47949
          d.addEntry(fm, entries[e], df.d_value[e] );
1121
47949
          Trace("fmf-uf-process-debug") << "Done add entry." << std::endl;
1122
        }
1123
      }
1124
    }
1125
  }else{
1126
84388
    for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
1127
48122
      if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
1128
84468
        std::vector< Node > new_cond;
1129
42234
        new_cond.insert(new_cond.end(), cond.begin(), cond.end());
1130
42234
        if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
1131
42234
          Trace("fmc-uf-process") << "index " << i << " succeeded meet." << std::endl;
1132
42234
          val.push_back(dc[index].d_value[i]);
1133
42234
          doUninterpretedCompose(fm, f, d, df, dc, index+1, new_cond, val);
1134
42234
          val.pop_back();
1135
        }else{
1136
          Trace("fmc-uf-process") << "index " << i << " failed meet." << std::endl;
1137
        }
1138
      }
1139
    }
1140
  }
1141
66098
}
1142
1143
99784
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
99784
  Trace("fmc-uf-process") << "compose " << index << " / " << val.size() << std::endl;
1148
272146
  for( unsigned i=1; i<cond.size(); i++) {
1149
172362
    debugPrint("fmc-uf-process", cond[i], true);
1150
172362
    Trace("fmc-uf-process") << " ";
1151
  }
1152
99784
  Trace("fmc-uf-process") << std::endl;
1153
99784
  if (index==(int)val.size()) {
1154
95898
    Node c = mkCond(cond);
1155
47949
    Trace("fmc-uf-entry") << "Entry : " << c << " -> index[" << curr.d_data << "]" << std::endl;
1156
47949
    entries[curr.d_data] = c;
1157
  }else{
1158
103670
    Node v = val[index];
1159
51835
    Trace("fmc-uf-process") << "Process " << v << std::endl;
1160
51835
    bool bind_var = false;
1161
51835
    if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
1162
24411
      int j = fm->getVariableId(f, v);
1163
24411
      Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
1164
24411
      if (!fm->isStar(cond[j + 1]))
1165
      {
1166
38
        v = cond[j+1];
1167
      }else{
1168
24373
        bind_var = true;
1169
      }
1170
    }
1171
51835
    if (bind_var) {
1172
24373
      Trace("fmc-uf-process") << "bind variable..." << std::endl;
1173
24373
      int j = fm->getVariableId(f, v);
1174
24373
      Assert(fm->isStar(cond[j + 1]));
1175
64033
      for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin();
1176
64033
           it != curr.d_child.end();
1177
           ++it)
1178
      {
1179
39660
        cond[j + 1] = it->first;
1180
39660
        doUninterpretedCompose2(
1181
39660
            fm, f, entries, index + 1, cond, val, it->second);
1182
      }
1183
24373
      cond[j + 1] = fm->getStar(v.getType());
1184
    }else{
1185
27462
      if( !v.isNull() ){
1186
26528
        if (curr.d_child.find(v) != curr.d_child.end())
1187
        {
1188
7788
          Trace("fmc-uf-process") << "follow value..." << std::endl;
1189
7788
          doUninterpretedCompose2(
1190
7788
              fm, f, entries, index + 1, cond, val, curr.d_child[v]);
1191
        }
1192
53056
        Node st = fm->getStar(v.getType());
1193
26528
        if (curr.d_child.find(st) != curr.d_child.end())
1194
        {
1195
22504
          Trace("fmc-uf-process") << "follow star..." << std::endl;
1196
22504
          doUninterpretedCompose2(
1197
22504
              fm, f, entries, index + 1, cond, val, curr.d_child[st]);
1198
        }
1199
      }
1200
    }
1201
  }
1202
99784
}
1203
1204
102622
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
102622
  Trace("fmc-if-process") << "int compose " << index << " / " << dc.size() << std::endl;
1208
249785
  for( unsigned i=1; i<cond.size(); i++) {
1209
147163
    debugPrint("fmc-if-process", cond[i], true);
1210
147163
    Trace("fmc-if-process") << " ";
1211
  }
1212
102622
  Trace("fmc-if-process") << std::endl;
1213
102622
  if ( index==(int)dc.size() ){
1214
87962
    Node c = mkCond(cond);
1215
87962
    Node v = evaluateInterpreted(n, val);
1216
43981
    d.addEntry(fm, c, v);
1217
  }
1218
  else {
1219
117282
    TypeNode vtn = n.getType();
1220
155617
    for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
1221
96976
      if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
1222
171116
        std::vector< Node > new_cond;
1223
85558
        new_cond.insert(new_cond.end(), cond.begin(), cond.end());
1224
85558
        if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
1225
85558
          bool process = true;
1226
85558
          if (vtn.isBoolean()) {
1227
            //short circuit
1228
111677
            if( (n.getKind()==OR && dc[index].d_value[i]==d_true) ||
1229
52167
                (n.getKind()==AND && dc[index].d_value[i]==d_false) ){
1230
15168
              Node c = mkCond(new_cond);
1231
7584
              d.addEntry(fm, c, dc[index].d_value[i]);
1232
7584
              process = false;
1233
            }
1234
          }
1235
85558
          if (process) {
1236
77974
            val.push_back(dc[index].d_value[i]);
1237
77974
            doInterpretedCompose(fm, f, d, n, dc, index+1, new_cond, val);
1238
77974
            val.pop_back();
1239
          }
1240
        }
1241
      }
1242
    }
1243
  }
1244
102622
}
1245
1246
145098
int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
1247
145098
  Trace("fmc-debug3") << "isCompat " << c << std::endl;
1248
145098
  Assert(cond.size() == c.getNumChildren() + 1);
1249
372974
  for (unsigned i=1; i<cond.size(); i++) {
1250
245182
    if (cond[i] != c[i - 1] && !fm->isStar(cond[i]) && !fm->isStar(c[i - 1]))
1251
    {
1252
17306
      return 0;
1253
    }
1254
  }
1255
127792
  return 1;
1256
}
1257
1258
127792
bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
1259
127792
  Trace("fmc-debug3") << "doMeet " << c << std::endl;
1260
127792
  Assert(cond.size() == c.getNumChildren() + 1);
1261
340336
  for (unsigned i=1; i<cond.size(); i++) {
1262
212544
    if( cond[i]!=c[i-1] ) {
1263
64338
      if (fm->isStar(cond[i]))
1264
      {
1265
36305
        cond[i] = c[i - 1];
1266
      }
1267
28033
      else if (!fm->isStar(c[i - 1]))
1268
      {
1269
        return false;
1270
      }
1271
    }
1272
  }
1273
127792
  return true;
1274
}
1275
1276
155726
Node FullModelChecker::mkCond( std::vector< Node > & cond ) {
1277
155726
  return NodeManager::currentNM()->mkNode(APPLY_UF, cond);
1278
}
1279
1280
52712
Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
1281
105424
  std::vector< Node > cond;
1282
52712
  mkCondDefaultVec(fm, f, cond);
1283
105424
  return mkCond(cond);
1284
}
1285
1286
101524
void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
1287
101524
  Trace("fmc-debug") << "Make default vec" << std::endl;
1288
  //get function symbol for f
1289
101524
  cond.push_back(d_quant_cond[f]);
1290
257934
  for (unsigned i=0; i<f[0].getNumChildren(); i++) {
1291
312820
    Node ts = fm->getStar(f[0][i].getType());
1292
156410
    Assert(ts.getType() == f[0][i].getType());
1293
156410
    cond.push_back(ts);
1294
  }
1295
101524
}
1296
1297
477
void FullModelChecker::mkCondVec( Node n, std::vector< Node > & cond ) {
1298
477
  cond.push_back(n.getOperator());
1299
1074
  for( unsigned i=0; i<n.getNumChildren(); i++ ){
1300
597
    cond.push_back( n[i] );
1301
  }
1302
477
}
1303
1304
43981
Node FullModelChecker::evaluateInterpreted( Node n, std::vector< Node > & vals ) {
1305
43981
  if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
1306
11078
    if (!vals[0].isNull() && !vals[1].isNull()) {
1307
9603
      return vals[0]==vals[1] ? d_true : d_false;
1308
    }else{
1309
1475
      return Node::null();
1310
    }
1311
32903
  }else if( n.getKind()==ITE ){
1312
3790
    if( vals[0]==d_true ){
1313
1682
      return vals[1];
1314
2108
    }else if( vals[0]==d_false ){
1315
2024
      return vals[2];
1316
    }else{
1317
84
      return vals[1]==vals[2] ? vals[1] : Node::null();
1318
    }
1319
29113
  }else if( n.getKind()==AND || n.getKind()==OR ){
1320
5462
    bool isNull = false;
1321
20910
    for (unsigned i=0; i<vals.size(); i++) {
1322
15448
      if((vals[i]==d_true && n.getKind()==OR) || (vals[i]==d_false && n.getKind()==AND)) {
1323
        return vals[i];
1324
15448
      }else if( vals[i].isNull() ){
1325
3544
        isNull = true;
1326
      }
1327
    }
1328
5462
    return isNull ? Node::null() : vals[0];
1329
  }else{
1330
47302
    std::vector<Node> children;
1331
23651
    if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
1332
7925
      children.push_back( n.getOperator() );
1333
    }
1334
60132
    for (unsigned i=0; i<vals.size(); i++) {
1335
39301
      if( vals[i].isNull() ){
1336
2820
        return Node::null();
1337
      }else{
1338
36481
        children.push_back( vals[i] );
1339
      }
1340
    }
1341
41662
    Node nc = NodeManager::currentNM()->mkNode(n.getKind(), children);
1342
20831
    Trace("fmc-eval") << "Evaluate " << nc << " to ";
1343
20831
    nc = Rewriter::rewrite(nc);
1344
20831
    Trace("fmc-eval") << nc << std::endl;
1345
20831
    return nc;
1346
  }
1347
}
1348
1349
3519
Node FullModelChecker::getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn ) {
1350
3519
  bool addRepId = !fm->getRepSet()->hasType(tn);
1351
3519
  Node de = fm->getSomeDomainElement(tn);
1352
3519
  if( addRepId ){
1353
116
    d_rep_ids[tn][de] = 0;
1354
  }
1355
3519
  return de;
1356
}
1357
1358
7129
Node FullModelChecker::getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix ) {
1359
7129
  return fm->getFunctionValue(op, argPrefix);
1360
}
1361
1362
1363
38356
bool FullModelChecker::useSimpleModels() {
1364
38356
  return options::fmfFmcSimple();
1365
}
1366
19859
void FullModelChecker::registerQuantifiedFormula(Node q)
1367
{
1368
19859
  if (d_quant_cond.find(q) != d_quant_cond.end())
1369
  {
1370
18394
    return;
1371
  }
1372
1465
  NodeManager* nm = NodeManager::currentNM();
1373
1465
  SkolemManager* sm = nm->getSkolemManager();
1374
2930
  std::vector<TypeNode> types;
1375
3633
  for (const Node& v : q[0])
1376
  {
1377
4336
    TypeNode tn = v.getType();
1378
2168
    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
24
      d_unhandledQuant.insert(q);
1384
    }
1385
2168
    types.push_back(tn);
1386
  }
1387
2930
  TypeNode typ = nm->mkFunctionType(types, nm->booleanType());
1388
2930
  Node op = sm->mkDummySkolem("qfmc", typ, "op for full-model checking");
1389
1465
  d_quant_cond[q] = op;
1390
}
1391
1392
19859
bool FullModelChecker::isHandled(Node q) const
1393
{
1394
19859
  return d_unhandledQuant.find(q) == d_unhandledQuant.end();
1395
}
1396
1397
}  // namespace fmcheck
1398
}  // namespace quantifiers
1399
}  // namespace theory
1400
29340
}  // namespace cvc5