GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/cnf_stream.cpp Lines: 367 394 93.1 %
Date: 2021-05-21 Branches: 709 1902 37.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Dejan Jovanovic, Haniel Barbosa, Liana Hadarean
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
 * A CNF converter that takes in asserts and has the side effect of given an
14
 * equisatisfiable stream of assertions to PropEngine.
15
 */
16
#include "prop/cnf_stream.h"
17
18
#include <queue>
19
20
#include "base/check.h"
21
#include "base/output.h"
22
#include "expr/node.h"
23
#include "options/bv_options.h"
24
#include "proof/clause_id.h"
25
#include "prop/minisat/minisat.h"
26
#include "prop/prop_engine.h"
27
#include "prop/theory_proxy.h"
28
#include "smt/dump.h"
29
#include "smt/smt_engine.h"
30
#include "printer/printer.h"
31
#include "smt/smt_engine_scope.h"
32
#include "theory/theory.h"
33
#include "theory/theory_engine.h"
34
35
namespace cvc5 {
36
namespace prop {
37
38
17943
CnfStream::CnfStream(SatSolver* satSolver,
39
                     Registrar* registrar,
40
                     context::Context* context,
41
                     OutputManager* outMgr,
42
                     ResourceManager* rm,
43
                     FormulaLitPolicy flpol,
44
17943
                     std::string name)
45
    : d_satSolver(satSolver),
46
      d_outMgr(outMgr),
47
      d_booleanVariables(context),
48
      d_notifyFormulas(context),
49
      d_nodeToLiteralMap(context),
50
      d_literalToNodeMap(context),
51
      d_flitPolicy(flpol),
52
      d_registrar(registrar),
53
      d_name(name),
54
      d_removable(false),
55
17943
      d_resourceManager(rm)
56
{
57
17943
}
58
59
9889312
bool CnfStream::assertClause(TNode node, SatClause& c)
60
{
61
9889312
  Trace("cnf") << "Inserting into stream " << c << " node = " << node << "\n";
62
9889312
  if (Dump.isOn("clauses") && d_outMgr != nullptr)
63
  {
64
    const Printer& printer = d_outMgr->getPrinter();
65
    std::ostream& out = d_outMgr->getDumpOut();
66
    if (c.size() == 1)
67
    {
68
      printer.toStreamCmdAssert(out, getNode(c[0]));
69
    }
70
    else
71
    {
72
      Assert(c.size() > 1);
73
      NodeBuilder b(kind::OR);
74
      for (unsigned i = 0; i < c.size(); ++i)
75
      {
76
        b << getNode(c[i]);
77
      }
78
      Node n = b;
79
      printer.toStreamCmdAssert(out, n);
80
    }
81
  }
82
83
9889312
  ClauseId clauseId = d_satSolver->addClause(c, d_removable);
84
85
9889312
  return clauseId != ClauseIdUndef;
86
}
87
88
199660
bool CnfStream::assertClause(TNode node, SatLiteral a)
89
{
90
399320
  SatClause clause(1);
91
199660
  clause[0] = a;
92
399320
  return assertClause(node, clause);
93
}
94
95
4398834
bool CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b)
96
{
97
8797668
  SatClause clause(2);
98
4398834
  clause[0] = a;
99
4398834
  clause[1] = b;
100
8797668
  return assertClause(node, clause);
101
}
102
103
3202389
bool CnfStream::assertClause(TNode node,
104
                             SatLiteral a,
105
                             SatLiteral b,
106
                             SatLiteral c)
107
{
108
6404778
  SatClause clause(3);
109
3202389
  clause[0] = a;
110
3202389
  clause[1] = b;
111
3202389
  clause[2] = c;
112
6404778
  return assertClause(node, clause);
113
}
114
115
84852370
bool CnfStream::hasLiteral(TNode n) const {
116
84852370
  NodeToLiteralMap::const_iterator find = d_nodeToLiteralMap.find(n);
117
84852370
  return find != d_nodeToLiteralMap.end();
118
}
119
120
148815
void CnfStream::ensureMappingForLiteral(TNode n)
121
{
122
148815
  SatLiteral lit = getLiteral(n);
123
148815
  if (!d_literalToNodeMap.contains(lit))
124
  {
125
    // Store backward-mappings
126
    d_literalToNodeMap.insert(lit, n);
127
    d_literalToNodeMap.insert(~lit, n.notNode());
128
  }
129
148815
}
130
131
234798
void CnfStream::ensureLiteral(TNode n)
132
{
133
234798
  AlwaysAssertArgument(
134
      hasLiteral(n) || n.getType().isBoolean(),
135
      n,
136
      "ProofCnfStream::ensureLiteral() requires a node of Boolean type.\n"
137
      "got node: %s\n"
138
      "its type: %s\n",
139
      n.toString().c_str(),
140
      n.getType().toString().c_str());
141
234798
  Trace("cnf") << "ensureLiteral(" << n << ")\n";
142
234798
  if (hasLiteral(n))
143
  {
144
130498
    ensureMappingForLiteral(n);
145
130498
    return;
146
  }
147
  // remove top level negation
148
104300
  n = n.getKind() == kind::NOT ? n[0] : n;
149
104300
  if (theory::Theory::theoryOf(n) == theory::THEORY_BOOL && !n.isVar())
150
  {
151
    // If we were called with something other than a theory atom (or
152
    // Boolean variable), we get a SatLiteral that is definitionally
153
    // equal to it.
154
    // These are not removable and have no proof ID
155
14059
    d_removable = false;
156
157
14059
    SatLiteral lit = toCNF(n, false);
158
159
    // Store backward-mappings
160
    // These may already exist
161
14059
    d_literalToNodeMap.insert_safe(lit, n);
162
14059
    d_literalToNodeMap.insert_safe(~lit, n.notNode());
163
  }
164
  else
165
  {
166
    // We have a theory atom or variable.
167
90241
    convertAtom(n);
168
  }
169
}
170
171
2837155
SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister, bool canEliminate) {
172
5674310
  Trace("cnf") << d_name << "::newLiteral(" << node << ", " << isTheoryAtom
173
2837155
               << ")\n"
174
2837155
               << push;
175
2837155
  Assert(node.getKind() != kind::NOT);
176
177
  // if we are tracking formulas, everything is a theory atom
178
2837155
  if (!isTheoryAtom && d_flitPolicy == FormulaLitPolicy::TRACK_AND_NOTIFY)
179
  {
180
    isTheoryAtom = true;
181
    d_notifyFormulas.insert(node);
182
  }
183
184
  // Get the literal for this node
185
2837155
  SatLiteral lit;
186
2837155
  if (!hasLiteral(node)) {
187
2837146
    Trace("cnf") << d_name << "::newLiteral: node already registered\n";
188
    // If no literal, we'll make one
189
2837146
    if (node.getKind() == kind::CONST_BOOLEAN) {
190
18326
      Trace("cnf") << d_name << "::newLiteral: boolean const\n";
191
18326
      if (node.getConst<bool>()) {
192
9113
        lit = SatLiteral(d_satSolver->trueVar());
193
      } else {
194
9213
        lit = SatLiteral(d_satSolver->falseVar());
195
      }
196
    } else {
197
2818820
      Trace("cnf") << d_name << "::newLiteral: new var\n";
198
2818820
      lit = SatLiteral(d_satSolver->newVar(isTheoryAtom, preRegister, canEliminate));
199
    }
200
2837146
    d_nodeToLiteralMap.insert(node, lit);
201
2837146
    d_nodeToLiteralMap.insert(node.notNode(), ~lit);
202
  } else {
203
9
    lit = getLiteral(node);
204
  }
205
206
  // If it's a theory literal, need to store it for back queries
207
4880245
  if (isTheoryAtom || d_flitPolicy == FormulaLitPolicy::TRACK
208
4549289
      || (Dump.isOn("clauses")))
209
  {
210
1125021
    d_literalToNodeMap.insert_safe(lit, node);
211
1125021
    d_literalToNodeMap.insert_safe(~lit, node.notNode());
212
  }
213
214
  // If a theory literal, we pre-register it
215
2837155
  if (preRegister) {
216
    // In case we are re-entered due to lemmas, save our state
217
794065
    bool backupRemovable = d_removable;
218
794069
    d_registrar->preRegister(node);
219
794061
    d_removable = backupRemovable;
220
  }
221
  // Here, you can have it
222
2837151
  Trace("cnf") << "newLiteral(" << node << ") => " << lit << "\n" << pop;
223
2837151
  return lit;
224
}
225
226
15855554
TNode CnfStream::getNode(const SatLiteral& literal) {
227
15855554
  Trace("cnf") << "getNode(" << literal << ")\n";
228
31711108
  Trace("cnf") << "getNode(" << literal << ") => "
229
15855554
               << d_literalToNodeMap[literal] << "\n";
230
15855554
  return d_literalToNodeMap[literal];
231
}
232
233
4990438
const CnfStream::NodeToLiteralMap& CnfStream::getTranslationCache() const
234
{
235
4990438
  return d_nodeToLiteralMap;
236
}
237
238
14287717
const CnfStream::LiteralToNodeMap& CnfStream::getNodeCache() const
239
{
240
14287717
  return d_literalToNodeMap;
241
}
242
243
15156
void CnfStream::getBooleanVariables(std::vector<TNode>& outputVariables) const {
244
15156
  context::CDList<TNode>::const_iterator it, it_end;
245
73409
  for (it = d_booleanVariables.begin(); it != d_booleanVariables.end(); ++ it) {
246
58253
    outputVariables.push_back(*it);
247
  }
248
15156
}
249
250
bool CnfStream::isNotifyFormula(TNode node) const
251
{
252
  return d_notifyFormulas.find(node) != d_notifyFormulas.end();
253
}
254
255
874719
SatLiteral CnfStream::convertAtom(TNode node)
256
{
257
874719
  Trace("cnf") << "convertAtom(" << node << ")\n";
258
259
874719
  Assert(!hasLiteral(node)) << "atom already mapped!";
260
261
874719
  bool theoryLiteral = false;
262
874719
  bool canEliminate = true;
263
874719
  bool preRegister = false;
264
265
  // Is this a variable add it to the list
266
874719
  if (node.isVar() && node.getKind() != kind::BOOLEAN_TERM_VARIABLE)
267
  {
268
80654
    d_booleanVariables.push_back(node);
269
  }
270
  else
271
  {
272
794065
    theoryLiteral = true;
273
794065
    canEliminate = false;
274
794065
    preRegister = true;
275
  }
276
277
  // Make a new literal (variables are not considered theory literals)
278
874723
  SatLiteral lit = newLiteral(node, theoryLiteral, preRegister, canEliminate);
279
  // Return the resulting literal
280
874715
  return lit;
281
}
282
283
63070892
SatLiteral CnfStream::getLiteral(TNode node) {
284
63070892
  Assert(!node.isNull()) << "CnfStream: can't getLiteral() of null node";
285
286
126141784
  Assert(d_nodeToLiteralMap.contains(node))
287
63070892
      << "Literal not in the CNF Cache: " << node << "\n";
288
289
63070892
  SatLiteral literal = d_nodeToLiteralMap[node];
290
126141784
  Trace("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal
291
63070892
               << "\n";
292
63070892
  return literal;
293
}
294
295
290540
SatLiteral CnfStream::handleXor(TNode xorNode)
296
{
297
290540
  Assert(!hasLiteral(xorNode)) << "Atom already mapped!";
298
290540
  Assert(xorNode.getKind() == kind::XOR) << "Expecting an XOR expression!";
299
290540
  Assert(xorNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
300
290540
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
301
290540
  Trace("cnf") << "CnfStream::handleXor(" << xorNode << ")\n";
302
303
290540
  SatLiteral a = toCNF(xorNode[0]);
304
290540
  SatLiteral b = toCNF(xorNode[1]);
305
306
290540
  SatLiteral xorLit = newLiteral(xorNode);
307
308
290540
  assertClause(xorNode.negate(), a, b, ~xorLit);
309
290540
  assertClause(xorNode.negate(), ~a, ~b, ~xorLit);
310
290540
  assertClause(xorNode, a, ~b, xorLit);
311
290540
  assertClause(xorNode, ~a, b, xorLit);
312
313
290540
  return xorLit;
314
}
315
316
417034
SatLiteral CnfStream::handleOr(TNode orNode)
317
{
318
417034
  Assert(!hasLiteral(orNode)) << "Atom already mapped!";
319
417034
  Assert(orNode.getKind() == kind::OR) << "Expecting an OR expression!";
320
417034
  Assert(orNode.getNumChildren() > 1) << "Expecting more then 1 child!";
321
417034
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
322
417034
  Trace("cnf") << "CnfStream::handleOr(" << orNode << ")\n";
323
324
  // Number of children
325
417034
  unsigned n_children = orNode.getNumChildren();
326
327
  // Transform all the children first
328
417034
  TNode::const_iterator node_it = orNode.begin();
329
417034
  TNode::const_iterator node_it_end = orNode.end();
330
834068
  SatClause clause(n_children + 1);
331
1418308
  for(int i = 0; node_it != node_it_end; ++node_it, ++i) {
332
1001274
    clause[i] = toCNF(*node_it);
333
  }
334
335
  // Get the literal for this node
336
417034
  SatLiteral orLit = newLiteral(orNode);
337
338
  // lit <- (a_1 | a_2 | a_3 | ... | a_n)
339
  // lit | ~(a_1 | a_2 | a_3 | ... | a_n)
340
  // (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n)
341
1418308
  for(unsigned i = 0; i < n_children; ++i) {
342
1001274
    assertClause(orNode, orLit, ~clause[i]);
343
  }
344
345
  // lit -> (a_1 | a_2 | a_3 | ... | a_n)
346
  // ~lit | a_1 | a_2 | a_3 | ... | a_n
347
417034
  clause[n_children] = ~orLit;
348
  // This needs to go last, as the clause might get modified by the SAT solver
349
417034
  assertClause(orNode.negate(), clause);
350
351
  // Return the literal
352
834068
  return orLit;
353
}
354
355
746793
SatLiteral CnfStream::handleAnd(TNode andNode)
356
{
357
746793
  Assert(!hasLiteral(andNode)) << "Atom already mapped!";
358
746793
  Assert(andNode.getKind() == kind::AND) << "Expecting an AND expression!";
359
746793
  Assert(andNode.getNumChildren() > 1) << "Expecting more than 1 child!";
360
746793
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
361
746793
  Trace("cnf") << "handleAnd(" << andNode << ")\n";
362
363
  // Number of children
364
746793
  unsigned n_children = andNode.getNumChildren();
365
366
  // Transform all the children first (remembering the negation)
367
746793
  TNode::const_iterator node_it = andNode.begin();
368
746793
  TNode::const_iterator node_it_end = andNode.end();
369
1493586
  SatClause clause(n_children + 1);
370
3927650
  for(int i = 0; node_it != node_it_end; ++node_it, ++i) {
371
3180857
    clause[i] = ~toCNF(*node_it);
372
  }
373
374
  // Get the literal for this node
375
746793
  SatLiteral andLit = newLiteral(andNode);
376
377
  // lit -> (a_1 & a_2 & a_3 & ... & a_n)
378
  // ~lit | (a_1 & a_2 & a_3 & ... & a_n)
379
  // (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n)
380
3927650
  for(unsigned i = 0; i < n_children; ++i) {
381
3180857
    assertClause(andNode.negate(), ~andLit, ~clause[i]);
382
  }
383
384
  // lit <- (a_1 & a_2 & a_3 & ... a_n)
385
  // lit | ~(a_1 & a_2 & a_3 & ... & a_n)
386
  // lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n
387
746793
  clause[n_children] = andLit;
388
  // This needs to go last, as the clause might get modified by the SAT solver
389
746793
  assertClause(andNode, clause);
390
391
1493586
  return andLit;
392
}
393
394
6822
SatLiteral CnfStream::handleImplies(TNode impliesNode)
395
{
396
6822
  Assert(!hasLiteral(impliesNode)) << "Atom already mapped!";
397
6822
  Assert(impliesNode.getKind() == kind::IMPLIES)
398
      << "Expecting an IMPLIES expression!";
399
6822
  Assert(impliesNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
400
6822
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
401
6822
  Trace("cnf") << "handleImplies(" << impliesNode << ")\n";
402
403
  // Convert the children to cnf
404
6822
  SatLiteral a = toCNF(impliesNode[0]);
405
6822
  SatLiteral b = toCNF(impliesNode[1]);
406
407
6822
  SatLiteral impliesLit = newLiteral(impliesNode);
408
409
  // lit -> (a->b)
410
  // ~lit | ~ a | b
411
6822
  assertClause(impliesNode.negate(), ~impliesLit, ~a, b);
412
413
  // (a->b) -> lit
414
  // ~(~a | b) | lit
415
  // (a | l) & (~b | l)
416
6822
  assertClause(impliesNode, a, impliesLit);
417
6822
  assertClause(impliesNode, ~b, impliesLit);
418
419
6822
  return impliesLit;
420
}
421
422
371598
SatLiteral CnfStream::handleIff(TNode iffNode)
423
{
424
371598
  Assert(!hasLiteral(iffNode)) << "Atom already mapped!";
425
371598
  Assert(iffNode.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!";
426
371598
  Assert(iffNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
427
371598
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
428
371598
  Trace("cnf") << "handleIff(" << iffNode << ")\n";
429
430
  // Convert the children to CNF
431
371598
  SatLiteral a = toCNF(iffNode[0]);
432
371598
  SatLiteral b = toCNF(iffNode[1]);
433
434
  // Get the now literal
435
371598
  SatLiteral iffLit = newLiteral(iffNode);
436
437
  // lit -> ((a-> b) & (b->a))
438
  // ~lit | ((~a | b) & (~b | a))
439
  // (~a | b | ~lit) & (~b | a | ~lit)
440
371598
  assertClause(iffNode.negate(), ~a, b, ~iffLit);
441
371598
  assertClause(iffNode.negate(), a, ~b, ~iffLit);
442
443
  // (a<->b) -> lit
444
  // ~((a & b) | (~a & ~b)) | lit
445
  // (~(a & b)) & (~(~a & ~b)) | lit
446
  // ((~a | ~b) & (a | b)) | lit
447
  // (~a | ~b | lit) & (a | b | lit)
448
371598
  assertClause(iffNode, ~a, ~b, iffLit);
449
371598
  assertClause(iffNode, a, b, iffLit);
450
451
371598
  return iffLit;
452
}
453
454
85666
SatLiteral CnfStream::handleIte(TNode iteNode)
455
{
456
85666
  Assert(!hasLiteral(iteNode)) << "Atom already mapped!";
457
85666
  Assert(iteNode.getKind() == kind::ITE);
458
85666
  Assert(iteNode.getNumChildren() == 3);
459
85666
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
460
171332
  Trace("cnf") << "handleIte(" << iteNode[0] << " " << iteNode[1] << " "
461
85666
               << iteNode[2] << ")\n";
462
463
85666
  SatLiteral condLit = toCNF(iteNode[0]);
464
85666
  SatLiteral thenLit = toCNF(iteNode[1]);
465
85666
  SatLiteral elseLit = toCNF(iteNode[2]);
466
467
85666
  SatLiteral iteLit = newLiteral(iteNode);
468
469
  // If ITE is true then one of the branches is true and the condition
470
  // implies which one
471
  // lit -> (ite b t e)
472
  // lit -> (t | e) & (b -> t) & (!b -> e)
473
  // lit -> (t | e) & (!b | t) & (b | e)
474
  // (!lit | t | e) & (!lit | !b | t) & (!lit | b | e)
475
85666
  assertClause(iteNode.negate(), ~iteLit, thenLit, elseLit);
476
85666
  assertClause(iteNode.negate(), ~iteLit, ~condLit, thenLit);
477
85666
  assertClause(iteNode.negate(), ~iteLit, condLit, elseLit);
478
479
  // If ITE is false then one of the branches is false and the condition
480
  // implies which one
481
  // !lit -> !(ite b t e)
482
  // !lit -> (!t | !e) & (b -> !t) & (!b -> !e)
483
  // !lit -> (!t | !e) & (!b | !t) & (b | !e)
484
  // (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e)
485
85666
  assertClause(iteNode, iteLit, ~thenLit, ~elseLit);
486
85666
  assertClause(iteNode, iteLit, ~condLit, ~thenLit);
487
85666
  assertClause(iteNode, iteLit, condLit, ~elseLit);
488
489
85666
  return iteLit;
490
}
491
492
9031326
SatLiteral CnfStream::toCNF(TNode node, bool negated)
493
{
494
18062652
  Trace("cnf") << "toCNF(" << node
495
9031326
               << ", negated = " << (negated ? "true" : "false") << ")\n";
496
9031326
  SatLiteral nodeLit;
497
18062652
  Node negatedNode = node.notNode();
498
499
  // If the non-negated node has already been translated, get the translation
500
9031326
  if(hasLiteral(node)) {
501
6231110
    Trace("cnf") << "toCNF(): already translated\n";
502
6231110
    nodeLit = getLiteral(node);
503
    // Return the (maybe negated) literal
504
6231110
    return !negated ? nodeLit : ~nodeLit;
505
  }
506
  // Handle each Boolean operator case
507
2800216
  switch (node.getKind())
508
  {
509
190142
    case kind::NOT: nodeLit = ~toCNF(node[0]); break;
510
290540
    case kind::XOR: nodeLit = handleXor(node); break;
511
85666
    case kind::ITE: nodeLit = handleIte(node); break;
512
6822
    case kind::IMPLIES: nodeLit = handleImplies(node); break;
513
417034
    case kind::OR: nodeLit = handleOr(node); break;
514
746793
    case kind::AND: nodeLit = handleAnd(node); break;
515
593567
    case kind::EQUAL:
516
1187134
      nodeLit =
517
1780701
          node[0].getType().isBoolean() ? handleIff(node) : convertAtom(node);
518
593567
      break;
519
469652
    default:
520
    {
521
469656
      nodeLit = convertAtom(node);
522
    }
523
469648
    break;
524
  }
525
  // Return the (maybe negated) literal
526
5600424
  Trace("cnf") << "toCNF(): resulting literal: "
527
2800212
               << (!negated ? nodeLit : ~nodeLit) << "\n";
528
2800212
  return !negated ? nodeLit : ~nodeLit;
529
}
530
531
105788
void CnfStream::convertAndAssertAnd(TNode node, bool negated)
532
{
533
105788
  Assert(node.getKind() == kind::AND);
534
211576
  Trace("cnf") << "CnfStream::convertAndAssertAnd(" << node
535
105788
               << ", negated = " << (negated ? "true" : "false") << ")\n";
536
105788
  if (!negated) {
537
    // If the node is a conjunction, we handle each conjunct separately
538
363814
    for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
539
363814
        conjunct != node_end; ++conjunct ) {
540
350929
      convertAndAssert(*conjunct, false);
541
    }
542
  } else {
543
    // If the node is a disjunction, we construct a clause and assert it
544
92901
    int nChildren = node.getNumChildren();
545
185802
    SatClause clause(nChildren);
546
92901
    TNode::const_iterator disjunct = node.begin();
547
1350583
    for(int i = 0; i < nChildren; ++ disjunct, ++ i) {
548
1257682
      Assert(disjunct != node.end());
549
1257682
      clause[i] = toCNF(*disjunct, true);
550
    }
551
92901
    Assert(disjunct == node.end());
552
92901
    assertClause(node.negate(), clause);
553
  }
554
105787
}
555
556
440627
void CnfStream::convertAndAssertOr(TNode node, bool negated)
557
{
558
440627
  Assert(node.getKind() == kind::OR);
559
881254
  Trace("cnf") << "CnfStream::convertAndAssertOr(" << node
560
440627
               << ", negated = " << (negated ? "true" : "false") << ")\n";
561
440627
  if (!negated) {
562
    // If the node is a disjunction, we construct a clause and assert it
563
440326
    int nChildren = node.getNumChildren();
564
880652
    SatClause clause(nChildren);
565
440326
    TNode::const_iterator disjunct = node.begin();
566
1749820
    for(int i = 0; i < nChildren; ++ disjunct, ++ i) {
567
1309494
      Assert(disjunct != node.end());
568
1309494
      clause[i] = toCNF(*disjunct, false);
569
    }
570
440326
    Assert(disjunct == node.end());
571
440326
    assertClause(node, clause);
572
  } else {
573
    // If the node is a conjunction, we handle each conjunct separately
574
1933
    for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
575
1933
        conjunct != node_end; ++conjunct ) {
576
1632
      convertAndAssert(*conjunct, true);
577
    }
578
  }
579
440627
}
580
581
53
void CnfStream::convertAndAssertXor(TNode node, bool negated)
582
{
583
53
  Assert(node.getKind() == kind::XOR);
584
106
  Trace("cnf") << "CnfStream::convertAndAssertXor(" << node
585
53
               << ", negated = " << (negated ? "true" : "false") << ")\n";
586
53
  if (!negated) {
587
    // p XOR q
588
53
    SatLiteral p = toCNF(node[0], false);
589
53
    SatLiteral q = toCNF(node[1], false);
590
    // Construct the clauses (p => !q) and (!q => p)
591
106
    SatClause clause1(2);
592
53
    clause1[0] = ~p;
593
53
    clause1[1] = ~q;
594
53
    assertClause(node, clause1);
595
106
    SatClause clause2(2);
596
53
    clause2[0] = p;
597
53
    clause2[1] = q;
598
53
    assertClause(node, clause2);
599
  } else {
600
    // !(p XOR q) is the same as p <=> q
601
    SatLiteral p = toCNF(node[0], false);
602
    SatLiteral q = toCNF(node[1], false);
603
    // Construct the clauses (p => q) and (q => p)
604
    SatClause clause1(2);
605
    clause1[0] = ~p;
606
    clause1[1] = q;
607
    assertClause(node.negate(), clause1);
608
    SatClause clause2(2);
609
    clause2[0] = p;
610
    clause2[1] = ~q;
611
    assertClause(node.negate(), clause2);
612
  }
613
53
}
614
615
80533
void CnfStream::convertAndAssertIff(TNode node, bool negated)
616
{
617
80533
  Assert(node.getKind() == kind::EQUAL);
618
161066
  Trace("cnf") << "CnfStream::convertAndAssertIff(" << node
619
80533
               << ", negated = " << (negated ? "true" : "false") << ")\n";
620
80533
  if (!negated) {
621
    // p <=> q
622
80002
    SatLiteral p = toCNF(node[0], false);
623
80002
    SatLiteral q = toCNF(node[1], false);
624
    // Construct the clauses (p => q) and (q => p)
625
160004
    SatClause clause1(2);
626
80002
    clause1[0] = ~p;
627
80002
    clause1[1] = q;
628
80002
    assertClause(node, clause1);
629
160004
    SatClause clause2(2);
630
80002
    clause2[0] = p;
631
80002
    clause2[1] = ~q;
632
80002
    assertClause(node, clause2);
633
  } else {
634
    // !(p <=> q) is the same as p XOR q
635
531
    SatLiteral p = toCNF(node[0], false);
636
531
    SatLiteral q = toCNF(node[1], false);
637
    // Construct the clauses (p => !q) and (!q => p)
638
1062
    SatClause clause1(2);
639
531
    clause1[0] = ~p;
640
531
    clause1[1] = ~q;
641
531
    assertClause(node.negate(), clause1);
642
1062
    SatClause clause2(2);
643
531
    clause2[0] = p;
644
531
    clause2[1] = q;
645
531
    assertClause(node.negate(), clause2);
646
  }
647
80533
}
648
649
58725
void CnfStream::convertAndAssertImplies(TNode node, bool negated)
650
{
651
58725
  Assert(node.getKind() == kind::IMPLIES);
652
117450
  Trace("cnf") << "CnfStream::convertAndAssertImplies(" << node
653
58725
               << ", negated = " << (negated ? "true" : "false") << ")\n";
654
58725
  if (!negated) {
655
    // p => q
656
58488
    SatLiteral p = toCNF(node[0], false);
657
58488
    SatLiteral q = toCNF(node[1], false);
658
    // Construct the clause ~p || q
659
116976
    SatClause clause(2);
660
58488
    clause[0] = ~p;
661
58488
    clause[1] = q;
662
58488
    assertClause(node, clause);
663
  } else {// Construct the
664
    // !(p => q) is the same as (p && ~q)
665
237
    convertAndAssert(node[0], false);
666
237
    convertAndAssert(node[1], true);
667
  }
668
58725
}
669
670
17430
void CnfStream::convertAndAssertIte(TNode node, bool negated)
671
{
672
17430
  Assert(node.getKind() == kind::ITE);
673
34860
  Trace("cnf") << "CnfStream::convertAndAssertIte(" << node
674
17430
               << ", negated = " << (negated ? "true" : "false") << ")\n";
675
  // ITE(p, q, r)
676
17430
  SatLiteral p = toCNF(node[0], false);
677
17430
  SatLiteral q = toCNF(node[1], negated);
678
17430
  SatLiteral r = toCNF(node[2], negated);
679
  // Construct the clauses:
680
  // (p => q) and (!p => r)
681
  //
682
  // Note that below q and r can be used directly because whether they are
683
  // negated has been push to the literal definitions above
684
34860
  Node nnode = node;
685
17430
  if( negated ){
686
69
    nnode = node.negate();
687
  }
688
34860
  SatClause clause1(2);
689
17430
  clause1[0] = ~p;
690
17430
  clause1[1] = q;
691
17430
  assertClause(nnode, clause1);
692
34860
  SatClause clause2(2);
693
17430
  clause2[0] = p;
694
17430
  clause2[1] = r;
695
17430
  assertClause(nnode, clause2);
696
17430
}
697
698
// At the top level we must ensure that all clauses that are asserted are
699
// not unit, except for the direct assertions. This allows us to remove the
700
// clauses later when they are not needed anymore (lemmas for example).
701
502584
void CnfStream::convertAndAssert(TNode node,
702
                                 bool removable,
703
                                 bool negated,
704
                                 bool input)
705
{
706
1005168
  Trace("cnf") << "convertAndAssert(" << node
707
1005168
               << ", negated = " << (negated ? "true" : "false")
708
502584
               << ", removable = " << (removable ? "true" : "false") << ")\n";
709
502584
  d_removable = removable;
710
502588
  convertAndAssert(node, negated);
711
502580
}
712
713
906187
void CnfStream::convertAndAssert(TNode node, bool negated)
714
{
715
1812374
  Trace("cnf") << "convertAndAssert(" << node
716
906187
               << ", negated = " << (negated ? "true" : "false") << ")\n";
717
718
906187
  d_resourceManager->spendResource(Resource::CnfStep);
719
720
906187
  switch(node.getKind()) {
721
105789
    case kind::AND: convertAndAssertAnd(node, negated); break;
722
440627
    case kind::OR: convertAndAssertOr(node, negated); break;
723
53
    case kind::XOR: convertAndAssertXor(node, negated); break;
724
58725
    case kind::IMPLIES: convertAndAssertImplies(node, negated); break;
725
17430
    case kind::ITE: convertAndAssertIte(node, negated); break;
726
50571
    case kind::NOT: convertAndAssert(node[0], !negated); break;
727
146404
    case kind::EQUAL:
728
146404
      if (node[0].getType().isBoolean())
729
      {
730
80533
        convertAndAssertIff(node, negated);
731
80533
        break;
732
      }
733
      CVC5_FALLTHROUGH;
734
    default:
735
    {
736
304924
      Node nnode = node;
737
152462
      if (negated)
738
      {
739
46663
        nnode = node.negate();
740
      }
741
      // Atoms
742
304924
      assertClause(nnode, toCNF(node, negated));
743
  }
744
152458
    break;
745
  }
746
906180
}
747
748
}  // namespace prop
749
27735
}  // namespace cvc5