Skip to content

Commit dd74a57

Browse files
committed
add expansion for quantifiers over booleans
This adds support for eager instantiation of quantifiers over booleans, using George Boole's Proposition II.
1 parent 2fff5b9 commit dd74a57

File tree

1 file changed

+64
-42
lines changed

1 file changed

+64
-42
lines changed

src/solvers/flattening/boolbv_quantifier.cpp

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -169,58 +169,80 @@ static optionalt<exprt> eager_quantifier_instantiation(
169169
return re;
170170
}
171171

172-
const optionalt<constant_exprt> min_i = get_quantifier_var_min(var_expr, re);
173-
const optionalt<constant_exprt> max_i = get_quantifier_var_max(var_expr, re);
172+
if(re.is_boolean())
173+
{
174+
// Expand in full.
175+
// This grows worst-case exponentially in the quantifier nesting depth.
176+
if(expr.id() == ID_forall)
177+
{
178+
// ∀b.f(b) <===> f(0)∧f(1)
179+
return and_exprt(
180+
expr.instantiate({false_exprt()}), expr.instantiate({true_exprt()}));
181+
}
182+
else if(expr.id() == ID_exists)
183+
{
184+
// ∃b.f(b) <===> f(0)∨f(1)
185+
return or_exprt(
186+
expr.instantiate({false_exprt()}), expr.instantiate({true_exprt()}));
187+
}
188+
else
189+
UNREACHABLE;
190+
}
191+
else
192+
{
193+
const optionalt<constant_exprt> min_i =
194+
get_quantifier_var_min(var_expr, re);
195+
const optionalt<constant_exprt> max_i =
196+
get_quantifier_var_max(var_expr, re);
174197

175-
if(!min_i.has_value() || !max_i.has_value())
176-
return nullopt;
198+
if(!min_i.has_value() || !max_i.has_value())
199+
return nullopt;
177200

178-
mp_integer lb = numeric_cast_v<mp_integer>(min_i.value());
179-
mp_integer ub = numeric_cast_v<mp_integer>(max_i.value());
201+
mp_integer lb = numeric_cast_v<mp_integer>(min_i.value());
202+
mp_integer ub = numeric_cast_v<mp_integer>(max_i.value());
180203

181-
if(lb>ub)
182-
return nullopt;
204+
if(lb > ub)
205+
return nullopt;
183206

184-
std::vector<exprt> expr_insts;
185-
for(mp_integer i=lb; i<=ub; ++i)
186-
{
187-
exprt constraint_expr = re;
188-
replace_expr(var_expr,
189-
from_integer(i, var_expr.type()),
190-
constraint_expr);
191-
expr_insts.push_back(constraint_expr);
192-
}
207+
std::vector<exprt> expr_insts;
208+
for(mp_integer i = lb; i <= ub; ++i)
209+
{
210+
exprt constraint_expr = re;
211+
replace_expr(var_expr, from_integer(i, var_expr.type()), constraint_expr);
212+
expr_insts.push_back(constraint_expr);
213+
}
193214

194-
if(expr.id()==ID_forall)
195-
{
196-
// maintain the domain constraint if it isn't guaranteed by the
197-
// instantiations (for a disjunction the domain constraint is implied by the
198-
// instantiations)
199-
if(re.id() == ID_and)
215+
if(expr.id() == ID_forall)
200216
{
201-
expr_insts.push_back(binary_predicate_exprt(
202-
var_expr, ID_gt, from_integer(lb, var_expr.type())));
203-
expr_insts.push_back(binary_predicate_exprt(
204-
var_expr, ID_le, from_integer(ub, var_expr.type())));
217+
// maintain the domain constraint if it isn't guaranteed by the
218+
// instantiations (for a disjunction the domain constraint is implied by the
219+
// instantiations)
220+
if(re.id() == ID_and)
221+
{
222+
expr_insts.push_back(binary_predicate_exprt(
223+
var_expr, ID_gt, from_integer(lb, var_expr.type())));
224+
expr_insts.push_back(binary_predicate_exprt(
225+
var_expr, ID_le, from_integer(ub, var_expr.type())));
226+
}
227+
return simplify_expr(conjunction(expr_insts), ns);
205228
}
206-
return simplify_expr(conjunction(expr_insts), ns);
207-
}
208-
else if(expr.id() == ID_exists)
209-
{
210-
// maintain the domain constraint if it isn't trivially satisfied by the
211-
// instantiations (for a conjunction the instantiations are stronger
212-
// constraints)
213-
if(re.id() == ID_or)
229+
else if(expr.id() == ID_exists)
214230
{
215-
expr_insts.push_back(binary_predicate_exprt(
216-
var_expr, ID_gt, from_integer(lb, var_expr.type())));
217-
expr_insts.push_back(binary_predicate_exprt(
218-
var_expr, ID_le, from_integer(ub, var_expr.type())));
231+
// maintain the domain constraint if it isn't trivially satisfied by the
232+
// instantiations (for a conjunction the instantiations are stronger
233+
// constraints)
234+
if(re.id() == ID_or)
235+
{
236+
expr_insts.push_back(binary_predicate_exprt(
237+
var_expr, ID_gt, from_integer(lb, var_expr.type())));
238+
expr_insts.push_back(binary_predicate_exprt(
239+
var_expr, ID_le, from_integer(ub, var_expr.type())));
240+
}
241+
return simplify_expr(disjunction(expr_insts), ns);
219242
}
220-
return simplify_expr(disjunction(expr_insts), ns);
221-
}
222243

223-
UNREACHABLE;
244+
UNREACHABLE;
245+
}
224246
}
225247

226248
literalt boolbvt::convert_quantifier(const quantifier_exprt &src)

0 commit comments

Comments
 (0)