GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/fmf/model_engine.cpp Lines: 137 195 70.3 %
Date: 2021-08-06 Branches: 235 695 33.8 %

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