GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/proof/alethe/alethe_post_processor.cpp Lines: 1 427 0.2 %
Date: 2021-11-07 Branches: 2 2101 0.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Hanna Lachnitt, Haniel Barbosa
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
 * The module for processing proof nodes into Alethe proof nodes
14
 */
15
16
#include "proof/alethe/alethe_post_processor.h"
17
18
#include "expr/node_algorithm.h"
19
#include "proof/proof.h"
20
#include "proof/proof_checker.h"
21
#include "proof/proof_node_algorithm.h"
22
#include "theory/builtin/proof_checker.h"
23
#include "util/rational.h"
24
25
namespace cvc5 {
26
27
namespace proof {
28
29
AletheProofPostprocessCallback::AletheProofPostprocessCallback(
30
    ProofNodeManager* pnm, AletheNodeConverter& anc)
31
    : d_pnm(pnm), d_anc(anc)
32
{
33
  NodeManager* nm = NodeManager::currentNM();
34
  d_cl = nm->mkBoundVar("cl", nm->sExprType());
35
}
36
37
bool AletheProofPostprocessCallback::shouldUpdate(std::shared_ptr<ProofNode> pn,
38
                                                  const std::vector<Node>& fa,
39
                                                  bool& continueUpdate)
40
{
41
  return pn->getRule() != PfRule::ALETHE_RULE;
42
}
43
44
bool AletheProofPostprocessCallback::update(Node res,
45
                                            PfRule id,
46
                                            const std::vector<Node>& children,
47
                                            const std::vector<Node>& args,
48
                                            CDProof* cdp,
49
                                            bool& continueUpdate)
50
{
51
  Trace("alethe-proof") << "- Alethe post process callback " << res << " " << id
52
                        << " " << children << " / " << args << std::endl;
53
54
  NodeManager* nm = NodeManager::currentNM();
55
  std::vector<Node> new_args = std::vector<Node>();
56
57
  switch (id)
58
  {
59
    // To keep the original shape of the proof node it is necessary to rederive
60
    // the original conclusion. However, the term that should be printed might
61
    // be different from that conclusion. Thus, it is stored as an additional
62
    // argument in the proof node. Usually, the only difference is an additional
63
    // cl operator or the outmost or operator being replaced by a cl operator.
64
    //
65
    // When steps are added to the proof that have not been there previously,
66
    // it is unwise to add them in the same manner. To illustrate this the
67
    // following counterexample shows the pitfalls of this approach:
68
    //
69
    //  (or a (or b c))   (not a)
70
    // --------------------------- RESOLUTION
71
    //  (or b c)
72
    //
73
    //  is converted into an Alethe proof that should be printed as
74
    //
75
    //  (cl a (or b c))   (cl (not a))
76
    // -------------------------------- RESOLUTION
77
    //  (cl (or b c))
78
    // --------------- OR
79
    //  (cl b c)
80
    //
81
    // Here, (cl (or b c)) and (cl b c) cannot correspond to the same proof node
82
    // (or b c). Thus, we build a new proof node using the kind SEXPR
83
    // that is then printed as (cl (or b c)). We denote this wrapping of a proof
84
    // node by using an extra pair of parenthesis, i.e. ((or b c)) is the proof
85
    // node printed as (cl (or b c)).
86
    //
87
    //
88
    // Some proof rules have a close correspondence in Alethe. There are two
89
    // very frequent patterns that, to avoid repetition, are described here and
90
    // referred to in the comments on the specific proof rules below.
91
    //
92
    // The first pattern, which will be called singleton pattern in the
93
    // following, adds the original proof node F with the corresponding rule R'
94
    // of the Alethe calculus and uses the same premises as the original proof
95
    // node (P1:F1) ... (Pn:Fn). However, the conclusion is printed as (cl F).
96
    //
97
    // This means a cvc5 rule R that looks as follows:
98
    //
99
    //  (P1:F1) ... (Pn:Fn)
100
    // --------------------- R
101
    //  F
102
    //
103
    // is transformed into:
104
    //
105
    //  (P1:F1) ... (Pn:Fn)
106
    // --------------------- R'
107
    //  (cl F)*
108
    //
109
    // * the corresponding proof node is F
110
    //
111
    // The second pattern, which will be called clause pattern in the following,
112
    // has a disjunction (or G1 ... Gn) as conclusion. It also adds the orignal
113
    // proof node (or G1 ... Gn) with the corresponding rule R' of the Alethe
114
    // calculus and uses the same premises as the original proof node (P1:F1)
115
    // ... (Pn:Fn). However, the conclusion is printed as (cl G1 ... Gn), i.e.
116
    // the or is replaced by the cl operator.
117
    //
118
    // This means a cvc5 rule R that looks as follows:
119
    //
120
    //  (P1:F1) ... (Pn:Fn)
121
    // --------------------- R
122
    //  (or G1 ... Gn)
123
    //
124
    // Is transformed into:
125
    //
126
    //  (P1:F1) ... (Pn:Fn)
127
    // --------------------- R'
128
    //  (cl G1 ... Gn)*
129
    //
130
    // * the corresponding proof node is (or G1 ... Gn)
131
    //
132
    //================================================= Core rules
133
    //======================== Assume and Scope
134
    case PfRule::ASSUME:
135
    {
136
      return addAletheStep(AletheRule::ASSUME, res, res, children, {}, *cdp);
137
    }
138
    // See proof_rule.h for documentation on the SCOPE rule. This comment uses
139
    // variable names as introduced there. Since the SCOPE rule originally
140
    // concludes
141
    // (=> (and F1 ... Fn) F) or (not (and F1 ... Fn)) but the ANCHOR rule
142
    // concludes (cl (not F1) ... (not Fn) F), to keep the original shape of the
143
    // proof node it is necessary to rederive the original conclusion. The
144
    // transformation is described below, depending on the form of SCOPE's
145
    // conclusion.
146
    //
147
    // Note that after the original conclusion is rederived the new proof node
148
    // will actually have to be printed, respectively, (cl (=> (and F1 ... Fn)
149
    // F)) or (cl (not (and F1 ... Fn))).
150
    //
151
    // Let (not (and F1 ... Fn))^i denote the repetition of (not (and F1 ...
152
    // Fn)) for i times.
153
    //
154
    // T1:
155
    //
156
    //   P
157
    // ----- ANCHOR    ------- ... ------- AND_POS
158
    //  VP1             VP2_1  ...  VP2_n
159
    // ------------------------------------ RESOLUTION
160
    //               VP2a
161
    // ------------------------------------ REORDER
162
    //  VP2b
163
    // ------ DUPLICATED_LITERALS   ------- IMPLIES_NEG1
164
    //   VP3                          VP4
165
    // ------------------------------------  RESOLUTION    ------- IMPLIES_NEG2
166
    //    VP5                                                VP6
167
    // ----------------------------------------------------------- RESOLUTION
168
    //                               VP7
169
    //
170
    // VP1: (cl (not F1) ... (not Fn) F)
171
    // VP2_i: (cl (not (and F1 ... Fn)) Fi), for i = 1 to n
172
    // VP2a: (cl F (not (and F1 ... Fn))^n)
173
    // VP2b: (cl (not (and F1 ... Fn))^n F)
174
    // VP3: (cl (not (and F1 ... Fn)) F)
175
    // VP4: (cl (=> (and F1 ... Fn) F) (and F1 ... Fn)))
176
    // VP5: (cl (=> (and F1 ... Fn) F) F)
177
    // VP6: (cl (=> (and F1 ... Fn) F) (not F))
178
    // VP7: (cl (=> (and F1 ... Fn) F) (=> (and F1 ... Fn) F))
179
    //
180
    // Note that if n = 1, then the ANCHOR step yields (cl (not F1) F), which is
181
    // the same as VP3. Since VP1 = VP3, the steps for that transformation are
182
    // not generated.
183
    //
184
    //
185
    // If F = false:
186
    //
187
    //                                    --------- IMPLIES_SIMPLIFY
188
    //    T1                                 VP9
189
    // --------- DUPLICATED_LITERALS      --------- EQUIV_1
190
    //    VP8                                VP10
191
    // -------------------------------------------- RESOLUTION
192
    //          (cl (not (and F1 ... Fn)))*
193
    //
194
    // VP8: (cl (=> (and F1 ... Fn))) (cl (not (=> (and F1 ... Fn) false))
195
    //      (not (and F1 ... Fn)))
196
    // VP9: (cl (= (=> (and F1 ... Fn) false) (not (and F1 ... Fn))))
197
    //
198
    //
199
    // Otherwise,
200
    //                T1
201
    //  ------------------------------ DUPLICATED_LITERALS
202
    //   (cl (=> (and F1 ... Fn) F))**
203
    //
204
    //
205
    // *  the corresponding proof node is (not (and F1 ... Fn))
206
    // ** the corresponding proof node is (=> (and F1 ... Fn) F)
207
    case PfRule::SCOPE:
208
    {
209
      bool success = true;
210
211
      // Build vp1
212
      std::vector<Node> negNode{d_cl};
213
      std::vector<Node> sanitized_args;
214
      for (Node arg : args)
215
      {
216
        negNode.push_back(arg.notNode());  // (not F1) ... (not Fn)
217
        sanitized_args.push_back(d_anc.convert(arg));
218
      }
219
      negNode.push_back(children[0]);  // (cl (not F1) ... (not Fn) F)
220
      Node vp1 = nm->mkNode(kind::SEXPR, negNode);
221
      success &= addAletheStep(AletheRule::ANCHOR_SUBPROOF,
222
                               vp1,
223
                               vp1,
224
                               children,
225
                               sanitized_args,
226
                               *cdp);
227
228
      Node andNode, vp3;
229
      if (args.size() == 1)
230
      {
231
        vp3 = vp1;
232
        andNode = args[0];  // F1
233
      }
234
      else
235
      {
236
        // Build vp2i
237
        andNode = nm->mkNode(kind::AND, args);  // (and F1 ... Fn)
238
        std::vector<Node> premisesVP2 = {vp1};
239
        std::vector<Node> notAnd = {d_cl, children[0]};  // cl F
240
        Node vp2_i;
241
        for (size_t i = 0, size = args.size(); i < size; i++)
242
        {
243
          vp2_i = nm->mkNode(kind::SEXPR, d_cl, andNode.notNode(), args[i]);
244
          success &=
245
              addAletheStep(AletheRule::AND_POS, vp2_i, vp2_i, {}, {}, *cdp);
246
          premisesVP2.push_back(vp2_i);
247
          notAnd.push_back(andNode.notNode());  // cl F (not (and F1 ... Fn))^i
248
        }
249
250
        Node vp2a = nm->mkNode(kind::SEXPR, notAnd);
251
        success &= addAletheStep(
252
            AletheRule::RESOLUTION, vp2a, vp2a, premisesVP2, {}, *cdp);
253
254
        notAnd.erase(notAnd.begin() + 1);  //(cl (not (and F1 ... Fn))^n)
255
        notAnd.push_back(children[0]);     //(cl (not (and F1 ... Fn))^n F)
256
        Node vp2b = nm->mkNode(kind::SEXPR, notAnd);
257
        success &=
258
            addAletheStep(AletheRule::REORDER, vp2b, vp2b, {vp2a}, {}, *cdp);
259
260
        vp3 = nm->mkNode(kind::SEXPR, d_cl, andNode.notNode(), children[0]);
261
        success &= addAletheStep(
262
            AletheRule::DUPLICATED_LITERALS, vp3, vp3, {vp2b}, {}, *cdp);
263
      }
264
265
      Node vp8 = nm->mkNode(
266
          kind::SEXPR, d_cl, nm->mkNode(kind::IMPLIES, andNode, children[0]));
267
268
      Node vp4 = nm->mkNode(kind::SEXPR, d_cl, vp8[1], andNode);
269
      success &=
270
          addAletheStep(AletheRule::IMPLIES_NEG1, vp4, vp4, {}, {}, *cdp);
271
272
      Node vp5 = nm->mkNode(kind::SEXPR, d_cl, vp8[1], children[0]);
273
      success &=
274
          addAletheStep(AletheRule::RESOLUTION, vp5, vp5, {vp4, vp3}, {}, *cdp);
275
276
      Node vp6 = nm->mkNode(kind::SEXPR, d_cl, vp8[1], children[0].notNode());
277
      success &=
278
          addAletheStep(AletheRule::IMPLIES_NEG2, vp6, vp6, {}, {}, *cdp);
279
280
      Node vp7 = nm->mkNode(kind::SEXPR, d_cl, vp8[1], vp8[1]);
281
      success &=
282
          addAletheStep(AletheRule::RESOLUTION, vp7, vp7, {vp5, vp6}, {}, *cdp);
283
284
      if (children[0] != nm->mkConst(false))
285
      {
286
        success &= addAletheStep(
287
            AletheRule::DUPLICATED_LITERALS, res, vp8, {vp7}, {}, *cdp);
288
      }
289
      else
290
      {
291
        success &= addAletheStep(
292
            AletheRule::DUPLICATED_LITERALS, vp8, vp8, {vp7}, {}, *cdp);
293
294
        Node vp9 =
295
            nm->mkNode(kind::SEXPR,
296
                       d_cl,
297
                       nm->mkNode(kind::EQUAL, vp8[1], andNode.notNode()));
298
299
        success &=
300
            addAletheStep(AletheRule::IMPLIES_SIMPLIFY, vp9, vp9, {}, {}, *cdp);
301
302
        Node vp10 =
303
            nm->mkNode(kind::SEXPR, d_cl, vp8[1].notNode(), andNode.notNode());
304
        success &=
305
            addAletheStep(AletheRule::EQUIV1, vp10, vp10, {vp9}, {}, *cdp);
306
307
        success &= addAletheStep(AletheRule::RESOLUTION,
308
                                 res,
309
                                 nm->mkNode(kind::SEXPR, d_cl, res),
310
                                 {vp8, vp10},
311
                                 {},
312
                                 *cdp);
313
      }
314
315
      return success;
316
    }
317
    // The rule is translated according to the theory id tid and the outermost
318
    // connective of the first term in the conclusion F, since F always has the
319
    // form (= t1 t2) where t1 is the term being rewritten. This is not an exact
320
    // translation but should work in most cases.
321
    //
322
    // E.g. if F is (= (* 0 d) 0) and tid = THEORY_ARITH, then prod_simplify
323
    // is correctly guessed as the rule.
324
    case PfRule::THEORY_REWRITE:
325
    {
326
      AletheRule vrule = AletheRule::UNDEFINED;
327
      Node t = res[0];
328
329
      theory::TheoryId tid;
330
      if (!theory::builtin::BuiltinProofRuleChecker::getTheoryId(args[1], tid))
331
      {
332
        return addAletheStep(
333
            vrule, res, nm->mkNode(kind::SEXPR, d_cl, res), children, {}, *cdp);
334
      }
335
      switch (tid)
336
      {
337
        case theory::TheoryId::THEORY_BUILTIN:
338
        {
339
          switch (t.getKind())
340
          {
341
            case kind::ITE:
342
            {
343
              vrule = AletheRule::ITE_SIMPLIFY;
344
              break;
345
            }
346
            case kind::EQUAL:
347
            {
348
              vrule = AletheRule::EQ_SIMPLIFY;
349
              break;
350
            }
351
            case kind::AND:
352
            {
353
              vrule = AletheRule::AND_SIMPLIFY;
354
              break;
355
            }
356
            case kind::OR:
357
            {
358
              vrule = AletheRule::OR_SIMPLIFY;
359
              break;
360
            }
361
            case kind::NOT:
362
            {
363
              vrule = AletheRule::NOT_SIMPLIFY;
364
              break;
365
            }
366
            case kind::IMPLIES:
367
            {
368
              vrule = AletheRule::IMPLIES_SIMPLIFY;
369
              break;
370
            }
371
            case kind::WITNESS:
372
            {
373
              vrule = AletheRule::QNT_SIMPLIFY;
374
              break;
375
            }
376
            default:
377
            {
378
              // In this case the rule is undefined
379
            }
380
          }
381
          break;
382
        }
383
        case theory::TheoryId::THEORY_BOOL:
384
        {
385
          vrule = AletheRule::BOOL_SIMPLIFY;
386
          break;
387
        }
388
        case theory::TheoryId::THEORY_UF:
389
        {
390
          if (t.getKind() == kind::EQUAL)
391
          {
392
            // A lot of these seem to be symmetry rules but not all...
393
            vrule = AletheRule::EQUIV_SIMPLIFY;
394
          }
395
          break;
396
        }
397
        case theory::TheoryId::THEORY_ARITH:
398
        {
399
          switch (t.getKind())
400
          {
401
            case kind::DIVISION:
402
            {
403
              vrule = AletheRule::DIV_SIMPLIFY;
404
              break;
405
            }
406
            case kind::PRODUCT:
407
            {
408
              vrule = AletheRule::PROD_SIMPLIFY;
409
              break;
410
            }
411
            case kind::MINUS:
412
            {
413
              vrule = AletheRule::MINUS_SIMPLIFY;
414
              break;
415
            }
416
            case kind::UMINUS:
417
            {
418
              vrule = AletheRule::UNARY_MINUS_SIMPLIFY;
419
              break;
420
            }
421
            case kind::PLUS:
422
            {
423
              vrule = AletheRule::SUM_SIMPLIFY;
424
              break;
425
            }
426
            case kind::MULT:
427
            {
428
              vrule = AletheRule::PROD_SIMPLIFY;
429
              break;
430
            }
431
            case kind::EQUAL:
432
            {
433
              vrule = AletheRule::EQUIV_SIMPLIFY;
434
              break;
435
            }
436
            case kind::LT:
437
            {
438
              [[fallthrough]];
439
            }
440
            case kind::GT:
441
            {
442
              [[fallthrough]];
443
            }
444
            case kind::GEQ:
445
            {
446
              [[fallthrough]];
447
            }
448
            case kind::LEQ:
449
            {
450
              vrule = AletheRule::COMP_SIMPLIFY;
451
              break;
452
            }
453
            case kind::CAST_TO_REAL:
454
            {
455
              return addAletheStep(AletheRule::LA_GENERIC,
456
                                   res,
457
                                   nm->mkNode(kind::SEXPR, d_cl, res),
458
                                   children,
459
                                   {nm->mkConst(Rational(1))},
460
                                   *cdp);
461
            }
462
            default:
463
            {
464
              // In this case the rule is undefined
465
            }
466
          }
467
          break;
468
        }
469
        case theory::TheoryId::THEORY_QUANTIFIERS:
470
        {
471
          vrule = AletheRule::QUANTIFIER_SIMPLIFY;
472
          break;
473
        }
474
        default:
475
        {
476
          // In this case the rule is undefined
477
        };
478
      }
479
      return addAletheStep(
480
          vrule, res, nm->mkNode(kind::SEXPR, d_cl, res), children, {}, *cdp);
481
    }
482
    // ======== Resolution and N-ary Resolution
483
    // See proof_rule.h for documentation on the RESOLUTION and CHAIN_RESOLUTION
484
    // rule. This comment uses variable names as introduced there.
485
    //
486
    // Because the RESOLUTION rule is merely a special case of CHAIN_RESOLUTION,
487
    // the same translation can be used for both.
488
    //
489
    // The main complication for the translation is that in the case the
490
    // conclusion C is (or G1 ... Gn), the result is ambigous. E.g.,
491
    //
492
    // (cl F1 (or F2 F3))    (cl (not F1))
493
    // -------------------------------------- RESOLUTION
494
    // (cl (or F2 F3))
495
    //
496
    // (cl F1 F2 F3)         (cl (not F1))
497
    // -------------------------------------- RESOLUTION
498
    // (cl F2 F3)
499
    //
500
    // both (cl (or F2 F3)) and (cl F2 F3) correspond to the same proof node (or
501
    // F2 F3). One way to deal with this issue is for the translation to keep
502
    // track of the current clause generated after each resolution (the
503
    // resolvent) and then compare it to the result. E.g. in the first case
504
    // current_resolvent = {(or F2 F3)} indicates that the result is a singleton
505
    // clause, while in the second current_resolvent = {F2,F3}, indicating the
506
    // result is a non-singleton clause.
507
    //
508
    // It is always clear what clauses to add to current_resolvent, except for
509
    // when a child is an assumption or the result of an equality resolution
510
    // step. In these cases it might be necessary to add an additional or step.
511
    //
512
    // If for any Ci, rule(Ci) = ASSUME or rule(Ci) = EQ_RESOLVE and Ci = (or F1
513
    // ... Fn) and Ci != L_{i-1} (for C1, C1 != L_1) then:
514
    //
515
    //        (Pi:Ci)
516
    // ---------------------- OR
517
    //  (VPi:(cl F1 ... Fn))
518
    //
519
    // Otherwise VPi = Ci.
520
    //
521
    // However to determine whether C is a singleton clause or not it is not
522
    // necessary to calculate the complete current resolvent. Instead it
523
    // suffices to find the last introduction of the conclusion as a subterm of
524
    // a child and then check if it is eliminated by a later resolution step. If
525
    // the conclusion was not introduced as a subterm it has to be a
526
    // non-singleton clause. If it was introduced but not eliminated, it follows
527
    // that it is indeed not a singleton clause and should be printed as (cl F1
528
    // ... Fn) instead of (cl (or F1 ... Fn)).
529
    //
530
    // This procedure is possible since the proof is already structured in a
531
    // certain way. It can never contain a second occurrence of a literal when
532
    // the first occurrence we found was eliminated from the proof. E.g.,
533
    //
534
    // (cl (not (or a b)))   (cl (or a b) (or a b))
535
    // ---------------------------------------------
536
    //                 (cl (or a b))
537
    //
538
    // is not possible because of the semantics of CHAIN_RESOLUTION, which only
539
    // removes one occurence of the resolvent in the resolving clauses.
540
    //
541
    //
542
    // If C = (or F1 ... Fn) is a non-singleton clause, then:
543
    //
544
    //   VP1 ... VPn
545
    // ------------------ RESOLUTION
546
    //  (cl F1 ... Fn)*
547
    //
548
    // Else if, C = false:
549
    //
550
    //   VP1 ... VPn
551
    // ------------------ RESOLUTION
552
    //       (cl)*
553
    //
554
    // Otherwise:
555
    //
556
    //   VP1 ... VPn
557
    // ------------------ RESOLUTION
558
    //      (cl C)*
559
    //
560
    //  * the corresponding proof node is C
561
    case PfRule::RESOLUTION:
562
    case PfRule::CHAIN_RESOLUTION:
563
    {
564
      Node trueNode = nm->mkConst(true);
565
      Node falseNode = nm->mkConst(false);
566
      std::vector<Node> new_children = children;
567
568
      // If a child F = (or F1 ... Fn) is the result of ASSUME or
569
      // EQ_RESOLVE it might be necessary to add an additional step with the
570
      // Alethe or rule since otherwise it will be used as (cl (or F1 ... Fn)).
571
572
      // The first child is used as a non-singleton clause if it is not equal
573
      // to its pivot L_1. Since it's the first clause in the resolution it can
574
      // only be equal to the pivot in the case the polarity is true.
575
      if (children[0].getKind() == kind::OR
576
          && (args[0] != trueNode || children[0] != args[1]))
577
      {
578
        std::shared_ptr<ProofNode> childPf = cdp->getProofFor(children[0]);
579
        if (childPf->getRule() == PfRule::ASSUME
580
            || childPf->getRule() == PfRule::EQ_RESOLVE)
581
        {
582
          // Add or step
583
          std::vector<Node> subterms{d_cl};
584
          subterms.insert(
585
              subterms.end(), children[0].begin(), children[0].end());
586
          Node conclusion = nm->mkNode(kind::SEXPR, subterms);
587
          addAletheStep(
588
              AletheRule::OR, conclusion, conclusion, {children[0]}, {}, *cdp);
589
          new_children[0] = conclusion;
590
        }
591
      }
592
593
      // For all other children C_i the procedure is similar. There is however a
594
      // key difference in the choice of the pivot element which is now the
595
      // L_{i-1}, i.e. the pivot of the child with the result of the i-1
596
      // resolution steps between the children before it. Therefore, if the
597
      // policy id_{i-1} is true, the pivot has to appear negated in the child
598
      // in which case it should not be a (cl (or F1 ... Fn)) node. The same is
599
      // true if it isn't the pivot element.
600
      for (std::size_t i = 1, size = children.size(); i < size; ++i)
601
      {
602
        if (children[i].getKind() == kind::OR
603
            && (args[2 * (i - 1)] != falseNode
604
                || args[2 * (i - 1) + 1] != children[i]))
605
        {
606
          std::shared_ptr<ProofNode> childPf = cdp->getProofFor(children[i]);
607
          if (childPf->getRule() == PfRule::ASSUME
608
              || childPf->getRule() == PfRule::EQ_RESOLVE)
609
          {
610
            // Add or step
611
            std::vector<Node> lits{d_cl};
612
            lits.insert(lits.end(), children[i].begin(), children[i].end());
613
            Node conclusion = nm->mkNode(kind::SEXPR, lits);
614
            addAletheStep(AletheRule::OR,
615
                          conclusion,
616
                          conclusion,
617
                          {children[i]},
618
                          {},
619
                          *cdp);
620
            new_children[i] = conclusion;
621
          }
622
        }
623
      }
624
625
      if (!expr::isSingletonClause(res, children, args))
626
      {
627
        return addAletheStepFromOr(
628
            AletheRule::RESOLUTION, res, new_children, {}, *cdp);
629
      }
630
      return addAletheStep(AletheRule::RESOLUTION,
631
                           res,
632
                           res == falseNode
633
                               ? nm->mkNode(kind::SEXPR, d_cl)
634
                               : nm->mkNode(kind::SEXPR, d_cl, res),
635
                           new_children,
636
                           {},
637
                           *cdp);
638
    }
639
    // ======== Factoring
640
    // See proof_rule.h for documentation on the FACTORING rule. This comment
641
    // uses variable names as introduced there.
642
    //
643
    // If C2 = (or F1 ... Fn) but C1 != (or C2 ... C2), then VC2 = (cl F1 ...
644
    // Fn) Otherwise, VC2 = (cl C2).
645
    //
646
    //    P
647
    // ------- DUPLICATED_LITERALS
648
    //   VC2*
649
    //
650
    // * the corresponding proof node is C2
651
    case PfRule::FACTORING:
652
    {
653
      if (res.getKind() == kind::OR)
654
      {
655
        for (const Node& child : children[0])
656
        {
657
          if (child != res)
658
          {
659
            return addAletheStepFromOr(
660
                AletheRule::DUPLICATED_LITERALS, res, children, {}, *cdp);
661
          }
662
        }
663
      }
664
      return addAletheStep(AletheRule::DUPLICATED_LITERALS,
665
                           res,
666
                           nm->mkNode(kind::SEXPR, d_cl, res),
667
                           children,
668
                           {},
669
                           *cdp);
670
    }
671
    // ======== Split
672
    // See proof_rule.h for documentation on the SPLIT rule. This comment
673
    // uses variable names as introduced there.
674
    //
675
    // --------- NOT_NOT      --------- NOT_NOT
676
    //    VP1                    VP2
677
    // -------------------------------- RESOLUTION
678
    //          (cl F (not F))*
679
    //
680
    // VP1: (cl (not (not (not F))) F)
681
    // VP2: (cl (not (not (not (not F)))) (not F))
682
    //
683
    // * the corresponding proof node is (or F (not F))
684
    case PfRule::SPLIT:
685
    {
686
      Node vp1 = nm->mkNode(
687
          kind::SEXPR, d_cl, args[0].notNode().notNode().notNode(), args[0]);
688
      Node vp2 = nm->mkNode(kind::SEXPR,
689
                              d_cl,
690
                              args[0].notNode().notNode().notNode().notNode(),
691
                              args[0].notNode());
692
693
      return addAletheStep(AletheRule::NOT_NOT, vp2, vp2, {}, {}, *cdp)
694
          && addAletheStep(AletheRule::NOT_NOT, vp1, vp1, {}, {}, *cdp)
695
          && addAletheStepFromOr(AletheRule::RESOLUTION, res, {vp1, vp2}, {}, *cdp);
696
    }
697
    // ======== Equality resolution
698
    // See proof_rule.h for documentation on the EQ_RESOLVE rule. This
699
    // comment uses variable names as introduced there.
700
    //
701
    // If F1 = (or G1 ... Gn), then P1 will be printed as (cl G1 ... Gn) but
702
    // needs to be printed as (cl (or G1 ... Gn)). The only exception to this
703
    // are ASSUME steps that are always printed as (cl (or G1 ... Gn)) and
704
    // EQ_RESOLVE steps themselves.
705
    //
706
    //           ------  ...  ------ OR_NEG
707
    //   P1       VP21   ...   VP2n
708
    //  ---------------------------- RESOLUTION
709
    //              VP3
710
    //  ---------------------------- DUPLICATED_LITERALS
711
    //              VP4
712
    //
713
    //  for i=1 to n, VP2i: (cl (or G1 ... Gn) (not Gi))
714
    //  VP3: (cl (or G1 ... Gn)^n)
715
    //  VP4: (cl (or (G1 ... Gn))
716
    //
717
    //  Let child1 = VP4.
718
    //
719
    //
720
    // Otherwise, child1 = P1.
721
    //
722
    //
723
    // Then, if F2 = false:
724
    //
725
    //  ------ EQUIV_POS2
726
    //   VP1                P2    child1
727
    //  --------------------------------- RESOLUTION
728
    //                (cl)*
729
    //
730
    // Otherwise:
731
    //
732
    //  ------ EQUIV_POS2
733
    //   VP1                P2    child1
734
    //  --------------------------------- RESOLUTION
735
    //              (cl F2)*
736
    //
737
    // VP1: (cl (not (= F1 F2)) (not F1) F2)
738
    //
739
    // * the corresponding proof node is F2
740
    case PfRule::EQ_RESOLVE:
741
    {
742
      bool success = true;
743
      Node vp1 =
744
          nm->mkNode(kind::SEXPR,
745
                     {d_cl, children[1].notNode(), children[0].notNode(), res});
746
      Node child1 = children[0];
747
748
      // Transform (cl F1 ... Fn) into (cl (or F1 ... Fn))
749
      if (children[0].notNode() != children[1].notNode()
750
          && children[0].getKind() == kind::OR)
751
      {
752
        PfRule pr = cdp->getProofFor(child1)->getRule();
753
        if (pr != PfRule::ASSUME && pr != PfRule::EQ_RESOLVE)
754
        {
755
          std::vector<Node> clauses{d_cl};
756
          clauses.insert(clauses.end(),
757
                         children[0].begin(),
758
                         children[0].end());  //(cl G1 ... Gn)
759
760
          std::vector<Node> vp2Nodes{children[0]};
761
          std::vector<Node> resNodes{d_cl};
762
          for (size_t i = 0, size = children[0].getNumChildren(); i < size; i++)
763
          {
764
            Node vp2i = nm->mkNode(
765
                kind::SEXPR,
766
                d_cl,
767
                children[0],
768
                children[0][i].notNode());  //(cl (or G1 ... Gn) (not Gi))
769
            success &=
770
                addAletheStep(AletheRule::OR_NEG, vp2i, vp2i, {}, {}, *cdp);
771
            vp2Nodes.push_back(vp2i);
772
            resNodes.push_back(children[0]);
773
          }
774
          Node vp3 = nm->mkNode(kind::SEXPR, resNodes);
775
          success &= addAletheStep(
776
              AletheRule::RESOLUTION, vp3, vp3, vp2Nodes, {}, *cdp);
777
778
          Node vp4 = nm->mkNode(kind::SEXPR, d_cl, children[0]);
779
          success &= addAletheStep(
780
              AletheRule::DUPLICATED_LITERALS, vp4, vp4, {vp3}, {}, *cdp);
781
          child1 = vp4;
782
        }
783
      }
784
785
      success &= addAletheStep(AletheRule::EQUIV_POS2, vp1, vp1, {}, {}, *cdp);
786
787
      return success &= addAletheStep(AletheRule::RESOLUTION,
788
                                      res,
789
                                      res == nm->mkConst(false)
790
                                          ? nm->mkNode(kind::SEXPR, d_cl)
791
                                          : nm->mkNode(kind::SEXPR, d_cl, res),
792
                                      {vp1, children[1], child1},
793
                                      {},
794
                                      *cdp);
795
    }
796
    // ======== Modus ponens
797
    // See proof_rule.h for documentation on the MODUS_PONENS rule. This comment
798
    // uses variable names as introduced there.
799
    //
800
    //     (P2:(=> F1 F2))
801
    // ------------------------ IMPLIES
802
    //  (VP1:(cl (not F1) F2))             (P1:F1)
803
    // -------------------------------------------- RESOLUTION
804
    //                   (cl F2)*
805
    //
806
    // * the corresponding proof node is F2
807
    case PfRule::MODUS_PONENS:
808
    {
809
      Node vp1 = nm->mkNode(kind::SEXPR, d_cl, children[0].notNode(), res);
810
811
      return addAletheStep(
812
                 AletheRule::IMPLIES, vp1, vp1, {children[1]}, {}, *cdp)
813
             && addAletheStep(AletheRule::RESOLUTION,
814
                              res,
815
                              nm->mkNode(kind::SEXPR, d_cl, res),
816
                              {vp1, children[0]},
817
                              {},
818
                              *cdp);
819
    }
820
    // ======== Double negation elimination
821
    // See proof_rule.h for documentation on the NOT_NOT_ELIM rule. This comment
822
    // uses variable names as introduced there.
823
    //
824
    // ---------------------------------- NOT_NOT
825
    //  (VP1:(cl (not (not (not F))) F))           (P:(not (not F)))
826
    // ------------------------------------------------------------- RESOLUTION
827
    //                            (cl F)*
828
    //
829
    // * the corresponding proof node is F
830
    case PfRule::NOT_NOT_ELIM:
831
    {
832
      Node vp1 = nm->mkNode(kind::SEXPR, d_cl, children[0].notNode(), res);
833
834
      return addAletheStep(AletheRule::NOT_NOT, vp1, vp1, {}, {}, *cdp)
835
             && addAletheStep(AletheRule::RESOLUTION,
836
                              res,
837
                              nm->mkNode(kind::SEXPR, d_cl, res),
838
                              {vp1, children[0]},
839
                              {},
840
                              *cdp);
841
    }
842
    // ======== Contradiction
843
    // See proof_rule.h for documentation on the CONTRA rule. This
844
    // comment uses variable names as introduced there.
845
    //
846
    //  P1   P2
847
    // --------- RESOLUTION
848
    //   (cl)*
849
    //
850
    // * the corresponding proof node is false
851
    case PfRule::CONTRA:
852
    {
853
      return addAletheStep(AletheRule::RESOLUTION,
854
                           res,
855
                           nm->mkNode(kind::SEXPR, d_cl),
856
                           children,
857
                           {},
858
                           *cdp);
859
    }
860
    // ======== And elimination
861
    // This rule is translated according to the singleton pattern.
862
    case PfRule::AND_ELIM:
863
    {
864
      return addAletheStep(AletheRule::AND,
865
                           res,
866
                           nm->mkNode(kind::SEXPR, d_cl, res),
867
                           children,
868
                           {},
869
                           *cdp);
870
    }
871
    // ======== And introduction
872
    // See proof_rule.h for documentation on the AND_INTRO rule. This
873
    // comment uses variable names as introduced there.
874
    //
875
    //
876
    // ----- AND_NEG
877
    //  VP1            P1 ... Pn
878
    // -------------------------- RESOLUTION
879
    //   (cl (and F1 ... Fn))*
880
    //
881
    // VP1:(cl (and F1 ... Fn) (not F1) ... (not Fn))
882
    //
883
    // * the corresponding proof node is (and F1 ... Fn)
884
    case PfRule::AND_INTRO:
885
    {
886
      std::vector<Node> neg_Nodes = {d_cl,res};
887
      for (size_t i = 0, size = children.size(); i < size; i++)
888
      {
889
        neg_Nodes.push_back(children[i].notNode());
890
      }
891
      Node vp1 = nm->mkNode(kind::SEXPR, neg_Nodes);
892
893
      std::vector<Node> new_children = {vp1};
894
      new_children.insert(new_children.end(), children.begin(), children.end());
895
896
      return addAletheStep(AletheRule::AND_NEG, vp1, vp1, {}, {}, *cdp)
897
             && addAletheStep(AletheRule::RESOLUTION,
898
                              res,
899
                              nm->mkNode(kind::SEXPR, d_cl, res),
900
                              new_children,
901
                              {},
902
                              *cdp);
903
    }
904
    // ======== Not Or elimination
905
    // This rule is translated according to the singleton pattern.
906
    case PfRule::NOT_OR_ELIM:
907
    {
908
      return addAletheStep(AletheRule::NOT_OR,
909
                           res,
910
                           nm->mkNode(kind::SEXPR, d_cl, res),
911
                           children,
912
                           {},
913
                           *cdp);
914
    }
915
    // ======== Implication elimination
916
    // This rule is translated according to the clause pattern.
917
    case PfRule::IMPLIES_ELIM:
918
    {
919
      return addAletheStepFromOr(AletheRule::IMPLIES, res, children, {}, *cdp);
920
    }
921
    // ======== Not Implication elimination version 1
922
    // This rule is translated according to the singleton pattern.
923
    case PfRule::NOT_IMPLIES_ELIM1:
924
    {
925
      return addAletheStep(AletheRule::NOT_IMPLIES1,
926
                           res,
927
                           nm->mkNode(kind::SEXPR, d_cl, res),
928
                           children,
929
                           {},
930
                           *cdp);
931
    }
932
    // ======== Not Implication elimination version 2
933
    // This rule is translated according to the singleton pattern.
934
    case PfRule::NOT_IMPLIES_ELIM2:
935
    {
936
      return addAletheStep(AletheRule::NOT_IMPLIES2,
937
                           res,
938
                           nm->mkNode(kind::SEXPR, d_cl, res),
939
                           children,
940
                           {},
941
                           *cdp);
942
    }
943
    // ======== Various elimination rules
944
    // The following rules are all translated according to the clause pattern.
945
    case PfRule::EQUIV_ELIM1:
946
    {
947
      return addAletheStepFromOr(AletheRule::EQUIV1, res, children, {}, *cdp);
948
    }
949
    case PfRule::EQUIV_ELIM2:
950
    {
951
      return addAletheStepFromOr(AletheRule::EQUIV2, res, children, {}, *cdp);
952
    }
953
    case PfRule::NOT_EQUIV_ELIM1:
954
    {
955
      return addAletheStepFromOr(
956
          AletheRule::NOT_EQUIV1, res, children, {}, *cdp);
957
    }
958
    case PfRule::NOT_EQUIV_ELIM2:
959
    {
960
      return addAletheStepFromOr(
961
          AletheRule::NOT_EQUIV2, res, children, {}, *cdp);
962
    }
963
    case PfRule::XOR_ELIM1:
964
    {
965
      return addAletheStepFromOr(AletheRule::XOR1, res, children, {}, *cdp);
966
    }
967
    case PfRule::XOR_ELIM2:
968
    {
969
      return addAletheStepFromOr(AletheRule::XOR2, res, children, {}, *cdp);
970
    }
971
    case PfRule::NOT_XOR_ELIM1:
972
    {
973
      return addAletheStepFromOr(AletheRule::NOT_XOR1, res, children, {}, *cdp);
974
    }
975
    case PfRule::NOT_XOR_ELIM2:
976
    {
977
      return addAletheStepFromOr(AletheRule::NOT_XOR2, res, children, {}, *cdp);
978
    }
979
    case PfRule::ITE_ELIM1:
980
    {
981
      return addAletheStepFromOr(AletheRule::ITE2, res, children, {}, *cdp);
982
    }
983
    case PfRule::ITE_ELIM2:
984
    {
985
      return addAletheStepFromOr(AletheRule::ITE1, res, children, {}, *cdp);
986
    }
987
    case PfRule::NOT_ITE_ELIM1:
988
    {
989
      return addAletheStepFromOr(AletheRule::NOT_ITE2, res, children, {}, *cdp);
990
    }
991
    case PfRule::NOT_ITE_ELIM2:
992
    {
993
      return addAletheStepFromOr(AletheRule::NOT_ITE1, res, children, {}, *cdp);
994
    }
995
    //================================================= De Morgan rules
996
    // ======== Not And
997
    // This rule is translated according to the clause pattern.
998
    case PfRule::NOT_AND:
999
    {
1000
      return addAletheStepFromOr(AletheRule::NOT_AND, res, children, {}, *cdp);
1001
    }
1002
1003
    //================================================= CNF rules
1004
    // The following rules are all translated according to the clause pattern.
1005
    case PfRule::CNF_AND_POS:
1006
    {
1007
      return addAletheStepFromOr(AletheRule::AND_POS, res, children, {}, *cdp);
1008
    }
1009
    case PfRule::CNF_AND_NEG:
1010
    {
1011
      return addAletheStepFromOr(AletheRule::AND_NEG, res, children, {}, *cdp);
1012
    }
1013
    case PfRule::CNF_OR_POS:
1014
    {
1015
      return addAletheStepFromOr(AletheRule::OR_POS, res, children, {}, *cdp);
1016
    }
1017
    case PfRule::CNF_OR_NEG:
1018
    {
1019
      return addAletheStepFromOr(AletheRule::OR_NEG, res, children, {}, *cdp);
1020
    }
1021
    case PfRule::CNF_IMPLIES_POS:
1022
    {
1023
      return addAletheStepFromOr(
1024
          AletheRule::IMPLIES_POS, res, children, {}, *cdp);
1025
    }
1026
    case PfRule::CNF_IMPLIES_NEG1:
1027
    {
1028
      return addAletheStepFromOr(
1029
          AletheRule::IMPLIES_NEG1, res, children, {}, *cdp);
1030
    }
1031
    case PfRule::CNF_IMPLIES_NEG2:
1032
    {
1033
      return addAletheStepFromOr(
1034
          AletheRule::IMPLIES_NEG2, res, children, {}, *cdp);
1035
    }
1036
    case PfRule::CNF_EQUIV_POS1:
1037
    {
1038
      return addAletheStepFromOr(
1039
          AletheRule::EQUIV_POS2, res, children, {}, *cdp);
1040
    }
1041
    case PfRule::CNF_EQUIV_POS2:
1042
    {
1043
      return addAletheStepFromOr(
1044
          AletheRule::EQUIV_POS1, res, children, {}, *cdp);
1045
    }
1046
    case PfRule::CNF_EQUIV_NEG1:
1047
    {
1048
      return addAletheStepFromOr(
1049
          AletheRule::EQUIV_NEG2, res, children, {}, *cdp);
1050
    }
1051
    case PfRule::CNF_EQUIV_NEG2:
1052
    {
1053
      return addAletheStepFromOr(
1054
          AletheRule::EQUIV_NEG1, res, children, {}, *cdp);
1055
    }
1056
    case PfRule::CNF_XOR_POS1:
1057
    {
1058
      return addAletheStepFromOr(AletheRule::XOR_POS1, res, children, {}, *cdp);
1059
    }
1060
    case PfRule::CNF_XOR_POS2:
1061
    {
1062
      return addAletheStepFromOr(AletheRule::XOR_POS2, res, children, {}, *cdp);
1063
    }
1064
    case PfRule::CNF_XOR_NEG1:
1065
    {
1066
      return addAletheStepFromOr(AletheRule::XOR_NEG2, res, children, {}, *cdp);
1067
    }
1068
    case PfRule::CNF_XOR_NEG2:
1069
    {
1070
      return addAletheStepFromOr(AletheRule::XOR_NEG1, res, children, {}, *cdp);
1071
    }
1072
    case PfRule::CNF_ITE_POS1:
1073
    {
1074
      return addAletheStepFromOr(AletheRule::ITE_POS2, res, children, {}, *cdp);
1075
    }
1076
    case PfRule::CNF_ITE_POS2:
1077
    {
1078
      return addAletheStepFromOr(AletheRule::ITE_POS1, res, children, {}, *cdp);
1079
    }
1080
    case PfRule::CNF_ITE_NEG1:
1081
    {
1082
      return addAletheStepFromOr(AletheRule::ITE_NEG2, res, children, {}, *cdp);
1083
    }
1084
    case PfRule::CNF_ITE_NEG2:
1085
    {
1086
      return addAletheStepFromOr(AletheRule::ITE_NEG1, res, children, {}, *cdp);
1087
    }
1088
    // ======== CNF ITE Pos version 3
1089
    //
1090
    // ----- ITE_POS1            ----- ITE_POS2
1091
    //  VP1                       VP2
1092
    // ------------------------------- RESOLUTION
1093
    //             VP3
1094
    // ------------------------------- REORDER
1095
    //             VP4
1096
    // ------------------------------- DUPLICATED_LITERALS
1097
    //  (cl (not (ite C F1 F2)) F1 F2)
1098
    //
1099
    // VP1: (cl (not (ite C F1 F2)) C F2)
1100
    // VP2: (cl (not (ite C F1 F2)) (not C) F1)
1101
    // VP3: (cl (not (ite C F1 F2)) F2 (not (ite C F1 F2)) F1)
1102
    // VP4: (cl (not (ite C F1 F2)) (not (ite C F1 F2)) F1 F2)
1103
    //
1104
    // * the corresponding proof node is (or (not (ite C F1 F2)) F1 F2)
1105
    case PfRule::CNF_ITE_POS3:
1106
    {
1107
      Node vp1 = nm->mkNode(kind::SEXPR, {d_cl, res[0], args[0][0], res[2]});
1108
      Node vp2 =
1109
          nm->mkNode(kind::SEXPR, {d_cl, res[0], args[0][0].notNode(), res[1]});
1110
      Node vp3 =
1111
          nm->mkNode(kind::SEXPR, {d_cl, res[0], res[2], res[0], res[1]});
1112
      Node vp4 =
1113
          nm->mkNode(kind::SEXPR, {d_cl, res[0], res[0], res[1], res[2]});
1114
1115
      return addAletheStep(AletheRule::ITE_POS1, vp1, vp1, {}, {}, *cdp)
1116
             && addAletheStep(AletheRule::ITE_POS2, vp2, vp2, {}, {}, *cdp)
1117
             && addAletheStep(
1118
                 AletheRule::RESOLUTION, vp3, vp3, {vp1, vp2}, {}, *cdp)
1119
             && addAletheStep(AletheRule::REORDER, vp4, vp4, {vp3}, {}, *cdp)
1120
             && addAletheStepFromOr(
1121
                 AletheRule::DUPLICATED_LITERALS, res, {vp4}, {}, *cdp);
1122
    }
1123
    // ======== CNF ITE Neg version 3
1124
    //
1125
    // ----- ITE_NEG1            ----- ITE_NEG2
1126
    //  VP1                       VP2
1127
    // ------------------------------- RESOLUTION
1128
    //             VP3
1129
    // ------------------------------- REORDER
1130
    //             VP4
1131
    // ------------------------------- DUPLICATED_LITERALS
1132
    //  (cl (ite C F1 F2) C (not F2))
1133
    //
1134
    // VP1: (cl (ite C F1 F2) C (not F2))
1135
    // VP2: (cl (ite C F1 F2) (not C) (not F1))
1136
    // VP3: (cl (ite C F1 F2) (not F2) (ite C F1 F2) (not F1))
1137
    // VP4: (cl (ite C F1 F2) (ite C F1 F2) (not F1) (not F2))
1138
    //
1139
    // * the corresponding proof node is (or (ite C F1 F2) C (not F2))
1140
    case PfRule::CNF_ITE_NEG3:
1141
    {
1142
      Node vp1 = nm->mkNode(kind::SEXPR, {d_cl, res[0], args[0][0], res[2]});
1143
      Node vp2 =
1144
          nm->mkNode(kind::SEXPR, {d_cl, res[0], args[0][0].notNode(), res[1]});
1145
      Node vp3 =
1146
          nm->mkNode(kind::SEXPR, {d_cl, res[0], res[2], res[0], res[1]});
1147
      Node vp4 =
1148
          nm->mkNode(kind::SEXPR, {d_cl, res[0], res[0], res[1], res[2]});
1149
1150
      return addAletheStep(AletheRule::ITE_NEG1, vp1, vp1, {}, {}, *cdp)
1151
             && addAletheStep(AletheRule::ITE_NEG2, vp2, vp2, {}, {}, *cdp)
1152
             && addAletheStep(
1153
                 AletheRule::RESOLUTION, vp3, vp3, {vp1, vp2}, {}, *cdp)
1154
             && addAletheStep(AletheRule::REORDER, vp4, vp4, {vp3}, {}, *cdp)
1155
             && addAletheStepFromOr(
1156
                 AletheRule::DUPLICATED_LITERALS, res, {vp4}, {}, *cdp);
1157
    }
1158
    default:
1159
    {
1160
      return addAletheStep(AletheRule::UNDEFINED,
1161
                           res,
1162
                           nm->mkNode(kind::SEXPR, d_cl, res),
1163
                           children,
1164
                           args,
1165
                           *cdp);
1166
    }
1167
  }
1168
}
1169
1170
bool AletheProofPostprocessCallback::addAletheStep(
1171
    AletheRule rule,
1172
    Node res,
1173
    Node conclusion,
1174
    const std::vector<Node>& children,
1175
    const std::vector<Node>& args,
1176
    CDProof& cdp)
1177
{
1178
  // delete attributes
1179
  Node sanitized_conclusion = conclusion;
1180
  if (expr::hasClosure(conclusion))
1181
  {
1182
    sanitized_conclusion = d_anc.convert(conclusion);
1183
  }
1184
1185
  std::vector<Node> new_args = std::vector<Node>();
1186
  new_args.push_back(
1187
      NodeManager::currentNM()->mkConst<Rational>(static_cast<unsigned>(rule)));
1188
  new_args.push_back(res);
1189
  new_args.push_back(sanitized_conclusion);
1190
  new_args.insert(new_args.end(), args.begin(), args.end());
1191
  Trace("alethe-proof") << "... add Alethe step " << res << " / " << conclusion
1192
                        << " " << rule << " " << children << " / " << new_args
1193
                        << std::endl;
1194
  return cdp.addStep(res, PfRule::ALETHE_RULE, children, new_args);
1195
}
1196
1197
bool AletheProofPostprocessCallback::addAletheStepFromOr(
1198
    AletheRule rule,
1199
    Node res,
1200
    const std::vector<Node>& children,
1201
    const std::vector<Node>& args,
1202
    CDProof& cdp)
1203
{
1204
  std::vector<Node> subterms = {d_cl};
1205
  subterms.insert(subterms.end(), res.begin(), res.end());
1206
  Node conclusion = NodeManager::currentNM()->mkNode(kind::SEXPR, subterms);
1207
  return addAletheStep(rule, res, conclusion, children, args, cdp);
1208
}
1209
1210
AletheProofPostprocessFinalCallback::AletheProofPostprocessFinalCallback(
1211
    ProofNodeManager* pnm, AletheNodeConverter& anc)
1212
    : d_pnm(pnm), d_anc(anc)
1213
{
1214
  NodeManager* nm = NodeManager::currentNM();
1215
  d_cl = nm->mkBoundVar("cl", nm->sExprType());
1216
}
1217
1218
bool AletheProofPostprocessFinalCallback::shouldUpdate(
1219
    std::shared_ptr<ProofNode> pn,
1220
    const std::vector<Node>& fa,
1221
    bool& continueUpdate)
1222
{
1223
  return false;
1224
}
1225
1226
bool AletheProofPostprocessFinalCallback::update(
1227
    Node res,
1228
    PfRule id,
1229
    const std::vector<Node>& children,
1230
    const std::vector<Node>& args,
1231
    CDProof* cdp,
1232
    bool& continueUpdate)
1233
{
1234
  return true;
1235
}
1236
1237
AletheProofPostprocess::AletheProofPostprocess(ProofNodeManager* pnm,
1238
                                               AletheNodeConverter& anc)
1239
    : d_pnm(pnm), d_cb(d_pnm, anc), d_fcb(d_pnm, anc)
1240
{
1241
}
1242
1243
AletheProofPostprocess::~AletheProofPostprocess() {}
1244
1245
void AletheProofPostprocess::process(std::shared_ptr<ProofNode> pf) {}
1246
1247
}  // namespace proof
1248
1249
31137
}  // namespace cvc5