LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/preprocessing/passes - bv_intro_pow2.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 51 66 77.3 %
Date: 2026-02-01 13:09:02 Functions: 5 5 100.0 %
Branches: 24 49 49.0 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Mathias Preiner, Liana Hadarean, Aina Niemetz
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * The BvIntroPow2 preprocessing pass.
      14                 :            :  *
      15                 :            :  * Traverses the formula and applies the IsPowerOfTwo rewrite rule. This
      16                 :            :  * preprocessing pass is particularly useful on QF_BV/pspace benchmarks and
      17                 :            :  * can be enabled via option `--bv-intro-pow2`.
      18                 :            :  */
      19                 :            : 
      20                 :            : #include "preprocessing/passes/bv_intro_pow2.h"
      21                 :            : 
      22                 :            : #include <unordered_map>
      23                 :            : 
      24                 :            : #include "preprocessing/assertion_pipeline.h"
      25                 :            : #include "preprocessing/preprocessing_pass_context.h"
      26                 :            : #include "theory/bv/theory_bv_utils.h"
      27                 :            : 
      28                 :            : namespace cvc5::internal {
      29                 :            : namespace preprocessing {
      30                 :            : namespace passes {
      31                 :            : 
      32                 :            : using NodeMap = std::unordered_map<Node, Node>;
      33                 :            : using namespace cvc5::internal::theory;
      34                 :            : 
      35                 :      50975 : BvIntroPow2::BvIntroPow2(PreprocessingPassContext* preprocContext)
      36                 :      50975 :     : PreprocessingPass(preprocContext, "bv-intro-pow2"){};
      37                 :            : 
      38                 :          5 : PreprocessingPassResult BvIntroPow2::applyInternal(
      39                 :            :     AssertionPipeline* assertionsToPreprocess)
      40                 :            : {
      41                 :          5 :   std::unordered_map<Node, Node> cache;
      42         [ +  + ]:         50 :   for (size_t i = 0, size = assertionsToPreprocess->size(); i < size; ++i)
      43                 :            :   {
      44                 :         90 :     Node cur = (*assertionsToPreprocess)[i];
      45                 :         90 :     Node res = pow2Rewrite(cur, cache);
      46         [ +  + ]:         45 :     if (res != cur)
      47                 :            :     {
      48                 :         15 :       assertionsToPreprocess->replace(
      49                 :            :           i, res, nullptr, TrustId::PREPROCESS_BV_INTRO_POW2);
      50                 :         15 :       assertionsToPreprocess->ensureRewritten(i);
      51                 :            :     }
      52                 :            :   }
      53                 :         10 :   return PreprocessingPassResult::NO_CONFLICT;
      54                 :            : }
      55                 :            : 
      56                 :         20 : bool BvIntroPow2::isPowerOfTwo(TNode node)
      57                 :            : {
      58         [ -  + ]:         20 :   if (node.getKind() != Kind::EQUAL)
      59                 :            :   {
      60                 :          0 :     return false;
      61                 :            :   }
      62 [ +  + ][ -  - ]:         20 :   if (node[0].getKind() != Kind::BITVECTOR_AND
      63 [ +  - ][ +  + ]:         20 :       && node[1].getKind() != Kind::BITVECTOR_AND)
         [ +  - ][ +  - ]
                 [ -  - ]
      64                 :            :   {
      65                 :          5 :     return false;
      66                 :            :   }
      67                 :         15 :   if (!bv::utils::isZero(node[0]) && !bv::utils::isZero(node[1]))
      68                 :            :   {
      69                 :          0 :     return false;
      70                 :            :   }
      71                 :            : 
      72         [ -  + ]:         30 :   TNode t = !bv::utils::isZero(node[0]) ? node[0] : node[1];
      73         [ -  + ]:         15 :   if (t.getNumChildren() != 2) return false;
      74                 :         30 :   TNode a = t[0];
      75                 :         30 :   TNode b = t[1];
      76         [ -  + ]:         15 :   if (bv::utils::getSize(t) < 2) return false;
      77                 :         30 :   Node diff = rewrite(nodeManager()->mkNode(Kind::BITVECTOR_SUB, a, b));
      78                 :         30 :   return (diff.isConst()
      79                 :         15 :           && (bv::utils::isOne(diff) || bv::utils::isOnes(diff)));
      80                 :            : }
      81                 :            : 
      82                 :         15 : Node BvIntroPow2::rewritePowerOfTwo(TNode node)
      83                 :            : {
      84                 :         15 :   NodeManager* nm = nodeManager();
      85         [ +  - ]:         30 :   TNode term = bv::utils::isZero(node[0]) ? node[1] : node[0];
      86                 :         30 :   TNode a = term[0];
      87                 :         30 :   TNode b = term[1];
      88                 :         15 :   uint32_t size = bv::utils::getSize(term);
      89                 :         45 :   Node diff = rewrite(nm->mkNode(Kind::BITVECTOR_SUB, a, b));
      90 [ -  + ][ -  + ]:         15 :   Assert(diff.isConst());
                 [ -  - ]
      91                 :         30 :   Node one = bv::utils::mkOne(nm, size);
      92         [ +  - ]:         30 :   TNode x = diff == one ? a : b;
      93                 :         30 :   Node sk = bv::utils::mkVar(nm, size);
      94                 :         45 :   Node sh = nm->mkNode(Kind::BITVECTOR_SHL, one, sk);
      95                 :         30 :   Node x_eq_sh = nm->mkNode(Kind::EQUAL, x, sh);
      96                 :         30 :   return x_eq_sh;
      97                 :            : }
      98                 :            : 
      99                 :         45 : Node BvIntroPow2::pow2Rewrite(Node node, std::unordered_map<Node, Node>& cache)
     100                 :            : {
     101                 :         45 :   const auto& ci = cache.find(node);
     102         [ -  + ]:         45 :   if (ci != cache.end())
     103                 :            :   {
     104                 :          0 :     Node incache = (*ci).second;
     105         [ -  - ]:          0 :     return incache.isNull() ? node : incache;
     106                 :            :   }
     107                 :            : 
     108                 :         90 :   Node res = Node::null();
     109    [ -  + ][ + ]:         45 :   switch (node.getKind())
     110                 :            :   {
     111                 :          0 :     case Kind::AND:
     112                 :            :     {
     113                 :          0 :       bool changed = false;
     114                 :          0 :       std::vector<Node> children;
     115         [ -  - ]:          0 :       for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i)
     116                 :            :       {
     117                 :          0 :         Node child = node[i];
     118                 :          0 :         Node found = pow2Rewrite(child, cache);
     119                 :          0 :         changed = changed || (child != found);
     120                 :          0 :         children.push_back(found);
     121                 :            :       }
     122         [ -  - ]:          0 :       if (changed)
     123                 :            :       {
     124                 :          0 :         res = nodeManager()->mkNode(Kind::AND, children);
     125                 :            :       }
     126                 :            :     }
     127                 :          0 :     break;
     128                 :            : 
     129                 :         20 :     case Kind::EQUAL:
     130                 :         20 :       if (node[0].getType().isBitVector() && isPowerOfTwo(node))
     131                 :            :       {
     132                 :         15 :         res = rewritePowerOfTwo(node);
     133                 :            :       }
     134                 :         20 :       break;
     135                 :         25 :     default: break;
     136                 :            :   }
     137                 :            : 
     138                 :         45 :   cache.insert(std::make_pair(node, res));
     139         [ +  + ]:         45 :   return res.isNull() ? node : res;
     140                 :            : }
     141                 :            : 
     142                 :            : }  // namespace passes
     143                 :            : }  // namespace preprocessing
     144                 :            : 
     145                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14