LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/prop - cnf_stream.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 428 467 91.6 %
Date: 2026-04-08 10:18:47 Functions: 31 34 91.2 %
Branches: 213 453 47.0 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * A CNF converter that takes in asserts and has the side effect of given an
      11                 :            :  * equisatisfiable stream of assertions to PropEngine.
      12                 :            :  */
      13                 :            : #include "prop/cnf_stream.h"
      14                 :            : 
      15                 :            : #include "base/check.h"
      16                 :            : #include "base/output.h"
      17                 :            : #include "expr/node.h"
      18                 :            : #include "options/bv_options.h"
      19                 :            : #include "printer/printer.h"
      20                 :            : #include "proof/clause_id.h"
      21                 :            : #include "prop/minisat/minisat.h"
      22                 :            : #include "prop/prop_engine.h"
      23                 :            : #include "prop/theory_proxy.h"
      24                 :            : #include "smt/env.h"
      25                 :            : #include "theory/theory.h"
      26                 :            : #include "theory/theory_engine.h"
      27                 :            : 
      28                 :            : namespace cvc5::internal {
      29                 :            : namespace prop {
      30                 :            : 
      31                 :      91815 : CnfStream::CnfStream(Env& env,
      32                 :            :                      SatSolver* satSolver,
      33                 :            :                      Registrar* registrar,
      34                 :            :                      context::Context* c,
      35                 :            :                      FormulaLitPolicy flpol,
      36                 :      91815 :                      std::string name)
      37                 :            :     : EnvObj(env),
      38                 :      91815 :       d_satSolver(satSolver),
      39                 :          0 :       d_booleanVariables(c),
      40                 :      91815 :       d_notifyFormulas(c),
      41                 :      91815 :       d_nodeToLiteralMap(c),
      42                 :      91815 :       d_literalToNodeMap(c),
      43                 :      91815 :       d_flitPolicy(flpol),
      44                 :      91815 :       d_registrar(registrar),
      45                 :      91815 :       d_name(name),
      46                 :      91815 :       d_removable(false),
      47                 :     183630 :       d_stats(statisticsRegistry(), name)
      48                 :            : {
      49                 :      91815 : }
      50                 :            : 
      51                 :   12600361 : bool CnfStream::assertClause(TNode node, SatClause& c)
      52                 :            : {
      53         [ +  - ]:   12600361 :   Trace("cnf") << "Inserting into stream " << c << " node = " << node << "\n";
      54                 :            : 
      55                 :            :   // Filter out duplicate literals. Don't rely on the SAT solver to do it.
      56                 :            :   // The ProofCnfStream assumes this happens in every SAT solver implicitely.
      57                 :            :   // However, CaDiCaL generates additional proof steps if clauses with
      58                 :            :   // duplicate literals are added.
      59                 :   12600361 :   std::unordered_set<uint64_t> cache;
      60                 :   12600361 :   SatClause cl;
      61         [ +  + ]:   47806425 :   for (const auto& lit : c)
      62                 :            :   {
      63         [ +  + ]:   35206064 :     if (cache.insert(lit.toInt()).second)
      64                 :            :     {
      65                 :   35168294 :       cl.push_back(lit);
      66                 :            :     }
      67                 :            :   }
      68                 :            : 
      69                 :   12600361 :   ClauseId clauseId = d_satSolver->addClause(cl, d_removable);
      70                 :            : 
      71                 :   12600361 :   return clauseId != ClauseIdUndef;
      72                 :   12600361 : }
      73                 :            : 
      74                 :     441429 : bool CnfStream::assertClause(TNode node, SatLiteral a)
      75                 :            : {
      76                 :     441429 :   SatClause clause(1);
      77                 :     441429 :   clause[0] = a;
      78                 :     882858 :   return assertClause(node, clause);
      79                 :     441429 : }
      80                 :            : 
      81                 :    5840736 : bool CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b)
      82                 :            : {
      83                 :    5840736 :   SatClause clause(2);
      84                 :    5840736 :   clause[0] = a;
      85                 :    5840736 :   clause[1] = b;
      86                 :   11681472 :   return assertClause(node, clause);
      87                 :    5840736 : }
      88                 :            : 
      89                 :    3763925 : bool CnfStream::assertClause(TNode node,
      90                 :            :                              SatLiteral a,
      91                 :            :                              SatLiteral b,
      92                 :            :                              SatLiteral c)
      93                 :            : {
      94                 :    3763925 :   SatClause clause(3);
      95                 :    3763925 :   clause[0] = a;
      96                 :    3763925 :   clause[1] = b;
      97                 :    3763925 :   clause[2] = c;
      98                 :    7527850 :   return assertClause(node, clause);
      99                 :    3763925 : }
     100                 :            : 
     101                 :  122621138 : bool CnfStream::hasLiteral(TNode n) const
     102                 :            : {
     103                 :  122621138 :   NodeToLiteralMap::const_iterator find = d_nodeToLiteralMap.find(n);
     104                 :  122621138 :   return find != d_nodeToLiteralMap.end();
     105                 :            : }
     106                 :            : 
     107                 :    8152759 : void CnfStream::ensureMappingForLiteral(TNode n)
     108                 :            : {
     109                 :    8152759 :   SatLiteral lit = getLiteral(n);
     110         [ +  + ]:    8152759 :   if (!d_literalToNodeMap.contains(lit))
     111                 :            :   {
     112                 :            :     // Store backward-mappings
     113                 :        443 :     d_literalToNodeMap.insert(lit, n);
     114                 :        443 :     d_literalToNodeMap.insert(~lit, n.notNode());
     115                 :            :   }
     116                 :    8152759 : }
     117                 :            : 
     118                 :    7948563 : void CnfStream::ensureLiteral(TNode n)
     119                 :            : {
     120                 :    7948563 :   AlwaysAssertArgument(
     121                 :            :       hasLiteral(n) || n.getType().isBoolean(),
     122                 :            :       n,
     123                 :            :       "ProofCnfStream::ensureLiteral() requires a node of Boolean type.\n"
     124                 :            :       "got node: %s\n"
     125                 :            :       "its type: %s\n",
     126                 :            :       n.toString().c_str(),
     127                 :            :       n.getType().toString().c_str());
     128         [ +  - ]:    7948563 :   Trace("cnf") << "ensureLiteral(" << n << ")\n";
     129                 :    7948563 :   TimerStat::CodeTimer codeTimer(d_stats.d_cnfConversionTime, true);
     130         [ +  + ]:    7948563 :   if (hasLiteral(n))
     131                 :            :   {
     132                 :    7899289 :     ensureMappingForLiteral(n);
     133                 :    7899289 :     return;
     134                 :            :   }
     135                 :            :   // remove top level negation
     136         [ +  + ]:      49274 :   n = n.getKind() == Kind::NOT ? n[0] : n;
     137 [ +  + ][ +  + ]:      49274 :   if (d_env.theoryOf(n) == theory::THEORY_BOOL && !n.isVar())
         [ +  - ][ +  + ]
                 [ -  - ]
     138                 :            :   {
     139                 :            :     // If we were called with something other than a theory atom (or
     140                 :            :     // Boolean variable), we get a SatLiteral that is definitionally
     141                 :            :     // equal to it.
     142                 :            :     // These are not removable and have no proof ID
     143                 :      37628 :     d_removable = false;
     144                 :            : 
     145                 :      37628 :     SatLiteral lit = toCNF(n, false);
     146                 :            : 
     147                 :            :     // Store backward-mappings
     148                 :            :     // These may already exist
     149                 :      37628 :     d_literalToNodeMap.insert_safe(lit, n);
     150                 :      37628 :     d_literalToNodeMap.insert_safe(~lit, n.notNode());
     151                 :            :   }
     152                 :            :   else
     153                 :            :   {
     154                 :            :     // We have a theory atom or variable.
     155                 :      11646 :     convertAtom(n);
     156                 :            :   }
     157         [ +  + ]:    7948563 : }
     158                 :            : 
     159                 :    3832855 : SatLiteral CnfStream::newLiteral(TNode node,
     160                 :            :                                  bool isTheoryAtom,
     161                 :            :                                  bool notifyTheory,
     162                 :            :                                  bool canEliminate)
     163                 :            : {
     164         [ +  - ]:    7665710 :   Trace("cnf") << d_name << "::newLiteral(" << node << ", " << isTheoryAtom
     165                 :          0 :                << ")\n"
     166                 :    3832855 :                << push;
     167 [ -  + ][ -  + ]:    3832855 :   Assert(node.getKind() != Kind::NOT);
                 [ -  - ]
     168                 :            : 
     169                 :            :   // if we are tracking formulas, everything is a theory atom
     170 [ +  + ][ -  + ]:    3832855 :   if (!isTheoryAtom && d_flitPolicy == FormulaLitPolicy::TRACK_AND_NOTIFY)
     171                 :            :   {
     172                 :          0 :     isTheoryAtom = true;
     173                 :          0 :     d_notifyFormulas.insert(node);
     174                 :            :   }
     175                 :            : 
     176                 :            :   // Get the literal for this node
     177                 :    3832855 :   SatLiteral lit;
     178         [ +  + ]:    3832855 :   if (!hasLiteral(node))
     179                 :            :   {
     180         [ +  - ]:    3832850 :     Trace("cnf") << d_name << "::newLiteral: node already registered\n";
     181                 :            :     // If no literal, we'll make one
     182         [ +  + ]:    3832850 :     if (node.getKind() == Kind::CONST_BOOLEAN)
     183                 :            :     {
     184         [ +  - ]:      64198 :       Trace("cnf") << d_name << "::newLiteral: boolean const\n";
     185         [ +  + ]:      64198 :       if (node.getConst<bool>())
     186                 :            :       {
     187                 :      39368 :         lit = SatLiteral(d_satSolver->trueVar());
     188                 :            :       }
     189                 :            :       else
     190                 :            :       {
     191                 :      24830 :         lit = SatLiteral(d_satSolver->falseVar());
     192                 :            :       }
     193                 :            :     }
     194                 :            :     else
     195                 :            :     {
     196         [ +  - ]:    3768652 :       Trace("cnf") << d_name << "::newLiteral: new var\n";
     197                 :    3768652 :       lit = SatLiteral(d_satSolver->newVar(isTheoryAtom, canEliminate));
     198                 :    3768652 :       d_stats.d_numAtoms++;
     199                 :            :     }
     200                 :    3832850 :     d_nodeToLiteralMap.insert(node, lit);
     201                 :    3832850 :     d_nodeToLiteralMap.insert(node.notNode(), ~lit);
     202                 :            :   }
     203                 :            :   else
     204                 :            :   {
     205         [ +  - ]:          5 :     Trace("cnf") << d_name << "::newLiteral: node already registered\n";
     206                 :          5 :     lit = getLiteral(node);
     207                 :            :   }
     208                 :            : 
     209                 :            :   // If it's a theory literal, need to store it for back queries
     210 [ +  + ][ +  + ]:    3832855 :   if (isTheoryAtom || d_flitPolicy == FormulaLitPolicy::TRACK
     211         [ -  + ]:    1458141 :       || d_flitPolicy == FormulaLitPolicy::TRACK_AND_NOTIFY_VAR)
     212                 :            :   {
     213                 :    2374714 :     d_literalToNodeMap.insert_safe(lit, node);
     214                 :    2374714 :     d_literalToNodeMap.insert_safe(~lit, node.notNode());
     215                 :            :   }
     216                 :            : 
     217                 :            :   // If a theory literal, we pre-register it
     218         [ +  + ]:    3832855 :   if (notifyTheory)
     219                 :            :   {
     220                 :            :     // In case we are re-entered due to lemmas, save our state
     221                 :    1432060 :     bool backupRemovable = d_removable;
     222                 :    1432076 :     d_registrar->notifySatLiteral(node);
     223                 :    1432044 :     d_removable = backupRemovable;
     224                 :            :   }
     225                 :            :   // Here, you can have it
     226         [ +  - ]:    3832839 :   Trace("cnf") << "newLiteral(" << node << ") => " << lit << "\n" << pop;
     227                 :    3832839 :   return lit;
     228                 :            : }
     229                 :            : 
     230                 :   69788632 : TNode CnfStream::getNode(const SatLiteral& literal)
     231                 :            : {
     232 [ -  + ][ -  + ]:   69788632 :   Assert(d_literalToNodeMap.find(literal) != d_literalToNodeMap.end());
                 [ -  - ]
     233         [ +  - ]:   69788632 :   Trace("cnf") << "getNode(" << literal << ")\n";
     234         [ +  - ]:  139577264 :   Trace("cnf") << "getNode(" << literal << ") => "
     235                 :   69788632 :                << d_literalToNodeMap[literal] << "\n";
     236                 :   69788632 :   return d_literalToNodeMap[literal];
     237                 :            : }
     238                 :            : 
     239                 :    2062692 : const CnfStream::NodeToLiteralMap& CnfStream::getTranslationCache() const
     240                 :            : {
     241                 :    2062692 :   return d_nodeToLiteralMap;
     242                 :            : }
     243                 :            : 
     244                 :    9744838 : const CnfStream::LiteralToNodeMap& CnfStream::getNodeCache() const
     245                 :            : {
     246                 :    9744838 :   return d_literalToNodeMap;
     247                 :            : }
     248                 :            : 
     249                 :      35499 : void CnfStream::getBooleanVariables(std::vector<TNode>& outputVariables) const
     250                 :            : {
     251                 :      35499 :   outputVariables.insert(outputVariables.end(),
     252                 :            :                          d_booleanVariables.begin(),
     253                 :            :                          d_booleanVariables.end());
     254                 :      35499 : }
     255                 :            : 
     256                 :          0 : bool CnfStream::isNotifyFormula(TNode node) const
     257                 :            : {
     258                 :          0 :   return d_notifyFormulas.find(node) != d_notifyFormulas.end();
     259                 :            : }
     260                 :            : 
     261                 :    1475787 : SatLiteral CnfStream::convertAtom(TNode node)
     262                 :            : {
     263         [ +  - ]:    1475787 :   Trace("cnf") << "convertAtom(" << node << ")\n";
     264                 :            : 
     265 [ -  + ][ -  + ]:    1475787 :   Assert(!hasLiteral(node)) << "atom already mapped!";
                 [ -  - ]
     266                 :            : 
     267                 :    1475787 :   bool theoryLiteral = false;
     268                 :    1475787 :   bool canEliminate = true;
     269                 :    1475787 :   bool preRegister = false;
     270                 :            : 
     271                 :            :   // Is this a variable add it to the list. We distinguish whether a Boolean
     272                 :            :   // variable has been marked as a "Boolean term skolem". These variables are
     273                 :            :   // introduced by the term formula removal pass (term_formula_removal.h)
     274                 :            :   // and maintained by Env (smt/env.h). We treat such variables as theory atoms
     275                 :            :   // since they may occur in term positions and thus need to be considered e.g.
     276                 :            :   // for theory combination.
     277                 :    1475787 :   bool isInternalBoolVar = false;
     278         [ +  + ]:    1475787 :   if (node.isVar())
     279                 :            :   {
     280                 :      47206 :     isInternalBoolVar = !d_env.isBooleanTermSkolem(node);
     281                 :            :   }
     282         [ +  + ]:    1475787 :   if (isInternalBoolVar)
     283                 :            :   {
     284                 :      43727 :     d_booleanVariables.push_back(node);
     285                 :            :     // if TRACK_AND_NOTIFY_VAR, we are notified when Boolean variables are
     286                 :            :     // asserted. Thus, they are marked as theory literals.
     287         [ -  + ]:      43727 :     if (d_flitPolicy == FormulaLitPolicy::TRACK_AND_NOTIFY_VAR)
     288                 :            :     {
     289                 :          0 :       theoryLiteral = true;
     290                 :            :     }
     291                 :            :   }
     292                 :            :   else
     293                 :            :   {
     294                 :    1432060 :     theoryLiteral = true;
     295                 :    1432060 :     canEliminate = false;
     296                 :    1432060 :     preRegister = true;
     297                 :            :   }
     298                 :            : 
     299                 :            :   // Make a new literal (variables are not considered theory literals)
     300                 :    1475803 :   SatLiteral lit = newLiteral(node, theoryLiteral, preRegister, canEliminate);
     301                 :            :   // Return the resulting literal
     302                 :    1475771 :   return lit;
     303                 :            : }
     304                 :            : 
     305                 :   99188079 : SatLiteral CnfStream::getLiteral(TNode node)
     306                 :            : {
     307 [ -  + ][ -  + ]:   99188079 :   Assert(!node.isNull()) << "CnfStream: can't getLiteral() of null node";
                 [ -  - ]
     308                 :            : 
     309 [ -  + ][ -  - ]:  198376158 :   Assert(d_nodeToLiteralMap.contains(node))
     310 [ -  + ][ -  + ]:   99188079 :       << "Literal not in the CNF Cache: " << node << "\n";
                 [ -  - ]
     311                 :            : 
     312                 :   99188079 :   SatLiteral literal = d_nodeToLiteralMap[node];
     313         [ +  - ]:  198376158 :   Trace("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal
     314                 :   99188079 :                << "\n";
     315                 :   99188079 :   return literal;
     316                 :            : }
     317                 :            : 
     318                 :     292883 : void CnfStream::handleXor(TNode xorNode)
     319                 :            : {
     320 [ -  + ][ -  + ]:     292883 :   Assert(!hasLiteral(xorNode)) << "Atom already mapped!";
                 [ -  - ]
     321 [ -  + ][ -  + ]:     292883 :   Assert(xorNode.getKind() == Kind::XOR) << "Expecting an XOR expression!";
                 [ -  - ]
     322 [ -  + ][ -  + ]:     292883 :   Assert(xorNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
                 [ -  - ]
     323 [ -  + ][ -  + ]:     292883 :   Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
                 [ -  - ]
     324         [ +  - ]:     292883 :   Trace("cnf") << "CnfStream::handleXor(" << xorNode << ")\n";
     325                 :            : 
     326                 :     292883 :   SatLiteral a = getLiteral(xorNode[0]);
     327                 :     292883 :   SatLiteral b = getLiteral(xorNode[1]);
     328                 :            : 
     329                 :     292883 :   SatLiteral xorLit = newLiteral(xorNode);
     330                 :            : 
     331                 :     292883 :   assertClause(xorNode.negate(), a, b, ~xorLit);
     332                 :     292883 :   assertClause(xorNode.negate(), ~a, ~b, ~xorLit);
     333                 :     292883 :   assertClause(xorNode, a, ~b, xorLit);
     334                 :     292883 :   assertClause(xorNode, ~a, b, xorLit);
     335                 :     292883 : }
     336                 :            : 
     337                 :     346555 : void CnfStream::handleOr(TNode orNode)
     338                 :            : {
     339 [ -  + ][ -  + ]:     346555 :   Assert(!hasLiteral(orNode)) << "Atom already mapped!";
                 [ -  - ]
     340 [ -  + ][ -  + ]:     346555 :   Assert(orNode.getKind() == Kind::OR) << "Expecting an OR expression!";
                 [ -  - ]
     341 [ -  + ][ -  + ]:     346555 :   Assert(orNode.getNumChildren() > 1) << "Expecting more then 1 child!";
                 [ -  - ]
     342 [ -  + ][ -  + ]:     346555 :   Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
                 [ -  - ]
     343         [ +  - ]:     346555 :   Trace("cnf") << "CnfStream::handleOr(" << orNode << ")\n";
     344                 :            : 
     345                 :            :   // Number of children
     346                 :     346555 :   size_t numChildren = orNode.getNumChildren();
     347                 :            : 
     348                 :            :   // Get the literal for this node
     349                 :     346555 :   SatLiteral orLit = newLiteral(orNode);
     350                 :            : 
     351                 :            :   // Transform all the children first
     352                 :     346555 :   SatClause clause(numChildren + 1);
     353         [ +  + ]:    1260532 :   for (size_t i = 0; i < numChildren; ++i)
     354                 :            :   {
     355                 :     913977 :     clause[i] = getLiteral(orNode[i]);
     356                 :            : 
     357                 :            :     // lit <- (a_1 | a_2 | a_3 | ... | a_n)
     358                 :            :     // lit | ~(a_1 | a_2 | a_3 | ... | a_n)
     359                 :            :     // (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n)
     360                 :     913977 :     assertClause(orNode, orLit, ~clause[i]);
     361                 :            :   }
     362                 :            : 
     363                 :            :   // lit -> (a_1 | a_2 | a_3 | ... | a_n)
     364                 :            :   // ~lit | a_1 | a_2 | a_3 | ... | a_n
     365                 :     346555 :   clause[numChildren] = ~orLit;
     366                 :            :   // This needs to go last, as the clause might get modified by the SAT solver
     367                 :     346555 :   assertClause(orNode.negate(), clause);
     368                 :     346555 : }
     369                 :            : 
     370                 :     685239 : void CnfStream::handleAnd(TNode andNode)
     371                 :            : {
     372 [ -  + ][ -  + ]:     685239 :   Assert(!hasLiteral(andNode)) << "Atom already mapped!";
                 [ -  - ]
     373 [ -  + ][ -  + ]:     685239 :   Assert(andNode.getKind() == Kind::AND) << "Expecting an AND expression!";
                 [ -  - ]
     374 [ -  + ][ -  + ]:     685239 :   Assert(andNode.getNumChildren() > 1) << "Expecting more than 1 child!";
                 [ -  - ]
     375 [ -  + ][ -  + ]:     685239 :   Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
                 [ -  - ]
     376         [ +  - ]:     685239 :   Trace("cnf") << "handleAnd(" << andNode << ")\n";
     377                 :            : 
     378                 :            :   // Number of children
     379                 :     685239 :   size_t numChildren = andNode.getNumChildren();
     380                 :            : 
     381                 :            :   // Get the literal for this node
     382                 :     685239 :   SatLiteral andLit = newLiteral(andNode);
     383                 :            : 
     384                 :            :   // Transform all the children first (remembering the negation)
     385                 :     685239 :   SatClause clause(numChildren + 1);
     386         [ +  + ]:    3976079 :   for (size_t i = 0; i < numChildren; ++i)
     387                 :            :   {
     388                 :    3290840 :     clause[i] = ~getLiteral(andNode[i]);
     389                 :            : 
     390                 :            :     // lit -> (a_1 & a_2 & a_3 & ... & a_n)
     391                 :            :     // ~lit | (a_1 & a_2 & a_3 & ... & a_n)
     392                 :            :     // (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n)
     393                 :    3290840 :     assertClause(andNode.negate(), ~andLit, ~clause[i]);
     394                 :            :   }
     395                 :            : 
     396                 :            :   // lit <- (a_1 & a_2 & a_3 & ... a_n)
     397                 :            :   // lit | ~(a_1 & a_2 & a_3 & ... & a_n)
     398                 :            :   // lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n
     399                 :     685239 :   clause[numChildren] = andLit;
     400                 :            :   // This needs to go last, as the clause might get modified by the SAT solver
     401                 :     685239 :   assertClause(andNode, clause);
     402                 :     685239 : }
     403                 :            : 
     404                 :       2717 : void CnfStream::handleImplies(TNode impliesNode)
     405                 :            : {
     406 [ -  + ][ -  + ]:       2717 :   Assert(!hasLiteral(impliesNode)) << "Atom already mapped!";
                 [ -  - ]
     407 [ -  + ][ -  + ]:       2717 :   Assert(impliesNode.getKind() == Kind::IMPLIES)
                 [ -  - ]
     408                 :          0 :       << "Expecting an IMPLIES expression!";
     409 [ -  + ][ -  + ]:       2717 :   Assert(impliesNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
                 [ -  - ]
     410 [ -  + ][ -  + ]:       2717 :   Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
                 [ -  - ]
     411         [ +  - ]:       2717 :   Trace("cnf") << "handleImplies(" << impliesNode << ")\n";
     412                 :            : 
     413                 :            :   // Convert the children to cnf
     414                 :       2717 :   SatLiteral a = getLiteral(impliesNode[0]);
     415                 :       2717 :   SatLiteral b = getLiteral(impliesNode[1]);
     416                 :            : 
     417                 :       2717 :   SatLiteral impliesLit = newLiteral(impliesNode);
     418                 :            : 
     419                 :            :   // lit -> (a->b)
     420                 :            :   // ~lit | ~ a | b
     421                 :       2717 :   assertClause(impliesNode.negate(), ~impliesLit, ~a, b);
     422                 :            : 
     423                 :            :   // (a->b) -> lit
     424                 :            :   // ~(~a | b) | lit
     425                 :            :   // (a | l) & (~b | l)
     426                 :       2717 :   assertClause(impliesNode, a, impliesLit);
     427                 :       2717 :   assertClause(impliesNode, ~b, impliesLit);
     428                 :       2717 : }
     429                 :            : 
     430                 :     257622 : void CnfStream::handleIff(TNode iffNode)
     431                 :            : {
     432 [ -  + ][ -  + ]:     257622 :   Assert(!hasLiteral(iffNode)) << "Atom already mapped!";
                 [ -  - ]
     433 [ -  + ][ -  + ]:     257622 :   Assert(iffNode.getKind() == Kind::EQUAL) << "Expecting an EQUAL expression!";
                 [ -  - ]
     434 [ -  + ][ -  + ]:     257622 :   Assert(iffNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
                 [ -  - ]
     435 [ -  + ][ -  + ]:     257622 :   Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
                 [ -  - ]
     436         [ +  - ]:     257622 :   Trace("cnf") << "handleIff(" << iffNode << ")\n";
     437                 :            : 
     438                 :            :   // Convert the children to CNF
     439                 :     257622 :   SatLiteral a = getLiteral(iffNode[0]);
     440                 :     257622 :   SatLiteral b = getLiteral(iffNode[1]);
     441                 :            : 
     442                 :            :   // Get the now literal
     443                 :     257622 :   SatLiteral iffLit = newLiteral(iffNode);
     444                 :            : 
     445                 :            :   // lit -> ((a-> b) & (b->a))
     446                 :            :   // ~lit | ((~a | b) & (~b | a))
     447                 :            :   // (~a | b | ~lit) & (~b | a | ~lit)
     448                 :     257622 :   assertClause(iffNode.negate(), ~a, b, ~iffLit);
     449                 :     257622 :   assertClause(iffNode.negate(), a, ~b, ~iffLit);
     450                 :            : 
     451                 :            :   // (a<->b) -> lit
     452                 :            :   // ~((a & b) | (~a & ~b)) | lit
     453                 :            :   // (~(a & b)) & (~(~a & ~b)) | lit
     454                 :            :   // ((~a | ~b) & (a | b)) | lit
     455                 :            :   // (~a | ~b | lit) & (a | b | lit)
     456                 :     257622 :   assertClause(iffNode, ~a, ~b, iffLit);
     457                 :     257622 :   assertClause(iffNode, a, b, iffLit);
     458                 :     257622 : }
     459                 :            : 
     460                 :     103393 : void CnfStream::handleIte(TNode iteNode)
     461                 :            : {
     462 [ -  + ][ -  + ]:     103393 :   Assert(!hasLiteral(iteNode)) << "Atom already mapped!";
                 [ -  - ]
     463 [ -  + ][ -  + ]:     103393 :   Assert(iteNode.getKind() == Kind::ITE);
                 [ -  - ]
     464 [ -  + ][ -  + ]:     103393 :   Assert(iteNode.getNumChildren() == 3);
                 [ -  - ]
     465 [ -  + ][ -  + ]:     103393 :   Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
                 [ -  - ]
     466                 :     206786 :   Trace("cnf") << "handleIte(" << iteNode[0] << " " << iteNode[1] << " "
     467 [ -  + ][ -  + ]:     103393 :                << iteNode[2] << ")\n";
                 [ -  - ]
     468                 :            : 
     469                 :     103393 :   SatLiteral condLit = getLiteral(iteNode[0]);
     470                 :     103393 :   SatLiteral thenLit = getLiteral(iteNode[1]);
     471                 :     103393 :   SatLiteral elseLit = getLiteral(iteNode[2]);
     472                 :            : 
     473                 :     103393 :   SatLiteral iteLit = newLiteral(iteNode);
     474                 :            : 
     475                 :            :   // If ITE is true then one of the branches is true and the condition
     476                 :            :   // implies which one
     477                 :            :   // lit -> (ite b t e)
     478                 :            :   // lit -> (t | e) & (b -> t) & (!b -> e)
     479                 :            :   // lit -> (t | e) & (!b | t) & (b | e)
     480                 :            :   // (!lit | t | e) & (!lit | !b | t) & (!lit | b | e)
     481                 :     103393 :   assertClause(iteNode.negate(), ~iteLit, thenLit, elseLit);
     482                 :     103393 :   assertClause(iteNode.negate(), ~iteLit, ~condLit, thenLit);
     483                 :     103393 :   assertClause(iteNode.negate(), ~iteLit, condLit, elseLit);
     484                 :            : 
     485                 :            :   // If ITE is false then one of the branches is false and the condition
     486                 :            :   // implies which one
     487                 :            :   // !lit -> !(ite b t e)
     488                 :            :   // !lit -> (!t | !e) & (b -> !t) & (!b -> !e)
     489                 :            :   // !lit -> (!t | !e) & (!b | !t) & (b | !e)
     490                 :            :   // (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e)
     491                 :     103393 :   assertClause(iteNode, iteLit, ~thenLit, ~elseLit);
     492                 :     103393 :   assertClause(iteNode, iteLit, ~condLit, ~thenLit);
     493                 :     103393 :   assertClause(iteNode, iteLit, condLit, ~elseLit);
     494                 :     103393 : }
     495                 :            : 
     496                 :    2285102 : SatLiteral CnfStream::toCNF(TNode node, bool negated)
     497                 :            : {
     498         [ +  - ]:    4570204 :   Trace("cnf") << "toCNF(" << node
     499         [ -  - ]:    2285102 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     500                 :            : 
     501                 :    2285102 :   TNode cur;
     502                 :    2285102 :   SatLiteral nodeLit;
     503                 :    2285102 :   std::vector<TNode> visit;
     504                 :    2285102 :   std::unordered_map<TNode, bool> cache;
     505                 :            : 
     506                 :    2285102 :   visit.push_back(node);
     507         [ +  + ]:   12893884 :   while (!visit.empty())
     508                 :            :   {
     509                 :   10608798 :     cur = visit.back();
     510 [ -  + ][ -  + ]:   10608798 :     Assert(cur.getType().isBoolean());
                 [ -  - ]
     511                 :            : 
     512         [ +  + ]:   10608798 :     if (hasLiteral(cur))
     513                 :            :     {
     514                 :    5754968 :       visit.pop_back();
     515                 :    8273662 :       continue;
     516                 :            :     }
     517                 :            : 
     518                 :    4853830 :     const auto& it = cache.find(cur);
     519         [ +  + ]:    4853830 :     if (it == cache.end())
     520                 :            :     {
     521                 :    2518694 :       cache.emplace(cur, false);
     522                 :    2518694 :       Kind k = cur.getKind();
     523                 :            :       // Only traverse Boolean nodes
     524 [ +  + ][ +  + ]:    2335140 :       if (k == Kind::NOT || k == Kind::XOR || k == Kind::ITE
     525 [ +  + ][ +  + ]:    1938864 :           || k == Kind::IMPLIES || k == Kind::OR || k == Kind::AND
                 [ +  + ]
     526                 :    4853834 :           || (k == Kind::EQUAL && cur[0].getType().isBoolean()))
     527                 :            :       {
     528                 :            :         // Preserve the order of the recursive version
     529         [ +  + ]:    7676969 :         for (size_t i = 0, size = cur.getNumChildren(); i < size; ++i)
     530                 :            :         {
     531                 :    5805002 :           visit.push_back(cur[size - 1 - i]);
     532                 :            :         }
     533                 :            :       }
     534                 :    2518694 :       continue;
     535                 :    2518694 :     }
     536         [ +  - ]:    2335136 :     else if (!it->second)
     537                 :            :     {
     538                 :    2335136 :       it->second = true;
     539                 :    2335136 :       Kind k = cur.getKind();
     540 [ -  + ][ +  + ]:    2335136 :       switch (k)
            [ +  + ][ + ]
     541                 :            :       {
     542                 :          0 :         case Kind::NOT: Assert(hasLiteral(cur[0])); break;
     543                 :     292883 :         case Kind::XOR: handleXor(cur); break;
     544                 :     103393 :         case Kind::ITE: handleIte(cur); break;
     545                 :       2717 :         case Kind::IMPLIES: handleImplies(cur); break;
     546                 :     346555 :         case Kind::OR: handleOr(cur); break;
     547                 :     685239 :         case Kind::AND: handleAnd(cur); break;
     548                 :     904349 :         default:
     549                 :     904349 :           if (k == Kind::EQUAL && cur[0].getType().isBoolean())
     550                 :            :           {
     551                 :     257622 :             handleIff(cur);
     552                 :            :           }
     553                 :            :           else
     554                 :            :           {
     555                 :     646743 :             convertAtom(cur);
     556                 :            :           }
     557                 :     904333 :           break;
     558                 :            :       }
     559                 :            :     }
     560                 :    2335120 :     visit.pop_back();
     561                 :            :   }
     562                 :            : 
     563                 :    2285086 :   nodeLit = getLiteral(node);
     564         [ +  - ]:    4570172 :   Trace("cnf") << "toCNF(): resulting literal: "
     565         [ -  - ]:    2285086 :                << (!negated ? nodeLit : ~nodeLit) << "\n";
     566         [ +  + ]:    4570172 :   return negated ? ~nodeLit : nodeLit;
     567                 :    2285134 : }
     568                 :            : 
     569                 :     101075 : void CnfStream::convertAndAssertAnd(TNode node, bool negated)
     570                 :            : {
     571 [ -  + ][ -  + ]:     101075 :   Assert(node.getKind() == Kind::AND);
                 [ -  - ]
     572         [ +  - ]:     202150 :   Trace("cnf") << "CnfStream::convertAndAssertAnd(" << node
     573         [ -  - ]:     101075 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     574         [ +  + ]:     101075 :   if (!negated)
     575                 :            :   {
     576                 :            :     // If the node is a conjunction, we handle each conjunct separately
     577                 :      14467 :     for (TNode::const_iterator conjunct = node.begin(), node_end = node.end();
     578         [ +  + ]:      51891 :          conjunct != node_end;
     579                 :      37424 :          ++conjunct)
     580                 :            :     {
     581                 :      37428 :       convertAndAssert(*conjunct, false);
     582                 :            :     }
     583                 :            :   }
     584                 :            :   else
     585                 :            :   {
     586                 :            :     // If the node is a disjunction, we construct a clause and assert it
     587                 :      86608 :     int nChildren = node.getNumChildren();
     588                 :      86608 :     SatClause clause(nChildren);
     589                 :      86608 :     TNode::const_iterator disjunct = node.begin();
     590         [ +  + ]:    1258969 :     for (int i = 0; i < nChildren; ++disjunct, ++i)
     591                 :            :     {
     592 [ -  + ][ -  + ]:    1172361 :       Assert(disjunct != node.end());
                 [ -  - ]
     593                 :    1172361 :       clause[i] = toCNF(*disjunct, true);
     594                 :            :     }
     595 [ -  + ][ -  + ]:      86608 :     Assert(disjunct == node.end());
                 [ -  - ]
     596                 :      86608 :     assertClause(node.negate(), clause);
     597                 :      86608 :   }
     598                 :     101073 : }
     599                 :            : 
     600                 :     232129 : void CnfStream::convertAndAssertOr(TNode node, bool negated)
     601                 :            : {
     602 [ -  + ][ -  + ]:     232129 :   Assert(node.getKind() == Kind::OR);
                 [ -  - ]
     603         [ +  - ]:     464258 :   Trace("cnf") << "CnfStream::convertAndAssertOr(" << node
     604         [ -  - ]:     232129 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     605         [ +  + ]:     232129 :   if (!negated)
     606                 :            :   {
     607                 :            :     // If the node is a disjunction, we construct a clause and assert it
     608                 :     231923 :     int nChildren = node.getNumChildren();
     609                 :     231923 :     SatClause clause(nChildren);
     610                 :     231923 :     TNode::const_iterator disjunct = node.begin();
     611         [ +  + ]:     890771 :     for (int i = 0; i < nChildren; ++disjunct, ++i)
     612                 :            :     {
     613 [ -  + ][ -  + ]:     658848 :       Assert(disjunct != node.end());
                 [ -  - ]
     614                 :     658848 :       clause[i] = toCNF(*disjunct, false);
     615                 :            :     }
     616 [ -  + ][ -  + ]:     231923 :     Assert(disjunct == node.end());
                 [ -  - ]
     617                 :     231923 :     assertClause(node, clause);
     618                 :     231923 :   }
     619                 :            :   else
     620                 :            :   {
     621                 :            :     // If the node is a conjunction, we handle each conjunct separately
     622                 :        206 :     for (TNode::const_iterator conjunct = node.begin(), node_end = node.end();
     623         [ +  + ]:       1272 :          conjunct != node_end;
     624                 :       1066 :          ++conjunct)
     625                 :            :     {
     626                 :       1066 :       convertAndAssert(*conjunct, true);
     627                 :            :     }
     628                 :            :   }
     629                 :     232129 : }
     630                 :            : 
     631                 :         70 : void CnfStream::convertAndAssertXor(TNode node, bool negated)
     632                 :            : {
     633 [ -  + ][ -  + ]:         70 :   Assert(node.getKind() == Kind::XOR);
                 [ -  - ]
     634         [ +  - ]:        140 :   Trace("cnf") << "CnfStream::convertAndAssertXor(" << node
     635         [ -  - ]:         70 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     636         [ +  + ]:         70 :   if (!negated)
     637                 :            :   {
     638                 :            :     // p XOR q
     639                 :         66 :     SatLiteral p = toCNF(node[0], false);
     640                 :         66 :     SatLiteral q = toCNF(node[1], false);
     641                 :            :     // Construct the clauses (p => !q) and (!q => p)
     642                 :         66 :     SatClause clause1(2);
     643                 :         66 :     clause1[0] = ~p;
     644                 :         66 :     clause1[1] = ~q;
     645                 :         66 :     assertClause(node, clause1);
     646                 :         66 :     SatClause clause2(2);
     647                 :         66 :     clause2[0] = p;
     648                 :         66 :     clause2[1] = q;
     649                 :         66 :     assertClause(node, clause2);
     650                 :         66 :   }
     651                 :            :   else
     652                 :            :   {
     653                 :            :     // !(p XOR q) is the same as p <=> q
     654                 :          4 :     SatLiteral p = toCNF(node[0], false);
     655                 :          4 :     SatLiteral q = toCNF(node[1], false);
     656                 :            :     // Construct the clauses (p => q) and (q => p)
     657                 :          4 :     SatClause clause1(2);
     658                 :          4 :     clause1[0] = ~p;
     659                 :          4 :     clause1[1] = q;
     660                 :          4 :     assertClause(node.negate(), clause1);
     661                 :          4 :     SatClause clause2(2);
     662                 :          4 :     clause2[0] = p;
     663                 :          4 :     clause2[1] = ~q;
     664                 :          4 :     assertClause(node.negate(), clause2);
     665                 :          4 :   }
     666                 :         70 : }
     667                 :            : 
     668                 :       8069 : void CnfStream::convertAndAssertIff(TNode node, bool negated)
     669                 :            : {
     670 [ -  + ][ -  + ]:       8069 :   Assert(node.getKind() == Kind::EQUAL);
                 [ -  - ]
     671         [ +  - ]:      16138 :   Trace("cnf") << "CnfStream::convertAndAssertIff(" << node
     672         [ -  - ]:       8069 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     673         [ +  + ]:       8069 :   if (!negated)
     674                 :            :   {
     675                 :            :     // p <=> q
     676                 :       7657 :     SatLiteral p = toCNF(node[0], false);
     677                 :       7657 :     SatLiteral q = toCNF(node[1], false);
     678                 :            :     // Construct the clauses (p => q) and (q => p)
     679                 :       7657 :     SatClause clause1(2);
     680                 :       7657 :     clause1[0] = ~p;
     681                 :       7657 :     clause1[1] = q;
     682                 :       7657 :     assertClause(node, clause1);
     683                 :       7657 :     SatClause clause2(2);
     684                 :       7657 :     clause2[0] = p;
     685                 :       7657 :     clause2[1] = ~q;
     686                 :       7657 :     assertClause(node, clause2);
     687                 :       7657 :   }
     688                 :            :   else
     689                 :            :   {
     690                 :            :     // !(p <=> q) is the same as p XOR q
     691                 :        412 :     SatLiteral p = toCNF(node[0], false);
     692                 :        412 :     SatLiteral q = toCNF(node[1], false);
     693                 :            :     // Construct the clauses (p => !q) and (!q => p)
     694                 :        412 :     SatClause clause1(2);
     695                 :        412 :     clause1[0] = ~p;
     696                 :        412 :     clause1[1] = ~q;
     697                 :        412 :     assertClause(node.negate(), clause1);
     698                 :        412 :     SatClause clause2(2);
     699                 :        412 :     clause2[0] = p;
     700                 :        412 :     clause2[1] = q;
     701                 :        412 :     assertClause(node.negate(), clause2);
     702                 :        412 :   }
     703                 :       8069 : }
     704                 :            : 
     705                 :      60870 : void CnfStream::convertAndAssertImplies(TNode node, bool negated)
     706                 :            : {
     707 [ -  + ][ -  + ]:      60870 :   Assert(node.getKind() == Kind::IMPLIES);
                 [ -  - ]
     708         [ +  - ]:     121740 :   Trace("cnf") << "CnfStream::convertAndAssertImplies(" << node
     709         [ -  - ]:      60870 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     710         [ +  + ]:      60870 :   if (!negated)
     711                 :            :   {
     712                 :            :     // p => q
     713                 :      60683 :     SatLiteral p = toCNF(node[0], false);
     714                 :      60683 :     SatLiteral q = toCNF(node[1], false);
     715                 :            :     // Construct the clause ~p || q
     716                 :      60683 :     SatClause clause(2);
     717                 :      60683 :     clause[0] = ~p;
     718                 :      60683 :     clause[1] = q;
     719                 :      60683 :     assertClause(node, clause);
     720                 :      60683 :   }
     721                 :            :   else
     722                 :            :   {  // Construct the
     723                 :            :     // !(p => q) is the same as (p && ~q)
     724                 :        187 :     convertAndAssert(node[0], false);
     725                 :        187 :     convertAndAssert(node[1], true);
     726                 :            :   }
     727                 :      60870 : }
     728                 :            : 
     729                 :      20165 : void CnfStream::convertAndAssertIte(TNode node, bool negated)
     730                 :            : {
     731 [ -  + ][ -  + ]:      20165 :   Assert(node.getKind() == Kind::ITE);
                 [ -  - ]
     732         [ +  - ]:      40330 :   Trace("cnf") << "CnfStream::convertAndAssertIte(" << node
     733         [ -  - ]:      20165 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     734                 :            :   // ITE(p, q, r)
     735                 :      20165 :   SatLiteral p = toCNF(node[0], false);
     736                 :      20165 :   SatLiteral q = toCNF(node[1], negated);
     737                 :      20165 :   SatLiteral r = toCNF(node[2], negated);
     738                 :            :   // Construct the clauses:
     739                 :            :   // (p => q) and (!p => r)
     740                 :            :   //
     741                 :            :   // Note that below q and r can be used directly because whether they are
     742                 :            :   // negated has been push to the literal definitions above
     743                 :      20165 :   Node nnode = node;
     744         [ +  + ]:      20165 :   if (negated)
     745                 :            :   {
     746                 :         88 :     nnode = node.negate();
     747                 :            :   }
     748                 :      20165 :   SatClause clause1(2);
     749                 :      20165 :   clause1[0] = ~p;
     750                 :      20165 :   clause1[1] = q;
     751                 :      20165 :   assertClause(nnode, clause1);
     752                 :      20165 :   SatClause clause2(2);
     753                 :      20165 :   clause2[0] = p;
     754                 :      20165 :   clause2[1] = r;
     755                 :      20165 :   assertClause(nnode, clause2);
     756                 :      20165 : }
     757                 :            : 
     758                 :            : // At the top level we must ensure that all clauses that are asserted are
     759                 :            : // not unit, except for the direct assertions. This allows us to remove the
     760                 :            : // clauses later when they are not needed anymore (lemmas for example).
     761                 :     601638 : void CnfStream::convertAndAssert(TNode node, bool removable, bool negated)
     762                 :            : {
     763         [ +  - ]:    1203276 :   Trace("cnf") << "convertAndAssert(" << node
     764         [ -  - ]:          0 :                << ", negated = " << (negated ? "true" : "false")
     765         [ -  - ]:     601638 :                << ", removable = " << (removable ? "true" : "false") << ")\n";
     766                 :     601638 :   d_removable = removable;
     767                 :     601638 :   TimerStat::CodeTimer codeTimer(d_stats.d_cnfConversionTime, true);
     768                 :     601654 :   convertAndAssert(node, negated);
     769                 :     601638 : }
     770                 :            : 
     771                 :     674528 : void CnfStream::convertAndAssert(TNode node, bool negated)
     772                 :            : {
     773         [ +  - ]:    1349056 :   Trace("cnf") << "convertAndAssert(" << node
     774         [ -  - ]:     674528 :                << ", negated = " << (negated ? "true" : "false") << ")\n";
     775                 :            : 
     776                 :     674528 :   resourceManager()->spendResource(Resource::CnfStep);
     777                 :            : 
     778 [ +  + ][ +  + ]:     674528 :   switch (node.getKind())
         [ +  + ][ +  + ]
     779                 :            :   {
     780                 :     101077 :     case Kind::AND: convertAndAssertAnd(node, negated); break;
     781                 :     232129 :     case Kind::OR: convertAndAssertOr(node, negated); break;
     782                 :         70 :     case Kind::XOR: convertAndAssertXor(node, negated); break;
     783                 :      60870 :     case Kind::IMPLIES: convertAndAssertImplies(node, negated); break;
     784                 :      20165 :     case Kind::ITE: convertAndAssertIte(node, negated); break;
     785                 :      34034 :     case Kind::NOT: convertAndAssert(node[0], !negated); break;
     786                 :      66629 :     case Kind::EQUAL:
     787         [ +  + ]:      66629 :       if (node[0].getType().isBoolean())
     788                 :            :       {
     789                 :       8069 :         convertAndAssertIff(node, negated);
     790                 :       8069 :         break;
     791                 :            :       }
     792                 :            :       CVC5_FALLTHROUGH;
     793                 :            :     default:
     794                 :            :     {
     795                 :     218126 :       Node nnode = node;
     796         [ +  + ]:     218126 :       if (negated)
     797                 :            :       {
     798                 :      28035 :         nnode = node.negate();
     799                 :            :       }
     800                 :            :       // Atoms
     801                 :     218142 :       assertClause(nnode, toCNF(node, negated));
     802                 :     218126 :     }
     803                 :     218110 :     break;
     804                 :            :   }
     805                 :     674500 : }
     806                 :            : 
     807                 :      91815 : CnfStream::Statistics::Statistics(StatisticsRegistry& sr,
     808                 :      91815 :                                   const std::string& name)
     809                 :            :     : d_cnfConversionTime(
     810                 :      91815 :           sr.registerTimer(name + "::CnfStream::cnfConversionTime")),
     811                 :      91815 :       d_numAtoms(sr.registerInt(name + "::CnfStream::numAtoms"))
     812                 :            : {
     813                 :      91815 : }
     814                 :            : 
     815                 :          0 : void CnfStream::dumpDimacs(std::ostream& out, const std::vector<Node>& clauses)
     816                 :            : {
     817                 :          0 :   std::vector<Node> auxUnits;
     818                 :          0 :   dumpDimacs(out, clauses, auxUnits);
     819                 :          0 : }
     820                 :            : 
     821                 :          0 : void CnfStream::dumpDimacs(std::ostream& out,
     822                 :            :                            const std::vector<Node>& clauses,
     823                 :            :                            const std::vector<Node>& auxUnits)
     824                 :            : {
     825                 :          0 :   std::stringstream dclauses;
     826                 :          0 :   SatVariable maxVar = 0;
     827         [ -  - ]:          0 :   for (size_t j = 0; j < 2; j++)
     828                 :            :   {
     829         [ -  - ]:          0 :     const std::vector<Node>& cls = j == 0 ? clauses : auxUnits;
     830         [ -  - ]:          0 :     for (const Node& i : cls)
     831                 :            :     {
     832                 :          0 :       std::vector<Node> lits;
     833                 :          0 :       if (j == 0 && i.getKind() == Kind::OR)
     834                 :            :       {
     835                 :            :         // print as clause if not an auxiliary unit
     836                 :          0 :         lits.insert(lits.end(), i.begin(), i.end());
     837                 :            :       }
     838                 :            :       else
     839                 :            :       {
     840                 :          0 :         lits.push_back(i);
     841                 :            :       }
     842         [ -  - ]:          0 :       Trace("dimacs-debug") << "Print " << i << std::endl;
     843         [ -  - ]:          0 :       for (const Node& l : lits)
     844                 :            :       {
     845                 :          0 :         bool negated = l.getKind() == Kind::NOT;
     846         [ -  - ]:          0 :         const Node& atom = negated ? l[0] : l;
     847                 :          0 :         SatLiteral lit = getLiteral(atom);
     848                 :          0 :         SatVariable v = lit.getSatVariable();
     849         [ -  - ]:          0 :         maxVar = v > maxVar ? v : maxVar;
     850         [ -  - ]:          0 :         dclauses << (negated ? "-" : "") << v << " ";
     851                 :          0 :       }
     852                 :          0 :       dclauses << "0" << std::endl;
     853                 :          0 :     }
     854                 :            :   }
     855                 :            : 
     856                 :          0 :   out << "p cnf " << maxVar << " " << (clauses.size() + auxUnits.size())
     857                 :          0 :       << std::endl;
     858                 :          0 :   out << dclauses.str();
     859                 :          0 : }
     860                 :            : 
     861                 :            : }  // namespace prop
     862                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14