bv2int: bvand translation code move (#5227)
authoryoni206 <yoni206@users.noreply.github.com>
Sat, 10 Oct 2020 01:40:52 +0000 (18:40 -0700)
committerGitHub <noreply@github.com>
Sat, 10 Oct 2020 01:40:52 +0000 (20:40 -0500)
This PR is essentially a code move.
It moves the code that translates bvand from the bv_to_int preprocessing pass to a new class IAndHelper, in the new files nl_iand_utils.{h,cpp}. The goal is to have this code in a place which can be shared between the bv2int preprocessing pass and the iand solver.

Future PRs will:

Optimize this utility
Make use of it in the iand solver
The code in nl_iand_utils.{h,cpp} is almost completely a move from bv_to_int.{h,cpp}. The changes are all minor, and include, e.g., the following changes:

the node manager is no longer a member, and so is the constant 0.
using the oneBitAnd function directly, without a function pointer.

src/CMakeLists.txt
src/preprocessing/passes/bv_to_int.cpp
src/preprocessing/passes/bv_to_int.h
src/theory/arith/nl/iand_solver.cpp
src/theory/arith/nl/iand_table.cpp [new file with mode: 0644]
src/theory/arith/nl/iand_table.h [new file with mode: 0644]

index f70bdde3ef9fa2942bece64330afd6f672e00055..3896d3111121f085774e0c1a9b0067f5480bd039 100644 (file)
@@ -357,6 +357,8 @@ libcvc4_add_sources(
   theory/arith/nl/icp/intersection.h
   theory/arith/nl/nl_constraint.cpp
   theory/arith/nl/nl_constraint.h
+  theory/arith/nl/iand_table.cpp
+  theory/arith/nl/iand_table.h
   theory/arith/nl/nl_lemma_utils.cpp
   theory/arith/nl/nl_lemma_utils.h
   theory/arith/nl/nl_model.cpp
index 9ee4e2b7db97854dabfa3aa056119212fb021d25..06a5714d3d9ebc70d5dd7e0c71c9d02079483905 100644 (file)
@@ -45,7 +45,6 @@ Rational intpow2(uint64_t b)
 /**
  * Helper functions for createBitwiseNode
  */
-bool oneBitAnd(bool a, bool b) { return (a && b); }
 
 } //end empty namespace
 
@@ -446,12 +445,11 @@ Node BVToInt::translateWithChildren(Node original,
         Assert(options::solveBVAsInt() == options::SolveBVAsIntMode::SUM);
         // Construct a sum of ites, based on granularity.
         Assert(translated_children.size() == 2);
-        Node newNode = createBitwiseNode(translated_children[0],
-                                       translated_children[1],
-                                       bvsize,
-                                       options::BVAndIntegerGranularity(),
-                                       &oneBitAnd);
-        returnNode = newNode;
+        returnNode =
+            d_iandTable.createBitwiseNode(translated_children[0],
+                                          translated_children[1],
+                                          bvsize,
+                                          options::BVAndIntegerGranularity());
       }
       break;
     }
@@ -1077,120 +1075,6 @@ Node BVToInt::translateQuantifiedFormula(Node quantifiedNode)
   return result;
 }
 
