LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/preprocessing/util - boolean_simplification.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 62 70 88.6 %
Date: 2026-03-20 10:41:15 Functions: 7 7 100.0 %
Branches: 29 50 58.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                 :            :  * Simple, commonly-used routines for Boolean simplification.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "cvc5_private.h"
      14                 :            : 
      15                 :            : #ifndef CVC5__BOOLEAN_SIMPLIFICATION_H
      16                 :            : #define CVC5__BOOLEAN_SIMPLIFICATION_H
      17                 :            : 
      18                 :            : #include <algorithm>
      19                 :            : #include <vector>
      20                 :            : 
      21                 :            : #include "base/check.h"
      22                 :            : #include "expr/node.h"
      23                 :            : 
      24                 :            : namespace cvc5::internal {
      25                 :            : namespace preprocessing {
      26                 :            : 
      27                 :            : /**
      28                 :            :  * A class to contain a number of useful functions for simple
      29                 :            :  * simplification of nodes.  One never uses it as an object (and
      30                 :            :  * it cannot be constructed).  It is used as a namespace.
      31                 :            :  */
      32                 :            : class BooleanSimplification
      33                 :            : {
      34                 :            :   // cannot construct one of these
      35                 :            :   BooleanSimplification() = delete;
      36                 :            :   BooleanSimplification(const BooleanSimplification&) = delete;
      37                 :            : 
      38                 :            :   CVC5_WARN_UNUSED_RESULT static bool push_back_associative_commute_recursive(
      39                 :            :       Node n, std::vector<Node>& buffer, Kind k, Kind notK, bool negateNode);
      40                 :            : 
      41                 :            :  public:
      42                 :            :   /**
      43                 :            :    * The threshold for removing duplicates.  (See removeDuplicates().)
      44                 :            :    */
      45                 :            :   static const uint32_t DUPLICATE_REMOVAL_THRESHOLD = 10;
      46                 :            : 
      47                 :            :   /**
      48                 :            :    * Remove duplicate nodes from a vector, modifying it in-place.
      49                 :            :    * If the vector has size >= DUPLICATE_REMOVAL_THRESHOLD, this
      50                 :            :    * function is a no-op.
      51                 :            :    */
      52                 :        144 :   static void removeDuplicates(std::vector<Node>& buffer)
      53                 :            :   {
      54         [ +  - ]:        144 :     if (buffer.size() < DUPLICATE_REMOVAL_THRESHOLD)
      55                 :            :     {
      56                 :        144 :       std::sort(buffer.begin(), buffer.end());
      57                 :            :       std::vector<Node>::iterator new_end =
      58                 :        144 :           std::unique(buffer.begin(), buffer.end());
      59                 :        144 :       buffer.erase(new_end, buffer.end());
      60                 :            :     }
      61                 :        144 :   }
      62                 :            : 
      63                 :            :   /**
      64                 :            :    * Takes a node with kind AND, collapses all AND and (NOT OR)-kinded
      65                 :            :    * children of it (as far as possible---see
      66                 :            :    * push_back_associative_commute()), removes duplicates, and returns
      67                 :            :    * the resulting Node.
      68                 :            :    */
      69                 :        136 :   static Node simplifyConflict(Node andNode)
      70                 :            :   {
      71         [ -  + ]:        136 :     AssertArgument(!andNode.isNull(), andNode);
      72         [ +  + ]:        136 :     AssertArgument(andNode.getKind() == Kind::AND, andNode);
      73                 :            : 
      74                 :        135 :     std::vector<Node> buffer;
      75                 :        135 :     push_back_associative_commute(andNode, buffer, Kind::AND, Kind::OR);
      76                 :            : 
      77                 :        135 :     removeDuplicates(buffer);
      78                 :            : 
      79         [ -  + ]:        135 :     if (buffer.size() == 1)
      80                 :            :     {
      81                 :          0 :       return buffer[0];
      82                 :            :     }
      83                 :            : 
      84                 :        135 :     NodeBuilder nb(andNode.getNodeManager(), Kind::AND);
      85                 :        135 :     nb.append(buffer);
      86                 :        135 :     return nb;
      87                 :        135 :   }
      88                 :            : 
      89                 :            :   /**
      90                 :            :    * Takes a node with kind OR, collapses all OR and (NOT AND)-kinded
      91                 :            :    * children of it (as far as possible---see
      92                 :            :    * push_back_associative_commute()), removes duplicates, and returns
      93                 :            :    * the resulting Node.
      94                 :            :    */
      95                 :         10 :   static Node simplifyClause(Node orNode)
      96                 :            :   {
      97         [ -  + ]:         10 :     AssertArgument(!orNode.isNull(), orNode);
      98         [ +  + ]:         10 :     AssertArgument(orNode.getKind() == Kind::OR, orNode);
      99                 :            : 
     100                 :          9 :     std::vector<Node> buffer;
     101                 :          9 :     push_back_associative_commute(orNode, buffer, Kind::OR, Kind::AND);
     102                 :            : 
     103                 :          9 :     removeDuplicates(buffer);
     104                 :            : 
     105 [ -  + ][ -  + ]:          9 :     Assert(buffer.size() > 0);
                 [ -  - ]
     106         [ -  + ]:          9 :     if (buffer.size() == 1)
     107                 :            :     {
     108                 :          0 :       return buffer[0];
     109                 :            :     }
     110                 :            : 
     111                 :          9 :     NodeBuilder nb(orNode.getNodeManager(), Kind::OR);
     112                 :          9 :     nb.append(buffer);
     113                 :          9 :     return nb;
     114                 :          9 :   }
     115                 :            : 
     116                 :            :   /**
     117                 :            :    * Takes a node with kind IMPLIES, converts it to an OR, then
     118                 :            :    * simplifies the result with simplifyClause().
     119                 :            :    *
     120                 :            :    * The input doesn't actually have to be Horn, it seems, but that's
     121                 :            :    * the common case(?), hence the name.
     122                 :            :    */
     123                 :          5 :   static Node simplifyHornClause(Node implication)
     124                 :            :   {
     125         [ +  + ]:          5 :     AssertArgument(implication.getKind() == Kind::IMPLIES, implication);
     126                 :            : 
     127                 :          4 :     TNode left = implication[0];
     128                 :          4 :     TNode right = implication[1];
     129                 :            : 
     130                 :          4 :     Node notLeft = negate(left);
     131                 :          4 :     Node clause = NodeBuilder(implication.getNodeManager(), Kind::OR)
     132                 :          8 :                   << notLeft << right;
     133                 :            : 
     134                 :          8 :     return simplifyClause(clause);
     135                 :          4 :   }
     136                 :            : 
     137                 :            :   /**
     138                 :            :    * Aids in reforming a node.  Takes a node of (N-ary) kind k and
     139                 :            :    * copies its children into an output vector, collapsing its k-kinded
     140                 :            :    * children into it.  Also collapses negations of notK.  For example:
     141                 :            :    *
     142                 :            :    *   push_back_associative_commute( [OR [OR a b] [OR b c d] [NOT [AND e f]]],
     143                 :            :    *                                  buffer, Kind::OR, Kind::AND )
     144                 :            :    *   yields a "buffer" vector of [a b b c d e f]
     145                 :            :    *
     146                 :            :    * @param n the node to operate upon
     147                 :            :    * @param buffer the output vector (must be empty on entry)
     148                 :            :    * @param k the kind to collapse (should equal the kind of node n)
     149                 :            :    * @param notK the "negation" of kind k (e.g. OR's negation is AND),
     150                 :            :    * or Kind::UNDEFINED_KIND if none.
     151                 :            :    */
     152                 :        144 :   static inline void push_back_associative_commute(Node n,
     153                 :            :                                                    std::vector<Node>& buffer,
     154                 :            :                                                    Kind k,
     155                 :            :                                                    Kind notK)
     156                 :            :   {
     157         [ -  + ]:        144 :     AssertArgument(buffer.empty(), buffer);
     158         [ -  + ]:        144 :     AssertArgument(!n.isNull(), n);
     159 [ +  - ][ -  + ]:        144 :     AssertArgument(k != Kind::UNDEFINED_KIND && k != Kind::NULL_EXPR, k);
                 [ -  + ]
     160         [ -  + ]:        144 :     AssertArgument(notK != Kind::NULL_EXPR, notK);
     161         [ -  + ]:        144 :     AssertArgument(n.getKind() == k,
     162                 :            :                    n,
     163                 :            :                    "expected node to have kind %s",
     164                 :            :                    kindToString(k).c_str());
     165                 :            : 
     166                 :            :     bool b CVC5_UNUSED =
     167                 :        144 :         push_back_associative_commute_recursive(n, buffer, k, notK, false);
     168                 :            : 
     169         [ -  + ]:        144 :     if (buffer.size() == 0)
     170                 :            :     {
     171                 :            :       // all the TRUEs for an AND (resp FALSEs for an OR) were simplified away
     172                 :          0 :       buffer.push_back(
     173                 :          0 :           n.getNodeManager()->mkConst(k == Kind::AND ? true : false));
     174                 :            :     }
     175                 :        144 :   } /* push_back_associative_commute() */
     176                 :            : 
     177                 :            :   /**
     178                 :            :    * Negates a node, doing all the double-negation elimination
     179                 :            :    * that's possible.
     180                 :            :    *
     181                 :            :    * @param n the node to negate (cannot be the null node)
     182                 :            :    */
     183                 :         18 :   static Node negate(TNode n)
     184                 :            :   {
     185         [ +  + ]:         18 :     AssertArgument(!n.isNull(), n);
     186                 :            : 
     187                 :         17 :     bool polarity = true;
     188                 :         17 :     TNode base = n;
     189         [ +  + ]:         23 :     while (base.getKind() == Kind::NOT)
     190                 :            :     {
     191                 :          6 :       base = base[0];
     192                 :          6 :       polarity = !polarity;
     193                 :            :     }
     194         [ -  + ]:         17 :     if (n.isConst())
     195                 :            :     {
     196                 :          0 :       return n.getNodeManager()->mkConst(!n.getConst<bool>());
     197                 :            :     }
     198         [ +  + ]:         17 :     if (polarity)
     199                 :            :     {
     200                 :         15 :       return base.notNode();
     201                 :            :     }
     202                 :            :     else
     203                 :            :     {
     204                 :          2 :       return base;
     205                 :            :     }
     206                 :         17 :   }
     207                 :            : 
     208                 :            :   /**
     209                 :            :    * Simplify an OR, AND, or IMPLIES.  This function is the identity
     210                 :            :    * for all other kinds.
     211                 :            :    */
     212                 :        132 :   inline static Node simplify(TNode n)
     213                 :            :   {
     214 [ +  - ][ -  - ]:        132 :     switch (n.getKind())
     215                 :            :     {
     216                 :        132 :       case Kind::AND: return simplifyConflict(n);
     217                 :            : 
     218                 :          0 :       case Kind::OR: return simplifyClause(n);
     219                 :            : 
     220                 :          0 :       case Kind::IMPLIES: return simplifyHornClause(n);
     221                 :            : 
     222                 :          0 :       default: return n;
     223                 :            :     }
     224                 :            :   }
     225                 :            : 
     226                 :            : }; /* class BooleanSimplification */
     227                 :            : 
     228                 :            : }  // namespace preprocessing
     229                 :            : }  // namespace cvc5::internal
     230                 :            : 
     231                 :            : #endif /* CVC5__BOOLEAN_SIMPLIFICATION_H */

Generated by: LCOV version 1.14