GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/proof_cnf_stream.cpp Lines: 605 619 97.7 %
Date: 2021-11-05 Branches: 1552 3326 46.7 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Haniel Barbosa, Andrew Reynolds, Tim King
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 the proof-producing CNF stream.
14
 */
15
16
#include "prop/proof_cnf_stream.h"
17
18
#include "options/smt_options.h"
19
#include "prop/minisat/minisat.h"
20
#include "theory/builtin/proof_checker.h"
21
#include "util/rational.h"
22
23
namespace cvc5 {
24
namespace prop {
25
26
5381
ProofCnfStream::ProofCnfStream(context::UserContext* u,
27
                               CnfStream& cnfStream,
28
                               SatProofManager* satPM,
29
5381
                               ProofNodeManager* pnm)
30
    : d_cnfStream(cnfStream),
31
      d_satPM(satPM),
32
      d_proof(pnm, nullptr, u, "ProofCnfStream::LazyCDProof"),
33
5381
      d_blocked(u)
34
{
35
5381
}
36
37
500608
void ProofCnfStream::addBlocked(std::shared_ptr<ProofNode> pfn)
38
{
39
500608
  d_blocked.insert(pfn);
40
500608
}
41
42
832825
bool ProofCnfStream::isBlocked(std::shared_ptr<ProofNode> pfn)
43
{
44
832825
  return d_blocked.contains(pfn);
45
}
46
47
121472
std::shared_ptr<ProofNode> ProofCnfStream::getProofFor(Node f)
48
{
49
121472
  return d_proof.getProofFor(f);
50
}
51
52
648196
bool ProofCnfStream::hasProofFor(Node f)
53
{
54
648196
  return d_proof.hasStep(f) || d_proof.hasGenerator(f);
55
}
56
57
std::string ProofCnfStream::identify() const { return "ProofCnfStream"; }
58
59
609352
void ProofCnfStream::normalizeAndRegister(TNode clauseNode)
60
{
61
1218704
  Node normClauseNode = d_psb.factorReorderElimDoubleNeg(clauseNode);
62
609352
  if (Trace.isOn("cnf") && normClauseNode != clauseNode)
63
  {
64
    Trace("cnf") << push
65
                 << "ProofCnfStream::normalizeAndRegister: steps to normalized "
66
                 << normClauseNode << "\n"
67
                 << pop;
68
  }
69
609352
  d_satPM->registerSatAssumptions({normClauseNode});
70
609352
}
71
72
98297
void ProofCnfStream::convertAndAssert(TNode node,
73
                                      bool negated,
74
                                      bool removable,
75
                                      ProofGenerator* pg)
76
{
77
196594
  Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node
78
196594
               << ", negated = " << (negated ? "true" : "false")
79
98297
               << ", removable = " << (removable ? "true" : "false") << ")\n";
80
98297
  d_cnfStream.d_removable = removable;
81
98297
  if (pg)
82
  {
83
142900
    Trace("cnf") << "ProofCnfStream::convertAndAssert: pg: " << pg->identify()
84
71450
                 << "\n";
85
142900
    Node toJustify = negated ? node.notNode() : static_cast<Node>(node);
86
71450
    d_proof.addLazyStep(toJustify,
87
                        pg,
88
                        PfRule::ASSUME,
89
                        true,
90
                        "ProofCnfStream::convertAndAssert:cnf");
91
  }
92
98297
  convertAndAssert(node, negated);
93
  // process saved steps in buffer
94
98297
  const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps();
95
2408378
  for (const std::pair<Node, ProofStep>& step : steps)
96
  {
97
2310081
    d_proof.addStep(step.first, step.second);
98
  }
99
98297
  d_psb.clear();
100
98297
}
101
102
168539
void ProofCnfStream::convertAndAssert(TNode node, bool negated)
103
{
104
337078
  Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node
105
168539
               << ", negated = " << (negated ? "true" : "false") << ")\n";
106
168539
  switch (node.getKind())
107
  {
108
22372
    case kind::AND: convertAndAssertAnd(node, negated); break;
109
34728
    case kind::OR: convertAndAssertOr(node, negated); break;
110
14
    case kind::XOR: convertAndAssertXor(node, negated); break;
111
19108
    case kind::IMPLIES: convertAndAssertImplies(node, negated); break;
112
7067
    case kind::ITE: convertAndAssertIte(node, negated); break;
113
23065
    case kind::NOT:
114
    {
115
      // track double negation elimination
116
23065
      if (negated)
117
      {
118
616
        d_proof.addStep(node[0], PfRule::NOT_NOT_ELIM, {node.notNode()}, {});
119
1232
        Trace("cnf")
120
616
            << "ProofCnfStream::convertAndAssert: NOT_NOT_ELIM added norm "
121
616
            << node[0] << "\n";
122
      }
123
23065
      convertAndAssert(node[0], !negated);
124
23065
      break;
125
    }
126
36449
    case kind::EQUAL:
127
36449
      if (node[0].getType().isBoolean())
128
      {
129
5830
        convertAndAssertIff(node, negated);
130
5830
        break;
131
      }
132
      CVC5_FALLTHROUGH;
133
    default:
134
    {
135
      // negate
136
112710
      Node nnode = negated ? node.negate() : static_cast<Node>(node);
137
      // Atoms
138
56355
      SatLiteral lit = toCNF(node, negated);
139
56355
      bool added = d_cnfStream.assertClause(nnode, lit);
140
56355
      if (negated && added && nnode != node.notNode())
141
      {
142
        // track double negation elimination
143
        //    (not (not n))
144
        //   -------------- NOT_NOT_ELIM
145
        //        n
146
        d_proof.addStep(nnode, PfRule::NOT_NOT_ELIM, {node.notNode()}, {});
147
        Trace("cnf")
148
            << "ProofCnfStream::convertAndAssert: NOT_NOT_ELIM added norm "
149
            << nnode << "\n";
150
      }
151
56355
      if (added)
152
      {
153
        // note that we do not need to do the normalization here since this is
154
        // not a clause and double negation is tracked in a dedicated manner
155
        // above
156
33598
        d_satPM->registerSatAssumptions({nnode});
157
56355
      }
158
    }
159
  }
160
168539
}
161
162
22372
void ProofCnfStream::convertAndAssertAnd(TNode node, bool negated)
163
{
164
44744
  Trace("cnf") << "ProofCnfStream::convertAndAssertAnd(" << node
165
22372
               << ", negated = " << (negated ? "true" : "false") << ")\n";
166
22372
  Assert(node.getKind() == kind::AND);
167
22372
  if (!negated)
168
  {
169
    // If the node is a conjunction, we handle each conjunct separately
170
5060
    NodeManager* nm = NodeManager::currentNM();
171
51169
    for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i)
172
    {
173
      // Create a proof step for each n_i
174
92218
      Node iNode = nm->mkConst<Rational>(i);
175
46109
      d_proof.addStep(node[i], PfRule::AND_ELIM, {node}, {iNode});
176
92218
      Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: AND_ELIM " << i
177
46109
                   << " added norm " << node[i] << "\n";
178
46109
      convertAndAssert(node[i], false);
179
    }
180
  }
181
  else
182
  {
183
    // If the node is a disjunction, we construct a clause and assert it
184
17312
    unsigned i, size = node.getNumChildren();
185
34624
    SatClause clause(size);
186
173267
    for (i = 0; i < size; ++i)
187
    {
188
155955
      clause[i] = toCNF(node[i], true);
189
    }
190
17312
    bool added = d_cnfStream.assertClause(node.negate(), clause);
191
    // register proof step
192
17312
    if (added)
193
    {
194
34522
      std::vector<Node> disjuncts;
195
173054
      for (i = 0; i < size; ++i)
196
      {
197
155793
        disjuncts.push_back(node[i].notNode());
198
      }
199
34522
      Node clauseNode = NodeManager::currentNM()->mkNode(kind::OR, disjuncts);
200
17261
      d_proof.addStep(clauseNode, PfRule::NOT_AND, {node.notNode()}, {});
201
34522
      Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: NOT_AND added "
202
17261
                   << clauseNode << "\n";
203
17261
      normalizeAndRegister(clauseNode);
204
    }
205
  }
206
22372
}
207
208
34728
void ProofCnfStream::convertAndAssertOr(TNode node, bool negated)
209
{
210
69456
  Trace("cnf") << "ProofCnfStream::convertAndAssertOr(" << node
211
34728
               << ", negated = " << (negated ? "true" : "false") << ")\n";
212
34728
  Assert(node.getKind() == kind::OR);
213
34728
  if (!negated)
214
  {
215
    // If the node is a disjunction, we construct a clause and assert it
216
34590
    unsigned size = node.getNumChildren();
217
69180
    SatClause clause(size);
218
146626
    for (unsigned i = 0; i < size; ++i)
219
    {
220
112036
      clause[i] = toCNF(node[i], false);
221
    }
222
34590
    normalizeAndRegister(node);
223
34590
    d_cnfStream.assertClause(node, clause);
224
  }
225
  else
226
  {
227
    // If the node is a negated disjunction, we handle it as a conjunction of
228
    // the negated arguments
229
138
    NodeManager* nm = NodeManager::currentNM();
230
1008
    for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i)
231
    {
232
      // Create a proof step for each (not n_i)
233
1740
      Node iNode = nm->mkConst<Rational>(i);
234
4350
      d_proof.addStep(
235
3480
          node[i].notNode(), PfRule::NOT_OR_ELIM, {node.notNode()}, {iNode});
236
1740
      Trace("cnf") << "ProofCnfStream::convertAndAssertOr: NOT_OR_ELIM " << i
237
870
                   << " added norm  " << node[i].notNode() << "\n";
238
870
      convertAndAssert(node[i], true);
239
    }
240
  }
241
34728
}
242
243
14
void ProofCnfStream::convertAndAssertXor(TNode node, bool negated)
244
{
245
28
  Trace("cnf") << "ProofCnfStream::convertAndAssertXor(" << node
246
14
               << ", negated = " << (negated ? "true" : "false") << ")\n";
247
14
  if (!negated)
248
  {
249
    // p XOR q
250
12
    SatLiteral p = toCNF(node[0], false);
251
12
    SatLiteral q = toCNF(node[1], false);
252
    bool added;
253
12
    NodeManager* nm = NodeManager::currentNM();
254
    // Construct the clause (~p v ~q)
255
24
    SatClause clause1(2);
256
12
    clause1[0] = ~p;
257
12
    clause1[1] = ~q;
258
12
    added = d_cnfStream.assertClause(node, clause1);
259
12
    if (added)
260
    {
261
      Node clauseNode =
262
22
          nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode());
263
11
      d_proof.addStep(clauseNode, PfRule::XOR_ELIM2, {node}, {});
264
22
      Trace("cnf") << "ProofCnfStream::convertAndAssertXor: XOR_ELIM2 added "
265
11
                   << clauseNode << "\n";
266
11
      normalizeAndRegister(clauseNode);
267
    }
268
    // Construct the clause (p v q)
269
24
    SatClause clause2(2);
270
12
    clause2[0] = p;
271
12
    clause2[1] = q;
272
12
    added = d_cnfStream.assertClause(node, clause2);
273
12
    if (added)
274
    {
275
22
      Node clauseNode = nm->mkNode(kind::OR, node[0], node[1]);
276
11
      d_proof.addStep(clauseNode, PfRule::XOR_ELIM1, {node}, {});
277
22
      Trace("cnf") << "ProofCnfStream::convertAndAssertXor: XOR_ELIM1 added "
278
11
                   << clauseNode << "\n";
279
11
      normalizeAndRegister(clauseNode);
280
    }
281
  }
