mirror of
https://github.com/Z3Prover/z3
synced 2025-04-26 10:35:33 +00:00
Add functionality for BDD vectors (#5198)
* Fix XOR over BDDs * Add operator<< for find_int_t * Add equality assertion macro that prints expression values on failure * Adapt contains_int and find_int to take externally-defined bits * Add more operations on BDD vectors * Remove old functions * Additional bddv functions * Rename some things * Make bddv a class and add operators * Fix find_num/contains_num calls
This commit is contained in:
parent
981839ee73
commit
4da1b7b03c
8 changed files with 499 additions and 138 deletions
226
src/test/bdd.cpp
226
src/test/bdd.cpp
|
@ -74,44 +74,217 @@ namespace dd {
|
|||
std::cout << c1.bdd_size() << "\n";
|
||||
}
|
||||
|
||||
static void test_xor() {
|
||||
bdd_manager m(4);
|
||||
bdd v0 = m.mk_var(0);
|
||||
bdd v1 = m.mk_var(0);
|
||||
SASSERT((m.mk_false() ^ v0) == v0);
|
||||
SASSERT((v0 ^ m.mk_false()) == v0);
|
||||
SASSERT((m.mk_true() ^ v0) == !v0);
|
||||
SASSERT((v0 ^ m.mk_true()) == !v0);
|
||||
SASSERT((v0 ^ v1) == ((v0 && !v1) || (!v0 && v1)));
|
||||
}
|
||||
|
||||
static void test_bddv_ops_on_constants() {
|
||||
unsigned const num_bits = 4;
|
||||
rational const modulus = rational::power_of_two(num_bits);
|
||||
bdd_manager m(num_bits);
|
||||
|
||||
SASSERT_EQ(m.to_val(m.mk_zero(num_bits)), rational(0));
|
||||
SASSERT_EQ(m.to_val(m.mk_ones(num_bits)), modulus - 1);
|
||||
|
||||
for (unsigned n = 0; n < 16; ++n) {
|
||||
rational const nr(n);
|
||||
SASSERT_EQ(m.to_val(m.mk_num(nr, num_bits)), nr);
|
||||
}
|
||||
|
||||
for (unsigned n = 0; n < 16; ++n) {
|
||||
for (unsigned k = 0; k < 16; ++k) {
|
||||
rational const nr(n);
|
||||
rational const kr(k);
|
||||
bddv const nv = m.mk_num(nr, num_bits);
|
||||
bddv const kv = m.mk_num(kr, num_bits);
|
||||
SASSERT_EQ((nv + kv).to_val(), (nr + kr) % modulus);
|
||||
SASSERT_EQ((nv * kr).to_val(), (nr * kr) % modulus);
|
||||
SASSERT_EQ((nv * kv).to_val(), (nr * kr) % modulus);
|
||||
bdd eq = m.mk_eq(nv, kv);
|
||||
SASSERT((eq.is_true() || eq.is_false()) && (eq.is_true() == (n == k)));
|
||||
eq = m.mk_eq(nv, kr);
|
||||
SASSERT((eq.is_true() || eq.is_false()) && (eq.is_true() == (n == k)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_bddv_eqfind_small() {
|
||||
bdd_manager m(4);
|
||||
unsigned_vector bits;
|
||||
bits.push_back(0);
|
||||
bddv const x = m.mk_var(bits);
|
||||
bddv const one = m.mk_num(rational(1), bits.size());
|
||||
bdd x_is_one = m.mk_eq(x, one);
|
||||
std::cout << "x_is_one:\n" << x_is_one << "\n";
|
||||
rational r;
|
||||
auto res = x_is_one.find_num(bits, r);
|
||||
SASSERT_EQ(res, find_result::singleton);
|
||||
SASSERT_EQ(r, rational(1));
|
||||
}
|
||||
|
||||
static void test_bddv_eqfind() {
|
||||
unsigned const num_bits = 4;
|
||||
bdd_manager m(num_bits);
|
||||
|
||||
unsigned_vector bits;
|
||||
bits.push_back(0);
|
||||
bits.push_back(1);
|
||||
bits.push_back(4);
|
||||
bits.push_back(27);
|
||||
|
||||
bddv const x = m.mk_var(bits);
|
||||
bddv const zero = m.mk_zero(num_bits);
|
||||
bddv const one = m.mk_num(rational(1), num_bits);
|
||||
bddv const five = m.mk_num(rational(5), num_bits);
|
||||
|
||||
SASSERT(m.mk_eq(one, rational(1)).is_true());
|
||||
SASSERT(m.mk_eq(five, rational(5)).is_true());
|
||||
SASSERT(m.mk_eq(five, rational(4)).is_false());
|
||||
SASSERT(m.mk_eq(five, five).is_true());
|
||||
SASSERT(m.mk_eq(five, one).is_false());
|
||||
|
||||
{
|
||||
bdd const x_is_five = m.mk_eq(x, rational(5));
|
||||
rational r;
|
||||
auto res = x_is_five.find_num(bits, r);
|
||||
SASSERT_EQ(res, find_result::singleton);
|
||||
SASSERT_EQ(r, rational(5));
|
||||
}
|
||||
|
||||
{
|
||||
bdd const x_is_five = m.mk_eq(bits, rational(5));
|
||||
rational r;
|
||||
auto res = x_is_five.find_num(bits, r);
|
||||
SASSERT_EQ(res, find_result::singleton);
|
||||
SASSERT_EQ(r, rational(5));
|
||||
}
|
||||
|
||||
{
|
||||
bdd const x_is_five = m.mk_eq(x, five);
|
||||
rational r;
|
||||
auto res = x_is_five.find_num(bits, r);
|
||||
SASSERT_EQ(res, find_result::singleton);
|
||||
SASSERT_EQ(r, rational(5));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_bddv_mul() {
|
||||
unsigned const num_bits = 4;
|
||||
bdd_manager m(num_bits);
|
||||
|
||||
unsigned_vector bits;
|
||||
bits.push_back(0);
|
||||
bits.push_back(1);
|
||||
bits.push_back(4);
|
||||
bits.push_back(27);
|
||||
|
||||
bddv const x = m.mk_var(bits);
|
||||
bddv const zero = m.mk_zero(num_bits);
|
||||
bddv const one = m.mk_num(rational(1), num_bits);
|
||||
bddv const five = m.mk_num(rational(5), num_bits);
|
||||
bddv const six = m.mk_num(rational(6), num_bits);
|
||||
|
||||
{
|
||||
// 5*x == 1 (mod 16) => x == 13 (mod 16)
|
||||
bdd const five_inv = x * five == one;
|
||||
rational r;
|
||||
auto res = five_inv.find_num(bits, r);
|
||||
SASSERT_EQ(res, find_result::singleton);
|
||||
SASSERT_EQ(r, rational(13));
|
||||
}
|
||||
|
||||
{
|
||||
// 6*x == 1 (mod 16) => no solution for x
|
||||
bdd const six_inv = x * six == one;
|
||||
rational r;
|
||||
auto res = six_inv.find_num(bits, r);
|
||||
SASSERT_EQ(res, find_result::empty);
|
||||
SASSERT(six_inv.is_false());
|
||||
}
|
||||
|
||||
{
|
||||
// 6*x == 0 (mod 16) => x is either 0 or 8 (mod 16)
|
||||
bdd const b = six * x == zero;
|
||||
rational r;
|
||||
SASSERT(b.contains_num(rational(0), bits));
|
||||
SASSERT(b.contains_num(rational(8), bits));
|
||||
SASSERT((b && (x != rational(0)) && (x != rational(8))).is_false());
|
||||
SASSERT((b && (x != rational(0))) == (x == rational(8)));
|
||||
}
|
||||
|
||||
SASSERT_EQ((x * zero).get_bits(), (x * rational(0)).get_bits());
|
||||
SASSERT_EQ((x * one).get_bits(), (x * rational(1)).get_bits());
|
||||
SASSERT_EQ((x * five).get_bits(), (x * rational(5)).get_bits());
|
||||
SASSERT_EQ((x * six).get_bits(), (x * rational(6)).get_bits());
|
||||
}
|
||||
|
||||
static void test_int() {
|
||||
unsigned const w = 3; // bit width
|
||||
unsigned_vector bits;
|
||||
bits.push_back(0);
|
||||
bits.push_back(1);
|
||||
bits.push_back(2);
|
||||
bdd_manager m(w);
|
||||
|
||||
bddv const x = m.mk_var(bits);
|
||||
|
||||
// Encodes the values x satisfying a*x + b == 0 (mod 2^w) as BDD.
|
||||
auto mk_affine = [] (rational const& a, bddv const& x, rational const& b) {
|
||||
return (a*x + b == rational(0));
|
||||
};
|
||||
|
||||
vector<bdd> num;
|
||||
for (unsigned n = 0; n < (1<<w); ++n)
|
||||
num.push_back(m.mk_int(rational(n), w));
|
||||
for (unsigned k = 0; k < (1 << w); ++k)
|
||||
for (unsigned n = 0; n < (1 << w); ++n)
|
||||
SASSERT(num[k].contains_int(rational(n), w) == (n == k));
|
||||
num.push_back(m.mk_eq(x, rational(n)));
|
||||
|
||||
for (unsigned k = 0; k < (1 << w); ++k) {
|
||||
for (unsigned n = 0; n < (1 << w); ++n) {
|
||||
SASSERT(num[k].contains_num(rational(n), bits) == (n == k));
|
||||
rational r;
|
||||
SASSERT_EQ((num[n] || num[k]).find_num(bits, r), (n == k) ? find_result::singleton : find_result::multiple);
|
||||
SASSERT(r == n || r == k);
|
||||
}
|
||||
}
|
||||
|
||||
bdd s0127 = num[0] || num[1] || num[2] || num[7];
|
||||
SASSERT(s0127.contains_int(rational(0), w));
|
||||
SASSERT(s0127.contains_int(rational(1), w));
|
||||
SASSERT(s0127.contains_int(rational(2), w));
|
||||
SASSERT(!s0127.contains_int(rational(3), w));
|
||||
SASSERT(!s0127.contains_int(rational(4), w));
|
||||
SASSERT(!s0127.contains_int(rational(5), w));
|
||||
SASSERT(!s0127.contains_int(rational(6), w));
|
||||
SASSERT(s0127.contains_int(rational(7), w));
|
||||
SASSERT(s0127.contains_num(rational(0), bits));
|
||||
SASSERT(s0127.contains_num(rational(1), bits));
|
||||
SASSERT(s0127.contains_num(rational(2), bits));
|
||||
SASSERT(!s0127.contains_num(rational(3), bits));
|
||||
SASSERT(!s0127.contains_num(rational(4), bits));
|
||||
SASSERT(!s0127.contains_num(rational(5), bits));
|
||||
SASSERT(!s0127.contains_num(rational(6), bits));
|
||||
SASSERT(s0127.contains_num(rational(7), bits));
|
||||
|
||||
bdd s123 = num[1] || num[2] || num[3];
|
||||
SASSERT((s0127 && s123) == (num[1] || num[2]));
|
||||
|
||||
// larger width constrains additional bits
|
||||
SASSERT(m.mk_int(rational(6), 3) != m.mk_int(rational(6), 4));
|
||||
SASSERT(mk_affine(rational(0), x, rational(0)).is_true());
|
||||
SASSERT(mk_affine(rational(0), x, rational(1)).is_false());
|
||||
// 2*x == 0 (mod 2^3) has the solutions 0, 4
|
||||
SASSERT(mk_affine(rational(2), x, rational(0)) == (num[0] || num[4]));
|
||||
|
||||
// 4*x + 2 == 0 (mod 2^3) has no solutions
|
||||
SASSERT(m.mk_affine(rational(4), rational(2), 3).is_false());
|
||||
SASSERT(mk_affine(rational(4), x, rational(2)).is_false());
|
||||
// 3*x + 2 == 0 (mod 2^3) has the unique solution 2
|
||||
SASSERT(m.mk_affine(rational(3), rational(2), 3) == num[2]);
|
||||
SASSERT(mk_affine(rational(3), x, rational(2)) == num[2]);
|
||||
// 2*x + 2 == 0 (mod 2^3) has the solutions 3, 7
|
||||
SASSERT(m.mk_affine(rational(2), rational(2), 3) == (num[3] || num[7]));
|
||||
// 12*x + 8 == 0 (mod 2^4) has the solutions 2, 6, 10, 14
|
||||
bdd expected = m.mk_int(rational(2), 4) || m.mk_int(rational(6), 4) || m.mk_int(rational(10), 4) || m.mk_int(rational(14), 4);
|
||||
SASSERT(m.mk_affine(rational(12), rational(8), 4) == expected);
|
||||
SASSERT(mk_affine(rational(2), x, rational(2)) == (num[3] || num[7]));
|
||||
|
||||
SASSERT(m.mk_affine(rational(0), rational(0), 3).is_true());
|
||||
SASSERT(m.mk_affine(rational(0), rational(1), 3).is_false());
|
||||
// 2*x == 0 (mod 2^3) has the solutions 0, 4
|
||||
SASSERT(m.mk_affine(rational(2), rational(0), 3) == (num[0] || num[4]));
|
||||
unsigned_vector bits4 = bits;
|
||||
bits4.push_back(10);
|
||||
bddv const x4 = m.mk_var(bits4);
|
||||
|
||||
// 12*x + 8 == 0 (mod 2^4) has the solutions 2, 6, 10, 14
|
||||
bdd expected = m.mk_eq(x4, rational(2)) || m.mk_eq(x4, rational(6)) || m.mk_eq(x4, rational(10)) || m.mk_eq(x4, rational(14));
|
||||
SASSERT(mk_affine(rational(12), x4, rational(8)) == expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,5 +293,10 @@ void tst_bdd() {
|
|||
dd::test2();
|
||||
dd::test3();
|
||||
dd::test4();
|
||||
dd::test_xor();
|
||||
dd::test_bddv_ops_on_constants();
|
||||
dd::test_bddv_eqfind_small();
|
||||
dd::test_bddv_eqfind();
|
||||
dd::test_bddv_mul();
|
||||
dd::test_int();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue