GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/cnf_stream.cpp Lines: 386 412 93.7 %
Date: 2021-08-01 Branches: 756 1997 37.9 %

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 "printer/printer.h"
25
#include "proof/clause_id.h"
26
#include "prop/minisat/minisat.h"
27
#include "prop/prop_engine.h"
28
#include "prop/theory_proxy.h"
29
#include "smt/dump.h"
30
#include "smt/smt_engine.h"
31
#include "smt/smt_engine_scope.h"
32
#include "smt/smt_statistics_registry.h"
33
#include "theory/theory.h"
34
#include "theory/theory_engine.h"
35
36
namespace cvc5 {
37
namespace prop {
38
39
16025
CnfStream::CnfStream(SatSolver* satSolver,
40
                     Registrar* registrar,
41
                     context::Context* context,
42
                     OutputManager* outMgr,
43
                     ResourceManager* rm,
44
                     FormulaLitPolicy flpol,
45
16025
                     std::string name)
46
    : d_satSolver(satSolver),
47
      d_outMgr(outMgr),
48
      d_booleanVariables(context),
49
      d_notifyFormulas(context),
50
      d_nodeToLiteralMap(context),
51
      d_literalToNodeMap(context),
52
      d_flitPolicy(flpol),
53
      d_registrar(registrar),
54
      d_name(name),
55
      d_removable(false),
56
      d_resourceManager(rm),
57
16025
      d_stats(name)
58
{
59
16025
}
60
61
9069634
bool CnfStream::assertClause(TNode node, SatClause& c)
62
{
63
9069634
  Trace("cnf") << "Inserting into stream " << c << " node = " << node << "\n";
64
9069634
  if (Dump.isOn("clauses") && d_outMgr != nullptr)
65
  {
66
    const Printer& printer = d_outMgr->getPrinter();
67
    std::ostream& out = d_outMgr->getDumpOut();
68
    if (c.size() == 1)
69
    {
70
      printer.toStreamCmdAssert(out, getNode(c[0]));
71
    }
72
    else
73
    {
74
      Assert(c.size() > 1);
75
      NodeBuilder b(kind::OR);
76
      for (unsigned i = 0; i < c.size(); ++i)
77
      {
78
        b << getNode(c[i]);
79
      }
80
      Node n = b;
81
      printer.toStreamCmdAssert(out, n);
82
    }
83
  }
84
85
9069634
  ClauseId clauseId = d_satSolver->addClause(c, d_removable);
86
87
9069634
  return clauseId != ClauseIdUndef;
88
}
89
90
208753
bool CnfStream::assertClause(TNode node, SatLiteral a)
91
{
92
417506
  SatClause clause(1);
93
208753
  clause[0] = a;
94
417506
  return assertClause(node, clause);
95
}
96
97
4148400
bool CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b)
98
{
99
8296800
  SatClause clause(2);
100
4148400
  clause[0] = a;
101
4148400
  clause[1] = b;
102
8296800
  return assertClause(node, clause);
103
}
104
105
2802430
bool CnfStream::assertClause(TNode node,
106
                             SatLiteral a,
107
                             SatLiteral b,
108
                             SatLiteral c)
109
{
110
5604860
  SatClause clause(3);
111
2802430
  clause[0] = a;
112
2802430
  clause[1] = b;
113
2802430
  clause[2] = c;
114
5604860
  return assertClause(node, clause);
115
}
116
117
55715096
bool CnfStream::hasLiteral(TNode n) const {
118
55715096
  NodeToLiteralMap::const_iterator find = d_nodeToLiteralMap.find(n);
119
55715096
  return find != d_nodeToLiteralMap.end();
120
}
121
122
2646530
void CnfStream::ensureMappingForLiteral(TNode n)
123
{
124
2646530
  SatLiteral lit = getLiteral(n);
125
2646530
  if (!d_literalToNodeMap.contains(lit))
126
  {
127
    // Store backward-mappings
128
200
    d_literalToNodeMap.insert(lit, n);
129
200
    d_literalToNodeMap.insert(~lit, n.notNode());
130
  }
131
2646530
}
132
133
2684853
void CnfStream::ensureLiteral(TNode n)
134
{
135
2684853
  AlwaysAssertArgument(
136
      hasLiteral(n) || n.getType().isBoolean(),
137
      n,
138
      "ProofCnfStream::ensureLiteral() requires a node of Boolean type.\n"
139
      "got node: %s\n"
140
      "its type: %s\n",
141
      n.toString().c_str(),
142
      n.getType().toString().c_str());
143
2684853
  Trace("cnf") << "ensureLiteral(" << n << ")\n";
144
2746122
  TimerStat::CodeTimer codeTimer(d_stats.d_cnfConversionTime, true);
145
2684853
  if (hasLiteral(n))
146
  {
147
2623584
    ensureMappingForLiteral(n);
148
2623584
    return;
149
  }
150
  // remove top level negation
151
61269
  n = n.getKind() == kind::NOT ? n[0] : n;
152
61269
  if (theory::Theory::theoryOf(n) == theory::THEORY_BOOL && !n.isVar())
153
  {
154
    // If we were called with something other than a theory atom (or
155
    // Boolean variable), we get a SatLiteral that is definitionally
156
    // equal to it.
157
    // These are not removable and have no proof ID
158
42390
    d_removable = false;
159
160
42390
    SatLiteral lit = toCNF(n, false);
161
162
    // Store backward-mappings
163
    // These may already exist
164
42390
    d_literalToNodeMap.insert_safe(lit, n);
165
42390
    d_literalToNodeMap.insert_safe(~lit, n.notNode());
166
  }
167
  else
168
  {
169
    // We have a theory atom or variable.
170
18879
    convertAtom(n);
171
  }
172
}
173
174
2627818
SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister, bool canEliminate) {
175
5255636
  Trace("cnf") << d_name << "::newLiteral(" << node << ", " << isTheoryAtom
176
2627818
               << ")\n"
177
2627818
               << push;
178
2627818
  Assert(node.getKind() != kind::NOT);
179
180
  // if we are tracking formulas, everything is a theory atom
181
2627818
  if (!isTheoryAtom && d_flitPolicy == FormulaLitPolicy::TRACK_AND_NOTIFY)
182
  {
183
    isTheoryAtom = true;
184
    d_notifyFormulas.insert(node);
185
  }
186
187
  // Get the literal for this node
188
2627818
  SatLiteral lit;
189
2627818
  if (!hasLiteral(node)) {
190
2627816
    Trace("cnf") << d_name << "::newLiteral: node already registered\n";
191
    // If no literal, we'll make one
192
2627816
    if (node.getKind() == kind::CONST_BOOLEAN) {
193
20011
      Trace("cnf") << d_name << "::newLiteral: boolean const\n";
194
20011
      if (node.getConst<bool>()) {
195
9950
        lit = SatLiteral(d_satSolver->trueVar());
196
      } else {
197
10061
        lit = SatLiteral(d_satSolver->falseVar());
198
      }
199
    } else {
200
2607805
      Trace("cnf") << d_name << "::newLiteral: new var\n";
201
2607805
      lit = SatLiteral(d_satSolver->newVar(isTheoryAtom, preRegister, canEliminate));
202
    }
203
2627816
    d_nodeToLiteralMap.insert(node, lit);
204
2627816
    d_nodeToLiteralMap.insert(node.notNode(), ~lit);
205
  } else {
206
2
    lit = getLiteral(node);
207
  }
208
209
  // If it's a theory literal, need to store it for back queries
210
4488246
  if (isTheoryAtom || d_flitPolicy == FormulaLitPolicy::TRACK
211
3791321
      || (Dump.isOn("clauses")))
212
  {
213
1464315
    d_literalToNodeMap.insert_safe(lit, node);
214
1464315
    d_literalToNodeMap.insert_safe(~lit, node.notNode());
215
  }
216
217
  // If a theory literal, we pre-register it
218
2627818
  if (preRegister) {
219
    // In case we are re-entered due to lemmas, save our state
220
767390
    bool backupRemovable = d_removable;
221
767394
    d_registrar->preRegister(node);
222
767386
    d_removable = backupRemovable;
223
  }
224
  // Here, you can have it
225
2627814
  Trace("cnf") << "newLiteral(" << node << ") => " << lit << "\n" << pop;
226
2627814
  return lit;
227
}
228
229
18737451
TNode CnfStream::getNode(const SatLiteral& literal) {
230
18737451
  Trace("cnf") << "getNode(" << literal << ")\n";
231
37474902
  Trace("cnf") << "getNode(" << literal << ") => "
232
18737451
               << d_literalToNodeMap[literal] << "\n";
233
18737451
  return d_literalToNodeMap[literal];
234
}
235
236
4919497
const CnfStream::NodeToLiteralMap& CnfStream::getTranslationCache() const
237
{
238
4919497
  return d_nodeToLiteralMap;
239
}
240
241
14545642
const CnfStream::LiteralToNodeMap& CnfStream::getNodeCache() const
242
{
243
14545642
  return d_literalToNodeMap;
244
}
245
246
16526
void CnfStream::getBooleanVariables(std::vector<TNode>& outputVariables) const {
247
16526
  context::CDList<TNode>::const_iterator it, it_end;
248
87627
  for (it = d_booleanVariables.begin(); it != d_booleanVariables.end(); ++ it) {
249
71101
    outputVariables.push_back(*it);
250
  }
251
16526
}
252
253
bool CnfStream::isNotifyFormula(TNode node) const
254
{
255
  return d_notifyFormulas.find(node) != d_notifyFormulas.end();
256
}
257
258
850859
SatLiteral CnfStream::convertAtom(TNode node)
259
{
260
850859
  Trace("cnf") << "convertAtom(" << node << ")\n";
261
262
850859
  Assert(!hasLiteral(node)) << "atom already mapped!";
263
264
850859
  bool theoryLiteral = false;
265
850859
  bool canEliminate = true;
266
850859
  bool preRegister = false;
267
268
  // Is this a variable add it to the list
269
850859
  if (node.isVar() && node.getKind() != kind::BOOLEAN_TERM_VARIABLE)
270
  {
271
83469
    d_booleanVariables.push_back(node);
272
  }
273
  else
274
  {
275
767390
    theoryLiteral = true;
276
767390
    canEliminate = false;
277
767390
    preRegister = true;
278
  }
279
280
  // Make a new literal (variables are not considered theory literals)
281
850863
  SatLiteral lit = newLiteral(node, theoryLiteral, preRegister, canEliminate);
282
  // Return the resulting literal
283
850855
  return lit;
284
}
285
286
41935306
SatLiteral CnfStream::getLiteral(TNode node) {
287
41935306
  Assert(!node.isNull()) << "CnfStream: can't getLiteral() of null node";
288
289
83870612
  Assert(d_nodeToLiteralMap.contains(node))
290
41935306
      << "Literal not in the CNF Cache: " << node << "\n";
291
292
41935306
  SatLiteral literal = d_nodeToLiteralMap[node];
293
83870612
  Trace("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal
294
41935306
               << "\n";
295
41935306
  return literal;
296
}
297
298
249847
void CnfStream::handleXor(TNode xorNode)
299
{
300
249847
  Assert(!hasLiteral(xorNode)) << "Atom already mapped!";
301
249847
  Assert(xorNode.getKind() == kind::XOR) << "Expecting an XOR expression!";
302
249847
  Assert(xorNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
303
249847
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
304
249847
  Trace("cnf") << "CnfStream::handleXor(" << xorNode << ")\n";
305
306
249847
  SatLiteral a = getLiteral(xorNode[0]);
307
249847
  SatLiteral b = getLiteral(xorNode[1]);
308
309
249847
  SatLiteral xorLit = newLiteral(xorNode);
310
311
249847
  assertClause(xorNode.negate(), a, b, ~xorLit);
312
249847
  assertClause(xorNode.negate(), ~a, ~b, ~xorLit);
313
249847
  assertClause(xorNode, a, ~b, xorLit);
314
249847
  assertClause(xorNode, ~a, b, xorLit);
315
249847
}
316
317
391824
void CnfStream::handleOr(TNode orNode)
318
{
319
391824
  Assert(!hasLiteral(orNode)) << "Atom already mapped!";
320
391824
  Assert(orNode.getKind() == kind::OR) << "Expecting an OR expression!";
321
391824
  Assert(orNode.getNumChildren() > 1) << "Expecting more then 1 child!";
322
391824
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
323
391824
  Trace("cnf") << "CnfStream::handleOr(" << orNode << ")\n";
324
325
  // Number of children
326
391824
  size_t numChildren = orNode.getNumChildren();
327
328
  // Get the literal for this node
329
391824
  SatLiteral orLit = newLiteral(orNode);
330
331
  // Transform all the children first
332
783648
  SatClause clause(numChildren + 1);
333
1352150
  for (size_t i = 0; i < numChildren; ++i)
334
  {
335
960326
    clause[i] = getLiteral(orNode[i]);
336
337
    // lit <- (a_1 | a_2 | a_3 | ... | a_n)
338
    // lit | ~(a_1 | a_2 | a_3 | ... | a_n)
339
    // (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n)
340
960326
    assertClause(orNode, orLit, ~clause[i]);
341
  }
342
343
  // lit -> (a_1 | a_2 | a_3 | ... | a_n)
344
  // ~lit | a_1 | a_2 | a_3 | ... | a_n
345
391824
  clause[numChildren] = ~orLit;
346
  // This needs to go last, as the clause might get modified by the SAT solver
347
391824
  assertClause(orNode.negate(), clause);
348
391824
}
349
350
643982
void CnfStream::handleAnd(TNode andNode)
351
{
352
643982
  Assert(!hasLiteral(andNode)) << "Atom already mapped!";
353
643982
  Assert(andNode.getKind() == kind::AND) << "Expecting an AND expression!";
354
643982
  Assert(andNode.getNumChildren() > 1) << "Expecting more than 1 child!";
355
643982
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
356
643982
  Trace("cnf") << "handleAnd(" << andNode << ")\n";
357
358
  // Number of children
359
643982
  size_t numChildren = andNode.getNumChildren();
360
361
  // Get the literal for this node
362
643982
  SatLiteral andLit = newLiteral(andNode);
363
364
  // Transform all the children first (remembering the negation)
365
1287964
  SatClause clause(numChildren + 1);
366
3454878
  for (size_t i = 0; i < numChildren; ++i)
367
  {
368
2810896
    clause[i] = ~getLiteral(andNode[i]);
369
370
    // lit -> (a_1 & a_2 & a_3 & ... & a_n)
371
    // ~lit | (a_1 & a_2 & a_3 & ... & a_n)
372
    // (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n)
373
2810896
    assertClause(andNode.negate(), ~andLit, ~clause[i]);
374
  }
375
376
  // lit <- (a_1 & a_2 & a_3 & ... a_n)
377
  // lit | ~(a_1 & a_2 & a_3 & ... & a_n)
378
  // lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n
379
643982
  clause[numChildren] = andLit;
380
  // This needs to go last, as the clause might get modified by the SAT solver
381
643982
  assertClause(andNode, clause);
382
643982
}
383
384
8536
void CnfStream::handleImplies(TNode impliesNode)
385
{
386
8536
  Assert(!hasLiteral(impliesNode)) << "Atom already mapped!";
387
8536
  Assert(impliesNode.getKind() == kind::IMPLIES)
388
      << "Expecting an IMPLIES expression!";
389
8536
  Assert(impliesNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
390
8536
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
391
8536
  Trace("cnf") << "handleImplies(" << impliesNode << ")\n";
392
393
  // Convert the children to cnf
394
8536
  SatLiteral a = getLiteral(impliesNode[0]);
395
8536
  SatLiteral b = getLiteral(impliesNode[1]);
396
397
8536
  SatLiteral impliesLit = newLiteral(impliesNode);
398
399
  // lit -> (a->b)
400
  // ~lit | ~ a | b
401
8536
  assertClause(impliesNode.negate(), ~impliesLit, ~a, b);
402
403
  // (a->b) -> lit
404
  // ~(~a | b) | lit
405
  // (a | l) & (~b | l)
406
8536
  assertClause(impliesNode, a, impliesLit);
407
8536
  assertClause(impliesNode, ~b, impliesLit);
408
8536
}
409
410
276016
void CnfStream::handleIff(TNode iffNode)
411
{
412
276016
  Assert(!hasLiteral(iffNode)) << "Atom already mapped!";
413
276016
  Assert(iffNode.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!";
414
276016
  Assert(iffNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
415
276016
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
416
276016
  Trace("cnf") << "handleIff(" << iffNode << ")\n";
417
418
  // Convert the children to CNF
419
276016
  SatLiteral a = getLiteral(iffNode[0]);
420
276016
  SatLiteral b = getLiteral(iffNode[1]);
421
422
  // Get the now literal
423
276016
  SatLiteral iffLit = newLiteral(iffNode);
424
425
  // lit -> ((a-> b) & (b->a))
426
  // ~lit | ((~a | b) & (~b | a))
427
  // (~a | b | ~lit) & (~b | a | ~lit)
428
276016
  assertClause(iffNode.negate(), ~a, b, ~iffLit);
429
276016
  assertClause(iffNode.negate(), a, ~b, ~iffLit);
430
431
  // (a<->b) -> lit
432
  // ~((a & b) | (~a & ~b)) | lit
433
  // (~(a & b)) & (~(~a & ~b)) | lit
434
  // ((~a | ~b) & (a | b)) | lit
435
  // (~a | ~b | lit) & (a | b | lit)
436
276016
  assertClause(iffNode, ~a, ~b, iffLit);
437
276016
  assertClause(iffNode, a, b, iffLit);
438
276016
}
439
440
83705
void CnfStream::handleIte(TNode iteNode)
441
{
442
83705
  Assert(!hasLiteral(iteNode)) << "Atom already mapped!";
443
83705
  Assert(iteNode.getKind() == kind::ITE);
444
83705
  Assert(iteNode.getNumChildren() == 3);
445
83705
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
446
167410
  Trace("cnf") << "handleIte(" << iteNode[0] << " " << iteNode[1] << " "
447
83705
               << iteNode[2] << ")\n";
448
449
83705
  SatLiteral condLit = getLiteral(iteNode[0]);
450
83705
  SatLiteral thenLit = getLiteral(iteNode[1]);
451
83705
  SatLiteral elseLit = getLiteral(iteNode[2]);
452
453
83705
  SatLiteral iteLit = newLiteral(iteNode);
454
455
  // If ITE is true then one of the branches is true and the condition
456
  // implies which one
457
  // lit -> (ite b t e)
458
  // lit -> (t | e) & (b -> t) & (!b -> e)
459
  // lit -> (t | e) & (!b | t) & (b | e)
460
  // (!lit | t | e) & (!lit | !b | t) & (!lit | b | e)
461
83705
  assertClause(iteNode.negate(), ~iteLit, thenLit, elseLit);
462
83705
  assertClause(iteNode.negate(), ~iteLit, ~condLit, thenLit);
463
83705
  assertClause(iteNode.negate(), ~iteLit, condLit, elseLit);
464
465
  // If ITE is false then one of the branches is false and the condition
466
  // implies which one
467
  // !lit -> !(ite b t e)
468
  // !lit -> (!t | !e) & (b -> !t) & (!b -> !e)
469
  // !lit -> (!t | !e) & (!b | !t) & (b | !e)
470
  // (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e)
471
83705
  assertClause(iteNode, iteLit, ~thenLit, ~elseLit);
472
83705
  assertClause(iteNode, iteLit, ~condLit, ~thenLit);
473
83705
  assertClause(iteNode, iteLit, condLit, ~elseLit);
474
83705
}
475
476
3022898
SatLiteral CnfStream::toCNF(TNode node, bool negated)
477
{
478
6045796
  Trace("cnf") << "toCNF(" << node
479
3022898
               << ", negated = " << (negated ? "true" : "false") << ")\n";
480
481
6045796
  TNode cur;
482
3022898
  SatLiteral nodeLit;
483
6045796
  std::vector<TNode> visit;
484
6045796
  std::unordered_map<TNode, bool> cache;
485
486
3022898
  visit.push_back(node);
487
24830594
  while (!visit.empty())
488
  {
489
10903852
    cur = visit.back();
490
10903852
    Assert(cur.getType().isBoolean());
491
492
16853049
    if (hasLiteral(cur))
493
    {
494
5949197
      visit.pop_back();
495
5949197
      continue;
496
    }
497
498
4954655
    const auto& it = cache.find(cur);
499
4954655
    if (it == cache.end())
500
    {
501
2581489
      cache.emplace(cur, false);
502
2581489
      Kind k = cur.getKind();
503
      // Only traverse Boolean nodes
504
4954662
      if (k == kind::NOT || k == kind::XOR || k == kind::ITE
505
2039621
          || k == kind::IMPLIES || k == kind::OR || k == kind::AND
506
3576761
          || (k == kind::EQUAL && cur[0].getType().isBoolean()))
507
      {
508
        // Preserve the order of the recursive version
509
7161698
        for (size_t i = 0, size = cur.getNumChildren(); i < size; ++i)
510
        {
511
5299465
          visit.push_back(cur[size - 1 - i]);
512
        }
513
      }
514
2581489
      continue;
515
    }
516
2373166
    else if (!it->second)
517
    {
518
2373166
      it->second = true;
519
2373166
      Kind k = cur.getKind();
520
2373166
      switch (k)
521
      {
522
        case kind::NOT: Assert(hasLiteral(cur[0])); break;
523
249847
        case kind::XOR: handleXor(cur); break;
524
83705
        case kind::ITE: handleIte(cur); break;
525
8536
        case kind::IMPLIES: handleImplies(cur); break;
526
391824
        case kind::OR: handleOr(cur); break;
527
643982
        case kind::AND: handleAnd(cur); break;
528
995272
        default:
529
995272
          if (k == kind::EQUAL && cur[0].getType().isBoolean())
530
          {
531
276016
            handleIff(cur);
532
          }
533
          else
534
          {
535
719260
            convertAtom(cur);
536
          }
537
995268
          break;
538
      }
539
    }
540
2373162
    visit.pop_back();
541
  }
542
543
3022894
  nodeLit = getLiteral(node);
544
6045788
  Trace("cnf") << "toCNF(): resulting literal: "
545
3022894
               << (!negated ? nodeLit : ~nodeLit) << "\n";
546
6045788
  return negated ? ~nodeLit : nodeLit;
547
}
548
549
118008
void CnfStream::convertAndAssertAnd(TNode node, bool negated)
550
{
551
118008
  Assert(node.getKind() == kind::AND);
552
236016
  Trace("cnf") << "CnfStream::convertAndAssertAnd(" << node
553
118008
               << ", negated = " << (negated ? "true" : "false") << ")\n";
554
118008
  if (!negated) {
555
    // If the node is a conjunction, we handle each conjunct separately
556
370983
    for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
557
370983
        conjunct != node_end; ++conjunct ) {
558
355565
      convertAndAssert(*conjunct, false);
559
    }
560
  } else {
561
    // If the node is a disjunction, we construct a clause and assert it
562
102588
    int nChildren = node.getNumChildren();
563
205176
    SatClause clause(nChildren);
564
102588
    TNode::const_iterator disjunct = node.begin();
565
1355556
    for(int i = 0; i < nChildren; ++ disjunct, ++ i) {
566
1252968
      Assert(disjunct != node.end());
567
1252968
      clause[i] = toCNF(*disjunct, true);
568
    }
569
102588
    Assert(disjunct == node.end());
570
102588
    assertClause(node.negate(), clause);
571
  }
572
118007
}
573
574
454479
void CnfStream::convertAndAssertOr(TNode node, bool negated)
575
{
576
454479
  Assert(node.getKind() == kind::OR);
577
908958
  Trace("cnf") << "CnfStream::convertAndAssertOr(" << node
578
454479
               << ", negated = " << (negated ? "true" : "false") << ")\n";
579
454479
  if (!negated) {
580
    // If the node is a disjunction, we construct a clause and assert it
581
454191
    int nChildren = node.getNumChildren();
582
908382
    SatClause clause(nChildren);
583
454191
    TNode::const_iterator disjunct = node.begin();
584
1807120
    for(int i = 0; i < nChildren; ++ disjunct, ++ i) {
585
1352929
      Assert(disjunct != node.end());
586
1352929
      clause[i] = toCNF(*disjunct, false);
587
    }
588
454191
    Assert(disjunct == node.end());
589
454191
    assertClause(node, clause);
590
  } else {
591
    // If the node is a conjunction, we handle each conjunct separately
592
1860
    for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
593
1860
        conjunct != node_end; ++conjunct ) {
594
1572
      convertAndAssert(*conjunct, true);
595
    }
596
  }
597
454479
}
598
599
49
void CnfStream::convertAndAssertXor(TNode node, bool negated)
600
{
601
49
  Assert(node.getKind() == kind::XOR);
602
98
  Trace("cnf") << "CnfStream::convertAndAssertXor(" << node
603
49
               << ", negated = " << (negated ? "true" : "false") << ")\n";
604
49
  if (!negated) {
605
    // p XOR q
606
49
    SatLiteral p = toCNF(node[0], false);
607
49
    SatLiteral q = toCNF(node[1], false);
608
    // Construct the clauses (p => !q) and (!q => p)
609
98
    SatClause clause1(2);
610
49
    clause1[0] = ~p;
611
49
    clause1[1] = ~q;
612
49
    assertClause(node, clause1);
613
98
    SatClause clause2(2);
614
49
    clause2[0] = p;
615
49
    clause2[1] = q;
616
49
    assertClause(node, clause2);
617
  } else {
618
    // !(p XOR q) is the same as p <=> q
619
    SatLiteral p = toCNF(node[0], false);
620
    SatLiteral q = toCNF(node[1], false);
621
    // Construct the clauses (p => q) and (q => p)
622
    SatClause clause1(2);
623
    clause1[0] = ~p;
624
    clause1[1] = q;
625
    assertClause(node.negate(), clause1);
626
    SatClause clause2(2);
627
    clause2[0] = p;
628
    clause2[1] = ~q;
629
    assertClause(node.negate(), clause2);
630
  }
631
49
}
632
633
16485
void CnfStream::convertAndAssertIff(TNode node, bool negated)
634
{
635
16485
  Assert(node.getKind() == kind::EQUAL);
636
32970
  Trace("cnf") << "CnfStream::convertAndAssertIff(" << node
637
16485
               << ", negated = " << (negated ? "true" : "false") << ")\n";
638
16485
  if (!negated) {
639
    // p <=> q
640
15943
    SatLiteral p = toCNF(node[0], false);
641
15943
    SatLiteral q = toCNF(node[1], false);
642
    // Construct the clauses (p => q) and (q => p)
643
31886
    SatClause clause1(2);
644
15943
    clause1[0] = ~p;
645
15943
    clause1[1] = q;
646
15943
    assertClause(node, clause1);
647
31886
    SatClause clause2(2);
648
15943
    clause2[0] = p;
649
15943
    clause2[1] = ~q;
650
15943
    assertClause(node, clause2);
651
  } else {
652
    // !(p <=> q) is the same as p XOR q
653
542
    SatLiteral p = toCNF(node[0], false);
654
542
    SatLiteral q = toCNF(node[1], false);
655
    // Construct the clauses (p => !q) and (!q => p)
656
1084
    SatClause clause1(2);
657
542
    clause1[0] = ~p;
658
542
    clause1[1] = ~q;
659
542
    assertClause(node.negate(), clause1);
660
1084
    SatClause clause2(2);
661
542
    clause2[0] = p;
662
542
    clause2[1] = q;
663
542
    assertClause(node.negate(), clause2);
664
  }
665
16485
}
666
667
62514
void CnfStream::convertAndAssertImplies(TNode node, bool negated)
668
{
669
62514
  Assert(node.getKind() == kind::IMPLIES);
670
125028
  Trace("cnf") << "CnfStream::convertAndAssertImplies(" << node
671
62514
               << ", negated = " << (negated ? "true" : "false") << ")\n";
672
62514
  if (!negated) {
673
    // p => q
674
62275
    SatLiteral p = toCNF(node[0], false);
675
62275
    SatLiteral q = toCNF(node[1], false);
676
    // Construct the clause ~p || q
677
124550
    SatClause clause(2);
678
62275
    clause[0] = ~p;
679
62275
    clause[1] = q;
680
62275
    assertClause(node, clause);
681
  } else {// Construct the
682
    // !(p => q) is the same as (p && ~q)
683
239
    convertAndAssert(node[0], false);
684
239
    convertAndAssert(node[1], true);
685
  }
686
62514
}
687
688
18674
void CnfStream::convertAndAssertIte(TNode node, bool negated)
689
{
690
18674
  Assert(node.getKind() == kind::ITE);
691
37348
  Trace("cnf") << "CnfStream::convertAndAssertIte(" << node
692
18674
               << ", negated = " << (negated ? "true" : "false") << ")\n";
693
  // ITE(p, q, r)
694
18674
  SatLiteral p = toCNF(node[0], false);
695
18674
  SatLiteral q = toCNF(node[1], negated);
696
18674
  SatLiteral r = toCNF(node[2], negated);
697
  // Construct the clauses:
698
  // (p => q) and (!p => r)
699
  //
700
  // Note that below q and r can be used directly because whether they are
701
  // negated has been push to the literal definitions above
702
37348
  Node nnode = node;
703
18674
  if( negated ){
704
69
    nnode = node.negate();
705
  }
706
37348
  SatClause clause1(2);
707
18674
  clause1[0] = ~p;
708
18674
  clause1[1] = q;
709
18674
  assertClause(nnode, clause1);
710
37348
  SatClause clause2(2);
711
18674
  clause2[0] = p;
712
18674
  clause2[1] = r;
713
18674
  assertClause(nnode, clause2);
714
18674
}
715
716
// At the top level we must ensure that all clauses that are asserted are
717
// not unit, except for the direct assertions. This allows us to remove the
718
// clauses later when they are not needed anymore (lemmas for example).
719
473566
void CnfStream::convertAndAssert(TNode node,
720
                                 bool removable,
721
                                 bool negated,
722
                                 bool input)
723
{
724
947132
  Trace("cnf") << "convertAndAssert(" << node
725
947132
               << ", negated = " << (negated ? "true" : "false")
726
473566
               << ", removable = " << (removable ? "true" : "false") << ")\n";
727
473566
  d_removable = removable;
728
947132
  TimerStat::CodeTimer codeTimer(d_stats.d_cnfConversionTime, true);
729
473570
  convertAndAssert(node, negated);
730
473562
}
731
732
883916
void CnfStream::convertAndAssert(TNode node, bool negated)
733
{
734
1767832
  Trace("cnf") << "convertAndAssert(" << node
735
883916
               << ", negated = " << (negated ? "true" : "false") << ")\n";
736
737
883916
  d_resourceManager->spendResource(Resource::CnfStep);
738
739
883916
  switch(node.getKind()) {
740
118009
    case kind::AND: convertAndAssertAnd(node, negated); break;
741
454479
    case kind::OR: convertAndAssertOr(node, negated); break;
742
49
    case kind::XOR: convertAndAssertXor(node, negated); break;
743
62514
    case kind::IMPLIES: convertAndAssertImplies(node, negated); break;
744
18674
    case kind::ITE: convertAndAssertIte(node, negated); break;
745
52738
    case kind::NOT: convertAndAssert(node[0], !negated); break;
746
86760
    case kind::EQUAL:
747
86760
      if (node[0].getType().isBoolean())
748
      {
749
16485
        convertAndAssertIff(node, negated);
750
16485
        break;
751
      }
752
      CVC5_FALLTHROUGH;
753
    default:
754
    {
755
321942
      Node nnode = node;
756
160971
      if (negated)
757
      {
758
48391
        nnode = node.negate();
759
      }
760
      // Atoms
761
321942
      assertClause(nnode, toCNF(node, negated));
762
  }
763
160967
    break;
764
  }
765
883909
}
766
767
16025
CnfStream::Statistics::Statistics(const std::string& name)
768
16025
    : d_cnfConversionTime(smtStatisticsRegistry().registerTimer(
769
16025
        name + "::CnfStream::cnfConversionTime"))
770
{
771
16025
}
772
773
}  // namespace prop
774
29280
}  // namespace cvc5