282
  else
283
  {
284
    // ~(p XOR q) is the same as p <=> q
285
2
    SatLiteral p = toCNF(node[0], false);
286
2
    SatLiteral q = toCNF(node[1], false);
287
    bool added;
288
2
    NodeManager* nm = NodeManager::currentNM();
289
    // Construct the clause ~p v q
290
4
    SatClause clause1(2);
291
2
    clause1[0] = ~p;
292
2
    clause1[1] = q;
293
2
    added = d_cnfStream.assertClause(node.negate(), clause1);
294
2
    if (added)
295
    {
296
4
      Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]);
297
2
      d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM2, {node.notNode()}, {});
298
4
      Trace("cnf")
299
2
          << "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM2 added "
300
2
          << clauseNode << "\n";
301
2
      normalizeAndRegister(clauseNode);
302
    }
303
    // Construct the clause ~q v p
304
4
    SatClause clause2(2);
305
2
    clause2[0] = p;
306
2
    clause2[1] = ~q;
307
2
    added = d_cnfStream.assertClause(node.negate(), clause2);
308
2
    if (added)
309
    {
310
4
      Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode());
311
2
      d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM1, {node.notNode()}, {});
312
4
      Trace("cnf")
313
2
          << "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM1 added "
314
2
          << clauseNode << "\n";
