@@ -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,16 @@ 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 ()));
923
+ auto identifier =
924
+ convert_identifier (std::string{" B" } + std::to_string (l.var_no ()));
925
+ // we might already have put expr in defined_expressions via
926
+ // prepare_for_convert_expr
927
+ if (defined_expressions.find (expr) == defined_expressions.end ())
947
928
defined_expressions[expr] = identifier;
948
- smt2_identifiers.insert (identifier);
949
- out << " (define-fun " << identifier << " () Bool " ;
950
- convert_expr (prepared_expr);
951
- out << " )\n " ;
952
- }
929
+ smt2_identifiers.insert (identifier);
930
+ out << " (define-fun " << identifier << " () Bool " ;
931
+ convert_expr (prepared_expr);
932
+ out << " )\n " ;
953
933
954
934
return l;
955
935
}
@@ -2439,36 +2419,50 @@ void smt2_convt::convert_expr(const exprt &expr)
2439
2419
else if (expr.id ()==ID_forall ||
2440
2420
expr.id ()==ID_exists)
2441
2421
{
2442
- const quantifier_exprt &quantifier_expr = to_quantifier_expr (expr);
2422
+ bool already_converted = false ;
2423
+ if (quantifier_as_defined_expr)
2424
+ {
2425
+ defined_expressionst::const_iterator it = defined_expressions.find (expr);
2426
+ if (it != defined_expressions.end ())
2427
+ {
2428
+ already_converted = true ;
2429
+ out << it->second ;
2430
+ }
2431
+ }
2443
2432
2444
- if (solver==solvert::MATHSAT )
2445
- // NOLINTNEXTLINE(readability/throw)
2446
- throw " MathSAT does not support quantifiers " ;
2433
+ if (!already_converted )
2434
+ {
2435
+ const quantifier_exprt &quantifier_expr = to_quantifier_expr (expr) ;
2447
2436
2448
- if (quantifier_expr.id () == ID_forall)
2449
- out << " (forall " ;
2450
- else if (quantifier_expr.id () == ID_exists)
2451
- out << " (exists " ;
2437
+ if (solver == solvert::MATHSAT)
2438
+ // NOLINTNEXTLINE(readability/throw)
2439
+ throw " MathSAT does not support quantifiers" ;
2440
+
2441
+ if (quantifier_expr.id () == ID_forall)
2442
+ out << " (forall " ;
2443
+ else if (quantifier_expr.id () == ID_exists)
2444
+ out << " (exists " ;
2452
2445
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
2446
out << ' (' ;
2462
- convert_expr (bound);
2463
- out << ' ' ;
2464
- convert_type (bound.type ());
2465
- out << ' )' ;
2466
- }
2467
- out << " ) " ;
2447
+ bool first = true ;
2448
+ for (const auto &bound : quantifier_expr.variables ())
2449
+ {
2450
+ if (first)
2451
+ first = false ;
2452
+ else
2453
+ out << ' ' ;
2454
+ out << ' (' ;
2455
+ convert_expr (bound);
2456
+ out << ' ' ;
2457
+ convert_type (bound.type ());
2458
+ out << ' )' ;
2459
+ }
2460
+ out << " ) " ;
2468
2461
2469
- convert_expr (quantifier_expr.where ());
2462
+ convert_expr (quantifier_expr.where ());
2470
2463
2471
- out << ' )' ;
2464
+ out << ' )' ;
2465
+ }
2472
2466
}
2473
2467
else if (
2474
2468
const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
@@ -5137,30 +5131,61 @@ void smt2_convt::find_symbols(const exprt &expr)
5137
5131
5138
5132
if (expr.id () == ID_exists || expr.id () == ID_forall)
5139
5133
{
5134
+ if (
5135
+ quantifier_as_defined_expr &&
5136
+ defined_expressions.find (expr) != defined_expressions.end ())
5137
+ {
5138
+ return ;
5139
+ }
5140
+
5140
5141
std::unordered_map<irep_idt, std::optional<identifiert>> shadowed_syms;
5141
5142
5142
5143
// do not declare the quantified symbol, but record
5143
5144
// as 'bound symbol'
5144
5145
const auto &q_expr = to_quantifier_expr (expr);
5145
- for (const auto &symbol : q_expr.variables ())
5146
- {
5147
- const auto identifier = symbol.get_identifier ();
5148
- auto id_entry =
5149
- identifier_map.insert ({identifier, identifiert{symbol.type (), true }});
5150
- shadowed_syms.insert (
5151
- {identifier,
5152
- id_entry.second ? std::nullopt
5153
- : std::optional{id_entry.first ->second }});
5154
- }
5155
- find_symbols (q_expr.where ());
5156
- for (const auto &[id, shadowed_val] : shadowed_syms)
5157
- {
5158
- auto previous_entry = identifier_map.find (id);
5159
- if (!shadowed_val.has_value ())
5160
- identifier_map.erase (previous_entry);
5161
- else
5162
- previous_entry->second = std::move (*shadowed_val);
5146
+ if (!quantifier_as_defined_expr)
5147
+ {
5148
+ for (const auto &symbol : q_expr.variables ())
5149
+ {
5150
+ const auto identifier = symbol.get_identifier ();
5151
+ auto id_entry =
5152
+ identifier_map.insert ({identifier, identifiert{symbol.type (), true }});
5153
+ shadowed_syms.insert (
5154
+ {identifier,
5155
+ id_entry.second ? std::nullopt
5156
+ : std::optional{id_entry.first ->second }});
5157
+ }
5158
+ find_symbols (q_expr.where ());
5159
+ for (const auto &[id, shadowed_val] : shadowed_syms)
5160
+ {
5161
+ auto previous_entry = identifier_map.find (id);
5162
+ if (!shadowed_val.has_value ())
5163
+ identifier_map.erase (previous_entry);
5164
+ else
5165
+ previous_entry->second = std::move (*shadowed_val);
5166
+ }
5167
+ }
5168
+ else
5169
+ {
5170
+ find_symbols (q_expr.where ());
5171
+
5172
+ const irep_idt id =
5173
+ " quantified_expr." + std::to_string (defined_expressions.size ());
5174
+
5175
+ out << " ; the following is a workaround for solvers removing quantified "
5176
+ " expression during preprocessing\n " ;
5177
+ out << " (declare-fun " << id << " () Bool)\n " ;
5178
+
5179
+ out << " (assert (=> " << id << ' ' ;
5180
+ convert_expr (expr);
5181
+ out << " ))\n " ;
5182
+ out << " (assert (=> " ;
5183
+ convert_expr (expr);
5184
+ out << ' ' << id << " ))\n " ;
5185
+
5186
+ defined_expressions[expr] = id;
5163
5187
}
5188
+
5164
5189
return ;
5165
5190
}
5166
5191
0 commit comments