Skip to content

Commit 1a256b8

Browse files
Merge pull request #5005 from romainbrenguier/bugfix/bdd-cache
Fix a bug with the cache in the BDD to exprt conversion
2 parents b1e748a + b8850ed commit 1a256b8

File tree

3 files changed

+70
-50
lines changed

3 files changed

+70
-50
lines changed

src/solvers/prop/bdd_expr.cpp

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,14 @@ static exprt make_or(exprt a, exprt b)
105105

106106
/// Helper function for \c bddt to \c exprt conversion
107107
/// \param r: node to convert
108-
/// \param complement: whether we want the negation of the expression
109-
/// represented by r
110108
/// \param cache: map of already computed values
111109
exprt bdd_exprt::as_expr(
112110
const bdd_nodet &r,
113-
bool complement,
114111
std::unordered_map<bdd_nodet::idt, exprt> &cache) const
115112
{
116113
if(r.is_constant())
117114
{
118-
if(complement)
115+
if(r.is_complement())
119116
return false_exprt();
120117
else
121118
return true_exprt();
@@ -129,63 +126,46 @@ exprt bdd_exprt::as_expr(
129126
auto insert_result = cache.emplace(r.id(), nil_exprt());
130127
if(insert_result.second)
131128
{
132-
insert_result.first->second = [&]() -> exprt {
129+
auto result_ignoring_complementation = [&]() -> exprt {
133130
if(r.else_branch().is_constant())
134131
{
135132
if(r.then_branch().is_constant())
136133
{
137-
if(r.else_branch().is_complement() != complement)
134+
if(r.else_branch().is_complement()) // else is false
138135
return n_expr;
139-
return not_exprt(n_expr);
136+
return not_exprt(n_expr); // else is true
140137
}
141138
else
142139
{
143-
if(r.else_branch().is_complement() != complement)
140+
if(r.else_branch().is_complement()) // else is false
144141
{
145-
return make_and(
146-
n_expr,
147-
as_expr(
148-
r.then_branch(),
149-
complement != r.then_branch().is_complement(),
150-
cache));
142+
exprt then_case = as_expr(r.then_branch(), cache);
143+
return make_and(n_expr, then_case);
151144
}
152-
return make_or(
153-
not_exprt(n_expr),
154-
as_expr(
155-
r.then_branch(),
156-
complement != r.then_branch().is_complement(),
157-
cache));
145+
exprt then_case = as_expr(r.then_branch(), cache);
146+
return make_or(not_exprt(n_expr), then_case);
158147
}
159148
}
160149
else if(r.then_branch().is_constant())
161150
{
162-
if(r.then_branch().is_complement() != complement)
151+
if(r.then_branch().is_complement()) // then is false
163152
{
164-
return make_and(
165-
not_exprt(n_expr),
166-
as_expr(
167-
r.else_branch(),
168-
complement != r.else_branch().is_complement(),
169-
cache));
153+
exprt else_case = as_expr(r.else_branch(), cache);
154+
return make_and(not_exprt(n_expr), else_case);
170155
}
171-
return make_or(
172-
n_expr,
173-
as_expr(
174-
r.else_branch(),
175-
complement != r.else_branch().is_complement(),
176-
cache));
156+
exprt else_case = as_expr(r.else_branch(), cache);
157+
return make_or(n_expr, else_case);
177158
}
178-
return if_exprt(
179-
n_expr,
180-
as_expr(
181-
r.then_branch(),
182-
r.then_branch().is_complement() != complement,
183-
cache),
184-
as_expr(
185-
r.else_branch(),
186-
r.else_branch().is_complement() != complement,
187-
cache));
159+
160+
exprt then_branch = as_expr(r.then_branch(), cache);
161+
exprt else_branch = as_expr(r.else_branch(), cache);
162+
return if_exprt(n_expr, then_branch, else_branch);
188163
}();
164+
165+
insert_result.first->second =
166+
r.is_complement()
167+
? boolean_negate(std::move(result_ignoring_complementation))
168+
: result_ignoring_complementation;
189169
}
190170
return insert_result.first->second;
191171
}
@@ -194,5 +174,5 @@ exprt bdd_exprt::as_expr(const bddt &root) const
194174
{
195175
std::unordered_map<bdd_nodet::idt, exprt> cache;
196176
bdd_nodet node = bdd_mgr.bdd_node(root);
197-
return as_expr(node, node.is_complement(), cache);
177+
return as_expr(node, cache);
198178
}

src/solvers/prop/bdd_expr.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ class bdd_exprt
5050
bddt from_expr_rec(const exprt &expr);
5151
exprt as_expr(
5252
const bdd_nodet &r,
53-
bool complement,
5453
std::unordered_map<bdd_nodet::idt, exprt> &cache) const;
5554
};
5655

unit/solvers/prop/bdd_expr.cpp

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,54 @@ SCENARIO("bdd_expr", "[core][solver][prop][bdd_expr]")
5656
WHEN("It is converted to an exprt")
5757
{
5858
const exprt result = bdd_expr_converter.as_expr(bdd);
59-
THEN("It is equal to the expression (a & !b) or (!b & a)")
59+
THEN("It is equivalent to the expression !(!a || b)")
6060
{
61-
REQUIRE(result.id() == ID_and);
62-
REQUIRE(result.operands().size() == 2);
63-
REQUIRE((result.op0() == a || result.op1() == a));
64-
REQUIRE((result.op0() == not_exprt(b) || result.op1() == not_exprt(b)));
61+
const bddt to_compare =
62+
bdd_expr_converter.from_expr(not_exprt{or_exprt{not_exprt{a}, b}});
63+
REQUIRE(bdd.bdd_xor(to_compare).is_false());
64+
REQUIRE(bdd.bdd_xor(to_compare.bdd_not()).is_true());
6565
}
6666
}
6767
}
68+
69+
GIVEN("(!a | b) xor (a => b) ")
70+
{
71+
const symbol_exprt a("a", bool_typet());
72+
const symbol_exprt b("b", bool_typet());
73+
const bddt bdd = bdd_expr_converter.from_expr(
74+
xor_exprt{or_exprt{not_exprt{a}, b}, implies_exprt{a, b}});
75+
THEN("It reduces to false")
76+
{
77+
REQUIRE(bdd.is_false());
78+
}
79+
}
80+
81+
GIVEN("e = (a | b) xor (c | d)")
82+
{
83+
const symbol_exprt a("a", bool_typet());
84+
const symbol_exprt b("b", bool_typet());
85+
const symbol_exprt c("c", bool_typet());
86+
const symbol_exprt d("d", bool_typet());
87+
88+
const xor_exprt expr{or_exprt{a, b}, or_exprt{c, d}};
89+
const bddt bdd = bdd_expr_converter.from_expr(expr);
90+
91+
THEN("e xor e is false")
92+
{
93+
REQUIRE(bdd.bdd_xor(bdd_expr_converter.from_expr(expr)).is_false());
94+
}
95+
96+
THEN("e xor !e is true")
97+
{
98+
REQUIRE(
99+
bdd.bdd_xor(bdd_expr_converter.from_expr(not_exprt{expr})).is_true());
100+
}
101+
102+
THEN("Converting to expr and back to BDD gives the same BDD")
103+
{
104+
const exprt expr_of_bdd = bdd_expr_converter.as_expr(bdd);
105+
const bddt bdd_of_expr = bdd_expr_converter.from_expr(expr_of_bdd);
106+
REQUIRE(bdd_of_expr.equals(bdd));
107+
}
108+
}
68109
}

0 commit comments

Comments
 (0)