315
2
      normalizeAndRegister(clauseNode);
316
    }
317
  }
318
14
}
319
320
5830
void ProofCnfStream::convertAndAssertIff(TNode node, bool negated)
321
{
322
11660
  Trace("cnf") << "ProofCnfStream::convertAndAssertIff(" << node
323
5830
               << ", negated = " << (negated ? "true" : "false") << ")\n";
324
5830
  if (!negated)
325
  {
326
    // p <=> q
327
5749
    Trace("cnf") << push;
328
5749
    SatLiteral p = toCNF(node[0], false);
329
5749
    SatLiteral q = toCNF(node[1], false);
330
5749
    Trace("cnf") << pop;
331
    bool added;
332
5749
    NodeManager* nm = NodeManager::currentNM();
333
    // Construct the clauses ~p v q
334
11498
    SatClause clause1(2);
335
5749
    clause1[0] = ~p;
336
5749
    clause1[1] = q;
337
5749
    added = d_cnfStream.assertClause(node, clause1);
338
5749
    if (added)
339
    {
340
10144
      Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]);
341
5072
      d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM1, {node}, {});
342
10144
      Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM1 added "
343
5072
                   << clauseNode << "\n";
344
5072
      normalizeAndRegister(clauseNode);
345
    }
346
    // Construct the clauses ~q v p
347
11498
    SatClause clause2(2);
348
5749
    clause2[0] = p;
349
5749
    clause2[1] = ~q;
350
5749
    added = d_cnfStream.assertClause(node, clause2);
351
5749
    if (added)
352
    {
353
9906
      Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode());
354
4953
      d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM2, {node}, {});
355
9906
      Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM2 added "
356
4953
                   << clauseNode << "\n";
357
4953
      normalizeAndRegister(clauseNode);
358
    }
359
  }
360
  else
361
  {
362
    // ~(p <=> q) is the same as p XOR q
363
81
    Trace("cnf") << push;
364
81
    SatLiteral p = toCNF(node[0], false);
365
81
    SatLiteral q = toCNF(node[1], false);
366
81
    Trace("cnf") << pop;
367
    bool added;
368
81
    NodeManager* nm = NodeManager::currentNM();
369
    // Construct the clauses ~p v ~q
370
162
    SatClause clause1(2);
371
81
    clause1[0] = ~p;
372
81
    clause1[1] = ~q;
373
81
    added = d_cnfStream.assertClause(node.negate(), clause1);
374
81
    if (added)
375
    {
376
      Node clauseNode =
377
144
          nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode());
378
144
      d_proof.addStep(
379
72
          clauseNode, PfRule::NOT_EQUIV_ELIM2, {node.notNode()}, {});
380
144
      Trace("cnf")
381
72
          << "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM2 added "
382
72
          << clauseNode << "\n";
383
72
      normalizeAndRegister(clauseNode);
384
    }
385
    // Construct the clauses q v p
386
162
    SatClause clause2(2);
387
81
    clause2[0] = p;
388
81
    clause2[1] = q;
389
81
    added = d_cnfStream.assertClause(node.negate(), clause2);
390
81
    if (added)
391
    {
392
142
      Node clauseNode = nm->mkNode(kind::OR, node[0], node[1]);
393
142
      d_proof.addStep(
394
71
          clauseNode, PfRule::NOT_EQUIV_ELIM1, {node.notNode()}, {});
395
142
      Trace("cnf")
396
71
          << "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM1 added "
397
71
          << clauseNode << "\n";
398
71
      normalizeAndRegister(clauseNode);
399
    }
400
  }
