@@ -67,6 +67,7 @@ smt2_convt::smt2_convt(
6767 use_datatypes(false ),
6868 use_lambda_for_array(false ),
6969 emit_set_logic(true ),
70+ quantifier_as_defined_expr(false ),
7071 ns(_ns),
7172 out(_out),
7273 benchmark(_benchmark),
@@ -136,6 +137,7 @@ smt2_convt::smt2_convt(
136137 use_lambda_for_array = true ;
137138 emit_set_logic = false ;
138139 use_datatypes = true ;
140+ quantifier_as_defined_expr = true ;
139141 break ;
140142 }
141143
@@ -888,16 +890,6 @@ void smt2_convt::convert_address_of_rec(
888890 expr.id_string ());
889891}
890892
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-
901893literalt smt2_convt::convert (const exprt &expr)
902894{
903895 PRECONDITION (expr.is_boolean ());
@@ -928,28 +920,13 @@ literalt smt2_convt::convert(const exprt &expr)
928920 // Note that here we are always converting, so we do not need to consider
929921 // other literal kinds, only "|B###|"
930922
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 " ;
953930
954931 return l;
955932}
@@ -2439,36 +2416,50 @@ void smt2_convt::convert_expr(const exprt &expr)
24392416 else if (expr.id ()==ID_forall ||
24402417 expr.id ()==ID_exists)
24412418 {
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+ }
24432429
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) ;
24472433
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 " ;
24522442
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 << ' ' ;
24612443 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 << " ) " ;
24682458
2469- convert_expr (quantifier_expr.where ());
2459+ convert_expr (quantifier_expr.where ());
24702460
2471- out << ' )' ;
2461+ out << ' )' ;
2462+ }
24722463 }
24732464 else if (
24742465 const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
@@ -5137,6 +5128,13 @@ void smt2_convt::find_symbols(const exprt &expr)
51375128
51385129 if (expr.id () == ID_exists || expr.id () == ID_forall)
51395130 {
5131+ if (
5132+ quantifier_as_defined_expr &&
5133+ defined_expressions.find (expr) != defined_expressions.end ())
5134+ {
5135+ return ;
5136+ }
5137+
51405138 std::unordered_map<irep_idt, std::optional<identifiert>> shadowed_syms;
51415139
51425140 // do not declare the quantified symbol, but record
@@ -5161,6 +5159,26 @@ void smt2_convt::find_symbols(const exprt &expr)
51615159 else
51625160 previous_entry->second = std::move (*shadowed_val);
51635161 }
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+
51645182 return ;
51655183 }
51665184
0 commit comments