GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/skolem_manager.cpp Lines: 161 171 94.2 %
Date: 2021-08-14 Branches: 319 781 40.8 %

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 skolem manager class.
14
 */
15
16
#include "expr/skolem_manager.h"
17
18
#include <sstream>
19
20
#include "expr/attribute.h"
21
#include "expr/bound_var_manager.h"
22
#include "expr/node_algorithm.h"
23
24
using namespace cvc5::kind;
25
26
namespace cvc5 {
27
28
// Attributes are global maps from Nodes to data. Thus, note that these could
29
// be implemented as internal maps in SkolemManager.
30
struct WitnessFormAttributeId
31
{
32
};
33
typedef expr::Attribute<WitnessFormAttributeId, Node> WitnessFormAttribute;
34
35
struct SkolemFormAttributeId
36
{
37
};
38
typedef expr::Attribute<SkolemFormAttributeId, Node> SkolemFormAttribute;
39
40
struct OriginalFormAttributeId
41
{
42
};
43
typedef expr::Attribute<OriginalFormAttributeId, Node> OriginalFormAttribute;
44
45
3522
const char* toString(SkolemFunId id)
46
{
47
3522
  switch (id)
48
  {
49
81
    case SkolemFunId::DIV_BY_ZERO: return "DIV_BY_ZERO";
50
73
    case SkolemFunId::INT_DIV_BY_ZERO: return "INT_DIV_BY_ZERO";
51
32
    case SkolemFunId::MOD_BY_ZERO: return "MOD_BY_ZERO";
52
11
    case SkolemFunId::SQRT: return "SQRT";
53
649
    case SkolemFunId::SELECTOR_WRONG: return "SELECTOR_WRONG";
54
2022
    case SkolemFunId::SHARED_SELECTOR: return "SHARED_SELECTOR";
55
23
    case SkolemFunId::SEQ_NTH_OOB: return "SEQ_NTH_OOB";
56
631
    case SkolemFunId::RE_UNFOLD_POS_COMPONENT: return "RE_UNFOLD_POS_COMPONENT";
57
    default: return "?";
58
  }
59
}
60
61
3522
std::ostream& operator<<(std::ostream& out, SkolemFunId id)
62
{
63
3522
  out << toString(id);
64
3522
  return out;
65
}
66
67
4117
Node SkolemManager::mkSkolem(Node v,
68
                             Node pred,
69
                             const std::string& prefix,
70
                             const std::string& comment,
71
                             int flags,
72
                             ProofGenerator* pg)
73
{
74
  // We do not currently insist that pred does not contain witness terms
75
4117
  Assert(v.getKind() == BOUND_VARIABLE);
76
  // make the witness term
77
4117
  NodeManager* nm = NodeManager::currentNM();
78
8234
  Node bvl = nm->mkNode(BOUND_VAR_LIST, v);
79
  // Make the witness term, where notice that pred may contain skolems. We do
80
  // not recursively convert pred to witness form, since witness terms should
81
  // be treated as opaque. Moreover, the use of witness forms leads to
82
  // variable shadowing issues in e.g. skolemization.
83
8234
  Node w = nm->mkNode(WITNESS, bvl, pred);
84
  // store the mapping to proof generator if it exists
85
4117
  if (pg != nullptr)
86
  {
87
    // We cache based on the existential of the original predicate
88
3344
    Node q = nm->mkNode(EXISTS, bvl, pred);
89
    // Notice this may overwrite an existing proof generator. This does not
90
    // matter since either should be able to prove q.
91
1672
    d_gens[q] = pg;
92
  }
93
4117
  Node k = mkSkolemInternal(w, prefix, comment, flags);
94
  // set witness form attribute for k
95
  WitnessFormAttribute wfa;
96
4117
  k.setAttribute(wfa, w);
97
8234
  Trace("sk-manager-skolem")
98
4117
      << "skolem: " << k << " witness " << w << std::endl;
99
8234
  return k;
100
}
101
102
737
Node SkolemManager::mkSkolemize(Node q,
103
                                std::vector<Node>& skolems,
104
                                const std::string& prefix,
105
                                const std::string& comment,
106
                                int flags,
107
                                ProofGenerator* pg)
108
{
109
737
  Trace("sk-manager-debug") << "mkSkolemize " << q << std::endl;
110
737
  Assert(q.getKind() == EXISTS);
111
737
  Node currQ = q;
112
1866
  for (const Node& av : q[0])
113
  {
114
1129
    Assert(currQ.getKind() == EXISTS && av == currQ[0][0]);
115
    // currQ is updated to the result of skolemizing its first variable in
116
    // the method below.
117
2258
    Node sk = skolemize(currQ, currQ, prefix, comment, flags);
118
2258
    Trace("sk-manager-debug")
119
1129
        << "made skolem " << sk << " for " << av << std::endl;
120
1129
    skolems.push_back(sk);
121
  }
122
737
  if (pg != nullptr)
123
  {
124
    // Same as above, this may overwrite an existing proof generator
125
    d_gens[q] = pg;
126
  }
127
737
  Trace("sk-manager-debug") << "...mkSkolemize returns " << currQ << std::endl;
128
737
  return currQ;
129
}
130
131
1129
Node SkolemManager::skolemize(Node q,
132
                              Node& qskolem,
133
                              const std::string& prefix,
134
                              const std::string& comment,
135
                              int flags)
136
{
137
1129
  Assert(q.getKind() == EXISTS);
138
2258
  Node v;
139
2258
  std::vector<Node> ovars;
140
1129
  Trace("sk-manager-debug") << "mkSkolemize..." << std::endl;
141
1129
  NodeManager* nm = NodeManager::currentNM();
142
4853
  for (const Node& av : q[0])
143
  {
144
5982
    if (v.isNull())
145
    {
146
1129
      v = av;
147
1129
      continue;
148
    }
149
3724
    ovars.push_back(av);
150
  }
151
1129
  Assert(!v.isNull());
152
  // make the predicate with one variable stripped off
153
2258
  Node pred = q[1];
154
1129
  Trace("sk-manager-debug") << "make exists predicate" << std::endl;
155
1129
  if (!ovars.empty())
156
  {
157
    // keeps the same variables
158
784
    Node bvl = nm->mkNode(BOUND_VAR_LIST, ovars);
159
    // update the predicate
160
392
    pred = nm->mkNode(EXISTS, bvl, pred);
161
  }
162
1129
  Trace("sk-manager-debug") << "call sub mkSkolem" << std::endl;
163
  // don't use a proof generator, since this may be an intermediate, partially
164
  // skolemized formula.
165
1129
  Node k = mkSkolem(v, pred, prefix, comment, flags, nullptr);
166
1129
  Assert(k.getType() == v.getType());
167
2258
  TNode tv = v;
168
2258
  TNode tk = k;
169
2258
  Trace("sk-manager-debug")
170
1129
      << "qskolem apply " << tv << " -> " << tk << " to " << pred << std::endl;
171
  // the quantified formula with one step of skolemization
172
1129
  qskolem = pred.substitute(tv, tk);
173
1129
  Trace("sk-manager-debug") << "qskolem done substitution" << std::endl;
174
2258
  return k;
175
}
176
177
53851
Node SkolemManager::mkPurifySkolem(Node t,
178
                                   const std::string& prefix,
179
                                   const std::string& comment,
180
                                   int flags)
181
{
182
107702
  Node to = getOriginalForm(t);
183
  // We do not currently insist that to does not contain witness terms
184
185
53851
  Node k = mkSkolemInternal(to, prefix, comment, flags);
186
  // set original form attribute for k
187
  OriginalFormAttribute ofa;
188
53851
  k.setAttribute(ofa, to);
189
190
107702
  Trace("sk-manager-skolem")
191
53851
      << "skolem: " << k << " purify " << to << std::endl;
192
107702
  return k;
193
}
194
195
7474
Node SkolemManager::mkSkolemFunction(SkolemFunId id,
196
                                     TypeNode tn,
197
                                     Node cacheVal,
198
                                     int flags)
199
{
200
14948
  std::tuple<SkolemFunId, TypeNode, Node> key(id, tn, cacheVal);
201
  std::map<std::tuple<SkolemFunId, TypeNode, Node>, Node>::iterator it =
202
7474
      d_skolemFuns.find(key);
203
7474
  if (it == d_skolemFuns.end())
204
  {
205
3522
    NodeManager* nm = NodeManager::currentNM();
206
7044
    std::stringstream ss;
207
3522
    ss << "SKOLEM_FUN_" << id;
208
7044
    Node k = nm->mkSkolem(ss.str(), tn, "an internal skolem function", flags);
209
3522
    d_skolemFuns[key] = k;
210
3522
    d_skolemFunMap[k] = key;
211
3522
    return k;
212
  }
213
3952
  return it->second;
214
}
215
216
818
Node SkolemManager::mkSkolemFunction(SkolemFunId id,
217
                                     TypeNode tn,
218
                                     const std::vector<Node>& cacheVals,
219
                                     int flags)
220
{
221
818
  Assert(cacheVals.size() > 1);
222
1636
  Node cacheVal = NodeManager::currentNM()->mkNode(SEXPR, cacheVals);
223
1636
  return mkSkolemFunction(id, tn, cacheVal, flags);
224
}
225
226
bool SkolemManager::isSkolemFunction(Node k,
227
                                     SkolemFunId& id,
228
                                     Node& cacheVal) const
229
{
230
  std::map<Node, std::tuple<SkolemFunId, TypeNode, Node>>::const_iterator it =
231
      d_skolemFunMap.find(k);
232
  if (it == d_skolemFunMap.end())
233
  {
234
    return false;
235
  }
236
  id = std::get<0>(it->second);
237
  cacheVal = std::get<2>(it->second);
238
  return true;
239
}
240
241
117334
Node SkolemManager::mkDummySkolem(const std::string& prefix,
242
                                  const TypeNode& type,
243
                                  const std::string& comment,
244
                                  int flags)
245
{
246
117334
  return NodeManager::currentNM()->mkSkolem(prefix, type, comment, flags);
247
}
248
249
60
ProofGenerator* SkolemManager::getProofGenerator(Node t) const
250
{
251
60
  std::map<Node, ProofGenerator*>::const_iterator it = d_gens.find(t);
252
60
  if (it != d_gens.end())
253
  {
254
    return it->second;
255
  }
256
60
  return nullptr;
257
}
258
259
1737
Node SkolemManager::getWitnessForm(Node k)
260
{
261
1737
  Assert(k.getKind() == SKOLEM);
262
  // simply look up the witness form for k via an attribute
263
  WitnessFormAttribute wfa;
264
1737
  return k.getAttribute(wfa);
265
}
266
267
233863
Node SkolemManager::getOriginalForm(Node n)
268
{
269
233863
  if (n.isNull())
270
  {
271
3
    return n;
272
  }
273
467720
  Trace("sk-manager-debug")
274
233860
      << "SkolemManager::getOriginalForm " << n << std::endl;
275
  OriginalFormAttribute ofa;
276
233860
  NodeManager* nm = NodeManager::currentNM();
277
467720
  std::unordered_map<TNode, Node> visited;
278
233860
  std::unordered_map<TNode, Node>::iterator it;
279
467720
  std::vector<TNode> visit;
280
467720
  TNode cur;
281
233860
  visit.push_back(n);
282
600282
  do
283
  {
284
834142
    cur = visit.back();
285
834142
    visit.pop_back();
286
834142
    it = visited.find(cur);
287
288
834142
    if (it == visited.end())
289
    {
290
557284
      if (cur.hasAttribute(ofa))
291
      {
292
359740
        visited[cur] = cur.getAttribute(ofa);
293
      }
294
      else
295
      {
296
197544
        visited[cur] = Node::null();
297
197544
        visit.push_back(cur);
298
197544
        if (cur.getMetaKind() == metakind::PARAMETERIZED)
299
        {
300
27435
          visit.push_back(cur.getOperator());
301
        }
302
572847
        for (const Node& cn : cur)
303
        {
304
375303
          visit.push_back(cn);
305
        }
306
      }
307
    }
308
276858
    else if (it->second.isNull())
309
    {
310
395088
      Node ret = cur;
311
197544
      bool childChanged = false;
312
395088
      std::vector<Node> children;
313
197544
      if (cur.getMetaKind() == metakind::PARAMETERIZED)
314
      {
315
27435
        it = visited.find(cur.getOperator());
316
27435
        Assert(it != visited.end());
317
27435
        Assert(!it->second.isNull());
318
27435
        childChanged = childChanged || cur.getOperator() != it->second;
319
27435
        children.push_back(it->second);
320
      }
321
572847
      for (const Node& cn : cur)
322
      {
323
375303
        it = visited.find(cn);
324
375303
        Assert(it != visited.end());
325
375303
        Assert(!it->second.isNull());
326
375303
        childChanged = childChanged || cn != it->second;
327
375303
        children.push_back(it->second);
328
      }
329
197544
      if (childChanged)
330
      {
331
56438
        ret = nm->mkNode(cur.getKind(), children);
332
      }
333
197544
      cur.setAttribute(ofa, ret);
334
197544
      visited[cur] = ret;
335
    }
336
834142
  } while (!visit.empty());
337
233860
  Assert(visited.find(n) != visited.end());
338
233860
  Assert(!visited.find(n)->second.isNull());
339
233860
  Trace("sk-manager-debug") << "..return " << visited[n] << std::endl;
340
233860
  return visited[n];
341
}
342
343
57968
Node SkolemManager::mkSkolemInternal(Node w,
344
                                     const std::string& prefix,
345
                                     const std::string& comment,
346
                                     int flags)
347
{
348
  // note that witness, original forms are independent, but share skolems
349
57968
  NodeManager* nm = NodeManager::currentNM();
350
  // w is not necessarily a witness term
351
  SkolemFormAttribute sfa;
352
115936
  Node k;
353
  // could already have a skolem if we used w already
354
57968
  if (w.hasAttribute(sfa))
355
  {
356
12186
    return w.getAttribute(sfa);
357
  }
358
  // make the new skolem
359
45782
  if (flags & NodeManager::SKOLEM_BOOL_TERM_VAR)
360
  {
361
841
    Assert (w.getType().isBoolean());
362
841
    k = nm->mkBooleanTermVariable();
363
  }
364
  else
365
  {
366
44941
    k = nm->mkSkolem(prefix, w.getType(), comment, flags);
367
  }
368
  // set skolem form attribute for w
369
45782
  w.setAttribute(sfa, k);
370
91564
  Trace("sk-manager") << "SkolemManager::mkSkolem: " << k << " : " << w
371
45782
                      << std::endl;
372
45782
  return k;
373
}
374
375
29340
}  // namespace cvc5