-Node BVToInt::createITEFromTable(
-    Node x,
-    Node y,
-    uint64_t granularity,
-    std::map<std::pair<uint64_t, uint64_t>, uint64_t> table)
-{
-  Assert(granularity <= 8);
-  uint64_t max_value = ((uint64_t)pow(2, granularity));
-  // The table represents a function from pairs of integers to integers, where
-  // all integers are between 0 (inclusive) and max_value (exclusive).
-  Assert(table.size() == max_value * max_value);
-  Node ite = d_nm->mkConst<Rational>(table[std::make_pair(0, 0)]);
-  for (uint64_t i = 0; i < max_value; i++)
-  {
-    for (uint64_t j = 0; j < max_value; j++)
-    {
-      if ((i == 0) && (j == 0))
-      {
-        continue;
-      }
-      ite = d_nm->mkNode(
-          kind::ITE,
-          d_nm->mkNode(
-              kind::AND,
-              d_nm->mkNode(kind::EQUAL, x, d_nm->mkConst<Rational>(i)),
-              d_nm->mkNode(kind::EQUAL, y, d_nm->mkConst<Rational>(j))),
-          d_nm->mkConst<Rational>(table[std::make_pair(i, j)]),
-          ite);
-    }
-  }
-  return ite;
-}
-
-Node BVToInt::createBitwiseNode(Node x,
-                                Node y,
-                                uint64_t bvsize,
-                                uint64_t granularity,
-                                bool (*f)(bool, bool))
-{
-  /**
-   * Standardize granularity.
-   * If it is greater than bvsize, it is set to bvsize.
-   * Otherwise, it is set to the closest (going down)  divider of bvsize.
-   */
-  Assert(0 < granularity && granularity <= 8);
-  if (granularity > bvsize)
-  {
-    granularity = bvsize;
-  }
-  else
-  {
-    while (bvsize % granularity != 0)
-    {
-      granularity = granularity - 1;
-    }
-  }
-  // transform f into a table
-  // f is defined over 1 bit, while the table is defined over `granularity` bits
-  std::map<std::pair<uint64_t, uint64_t>, uint64_t> table;
-  uint64_t max_value = ((uint64_t)pow(2, granularity));
-  for (uint64_t i = 0; i < max_value; i++)
-  {
-    for (uint64_t j = 0; j < max_value; j++)
-    {
-      uint64_t sum = 0;
-      for (uint64_t n = 0; n < granularity; n++)
-      {
-        // b is the result of f on the current bit
-        bool b = f((((i >> n) & 1) == 1), (((j >> n) & 1) == 1));
-        // add the corresponding power of 2 only if the result is 1
-        if (b)
-        {
-          sum += 1 << n;
-        }
-      }
-      table[std::make_pair(i, j)] = sum;
-    }
-  }
-   Assert(table.size() == max_value * max_value);
-
-  /*
-   * Create the sum.
-   * For granularity 1, the sum has bvsize elements.
-   * In contrast, if bvsize = granularity, sum has one element.
-   * Each element in the sum is an ite that corresponds to the generated table,
-   * multiplied by the appropriate power of two.
-   * More details are in bv_to_int.h .
-   */
-  uint64_t sumSize = bvsize / granularity;
-  Node sumNode = d_zero;
-  /**
-   * extract definition in integers is:
-   * (define-fun intextract ((k Int) (i Int) (j Int) (a Int)) Int
-   * (mod (div a (two_to_the j)) (two_to_the (+ (- i j) 1))))
-   */
-  for (uint64_t i = 0; i < sumSize; i++)
-  {
-    Node xExtract = d_nm->mkNode(
-        kind::INTS_MODULUS_TOTAL,
-        d_nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i * granularity)),
-        pow2(granularity));
-    Node yExtract = d_nm->mkNode(
-        kind::INTS_MODULUS_TOTAL,
-        d_nm->mkNode(kind::INTS_DIVISION_TOTAL, y, pow2(i * granularity)),
-        pow2(granularity));
-    Node ite = createITEFromTable(xExtract, yExtract, granularity, table);
-    sumNode =
-        d_nm->mkNode(kind::PLUS,
-                     sumNode,
-                     d_nm->mkNode(kind::MULT, pow2(i * granularity), ite));
-  }
-  return sumNode;
-}
-
 Node BVToInt::createBVNotNode(Node n, uint64_t bvsize)
 {
   return d_nm->mkNode(kind::MINUS, maxInt(bvsize), n);
index d1562ad65defae5487561acdf576cec8e8eb0064..0f6a6a4bb67159d11c5f0f0f3b43e4937a3cbaeb 100644 (file)
@@ -75,6 +75,7 @@
 #include "context/context.h"
 #include "preprocessing/preprocessing_pass.h"
 #include "preprocessing/preprocessing_pass_context.h"
+#include "theory/arith/nl/iand_table.h"
 
 namespace CVC4 {
 namespace preprocessing {
@@ -90,79 +91,6 @@ class BVToInt : public PreprocessingPass
  protected:
   PreprocessingPassResult applyInternal(
       AssertionPipeline* assertionsToPreprocess) override;
-
-  /**
-   * A generic function that creates a node that represents a bitwise
-   * operation.
-   *
-   * For example: Suppose bvsize is 4, granularity is 1, and f(x,y) = x && y.
-   * Denote by ITE(a,b) the term: ite(a==0, 0, ite(b==1, 1, 0)).
-   * The result of this function would be:
-   * ITE(x[0], y[0])*2^0 + ... + ITE(x[3], y[3])*2^3
-   *
-   * For another example: Suppose bvsize is 4, granularity is 2,
-   * and f(x,y) = x && y.
-   * Denote by ITE(a,b) the term that corresponds to the following table:
-   * a | b |  ITE(a,b)
-   * ----------------
-   * 0 | 0 | 0
-   * 0 | 1 | 0
-   * 0 | 2 | 0
-   * 0 | 3 | 0
-   * 1 | 0 | 0
-   * 1 | 1 | 1
-   * 1 | 2 | 0
-   * 1 | 3 | 1
-   * 2 | 0 | 0
-   * 2 | 1 | 0
-   * 2 | 2 | 2
-   * 2 | 3 | 2
-   * 3 | 0 | 0
-   * 3 | 1 | 1
-   * 3 | 2 | 2
-   * 3 | 3 | 3
-   *
-   * For example, 2 in binary is 10 and 1 in binary is 01, and so doing
-   * "bitwise f" on them gives 00.
-   * The result of this function would be:
-   * ITE(x[1:0], y[1:0])*2^0 + ITE(x[3:2], y[3:2])*2^2
-   *
-   *
-   * @param x is an integer operand that correspond to the first original
-   *        bit-vector operand.
-   * @param y is an integer operand that correspond to the second original
-   *        bit-vector operand.
-   * @param bvsize is the bit width of the original bit-vector variables.
-   * @param granularity is specified in the options for this preprocessing
-   *        pass.
-   * @param f is a pointer to a boolean function that corresponds
-   *        to the original bitwise operation.
-   * @return A node that represents the operation, as described above.
-   */
-  Node createBitwiseNode(Node x,
-                         Node y,
-                         uint64_t bvsize,
-                         uint64_t granularity,
-                         bool (*f)(bool, bool));
-
-  /**
-   * A helper function for createBitwiseNode
-   * @param x integer node corresponding to the original first bit-vector
-   *        argument
-   * @param y integer node corresponding to the original second bit-vector
-   *        argument nodes.
-   * @param granularity the bitwidth of the original bit-vector nodes.
-   * @param table a function from pairs of integers to integers.
-   *        The domain of this function consists of pairs of
-   *        integers between 0 (inclusive) and 2^{bitwidth} (exclusive).
-   * @return An ite term that represents this table.
-   */
-  Node createITEFromTable(
-      Node x,
-      Node y,
-      uint64_t granularity,
-      std::map<std::pair<uint64_t, uint64_t>, uint64_t> table);
-
   /**
    * A generic function that creates a logical shift node (either left or
    * right). a << b gets translated to a * 2^b mod 2^k, where k is the bit
@@ -354,6 +282,9 @@ class BVToInt : public PreprocessingPass
    */
   Node d_zero;
   Node d_one;
+  
+  /** helper class for handeling bvand translation */
+  theory::arith::nl::IAndTable d_iandTable;
 };
 
 }  // namespace passes
index a72010bf46f15df5a035e07bbeaac120e905d694..954f921ce1749311b1155a3921624a6c5c118d91 100644 (file)
@@ -245,7 +245,6 @@ Node IAndSolver::valueBasedLemma(Node i)
   return lem;
 }
 