401
5830
}
402
403
19108
void ProofCnfStream::convertAndAssertImplies(TNode node, bool negated)
404
{
405
38216
  Trace("cnf") << "ProofCnfStream::convertAndAssertImplies(" << node
406
19108
               << ", negated = " << (negated ? "true" : "false") << ")\n";
407
19108
  if (!negated)
408
  {
409
    // ~p v q
410
19009
    SatLiteral p = toCNF(node[0], false);
411
19009
    SatLiteral q = toCNF(node[1], false);
412
    // Construct the clause ~p || q
413
38018
    SatClause clause(2);
414
19009
    clause[0] = ~p;
415
19009
    clause[1] = q;
416
19009
    bool added = d_cnfStream.assertClause(node, clause);
417
19009
    if (added)
418
    {
419
      Node clauseNode = NodeManager::currentNM()->mkNode(
420
36118
          kind::OR, node[0].notNode(), node[1]);
421
18059
      d_proof.addStep(clauseNode, PfRule::IMPLIES_ELIM, {node}, {});
422
36118
      Trace("cnf")
423
18059
          << "ProofCnfStream::convertAndAssertImplies: IMPLIES_ELIM added "
424
18059
          << clauseNode << "\n";
425
18059
      normalizeAndRegister(clauseNode);
426
    }
427
  }
428
  else
429
  {
430
    // ~(p => q) is the same as p ^ ~q
431
    // process p
432
99
    convertAndAssert(node[0], false);
433
99
    d_proof.addStep(node[0], PfRule::NOT_IMPLIES_ELIM1, {node.notNode()}, {});
434
198
    Trace("cnf")
435
99
        << "ProofCnfStream::convertAndAssertImplies: NOT_IMPLIES_ELIM1 added "
436
99
        << node[0] << "\n";
437
    // process ~q
438
99
    convertAndAssert(node[1], true);
439
396
    d_proof.addStep(
440
297
        node[1].notNode(), PfRule::NOT_IMPLIES_ELIM2, {node.notNode()}, {});
441
198
    Trace("cnf")
442
99
        << "ProofCnfStream::convertAndAssertImplies: NOT_IMPLIES_ELIM2 added "
443
99
        << node[1].notNode() << "\n";
444
  }
445
19108
}
446
447
7067
void ProofCnfStream::convertAndAssertIte(TNode node, bool negated)
448
{
449
14134
  Trace("cnf") << "ProofCnfStream::convertAndAssertIte(" << node
450
7067
               << ", negated = " << (negated ? "true" : "false") << ")\n";
451
  // ITE(p, q, r)
452
7067
  SatLiteral p = toCNF(node[0], false);
453
7067
  SatLiteral q = toCNF(node[1], negated);
454
7067
  SatLiteral r = toCNF(node[2], negated);
455
  bool added;
456
7067
  NodeManager* nm = NodeManager::currentNM();
457
  // Construct the clauses:
458
  // (~p v q) and (p v r)
459
  //
460
  // Note that below q and r can be used directly because whether they are
461
  // negated has been push to the literal definitions above
462
14134
  Node nnode = negated ? node.negate() : static_cast<Node>(node);
463
  // (~p v q)
464
14134
  SatClause clause1(2);
465
7067
  clause1[0] = ~p;
466
7067
  clause1[1] = q;
467
7067
  added = d_cnfStream.assertClause(nnode, clause1);
468
7067
  if (added)
469
  {
470
    // redo the negation here to avoid silent double negation elimination
471
7016
    if (!negated)
472
    {
473
13214
      Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]);
474
6607
      d_proof.addStep(clauseNode, PfRule::ITE_ELIM1, {node}, {});
475
13214
      Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM1 added "
476
6607
                   << clauseNode << "\n";
477
6607
      normalizeAndRegister(clauseNode);
478
    }
479
    else
480
    {
481
      Node clauseNode =
482
818
          nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode());
483
409
      d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM1, {node.notNode()}, {});
484
818
      Trace("cnf")
485
409
          << "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM1 added "
486
409
          << clauseNode << "\n";
487
409
      normalizeAndRegister(clauseNode);
488
    }
489
  }
490
  // (p v r)
491
14134
  SatClause clause2(2);
492
7067
  clause2[0] = p;
493
7067
  clause2[1] = r;
494
7067
  added = d_cnfStream.assertClause(nnode, clause2);
495
7067
  if (added)
496
  {
497
    // redo the negation here to avoid silent double negation elimination
498
6919
    if (!negated)
499
    {
500
13020
      Node clauseNode = nm->mkNode(kind::OR, node[0], node[2]);
501
6510
      d_proof.addStep(clauseNode, PfRule::ITE_ELIM2, {node}, {});
502
13020
      Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM2 added "
503
6510
                   << clauseNode << "\n";
504
6510
      normalizeAndRegister(clauseNode);
505
    }
506
    else
507
    {
508
818
      Node clauseNode = nm->mkNode(kind::OR, node[0], node[2].notNode());
509
409
      d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM2, {node.notNode()}, {});
510
818
      Trace("cnf")
511
409
          << "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM2 added "
512
409
          << clauseNode << "\n";
513
409
      normalizeAndRegister(clauseNode);
514
    }
515
  }
