-
Notifications
You must be signed in to change notification settings - Fork 277
Quantifiers #6550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quantifiers #6550
Changes from all commits
77442e7
5828e70
782beb8
fb6b286
6850351
e4c5999
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
CORE | ||
boolean-quantifier.smt2 | ||
|
||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^unsat$ | ||
-- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
(define-fun q1 () Bool (exists ((b Bool)) b)) | ||
(define-fun q2 () Bool (exists ((b Bool)) (not b))) | ||
|
||
(define-fun q3 () Bool (not (forall ((b Bool)) b))) | ||
(define-fun q4 () Bool (not (forall ((b Bool)) (not b)))) | ||
|
||
(define-fun q5 () Bool (exists ((a Bool) (b Bool)) (= a b))) | ||
(define-fun q6 () Bool (not (forall ((a Bool) (b Bool)) (= a b)))) | ||
|
||
(define-fun q7 () Bool (forall ((a Bool)) (exists ((b Bool)) (= a b)))) | ||
|
||
; the above are all valid, and we assert one of them is not | ||
(assert (not (and q1 q2 q3 q4 q5 q6 q7))) | ||
|
||
(check-sat) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
KNOWNBUG | ||
bv-quantifier-valid.smt2 | ||
|
||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^unsat$ | ||
-- | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
(define-fun q1 () Bool (exists ((b (_ BitVec 8))) (= b #x00))) | ||
(define-fun q2 () Bool (exists ((b (_ BitVec 8))) (not (= b #x00)))) | ||
|
||
(define-fun q3 () Bool (not (forall ((b (_ BitVec 8))) (= b #x00)))) | ||
(define-fun q4 () Bool (not (forall ((b (_ BitVec 8))) (not (= b #x00))))) | ||
|
||
(define-fun q5 () Bool (exists ((a (_ BitVec 8)) (b (_ BitVec 8))) (= a b))) | ||
(define-fun q6 () Bool (not (forall ((a (_ BitVec 8)) (b (_ BitVec 8))) (= a b)))) | ||
|
||
(define-fun q7 () Bool (forall ((a (_ BitVec 8))) (exists ((b (_ BitVec 8))) (= a b)))) | ||
|
||
; the above are all valid, and we assert one of them is not | ||
(assert (not (and q1 q2 q3 q4 q5 q6 q7))) | ||
|
||
(check-sat) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,6 @@ Author: Daniel Kroening, [email protected] | |
#include <util/invariant.h> | ||
#include <util/optional.h> | ||
#include <util/range.h> | ||
#include <util/replace_expr.h> | ||
#include <util/simplify_expr.h> | ||
|
||
/// A method to detect equivalence between experts that can contain typecast | ||
|
@@ -138,71 +137,109 @@ get_quantifier_var_max(const exprt &var_expr, const exprt &quantifier_expr) | |
return {}; | ||
} | ||
|
||
static optionalt<exprt> | ||
instantiate_quantifier(const quantifier_exprt &expr, const namespacet &ns) | ||
static optionalt<exprt> eager_quantifier_instantiation( | ||
const quantifier_exprt &expr, | ||
const namespacet &ns) | ||
{ | ||
if(expr.variables().size() > 1) | ||
{ | ||
// Qx,y.P(x,y) is the same as Qx.Qy.P(x,y) | ||
auto new_variables = expr.variables(); | ||
new_variables.pop_back(); | ||
auto new_expression = quantifier_exprt( | ||
expr.id(), | ||
expr.variables().back(), | ||
quantifier_exprt(expr.id(), new_variables, expr.where())); | ||
return eager_quantifier_instantiation(new_expression, ns); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function doesn't exist at the point of this commit (else line 142 should already say "eager_quantifier_instantiation"). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will go way once rebased on #6551. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now fixed with separate commit. |
||
} | ||
|
||
const symbol_exprt &var_expr = expr.symbol(); | ||
|
||
/** | ||
* We need to rewrite the forall/exists quantifier into | ||
* an OR/AND expr. | ||
**/ | ||
|
||
const exprt re = simplify_expr(expr.where(), ns); | ||
const exprt where_simplified = simplify_expr(expr.where(), ns); | ||
|
||
if(re.is_true() || re.is_false()) | ||
if(where_simplified.is_true() || where_simplified.is_false()) | ||
{ | ||
return re; | ||
return where_simplified; | ||
} | ||
|
||
const optionalt<constant_exprt> min_i = get_quantifier_var_min(var_expr, re); | ||
const optionalt<constant_exprt> max_i = get_quantifier_var_max(var_expr, re); | ||
if(var_expr.is_boolean()) | ||
{ | ||
// Expand in full. | ||
// This grows worst-case exponentially in the quantifier nesting depth. | ||
if(expr.id() == ID_forall) | ||
{ | ||
// ∀b.f(b) <===> f(0)∧f(1) | ||
return and_exprt( | ||
expr.instantiate({false_exprt()}), expr.instantiate({true_exprt()})); | ||
} | ||
else if(expr.id() == ID_exists) | ||
{ | ||
// ∃b.f(b) <===> f(0)∨f(1) | ||
return or_exprt( | ||
expr.instantiate({false_exprt()}), expr.instantiate({true_exprt()})); | ||
} | ||
else | ||
UNREACHABLE; | ||
} | ||
|
||
const optionalt<constant_exprt> min_i = | ||
get_quantifier_var_min(var_expr, where_simplified); | ||
const optionalt<constant_exprt> max_i = | ||
get_quantifier_var_max(var_expr, where_simplified); | ||
|
||
if(!min_i.has_value() || !max_i.has_value()) | ||
return nullopt; | ||
|
||
mp_integer lb = numeric_cast_v<mp_integer>(min_i.value()); | ||
mp_integer ub = numeric_cast_v<mp_integer>(max_i.value()); | ||
|
||
if(lb>ub) | ||
if(lb > ub) | ||
return nullopt; | ||
|
||
auto expr_simplified = | ||
quantifier_exprt(expr.id(), expr.variables(), where_simplified); | ||
|
||
std::vector<exprt> expr_insts; | ||
for(mp_integer i=lb; i<=ub; ++i) | ||
for(mp_integer i = lb; i <= ub; ++i) | ||
{ | ||
exprt constraint_expr = re; | ||
replace_expr(var_expr, | ||
from_integer(i, var_expr.type()), | ||
constraint_expr); | ||
exprt constraint_expr = | ||
expr_simplified.instantiate({from_integer(i, var_expr.type())}); | ||
expr_insts.push_back(constraint_expr); | ||
} | ||
|
||
if(expr.id()==ID_forall) | ||
if(expr.id() == ID_forall) | ||
{ | ||
// maintain the domain constraint if it isn't guaranteed by the | ||
// instantiations (for a disjunction the domain constraint is implied by the | ||
// instantiations) | ||
if(re.id() == ID_and) | ||
// maintain the domain constraint if it isn't guaranteed | ||
// by the instantiations (for a disjunction the domain | ||
// constraint is implied by the instantiations) | ||
if(where_simplified.id() == ID_and) | ||
{ | ||
expr_insts.push_back(binary_predicate_exprt( | ||
var_expr, ID_gt, from_integer(lb, var_expr.type()))); | ||
expr_insts.push_back(binary_predicate_exprt( | ||
var_expr, ID_le, from_integer(ub, var_expr.type()))); | ||
} | ||
|
||
return simplify_expr(conjunction(expr_insts), ns); | ||
} | ||
else if(expr.id() == ID_exists) | ||
{ | ||
// maintain the domain constraint if it isn't trivially satisfied by the | ||
// instantiations (for a conjunction the instantiations are stronger | ||
// constraints) | ||
if(re.id() == ID_or) | ||
// maintain the domain constraint if it isn't trivially satisfied | ||
// by the instantiations (for a conjunction the instantiations are | ||
// stronger constraints) | ||
if(where_simplified.id() == ID_or) | ||
{ | ||
expr_insts.push_back(binary_predicate_exprt( | ||
var_expr, ID_gt, from_integer(lb, var_expr.type()))); | ||
expr_insts.push_back(binary_predicate_exprt( | ||
var_expr, ID_le, from_integer(ub, var_expr.type()))); | ||
} | ||
|
||
return simplify_expr(disjunction(expr_insts), ns); | ||
} | ||
|
||
|
@@ -223,7 +260,7 @@ literalt boolbvt::convert_quantifier(const quantifier_exprt &src) | |
auto new_src = | ||
quantifier_exprt(src.id(), std::move(fresh_symbols), where_replaced); | ||
|
||
const auto res = instantiate_quantifier(src, ns); | ||
const auto res = eager_quantifier_instantiation(src, ns); | ||
|
||
if(res) | ||
return convert_bool(*res); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be helpful for either this file or the commit message to include an explanation what exactly is missing here.