Skip to content

Commit 40bd2b5

Browse files
committed
SMT2 backend: workaround for Z3 get-value limitation
Z3 refuses to provide values for defined functions whose definition includes a quantifier. This commit works around this limitation by replacing define-fun by equivalent declare-fun and assert commands.
1 parent a914ead commit 40bd2b5

File tree

2 files changed

+36
-25
lines changed

2 files changed

+36
-25
lines changed

src/solvers/smt2/smt2_conv.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,16 @@ void smt2_convt::convert_address_of_rec(
789789
expr.id_string());
790790
}
791791

792+
static bool has_quantifier(const exprt &expr)
793+
{
794+
bool result = false;
795+
expr.visit_post([&result](const exprt &node) {
796+
if(node.id() == ID_exists || node.id() == ID_forall)
797+
result = true;
798+
});
799+
return result;
800+
}
801+
792802
literalt smt2_convt::convert(const exprt &expr)
793803
{
794804
PRECONDITION(expr.type().id() == ID_bool);
@@ -818,13 +828,28 @@ literalt smt2_convt::convert(const exprt &expr)
818828
// store and in future we use the literal instead of the whole expression
819829
// Note that here we are always converting, so we do not need to consider
820830
// other literal kinds, only "|B###|"
821-
defined_expressions[expr] =
822-
std::string{"|B"} + std::to_string(l.var_no()) + "|";
823-
out << "(define-fun ";
824-
convert_literal(l);
825-
out << " () Bool ";
826-
convert_expr(prepared_expr);
827-
out << ")" << "\n";
831+
832+
// Z3 refuses get-value when a defined symbol contains a quantifier.
833+
if(has_quantifier(prepared_expr))
834+
{
835+
out << "(declare-fun ";
836+
convert_literal(l);
837+
out << " () Bool)\n";
838+
out << "(assert (= ";
839+
convert_literal(l);
840+
convert_expr(prepared_expr);
841+
out << "))\n";
842+
}
843+
else
844+
{
845+
defined_expressions[expr] =
846+
std::string{"|B"} + std::to_string(l.var_no()) + "|";
847+
out << "(define-fun ";
848+
convert_literal(l);
849+
out << " () Bool ";
850+
convert_expr(prepared_expr);
851+
out << ")\n";
852+
}
828853

829854
return l;
830855
}

src/solvers/smt2/smt2_dec.cpp

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -184,24 +184,10 @@ decision_proceduret::resultt smt2_dect::read_result(std::istream &in)
184184
if(res != resultt::D_UNSATISFIABLE)
185185
{
186186
const auto &message = id2string(parsed.get_sub()[1].id());
187-
// Special case error handling
188-
if(
189-
solver == solvert::Z3 &&
190-
message.find("must not contain quantifiers") != std::string::npos)
191-
{
192-
// We tried to "(get-value |XXXX|)" where |XXXX| is determined to
193-
// include a quantified expression
194-
// Nothing to do, this should be caught and value assigned by the
195-
// set_to defaults later.
196-
}
197-
// Unhandled error, log the error and report it back up to caller
198-
else
199-
{
200-
messaget log{message_handler};
201-
log.error() << "SMT2 solver returned error message:\n"
202-
<< "\t\"" << message << "\"" << messaget::eom;
203-
return decision_proceduret::resultt::D_ERROR;
204-
}
187+
messaget log{message_handler};
188+
log.error() << "SMT2 solver returned error message:\n"
189+
<< "\t\"" << message << "\"" << messaget::eom;
190+
return decision_proceduret::resultt::D_ERROR;
205191
}
206192
}
207193
}

0 commit comments

Comments
 (0)