516
7067
}
517
518
15225
void ProofCnfStream::convertPropagation(TrustNode trn)
519
{
520
30450
  Node proven = trn.getProven();
521
30450
  Trace("cnf") << "ProofCnfStream::convertPropagation: proven explanation"
522
15225
               << proven << "\n";
523
  // If we are not producing proofs in the theory engine there is no need to
524
  // keep track in d_proof of the clausification. We still need however to let
525
  // the SAT proof manager know that this clause is an assumption.
526
15225
  bool proofLogging = trn.getGenerator() != nullptr;
527
15225
  if (proofLogging)
528
  {
529
15225
    Assert(trn.getGenerator()->getProofFor(proven)->isClosed());
530
30450
    Trace("cnf-steps") << proven << " by explainPropagation "
531
15225
                       << trn.identifyGenerator() << std::endl;
532
15225
    d_proof.addLazyStep(proven,
533
                        trn.getGenerator(),
534
                        PfRule::ASSUME,
535
                        true,
536
                        "ProofCnfStream::convertPropagation");
537
  }
538
  // since the propagation is added directly to the SAT solver via theoryProxy,
539
  // do the transformation of the lemma E1 ^ ... ^ En => P into CNF here
540
15225
  NodeManager* nm = NodeManager::currentNM();
541
30450
  Node clauseImpliesElim;
542
15225
  if (proofLogging)
543
  {
544
15225
    clauseImpliesElim = nm->mkNode(kind::OR, proven[0].notNode(), proven[1]);
545
30450
    Trace("cnf") << "ProofCnfStream::convertPropagation: adding "
546
30450
                 << PfRule::IMPLIES_ELIM << " rule to conclude "
547
15225
                 << clauseImpliesElim << "\n";
548
15225
    d_proof.addStep(clauseImpliesElim, PfRule::IMPLIES_ELIM, {proven}, {});
549
  }
550
30450
  Node clauseExp;
551
  // need to eliminate AND
552
15225
  if (proven[0].getKind() == kind::AND)
553
  {
554
28360
    std::vector<Node> disjunctsAndNeg{proven[0]};
555
28360
    std::vector<Node> disjunctsRes;
556
133878
    for (unsigned i = 0, size = proven[0].getNumChildren(); i < size; ++i)
557
    {
558
119698
      disjunctsAndNeg.push_back(proven[0][i].notNode());
559
119698
      disjunctsRes.push_back(proven[0][i].notNode());
560
    }
561
14180
    disjunctsRes.push_back(proven[1]);
562
14180
    clauseExp = nm->mkNode(kind::OR, disjunctsRes);
563
14180
    if (proofLogging)
564
    {
565
      // add proof steps to convert into clause
566
28360
      Node clauseAndNeg = nm->mkNode(kind::OR, disjunctsAndNeg);
567
14180
      d_proof.addStep(clauseAndNeg, PfRule::CNF_AND_NEG, {}, {proven[0]});
568
70900
      d_proof.addStep(clauseExp,
569
                      PfRule::RESOLUTION,
570
                      {clauseAndNeg, clauseImpliesElim},
571
56720
                      {nm->mkConst(true), proven[0]});
572
    }
573
  }
574
  else
575
  {
576
1045
    clauseExp = nm->mkNode(kind::OR, proven[0].notNode(), proven[1]);
577
  }
578
15225
  normalizeAndRegister(clauseExp);
579
  // consume steps
580
15225
  if (proofLogging)
581
  {
582
15225
    const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps();
583
170754
    for (const std::pair<Node, ProofStep>& step : steps)
584
    {
585
155529
      d_proof.addStep(step.first, step.second);
586
    }
587
15225
    d_psb.clear();
588
  }
589
15225
}
590
591
26663
void ProofCnfStream::ensureLiteral(TNode n)
592
{
593
26663
  Trace("cnf") << "ProofCnfStream::ensureLiteral(" << n << ")\n";
594
26663
  if (d_cnfStream.hasLiteral(n))
595
  {
596
25686
    d_cnfStream.ensureMappingForLiteral(n);
597
25686
    return;
598
  }
599
  // remove top level negation. We don't need to track this because it's a
600
  // literal.
601
977
  n = n.getKind() == kind::NOT ? n[0] : n;
602
977
  if (theory::Theory::theoryOf(n) == theory::THEORY_BOOL && !n.isVar())
603
  {
604
    // These are not removable
605
16
    d_cnfStream.d_removable = false;
606
16
    SatLiteral lit = toCNF(n, false);
607
    // Store backward-mappings
608
    // These may already exist
609
16
    d_cnfStream.d_literalToNodeMap.insert_safe(lit, n);
610
16
    d_cnfStream.d_literalToNodeMap.insert_safe(~lit, n.notNode());
611
  }
612
  else
613
  {
614
961
    d_cnfStream.convertAtom(n);
615
  }
616
}
617
618
777092
SatLiteral ProofCnfStream::toCNF(TNode node, bool negated)
619
{
620
1554184
  Trace("cnf") << "toCNF(" << node
621
777092
               << ", negated = " << (negated ? "true" : "false") << ")\n";
622
777092
  SatLiteral lit;
623
  // If the node has already has a literal, return it (maybe negated)
624
777092
  if (d_cnfStream.hasLiteral(node))
625
  {
626
514528
    Trace("cnf") << "toCNF(): already translated\n";
627
514528
    lit = d_cnfStream.getLiteral(node);
628
    // Return the (maybe negated) literal
629
514528
    return !negated ? lit : ~lit;
630
  }
631
632
  // Handle each Boolean operator case
633
262564
  switch (node.getKind())
634
  {
635
46877
    case kind::AND: lit = handleAnd(node); break;
636
30998
    case kind::OR: lit = handleOr(node); break;
637
10749
    case kind::XOR: lit = handleXor(node); break;
638
986
    case kind::IMPLIES: lit = handleImplies(node); break;
639
5887
    case kind::ITE: lit = handleIte(node); break;
640
23142
    case kind::NOT: lit = ~toCNF(node[0]); break;
641
75264
    case kind::EQUAL:
642
200680
      lit = node[0].getType().isBoolean() ? handleIff(node)
643
125416
                                          : d_cnfStream.convertAtom(node);
644
75264
      break;
645
68661
    default:
646
    {
647
68661
      lit = d_cnfStream.convertAtom(node);
648
    }
649
68661
    break;
650
  }
651
  // Return the (maybe negated) literal
652
262564
  return !negated ? lit : ~lit;
653
}
654
655
46877
SatLiteral ProofCnfStream::handleAnd(TNode node)
656
{
657
46877
  Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
658
46877
  Assert(node.getKind() == kind::AND) << "Expecting an AND expression!";
659
46877
  Assert(node.getNumChildren() > 1) << "Expecting more than 1 child!";
660
46877
  Assert(!d_cnfStream.d_removable)
661
      << "Removable clauses cannot contain Boolean structure";
662
46877
  Trace("cnf") << "ProofCnfStream::handleAnd(" << node << ")\n";
663
  // Number of children
664
46877
  unsigned size = node.getNumChildren();
665
  // Transform all the children first (remembering the negation)
666
93754
  SatClause clause(size + 1);
667
228304
  for (unsigned i = 0; i < size; ++i)
668
  {
669
181427
    Trace("cnf") << push;
670
181427
    clause[i] = ~toCNF(node[i]);
671
181427
    Trace("cnf") << pop;
672
  }
673
  // Create literal for the node
674
46877
  SatLiteral lit = d_cnfStream.newLiteral(node);
675
  bool added;
676
46877
  NodeManager* nm = NodeManager::currentNM();
677
  // lit -> (a_1 & a_2 & a_3 & ... & a_n)
678
  // ~lit | (a_1 & a_2 & a_3 & ... & a_n)
679
  // (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n)
680
228304
  for (unsigned i = 0; i < size; ++i)
681
  {
682
181427
    Trace("cnf") << push;
683
181427
    added = d_cnfStream.assertClause(node.negate(), ~lit, ~clause[i]);
684
181427
    Trace("cnf") << pop;
685
181427
    if (added)
686
    {
687
335574
      Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[i]);
688
335574
      Node iNode = nm->mkConst<Rational>(i);
689
167787
      d_proof.addStep(clauseNode, PfRule::CNF_AND_POS, {}, {node, iNode});
690
335574
      Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_POS " << i
691
167787
                   << " added " << clauseNode << "\n";
692
167787
      normalizeAndRegister(clauseNode);
693
    }
694
  }
