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