@@ -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,16 @@ 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 ()));
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 ())
947928 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 " ;
953933
954934 return l;
955935}
@@ -2439,36 +2419,50 @@ void smt2_convt::convert_expr(const exprt &expr)
24392419 else if (expr.id ()==ID_forall ||
24402420 expr.id ()==ID_exists)
24412421 {
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+ }
24432432
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) ;
24472436
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 " ;
24522445
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 << ' ' ;
24612446 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 << " ) " ;
24682461
2469- convert_expr (quantifier_expr.where ());
2462+ convert_expr (quantifier_expr.where ());
24702463
2471- out << ' )' ;
2464+ out << ' )' ;
2465+ }
24722466 }
24732467 else if (
24742468 const auto object_size = expr_try_dynamic_cast<object_size_exprt>(expr))
@@ -5137,30 +5131,61 @@ void smt2_convt::find_symbols(const exprt &expr)
51375131
51385132 if (expr.id () == ID_exists || expr.id () == ID_forall)
51395133 {
5134+ if (
5135+ quantifier_as_defined_expr &&
5136+ defined_expressions.find (expr) != defined_expressions.end ())
5137+ {
5138+ return ;
5139+ }
5140+
51405141 std::unordered_map<irep_idt, std::optional<identifiert>> shadowed_syms;
51415142
51425143 // do not declare the quantified symbol, but record
51435144 // as 'bound symbol'
51445145 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;
51635187 }
5188+
51645189 return ;
51655190 }
51665191
0 commit comments