695
  // lit <- (a_1 & a_2 & a_3 & ... a_n)
696
  // lit | ~(a_1 & a_2 & a_3 & ... & a_n)
697
  // lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n
698
46877
  clause[size] = lit;
699
  // This needs to go last, as the clause might get modified by the SAT solver
700
46877
  Trace("cnf") << push;
701
46877
  added = d_cnfStream.assertClause(node, clause);
702
46877
  Trace("cnf") << pop;
703
46877
  if (added)
704
  {
705
91084
    std::vector<Node> disjuncts{node};
706
222562
    for (unsigned i = 0; i < size; ++i)
707
    {
708
177020
      disjuncts.push_back(node[i].notNode());
709
    }
710
91084
    Node clauseNode = nm->mkNode(kind::OR, disjuncts);
711
45542
    d_proof.addStep(clauseNode, PfRule::CNF_AND_NEG, {}, {node});
712
91084
    Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_NEG added "
713
45542
                 << clauseNode << "\n";
714
45542
    normalizeAndRegister(clauseNode);
715
  }
716
93754
  return lit;
717
}
718
719
30998
SatLiteral ProofCnfStream::handleOr(TNode node)
720
{
721
30998
  Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
722
30998
  Assert(node.getKind() == kind::OR) << "Expecting an OR expression!";
723
30998
  Assert(node.getNumChildren() > 1) << "Expecting more then 1 child!";
724
30998
  Assert(!d_cnfStream.d_removable)
725
      << "Removable clauses can not contain Boolean structure";
726
30998
  Trace("cnf") << "ProofCnfStream::handleOr(" << node << ")\n";
727
  // Number of children
728
30998
  unsigned size = node.getNumChildren();
729
  // Transform all the children first
730
61996
  SatClause clause(size + 1);
731
116897
  for (unsigned i = 0; i < size; ++i)
732
  {
733
85899
    clause[i] = toCNF(node[i]);
734
  }
735
  // Create literal for the node
736
30998
  SatLiteral lit = d_cnfStream.newLiteral(node);
737
  bool added;
738
30998
  NodeManager* nm = NodeManager::currentNM();
739
  // lit <- (a_1 | a_2 | a_3 | ... | a_n)
740
  // lit | ~(a_1 | a_2 | a_3 | ... | a_n)
741
  // (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n)
742
116897
  for (unsigned i = 0; i < size; ++i)
743
  {
744
85899
    added = d_cnfStream.assertClause(node, lit, ~clause[i]);
745
85899
    if (added)
746
    {
747
158146
      Node clauseNode = nm->mkNode(kind::OR, node, node[i].notNode());
748
158146
      Node iNode = nm->mkConst<Rational>(i);
749
79073
      d_proof.addStep(clauseNode, PfRule::CNF_OR_NEG, {}, {node, iNode});
750
158146
      Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_NEG " << i << " added "
751
79073
                   << clauseNode << "\n";
752
79073
      normalizeAndRegister(clauseNode);
753
    }
754
  }
755
  // lit -> (a_1 | a_2 | a_3 | ... | a_n)
756
  // ~lit | a_1 | a_2 | a_3 | ... | a_n
757
30998
  clause[size] = ~lit;
758
  // This needs to go last, as the clause might get modified by the SAT solver
759
30998
  added = d_cnfStream.assertClause(node.negate(), clause);
760
30998
  if (added)
761
  {
762
60244
    std::vector<Node> disjuncts{node.notNode()};
763
113147
    for (unsigned i = 0; i < size; ++i)
764
    {
765
83025
      disjuncts.push_back(node[i]);
766
    }
767
60244
    Node clauseNode = nm->mkNode(kind::OR, disjuncts);
768
30122
    d_proof.addStep(clauseNode, PfRule::CNF_OR_POS, {}, {node});
769
60244
    Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_POS added " << clauseNode
770
30122
                 << "\n";
771
30122
    normalizeAndRegister(clauseNode);
772
  }
773
61996
  return lit;
774
}
775
776
10749
SatLiteral ProofCnfStream::handleXor(TNode node)
777
{
778
10749
  Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
779
10749
  Assert(node.getKind() == kind::XOR) << "Expecting an XOR expression!";
780
10749
  Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!";
781
10749
  Assert(!d_cnfStream.d_removable)
782
      << "Removable clauses can not contain Boolean structure";
783
10749
  Trace("cnf") << "ProofCnfStream::handleXor(" << node << ")\n";
784
10749
  SatLiteral a = toCNF(node[0]);
785
10749
  SatLiteral b = toCNF(node[1]);
786
10749
  SatLiteral lit = d_cnfStream.newLiteral(node);
787
  bool added;
788
10749
  added = d_cnfStream.assertClause(node.negate(), a, b, ~lit);
789
10749
  if (added)
790
  {
791
    Node clauseNode = NodeManager::currentNM()->mkNode(
792
21354
        kind::OR, node.notNode(), node[0], node[1]);
793
10677
    d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS1, {}, {node});
794
21354
    Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS1 added "
795
10677
                 << clauseNode << "\n";
796
10677
    normalizeAndRegister(clauseNode);
797
  }