-bool oneBitAnd(bool a, bool b) { return (a && b); }
 
 }  // namespace nl
 }  // namespace arith
diff --git a/src/theory/arith/nl/iand_table.cpp b/src/theory/arith/nl/iand_table.cpp
new file mode 100644 (file)
index 0000000..1ae866e
--- /dev/null
@@ -0,0 +1,157 @@
+/*********************                                                        */
+/*! \file iand_table.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Yoni Zohar
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities to maintain finite tables that represent
+ ** the value of iand.
+ **/
+
+#include "theory/arith/nl/iand_table.h"
+
+#include <cmath>
+
+#include "cvc4_private.h"
+#include "theory/arith/nl/nl_model.h"
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+static Rational intpow2(uint64_t b)
+{
+  return Rational(Integer(2).pow(b), Integer(1));
+}
+
+Node pow2(uint64_t k)
+{
+  Assert(k >= 0);
+  NodeManager* nm = NodeManager::currentNM();
+  return nm->mkConst<Rational>(intpow2(k));
+}
+
+bool oneBitAnd(bool a, bool b) { return (a && b); }
+
+Node IAndTable::createITEFromTable(
+    Node x,
+    Node y,
+    uint64_t granularity,
+    const std::map<std::pair<uint64_t, uint64_t>, uint64_t>& table)
+{
+  NodeManager* nm = NodeManager::currentNM();
+  Assert(granularity <= 8);
+  uint64_t max_value = ((uint64_t)pow(2, granularity));
+  // The table represents a function from pairs of integers to integers, where
+  // all integers are between 0 (inclusive) and max_value (exclusive).
+  Assert(table.size() == max_value * max_value);
+  Node ite = nm->mkConst<Rational>(table.at(std::make_pair(0, 0)));
+  for (uint64_t i = 0; i < max_value; i++)
+  {
+    for (uint64_t j = 0; j < max_value; j++)
+    {
+      if ((i == 0) && (j == 0))
+      {
+        continue;
+      }
+      ite = nm->mkNode(
+          kind::ITE,
+          nm->mkNode(kind::AND,
+                     nm->mkNode(kind::EQUAL, x, nm->mkConst<Rational>(i)),
+                     nm->mkNode(kind::EQUAL, y, nm->mkConst<Rational>(j))),
+          nm->mkConst<Rational>(table.at(std::make_pair(i, j))),
+          ite);
+    }
+  }
+  return ite;
+}
+
+Node IAndTable::createBitwiseNode(Node x,
+                                  Node y,
+                                  uint64_t bvsize,
+                                  uint64_t granularity)
+{
+  NodeManager* nm = NodeManager::currentNM();
+  /**
+   * Standardize granularity.
+   * If it is greater than bvsize, it is set to bvsize.
+   * Otherwise, it is set to the closest (going down)  divider of bvsize.
+   */
+  Assert(0 < granularity && granularity <= 8);
+  if (granularity > bvsize)
+  {
+    granularity = bvsize;
+  }
+  else
+  {
+    while (bvsize % granularity != 0)
+    {
+      granularity = granularity - 1;
+    }
+  }
+  // transform f into a table
+  // f is defined over 1 bit, while the table is defined over `granularity` bits
+  std::map<std::pair<uint64_t, uint64_t>, uint64_t> table;
+  uint64_t max_value = ((uint64_t)pow(2, granularity));
+  for (uint64_t i = 0; i < max_value; i++)
+  {
+    for (uint64_t j = 0; j < max_value; j++)
+    {
+      uint64_t sum = 0;
+      for (uint64_t n = 0; n < granularity; n++)
+      {
+        // b is the result of f on the current bit
+        bool b = oneBitAnd((((i >> n) & 1) == 1), (((j >> n) & 1) == 1));
+        // add the corresponding power of 2 only if the result is 1
+        if (b)
+        {
+          sum += 1 << n;
+        }
+      }
+      table[std::make_pair(i, j)] = sum;
+    }
+  }
+  Assert(table.size() == max_value * max_value);
+
+  /*
+   * Create the sum.
+   * For granularity 1, the sum has bvsize elements.
+   * In contrast, if bvsize = granularity, sum has one element.
+   * Each element in the sum is an ite that corresponds to the generated table,
+   * multiplied by the appropriate power of two.
+   * More details are in bv_to_int.h .
+   */
+  uint64_t sumSize = bvsize / granularity;
+  Node sumNode = nm->mkConst<Rational>(0);
+  /**
+   * extract definition in integers is:
+   * (define-fun intextract ((k Int) (i Int) (j Int) (a Int)) Int
+   * (mod (div a (two_to_the j)) (two_to_the (+ (- i j) 1))))
+   */
+  for (uint64_t i = 0; i < sumSize; i++)
+  {
+    Node xExtract = nm->mkNode(
+        kind::INTS_MODULUS_TOTAL,
+        nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i * granularity)),
+        pow2(granularity));
+    Node yExtract = nm->mkNode(
+        kind::INTS_MODULUS_TOTAL,
+        nm->mkNode(kind::INTS_DIVISION_TOTAL, y, pow2(i * granularity)),
+        pow2(granularity));
+    Node ite = createITEFromTable(xExtract, yExtract, granularity, table);
+    sumNode = nm->mkNode(kind::PLUS,
+                         sumNode,
+                         nm->mkNode(kind::MULT, pow2(i * granularity), ite));
+  }
+  return sumNode;
+}
+
+}  // namespace nl
+}  // namespace arith
+}  // namespace theory
+}  // namespace CVC4
diff --git a/src/theory/arith/nl/iand_table.h b/src/theory/arith/nl/iand_table.h
new file mode 100644 (file)
index 0000000..54c8b8d
--- /dev/null
@@ -0,0 +1,110 @@
+/*********************                                                        */
+/*! \file iand_table.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Yoni Zohar
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities to maintain finite tables that represent
+ ** the value of iand.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__IAND_TABLE_H
+#define CVC4__THEORY__ARITH__IAND_TABLE_H
+
+#include <tuple>
+#include <vector>
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+/**
+ * A class that computes tables for iand values
+ * with various bit-widths
+ */
+class IAndTable
+{
+ public:
+  /**
+   * A generic function that creates a node that represents a bitwise
+   * operation.
+   *
+   * For example: Suppose bvsize is 4, granularity is 1, and f(x,y) = x && y.
+   * Denote by ITE(a,b) the term: ite(a==0, 0, ite(b==1, 1, 0)).
+   * The result of this function would be:
+   * ITE(x[0], y[0])*2^0 + ... + ITE(x[3], y[3])*2^3
+   *
+   * For another example: Suppose bvsize is 4, granularity is 2,
+   * and f(x,y) = x && y.
+   * Denote by ITE(a,b) the term that corresponds to the following table:
+   * a | b |  ITE(a,b)
+   * ----------------
+   * 0 | 0 | 0
+   * 0 | 1 | 0
+   * 0 | 2 | 0
+   * 0 | 3 | 0
+   * 1 | 0 | 0
+   * 1 | 1 | 1
+   * 1 | 2 | 0
+   * 1 | 3 | 1
+   * 2 | 0 | 0
+   * 2 | 1 | 0
+   * 2 | 2 | 2
+   * 2 | 3 | 2
+   * 3 | 0 | 0
+   * 3 | 1 | 1
+   * 3 | 2 | 2
+   * 3 | 3 | 3
+   *
+   * For example, 2 in binary is 10 and 1 in binary is 01, and so doing
+   * "bitwise f" on them gives 00.
+   * The result of this function would be:
+   * ITE(x[1:0], y[1:0])*2^0 + ITE(x[3:2], y[3:2])*2^2
+   *
+   *
+   * @param x is an integer operand that correspond to the first original
+   *        bit-vector operand.
+   * @param y is an integer operand that correspond to the second original
+   *        bit-vector operand.
+   * @param bvsize is the bit width of the original bit-vector variables.
+   * @param granularity is specified in the options for this preprocessing
+   *        pass.
+   * @param f is a pointer to a boolean function that corresponds
+   *        to the original bitwise operation.
+   * @return A node that represents the operation, as described above.
+   */
+  Node createBitwiseNode(Node x, Node y, uint64_t bvsize, uint64_t granularity);
+
+  /**
+   * A helper function for createBitwiseNode
+   * @param x integer node corresponding to the original first bit-vector
+   *        argument
+   * @param y integer node corresponding to the original second bit-vector
+   *        argument nodes.
+   * @param granularity the bitwidth of the original bit-vector nodes.
+   * @param table a function from pairs of integers to integers.
+   *        The domain of this function consists of pairs of
+   *        integers between 0 (inclusive) and 2^{bitwidth} (exclusive).
+   * @return An ite term that represents this table.
+   */
+  Node createITEFromTable(
+      Node x,
+      Node y,
+      uint64_t granularity,
+      const std::map<std::pair<uint64_t, uint64_t>, uint64_t>& table);
+};
+
+}  // namespace nl
+}  // namespace arith
+}  // namespace theory
+}  // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__IAND_TABLE_H */