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: 96 111 86.5 %
Date: 2026-03-16 10:41:14 Functions: 19 20 95.0 %
Branches: 56 98 57.1 %

           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                 :            : #include "expr/node.h"
      20                 :            : 
      21                 :            : namespace cvc5::internal {
      22                 :            : namespace theory {
      23                 :            : namespace bv {
      24                 :            : 
      25                 :            : template <class T> class TBitblaster;
      26                 :            : 
      27                 :            : template <class T> 
      28                 :            : std::string toString (const std::vector<T>& bits);
      29                 :            : 
      30                 :            : template <> inline
      31                 :          0 : std::string toString<Node> (const std::vector<Node>& bits) {
      32                 :          0 :   std::ostringstream os;
      33         [ -  - ]:          0 :   for (int i = bits.size() - 1; i >= 0; --i) {
      34                 :          0 :     TNode bit = bits[i];
      35         [ -  - ]:          0 :     if (bit.getKind() == Kind::CONST_BOOLEAN)
      36                 :            :     {
      37         [ -  - ]:          0 :       os << (bit.getConst<bool>() ? "1" : "0");
      38                 :            :     }
      39                 :            :     else
      40                 :            :     {
      41                 :          0 :       os << bit<< " ";
      42                 :            :     }
      43                 :          0 :   }
      44                 :          0 :   os <<"\n";
      45                 :          0 :   return os.str();
      46                 :          0 : }
      47                 :            : 
      48                 :            : template <class T>
      49                 :            : T mkTrue(NodeManager* nm);
      50                 :            : template <class T>
      51                 :            : T mkFalse(NodeManager* nm);
      52                 :            : template <class T> T mkNot(T a);
      53                 :            : template <class T> T mkOr(T a, T b);
      54                 :            : template <class T>
      55                 :            : T mkOr(NodeManager* nm, const std::vector<T>& a);
      56                 :            : template <class T> T mkAnd(T a, T b);
      57                 :            : template <class T>
      58                 :            : T mkAnd(NodeManager* nm, const std::vector<T>& a);
      59                 :            : template <class T> T mkXor(T a, T b);
      60                 :            : template <class T> T mkIff(T a, T b);
      61                 :            : template <class T> T mkIte(T cond, T a, T b);
      62                 :            : 
      63                 :            : template <>
      64                 :      98308 : inline Node mkTrue<Node>(NodeManager* nm)
      65                 :            : {
      66                 :     196616 :   return nm->mkConst<bool>(true);
      67                 :            : }
      68                 :            : 
      69                 :            : template <>
      70                 :     427513 : inline Node mkFalse<Node>(NodeManager* nm)
      71                 :            : {
      72                 :     855026 :   return nm->mkConst<bool>(false);
      73                 :            : }
      74                 :            : 
      75                 :            : template <> inline
      76                 :     467570 : Node mkNot<Node>(Node a) {
      77                 :     467570 :   return NodeManager::mkNode(Kind::NOT, a);
      78                 :            : }
      79                 :            : 
      80                 :            : template <> inline
      81                 :     727629 : Node mkOr<Node>(Node a, Node b) {
      82                 :     727629 :   return NodeManager::mkNode(Kind::OR, a, b);
      83                 :            : }
      84                 :            : 
      85                 :            : template <>
      86                 :            : inline Node mkOr<Node>(NodeManager* nm, const std::vector<Node>& children)
      87                 :            : {
      88                 :            :   Assert(children.size());
      89                 :            :   if (children.size() == 1) return children[0];
      90                 :            :   return nm->mkNode(Kind::OR, children);
      91                 :            : }
      92                 :            : 
      93                 :            : template <> inline
      94                 :    1449986 : Node mkAnd<Node>(Node a, Node b) {
      95                 :    1449986 :   return NodeManager::mkNode(Kind::AND, a, b);
      96                 :            : }
      97                 :            : 
      98                 :            : template <>
      99                 :      77539 : inline Node mkAnd<Node>(NodeManager* nm, const std::vector<Node>& children)
     100                 :            : {
     101 [ -  + ][ -  + ]:      77539 :   Assert(children.size());
                 [ -  - ]
     102         [ +  + ]:      77539 :   if (children.size() == 1) return children[0];
     103                 :      50742 :   return nm->mkNode(Kind::AND, children);
     104                 :            : }
     105                 :            : 
     106                 :            : template <> inline
     107                 :    1156339 : Node mkXor<Node>(Node a, Node b) {
     108                 :    1156339 :   return NodeManager::mkNode(Kind::XOR, a, b);
     109                 :            : }
     110                 :            : 
     111                 :            : template <> inline
     112                 :     900147 : Node mkIff<Node>(Node a, Node b) {
     113                 :     900147 :   return NodeManager::mkNode(Kind::EQUAL, a, b);
     114                 :            : }
     115                 :            : 
     116                 :            : template <> inline
     117                 :     314951 : Node mkIte<Node>(Node cond, Node a, Node b) {
     118                 :     314951 :   return NodeManager::mkNode(Kind::ITE, cond, a, b);
     119                 :            : }
     120                 :            : 
     121                 :            : /*
     122                 :            :  Various helper functions that get called by the bitblasting procedures
     123                 :            :  */
     124                 :            : 
     125                 :            : template <class T>
     126                 :      25134 : void inline extractBits(const std::vector<T>& b, std::vector<T>& dest, unsigned lo, unsigned hi) {
     127 [ +  - ][ +  - ]:      25134 :   Assert(lo < b.size() && hi < b.size() && lo <= hi);
         [ +  - ][ +  - ]
         [ -  + ][ -  + ]
                 [ -  - ]
     128         [ +  + ]:     203260 :   for (unsigned i = lo; i <= hi; ++i) {
     129                 :     178126 :     dest.push_back(b[i]); 
     130                 :            :   }
     131                 :      25134 : }
     132                 :            : 
     133                 :            : template <class T>
     134                 :      17430 : void inline negateBits(const std::vector<T>& bits, std::vector<T>& negated_bits) {
     135         [ +  + ]:     134460 :   for(unsigned i = 0; i < bits.size(); ++i) {
     136                 :     117030 :     negated_bits.push_back(mkNot(bits[i])); 
     137                 :            :   }
     138                 :      17430 : }
     139                 :            : 
     140                 :            : template <class T>
     141                 :       4932 : bool inline isZero(NodeManager* nm, const std::vector<T>& bits)
     142                 :            : {
     143         [ +  + ]:       6981 :   for(unsigned i = 0; i < bits.size(); ++i) {
     144         [ +  + ]:       6729 :     if (bits[i] != mkFalse<T>(nm))
     145                 :            :     {
     146                 :       4680 :       return false;
     147                 :            :     }
     148                 :            :   }
     149                 :        252 :   return true;
     150                 :            : }
     151                 :            : 
     152                 :            : template <class T>
     153                 :       4680 : void inline rshift(NodeManager* nm, std::vector<T>& bits, unsigned amount)
     154                 :            : {
     155         [ +  + ]:      54121 :   for (unsigned i = 0; i < bits.size() - amount; ++i) {
     156                 :      49441 :     bits[i] = bits[i+amount]; 
     157                 :            :   }
     158         [ +  + ]:       9360 :   for(unsigned i = bits.size() - amount; i < bits.size(); ++i) {
     159                 :       4680 :     bits[i] = mkFalse<T>(nm);
     160                 :            :   }
     161                 :       4680 : }
     162                 :            : 
     163                 :            : template <class T>
     164                 :       9360 : void inline lshift(NodeManager* nm, std::vector<T>& bits, unsigned amount)
     165                 :            : {
     166         [ +  + ]:     108242 :   for (int i = (int)bits.size() - 1; i >= (int)amount ; --i) {
     167                 :      98882 :     bits[i] = bits[i-amount]; 
     168                 :            :   }
     169         [ +  + ]:      18720 :   for(unsigned i = 0; i < amount; ++i) {
     170                 :       9360 :     bits[i] = mkFalse<T>(nm);
     171                 :            :   }
     172                 :       9360 : }
     173                 :            : 
     174                 :            : template <class T>
     175                 :       9976 : void inline makeZero(NodeManager* nm, std::vector<T>& bits, unsigned width)
     176                 :            : {
     177 [ -  + ][ -  + ]:       9976 :   Assert(bits.size() == 0);
                 [ -  - ]
     178         [ +  + ]:     102357 :   for(unsigned i = 0; i < width; ++i) {
     179                 :      92381 :     bits.push_back(mkFalse<T>(nm));
     180                 :            :   }
     181                 :       9976 : }
     182                 :            : 
     183                 :            : /** 
     184                 :            :  * Constructs a simple ripple carry adder
     185                 :            :  * 
     186                 :            :  * @param a first term to be added
     187                 :            :  * @param b second term to be added
     188                 :            :  * @param res the result
     189                 :            :  * @param carry the carry-in bit 
     190                 :            :  * 
     191                 :            :  * @return the carry-out
     192                 :            :  */
     193                 :            : template <class T>
     194                 :      22529 : T inline rippleCarryAdder(const std::vector<T>&a, const std::vector<T>& b, std::vector<T>& res, T carry) {
     195 [ +  - ][ +  - ]:      22529 :   Assert(a.size() == b.size() && res.size() == 0);
         [ -  + ][ -  + ]
                 [ -  - ]
     196                 :            : 
     197         [ +  + ]:     272412 :   for (unsigned i = 0 ; i < a.size(); ++i) {
     198                 :     499766 :     T sum = mkXor(mkXor(a[i], b[i]), carry);
     199                 :     749649 :     carry = mkOr( mkAnd(a[i], b[i]),
     200                 :     499766 :                   mkAnd( mkXor(a[i], b[i]),
     201                 :            :                          carry));
     202                 :     249883 :     res.push_back(sum); 
     203                 :            :   }
     204                 :            : 
     205                 :      22529 :   return carry;
     206                 :            : }
     207                 :            : 
     208                 :            : template <class T>
     209                 :       2507 : inline void shiftAddMultiplier(NodeManager* nm,
     210                 :            :                                const std::vector<T>& a,
     211                 :            :                                const std::vector<T>& b,
     212                 :            :                                std::vector<T>& res)
     213                 :            : {
     214         [ +  + ]:      22516 :   for (unsigned i = 0; i < a.size(); ++i) {
     215                 :      20009 :     res.push_back(mkAnd(b[0], a[i])); 
     216                 :            :   }
     217                 :            :   
     218         [ +  + ]:      20009 :   for(unsigned k = 1; k < res.size(); ++k) {
     219                 :      17502 :     T carry_in = mkFalse<T>(nm);
     220                 :      17502 :     T carry_out;
     221         [ +  + ]:     149241 :     for(unsigned j = 0; j < res.size() -k; ++j) {
     222                 :     263478 :       T aj = mkAnd(b[k], a[j]);
     223                 :     263478 :       carry_out = mkOr(mkAnd(res[j+k], aj),
     224                 :     131739 :                        mkAnd( mkXor(res[j+k], aj), carry_in));
     225                 :     131739 :       res[j+k] = mkXor(mkXor(res[j+k], aj), carry_in);
     226                 :     131739 :       carry_in = carry_out; 
     227                 :            :     }
     228                 :            :   }
     229                 :       2507 : }
     230                 :            : 
     231                 :            : template <class T>
     232                 :      29784 : T inline uLessThanBB(const std::vector<T>&a, const std::vector<T>& b, bool orEqual) {
     233 [ +  - ][ +  - ]:      29784 :   Assert(a.size() && b.size());
         [ -  + ][ -  + ]
                 [ -  - ]
     234                 :            : 
     235                 :      59568 :   T res = mkAnd(mkNot(a[0]), b[0]);
     236                 :            :   
     237         [ -  + ]:      29784 :   if(orEqual) {
     238                 :          0 :     res = mkOr(res, mkIff(a[0], b[0])); 
     239                 :            :   }
     240                 :            :   
     241         [ +  + ]:     223493 :   for (unsigned i = 1; i < a.size(); ++i) {
     242                 :            :     // a < b iff ( a[i] <-> b[i] AND a[i-1:0] < b[i-1:0]) OR (~a[i] AND b[i]) 
     243                 :     387418 :     res = mkOr(mkAnd(mkIff(a[i], b[i]), res),
     244                 :     387418 :                mkAnd(mkNot(a[i]), b[i])); 
     245                 :            :   }
     246                 :      29784 :   return res;
     247                 :          0 : }
     248                 :            : 
     249                 :            : template <class T>
     250                 :      14964 : T inline sLessThanBB(const std::vector<T>&a, const std::vector<T>& b, bool orEqual) {
     251 [ +  - ][ +  - ]:      14964 :   Assert(a.size() && b.size());
         [ -  + ][ -  + ]
                 [ -  - ]
     252         [ +  + ]:      14964 :   if (a.size() == 1) {
     253         [ -  + ]:       2397 :     if(orEqual) {
     254                 :          0 :       return  mkOr(mkIff(a[0], b[0]),
     255                 :          0 :                    mkAnd(a[0], mkNot(b[0]))); 
     256                 :            :     }
     257                 :            : 
     258                 :       2397 :     return mkAnd(a[0], mkNot(b[0]));
     259                 :            :   }
     260                 :      12567 :   unsigned n = a.size() - 1; 
     261                 :      12567 :   std::vector<T> a1, b1;
     262                 :      12567 :   extractBits(a, a1, 0, n-1);
     263                 :      12567 :   extractBits(b, b1, 0, n-1);
     264                 :            :   
     265                 :            :   // unsigned comparison of the first n-1 bits
     266                 :      12567 :   T ures = uLessThanBB(a1, b1, orEqual);
     267                 :      62835 :   T res = mkOr(// a b have the same sign
     268                 :      25134 :                mkAnd(mkIff(a[n], b[n]),
     269                 :            :                      ures),
     270                 :            :                // a is negative and b positive
     271                 :      12567 :                mkAnd(a[n],
     272                 :      12567 :                      mkNot(b[n])));
     273                 :      12567 :   return res;
     274                 :      12567 : }
     275                 :            : 
     276                 :            : }  // namespace bv
     277                 :            : }  // namespace theory
     278                 :            : }  // namespace cvc5::internal
     279                 :            : 
     280                 :            : #endif  // CVC5__THEORY__BV__BITBLAST__BITBLAST_UTILS_H

Generated by: LCOV version 1.14