GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/first_order_model.cpp Lines: 161 180 89.4 %
Date: 2021-11-05 Branches: 247 536 46.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, 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 model engine model class.
14
 */
15
16
#include "theory/quantifiers/first_order_model.h"
17
#include "options/base_options.h"
18
#include "options/quantifiers_options.h"
19
#include "theory/quantifiers/fmf/bounded_integers.h"
20
#include "theory/quantifiers/fmf/model_engine.h"
21
#include "theory/quantifiers/quantifiers_attributes.h"
22
#include "theory/quantifiers/term_database.h"
23
#include "theory/quantifiers/term_enumeration.h"
24
#include "theory/quantifiers/term_registry.h"
25
#include "theory/quantifiers/term_util.h"
26
27
using namespace cvc5::kind;
28
using namespace cvc5::context;
29
30
namespace cvc5 {
31
namespace theory {
32
namespace quantifiers {
33
34
struct ModelBasisAttributeId
35
{
36
};
37
using ModelBasisAttribute = expr::Attribute<ModelBasisAttributeId, bool>;
38
// for APPLY_UF terms, 1 : term has direct child with model basis attribute,
39
//                     0 : term has no direct child with model basis attribute.
40
struct ModelBasisArgAttributeId
41
{
42
};
43
using ModelBasisArgAttribute = expr::Attribute<ModelBasisArgAttributeId, uint64_t>;
44
45
15271
FirstOrderModel::FirstOrderModel(Env& env,
46
                                 QuantifiersState& qs,
47
                                 QuantifiersRegistry& qr,
48
15271
                                 TermRegistry& tr)
49
    : EnvObj(env),
50
      d_model(nullptr),
51
      d_qreg(qr),
52
      d_treg(tr),
53
      d_eq_query(env, qs, this),
54
      d_forall_asserts(context()),
55
15271
      d_forallRlvComputed(false)
56
{
57
15271
}
58
59
12153
void FirstOrderModel::finishInit(TheoryModel* m) { d_model = m; }
60
61
130334
Node FirstOrderModel::getValue(TNode n) const { return d_model->getValue(n); }
62
8807
bool FirstOrderModel::hasTerm(TNode a) { return d_model->hasTerm(a); }
63
238408
Node FirstOrderModel::getRepresentative(TNode a)
64
{
65
238408
  return d_model->getRepresentative(a);
66
}
67
bool FirstOrderModel::areEqual(TNode a, TNode b)
68
{
69
  return d_model->areEqual(a, b);
70
}
71
bool FirstOrderModel::areDisequal(TNode a, TNode b)
72
{
73
  return d_model->areDisequal(a, b);
74
}
75
eq::EqualityEngine* FirstOrderModel::getEqualityEngine()
76
{
77
  return d_model->getEqualityEngine();
78
}
79
169694
const RepSet* FirstOrderModel::getRepSet() const
80
{
81
169694
  return d_model->getRepSet();
82
}
83
11159
RepSet* FirstOrderModel::getRepSetPtr() { return d_model->getRepSetPtr(); }
84
TheoryModel* FirstOrderModel::getTheoryModel() { return d_model; }
85
86
76576
Node FirstOrderModel::getInternalRepresentative(Node a, Node q, size_t index)
87
{
88
76576
  return d_eq_query.getInternalRepresentative(a, q, index);
89
}
90
91
69375
void FirstOrderModel::assertQuantifier( Node n ){
92
69375
  if( n.getKind()==FORALL ){
93
69375
    d_forall_asserts.push_back( n );
94
  }else if( n.getKind()==NOT ){
95
    Assert(n[0].getKind() == FORALL);
96
  }
97
69375
}
98
99
125330
size_t FirstOrderModel::getNumAssertedQuantifiers() const
100
{
101
125330
  return d_forall_asserts.size();
102
}
103
104
725498
Node FirstOrderModel::getAssertedQuantifier( unsigned i, bool ordered ) {
105
725498
  if( !ordered || !d_forallRlvComputed ){
106
489704
    return d_forall_asserts[i];
107
  }
108
  // If we computed the relevant forall assertion vector, in reset_round,
109
  // then it should have the same size as the default assertion vector.
110
235794
  Assert(d_forall_rlv_assert.size() == d_forall_asserts.size());
111
235794
  return d_forall_rlv_assert[i];
112
}
113
114
2117
void FirstOrderModel::initialize() {
115
2117
  processInitialize( true );
116
  //this is called after representatives have been chosen and the equality engine has been built
117
  //for each quantifier, collect all operators we care about
118
11369
  for( unsigned i=0; i<getNumAssertedQuantifiers(); i++ ){
119
18504
    Node f = getAssertedQuantifier( i );
120
9252
    if( d_quant_var_id.find( f )==d_quant_var_id.end() ){
121
3795
      for(unsigned j=0; j<f[0].getNumChildren(); j++){
122
2254
        d_quant_var_id[f][f[0][j]] = j;
123
      }
124
    }
125
9252
    processInitializeQuantifier( f );
126
    //initialize relevant models within bodies of all quantifiers
127
18504
    std::map< Node, bool > visited;
128
9252
    initializeModelForTerm( f[1], visited );
129
  }
130
2117
  processInitialize( false );
131
2117
}
132
133
222512
void FirstOrderModel::initializeModelForTerm( Node n, std::map< Node, bool >& visited ){
134
222512
  if( visited.find( n )==visited.end() ){
135
161558
    visited[n] = true;
136
161558
    processInitializeModelForTerm( n );
137
374818
    for( int i=0; i<(int)n.getNumChildren(); i++ ){
138
213260
      initializeModelForTerm( n[i], visited );
139
    }
140
  }
141
222512
}
142
143
3419
Node FirstOrderModel::getSomeDomainElement(TypeNode tn){
144
  //check if there is even any domain elements at all
145
3419
  RepSet* rs = d_model->getRepSetPtr();
146
3419
  if (!rs->hasType(tn) || rs->getNumRepresentatives(tn) == 0)
147
  {
148
254
    Trace("fm-debug") << "Must create domain element for " << tn << "..."
149
127
                      << std::endl;
150
254
    Node mbt = getModelBasisTerm(tn);
151
127
    Trace("fm-debug") << "Add to representative set..." << std::endl;
152
127
    rs->add(tn, mbt);
153
  }
154
3419
  return rs->getRepresentative(tn, 0);
155
}
156
157
7520
bool FirstOrderModel::initializeRepresentativesForType(TypeNode tn)
158
{
159
7520
  RepSet* rs = d_model->getRepSetPtr();
160
7520
  if (tn.isSort())
161
  {
162
    // must ensure uninterpreted type is non-empty.
163
1808
    if (!rs->hasType(tn))
164
    {
165
      // terms in rep_set are now constants which mapped to terms through
166
      // TheoryModel. Thus, should introduce a constant and a term.
167
      // For now, we just add an arbitrary term.
168
14
      Node var = getSomeDomainElement(tn);
169
14
      Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn
170
7
                     << std::endl;
171
7
      rs->add(tn, var);
172
    }
173
1808
    return true;
174
  }
175
  else
176
  {
177
    // can we complete it?
178
5712
    if (d_qreg.getQuantifiersBoundInference().mayComplete(tn))
179
    {
180
4268
      Trace("fm-debug") << "  do complete, since cardinality is small ("
181
2134
                        << tn.getCardinality() << ")..." << std::endl;
182
2134
      rs->complete(tn);
183
      // must have succeeded
184
2134
      Assert(rs->hasType(tn));
185
2134
      return true;
186
    }
187
3578
    Trace("fm-debug") << "  variable cannot be bounded." << std::endl;
188
3578
    return false;
189
  }
190
}
191
192
bool FirstOrderModel::isModelBasis(TNode n)
193
{
194
  return n.getAttribute(ModelBasisAttribute());
195
}
196
197
15271
EqualityQuery* FirstOrderModel::getEqualityQuery() { return &d_eq_query; }
198
199
/** needs check */
200
122791
bool FirstOrderModel::checkNeeded() {
201
122791
  return d_forall_asserts.size()>0;
202
}
203
204
34949
void FirstOrderModel::reset_round() {
205
34949
  d_quant_active.clear();
206
207
  // compute which quantified formulas are asserted if necessary
208
69898
  std::map<Node, bool> qassert;
209
34949
  if (!d_forall_rlv_vec.empty())
210
  {
211
6676
    Trace("fm-relevant-debug")
212
3338
        << "Mark asserted quantified formulas..." << std::endl;
213
152766
    for (const Node& q : d_forall_asserts)
214
    {
215
149428
      qassert[q] = true;
216
    }
217
  }
218
  //order the quantified formulas
219
34949
  d_forall_rlv_assert.clear();
220
34949
  d_forallRlvComputed = false;
221
34949
  if( !d_forall_rlv_vec.empty() ){
222
3338
    d_forallRlvComputed = true;
223
3338
    Trace("fm-relevant") << "Build sorted relevant list..." << std::endl;
224
3338
    Trace("fm-relevant-debug") << "Add relevant asserted formulas..." << std::endl;
225
3338
    std::map<Node, bool>::iterator ita;
226
11796
    for( int i=(int)(d_forall_rlv_vec.size()-1); i>=0; i-- ){
227
16916
      Node q = d_forall_rlv_vec[i];
228
8458
      ita = qassert.find(q);
229
8458
      if (ita != qassert.end())
230
      {
231
7869
        Trace("fm-relevant") << "   " << q << std::endl;
232
7869
        d_forall_rlv_assert.push_back( q );
233
7869
        qassert.erase(ita);
234
      }
235
    }
236
3338
    Trace("fm-relevant-debug") << "Add remaining asserted formulas..." << std::endl;
237
152766
    for (const Node& q : d_forall_asserts)
238
    {
239
      // if we didn't include it above
240
149428
      if (qassert.find(q) != qassert.end())
241
      {
242
141559
        d_forall_rlv_assert.push_back( q );
243
      }else{
244
7869
        Trace("fm-relevant-debug") << "...already included " << q << std::endl;
245
      }
246
    }
247
3338
    Trace("fm-relevant-debug") << "Sizes : " << d_forall_rlv_assert.size() << " " << d_forall_asserts.size() << std::endl;
248
3338
    Assert(d_forall_rlv_assert.size() == d_forall_asserts.size());
249
  }
250
34949
}
251
252
2432
void FirstOrderModel::markRelevant( Node q ) {
253
  // Put q on the back of the vector d_forall_rlv_vec.
254
  // If we were the last quantifier marked relevant, this is a no-op, return.
255
2432
  if( q!=d_last_forall_rlv ){
256
1159
    Trace("fm-relevant") << "Mark relevant : " << q << std::endl;
257
    std::vector<Node>::iterator itr =
258
1159
        std::find(d_forall_rlv_vec.begin(), d_forall_rlv_vec.end(), q);
259
1159
    if (itr != d_forall_rlv_vec.end())
260
    {
261
154
      d_forall_rlv_vec.erase(itr, itr + 1);
262
    }
263
1159
    d_forall_rlv_vec.push_back(q);
264
1159
    d_last_forall_rlv = q;
265
  }
266
2432
}
267
268
1646
void FirstOrderModel::setQuantifierActive( TNode q, bool active ) {
269
1646
  d_quant_active[q] = active;
270
1646
}
271
272
323883
bool FirstOrderModel::isQuantifierActive(TNode q) const
273
{
274
323883
  std::map<TNode, bool>::const_iterator it = d_quant_active.find(q);
275
323883
  if( it==d_quant_active.end() ){
276
323756
    return true;
277
  }
278
127
  return it->second;
279
}
280
281
27419
bool FirstOrderModel::isQuantifierAsserted(TNode q) const
282
{
283
27419
  return std::find( d_forall_asserts.begin(), d_forall_asserts.end(), q )!=d_forall_asserts.end();
284
}
285
286
88285
Node FirstOrderModel::getModelBasisTerm(TypeNode tn)
287
{
288
88285
  if (d_model_basis_term.find(tn) == d_model_basis_term.end())
289
  {
290
2208
    Node mbt;
291
1104
    if (tn.isClosedEnumerable())
292
    {
293
589
      mbt = d_treg.getTermEnumeration()->getEnumerateTerm(tn, 0);
294
    }
295
    else
296
    {
297
515
      if (options::fmfFreshDistConst())
298
      {
299
        mbt = d_treg.getTermDatabase()->getOrMakeTypeFreshVariable(tn);
300
      }
301
      else
302
      {
303
        // The model basis term cannot be an interpreted function, or else we
304
        // may produce an inconsistent model by choosing an arbitrary
305
        // equivalence class for it. Hence, we require that it be an existing or
306
        // fresh variable.
307
515
        mbt = d_treg.getTermDatabase()->getOrMakeTypeGroundTerm(tn, true);
308
      }
309
    }
310
    ModelBasisAttribute mba;
311
1104
    mbt.setAttribute(mba, true);
312
1104
    d_model_basis_term[tn] = mbt;
313
2208
    Trace("model-basis-term") << "Choose " << mbt << " as model basis term for "
314
1104
                              << tn << std::endl;
315
  }
316
88285
  return d_model_basis_term[tn];
317
}
318
319
75190
bool FirstOrderModel::isModelBasisTerm(Node n)
320
{
321
75190
  return n == getModelBasisTerm(n.getType());
322
}
323
324
11311
Node FirstOrderModel::getModelBasisOpTerm(Node op)
325
{
326
11311
  if (d_model_basis_op_term.find(op) == d_model_basis_op_term.end())
327
  {
328
2188
    TypeNode t = op.getType();
329
2188
    std::vector<Node> children;
330
1094
    children.push_back(op);
331
2703
    for (int i = 0; i < (int)(t.getNumChildren() - 1); i++)
332
    {
333
1609
      children.push_back(getModelBasisTerm(t[i]));
334
    }
335
1094
    if (children.size() == 1)
336
    {
337
      d_model_basis_op_term[op] = op;
338
    }
339
    else
340
    {
341
1094
      d_model_basis_op_term[op] =
342
2188
          NodeManager::currentNM()->mkNode(APPLY_UF, children);
343
    }
344
  }
345
11311
  return d_model_basis_op_term[op];
346
}
347
348
Node FirstOrderModel::getModelBasis(Node q, Node n)
349
{
350
  // make model basis
351
  if (d_model_basis_terms.find(q) == d_model_basis_terms.end())
352
  {
353
    for (unsigned j = 0; j < q[0].getNumChildren(); j++)
354
    {
355
      d_model_basis_terms[q].push_back(getModelBasisTerm(q[0][j].getType()));
356
    }
357
  }
358
  Node gn = d_qreg.substituteInstConstants(n, q, d_model_basis_terms[q]);
359
  return gn;
360
}
361
362
24527
void FirstOrderModel::computeModelBasisArgAttribute(Node n)
363
{
364
24527
  if (!n.hasAttribute(ModelBasisArgAttribute()))
365
  {
366
    // ensure that the model basis terms have been defined
367
4029
    if (n.getKind() == APPLY_UF)
368
    {
369
4029
      getModelBasisOpTerm(n.getOperator());
370
    }
371
4029
    uint64_t val = 0;
372
    // determine if it has model basis attribute
373
11126
    for (unsigned j = 0, nchild = n.getNumChildren(); j < nchild; j++)
374
    {
375
7097
      if (n[j].getAttribute(ModelBasisAttribute()))
376
      {
377
912
        val++;
378
      }
379
    }
380
    ModelBasisArgAttribute mbaa;
381
4029
    n.setAttribute(mbaa, val);
382
  }
383
24527
}
384
385
24527
unsigned FirstOrderModel::getModelBasisArg(Node n)
386
{
387
24527
  computeModelBasisArgAttribute(n);
388
24527
  return n.getAttribute(ModelBasisArgAttribute());
389
}
390
391
}  // namespace quantifiers
392
}  // namespace theory
393
31125
}  // namespace cvc5