GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/skolem_manager.cpp Lines: 162 172 94.2 %
Date: 2021-09-07 Branches: 320 782 40.9 %

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