GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/quantifiers_attributes.cpp Lines: 170 229 74.2 %
Date: 2021-09-16 Branches: 395 920 42.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Paul Meng, Morgan Deters
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 QuantifiersAttributes class.
14
 */
15
16
#include "theory/quantifiers/quantifiers_attributes.h"
17
18
#include "options/quantifiers_options.h"
19
#include "theory/arith/arith_msum.h"
20
#include "theory/quantifiers/sygus/synth_engine.h"
21
#include "theory/quantifiers/term_util.h"
22
23
using namespace std;
24
using namespace cvc5::kind;
25
using namespace cvc5::context;
26
27
namespace cvc5 {
28
namespace theory {
29
namespace quantifiers {
30
31
965082
bool QAttributes::isStandard() const
32
{
33
965082
  return !d_sygus && !d_quant_elim && !isFunDef() && !d_isInternal;
34
}
35
36
9942
QuantAttributes::QuantAttributes() {}
37
38
3087
void QuantAttributes::setUserAttribute(const std::string& attr,
39
                                       TNode n,
40
                                       const std::vector<Node>& nodeValues)
41
{
42
3087
  Trace("quant-attr-debug") << "Set " << attr << " " << n << std::endl;
43
3087
  if (attr == "fun-def")
44
  {
45
    Trace("quant-attr-debug") << "Set function definition " << n << std::endl;
46
    FunDefAttribute fda;
47
    n.setAttribute( fda, true );
48
  }
49
3087
  else if (attr == "qid")
50
  {
51
    // using z3 syntax "qid"
52
2940
    Trace("quant-attr-debug") << "Set quant-name " << n << std::endl;
53
    QuantNameAttribute qna;
54
2940
    n.setAttribute(qna, true);
55
147
  }else if( attr=="quant-inst-max-level" ){
56
    Assert(nodeValues.size() == 1);
57
    uint64_t lvl = nodeValues[0].getConst<Rational>().getNumerator().getLong();
58
    Trace("quant-attr-debug") << "Set instantiation level " << n << " to " << lvl << std::endl;
59
    QuantInstLevelAttribute qila;
60
    n.setAttribute( qila, lvl );
61
147
  }else if( attr=="quant-elim" ){
62
129
    Trace("quant-attr-debug") << "Set quantifier elimination " << n << std::endl;
63
    QuantElimAttribute qea;
64
129
    n.setAttribute( qea, true );
65
18
  }else if( attr=="quant-elim-partial" ){
66
17
    Trace("quant-attr-debug") << "Set partial quantifier elimination " << n << std::endl;
67
    QuantElimPartialAttribute qepa;
68
17
    n.setAttribute( qepa, true );
69
  }
70
3087
}
71
72
bool QuantAttributes::checkFunDef( Node q ) {
73
  return !getFunDefHead( q ).isNull();
74
}
75
76
bool QuantAttributes::checkFunDefAnnotation( Node ipl ) {
77
  if( !ipl.isNull() ){
78
    for( unsigned i=0; i<ipl.getNumChildren(); i++ ){
79
      if( ipl[i].getKind()==INST_ATTRIBUTE ){
80
        if( ipl[i][0].getAttribute(FunDefAttribute()) ){
81
          return true;
82
        }
83
      }
84
    }
85
  }
86
  return false;
87
}
88
89
615
Node QuantAttributes::getFunDefHead( Node q ) {
90
  //&& q[1].getKind()==EQUAL && q[1][0].getKind()==APPLY_UF &&
91
615
  if( q.getKind()==FORALL && q.getNumChildren()==3 ){
92
238
    Node ipl = q[2];
93
238
    for (unsigned i = 0; i < ipl.getNumChildren(); i++)
94
    {
95
708
      if (ipl[i].getKind() == INST_ATTRIBUTE
96
708
          && ipl[i][0].getAttribute(FunDefAttribute()))
97
      {
98
234
        return ipl[i][0];
99
      }
100
    }
101
  }
102
381
  return Node::null();
103
}
104
117
Node QuantAttributes::getFunDefBody( Node q ) {
105
234
  Node h = getFunDefHead( q );
106
117
  if( !h.isNull() ){
107
117
    if( q[1].getKind()==EQUAL ){
108
112
      if( q[1][0]==h ){
109
63
        return q[1][1];
110
49
      }else if( q[1][1]==h ){
111
48
        return q[1][0];
112
      }
113
1
      else if (q[1][0].getType().isReal())
114
      {
115
        // solve for h in the equality
116
1
        std::map<Node, Node> msum;
117
1
        if (ArithMSum::getMonomialSumLit(q[1], msum))
118
        {
119
1
          Node veq;
120
1
          int res = ArithMSum::isolate(h, msum, veq, EQUAL);
121
1
          if (res != 0)
122
          {
123
1
            Assert(veq.getKind() == EQUAL);
124
1
            return res == 1 ? veq[1] : veq[0];
125
          }
126
        }
127
      }
128
    }else{
129
5
      Node atom = q[1].getKind()==NOT ? q[1][0] : q[1];
130
5
      bool pol = q[1].getKind()!=NOT;
131
5
      if( atom==h ){
132
5
        return NodeManager::currentNM()->mkConst( pol );
133
      }
134
    }
135
  }
136
  return Node::null();
137
}
138
139
2589
bool QuantAttributes::checkSygusConjecture( Node q ) {
140
2589
  return ( q.getKind()==FORALL && q.getNumChildren()==3 ) ? checkSygusConjectureAnnotation( q[2] ) : false;
141
}
142
143
425
bool QuantAttributes::checkSygusConjectureAnnotation( Node ipl ){
144
425
  if( !ipl.isNull() ){
145
516
    for( unsigned i=0; i<ipl.getNumChildren(); i++ ){
146
425
      if( ipl[i].getKind()==INST_ATTRIBUTE ){
147
516
        Node avar = ipl[i][0];
148
425
        if( avar.getAttribute(SygusAttribute()) ){
149
334
          return true;
150
        }
151
      }
152
    }
153
  }
154
91
  return false;
155
}
156
157
bool QuantAttributes::checkQuantElimAnnotation( Node ipl ) {
158
  if( !ipl.isNull() ){
159
    for( unsigned i=0; i<ipl.getNumChildren(); i++ ){
160
      if( ipl[i].getKind()==INST_ATTRIBUTE ){
161
        Node avar = ipl[i][0];
162
        if( avar.getAttribute(QuantElimAttribute()) ){
163
          return true;
164
        }
165
      }
166
    }
167
  }
168
  return false;
169
}
170
171
2298
bool QuantAttributes::hasPattern(Node q)
172
{
173
2298
  Assert(q.getKind() == FORALL);
174
2298
  if (q.getNumChildren() != 3)
175
  {
176
2124
    return false;
177
  }
178
199
  for (const Node& qc : q[2])
179
  {
180
183
    if (qc.getKind() == INST_PATTERN || qc.getKind() == INST_NO_PATTERN)
181
    {
182
158
      return true;
183
    }
184
  }
185
16
  return false;
186
}
187
188
25086
void QuantAttributes::computeAttributes( Node q ) {
189
25086
  computeQuantAttributes( q, d_qattr[q] );
190
25086
  QAttributes& qa = d_qattr[q];
191
25086
  if (qa.isFunDef())
192
  {
193
272
    Node f = qa.d_fundef_f;
194
136
    if( d_fun_defs.find( f )!=d_fun_defs.end() ){
195
      CVC5Message() << "Cannot define function " << f << " more than once."
196
                    << std::endl;
197
      AlwaysAssert(false);
198
    }
199
136
    d_fun_defs[f] = true;
200
  }
201
25086
}
202
203
193232
void QuantAttributes::computeQuantAttributes( Node q, QAttributes& qa ){
204
193232
  Trace("quant-attr-debug") << "Compute attributes for " << q << std::endl;
205
193232
  if( q.getNumChildren()==3 ){
206
34208
    NodeManager* nm = NodeManager::currentNM();
207
34208
    qa.d_ipl = q[2];
208
71902
    for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
209
37694
      Kind k = q[2][i].getKind();
210
75388
      Trace("quant-attr-debug")
211
37694
          << "Check : " << q[2][i] << " " << k << std::endl;
212
37694
      if (k == INST_PATTERN || k == INST_NO_PATTERN)
213
      {
214
27103
        qa.d_hasPattern = true;
215
      }
216
10591
      else if (k == INST_POOL || k == INST_ADD_TO_POOL
217
10535
               || k == SKOLEM_ADD_TO_POOL)
218
      {
219
112
        qa.d_hasPool = true;
220
      }
221
10479
      else if (k == INST_ATTRIBUTE)
222
      {
223
20958
        Node avar;
224
        // We support two use cases of INST_ATTRIBUTE:
225
        // (1) where the user constructs a term of the form
226
        // (INST_ATTRIBUTE "keyword" [nodeValues])
227
        // (2) where we internally generate nodes of the form
228
        // (INST_ATTRIBUTE v) where v has an internal attribute set on it.
229
        // We distinguish these two cases by checking the kind of the first
230
        // child.
231
10479
        if (q[2][i][0].getKind() == CONST_STRING)
232
        {
233
          // make a dummy variable to be used below
234
3087
          avar = nm->mkBoundVar(nm->booleanType());
235
6174
          std::vector<Node> nodeValues(q[2][i].begin() + 1, q[2][i].end());
236
          // set user attribute on the dummy variable
237
9261
          setUserAttribute(
238
6174
              q[2][i][0].getConst<String>().toString(), avar, nodeValues);
239
        }
240
        else
241
        {
242
          // assume the dummy variable has already had its attributes set
243
7392
          avar = q[2][i][0];
244
        }
245
10479
        if( avar.getAttribute(FunDefAttribute()) ){
246
1068
          Trace("quant-attr") << "Attribute : function definition : " << q << std::endl;
247
          //get operator directly from pattern
248
1068
          qa.d_fundef_f = q[2][i][0].getOperator();
249
        }
250
10479
        if( avar.getAttribute(SygusAttribute()) ){
251
          //not necessarily nested existential
252
          //Assert( q[1].getKind()==NOT );
253
          //Assert( q[1][0].getKind()==FORALL );
254
2420
          Trace("quant-attr") << "Attribute : sygus : " << q << std::endl;
255
2420
          qa.d_sygus = true;
256
        }
257
10479
        if (avar.hasAttribute(SygusSideConditionAttribute()))
258
        {
259
132
          qa.d_sygusSideCondition =
260
264
              avar.getAttribute(SygusSideConditionAttribute());
261
264
          Trace("quant-attr")
262
132
              << "Attribute : sygus side condition : "
263
132
              << qa.d_sygusSideCondition << " : " << q << std::endl;
264
        }
265
10479
        if (avar.getAttribute(QuantNameAttribute()))
266
        {
267
          // only set the name if there is a value
268
2940
          if (q[2][i].getNumChildren() > 1)
269
          {
270
5880
            Trace("quant-attr") << "Attribute : quantifier name : "
271
5880
                                << q[2][i][1].getConst<String>().toString()
272
2940
                                << " for " << q << std::endl;
273
            // assign the name to a variable with the given name (to avoid
274
            // enclosing the name in quotes)
275
5880
            qa.d_name = nm->mkBoundVar(q[2][i][1].getConst<String>().toString(),
276
8820
                                       nm->booleanType());
277
          }
278
          else
279
          {
280
            Warning() << "Missing name for qid attribute";
281
          }
282
        }
283
10479
        if( avar.hasAttribute(QuantInstLevelAttribute()) ){
284
          qa.d_qinstLevel = avar.getAttribute(QuantInstLevelAttribute());
285
          Trace("quant-attr") << "Attribute : quant inst level " << qa.d_qinstLevel << " : " << q << std::endl;
286
        }
287
10479
        if( avar.getAttribute(QuantElimAttribute()) ){
288
385
          Trace("quant-attr") << "Attribute : quantifier elimination : " << q << std::endl;
289
385
          qa.d_quant_elim = true;
290
          //don't set owner, should happen naturally
291
        }
292
10479
        if( avar.getAttribute(QuantElimPartialAttribute()) ){
293
17
          Trace("quant-attr") << "Attribute : quantifier elimination partial : " << q << std::endl;
294
17
          qa.d_quant_elim = true;
295
17
          qa.d_quant_elim_partial = true;
296
          //don't set owner, should happen naturally
297
        }
298
10479
        if (avar.getAttribute(InternalQuantAttribute()))
299
        {
300
3250
          Trace("quant-attr") << "Attribute : internal : " << q << std::endl;
301
3250
          qa.d_isInternal = true;
302
        }
303
10479
        if( avar.hasAttribute(QuantIdNumAttribute()) ){
304
          qa.d_qid_num = avar;
305
          Trace("quant-attr") << "Attribute : id number " << qa.d_qid_num.getAttribute(QuantIdNumAttribute()) << " : " << q << std::endl;
306
        }
307
      }
308
    }
309
  }
310
193232
}
311
312
820
bool QuantAttributes::isFunDef( Node q ) {
313
820
  std::map< Node, QAttributes >::iterator it = d_qattr.find( q );
314
820
  if( it==d_qattr.end() ){
315
    return false;
316
  }else{
317
820
    return it->second.isFunDef();
318
  }
319
}
320
321
1117
bool QuantAttributes::isSygus( Node q ) {
322
1117
  std::map< Node, QAttributes >::iterator it = d_qattr.find( q );
323
1117
  if( it==d_qattr.end() ){
324
    return false;
325
  }else{
326
1117
    return it->second.d_sygus;
327
  }
328
}
329
330
970
int64_t QuantAttributes::getQuantInstLevel(Node q)
331
{
332
970
  std::map< Node, QAttributes >::iterator it = d_qattr.find( q );
333
970
  if( it==d_qattr.end() ){
334
    return -1;
335
  }else{
336
970
    return it->second.d_qinstLevel;
337
  }
338
}
339
340
bool QuantAttributes::isQuantElim( Node q ) {
341
  std::map< Node, QAttributes >::iterator it = d_qattr.find( q );
342
  if( it==d_qattr.end() ){
343
    return false;
344
  }else{
345
    return it->second.d_quant_elim;
346
  }
347
}
348
349
9895
bool QuantAttributes::isQuantElimPartial( Node q ) {
350
9895
  std::map< Node, QAttributes >::iterator it = d_qattr.find( q );
351
9895
  if( it==d_qattr.end() ){
352
    return false;
353
  }else{
354
9895
    return it->second.d_quant_elim_partial;
355
  }
356
}
357
358
67642
bool QuantAttributes::isInternal(Node q) const
359
{
360
67642
  std::map<Node, QAttributes>::const_iterator it = d_qattr.find(q);
361
67642
  if (it != d_qattr.end())
362
  {
363
67642
    return it->second.d_isInternal;
364
  }
365
  return false;
366
}
367
368
34
Node QuantAttributes::getQuantName(Node q) const
369
{
370
34
  std::map<Node, QAttributes>::const_iterator it = d_qattr.find(q);
371
34
  if (it != d_qattr.end())
372
  {
373
34
    return it->second.d_name;
374
  }
375
  return Node::null();
376
}
377
378
std::string QuantAttributes::quantToString(Node q) const
379
{
380
  std::stringstream ss;
381
  Node name = getQuantName(q);
382
  ss << (name.isNull() ? q : name);
383
  return ss.str();
384
}
385
386
int QuantAttributes::getQuantIdNum( Node q ) {
387
  std::map< Node, QAttributes >::iterator it = d_qattr.find( q );
388
  if( it!=d_qattr.end() ){
389
    if( !it->second.d_qid_num.isNull() ){
390
      return it->second.d_qid_num.getAttribute(QuantIdNumAttribute());
391
    }
392
  }
393
  return -1;
394
}
395
396
Node QuantAttributes::getQuantIdNumNode( Node q ) {
397
  std::map< Node, QAttributes >::iterator it = d_qattr.find( q );
398
  if( it==d_qattr.end() ){
399
    return Node::null();
400
  }else{
401
    return it->second.d_qid_num;
402
  }
403
}
404
405
2835
void QuantAttributes::setInstantiationLevelAttr(Node n, Node qn, uint64_t level)
406
{
407
5670
  Trace("inst-level-debug2") << "IL : " << n << " " << qn << " " << level
408
2835
                             << std::endl;
409
  // if not from the vector of terms we instantiatied
410
2835
  if (qn.getKind() != BOUND_VARIABLE && n != qn)
411
  {
412
    // if this is a new term, without an instantiation level
413
2078
    if (!n.hasAttribute(InstLevelAttribute()))
414
    {
415
      InstLevelAttribute ila;
416
1188
      n.setAttribute(ila, level);
417
2376
      Trace("inst-level-debug") << "Set instantiation level " << n << " to "
418
1188
                                << level << std::endl;
419
1188
      Assert(n.getNumChildren() == qn.getNumChildren());
420
3677
      for (unsigned i = 0; i < n.getNumChildren(); i++)
421
      {
422
2489
        setInstantiationLevelAttr(n[i], qn[i], level);
423
      }
424
    }
425
  }
426
2835
}
427
428
2099
void QuantAttributes::setInstantiationLevelAttr(Node n, uint64_t level)
429
{
430
2099
  if (!n.hasAttribute(InstLevelAttribute()))
431
  {
432
    InstLevelAttribute ila;
433
1104
    n.setAttribute(ila, level);
434
2208
    Trace("inst-level-debug") << "Set instantiation level " << n << " to "
435
1104
                              << level << std::endl;
436
2973
    for (unsigned i = 0; i < n.getNumChildren(); i++)
437
    {
438
1869
      setInstantiationLevelAttr(n[i], level);
439
    }
440
  }
441
2099
}
442
443
}  // namespace quantifiers
444
}  // namespace theory
445
29577
}  // namespace cvc5