#if VZ3
#define UNIMPLEMENTED ASSERTION_VIOLATION
#define MODEL_COMPLETION true
#include "Forwards.hpp"
#include "SATSolver.hpp"
#include "SATLiteral.hpp"
#include "SATClause.hpp"
#include "Lib/Environment.hpp"
#include "Kernel/NumTraits.hpp"
#include "Kernel/Signature.hpp"
#include "Kernel/OperatorType.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/SubstHelper.hpp"
#include "Kernel/BottomUpEvaluation.hpp"
#include "Lib/Coproduct.hpp"
#include "Shell/UIHelper.hpp"
#include "Z3Interfacing.hpp"
#include <unordered_set>
#define DEBUG(...)
#define TRACE_Z3 0
#define INSTANTIATE_EXPRESSIONS 0
#define ENABLE_Z3_PROOF_GENERATION 0
namespace Lib {
using SortId = TermList;
template<>
struct BottomUpChildIter<z3::expr>
{
unsigned _idx;
z3::expr _self;
BottomUpChildIter(z3::expr a, EmptyContext = EmptyContext()) : _idx(0), _self(a) {}
z3::expr self(EmptyContext = EmptyContext()) { return _self; }
z3::expr next(EmptyContext = EmptyContext()) { return _self.arg(_idx++); }
bool hasNext(EmptyContext = EmptyContext()) { return _self.is_app() && _idx < _self.num_args(); }
unsigned nChildren(EmptyContext = EmptyContext()) { return _self.is_app() ? _self.num_args() : 0; }
};
}
auto quotient0_name(char c, z3::sort s)
{ return Output::toString("quot-0-", c, "-", s); }
auto remainder0_name(char c, z3::sort s)
{ return Output::toString("rem-0-", c, "-", s); }
template<class UInt64ToExpr>
z3::expr int_to_z3_expr(IntegerConstantType const& val, UInt64ToExpr toExpr) {
auto sign = val.sign();
auto abs = val.abs();
RStack<uint64_t> digits;
z3::expr base = toExpr(std::numeric_limits<uint64_t>::max()) + toExpr(1);
while(!abs.fits<unsigned long>()) {
auto ui = abs.truncate<unsigned long>();
using ui_t = decltype(ui);
static_assert(sizeof(ui_t) == sizeof(uint64_t), "unexpected number size");
static_assert(sizeof(ui_t) == 64 / 8, "unexpected number size");
static_assert(std::numeric_limits<ui_t>::max() == std::numeric_limits<uint64_t>::max(), "unexpected number size");
digits->push(uint64_t(ui));
abs.rshiftBits(64);
}
z3::expr res = toExpr(uint64_t(abs.template truncate<unsigned int>()));
while(digits->isNonEmpty()) {
res = toExpr(digits->pop()) + (res * base);
}
return sign == Sign::Neg ? -res : res;
}
template<class Real>
z3::expr to_z3_expr(Real const& val, z3::context& ctx)
{
auto num = int_to_z3_expr(val.numerator() , [&](uint64_t i) { return ctx.real_val(i); });
auto den = int_to_z3_expr(val.denominator(), [&](uint64_t i) { return ctx.real_val(i); });
return num / den;
}
z3::expr to_z3_expr(IntegerConstantType const& val, z3::context& ctx)
{ return int_to_z3_expr(val, [&](uint64_t i) { return ctx.int_val(i); }); }
namespace SAT
{
using namespace std;
using namespace Shell;
using namespace Lib;
using ProblemExportSyntax = Shell::Options::ProblemExportSyntax;
Z3Interfacing::Z3Interfacing(const Shell::Options& opts, SAT2FO& s2f, bool unsatCore, std::string const& exportFile,Shell::Options::ProblemExportSyntax exportSyntax):
Z3Interfacing(s2f, opts.showZ3(), unsatCore, exportFile, exportSyntax)
{ }
const char* errToString(Z3_error_code code)
{
switch (code) {
case Z3_OK: return "Z3_OK";
case Z3_SORT_ERROR: return "Z3_SORT_ERROR";
case Z3_IOB: return "Z3_IOB";
case Z3_INVALID_ARG: return "Z3_INVALID_ARG";
case Z3_PARSER_ERROR: return "Z3_PARSER_ERROR";
case Z3_NO_PARSER: return "Z3_NO_PARSER";
case Z3_INVALID_PATTERN: return "Z3_INVALID_PATTERN";
case Z3_MEMOUT_FAIL: return "Z3_MEMOUT_FAIL";
case Z3_FILE_ACCESS_ERROR: return "Z3_FILE_ACCESS_ERROR";
case Z3_INTERNAL_FATAL: return "Z3_INTERNAL_FATAL";
case Z3_INVALID_USAGE: return "Z3_INVALID_USAGE";
case Z3_DEC_REF_ERROR: return "Z3_DEC_REF_ERROR";
case Z3_EXCEPTION: return "Z3_EXCEPTION";
}
ASSERTION_VIOLATION; return "UNKNOWN ERROR";
}
struct Z3MkConstructorCall {
Z3_context c;
Z3_symbol name;
Z3_symbol tester;
Stack<Z3_symbol> field_names;
Stack<Z3_sort> sorts;
Stack<unsigned> sort_refs;
unsigned arity() { return field_names.size(); }
Z3_constructor operator()() {
return Z3_mk_constructor(
c,
name,
tester,
arity(),
field_names.begin(),
sorts.begin(),
sort_refs.begin()
);
}
};
struct Z3Constructor
{
z3::func_decl func;
z3::func_decl tester;
Stack<z3::func_decl> args;
};
struct Z3Datatype
{
z3::sort sort;
Stack<Z3Constructor> ctors;
};
struct Z3MkDatatypesCall
{
std::unique_ptr<z3::context>& _context;
Stack<Z3_symbol> sortNames; Stack<Stack<Z3MkConstructorCall>> mkConstrs;
Z3MkDatatypesCall(decltype(_context) context, Stack<TermAlgebra*> const& tas)
: _context(context)
, sortNames(tas.size())
, mkConstrs(tas.size())
{ }
unsigned nDtys() { return sortNames.size(); }
Stack<Z3Datatype> operator()(){
Array<Z3_sort> sorts;
Stack<Z3_constructor_list> z3_ctor_lists(nDtys()); Stack<Stack<Z3_constructor>> ctorss; for (auto& mks : mkConstrs) {
Stack<Z3_constructor> ctors(mks.size());
for (auto& mkConstr : mks) {
ctors.push(mkConstr());
}
z3_ctor_lists.push(Z3_mk_constructor_list(*_context, ctors.size(), ctors.begin()));
ctorss.push(std::move(ctors));
}
Z3_mk_datatypes(*_context, nDtys(), sortNames.begin(), sorts.begin(), z3_ctor_lists.begin());
Stack<Z3Datatype> out(nDtys());
for (unsigned i = 0; i < ctorss.size(); i++) {
auto sort = z3::sort(*_context, sorts[i]);
Stack<Z3Constructor> ctors_res(ctorss[i].size());
for (unsigned j = 0; j < ctorss[i].size(); j++) {
Z3_func_decl func;
Z3_func_decl tester;
DArray<Z3_func_decl> args(mkConstrs[i][j].arity());
Z3_query_constructor(*_context, ctorss[i][j], mkConstrs[i][j].arity(), &func, &tester, args.begin());
ctors_res.push(Z3Constructor {
.func = z3::func_decl(*_context, func),
.tester = z3::func_decl(*_context, tester),
.args = arrayIter(args)
.map([&](auto arg) { return z3::func_decl(*_context, arg); })
.template collect<Stack>(),
});
}
out.push(Z3Datatype { .sort = sort, .ctors = std::move(ctors_res), });
}
for (auto& lst : z3_ctor_lists) {
Z3_del_constructor_list(*_context, lst);
}
for (auto& ctors : ctorss) {
for (auto& ctor : ctors) {
Z3_del_constructor(*_context, ctor);
}
}
return out;
}
};
void handleZ3Error(Z3_context ctxt, Z3_error_code code)
{
DEBUG(errToString(code))
throw z3::exception(errToString(code));
}
Z3Interfacing::Z3Interfacing(SAT2FO& s2f, bool showZ3, bool unsatCore, std::string const& exportSmtlib, Options::ProblemExportSyntax exportSyntax):
_hasSeenArrays(false),
_varCnt(0),
_sat2fo(s2f),
_outSyntax(exportSyntax),
_status(Status::SATISFIABLE),
_context(new z3::context()),
_solver(*_context),
_model((_solver.check(), _solver.get_model())),
_assumptions([]() {
if (ENABLE_Z3_PROOF_GENERATION) {
z3::set_param("proof", true);
}
return decltype(_assumptions)();
}()),
_showZ3(showZ3),
_unsatCore(unsatCore),
_exporter([&](){
using namespace ProblemExport;
if (exportSmtlib == "") {
return decltype(_exporter)(NoExport{});
} else {
std::ofstream file(exportSmtlib.c_str());
if (file.fail())
throw UserErrorException("Failed to open file: ", exportSmtlib);
switch (exportSyntax) {
case Shell::Options::ProblemExportSyntax::SMTLIB: return decltype(_exporter)(Smtlib (std::move(file), *_context));
case Shell::Options::ProblemExportSyntax::API_CALLS: return decltype(_exporter)(ApiCalls(std::move(file), *_context));
}
ASSERTION_VIOLATION
}
}())
{
_out = exportSmtlib == "" ? Option<std::ofstream>()
: Option<std::ofstream>(std::ofstream(exportSmtlib.c_str())) ;
if (_out.isSome() && _out.unwrap().fail()) {
throw UserErrorException("Failed to open file: ", exportSmtlib);
}
_exporter.apply([&](auto& e) { e.initialize(); });
z3_set_param("rewriter.expand_store_eq", true);
z3_set_param("model.completion", MODEL_COMPLETION);
z3_set_param("model.compact", true);
if (_unsatCore) {
z3_set_param(":unsat-core", true);
}
#if TRACE_Z3
z3_enable_trace("arith");
#endif
for (auto c : { 'f', 't' }) {
for (auto s : { _context->real_sort(), _context->int_sort() }) {
z3::sort_vector dom(*_context);
dom.push_back(s);
z3_declare_fun(quotient0_name(c, s), dom, s);
z3_declare_fun(remainder0_name(c,s), dom, s);
}
}
}
void ProblemExport::Smtlib::initialize() { }
void ProblemExport::Smtlib::terminate() { out << std::endl; }
void ProblemExport::Smtlib::declareSort(z3::sort sort) { out << "(declare-sort " << sort << " 0)" << std::endl; }
void ProblemExport::Smtlib::eval(z3::expr const& x) { out << "(get-value (" << x << "))" << std::endl; }
void ProblemExport::Smtlib::unsatCore() { out << "(get-unsat-core)" << std::endl; }
void ProblemExport::Smtlib::addAssert(z3::expr const& x) { out << "(assert " << x << ")" << std::endl; }
void ProblemExport::Smtlib::get_model() { out << "(get-model)" << std::endl; }
void ProblemExport::Smtlib::reset() { out << "(reset)" << std::endl; }
void ProblemExport::Smtlib::declare_const(std::string const& name, z3::sort codomain)
{ return declare_fun(name, z3::sort_vector(codomain.ctx()), codomain); }
void ProblemExport::Smtlib::declare_fun(std::string const& name, z3::sort_vector domain, z3::sort codomain) {
out << "(declare-fun " << name << " (";
for (auto s : domain)
out << " " << s;
out << " ) " << codomain << ")" << std::endl;
}
void ProblemExport::Smtlib::check(Stack<z3::expr> const& assumptions) {
out << "(check-sat-assuming (";
for (auto const& a : assumptions)
out << " " << a;
out << " ))" << std::endl;
}
void ProblemExport::Smtlib::instantiate_expression(z3::expr const&) { }
void ProblemExport::Smtlib::declare_array_sort(z3::sort array, z3::sort index, z3::sort result) { }
template<class Value>
void ProblemExport::Smtlib::set_param(const char* k, Value const& v)
{ out << ";- setting z3 parameter: " << k << "=" << v << std::endl; }
void ProblemExport::Smtlib::Z3_mk_datatypes(Z3MkDatatypesCall const& call) {
auto quote = [&](auto x){
std::stringstream s;
s << x;
auto str = s.str();
if (str[0] == '\'') {
return "|" + str + "|";
} else {
return str;
}
};
out << "(declare-datatypes (" << std::endl;
for (auto& s : call.sortNames) {
out << " (" << quote(z3::symbol(_ctxt, s)) << " 0)";
}
out << " ) (" << std::endl;
for (unsigned i = 0; i < call.sortNames.size(); i++) {
out << " ( ;-- datatype " << z3::symbol(_ctxt, call.sortNames[i]) << std::endl;
for (auto& ctor : call.mkConstrs[i]) {
out << " ( " << quote(z3::symbol(_ctxt, ctor.name));
for (unsigned j = 0; j < ctor.field_names.size(); j++) {
out << " ( " << quote(z3::symbol(_ctxt, ctor.field_names[j])) << " ";
if (ctor.sorts[j] == nullptr) out << quote(z3::symbol(_ctxt, call.sortNames[ctor.sort_refs[j]]));
else out << z3::sort(_ctxt, ctor.sorts[j]);
out << " )";
}
out << " )" << std::endl;
}
out << " )";
}
out << "))" << std::endl;
}
std::string ProblemExport::ApiCalls::escapeVarName(z3::sort const& sym)
{
if (sym.is_array()) {
return _escapeVarName(sym);
} else {
return Z3_ast(sym) == nullptr
? std::string("nullptr")
: _escapeVarName(sym.name());
}
}
std::string ProblemExport::ApiCalls::escapeVarName(z3::symbol const& sym)
{ return _escapeVarName(sym); }
template<class Outputable>
std::string ProblemExport::ApiCalls::_escapeVarName(Outputable const& sym) {
std::stringstream cvar;
auto generatePrefix = [&](std::string const& toEscape) -> std::string {
unsigned iter = 0;
while (iter < toEscape.length()) {
if (std::isalnum(toEscape[iter]) || toEscape[iter] == '_') break;
else iter++;
}
if (iter == toEscape.length()) {
cvar << "_";
} else {
if ('0' <= toEscape[iter] && toEscape[iter] <= '9')
cvar << "_";
while (iter != toEscape.length()) {
if (std::isalnum(toEscape[iter]) || toEscape[iter] == '_') {
cvar << toEscape[iter];
} else {
cvar << '_';
}
iter++;
}
}
return std::string(cvar.str());
};
auto origName = Output::toString(sym);
return _escapedNames.getOrInit(origName, [&](){
auto& ids = _escapePrefixes.getOrInit(generatePrefix(origName));
auto nextId = ids.size();
auto id = ids.getOrInit(origName, [&](){ return nextId; });
if (id != 0)
cvar << "_" << id;
return cvar.str();
});
}
void ProblemExport::ApiCalls::enableTrace(const char* name)
{
out << "Z3_enable_trace(\"" << name << "\");" << std::endl;
}
void ProblemExport::ApiCalls::instantiate_expression(z3::expr const& expr)
{
#if INSTANTIATE_EXPRESSIONS
out << " (void) " << serialize(expr) << ";" << std::endl;
#endif
}
void ProblemExport::ApiCalls::initialize() {
out << R"(
#include <z3++.h>
#include <z3_api.h>
#include <iostream>
#include <vector>
int main() {)" << std::endl;
#if ENABLE_Z3_PROOF_GENERATION
out << " z3::set_param(\"proof\", true);" << std::endl;
#endif
out << R"(
z3::context ctx;
z3::solver solver(ctx);
z3::model model(ctx);
auto sort_vec = [&](std::initializer_list<z3::sort> xs) {
z3::sort_vector vec(ctx);
for (auto s : xs) vec.push_back(s);
return vec;
};
auto expr_vec = [&](std::initializer_list<z3::expr> xs) {
z3::expr_vector vec(ctx);
for (auto s : xs) vec.push_back(std::move(s));
return vec;
};
auto query_constructor = [&](Z3_constructor& ctor,
z3::func_decl* name,
z3::func_decl* tester,
std::vector<z3::func_decl*> accessors) {
Z3_func_decl _name;
Z3_func_decl _tester;
std::vector<Z3_func_decl> _accessors;
for (auto a : accessors)
_accessors.push_back(Z3_func_decl(a));
Z3_query_constructor(ctx, ctor, accessors.size(), &_name, &_tester, accessors.size() == 0 ? nullptr : &_accessors[0]);
*name = z3::func_decl(ctx, _name);
*tester = z3::func_decl(ctx, _tester);
for (auto i = 0; i < accessors.size(); i++) {
*accessors[i] = z3::func_decl(ctx, _accessors[i]);
}
};
auto mk_constructor = [&](Z3_symbol name,
Z3_symbol tester,
std::vector<Z3_symbol> argNames,
std::vector<Z3_sort> sorts,
std::vector<unsigned> sortRefs) {
return Z3_mk_constructor(ctx, name, tester, argNames.size(),
argNames.size() == 0 ? nullptr : &argNames[0],
sorts.size() == 0 ? nullptr : &sorts[0],
sortRefs.size() == 0 ? nullptr : &sortRefs[0]);
};
auto mk_constructor_list = [&](std::vector<Z3_constructor> ctors) {
return Z3_mk_constructor_list(ctx, ctors.size(), ctors.size() == 0 ? nullptr : &ctors[0]);
};
)" << std::endl;
#define ADD_BUILTIN_SORT(name, Name) \
out << " z3::sort " << escapeVarName(_ctxt.str_symbol(Name)) \
<< " = ctx." << name << "_sort();" << std::endl;
ADD_BUILTIN_SORT("bool", "Bool")
ADD_BUILTIN_SORT("int", "Int")
ADD_BUILTIN_SORT("real", "Real")
#undef ADD_BUILTIN_SORT
out << endl;
}
void ProblemExport::ApiCalls::declare_array_sort(z3::sort array, z3::sort index, z3::sort result)
{
out << " z3::sort " << escapeVarName(array)
<< " = ctx.array_sort("
<< escapeVarName(index) << ", "
<< escapeVarName(result) << ");" << std::endl;
}
void ProblemExport::ApiCalls::terminate()
{
out << "} // int main();" << std::endl;
}
struct ProblemExport::ApiCalls::EscapeString {
std::string s;
EscapeString(std::string s) : s(s) {}
EscapeString(z3::expr const& x) : EscapeString(Output::toString(x)) {}
friend std::ostream& operator<<(std::ostream& out, EscapeString const& self)
{ return out << "R\"(" << self.s << ")\""; }};
std::ostream& ProblemExport::operator<<(std::ostream& out, ProblemExport::ApiCalls::Serialize<std::string> const& self)
{ return out << ProblemExport::ApiCalls::EscapeString{self.inner}; }
std::ostream& ProblemExport::operator<<(std::ostream& out, ProblemExport::ApiCalls::Serialize<bool> const& self)
{ return out << ( self.inner ? "true" : "false" ); }
std::ostream& ProblemExport::operator<<(std::ostream& out, ProblemExport::ApiCalls::Serialize<z3::expr> const& self)
{
auto& x = self.inner;
auto& state = self.state;
#define ARG(idx) state.serialize(x.arg(idx))
auto vec_func = [&](auto f) -> std::ostream& {
out << f << "(expr_vec({";
if (x.num_args() > 0) {
out << ARG(0);
for (unsigned i = 1; i < x.num_args(); i++)
out << ", " << ARG(i);
}
return out << "}))";
};
auto func = [&](auto f) -> std::ostream& {
if (x.num_args() > 4)
return vec_func(f);
else {
if (x.num_args() == 0 && state._predeclaredConstants.contains(f)) {
return out << f;
} else {
out << f << "(";
if (x.num_args() > 0) {
out << ARG(0);
for (unsigned i = 1; i < x.num_args(); i++)
out << ", " << ARG(i);
}
return out << ")";
}
}
};
auto bin = [&](auto op) -> std::ostream& {
ASS_EQ(x.num_args(), 2)
return out << "(" << ARG(0) << " " << op << " " << ARG(1) << ")";
};
if (x.is_eq()) return bin("==");
else if (x.is_and()) return bin("&&");
else if (x.is_or()) return bin("||");
else if (x.is_not()) return func("!");
else if (x.is_ite()) return func("z3::ite");
else if (x.is_distinct()) return vec_func("z3::distinct");
else if (x.is_implies()) return func("z3::implies");
else if (x.is_true()) return out << "ctx.bool_val(true)";
else if (x.is_false()) return out << "ctx.bool_val(false)";
else if (x.is_numeral()) return out << "ctx.int_val(\"" << x << "\")";
else if (x.is_app()) {
auto f = x.decl();
if (f.name().kind() == Z3_STRING_SYMBOL) {
if (f.name().str() == "/" ) return bin("/");
if (f.name().str() == "*" ) return bin("*");
if (f.name().str() == "+" ) return bin("+");
if (f.name().str() == "-" ) return x.num_args() == 1 ? func("-") : bin("-");
if (f.name().str() == "<=") return bin("<=");
if (f.name().str() == "<" ) return bin("<" );
if (f.name().str() == ">=") return bin(">=");
if (f.name().str() == ">" ) return bin(">" );
}
return func(self.state.escapeVarName(f.name()));
} else {
ASSERTION_VIOLATION
}
#undef ARG
}
template<class A>
std::ostream& ProblemExport::operator<<(std::ostream& out, ProblemExport::ApiCalls::Serialize<A> const& self)
{ return out << self.inner; }
std::ostream& ProblemExport::operator<<(std::ostream& out, ProblemExport::ApiCalls::Serialize<z3::symbol> const& self)
{
if (self.inner.kind() == Z3_INT_SYMBOL) {
return out << "ctx.int_symbol(" << self.inner.to_int() << ")";
} else {
auto str = Output::toString(self.inner);
return out << "ctx.str_symbol(" << ProblemExport::ApiCalls::EscapeString(str) << ")";
}
}
void ProblemExport::ApiCalls::declareSort(z3::sort sort) {
out << " z3::sort " << escapeVarName(sort)
<< " = ctx.uninterpreted_sort(" << serialize(sort.name()) << ");" << std::endl;
}
void ProblemExport::ApiCalls::eval(z3::expr const& x)
{ out << " std::cout << \"model.eval(" << serialize(x) << ") = \" << model.eval(" << serialize(x) << " , " << MODEL_COMPLETION << ") << std::endl;" << std::endl; }
void ProblemExport::ApiCalls::unsatCore()
{
out << " std::cout << \"===== start solver.unsat_core() ====\" << std::endl;" << std::endl
<< " std::cout << solver.unsat_core() << std::endl;" << std::endl
<< " std::cout << \"===== end solver.unsat_core() ====\" << std::endl;" << std::endl;
}
void ProblemExport::ApiCalls::addAssert(z3::expr const& x)
{
out << " solver.add(" << serialize(x) << ");" << std::endl;
}
void ProblemExport::ApiCalls::check(Stack<z3::expr> const& xs)
{
out << std::endl;
out << std::endl << " std::cout << \"solver.check(..) = \" << solver.check(expr_vec({";
for (auto& x : xs) {
out << serialize(x) << ", ";
}
out << "})) << std::endl;" << std::endl;
out << std::endl;
}
void ProblemExport::ApiCalls::get_model() {
out << std::endl;
out << " model = solver.get_model();" << std::endl;
out << " std::cout << std::endl;" << std::endl;
out << " std::cout << \"===== start model ====\" << std::endl;" << std::endl;
out << " std::cout << model << std::endl;" << std::endl;
out << " std::cout << \"===== end model ====\" << std::endl;" << std::endl;
out << " std::cout << std::endl;" << std::endl;
out << std::endl;
}
void ProblemExport::ApiCalls::reset() { out << " std::cout << solver.reset() << std::endl;" << std::endl; }
template<class Value>
void ProblemExport::ApiCalls::set_param(const char* k, Value const& v)
{ out << " solver.set(" << EscapeString{k} << "," << serialize(v) << ");" << std::endl; }
template<class A, class F> struct InitList { A const& inner; F output; };
template<class A, class F> InitList<A, F> initList(A const& a, F f) { return InitList<A,F> { a, std::move(f), }; }
template<class A, class F> std::ostream& operator<<(std::ostream& out, InitList<A, F> const& self)
{
out << "{ ";
for (auto& x : self.inner) {
self.output(out, x);
out << ", ";
}
return out << "}";
}
void ProblemExport::ApiCalls::Z3_mk_datatypes(Z3MkDatatypesCall const& call) {
out << std::endl << " // datatypes:";
for (auto s : call.sortNames) {
out << " " << z3::symbol(_ctxt, s);
}
out << std::endl;
for (auto& cs : call.mkConstrs) {
for (auto& c : cs) {
out << " z3::func_decl " << escapeVarName(z3::symbol(_ctxt, c.name)) << "(ctx);" << std::endl;
out << " z3::func_decl " << escapeVarName(z3::symbol(_ctxt, c.tester)) << "(ctx);" << std::endl;
for (auto f : c.field_names)
out << " z3::func_decl " << escapeVarName(z3::symbol(_ctxt, f)) << "(ctx);" << std::endl;
}
}
for (auto s : call.sortNames)
out << " z3::sort " << escapeVarName(z3::symbol(_ctxt,s)) << "(ctx);" << std::endl;
out << " {" << std::endl
<< " Z3_symbol sort_names[] = " << initList(call.sortNames, [&](auto& out, auto& s) { z3::symbol sym(_ctxt, s); out << serialize(sym); }) << ";" << std::endl
<< " Z3_sort sorts[] = " << initList(call.sortNames, [&](auto& out, auto& ) { out << "nullptr"; }) << ";" << std::endl;
auto ctor_name = [&](auto& c) { return "ctor_" + escapeVarName(z3::symbol(_ctxt, c.name)); };
for (auto& cs : call.mkConstrs) {
for (auto& c : cs) {
z3::symbol name(_ctxt, c.name);
z3::symbol tester(_ctxt, c.tester);
out << " auto " << ctor_name(c) << " = mk_constructor("
<< serialize(name) << ", "
<< serialize(tester) << ", "
<< initList(c.field_names, [&](auto& out, auto& f){ out << serialize(z3::symbol(_ctxt,f)); }) << ", "
<< initList(c.sorts, [&](auto& out, auto& s){ out << escapeVarName(z3::sort(_ctxt,s)); }) << ", "
<< initList(c.sort_refs, [&](auto& out, auto& s){ out << serialize(s); }) << ");" << std::endl;
}
}
out << " Z3_constructor_list constructor_lists[] = {" << std::endl;
for (auto& cs : call.mkConstrs) {
out << " mk_constructor_list({";
for (auto c : cs)
out << ctor_name(c) << ", ";
out << " })," << std::endl;
}
out << " };" << std::endl;
out << " Z3_mk_datatypes(ctx, " << call.sortNames.size() << ", sort_names, sorts, constructor_lists);" << std::endl;
int i = 0;
for (auto s : call.sortNames)
out << " " << escapeVarName(z3::symbol(_ctxt,s)) << " = z3::sort(ctx, sorts[" << i++ <<"]);" << std::endl;
for (auto& cs : call.mkConstrs) {
for (auto c : cs){
out << " query_constructor("
<< ctor_name(c) << ", "
<< "&" << escapeVarName(z3::symbol(_ctxt, c.name)) << ", "
<< "&" << escapeVarName(z3::symbol(_ctxt, c.tester)) << ", "
<< "{";
for (auto f : c.field_names) {
out << "&" << escapeVarName(z3::symbol(_ctxt, f)) << ", ";
}
out << "});" << std::endl;
}
}
out << " }" << std::endl << std::endl;
}
void ProblemExport::ApiCalls::declare_fun(std::string const& name, z3::sort_vector domain, z3::sort codomain) {
out << " z3::func_decl " << escapeVarName(_ctxt.str_symbol(name.c_str())) << " = ctx.function(" << EscapeString{name} << ", sort_vec({";
for (auto s : domain)
out << escapeVarName(s) << ", ";
out << "}), " << escapeVarName(codomain) << " );" << std::endl;
}
void ProblemExport::ApiCalls::declare_const(std::string const& name, z3::sort codomain) {
auto varName = escapeVarName(_ctxt.str_symbol(name.c_str()));
out << " z3::expr " << varName
<< " = ctx.constant(" << EscapeString{name} << ", " << escapeVarName(codomain) << " );" << std::endl;
_predeclaredConstants.insert(std::move(varName));
}
z3::sort Z3Interfacing::z3_array_sort(z3::sort const& index_sort, z3::sort const& value_sort)
{
auto z3_sort = _context->array_sort(index_sort,value_sort);
_exporter.apply([&](auto& e) { e.declare_array_sort(z3_sort, index_sort, value_sort); });
return z3_sort;
}
void Z3Interfacing::z3_enable_trace(const char* name) {
Z3_enable_trace(name);
_exporter.apply([&](auto& e) { e.enableTrace(name); });
}
z3::sort Z3Interfacing::z3_declare_sort(std::string const& name) {
auto sort = _context->uninterpreted_sort(_context->str_symbol(name.c_str()));
_exporter.apply([&](auto& e) { e.declareSort(sort); });
return sort;
}
z3::expr Z3Interfacing::z3_eval(z3::expr const& x) {
_exporter.apply([&](auto& e) { e.eval(x); });
return _model.eval(x, MODEL_COMPLETION);
}
z3::expr_vector Z3Interfacing::z3_unsat_core() {
_exporter.apply([&](auto& e) { e.unsatCore(); });
return _solver.unsat_core();
}
void Z3Interfacing::z3_add(z3::expr const& x) {
_exporter.apply([&](auto& e) { e.addAssert(x); });
_solver.add(x);
}
z3::check_result Z3Interfacing::z3_check() {
_exporter.apply([&](auto& e) { e.check(_assumptions); });
return _solver.check(_assumptions.size(), _assumptions.begin());
}
z3::model Z3Interfacing::z3_get_model() {
_exporter.apply([&](auto& e) { e.get_model(); });
return _solver.get_model();
}
z3::expr Z3Interfacing::z3_declare_const(std::string const& name, z3::sort sort) {
_exporter.apply([&](auto& e) { e.declare_const(name, sort); });
return _context->function(name.c_str(), z3::sort_vector(*_context), sort)();
}
z3::func_decl Z3Interfacing::z3_declare_fun(std::string const& name, z3::sort_vector domain, z3::sort codomain) {
_exporter.apply([&](auto& e) { e.declare_fun(name, domain, codomain); });
return _context->function(name.c_str(), domain, codomain);
}
template<class Value>
void Z3Interfacing::z3_set_param(const char* k, Value const& v)
{
_exporter.apply([&](auto& e) { e.set_param(k, v); });
_solver.set(k, v);
}
char const* Z3Interfacing::z3_full_version()
{
return Z3_get_full_version();
}
unsigned Z3Interfacing::newVar()
{
++_varCnt;
auto rep = getRepresentation(SATLiteral(_varCnt,1));
_exporter.apply([&](auto& exp){ exp.instantiate_expression(rep.expr); });
return _varCnt;
}
void Z3Interfacing::addClause(SATClause* cl)
{
ASS(cl);
auto z3clause = getRepresentation(cl);
if(_showZ3){
std::cout << "[Z3] add (clause): " << z3clause.expr << std::endl;
}
for (auto def : z3clause.defs) {
DEBUG("adding def: ", def)
z3_add(def);
}
z3_add(z3clause.expr);
DEBUG("adding expr: ", z3clause.expr)
}
void Z3Interfacing::addAssumption(SATLiteral lit)
{
auto pushAssumption = [&](SATLiteral lit) -> z3::expr
{
auto repr = getRepresentation(lit);
for (auto& def : repr.defs)
_assumptions.push(def);
_assumptions.push(repr.expr);
return repr.expr;
};
if (_unsatCore) {
_assumptionLookup.getOrInit(lit, [&]() { return pushAssumption(lit); });
} else {
pushAssumption(lit);
}
}
Z3Interfacing::Representation Z3Interfacing::getRepresentation(SATClause* cl)
{
z3::expr z3clause = _context->bool_val(false);
Stack<z3::expr> defs;
unsigned clen=cl->length();
for(unsigned i=0;i<clen;i++){
SATLiteral l = (*cl)[i];
auto repr = getRepresentation(l);
_exporter.apply([&](auto& exp){ exp.instantiate_expression(repr.expr); });
defs.loadFromIterator(repr.defs.iterFifo());
z3clause = z3clause || repr.expr;
}
return Representation(std::move(z3clause), std::move(defs));
}
void Z3Interfacing::solveModuloAssumptionsAndSetStatus()
{
DEBUG("assumptions: ", _assumptions);
class ScopedPushAndPop {
z3::solver& _s;
bool _dpp;
public:
ScopedPushAndPop(z3::solver& s, bool doPushPop) : _s(s), _dpp(doPushPop) { if (_dpp) {_s.push();} }
~ScopedPushAndPop() { if (_dpp) {_s.pop();} }
} _maybePushAndPop(_solver,_hasSeenArrays);
auto result = z3_check();
if(_showZ3){
std::cout << "[Z3] solve result: " << result << std::endl;
}
switch (result) {
case z3::check_result::unsat:
_status = Status::UNSATISFIABLE;
break;
case z3::check_result::sat:
_status = Status::SATISFIABLE;
_model = z3_get_model();
break;
case z3::check_result::unknown:
_status = Status::UNKNOWN;
break;
default: ASSERTION_VIOLATION;
}
}
Status Z3Interfacing::solveUnderAssumptionsLimited(const SATLiteralStack& assumps, unsigned conflictCountLimit)
{
_assumptionLookup.clear();
_assumptions.reset();
for (auto a: assumps)
addAssumption(a);
solveModuloAssumptionsAndSetStatus();
return _status;
}
SATLiteralStack Z3Interfacing::failedAssumptions() {
SATLiteralStack result;
if (_unsatCore) {
auto core = z3_unsat_core();
for (auto phi : core) {
_assumptionLookup
.tryGet(phi)
.andThen([&result](SATLiteral l) { result.push(l); });
}
return result;
}
ASSERTION_VIOLATION
}
SATClauseList *Z3Interfacing::minimizePremises(SATClauseList *premises) {
z3::solver solver(*_context);
for(SATClause *cl : iterTraits(premises->iter())) {
auto repr = getRepresentation(cl);
auto tag = _context->constant(_context->int_symbol(cl->number), _context->bool_sort());
solver.add(repr.expr, tag);
for(z3::expr def : repr.defs)
solver.add(def);
}
ALWAYS(solver.check() == z3::unsat);
z3::expr_vector core = solver.unsat_core();
std::unordered_set<unsigned> lookup;
for(z3::expr member : core) {
ASS(member.is_const())
lookup.insert(member.decl().name().to_int());
}
SATClauseList *minimised = nullptr;
for(SATClause *cl : iterTraits(premises->iter()))
if(lookup.count(cl->number))
SATClauseList::push(cl, minimised);
return minimised;
}
VarAssignment Z3Interfacing::getAssignment(unsigned var)
{
ASS_EQ(_status,Status::SATISFIABLE);
z3::expr rep = isNamedExpr(var) ? getNameExpr(var) : getRepresentation(SATLiteral(var,1)).expr;
_exporter.apply([&](auto& exp){ exp.instantiate_expression(rep); });
ASS(isNamedExpr(var) || getRepresentation(SATLiteral(var,1)).defs.isEmpty())
auto assignment = z3_eval(rep);
if(assignment.bool_value()==Z3_L_TRUE){
return VarAssignment::TRUE;
} else if(assignment.bool_value()==Z3_L_FALSE){
return VarAssignment::FALSE;
} else {
#if VDEBUG
std::cout << std::endl;
std::cout << "===== start _model ====" << std::endl;
std::cout << _model << std::endl;
std::cout << "===== end _model ====" << std::endl;
std::cout << std::endl;
std::cout << rep << std::endl;
ASSERTION_VIOLATION_REP(assignment);
#endif
return VarAssignment::NOT_KNOWN;
}
}
OperatorType* operatorType(Z3Interfacing::FuncOrPredId f)
{
return f.isPredicate
? env.signature->getPredicate(f.id)->predType()
: env.signature->getFunction (f.id)->fnType();
}
Term* createTermOrPred(Z3Interfacing::FuncOrPredId f, unsigned arity, TermList* ts)
{
return f.isPredicate
? Literal::create(f.id, arity, true, ts)
: Term::create(f.id, arity, ts);
}
Term* Z3Interfacing::evaluateInModel(Term* trm)
{
DEBUG("in: ", *trm)
DEBUG("model: \n", _model)
ASS(!trm->isLiteral());
auto ev = z3_eval(getRepresentation(trm));
SortId sort = SortHelper::getResultSort(trm);
DEBUG("z3 expr: ", ev)
using Copro = Coproduct<Term*, RationalConstantType, IntegerConstantType>;
using Result = Option<Copro>;
auto result = BottomUpEvaluation<z3::expr, Option<Copro>>()
.function(
[&](z3::expr const& expr, Result* evaluatedArgs) -> Result
{
auto toTerm = [&](Copro const& co, SortId sort) -> Term* {
return co.match(
[&](Term* t)
{ return t; },
[&](RationalConstantType c)
{
return sort == RealTraits::sort()
? theory->representConstant(RealConstantType(c))
: theory->representConstant(c);
},
[&](IntegerConstantType c)
{ return theory->representConstant(c); }
);
};
DEBUG("in: ", expr)
auto intVal = [](z3::expr e) -> Option<int> {
int val;
return e.is_numeral_i(val)
? Option<int>(val)
: Option<int>();
};
if (expr.is_int()) {
return intVal(expr)
.map([](int i) { return Copro(IntTraits::constantT(i)); });
} else if(expr.is_real()) {
if (!expr.is_numeral()) {
return Result();
}
auto toFrac = [&](int l, int r) { return Copro(RatTraits::constant(l,r)); };
auto nonFractional = intVal(expr).map([&](int i) { return toFrac(i,1); });
if (nonFractional.isSome()) {
return nonFractional;
} else {
auto num = intVal(expr.numerator());
auto den = intVal(expr.denominator());
if (num.isSome() && den.isSome()) {
return Result(Copro(toFrac(num.unwrap(), den.unwrap())));
} else {
return Result();
}
}
} else if (expr.is_app()) {
auto f = expr.decl();
auto vfunc = _fromZ3.get(f);
unsigned arity = f.arity();
ASS(arity == 0 || evaluatedArgs != nullptr)
Stack<TermList> args(arity);
for (unsigned i = 0; i < arity; i++) {
if (evaluatedArgs[i].isNone()) {
return Result();
} else {
auto argSort = operatorType(vfunc)->arg(i);
auto t = TermList(toTerm(evaluatedArgs[i].unwrap(), argSort));
args.push(t);
}
}
return Result(Copro(createTermOrPred(vfunc, args.size(), args.begin())));
} else {
return Result();
}
})
.apply(ev)
.map([&](Copro co) {
return co.match(
[&](Term* t)
{ return t; },
[&](RationalConstantType c)
{
return sort == RealTraits::sort()
? theory->representConstant(RealConstantType(c))
: theory->representConstant(c);
},
[&](IntegerConstantType c)
{ return theory->representConstant(c); }
);
})
.unwrapOrElse([](){ return nullptr; });
DEBUG("vampire expr: ", ev)
return result;
}
bool Z3Interfacing::isZeroImplied(unsigned var)
{
return false;
}
z3::sort Z3Interfacing::getz3sort(SortId s)
{
auto srt = _sorts.tryGet(s);
if (srt.isSome()) {
return srt.unwrap();
} else {
auto insert = [&](z3::sort x) { _sorts.insert(s, x); };
if(s == AtomicSort::boolSort()) insert(_context->bool_sort());
else if(s == IntTraits::sort()) insert( _context->int_sort());
else if(s == RealTraits::sort()) insert(_context->real_sort());
else if(s == RatTraits::sort()) insert(_context->real_sort()); else if(s.isArraySort()) {
_hasSeenArrays = true;
insert(z3_array_sort(
getz3sort(SortHelper::getIndexSort(s)),
getz3sort(SortHelper::getInnerSort(s))
));
} else if (env.signature->isTermAlgebraSort(s)) {
createTermAlgebra(s);
} else {
insert(z3_declare_sort(s.toString()));
}
}
return _sorts.get(s);
}
template<class A>
std::string to_string(A const& a)
{
std::stringstream out;
out << a;
return out.str();
}
void Z3Interfacing::createTermAlgebra(TermList sort)
{
ASS(sort.isTerm() && sort.term()->isSort());
if (_createdTermAlgebras.contains(sort)) return;
Stack<TermList> taSorts; Map<SortId, unsigned> recSorts;
auto subsorts = TermAlgebra::subSorts(sort);
for (auto s : subsorts.iter()) {
if (env.signature->isTermAlgebraSort(s)
&& !_createdTermAlgebras.contains(s)) {
auto idx = taSorts.size();
taSorts.push(s);
recSorts.insert(s, idx);
}
}
auto new_string_symbol = [this](unsigned f, const std::string& typePostfix, bool pred = false)
{ return Z3_mk_string_symbol(*_context,
((pred ? env.signature->getPredicate(f) : env.signature->getFunction(f))->name()+'_'+typePostfix).c_str()); };
Stack<Stack<Z3_constructor>> ctorss(taSorts.size());
Stack<Z3_constructor_list> ctorss_z3(taSorts.size());
Stack<Z3_symbol> sortNames(taSorts.size());
struct SerDtor { z3::symbol name; SortId sort; };
struct SerCtor { z3::symbol name; Stack<SerDtor> dtors; };
struct SerDtype { SortId name; Stack<SerCtor> ctors; };
Stack<SerDtype> toSerialize;
DEBUG("creating constructors: ");
for (auto taSort : taSorts) {
_createdTermAlgebras.insert(taSort);
ASS(taSort.isTerm());
auto taSortT = taSort.term();
auto ta = env.signature->getTermAlgebraOfSort(taSort);
Substitution typeSubst;
std::string typePostfix = "$";
ta->getTypeSub(taSortT, typeSubst);
for(unsigned i = 0; i < taSortT->arity(); i++) {
typePostfix += taSortT->nthArgument(i)->toString();
}
Stack<Z3_constructor> ctors(ta->nConstructors());
Stack<SerCtor> serCtors;
for (auto cons : ta->iterCons()) {
Stack<SerDtor> serDtors;
auto consTermArity = cons->arity()-cons->numTypeArguments();
Stack<Z3_sort> argSorts(consTermArity);
Stack<unsigned> argSortRefs(consTermArity);
Stack<Z3_symbol> argNames(consTermArity);
for (unsigned i = cons->numTypeArguments(); i < cons->arity(); i++) {
auto argSort = SubstHelper::apply(cons->argSort(i),typeSubst);
auto dtorName = new_string_symbol(cons->destructorFunctor(i-cons->numTypeArguments()),typePostfix);
if (_out.isSome())
serDtors.push(SerDtor {
.name = z3::symbol(*_context, dtorName),
.sort = argSort,
});
argNames.push(dtorName);
recSorts.tryGet(argSort)
.match([&](unsigned idx) {
argSortRefs.push(idx);
argSorts.push(nullptr);
},
[&]() {
argSortRefs.push(0); argSorts.push(getz3sort(argSort));
});
}
DEBUG("\t", taSort.toString(), "::", env.signature->getFunction(cons->functor())->name(), ": ");
Z3_symbol ctorName = Z3_mk_string_symbol(*_context, env.signature->getFunction(cons->functor())->name().c_str());
ASS_EQ(argSortRefs.size(), consTermArity);
ASS_EQ( argSorts.size(), consTermArity);
ASS_EQ( argNames.size(), consTermArity);
if (_out.isSome())
serCtors.push(SerCtor{
.name = z3::symbol(*_context, ctorName),
.dtors = std::move(serDtors),
});
ctors.push(Z3_mk_constructor(*_context,
ctorName,
new_string_symbol(cons->discriminator(), typePostfix, true),
consTermArity,
consTermArity == 0 ? nullptr : argNames.begin(),
consTermArity == 0 ? nullptr : argSorts.begin(),
consTermArity == 0 ? nullptr : argSortRefs.begin()
));
}
ASS_EQ(ctors.size(), ta->nConstructors());
ctorss.push(std::move(ctors));
ASS_EQ(ctorss.top().size(), ta->nConstructors());
ctorss_z3.push(Z3_mk_constructor_list(*_context, ctorss.top().size(), ctorss.top().begin()));
sortNames.push(Z3_mk_string_symbol(*_context, taSort.toString().c_str()));
if (_out.isSome())
toSerialize.push(SerDtype {
.name = taSort,
.ctors = std::move(serCtors),
});
}
ASS_EQ(sortNames.size(), taSorts.size())
ASS_EQ(ctorss.size() , taSorts.size())
ASS_EQ(ctorss_z3.size(), taSorts.size())
Array<Z3_sort> sorts(taSorts.size());
Z3_mk_datatypes(*_context, taSorts.size(), sortNames.begin(), sorts.begin(), ctorss_z3.begin());
for (unsigned iSort = 0; iSort < sorts.size(); iSort++) {
_sorts.insert(taSorts[iSort], z3::sort(*_context, sorts[iSort]));
auto ta = env.signature->getTermAlgebraOfSort(taSorts[iSort]);
auto& ctors = ctorss[iSort];
for (unsigned iCons = 0; iCons < ta->nConstructors(); iCons++) {
auto ctor_v = ta->constructor(iCons);
auto ctorTermArity = ctor_v->arity() - ctor_v->numTypeArguments();
Z3_func_decl ctor_z3;
Z3_func_decl discr_z3;
Array<Z3_func_decl> destr(ctorTermArity);
Z3_query_constructor(*_context,
ctors[iCons],
ctorTermArity,
&ctor_z3,
&discr_z3,
destr.begin());
auto registerDecl = [&](auto vampireId, auto z3Id) {
_toZ3.insert(vampireId, z3Id);
_fromZ3.insert(z3Id, vampireId);
};
registerDecl(FuncOrPredId::monomorphicFunction(ctor_v->functor()), z3::func_decl(*_context, ctor_z3));
if (ctor_v->hasDiscriminator()) {
registerDecl(FuncOrPredId::monomorphicPredicate(ctor_v->discriminator()), z3::func_decl(*_context, discr_z3));
}
for (unsigned iDestr = 0; iDestr < ctorTermArity; iDestr++) {
auto dtor = z3::func_decl(*_context, destr[iDestr]);
bool is_predicate = ctor_v->argSort(iDestr).isBoolSort();
auto id = FuncOrPredId(ctor_v->destructorFunctor(iDestr), is_predicate);
registerDecl(id, dtor);
}
}
}
}
z3::func_decl const& Z3Interfacing::findConstructor(Term* t)
{
auto id = FuncOrPredId::monomorphicFunction(t->functor());
auto f = _toZ3.tryGet(id);
if (f.isSome()) {
return f.unwrap();
} else {
createTermAlgebra(SortHelper::getResultSort(t));
return _toZ3.get(id);
}
}
z3::expr to_int(z3::expr e)
{ return z3::expr(e.ctx(), Z3_mk_real2int(e.ctx(), e)); }
namespace tptp {
z3::expr floor(z3::expr e)
{ return to_real(to_int(e)); }
z3::expr ceiling(z3::expr x)
{ return -tptp::floor(-x); }
z3::expr truncate(z3::expr x)
{ return ite(x >= 0, tptp::floor(x), tptp::ceiling(x)); }
z3::expr quotient0(char kind, z3::expr x)
{
std::string fname = quotient0_name(kind, x.get_sort());
auto quotient0 = x.ctx().function(fname.c_str(), x.get_sort(), x.get_sort());
return quotient0(x);
}
z3::expr remainder0(char kind, z3::expr x)
{
std::string fname = remainder0_name(kind, x.get_sort());
auto remainder0 = x.ctx().function(fname.c_str(), x.get_sort(), x.get_sort());
return remainder0(x);
}
z3::expr quotient_e(z3::expr l, z3::expr r)
{ return l / r; }
z3::expr remainder_e(z3::expr l, z3::expr r)
{ return z3::mod(l, r); }
z3::expr quotient_t(z3::expr l, z3::expr r)
{ return ite(r == 0, tptp::quotient0('t', r)
, tptp::truncate(l / r)); }
z3::expr quotient_f(z3::expr l, z3::expr r)
{ return ite(r == 0, tptp::quotient0('f', l / r)
, tptp::floor(l / r)); }
template<class F>
struct LiftInt
{
F bin_real_func;
z3::expr operator()(z3::expr l, z3::expr r)
{ return to_int(bin_real_func(to_real(l), to_real(r))); }
};
template<class F> LiftInt<F> liftInt(F f) { return LiftInt<F>{ f }; }
template<class F>
struct RemainderOp
{
char kind;
F quotient;
z3::expr operator()(z3::expr l, z3::expr r)
{ return ite(r == 0, remainder0(kind, l)
, l - r * quotient(l,r)); }
};
template<class F> RemainderOp<F> remainder(char kind, F f) { return RemainderOp<F>{ kind, f }; }
}
z3::func_decl Z3Interfacing::z3Function(FuncOrPredId functor)
{
auto& self = *this;
auto found = self._toZ3.tryGet(functor);
if (found.isSome()) {
return found.unwrap();
} else {
auto symb = functor.isPredicate ? env.signature->getPredicate(functor.id)
: env.signature->getFunction(functor.id);
auto type = functor.isPredicate ? symb->predType() : symb->fnType();
std::string namebuf = symb->name();
Substitution typeSubst;
if(functor.forSorts) {
SortHelper::getTypeSub(functor.forSorts, typeSubst);
namebuf += '$';
for(unsigned i = 0; i < functor.forSorts->numTypeArguments(); i++)
namebuf += functor.forSorts->typeArg(i).toString();
}
z3::sort_vector domain_sorts = z3::sort_vector(*self._context);
for (unsigned i=type->numTypeArguments(); i<type->arity(); i++) {
TermList arg = SubstHelper::apply(type->arg(i), typeSubst);
domain_sorts.push_back(self.getz3sort(arg));
}
auto codomain = functor.isPredicate ? self._context->bool_sort() : self.getz3sort(SubstHelper::apply(type->result(), typeSubst));
auto decl = self.z3_declare_fun(namebuf, domain_sorts, codomain);
self._toZ3.insert(functor, decl);
return decl;
}
}
z3::expr Z3Interfacing::getRepresentation(Term* trm)
{
auto expr = BottomUpEvaluation<TermList, z3::expr>()
.function(
[&](TermList toEval, z3::expr* args) -> z3::expr
{
ASS(toEval.isTerm())
auto trm = toEval.term();
bool isLit = trm->isLiteral();
Signature::Symbol* symb;
SortId range_sort;
if (isLit) {
symb = env.signature->getPredicate(trm->functor());
range_sort = AtomicSort::boolSort();
if( trm->functor()==0 || symb->equalityProxy()){
ASS(trm->numTermArguments()==2);
if (symb->wasFlipped()) {
return args[0] != args[1];
} else {
return args[0] == args[1];
}
}
} else {
auto actualSort = SortHelper::getResultSort(trm);
symb = env.signature->getFunction(trm->functor());
OperatorType* ftype = symb->fnType();
range_sort = ftype->result();
if (env.signature->isTermAlgebraSort(actualSort) && !_createdTermAlgebras.contains(actualSort) ) {
createTermAlgebra(actualSort);
}
}
if (!isLit) {
auto linMul = tryNumTraits([&](auto n) {
return asig(n).ifLinMul(trm, [&](auto& c, auto t) {
return to_z3_expr(c, *_context) * args[0];
});
});
if (linMul) {
return *linMul;
}
}
if(trm->arity() == 0) {
if(symb->integerConstant()){
return to_z3_expr(symb->integerValue(), *_context);
}
if(symb->realConstant()) {
return to_z3_expr(symb->realValue(), *_context);
}
if(symb->rationalConstant()) {
return to_z3_expr(symb->rationalValue(), *_context);
}
if(!isLit && env.signature->isFoolConstantSymbol(true,trm->functor())) {
return _context->bool_val(true);
}
if(!isLit && env.signature->isFoolConstantSymbol(false,trm->functor())) {
return _context->bool_val(false);
}
if(symb->termAlgebraCons()) {
auto ctor = findConstructor(trm);
return ctor();
}
return getConst(symb, getz3sort(range_sort));
}
ASS_G(trm->arity(), 0);
if(symb->interpreted()){
Interpretation interp = static_cast<Signature::InterpretedSymbol*>(symb)->getInterpretation();
if (Theory::isPolymorphic(interp)) {
switch(interp){
case Theory::ARRAY_SELECT:
case Theory::ARRAY_BOOL_SELECT:
return select(args[0],args[1]);
case Theory::ARRAY_STORE:
return store(args[0],args[1],args[2]);
default:
{} }
} else {
auto int_zero = _context->int_val(0);
auto real_zero = _context->real_val(0);
switch(interp){
case Theory::INT_DIVIDES:
{
auto k = getNamingConstantFor(toEval, _context->int_sort());
return k * args[0] == args[1];
}
case Theory::INT_UNARY_MINUS:
case Theory::RAT_UNARY_MINUS:
case Theory::REAL_UNARY_MINUS:
return -args[0];
case Theory::INT_PLUS:
case Theory::RAT_PLUS:
case Theory::REAL_PLUS:
return args[0] + args[1];
case Theory::INT_MINUS:
case Theory::RAT_MINUS:
case Theory::REAL_MINUS:
return args[0] - args[1];
case Theory::INT_MULTIPLY:
case Theory::RAT_MULTIPLY:
case Theory::REAL_MULTIPLY:
return args[0] * args[1];
case Theory::RAT_QUOTIENT:
case Theory::REAL_QUOTIENT:
return args[0] / args[1];
case Theory::INT_QUOTIENT_E: return args[0] / args[1];
case Theory::INT_REMAINDER_E: return z3::mod(args[0], args[1]);
case Theory::RAT_QUOTIENT_E:
case Theory::REAL_QUOTIENT_E: return tptp::quotient_e (args[0], args[1]);
case Theory::RAT_REMAINDER_E:
case Theory::REAL_REMAINDER_E: return tptp::remainder('e', tptp::quotient_e)(args[0], args[1]);
case Theory::INT_QUOTIENT_T: return tptp::liftInt( tptp::quotient_t )(args[0],args[1]);
case Theory::INT_REMAINDER_T: return tptp::liftInt(tptp::remainder('t', tptp::quotient_t))(args[0],args[1]);
case Theory::RAT_QUOTIENT_T:
case Theory::REAL_QUOTIENT_T: return tptp::quotient_t (args[0], args[1]);
case Theory::REAL_REMAINDER_T:
case Theory::RAT_REMAINDER_T: return tptp::remainder('t', tptp::quotient_t)(args[0], args[1]);
case Theory::INT_QUOTIENT_F: return tptp::liftInt( tptp::quotient_f )(args[0], args[1]);
case Theory::INT_REMAINDER_F: return tptp::liftInt(tptp::remainder('f', tptp::quotient_f))(args[0],args[1]);
case Theory::RAT_QUOTIENT_F:
case Theory::REAL_QUOTIENT_F: return tptp::quotient_f (args[0], args[1]);
case Theory::REAL_REMAINDER_F:
case Theory::RAT_REMAINDER_F: return tptp::remainder('f', tptp::quotient_f)(args[0], args[1]);
case Theory::RAT_TO_INT:
case Theory::REAL_TO_INT:
case Theory::INT_FLOOR:
case Theory::RAT_FLOOR:
case Theory::REAL_FLOOR:
return to_real(to_int(args[0]));
case Theory::RAT_TO_REAL:
return args[0];
case Theory::INT_TO_REAL:
case Theory::INT_TO_RAT:
return to_real(args[0]);
case Theory::INT_CEILING:
case Theory::RAT_CEILING:
case Theory::REAL_CEILING:
return tptp::ceiling(args[0]);
case Theory::INT_TRUNCATE:
case Theory::RAT_TRUNCATE:
case Theory::REAL_TRUNCATE:
return tptp::truncate(args[0]);
case Theory::INT_ROUND:
case Theory::RAT_ROUND:
case Theory::REAL_ROUND: {
z3::expr t = args[0];
z3::expr i = to_int(t);
z3::expr i2 = i + _context->real_val(1,2);
return ite(t > i2, i+1, ite(t==i2, ite(z3::mod(i, 2),i ,i+1 ),i));
}
case Theory::INT_ABS: {
z3::expr t = args[0];
return ite(t > 0, t, -t);
}
case Theory::INT_IS_INT:
case Theory::RAT_IS_INT:
case Theory::REAL_IS_INT:
return z3::is_int(args[0]);
case Theory::INT_LESS:
case Theory::RAT_LESS:
case Theory::REAL_LESS:
return args[0] < args[1];
case Theory::INT_GREATER:
case Theory::RAT_GREATER:
case Theory::REAL_GREATER:
return args[0] > args[1];
case Theory::INT_LESS_EQUAL:
case Theory::RAT_LESS_EQUAL:
case Theory::REAL_LESS_EQUAL:
return args[0] <= args[1];
case Theory::INT_GREATER_EQUAL:
case Theory::RAT_GREATER_EQUAL:
case Theory::REAL_GREATER_EQUAL:
return args[0] >= args[1];
default:
{} }
}
}
auto f = z3Function(Z3Interfacing::FuncOrPredId(trm));
return f(f.arity(), args);
})
.apply(TermList(trm));
return expr;
}
Z3Interfacing::Representation Z3Interfacing::getRepresentation(SATLiteral slit)
{
Literal* lit = _sat2fo.toFO(slit);
if(lit && lit->ground()){
try{
Representation repr(getRepresentation(lit), Stack<z3::expr>());
_exporter.apply([&expr = repr.expr](auto& exp){ exp.instantiate_expression(expr); });
z3::expr bname = getNameExpr(slit.var());
_exporter.apply([&](auto& exp){ exp.instantiate_expression(bname); });
z3::expr naming = (bname == repr.expr);
_exporter.apply([&](auto& exp){ exp.instantiate_expression(naming); });
repr.defs.push(naming);
repr.expr = bname;
if(_showZ3){
std::cout << "[Z3] add (naming): " << naming << std::endl;
}
if(!slit.positive()) {
repr.expr = !repr.expr;
_exporter.apply([&expr = repr.expr](auto& exp){ exp.instantiate_expression(expr); });
}
return repr;
}catch(z3::exception& exception){
reportSpiderFail();
cout << "Z3 exception:\n" << exception.msg() << endl;
ASSERTION_VIOLATION_REP("Failed to create Z3 rep for " + lit->toString());
}
} else {
z3::expr e = getNameExpr(slit.var());
e = slit.positive() ? e : !e;
_exporter.apply([&](auto& exp){ exp.instantiate_expression(e); });
return Representation(e, Stack<z3::expr>());
}
}
Z3Interfacing::~Z3Interfacing()
{
_sorts.clear();
_toZ3.clear();
_fromZ3.clear();
_exporter.apply([&](auto& e) { e.terminate(); });
}
bool Z3Interfacing::isNamedExpr(unsigned var) const
{ return _varNames.find(var); }
z3::expr Z3Interfacing::getNameExpr(unsigned var)
{
return _varNames.getOrInit(var, [&]()
{ return z3_declare_const("v"+Lib::Int::toString(var), _context->bool_sort()); });
}
z3::expr Z3Interfacing::getNamingConstantFor(TermList toName, z3::sort sort)
{
return _termIndexedConstants.getOrInit(toName, [&]()
{ return z3_declare_const("n" + toName.toString(), sort); });
}
z3::expr Z3Interfacing::getConst(Signature::Symbol* symb, z3::sort sort)
{
return _constantNames.getOrInit(symb, [&]()
{ return z3_declare_const("c" + symb->name(), sort); });
}
}
#endif