798
10749
  added = d_cnfStream.assertClause(node.negate(), ~a, ~b, ~lit);
799
10749
  if (added)
800
  {
801
    Node clauseNode = NodeManager::currentNM()->mkNode(
802
21290
        kind::OR, node.notNode(), node[0].notNode(), node[1].notNode());
803
10645
    d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS2, {}, {node});
804
21290
    Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS2 added "
805
10645
                 << clauseNode << "\n";
806
10645
    normalizeAndRegister(clauseNode);
807
  }
808
10749
  added = d_cnfStream.assertClause(node, a, ~b, lit);
809
10749
  if (added)
810
  {
811
    Node clauseNode = NodeManager::currentNM()->mkNode(
812
21276
        kind::OR, node, node[0], node[1].notNode());
813
10638
    d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG2, {}, {node});
814
21276
    Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG2 added "
815
10638
                 << clauseNode << "\n";
816
10638
    normalizeAndRegister(clauseNode);
817
  }
818
10749
  added = d_cnfStream.assertClause(node, ~a, b, lit);
819
10749
  if (added)
820
  {
821
    Node clauseNode = NodeManager::currentNM()->mkNode(
822
21364
        kind::OR, node, node[0].notNode(), node[1]);
823
10682
    d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG1, {}, {node});
824
21364
    Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG1 added "
825
10682
                 << clauseNode << "\n";
826
10682
    normalizeAndRegister(clauseNode);
827
  }
828
10749
  return lit;
829
}
830
831
25112
SatLiteral ProofCnfStream::handleIff(TNode node)
832
{
833
25112
  Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
834
25112
  Assert(node.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!";
835
25112
  Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!";
836
25112
  Trace("cnf") << "handleIff(" << node << ")\n";
837
  // Convert the children to CNF
838
25112
  SatLiteral a = toCNF(node[0]);
839
25112
  SatLiteral b = toCNF(node[1]);
840
  // Create literal for the node
841
25112
  SatLiteral lit = d_cnfStream.newLiteral(node);
842
  bool added;
843
25112
  NodeManager* nm = NodeManager::currentNM();
844
  // lit -> ((a-> b) & (b->a))
845
  // ~lit | ((~a | b) & (~b | a))
846
  // (~a | b | ~lit) & (~b | a | ~lit)
847
25112
  added = d_cnfStream.assertClause(node.negate(), ~a, b, ~lit);
848
25112
  if (added)
849
  {
850
    Node clauseNode =
851
49692
        nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]);
852
24846
    d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS1, {}, {node});
853
49692
    Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS1 added "
854
24846
                 << clauseNode << "\n";
855
24846
    normalizeAndRegister(clauseNode);
856
  }
857
25112
  added = d_cnfStream.assertClause(node.negate(), a, ~b, ~lit);
858
25112
  if (added)
859
  {
860
    Node clauseNode =
861
47918
        nm->mkNode(kind::OR, node.notNode(), node[0], node[1].notNode());
862
23959
    d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS2, {}, {node});
863
47918
    Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS2 added "
864
23959
                 << clauseNode << "\n";
865
23959
    normalizeAndRegister(clauseNode);
866
  }
867
  // (a<->b) -> lit
868
  // ~((a & b) | (~a & ~b)) | lit
869
  // (~(a & b)) & (~(~a & ~b)) | lit
870
  // ((~a | ~b) & (a | b)) | lit
871
  // (~a | ~b | lit) & (a | b | lit)
872
25112
  added = d_cnfStream.assertClause(node, ~a, ~b, lit);
873
25112
  if (added)
874
  {
875
    Node clauseNode =
876
49576
        nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode());
877
24788
    d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG2, {}, {node});
878
49576
    Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG2 added "
879
24788
                 << clauseNode << "\n";
880
24788
    normalizeAndRegister(clauseNode);
881
  }
882
25112
  added = d_cnfStream.assertClause(node, a, b, lit);
883
25112
  if (added)
884
  {
885
48010
    Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[1]);
886
24005
    d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG1, {}, {node});
887
48010
    Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG1 added "
888
24005
                 << clauseNode << "\n";
889
24005
    normalizeAndRegister(clauseNode);
890
  }
891
25112
  return lit;
892
}
893
894
986
SatLiteral ProofCnfStream::handleImplies(TNode node)
895
{
896
986
  Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
897
986
  Assert(node.getKind() == kind::IMPLIES) << "Expecting an IMPLIES expression!";
898
986
  Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!";
899
986
  Assert(!d_cnfStream.d_removable)
900
      << "Removable clauses can not contain Boolean structure";
901
986
  Trace("cnf") << "ProofCnfStream::handleImplies(" << node << ")\n";
902
  // Convert the children to cnf
903
986
  SatLiteral a = toCNF(node[0]);
904
986
  SatLiteral b = toCNF(node[1]);
905
986
  SatLiteral lit = d_cnfStream.newLiteral(node);
906
  bool added;
907
986
  NodeManager* nm = NodeManager::currentNM();
908
  // lit -> (a->b)
909
  // ~lit | ~ a | b
910
986
  added = d_cnfStream.assertClause(node.negate(), ~lit, ~a, b);
911
986
  if (added)
912
  {
913
    Node clauseNode =
914
1952
        nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]);
