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