GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_explain.cpp Lines: 157 164 95.7 %
Date: 2021-11-05 Branches: 294 786 37.4 %

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 techniques for sygus explanations.
14
 */
15
16
#include "theory/quantifiers/sygus/sygus_explain.h"
17
18
#include "expr/dtype.h"
19
#include "expr/dtype_cons.h"
20
#include "smt/logic_exception.h"
21
#include "theory/datatypes/sygus_datatype_utils.h"
22
#include "theory/datatypes/theory_datatypes_utils.h"
23
#include "theory/quantifiers/sygus/sygus_invariance.h"
24
#include "theory/quantifiers/sygus/term_database_sygus.h"
25
26
using namespace cvc5::kind;
27
using namespace std;
28
29
namespace cvc5 {
30
namespace theory {
31
namespace quantifiers {
32
33
150567
void TermRecBuild::addTerm(Node n)
34
{
35
150567
  d_term.push_back(n);
36
301134
  std::vector<Node> currc;
37
150567
  d_kind.push_back(n.getKind());
38
150567
  if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
39
  {
40
150485
    currc.push_back(n.getOperator());
41
150485
    d_has_op.push_back(true);
42
  }
43
  else
44
  {
45
82
    d_has_op.push_back(false);
46
  }
47
271682
  for (unsigned i = 0; i < n.getNumChildren(); i++)
48
  {
49
121115
    currc.push_back(n[i]);
50
  }
51
150567
  d_children.push_back(currc);
52
150567
}
53
54
34458
void TermRecBuild::init(Node n)
55
{
56
34458
  Assert(d_term.empty());
57
34458
  addTerm(n);
58
34458
}
59
60
116109
void TermRecBuild::push(unsigned p)
61
{
62
116109
  Assert(!d_term.empty());
63
116109
  unsigned curr = d_term.size() - 1;
64
116109
  Assert(d_pos.size() == curr);
65
116109
  Assert(d_pos.size() + 1 == d_children.size());
66
116109
  Assert(p < d_term[curr].getNumChildren());
67
116109
  addTerm(d_term[curr][p]);
68
116109
  d_pos.push_back(p);
69
116109
}
70
71
116109
void TermRecBuild::pop()
72
{
73
116109
  Assert(!d_pos.empty());
74
116109
  d_pos.pop_back();
75
116109
  d_kind.pop_back();
76
116109
  d_has_op.pop_back();
77
116109
  d_children.pop_back();
78
116109
  d_term.pop_back();
79
116109
}
80
81
237154
void TermRecBuild::replaceChild(unsigned i, Node r)
82
{
83
237154
  Assert(!d_term.empty());
84
237154
  unsigned curr = d_term.size() - 1;
85
237154
  unsigned o = d_has_op[curr] ? 1 : 0;
86
237154
  d_children[curr][i + o] = r;
87
237154
}
88
89
Node TermRecBuild::getChild(unsigned i)
90
{
91
  unsigned curr = d_term.size() - 1;
92
  unsigned o = d_has_op[curr] ? 1 : 0;
93
  return d_children[curr][i + o];
94
}
95
96
201943
Node TermRecBuild::build(unsigned d)
97
{
98
201943
  Assert(d_pos.size() + 1 == d_term.size());
99
201943
  Assert(d < d_term.size());
100
201943
  int p = d < d_pos.size() ? d_pos[d] : -2;
101
403886
  std::vector<Node> children;
102
201943
  unsigned o = d_has_op[d] ? 1 : 0;
103
807729
  for (unsigned i = 0; i < d_children[d].size(); i++)
104
  {
105
1211572
    Node nc;
106
605786
    if (p + o == i)
107
    {
108
80898
      nc = build(d + 1);
109
    }
110
    else
111
    {
112
524888
      nc = d_children[d][i];
113
    }
114
605786
    children.push_back(nc);
115
  }
116
403886
  return NodeManager::currentNM()->mkNode(d_kind[d], children);
117
}
118
119
62621
void SygusExplain::getExplanationForEquality(Node n,
120
                                             Node vn,
121
                                             std::vector<Node>& exp)
122
{
123
125242
  std::map<unsigned, bool> cexc;
124
62621
  getExplanationForEquality(n, vn, exp, cexc);
125
62621
}
126
127
62946
void SygusExplain::getExplanationForEquality(Node n,
128
                                             Node vn,
129
                                             std::vector<Node>& exp,
130
                                             std::map<unsigned, bool>& cexc)
131
{
132
  // since builtin types occur in grammar, types are comparable but not
133
  // necessarily equal
134
62946
  Assert(n.getType().isComparableTo(n.getType()));
135
62946
  if (n == vn)
136
  {
137
711
    return;
138
  }
139
125181
  TypeNode tn = n.getType();
140
62946
  if (!tn.isDatatype())
141
  {
142
    // sygus datatype fields that are not sygus datatypes are treated as
143
    // abstractions only, hence we disregard this field
144
711
    return;
145
  }
146
62235
  Assert(vn.getKind() == kind::APPLY_CONSTRUCTOR);
147
62235
  const DType& dt = tn.getDType();
148
62235
  int i = datatypes::utils::indexOf(vn.getOperator());
149
124470
  Node tst = datatypes::utils::mkTester(n, i, dt);
150
62235
  exp.push_back(tst);
151
105586
  for (unsigned j = 0; j < vn.getNumChildren(); j++)
152
  {
153
43351
    if (cexc.find(j) == cexc.end())
154
    {
155
      Node sel = NodeManager::currentNM()->mkNode(
156
86702
          kind::APPLY_SELECTOR_TOTAL, dt[i].getSelectorInternal(tn, j), n);
157
43351
      getExplanationForEquality(sel, vn[j], exp);
158
    }
159
  }
160
}
161
162
325
Node SygusExplain::getExplanationForEquality(Node n, Node vn)
163
{
164
650
  std::map<unsigned, bool> cexc;
165
650
  return getExplanationForEquality(n, vn, cexc);
166
}
167
168
325
Node SygusExplain::getExplanationForEquality(Node n,
169
                                             Node vn,
170
                                             std::map<unsigned, bool>& cexc)
171
{
172
650
  std::vector<Node> exp;
173
325
  getExplanationForEquality(n, vn, exp, cexc);
174
325
  Assert(!exp.empty());
175
444
  return exp.size() == 1 ? exp[0]
176
769
                         : NodeManager::currentNM()->mkNode(kind::AND, exp);
177
}
178
179
// we have ( n = vn => eval( n ) = bvr ) ^ vn != vnr , returns exp such that exp
180
// => ( eval( n ) = bvr ^ vn != vnr )
181
150567
void SygusExplain::getExplanationFor(TermRecBuild& trb,
182
                                     Node n,
183
                                     Node vn,
184
                                     std::vector<Node>& exp,
185
                                     std::map<TypeNode, int>& var_count,
186
                                     SygusInvarianceTest& et,
187
                                     Node vnr,
188
                                     Node& vnr_exp,
189
                                     int& sz)
190
{
191
150567
  Assert(vnr.isNull() || vn != vnr);
192
150567
  Assert(n.getType().isComparableTo(vn.getType()));
193
300982
  TypeNode ntn = n.getType();
194
150567
  if (!ntn.isDatatype())
195
  {
196
    // SyGuS datatype fields that are not sygus datatypes are treated as
197
    // abstractions only, hence we disregard this field. It is important
198
    // that users of this method pay special attention to any constants,
199
    // otherwise the explanation n.eqNode(vn) is necessary here. For example,
200
    // any lemma schema that blocks the current value of an enumerator should
201
    // not make any assumptions about the value of the arguments of its any
202
    // constant constructors, since their explanation is not included here.
203
152
    return;
204
  }
205
150415
  Assert(vn.getKind() == APPLY_CONSTRUCTOR);
206
150415
  Assert(vnr.isNull() || vnr.getKind() == APPLY_CONSTRUCTOR);
207
300830
  std::map<unsigned, bool> cexc;
208
  // for each child,
209
  // check whether replacing that child by a fresh variable
210
  // also satisfies the invariance test.
211
271460
  for (unsigned i = 0; i < vn.getNumChildren(); i++)
212
  {
213
242090
    TypeNode xtn = vn[i].getType();
214
242090
    Node x = d_tdb->getFreeVarInc(xtn, var_count);
215
121045
    trb.replaceChild(i, x);
216
242090
    Node nvn = trb.build();
217
121045
    Assert(nvn.getKind() == kind::APPLY_CONSTRUCTOR);
218
121045
    if (et.is_invariant(d_tdb, nvn, x))
219
    {
220
4936
      cexc[i] = true;
221
      // we are tracking term size if positive
222
4936
      if (sz >= 0)
223
      {
224
400
        int s = datatypes::utils::getSygusTermSize(vn[i]);
225
400
        sz = sz - s;
226
      }
227
    }
228
    else
229
    {
230
      // revert
231
116109
      trb.replaceChild(i, vn[i]);
232
    }
233
  }
234
150415
  const DType& dt = ntn.getDType();
235
150415
  int cindex = datatypes::utils::indexOf(vn.getOperator());
236
150415
  Assert(cindex >= 0 && cindex < (int)dt.getNumConstructors());
237
300830
  Node tst = datatypes::utils::mkTester(n, cindex, dt);
238
150415
  exp.push_back(tst);
239
  // if the operator of vn is different than vnr, then disunification obligation
240
  // is met
241
150415
  if (!vnr.isNull())
242
  {
243
7874
    if (vnr.getOperator() != vn.getOperator())
244
    {
245
4424
      vnr = Node::null();
246
4424
      vnr_exp = NodeManager::currentNM()->mkConst(true);
247
    }
248
  }
249
271460
  for (unsigned i = 0; i < vn.getNumChildren(); i++)
250
  {
251
    Node sel = NodeManager::currentNM()->mkNode(
252
242090
        kind::APPLY_SELECTOR_TOTAL, dt[cindex].getSelectorInternal(ntn, i), n);
253
242090
    Node vnr_c = vnr.isNull() ? vnr : (vn[i] == vnr[i] ? Node::null() : vnr[i]);
254
121045
    if (cexc.find(i) == cexc.end())
255
    {
256
116109
      trb.push(i);
257
232218
      Node vnr_exp_c;
258
116109
      getExplanationFor(
259
          trb, sel, vn[i], exp, var_count, et, vnr_c, vnr_exp_c, sz);
260
116109
      trb.pop();
261
116109
      if (!vnr_c.isNull())
262
      {
263
3444
        Assert(!vnr_exp_c.isNull());
264
3444
        if (vnr_exp_c.isConst() || vnr_exp.isNull())
265
        {
266
          // recursively satisfied the disunification obligation
267
3444
          if (vnr_exp_c.isConst())
268
          {
269
            // was successful, don't consider further
270
3444
            vnr = Node::null();
271
          }
272
3444
          vnr_exp = vnr_exp_c;
273
        }
274
      }
275
    }
276
    else
277
    {
278
      // if excluded, we may need to add the explanation for this
279
4936
      if (vnr_exp.isNull() && !vnr_c.isNull())
280
      {
281
8
        vnr_exp = getExplanationForEquality(sel, vnr[i]);
282
      }
283
    }
284
  }
285
}
286
287
void SygusExplain::getExplanationFor(Node n,
288
                                     Node vn,
289
                                     std::vector<Node>& exp,
290
                                     SygusInvarianceTest& et,
291
                                     Node vnr,
292
                                     unsigned& sz)
293
{
294
  std::map<TypeNode, int> var_count;
295
  return getExplanationFor(n, vn, exp, et, vnr, var_count, sz);
296
}
297
298
4432
void SygusExplain::getExplanationFor(Node n,
299
                                     Node vn,
300
                                     std::vector<Node>& exp,
301
                                     SygusInvarianceTest& et,
302
                                     Node vnr,
303
                                     std::map<TypeNode, int>& var_count,
304
                                     unsigned& sz)
305
{
306
  // naive :
307
  // return getExplanationForEquality( n, vn, exp );
308
309
  // set up the recursion object;
310
8864
  TermRecBuild trb;
311
4432
  trb.init(vn);
312
8864
  Node vnr_exp;
313
4432
  int sz_use = sz;
314
4432
  getExplanationFor(trb, n, vn, exp, var_count, et, vnr, vnr_exp, sz_use);
315
4432
  Assert(sz_use >= 0);
316
4432
  sz = sz_use;
317
4432
  Assert(vnr.isNull() || !vnr_exp.isNull());
318
4432
  if (!vnr_exp.isNull() && !vnr_exp.isConst())
319
  {
320
6
    exp.push_back(vnr_exp.negate());
321
  }
322
4432
}
323
324
18051
void SygusExplain::getExplanationFor(Node n,
325
                                     Node vn,
326
                                     std::vector<Node>& exp,
327
                                     SygusInvarianceTest& et,
328
                                     bool strict)
329
{
330
36102
  std::map<TypeNode, int> var_count;
331
18051
  getExplanationFor(n, vn, exp, et, var_count, strict);
332
18051
}
333
334
34854
void SygusExplain::getExplanationFor(Node n,
335
                                     Node vn,
336
                                     std::vector<Node>& exp,
337
                                     SygusInvarianceTest& et,
338
                                     std::map<TypeNode, int>& var_count,
339
                                     bool strict)
340
{
341
34854
  if (!strict)
342
  {
343
    // check if it is invariant over the entire node
344
28778
    TypeNode vtn = vn.getType();
345
28778
    Node x = d_tdb->getFreeVarInc(vtn, var_count);
346
16803
    if (et.is_invariant(d_tdb, x, x))
347
    {
348
4828
      return;
349
    }
350
11975
    var_count[vtn]--;
351
  }
352
30026
  int sz = -1;
353
60052
  TermRecBuild trb;
354
30026
  trb.init(vn);
355
60052
  Node vnr;
356
60052
  Node vnr_exp;
357
30026
  getExplanationFor(trb, n, vn, exp, var_count, et, vnr, vnr_exp, sz);
358
}
359
360
}  // namespace quantifiers
361
}  // namespace theory
362
31125
}  // namespace cvc5