915
976
    d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_POS, {}, {node});
916
1952
    Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_POS added "
917
976
                 << clauseNode << "\n";
918
976
    normalizeAndRegister(clauseNode);
919
  }
920
  // (a->b) -> lit
921
  // ~(~a | b) | lit
922
  // (a | l) & (~b | l)
923
986
  added = d_cnfStream.assertClause(node, a, lit);
924
986
  if (added)
925
  {
926
1960
    Node clauseNode = nm->mkNode(kind::OR, node, node[0]);
927
980
    d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG1, {}, {node});
928
1960
    Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG1 added "
929
980
                 << clauseNode << "\n";
930
980
    normalizeAndRegister(clauseNode);
931
  }
932
986
  added = d_cnfStream.assertClause(node, ~b, lit);
933
986
  if (added)
934
  {
935
1968
    Node clauseNode = nm->mkNode(kind::OR, node, node[1].notNode());
936
984
    d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG2, {}, {node});
937
1968
    Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG2 added "
938
984
                 << clauseNode << "\n";
939
984
    normalizeAndRegister(clauseNode);
940
  }
941
986
  return lit;
942
}
943
944
5887
SatLiteral ProofCnfStream::handleIte(TNode node)
945
{
946
5887
  Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
947
5887
  Assert(node.getKind() == kind::ITE);
948
5887
  Assert(node.getNumChildren() == 3);
949
5887
  Assert(!d_cnfStream.d_removable)
950
      << "Removable clauses can not contain Boolean structure";
951
11774
  Trace("cnf") << "handleIte(" << node[0] << " " << node[1] << " " << node[2]
952
5887
               << ")\n";
953
5887
  SatLiteral condLit = toCNF(node[0]);
954
5887
  SatLiteral thenLit = toCNF(node[1]);
955
5887
  SatLiteral elseLit = toCNF(node[2]);
956
  // create literal to the node
957
5887
  SatLiteral lit = d_cnfStream.newLiteral(node);
958
  bool added;
959
5887
  NodeManager* nm = NodeManager::currentNM();
960
  // If ITE is true then one of the branches is true and the condition
961
  // implies which one
962
  // lit -> (ite b t e)
963
  // lit -> (t | e) & (b -> t) & (!b -> e)
964
  // lit -> (t | e) & (!b | t) & (b | e)
965
  // (!lit | t | e) & (!lit | !b | t) & (!lit | b | e)
966
5887
  added = d_cnfStream.assertClause(node.negate(), ~lit, thenLit, elseLit);
967
5887
  if (added)
968
  {
969
11682
    Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[1], node[2]);
970
5841
    d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS3, {}, {node});
971
11682
    Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS3 added "
972
5841
                 << clauseNode << "\n";
973
5841
    normalizeAndRegister(clauseNode);
974
  }
975
5887
  added = d_cnfStream.assertClause(node.negate(), ~lit, ~condLit, thenLit);
976
5887
  if (added)
977
  {
978
    Node clauseNode =
979
11522
        nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]);
980
5761
    d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS1, {}, {node});
981
11522
    Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS1 added "
982
5761
                 << clauseNode << "\n";
983
5761
    normalizeAndRegister(clauseNode);
984
  }
985
5887
  added = d_cnfStream.assertClause(node.negate(), ~lit, condLit, elseLit);
986
5887
  if (added)
987
  {
988
11162
    Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[0], node[2]);
989
5581
    d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS2, {}, {node});
990
11162
    Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS2 added "
991
5581
                 << clauseNode << "\n";
992
5581
    normalizeAndRegister(clauseNode);
993
  }
994
  // If ITE is false then one of the branches is false and the condition
995
  // implies which one
996
  // !lit -> !(ite b t e)
997
  // !lit -> (!t | !e) & (b -> !t) & (!b -> !e)
998
  // !lit -> (!t | !e) & (!b | !t) & (b | !e)
999
  // (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e)
1000
5887
  added = d_cnfStream.assertClause(node, lit, ~thenLit, ~elseLit);
1001
5887
  if (added)
1002
  {
1003
    Node clauseNode =
1004
11698
        nm->mkNode(kind::OR, node, node[1].notNode(), node[2].notNode());
1005
5849
    d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG3, {}, {node});
1006
11698
    Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG3 added "
1007
5849
                 << clauseNode << "\n";
1008
5849
    normalizeAndRegister(clauseNode);
1009
  }
1010
5887
  added = d_cnfStream.assertClause(node, lit, ~condLit, ~thenLit);
1011
5887
  if (added)
1012
  {
1013
    Node clauseNode =
1014
11552
        nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode());
1015
5776
    d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG1, {}, {node});
1016
11552
    Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG1 added "
1017
5776
                 << clauseNode << "\n";
1018
5776
    normalizeAndRegister(clauseNode);
1019
  }
1020
5887
  added = d_cnfStream.assertClause(node, lit, condLit, ~elseLit);
1021
5887
  if (added)
1022
  {
1023
11152
    Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[2].notNode());
1024
5576
    d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG2, {}, {node});
1025
11152
    Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG2 added "
1026
5576
                 << clauseNode << "\n";
1027
5576
    normalizeAndRegister(clauseNode);
1028
  }
1029
5887
  return lit;
1030
}
1031
1032
}  // namespace prop
1033
31125
}  // namespace cvc5