LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/bv/bitblast - bitblast_utils.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 97 111 87.4 %
Date: 2026-08-31 23:16:50 Functions: 21 22 95.5 %
Branches: 62 110 56.4 %

           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                 :            :  * Various utility functions for bit-blasting.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "cvc5_private.h"
      14                 :            : 
      15                 :            : #ifndef CVC5__THEORY__BV__BITBLAST__BITBLAST_UTILS_H
      16                 :            : #define CVC5__THEORY__BV__BITBLAST__BITBLAST_UTILS_H
      17                 :            : 
      18                 :            : #include <ostream>
      19                 :            : 
      20                 :            : #include "expr/node.h"
      21                 :            : 
      22                 :            : namespace cvc5::internal {
      23                 :            : namespace theory {
      24                 :            : namespace bv {
      25                 :            : 
      26                 :            : template <class T>
      27                 :            : class TBitblaster;
      28                 :            : 
      29                 :            : template <class T>
      30                 :            : std::string toString(const std::vector<T>& bits);
      31                 :            : 
      32                 :            : template <>
      33                 :          0 : inline std::string toString<Node>(const std::vector<Node>& bits)
      34                 :            : {
      35                 :          0 :   std::ostringstream os;
      36         [ -  - ]:          0 :   for (int i = bits.size() - 1; i >= 0; --i)
      37                 :            :   {
      38                 :          0 :     TNode bit = bits[i];
      39         [ -  - ]:          0 :     if (bit.getKind() == Kind::CONST_BOOLEAN)
      40                 :            :     {
      41         [ -  - ]:          0 :       os << (bit.getConst<bool>() ? "1" : "0");
      42                 :            :     }
      43                 :            :     else
      44                 :            :     {
      45                 :          0 :       os << bit << " ";
      46                 :            :     }
      47                 :          0 :   }
      48                 :          0 :   os << "\n";
      49                 :          0 :   return os.str();
      50                 :          0 : }
      51                 :            : 
      52                 :            : template <class T>
      53                 :            : T mkTrue(NodeManager* nm);
      54                 :            : template <class T>
      55                 :            : T mkFalse(NodeManager* nm);
      56                 :            : template <class T>
      57                 :            : T mkNot(T a);
      58                 :            : template <class T>
      59                 :            : T mkOr(T a, T b);
      60                 :            : template <std::size_t N>
      61                 :            : Node mkOr(const TNode (&children)[N]);
      62                 :            : template <class T>
      63                 :            : T mkOr(NodeManager* nm, const std::vector<T>& a);
      64                 :            : template <class T>
      65                 :            : T mkAnd(T a, T b);
      66                 :            : template <std::size_t N>
      67                 :            : Node mkAnd(const TNode (&children)[N]);
      68                 :            : template <class T>
      69                 :            : T mkAnd(NodeManager* nm, const std::vector<T>& a);
      70                 :            : template <class T>
      71                 :            : T mkXor(T a, T b);
      72                 :            : template <class T>
      73                 :            : T mkIff(T a, T b);
      74                 :            : template <class T>
      75                 :            : T mkIte(T cond, T a, T b);
      76                 :            : 
      77                 :            : template <>
      78                 :     115904 : inline Node mkTrue<Node>(NodeManager* nm)
      79                 :            : {
      80                 :     231808 :   return nm->mkConst<bool>(true);
      81                 :            : }
      82                 :            : 
      83                 :            : template <>
      84                 :     997083 : inline Node mkFalse<Node>(NodeManager* nm)
      85                 :            : {
      86                 :    1994166 :   return nm->mkConst<bool>(false);
      87                 :            : }
      88                 :            : 
      89                 :            : template <>
      90                 :     743872 : inline Node mkNot<Node>(Node a)
      91                 :            : {
      92                 :     743872 :   return NodeManager::mkNode(Kind::NOT, a);
      93                 :            : }
      94                 :            : 
      95                 :            : template <>
      96                 :     193845 : inline Node mkOr<Node>(Node a, Node b)
      97                 :            : {
      98                 :     193845 :   return NodeManager::mkNode(Kind::OR, a, b);
      99                 :            : }
     100                 :            : 
     101                 :            : template <std::size_t N>
     102                 :    1331363 : inline Node mkOr(const TNode (&children)[N])
     103                 :            : {
     104                 :            :   static_assert(N >= 1, "mkOr requires at least 1 child!");
     105                 :            :   if constexpr (N == 1) return children[0];
     106                 :    1331363 :   return NodeManager::mkNode(Kind::OR, children);
     107                 :            : }
     108                 :            : 
     109                 :            : template <>
     110                 :            : inline Node mkOr<Node>(NodeManager* nm, const std::vector<Node>& children)
     111                 :            : {
     112                 :            :   Assert(children.size());
     113                 :            :   if (children.size() == 1) return children[0];
     114                 :            :   return nm->mkNode(Kind::OR, children);
     115                 :            : }
     116                 :            : 
     117                 :            : template <>
     118                 :    2913706 : inline Node mkAnd<Node>(Node a, Node b)
     119                 :            : {
     120                 :    2913706 :   return NodeManager::mkNode(Kind::AND, a, b);
     121                 :            : }
     122                 :            : 
     123                 :            : template <std::size_t N>
     124                 :      82314 : inline Node mkAnd(const TNode (&children)[N])
     125                 :            : {
     126                 :            :   static_assert(N >= 1, "mkAnd requires at least 1 child!");
     127                 :            :   if constexpr (N == 1) return children[0];
     128                 :      82314 :   return NodeManager::mkNode(Kind::AND, children);
     129                 :            : }
     130                 :            : 
     131                 :            : template <>
     132                 :      90150 : inline Node mkAnd<Node>(NodeManager* nm, const std::vector<Node>& children)
     133                 :            : {
     134 [ -  + ][ -  + ]:      90150 :   Assert(children.size());
                 [ -  - ]
     135         [ +  + ]:      90150 :   if (children.size() == 1) return children[0];
     136                 :      61376 :   return nm->mkNode(Kind::AND, children);
     137                 :            : }
     138                 :            : 
     139                 :            : template <>
     140                 :    3364334 : inline Node mkXor<Node>(Node a, Node b)
     141                 :            : {
     142                 :    3364334 :   return NodeManager::mkNode(Kind::XOR, a, b);
     143                 :            : }
     144                 :            : 
     145                 :            : template <>
     146                 :    1109790 : inline Node mkIff<Node>(Node a, Node b)
     147                 :            : {
     148                 :    1109790 :   return NodeManager::mkNode(Kind::EQUAL, a, b);
     149                 :            : }
     150                 :            : 
     151                 :            : template <>
     152                 :    1027199 : inline Node mkIte<Node>(Node cond, Node a, Node b)
     153                 :            : {
     154                 :    1027199 :   return NodeManager::mkNode(Kind::ITE, cond, a, b);
     155                 :            : }
     156                 :            : 
     157                 :            : /*
     158                 :            :  Various helper functions that get called by the bitblasting procedures
     159                 :            :  */
     160                 :            : 
     161                 :            : template <class T>
     162                 :      24992 : void inline extractBits(const std::vector<T>& b,
     163                 :            :                         std::vector<T>& dest,
     164                 :            :                         unsigned lo,
     165                 :            :                         unsigned hi)
     166                 :            : {
     167 [ +  - ][ +  - ]:      24992 :   Assert(lo < b.size() && hi < b.size() && lo <= hi);
         [ +  - ][ +  - ]
         [ -  + ][ -  + ]
                 [ -  - ]
     168         [ +  + ]:     211910 :   for (unsigned i = lo; i <= hi; ++i)
     169                 :            :   {
     170                 :     186918 :     dest.push_back(b[i]);
     171                 :            :   }
     172                 :      24992 : }
     173                 :            : 
     174                 :            : template <class T>
     175                 :      21556 : void inline negateBits(const std::vector<T>& bits, std::vector<T>& negated_bits)
     176                 :            : {
     177         [ +  + ]:     378733 :   for (unsigned i = 0; i < bits.size(); ++i)
     178                 :            :   {
     179                 :     357177 :     negated_bits.push_back(mkNot(bits[i]));
     180                 :            :   }
     181                 :      21556 : }
     182                 :            : 
     183                 :            : template <class T>
     184                 :       7252 : bool inline isZero(NodeManager* nm, const std::vector<T>& bits)
     185                 :            : {
     186         [ +  + ]:      38867 :   for (unsigned i = 0; i < bits.size(); ++i)
     187                 :            :   {
     188         [ +  + ]:      38745 :     if (bits[i] != mkFalse<T>(nm))
     189                 :            :     {
     190                 :       7130 :       return false;
     191                 :            :     }
     192                 :            :   }
     193                 :        122 :   return true;
     194                 :            : }
     195                 :            : 
     196                 :            : template <class T>
     197                 :       7130 : void inline rshift(NodeManager* nm, std::vector<T>& bits, unsigned amount)
     198                 :            : {
     199         [ +  + ]:     287293 :   for (unsigned i = 0; i < bits.size() - amount; ++i)
     200                 :            :   {
     201                 :     280163 :     bits[i] = bits[i + amount];
     202                 :            :   }
     203         [ +  + ]:      14260 :   for (unsigned i = bits.size() - amount; i < bits.size(); ++i)
     204                 :            :   {
     205                 :       7130 :     bits[i] = mkFalse<T>(nm);
     206                 :            :   }
     207                 :       7130 : }
     208                 :            : 
     209                 :            : template <class T>
     210                 :      14260 : void inline lshift(NodeManager* nm, std::vector<T>& bits, unsigned amount)
     211                 :            : {
     212         [ +  + ]:     574586 :   for (int i = (int)bits.size() - 1; i >= (int)amount; --i)
     213                 :            :   {
     214                 :     560326 :     bits[i] = bits[i - amount];
     215                 :            :   }
     216         [ +  + ]:      28520 :   for (unsigned i = 0; i < amount; ++i)
     217                 :            :   {
     218                 :      14260 :     bits[i] = mkFalse<T>(nm);
     219                 :            :   }
     220                 :      14260 : }
     221                 :            : 
     222                 :            : template <class T>
     223                 :      12202 : void inline makeZero(NodeManager* nm, std::vector<T>& bits, unsigned width)
     224                 :            : {
     225 [ -  + ][ -  + ]:      12202 :   Assert(bits.size() == 0);
                 [ -  - ]
     226         [ +  + ]:     343366 :   for (unsigned i = 0; i < width; ++i)
     227                 :            :   {
     228                 :     331164 :     bits.push_back(mkFalse<T>(nm));
     229                 :            :   }
     230                 :      12202 : }
     231                 :            : 
     232                 :            : /**
     233                 :            :  * Constructs a simple ripple carry adder
     234                 :            :  *
     235                 :            :  * @param a first term to be added
     236                 :            :  * @param b second term to be added
     237                 :            :  * @param res the result
     238                 :            :  * @param carry the carry-in bit
     239                 :            :  *
     240                 :            :  * @return the carry-out
     241                 :            :  */
     242                 :            : template <class T>
     243                 :      30265 : T inline rippleCarryAdder(const std::vector<T>& a,
     244                 :            :                           const std::vector<T>& b,
     245                 :            :                           std::vector<T>& res,
     246                 :            :                           T carry)
     247                 :            : {
     248 [ +  - ][ +  - ]:      30265 :   Assert(a.size() == b.size() && res.size() == 0);
         [ -  + ][ -  + ]
                 [ -  - ]
     249                 :            : 
     250         [ +  + ]:     993323 :   for (unsigned i = 0; i < a.size(); ++i)
     251                 :            :   {
     252                 :    1926116 :     T sum = mkXor(mkXor(a[i], b[i]), carry);
     253 [ +  + ][ -  - ]:    2889174 :     carry = mkOr({mkAnd(a[i], b[i]), mkAnd(mkXor(a[i], b[i]), carry)});
     254                 :     963058 :     res.push_back(sum);
     255                 :            :   }
     256                 :            : 
     257                 :      30265 :   return carry;
     258                 :            : }
     259                 :            : 
     260                 :            : template <class T>
     261                 :       2524 : inline void shiftAddMultiplier(NodeManager* nm,
     262                 :            :                                const std::vector<T>& a,
     263                 :            :                                const std::vector<T>& b,
     264                 :            :                                std::vector<T>& res)
     265                 :            : {
     266         [ +  + ]:      23465 :   for (unsigned i = 0; i < a.size(); ++i)
     267                 :            :   {
     268                 :      20941 :     res.push_back(mkAnd(b[0], a[i]));
     269                 :            :   }
     270                 :            : 
     271         [ +  + ]:      20941 :   for (unsigned k = 1; k < res.size(); ++k)
     272                 :            :   {
     273                 :      18417 :     T carry_in = mkFalse<T>(nm);
     274                 :      18417 :     T carry_out;
     275         [ +  + ]:     172721 :     for (unsigned j = 0; j < res.size() - k; ++j)
     276                 :            :     {
     277                 :     308608 :       T aj = mkAnd(b[k], a[j]);
     278 [ +  + ][ -  - ]:     925824 :       carry_out =
     279                 :     771520 :           mkOr({mkAnd(res[j + k], aj), mkAnd(mkXor(res[j + k], aj), carry_in)});
     280                 :     154304 :       res[j + k] = mkXor(mkXor(res[j + k], aj), carry_in);
     281                 :     154304 :       carry_in = carry_out;
     282                 :            :     }
     283                 :            :   }
     284                 :       2524 : }
     285                 :            : 
     286                 :            : template <class T>
     287                 :      28962 : T inline uLessThanBB(const std::vector<T>& a,
     288                 :            :                      const std::vector<T>& b,
     289                 :            :                      bool orEqual)
     290                 :            : {
     291 [ +  - ][ +  - ]:      28962 :   Assert(a.size() && b.size());
         [ -  + ][ -  + ]
                 [ -  - ]
     292                 :            : 
     293                 :      57924 :   T res = mkAnd(mkNot(a[0]), b[0]);
     294                 :            : 
     295         [ -  + ]:      28962 :   if (orEqual)
     296                 :            :   {
     297                 :          0 :     res = mkOr(res, mkIff(a[0], b[0]));
     298                 :            :   }
     299                 :            : 
     300         [ +  + ]:     230467 :   for (unsigned i = 1; i < a.size(); ++i)
     301                 :            :   {
     302                 :            :     // a < b iff ( a[i] <-> b[i] AND a[i-1:0] < b[i-1:0]) OR (~a[i] AND b[i])
     303 [ +  + ][ -  - ]:     604515 :     res = mkOr({mkAnd(mkIff(a[i], b[i]), res), mkAnd(mkNot(a[i]), b[i])});
     304                 :            :   }
     305                 :      28962 :   return res;
     306                 :          0 : }
     307                 :            : 
     308                 :            : template <class T>
     309                 :      14654 : T inline sLessThanBB(const std::vector<T>& a,
     310                 :            :                      const std::vector<T>& b,
     311                 :            :                      bool orEqual)
     312                 :            : {
     313 [ +  - ][ +  - ]:      14654 :   Assert(a.size() && b.size());
         [ -  + ][ -  + ]
                 [ -  - ]
     314         [ +  + ]:      14654 :   if (a.size() == 1)
     315                 :            :   {
     316         [ -  + ]:       2158 :     if (orEqual)
     317                 :            :     {
     318                 :          0 :       return mkOr({mkIff(a[0], b[0]), mkAnd(a[0], mkNot(b[0]))});
     319                 :            :     }
     320                 :            : 
     321                 :       2158 :     return mkAnd(a[0], mkNot(b[0]));
     322                 :            :   }
     323                 :      12496 :   unsigned n = a.size() - 1;
     324                 :      12496 :   std::vector<T> a1, b1;
     325                 :      12496 :   extractBits(a, a1, 0, n - 1);
     326                 :      12496 :   extractBits(b, b1, 0, n - 1);
     327                 :            : 
     328                 :            :   // unsigned comparison of the first n-1 bits
     329                 :      12496 :   T ures = uLessThanBB(a1, b1, orEqual);
     330                 :      99968 :   T res = mkOr({// a b have the same sign
     331                 :      24992 :                 mkAnd(mkIff(a[n], b[n]), ures),
     332                 :            :                 // a is negative and b positive
     333                 :      24992 :                 mkAnd(a[n], mkNot(b[n]))});
     334                 :      12496 :   return res;
     335                 :      12496 : }
     336                 :            : 
     337                 :            : }  // namespace bv
     338                 :            : }  // namespace theory
     339                 :            : }  // namespace cvc5::internal
     340                 :            : 
     341                 :            : #endif  // CVC5__THEORY__BV__BITBLAST__BITBLAST_UTILS_H

Generated by: LCOV version 1.14