GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/prop/cnf_stream.cpp Lines: 394 400 98.5 %
Date: 2021-11-07 Branches: 764 1943 39.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 "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/env.h"
30
#include "smt/smt_statistics_registry.h"
31
#include "smt/solver_engine_scope.h"
32
#include "theory/theory.h"
33
#include "theory/theory_engine.h"
34
35
namespace cvc5 {
36
namespace prop {
37
38
22653
CnfStream::CnfStream(SatSolver* satSolver,
39
                     Registrar* registrar,
40
                     context::Context* context,
41
                     Env* env,
42
                     ResourceManager* rm,
43
                     FormulaLitPolicy flpol,
44
22653
                     std::string name)
45
    : d_satSolver(satSolver),
46
      d_env(env),
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
      d_resourceManager(rm),
56
22653
      d_stats(name)
57
{
58
22653
}
59
60
9612516
bool CnfStream::assertClause(TNode node, SatClause& c)
61
{
62
9612516
  Trace("cnf") << "Inserting into stream " << c << " node = " << node << "\n";
63
64
9612516
  ClauseId clauseId = d_satSolver->addClause(c, d_removable);
65
66
9612516
  return clauseId != ClauseIdUndef;
67
}
68
69
250405
bool CnfStream::assertClause(TNode node, SatLiteral a)
70
{
71
500810
  SatClause clause(1);
72
250405
  clause[0] = a;
73
500810
  return assertClause(node, clause);
74
}
75
76
4559673
bool CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b)
77
{
78
9119346
  SatClause clause(2);
79
4559673
  clause[0] = a;
80
4559673
  clause[1] = b;
81
9119346
  return assertClause(node, clause);
82
}
83
84
2990647
bool CnfStream::assertClause(TNode node,
85
                             SatLiteral a,
86
                             SatLiteral b,
87
                             SatLiteral c)
88
{
89
5981294
  SatClause clause(3);
90
2990647
  clause[0] = a;
91
2990647
  clause[1] = b;
92
2990647
  clause[2] = c;
93
5981294
  return assertClause(node, clause);
94
}
95
96
75102036
bool CnfStream::hasLiteral(TNode n) const {
97
75102036
  NodeToLiteralMap::const_iterator find = d_nodeToLiteralMap.find(n);
98
75102036
  return find != d_nodeToLiteralMap.end();
99
}
100
101
2877749
void CnfStream::ensureMappingForLiteral(TNode n)
102
{
103
2877749
  SatLiteral lit = getLiteral(n);
104
2877749
  if (!d_literalToNodeMap.contains(lit))
105
  {
106
    // Store backward-mappings
107
262
    d_literalToNodeMap.insert(lit, n);
108
262
    d_literalToNodeMap.insert(~lit, n.notNode());
109
  }
110
2877749
}
111
112
2917329
void CnfStream::ensureLiteral(TNode n)
113
{
114
2917329
  AlwaysAssertArgument(
115
      hasLiteral(n) || n.getType().isBoolean(),
116
      n,
117
      "ProofCnfStream::ensureLiteral() requires a node of Boolean type.\n"
118
      "got node: %s\n"
119
      "its type: %s\n",
120
      n.toString().c_str(),
121
      n.getType().toString().c_str());
122
2917329
  Trace("cnf") << "ensureLiteral(" << n << ")\n";
123
2982630
  TimerStat::CodeTimer codeTimer(d_stats.d_cnfConversionTime, true);
124
2917329
  if (hasLiteral(n))
125
  {
126
2852028
    ensureMappingForLiteral(n);
127
2852028
    return;
128
  }
129
  // remove top level negation
130
65301
  n = n.getKind() == kind::NOT ? n[0] : n;
131
65301
  if (theory::Theory::theoryOf(n) == theory::THEORY_BOOL && !n.isVar())
132
  {
133
    // If we were called with something other than a theory atom (or
134
    // Boolean variable), we get a SatLiteral that is definitionally
135
    // equal to it.
136
    // These are not removable and have no proof ID
137
44645
    d_removable = false;
138
139
44645
    SatLiteral lit = toCNF(n, false);
140
141
    // Store backward-mappings
142
    // These may already exist
143
44645
    d_literalToNodeMap.insert_safe(lit, n);
144
44645
    d_literalToNodeMap.insert_safe(~lit, n.notNode());
145
  }
146
  else
147
  {
148
    // We have a theory atom or variable.
149
20656
    convertAtom(n);
150
  }
151
}
152
153
2794862
SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister, bool canEliminate) {
154
5589724
  Trace("cnf") << d_name << "::newLiteral(" << node << ", " << isTheoryAtom
155
2794862
               << ")\n"
156
2794862
               << push;
157
2794862
  Assert(node.getKind() != kind::NOT);
158
159
  // if we are tracking formulas, everything is a theory atom
160
2794862
  if (!isTheoryAtom && d_flitPolicy == FormulaLitPolicy::TRACK_AND_NOTIFY)
161
  {
162
    isTheoryAtom = true;
163
    d_notifyFormulas.insert(node);
164
  }
165
166
  // Get the literal for this node
167
2794862
  SatLiteral lit;
168
2794862
  if (!hasLiteral(node)) {
169
2794860
    Trace("cnf") << d_name << "::newLiteral: node already registered\n";
170
    // If no literal, we'll make one
171
2794860
    if (node.getKind() == kind::CONST_BOOLEAN) {
172
30898
      Trace("cnf") << d_name << "::newLiteral: boolean const\n";
173
30898
      if (node.getConst<bool>()) {
174
15385
        lit = SatLiteral(d_satSolver->trueVar());
175
      } else {
176
15513
        lit = SatLiteral(d_satSolver->falseVar());
177
      }
178
    } else {
179
2763962
      Trace("cnf") << d_name << "::newLiteral: new var\n";
180
2763962
      lit = SatLiteral(d_satSolver->newVar(isTheoryAtom, preRegister, canEliminate));
181
    }
182
2794860
    d_nodeToLiteralMap.insert(node, lit);
183
2794860
    d_nodeToLiteralMap.insert(node.notNode(), ~lit);
184
  } else {
185
2
    lit = getLiteral(node);
186
  }
187
188
  // If it's a theory literal, need to store it for back queries
189
2794862
  if (isTheoryAtom || d_flitPolicy == FormulaLitPolicy::TRACK)
190
  {
191
1509719
    d_literalToNodeMap.insert_safe(lit, node);
192
1509719
    d_literalToNodeMap.insert_safe(~lit, node.notNode());
193
  }
194
195
  // If a theory literal, we pre-register it
196
2794862
  if (preRegister) {
197
    // In case we are re-entered due to lemmas, save our state
198
859219
    bool backupRemovable = d_removable;
199
859223
    d_registrar->preRegister(node);
200
859215
    d_removable = backupRemovable;
201
  }
202
  // Here, you can have it
203
2794858
  Trace("cnf") << "newLiteral(" << node << ") => " << lit << "\n" << pop;
204
2794858
  return lit;
205
}
206
207
21780656
TNode CnfStream::getNode(const SatLiteral& literal) {
208
21780656
  Trace("cnf") << "getNode(" << literal << ")\n";
209
43561312
  Trace("cnf") << "getNode(" << literal << ") => "
210
21780656
               << d_literalToNodeMap[literal] << "\n";
211
21780656
  return d_literalToNodeMap[literal];
212
}
213
214
2590003
const CnfStream::NodeToLiteralMap& CnfStream::getTranslationCache() const
215
{
216
2590003
  return d_nodeToLiteralMap;
217
}
218
219
7394828
const CnfStream::LiteralToNodeMap& CnfStream::getNodeCache() const
220
{
221
7394828
  return d_literalToNodeMap;
222
}
223
224
24999
void CnfStream::getBooleanVariables(std::vector<TNode>& outputVariables) const {
225
24999
  context::CDList<TNode>::const_iterator it, it_end;
226
83126
  for (it = d_booleanVariables.begin(); it != d_booleanVariables.end(); ++ it) {
227
58127
    outputVariables.push_back(*it);
228
  }
229
24999
}
230
231
bool CnfStream::isNotifyFormula(TNode node) const
232
{
233
  return d_notifyFormulas.find(node) != d_notifyFormulas.end();
234
}
235
236
899007
SatLiteral CnfStream::convertAtom(TNode node)
237
{
238
899007
  Trace("cnf") << "convertAtom(" << node << ")\n";
239
240
899007
  Assert(!hasLiteral(node)) << "atom already mapped!";
241
242
899007
  bool theoryLiteral = false;
243
899007
  bool canEliminate = true;
244
899007
  bool preRegister = false;
245
246
  // Is this a variable add it to the list
247
899007
  if (node.isVar() && node.getKind() != kind::BOOLEAN_TERM_VARIABLE)
248
  {
249
39788
    d_booleanVariables.push_back(node);
250
  }
251
  else
252
  {
253
859219
    theoryLiteral = true;
254
859219
    canEliminate = false;
255
859219
    preRegister = true;
256
  }
257
258
  // Make a new literal (variables are not considered theory literals)
259
899011
  SatLiteral lit = newLiteral(node, theoryLiteral, preRegister, canEliminate);
260
  // Return the resulting literal
261
899003
  return lit;
262
}
263
264
53338268
SatLiteral CnfStream::getLiteral(TNode node) {
265
53338268
  Assert(!node.isNull()) << "CnfStream: can't getLiteral() of null node";
266
267
106676536
  Assert(d_nodeToLiteralMap.contains(node))
268
53338268
      << "Literal not in the CNF Cache: " << node << "\n";
269
270
53338268
  SatLiteral literal = d_nodeToLiteralMap[node];
271
106676536
  Trace("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal
272
53338268
               << "\n";
273
53338268
  return literal;
274
}
275
276
277835
void CnfStream::handleXor(TNode xorNode)
277
{
278
277835
  Assert(!hasLiteral(xorNode)) << "Atom already mapped!";
279
277835
  Assert(xorNode.getKind() == kind::XOR) << "Expecting an XOR expression!";
280
277835
  Assert(xorNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
281
277835
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
282
277835
  Trace("cnf") << "CnfStream::handleXor(" << xorNode << ")\n";
283
284
277835
  SatLiteral a = getLiteral(xorNode[0]);
285
277835
  SatLiteral b = getLiteral(xorNode[1]);
286
287
277835
  SatLiteral xorLit = newLiteral(xorNode);
288
289
277835
  assertClause(xorNode.negate(), a, b, ~xorLit);
290
277835
  assertClause(xorNode.negate(), ~a, ~b, ~xorLit);
291
277835
  assertClause(xorNode, a, ~b, xorLit);
292
277835
  assertClause(xorNode, ~a, b, xorLit);
293
277835
}
294
295
415044
void CnfStream::handleOr(TNode orNode)
296
{
297
415044
  Assert(!hasLiteral(orNode)) << "Atom already mapped!";
298
415044
  Assert(orNode.getKind() == kind::OR) << "Expecting an OR expression!";
299
415044
  Assert(orNode.getNumChildren() > 1) << "Expecting more then 1 child!";
300
415044
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
301
415044
  Trace("cnf") << "CnfStream::handleOr(" << orNode << ")\n";
302
303
  // Number of children
304
415044
  size_t numChildren = orNode.getNumChildren();
305
306
  // Get the literal for this node
307
415044
  SatLiteral orLit = newLiteral(orNode);
308
309
  // Transform all the children first
310
830088
  SatClause clause(numChildren + 1);
311
1448207
  for (size_t i = 0; i < numChildren; ++i)
312
  {
313
1033163
    clause[i] = getLiteral(orNode[i]);
314
315
    // lit <- (a_1 | a_2 | a_3 | ... | a_n)
316
    // lit | ~(a_1 | a_2 | a_3 | ... | a_n)
317
    // (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n)
318
1033163
    assertClause(orNode, orLit, ~clause[i]);
319
  }
320
321
  // lit -> (a_1 | a_2 | a_3 | ... | a_n)
322
  // ~lit | a_1 | a_2 | a_3 | ... | a_n
323
415044
  clause[numChildren] = ~orLit;
324
  // This needs to go last, as the clause might get modified by the SAT solver
325
415044
  assertClause(orNode.negate(), clause);
326
415044
}
327
328
700917
void CnfStream::handleAnd(TNode andNode)
329
{
330
700917
  Assert(!hasLiteral(andNode)) << "Atom already mapped!";
331
700917
  Assert(andNode.getKind() == kind::AND) << "Expecting an AND expression!";
332
700917
  Assert(andNode.getNumChildren() > 1) << "Expecting more than 1 child!";
333
700917
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
334
700917
  Trace("cnf") << "handleAnd(" << andNode << ")\n";
335
336
  // Number of children
337
700917
  size_t numChildren = andNode.getNumChildren();
338
339
  // Get the literal for this node
340
700917
  SatLiteral andLit = newLiteral(andNode);
341
342
  // Transform all the children first (remembering the negation)
343
1401834
  SatClause clause(numChildren + 1);
344
3941365
  for (size_t i = 0; i < numChildren; ++i)
345
  {
346
3240448
    clause[i] = ~getLiteral(andNode[i]);
347
348
    // lit -> (a_1 & a_2 & a_3 & ... & a_n)
349
    // ~lit | (a_1 & a_2 & a_3 & ... & a_n)
350
    // (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n)
351
3240448
    assertClause(andNode.negate(), ~andLit, ~clause[i]);
352
  }
353
354
  // lit <- (a_1 & a_2 & a_3 & ... a_n)
355
  // lit | ~(a_1 & a_2 & a_3 & ... & a_n)
356
  // lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n
357
700917
  clause[numChildren] = andLit;
358
  // This needs to go last, as the clause might get modified by the SAT solver
359
700917
  assertClause(andNode, clause);
360
700917
}
361
362
8515
void CnfStream::handleImplies(TNode impliesNode)
363
{
364
8515
  Assert(!hasLiteral(impliesNode)) << "Atom already mapped!";
365
8515
  Assert(impliesNode.getKind() == kind::IMPLIES)
366
      << "Expecting an IMPLIES expression!";
367
8515
  Assert(impliesNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
368
8515
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
369
8515
  Trace("cnf") << "handleImplies(" << impliesNode << ")\n";
370
371
  // Convert the children to cnf
372
8515
  SatLiteral a = getLiteral(impliesNode[0]);
373
8515
  SatLiteral b = getLiteral(impliesNode[1]);
374
375
8515
  SatLiteral impliesLit = newLiteral(impliesNode);
376
377
  // lit -> (a->b)
378
  // ~lit | ~ a | b
379
8515
  assertClause(impliesNode.negate(), ~impliesLit, ~a, b);
380
381
  // (a->b) -> lit
382
  // ~(~a | b) | lit
383
  // (a | l) & (~b | l)
384
8515
  assertClause(impliesNode, a, impliesLit);
385
8515
  assertClause(impliesNode, ~b, impliesLit);
386
8515
}
387
388
272569
void CnfStream::handleIff(TNode iffNode)
389
{
390
272569
  Assert(!hasLiteral(iffNode)) << "Atom already mapped!";
391
272569
  Assert(iffNode.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!";
392
272569
  Assert(iffNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
393
272569
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
394
272569
  Trace("cnf") << "handleIff(" << iffNode << ")\n";
395
396
  // Convert the children to CNF
397
272569
  SatLiteral a = getLiteral(iffNode[0]);
398
272569
  SatLiteral b = getLiteral(iffNode[1]);
399
400
  // Get the now literal
401
272569
  SatLiteral iffLit = newLiteral(iffNode);
402
403
  // lit -> ((a-> b) & (b->a))
404
  // ~lit | ((~a | b) & (~b | a))
405
  // (~a | b | ~lit) & (~b | a | ~lit)
406
272569
  assertClause(iffNode.negate(), ~a, b, ~iffLit);
407
272569
  assertClause(iffNode.negate(), a, ~b, ~iffLit);
408
409
  // (a<->b) -> lit
410
  // ~((a & b) | (~a & ~b)) | lit
411
  // (~(a & b)) & (~(~a & ~b)) | lit
412
  // ((~a | ~b) & (a | b)) | lit
413
  // (~a | ~b | lit) & (a | b | lit)
414
272569
  assertClause(iffNode, ~a, ~b, iffLit);
415
272569
  assertClause(iffNode, a, b, iffLit);
416
272569
}
417
418
99665
void CnfStream::handleIte(TNode iteNode)
419
{
420
99665
  Assert(!hasLiteral(iteNode)) << "Atom already mapped!";
421
99665
  Assert(iteNode.getKind() == kind::ITE);
422
99665
  Assert(iteNode.getNumChildren() == 3);
423
99665
  Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
424
199330
  Trace("cnf") << "handleIte(" << iteNode[0] << " " << iteNode[1] << " "
425
99665
               << iteNode[2] << ")\n";
426
427
99665
  SatLiteral condLit = getLiteral(iteNode[0]);
428
99665
  SatLiteral thenLit = getLiteral(iteNode[1]);
429
99665
  SatLiteral elseLit = getLiteral(iteNode[2]);
430
431
99665
  SatLiteral iteLit = newLiteral(iteNode);
432
433
  // If ITE is true then one of the branches is true and the condition
434
  // implies which one
435
  // lit -> (ite b t e)
436
  // lit -> (t | e) & (b -> t) & (!b -> e)
437
  // lit -> (t | e) & (!b | t) & (b | e)
438
  // (!lit | t | e) & (!lit | !b | t) & (!lit | b | e)
439
99665
  assertClause(iteNode.negate(), ~iteLit, thenLit, elseLit);
440
99665
  assertClause(iteNode.negate(), ~iteLit, ~condLit, thenLit);
441
99665
  assertClause(iteNode.negate(), ~iteLit, condLit, elseLit);
442
443
  // If ITE is false then one of the branches is false and the condition
444
  // implies which one
445
  // !lit -> !(ite b t e)
446
  // !lit -> (!t | !e) & (b -> !t) & (!b -> !e)
447
  // !lit -> (!t | !e) & (!b | !t) & (b | !e)
448
  // (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e)
449
99665
  assertClause(iteNode, iteLit, ~thenLit, ~elseLit);
450
99665
  assertClause(iteNode, iteLit, ~condLit, ~thenLit);
451
99665
  assertClause(iteNode, iteLit, condLit, ~elseLit);
452
99665
}
453
454
2756248
SatLiteral CnfStream::toCNF(TNode node, bool negated)
455
{
456
5512496
  Trace("cnf") << "toCNF(" << node
457
2756248
               << ", negated = " << (negated ? "true" : "false") << ")\n";
458
459
5512496
  TNode cur;
460
2756248
  SatLiteral nodeLit;
461
5512496
  std::vector<TNode> visit;
462
5512496
  std::unordered_map<TNode, bool> cache;
463
464
2756248
  visit.push_back(node);
465
25615576
  while (!visit.empty())
466
  {
467
11429668
    cur = visit.back();
468
11429668
    Assert(cur.getType().isBoolean());
469
470
17569514
    if (hasLiteral(cur))
471
    {
472
6139846
      visit.pop_back();
473
6139846
      continue;
474
    }
475
476
5289822
    const auto& it = cache.find(cur);
477
5289822
    if (it == cache.end())
478
    {
479
2757597
      cache.emplace(cur, false);
480
2757597
      Kind k = cur.getKind();
481
      // Only traverse Boolean nodes
482
5289829
      if (k == kind::NOT || k == kind::XOR || k == kind::ITE
483
2154732
          || k == kind::IMPLIES || k == kind::OR || k == kind::AND
484
3787846
          || (k == kind::EQUAL && cur[0].getType().isBoolean()))
485
      {
486
        // Preserve the order of the recursive version
487
7915740
        for (size_t i = 0, size = cur.getNumChildren(); i < size; ++i)
488
        {
489
5915823
          visit.push_back(cur[size - 1 - i]);
490
        }
491
      }
492
2757597
      continue;
493
    }
494
2532225
    else if (!it->second)
495
    {
496
2532225
      it->second = true;
497
2532225
      Kind k = cur.getKind();
498
2532225
      switch (k)
499
      {
500
        case kind::NOT: Assert(hasLiteral(cur[0])); break;
501
277835
        case kind::XOR: handleXor(cur); break;
502
99665
        case kind::ITE: handleIte(cur); break;
503
8515
        case kind::IMPLIES: handleImplies(cur); break;
504
415044
        case kind::OR: handleOr(cur); break;
505
700917
        case kind::AND: handleAnd(cur); break;
506
1030249
        default:
507
1030249
          if (k == kind::EQUAL && cur[0].getType().isBoolean())
508
          {
509
272569
            handleIff(cur);
510
          }
511
          else
512
          {
513
757684
            convertAtom(cur);
514
          }
515
1030245
          break;
516
      }
517
    }
518
2532221
    visit.pop_back();
519
  }
520
521
2756244
  nodeLit = getLiteral(node);
522
5512488
  Trace("cnf") << "toCNF(): resulting literal: "
523
2756244
               << (!negated ? nodeLit : ~nodeLit) << "\n";
524
5512488
  return negated ? ~nodeLit : nodeLit;
525
}
526
527
159105
void CnfStream::convertAndAssertAnd(TNode node, bool negated)
528
{
529
159105
  Assert(node.getKind() == kind::AND);
530
318210
  Trace("cnf") << "CnfStream::convertAndAssertAnd(" << node
531
159105
               << ", negated = " << (negated ? "true" : "false") << ")\n";
532
159105
  if (!negated) {
533
    // If the node is a conjunction, we handle each conjunct separately
534
151257
    for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
535
151257
        conjunct != node_end; ++conjunct ) {
536
133331
      convertAndAssert(*conjunct, false);
537
    }
538
  } else {
539
    // If the node is a disjunction, we construct a clause and assert it
540
141177
    int nChildren = node.getNumChildren();
541
282354
    SatClause clause(nChildren);
542
141177
    TNode::const_iterator disjunct = node.begin();
543
1689299
    for(int i = 0; i < nChildren; ++ disjunct, ++ i) {
544
1548122
      Assert(disjunct != node.end());
545
1548122
      clause[i] = toCNF(*disjunct, true);
546
    }
547
141177
    Assert(disjunct == node.end());
548
141177
    assertClause(node.negate(), clause);
549
  }
550
159104
}
551
552
234719
void CnfStream::convertAndAssertOr(TNode node, bool negated)
553
{
554
234719
  Assert(node.getKind() == kind::OR);
555
469438
  Trace("cnf") << "CnfStream::convertAndAssertOr(" << node
556
234719
               << ", negated = " << (negated ? "true" : "false") << ")\n";
557
234719
  if (!negated) {
558
    // If the node is a disjunction, we construct a clause and assert it
559
234528
    int nChildren = node.getNumChildren();
560
469056
    SatClause clause(nChildren);
561
234528
    TNode::const_iterator disjunct = node.begin();
562
968097
    for(int i = 0; i < nChildren; ++ disjunct, ++ i) {
563
733569
      Assert(disjunct != node.end());
564
733569
      clause[i] = toCNF(*disjunct, false);
565
    }
566
234528
    Assert(disjunct == node.end());
567
234528
    assertClause(node, clause);
568
  } else {
569
    // If the node is a conjunction, we handle each conjunct separately
570
1248
    for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
571
1248
        conjunct != node_end; ++conjunct ) {
572
1057
      convertAndAssert(*conjunct, true);
573
    }
574
  }
575
234719
}
576
577
53
void CnfStream::convertAndAssertXor(TNode node, bool negated)
578
{
579
53
  Assert(node.getKind() == kind::XOR);
580
106
  Trace("cnf") << "CnfStream::convertAndAssertXor(" << node
581
53
               << ", negated = " << (negated ? "true" : "false") << ")\n";
582
53
  if (!negated) {
583
    // p XOR q
584
51
    SatLiteral p = toCNF(node[0], false);
585
51
    SatLiteral q = toCNF(node[1], false);
586
    // Construct the clauses (p => !q) and (!q => p)
587
102
    SatClause clause1(2);
588
51
    clause1[0] = ~p;
589
51
    clause1[1] = ~q;
590
51
    assertClause(node, clause1);
591
102
    SatClause clause2(2);
592
51
    clause2[0] = p;
593
51
    clause2[1] = q;
594
51
    assertClause(node, clause2);
595
  } else {
596
    // !(p XOR q) is the same as p <=> q
597
2
    SatLiteral p = toCNF(node[0], false);
598
2
    SatLiteral q = toCNF(node[1], false);
599
    // Construct the clauses (p => q) and (q => p)
600
4
    SatClause clause1(2);
601
2
    clause1[0] = ~p;
602
2
    clause1[1] = q;
603
2
    assertClause(node.negate(), clause1);
604
4
    SatClause clause2(2);
605
2
    clause2[0] = p;
606
2
    clause2[1] = ~q;
607
2
    assertClause(node.negate(), clause2);
608
  }
609
53
}
610
611
17049
void CnfStream::convertAndAssertIff(TNode node, bool negated)
612
{
613
17049
  Assert(node.getKind() == kind::EQUAL);
614
34098
  Trace("cnf") << "CnfStream::convertAndAssertIff(" << node
615
17049
               << ", negated = " << (negated ? "true" : "false") << ")\n";
616
17049
  if (!negated) {
617
    // p <=> q
618
16512
    SatLiteral p = toCNF(node[0], false);
619
16512
    SatLiteral q = toCNF(node[1], false);
620
    // Construct the clauses (p => q) and (q => p)
621
33024
    SatClause clause1(2);
622
16512
    clause1[0] = ~p;
623
16512
    clause1[1] = q;
624
16512
    assertClause(node, clause1);
625
33024
    SatClause clause2(2);
626
16512
    clause2[0] = p;
627
16512
    clause2[1] = ~q;
628
16512
    assertClause(node, clause2);
629
  } else {
630
    // !(p <=> q) is the same as p XOR q
631
537
    SatLiteral p = toCNF(node[0], false);
632
537
    SatLiteral q = toCNF(node[1], false);
633
    // Construct the clauses (p => !q) and (!q => p)
634
1074
    SatClause clause1(2);
635
537
    clause1[0] = ~p;
636
537
    clause1[1] = ~q;
637
537
    assertClause(node.negate(), clause1);
638
1074
    SatClause clause2(2);
639
537
    clause2[0] = p;
640
537
    clause2[1] = q;
641
537
    assertClause(node.negate(), clause2);
642
  }
643
17049
}
644
645
72736
void CnfStream::convertAndAssertImplies(TNode node, bool negated)
646
{
647
72736
  Assert(node.getKind() == kind::IMPLIES);
648
145472
  Trace("cnf") << "CnfStream::convertAndAssertImplies(" << node
649
72736
               << ", negated = " << (negated ? "true" : "false") << ")\n";
650
72736
  if (!negated) {
651
    // p => q
652
72496
    SatLiteral p = toCNF(node[0], false);
653
72496
    SatLiteral q = toCNF(node[1], false);
654
    // Construct the clause ~p || q
655
144992
    SatClause clause(2);
656
72496
    clause[0] = ~p;
657
72496
    clause[1] = q;
658
72496
    assertClause(node, clause);
659
  } else {// Construct the
660
    // !(p => q) is the same as (p && ~q)
661
240
    convertAndAssert(node[0], false);
662
240
    convertAndAssert(node[1], true);
663
  }
664
72736
}
665
666
18879
void CnfStream::convertAndAssertIte(TNode node, bool negated)
667
{
668
18879
  Assert(node.getKind() == kind::ITE);
669
37758
  Trace("cnf") << "CnfStream::convertAndAssertIte(" << node
670
18879
               << ", negated = " << (negated ? "true" : "false") << ")\n";
671
  // ITE(p, q, r)
672
18879
  SatLiteral p = toCNF(node[0], false);
673
18879
  SatLiteral q = toCNF(node[1], negated);
674
18879
  SatLiteral r = toCNF(node[2], negated);
675
  // Construct the clauses:
676
  // (p => q) and (!p => r)
677
  //
678
  // Note that below q and r can be used directly because whether they are
679
  // negated has been push to the literal definitions above
680
37758
  Node nnode = node;
681
18879
  if( negated ){
682
73
    nnode = node.negate();
683
  }
684
37758
  SatClause clause1(2);
685
18879
  clause1[0] = ~p;
686
18879
  clause1[1] = q;
687
18879
  assertClause(nnode, clause1);
688
37758
  SatClause clause2(2);
689
18879
  clause2[0] = p;
690
18879
  clause2[1] = r;
691
18879
  assertClause(nnode, clause2);
692
18879
}
693
694
// At the top level we must ensure that all clauses that are asserted are
695
// not unit, except for the direct assertions. This allows us to remove the
696
// clauses later when they are not needed anymore (lemmas for example).
697
561753
void CnfStream::convertAndAssert(TNode node,
698
                                 bool removable,
699
                                 bool negated,
700
                                 bool input)
701
{
702
1123506
  Trace("cnf") << "convertAndAssert(" << node
703
1123506
               << ", negated = " << (negated ? "true" : "false")
704
561753
               << ", removable = " << (removable ? "true" : "false") << ")\n";
705
561753
  d_removable = removable;
706
1123506
  TimerStat::CodeTimer codeTimer(d_stats.d_cnfConversionTime, true);
707
561757
  convertAndAssert(node, negated);
708
561749
}
709
710
767584
void CnfStream::convertAndAssert(TNode node, bool negated)
711
{
712
1535168
  Trace("cnf") << "convertAndAssert(" << node
713
767584
               << ", negated = " << (negated ? "true" : "false") << ")\n";
714
715
767584
  d_resourceManager->spendResource(Resource::CnfStep);
716
717
767584
  switch(node.getKind()) {
718
159106
    case kind::AND: convertAndAssertAnd(node, negated); break;
719
234719
    case kind::OR: convertAndAssertOr(node, negated); break;
720
53
    case kind::XOR: convertAndAssertXor(node, negated); break;
721
72736
    case kind::IMPLIES: convertAndAssertImplies(node, negated); break;
722
18879
    case kind::ITE: convertAndAssertIte(node, negated); break;
723
70966
    case kind::NOT: convertAndAssert(node[0], !negated); break;
724
99459
    case kind::EQUAL:
725
99459
      if (node[0].getType().isBoolean())
726
      {
727
17049
        convertAndAssertIff(node, negated);
728
17049
        break;
729
      }
730
      CVC5_FALLTHROUGH;
731
    default:
732
    {
733
388158
      Node nnode = node;
734
194079
      if (negated)
735
      {
736
64729
        nnode = node.negate();
737
      }
738
      // Atoms
739
388158
      assertClause(nnode, toCNF(node, negated));
740
  }
741
194075
    break;
742
  }
743
767577
}
744
745
22653
CnfStream::Statistics::Statistics(const std::string& name)
746
22653
    : d_cnfConversionTime(smtStatisticsRegistry().registerTimer(
747
22653
        name + "::CnfStream::cnfConversionTime"))
748
{
749
22653
}
750
751
}  // namespace prop
752
31137
}  // namespace cvc5