GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/builtin/proof_checker.cpp Lines: 169 218 77.5 %
Date: 2021-09-18 Branches: 304 960 31.7 %

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 equality proof checker.
14
 */
15
16
#include "theory/builtin/proof_checker.h"
17
18
#include "expr/skolem_manager.h"
19
#include "smt/env.h"
20
#include "smt/term_formula_removal.h"
21
#include "theory/evaluator.h"
22
#include "theory/rewriter.h"
23
#include "theory/substitutions.h"
24
#include "theory/theory.h"
25
26
using namespace cvc5::kind;
27
28
namespace cvc5 {
29
namespace theory {
30
namespace builtin {
31
32
9940
BuiltinProofRuleChecker::BuiltinProofRuleChecker(Env& env) : d_env(env) {}
33
34
3794
void BuiltinProofRuleChecker::registerTo(ProofChecker* pc)
35
{
36
3794
  pc->registerChecker(PfRule::ASSUME, this);
37
3794
  pc->registerChecker(PfRule::SCOPE, this);
38
3794
  pc->registerChecker(PfRule::SUBS, this);
39
3794
  pc->registerChecker(PfRule::REWRITE, this);
40
3794
  pc->registerChecker(PfRule::EVALUATE, this);
41
3794
  pc->registerChecker(PfRule::MACRO_SR_EQ_INTRO, this);
42
3794
  pc->registerChecker(PfRule::MACRO_SR_PRED_INTRO, this);
43
3794
  pc->registerChecker(PfRule::MACRO_SR_PRED_ELIM, this);
44
3794
  pc->registerChecker(PfRule::MACRO_SR_PRED_TRANSFORM, this);
45
3794
  pc->registerChecker(PfRule::THEORY_REWRITE, this);
46
3794
  pc->registerChecker(PfRule::REMOVE_TERM_FORMULA_AXIOM, this);
47
  // trusted rules
48
3794
  pc->registerTrustedChecker(PfRule::THEORY_LEMMA, this, 1);
49
3794
  pc->registerTrustedChecker(PfRule::PREPROCESS, this, 3);
50
3794
  pc->registerTrustedChecker(PfRule::PREPROCESS_LEMMA, this, 3);
51
3794
  pc->registerTrustedChecker(PfRule::THEORY_PREPROCESS, this, 3);
52
3794
  pc->registerTrustedChecker(PfRule::THEORY_PREPROCESS_LEMMA, this, 3);
53
3794
  pc->registerTrustedChecker(PfRule::THEORY_EXPAND_DEF, this, 3);
54
3794
  pc->registerTrustedChecker(PfRule::WITNESS_AXIOM, this, 3);
55
3794
  pc->registerTrustedChecker(PfRule::TRUST_REWRITE, this, 1);
56
3794
  pc->registerTrustedChecker(PfRule::TRUST_SUBS, this, 1);
57
3794
  pc->registerTrustedChecker(PfRule::TRUST_SUBS_MAP, this, 1);
58
3794
  pc->registerTrustedChecker(PfRule::TRUST_SUBS_EQ, this, 3);
59
3794
  pc->registerTrustedChecker(PfRule::THEORY_INFERENCE, this, 3);
60
3794
}
61
62
1488874
Node BuiltinProofRuleChecker::applySubstitutionRewrite(
63
    Node n,
64
    const std::vector<Node>& exp,
65
    MethodId ids,
66
    MethodId ida,
67
    MethodId idr)
68
{
69
2977748
  Node nks = applySubstitution(n, exp, ids, ida);
70
2977748
  return d_env.getRewriter()->rewriteViaMethod(nks, idr);
71
}
72
73
2994381
bool BuiltinProofRuleChecker::getSubstitutionForLit(Node exp,
74
                                                    TNode& var,
75
                                                    TNode& subs,
76
                                                    MethodId ids)
77
{
78
2994381
  if (ids == MethodId::SB_DEFAULT)
79
  {
80
2978529
    if (exp.getKind() != EQUAL)
81
    {
82
      return false;
83
    }
84
2978529
    var = exp[0];
85
2978529
    subs = exp[1];
86
  }
87
15852
  else if (ids == MethodId::SB_LITERAL)
88
  {
89
15852
    bool polarity = exp.getKind() != NOT;
90
15852
    var = polarity ? exp : exp[0];
91
15852
    subs = NodeManager::currentNM()->mkConst(polarity);
92
  }
93
  else if (ids == MethodId::SB_FORMULA)
94
  {
95
    var = exp;
96
    subs = NodeManager::currentNM()->mkConst(true);
97
  }
98
  else
99
  {
100
    Assert(false) << "BuiltinProofRuleChecker::applySubstitution: no "
101
                     "substitution for "
102
                  << ids << std::endl;
103
    return false;
104
  }
105
2994381
  return true;
106
}
107
108
2994381
bool BuiltinProofRuleChecker::getSubstitutionFor(Node exp,
109
                                                 std::vector<TNode>& vars,
110
                                                 std::vector<TNode>& subs,
111
                                                 std::vector<TNode>& from,
112
                                                 MethodId ids)
113
{
114
5988762
  TNode v;
115
5988762
  TNode s;
116
2994381
  if (exp.getKind() == AND && ids == MethodId::SB_DEFAULT)
117
  {
118
    for (const Node& ec : exp)
119
    {
120
      // non-recursive, do not use nested AND
121
      if (!getSubstitutionForLit(ec, v, s, ids))
122
      {
123
        return false;
124
      }
125
      vars.push_back(v);
126
      subs.push_back(s);
127
      from.push_back(ec);
128
    }
129
    return true;
130
  }
131
2994381
  bool ret = getSubstitutionForLit(exp, v, s, ids);
132
2994381
  vars.push_back(v);
133
2994381
  subs.push_back(s);
134
2994381
  from.push_back(exp);
135
2994381
  return ret;
136
}
137
138
Node BuiltinProofRuleChecker::applySubstitution(Node n,
139
                                                Node exp,
140
                                                MethodId ids,
141
                                                MethodId ida)
142
{
143
  std::vector<Node> expv{exp};
144
  return applySubstitution(n, expv, ids, ida);
145
}
146
147
1511251
Node BuiltinProofRuleChecker::applySubstitution(Node n,
148
                                                const std::vector<Node>& exp,
149
                                                MethodId ids,
150
                                                MethodId ida)
151
{
152
3022502
  std::vector<TNode> vars;
153
3022502
  std::vector<TNode> subs;
154
3022502
  std::vector<TNode> from;
155
3954686
  for (size_t i = 0, nexp = exp.size(); i < nexp; i++)
156
  {
157
2443435
    if (exp[i].isNull())
158
    {
159
      return Node::null();
160
    }
161
2443435
    if (!getSubstitutionFor(exp[i], vars, subs, from, ids))
162
    {
163
      return Node::null();
164
    }
165
  }
166
1511251
  if (ida == MethodId::SBA_SIMUL)
167
  {
168
    // simply apply the simultaneous substitution now
169
    return n.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
170
  }
171
1511251
  else if (ida == MethodId::SBA_FIXPOINT)
172
  {
173
60848
    SubstitutionMap sm;
174
2439409
    for (size_t i = 0, nvars = vars.size(); i < nvars; i++)
175
    {
176
2408985
      sm.addSubstitution(vars[i], subs[i]);
177
    }
178
60848
    Node ns = sm.apply(n);
179
30424
    return ns;
180
  }
181
1480827
  Assert(ida == MethodId::SBA_SEQUENTIAL);
182
  // we prefer n traversals of the term to n^2/2 traversals of range terms
183
2961654
  Node ns = n;
184
1515277
  for (size_t i = 0, nvars = vars.size(); i < nvars; i++)
185
  {
186
68900
    TNode v = vars[(nvars - 1) - i];
187
68900
    TNode s = subs[(nvars - 1) - i];
188
34450
    ns = ns.substitute(v, s);
189
  }
190
1480827
  return ns;
191
}
192
193
1171453
Node BuiltinProofRuleChecker::checkInternal(PfRule id,
194
                                            const std::vector<Node>& children,
195
                                            const std::vector<Node>& args)
196
{
197
1171453
  NodeManager * nm = NodeManager::currentNM();
198
  // compute what was proven
199
1171453
  if (id == PfRule::ASSUME)
200
  {
201
    Assert(children.empty());
202
    Assert(args.size() == 1);
203
    Assert(args[0].getType().isBoolean());
204
    return args[0];
205
  }
206
1171453
  else if (id == PfRule::SCOPE)
207
  {
208
116838
    Assert(children.size() == 1);
209
116838
    if (args.empty())
210
    {
211
      // no antecedant
212
      return children[0];
213
    }
214
233676
    Node ant = nm->mkAnd(args);
215
    // if the conclusion is false, its the negated antencedant only
216
116838
    if (children[0].isConst() && !children[0].getConst<bool>())
217
    {
218
68593
      return ant.notNode();
219
    }
220
48245
    return nm->mkNode(IMPLIES, ant, children[0]);
221
  }
222
1054615
  else if (id == PfRule::SUBS)
223
  {
224
    Assert(children.size() > 0);
225
    Assert(1 <= args.size() && args.size() <= 2);
226
    MethodId ids = MethodId::SB_DEFAULT;
227
    if (args.size() == 2 && !getMethodId(args[1], ids))
228
    {
229
      return Node::null();
230
    }
231
    std::vector<Node> exp;
232
    for (size_t i = 0, nchild = children.size(); i < nchild; i++)
233
    {
234
      exp.push_back(children[i]);
235
    }
236
    Node res = applySubstitution(args[0], exp, ids);
237
    if (res.isNull())
238
    {
239
      return Node::null();
240
    }
241
    return args[0].eqNode(res);
242
  }
243
1054615
  else if (id == PfRule::REWRITE)
244
  {
245
2737
    Assert(children.empty());
246
2737
    Assert(1 <= args.size() && args.size() <= 2);
247
2737
    MethodId idr = MethodId::RW_REWRITE;
248
2737
    if (args.size() == 2 && !getMethodId(args[1], idr))
249
    {
250
      return Node::null();
251
    }
252
5474
    Node res = d_env.getRewriter()->rewriteViaMethod(args[0], idr);
253
2737
    if (res.isNull())
254
    {
255
      return Node::null();
256
    }
257
2737
    return args[0].eqNode(res);
258
  }
259
1051878
  else if (id == PfRule::EVALUATE)
260
  {
261
28345
    Assert(children.empty());
262
28345
    Assert(args.size() == 1);
263
56690
    Node res = d_env.getRewriter()->rewriteViaMethod(args[0], MethodId::RW_EVALUATE);
264
28345
    if (res.isNull())
265
    {
266
      return Node::null();
267
    }
268
28345
    return args[0].eqNode(res);
269
  }
270
1023533
  else if (id == PfRule::MACRO_SR_EQ_INTRO)
271
  {
272
25326
    Assert(1 <= args.size() && args.size() <= 4);
273
    MethodId ids, ida, idr;
274
25326
    if (!getMethodIds(args, ids, ida, idr, 1))
275
    {
276
      return Node::null();
277
    }
278
50652
    Node res = applySubstitutionRewrite(args[0], children, ids, ida, idr);
279
25326
    if (res.isNull())
280
    {
281
      return Node::null();
282
    }
283
25326
    return args[0].eqNode(res);
284
  }
285
998207
  else if (id == PfRule::MACRO_SR_PRED_INTRO)
286
  {
287
19276
    Trace("builtin-pfcheck") << "Check " << id << " " << children.size() << " "
288
9638
                             << args[0] << std::endl;
289
9638
    Assert(1 <= args.size() && args.size() <= 4);
290
    MethodId ids, ida, idr;
291
9638
    if (!getMethodIds(args, ids, ida, idr, 1))
292
    {
293
      return Node::null();
294
    }
295
19276
    Node res = applySubstitutionRewrite(args[0], children, ids, ida, idr);
296
9638
    if (res.isNull())
297
    {
298
      return Node::null();
299
    }
300
9638
    Trace("builtin-pfcheck") << "Result is " << res << std::endl;
301
19276
    Trace("builtin-pfcheck") << "Witness form is "
302
9638
                             << SkolemManager::getOriginalForm(res) << std::endl;
303
    // **** NOTE: can rewrite the witness form here. This enables certain lemmas
304
    // to be provable, e.g. (= k t) where k is a purification Skolem for t.
305
9638
    res = Rewriter::rewrite(SkolemManager::getOriginalForm(res));
306
9638
    if (!res.isConst() || !res.getConst<bool>())
307
    {
308
4
      Trace("builtin-pfcheck")
309
2
          << "Failed to rewrite to true, res=" << res << std::endl;
310
2
      return Node::null();
311
    }
312
9636
    Trace("builtin-pfcheck") << "...success" << std::endl;
313
9636
    return args[0];
314
  }
315
988569
  else if (id == PfRule::MACRO_SR_PRED_ELIM)
316
  {
317
1272
    Trace("builtin-pfcheck") << "Check " << id << " " << children.size() << " "
318
636
                             << args.size() << std::endl;
319
636
    Assert(children.size() >= 1);
320
636
    Assert(args.size() <= 3);
321
1272
    std::vector<Node> exp;
322
636
    exp.insert(exp.end(), children.begin() + 1, children.end());
323
    MethodId ids, ida, idr;
324
636
    if (!getMethodIds(args, ids, ida, idr, 0))
325
    {
326
      return Node::null();
327
    }
328
1272
    Node res1 = applySubstitutionRewrite(children[0], exp, ids, ida, idr);
329
636
    Trace("builtin-pfcheck") << "Returned " << res1 << std::endl;
330
636
    return res1;
331
  }
332
987933
  else if (id == PfRule::MACRO_SR_PRED_TRANSFORM)
333
  {
334
1453274
    Trace("builtin-pfcheck") << "Check " << id << " " << children.size() << " "
335
726637
                             << args.size() << std::endl;
336
726637
    Assert(children.size() >= 1);
337
726637
    Assert(1 <= args.size() && args.size() <= 4);
338
726637
    Assert(args[0].getType().isBoolean());
339
    MethodId ids, ida, idr;
340
726637
    if (!getMethodIds(args, ids, ida, idr, 1))
341
    {
342
      return Node::null();
343
    }
344
1453274
    std::vector<Node> exp;
345
726637
    exp.insert(exp.end(), children.begin() + 1, children.end());
346
1453274
    Node res1 = applySubstitutionRewrite(children[0], exp, ids, ida, idr);
347
1453274
    Node res2 = applySubstitutionRewrite(args[0], exp, ids, ida, idr);
348
    // if not already equal, do rewriting
349
726637
    if (res1 != res2)
350
    {
351
      // can rewrite the witness forms
352
798
      res1 = Rewriter::rewrite(SkolemManager::getOriginalForm(res1));
353
798
      res2 = Rewriter::rewrite(SkolemManager::getOriginalForm(res2));
354
798
      if (res1.isNull() || res1 != res2)
355
      {
356
218
        Trace("builtin-pfcheck") << "Failed to match results" << std::endl;
357
218
        Trace("builtin-pfcheck-debug") << res1 << " vs " << res2 << std::endl;
358
218
        return Node::null();
359
      }
360
    }
361
726419
    return args[0];
362
  }
363
261296
  else if (id == PfRule::REMOVE_TERM_FORMULA_AXIOM)
364
  {
365
3232
    Assert(children.empty());
366
3232
    Assert(args.size() == 1);
367
3232
    return RemoveTermFormulas::getAxiomFor(args[0]);
368
  }
369
258064
  else if (id == PfRule::PREPROCESS || id == PfRule::PREPROCESS_LEMMA
370
257182
           || id == PfRule::THEORY_PREPROCESS
371
256176
           || id == PfRule::THEORY_PREPROCESS_LEMMA
372
255957
           || id == PfRule::THEORY_EXPAND_DEF || id == PfRule::WITNESS_AXIOM
373
255944
           || id == PfRule::THEORY_LEMMA || id == PfRule::THEORY_REWRITE
374
2896
           || id == PfRule::TRUST_REWRITE || id == PfRule::TRUST_SUBS
375
2896
           || id == PfRule::TRUST_SUBS_MAP || id == PfRule::TRUST_SUBS_EQ
376
2843
           || id == PfRule::THEORY_INFERENCE)
377
  {
378
    // "trusted" rules
379
258064
    Assert(!args.empty());
380
258064
    Assert(args[0].getType().isBoolean());
381
258064
    return args[0];
382
  }
383
384
  // no rule
385
  return Node::null();
386
}
387
388
109
bool BuiltinProofRuleChecker::getTheoryId(TNode n, TheoryId& tid)
389
{
390
  uint32_t i;
391
109
  if (!getUInt32(n, i))
392
  {
393
    return false;
394
  }
395
109
  tid = static_cast<TheoryId>(i);
396
109
  return true;
397
}
398
399
251235
Node BuiltinProofRuleChecker::mkTheoryIdNode(TheoryId tid)
400
{
401
  return NodeManager::currentNM()->mkConst(
402
251235
      Rational(static_cast<uint32_t>(tid)));
403
}
404
405
}  // namespace builtin
406
}  // namespace theory
407
29574
}  // namespace cvc5