@@ -67,6 +67,7 @@ smt2_convt::smt2_convt(
67
67
use_datatypes(false ),
68
68
use_lambda_for_array(false ),
69
69
emit_set_logic(true ),
70
+ quantifier_as_defined_expr(false ),
70
71
ns(_ns),
71
72
out(_out),
72
73
benchmark(_benchmark),
@@ -136,6 +137,7 @@ smt2_convt::smt2_convt(
136
137
use_lambda_for_array = true ;
137
138
emit_set_logic = false ;
138
139
use_datatypes = true ;
140
+ quantifier_as_defined_expr = true ;
139
141
break ;
140
142
}
141
143
@@ -888,16 +890,6 @@ void smt2_convt::convert_address_of_rec(
888
890
expr.id_string ());
889
891
}
890
892
891
- static bool has_quantifier (const exprt &expr)
892
- {
893
- bool result = false ;
894
- expr.visit_post ([&result](const exprt &node) {
895
- if (node.id () == ID_exists || node.id () == ID_forall)
896
- result = true ;
897
- });
898
- return result;
899
- }
900
-
901
893
literalt smt2_convt::convert (const exprt &expr)
902
894
{
903
895
PRECONDITION (expr.is_boolean ());
@@ -928,28 +920,13 @@ literalt smt2_convt::convert(const exprt &expr)
928
920
// Note that here we are always converting, so we do not need to consider
929
921
// other literal kinds, only "|B###|"
930
922
931
- // Z3 refuses get-value when a defined symbol contains a quantifier.
932
- if (has_quantifier (prepared_expr))
933
- {
934
- out << " (declare-fun " ;
935
- convert_literal (l);
936
- out << " () Bool)\n " ;
937
- out << " (assert (= " ;
938
- convert_literal (l);
939
- out << ' ' ;
940
- convert_expr (prepared_expr);
941
- out << " ))\n " ;
942
- }
943
- else
944
- {
945
- auto identifier =
946
- convert_identifier (std::string{" B" } + std::to_string (l.var_no ()));
947
- defined_expressions[expr] = identifier;
948
- smt2_identifiers.insert (identifier);
949
- out << " (define-fun " << identifier << " () Bool " ;
950
- convert_expr (prepared_expr);
951
- out << " )\n " ;
952
- }
923
+ auto identifier =
924
+ convert_identifier (std::string{" B" } + std::to_string (l.var_no ()));
925
+ defined_expressions[expr] = identifier;
926
+ smt2_identifiers.insert (identifier);
927
+ out << " (define-fun " << identifier << " () Bool " ;
928
+ convert_expr (prepared_expr);
929
+ out << " )\n " ;
953
930
954
931
return l;
955
932
}
@@ -2439,36 +2416,50 @@ void smt2_convt::convert_expr(const exprt &expr)
2439
2416
else if (expr.id ()==ID_forall ||
2440
2417
expr.id ()==ID_exists)
2441
2418
{
2442
- const quantifier_exprt &quantifier_expr = to_quantifier_expr (expr);
2419
+ bool already_converted = false ;
2420
+ if (quantifier_as_defined_expr)
2421
+ {
2422
+ defined_expressionst::const_iterator it = defined_expressions.find (expr);
2423
+ if (it != defined_expressions.end ())
2424
+ {
2425
+ already_converted = true ;
2426
+ out << it->second ;
2427
+ }
2428
+ }
2443
2429
2444
- if (solver==solvert::MATHSAT )
2445
- // NOLINTNEXTLINE(readability/throw)
2446
- throw " MathSAT does not support quantifiers " ;
2430
+ if (!already_converted )
2431
+ {
2432
+ const quantifier_exprt &quantifier_expr = to_quantifier_expr (expr) ;
2447
2433
2448
- if (quantifier_expr.id () == ID_forall)
2449
- out << " (forall " ;
2450
- else if (quantifier_expr.id () == ID_exists)
2451
- out << " (exists " ;
2434
+ if (solver == solvert::MATHSAT)
2435
+ // NOLINTNEXTLINE(readability/throw)
2436
+ throw " MathSAT does not support quantifiers" ;
2437
+
2438
+ if (quantifier_expr.id () == ID_forall)
2439
+ out << " (forall " ;
2440
+ else if (quantifier_expr.id () == ID_exists)
2441
+ out << " (exists " ;
2452
2442
2453
- out << ' (' ;
2454
- bool first = true ;
2455
- for (const auto &bound : quantifier_expr.variables ())
2456
- {
2457
- if (first)
2458
- first = false ;
2459
- else
2460
- out << ' ' ;
2461
2443
out << ' (' ;
2462
- convert_expr (bound);
2463
- out << ' ' ;
2464
- convert_type (bound.type ());
2465
- out << ' )' ;
2466
- }
2467
- out << " ) " ;
2444
+ bool first = true ;
2445
+ for (const auto &bound : quantifier_expr.variables ())
2446
+ {
2447
+ if (first)
2448
+ first = false ;
2449
+ else
2450
+ out << ' ' ;
2451
+ out << ' (' ;
2452
+ convert_expr (bound);
2453
+ out << ' ' ;
2454
+ convert_type (bound.type ());
2455
+ out << ' )' ;
2456
+ }
2457
+ out << " ) " ;
2468
2458
2469
- convert_expr (quantifier_expr.where ());
2459
+ convert_expr (quantifier_expr.where ());
2470
2460
2471
- out << ' )' ;
2461
+ out << ' )' ;
2462
+ }
2472
2463
}
2473
2464
else if (
2474
2465
const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
@@ -5137,6 +5128,13 @@ void smt2_convt::find_symbols(const exprt &expr)
5137
5128
5138
5129
if (expr.id () == ID_exists || expr.id () == ID_forall)
5139
5130
{
5131
+ if (
5132
+ quantifier_as_defined_expr &&
5133
+ defined_expressions.find (expr) != defined_expressions.end ())
5134
+ {
5135
+ return ;
5136
+ }
5137
+
5140
5138
std::unordered_map<irep_idt, std::optional<identifiert>> shadowed_syms;
5141
5139
5142
5140
// do not declare the quantified symbol, but record
@@ -5161,6 +5159,26 @@ void smt2_convt::find_symbols(const exprt &expr)
5161
5159
else
5162
5160
previous_entry->second = std::move (*shadowed_val);
5163
5161
}
5162
+
5163
+ if (quantifier_as_defined_expr)
5164
+ {
5165
+ const irep_idt id =
5166
+ " quantified_expr." + std::to_string (defined_expressions.size ());
5167
+
5168
+ out << " ; the following is a workaround for solvers removing quantified "
5169
+ " expression during preprocessing\n " ;
5170
+ out << " (declare-fun " << id << " () Bool)\n " ;
5171
+
5172
+ out << " (assert (=> " << id << ' ' ;
5173
+ convert_expr (expr);
5174
+ out << " ))\n " ;
5175
+ out << " (assert (=> " ;
5176
+ convert_expr (expr);
5177
+ out << ' ' << id << " ))\n " ;
5178
+
5179
+ defined_expressions[expr] = id;
5180
+ }
5181
+
5164
5182
return ;
5165
5183
}
5166
5184
0 commit comments