GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/fmf/model_engine.cpp Lines: 140 198 70.7 %
Date: 2021-11-07 Branches: 233 677 34.4 %

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