mirror of
https://github.com/Z3Prover/z3
synced 2025-06-03 12:51:22 +00:00
initial commit for interpolation
This commit is contained in:
parent
197b2e8ddb
commit
68fb01c206
15 changed files with 3005 additions and 1 deletions
327
src/interp/iz3foci.cpp
Executable file
327
src/interp/iz3foci.cpp
Executable file
|
@ -0,0 +1,327 @@
|
|||
/* Copyright 2011 Microsoft Research. */
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
|
||||
#include "iz3hash.h"
|
||||
#include "foci2.h"
|
||||
#include "iz3foci.h"
|
||||
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
class iz3foci_impl : public iz3secondary {
|
||||
|
||||
int frames;
|
||||
int *parents;
|
||||
foci2 *foci;
|
||||
foci2::symb select_op;
|
||||
foci2::symb store_op;
|
||||
foci2::symb mod_op;
|
||||
|
||||
public:
|
||||
iz3foci_impl(iz3mgr *mgr, int _frames, int *_parents) : iz3secondary(*mgr) {
|
||||
frames = _frames;
|
||||
parents = _parents;
|
||||
foci = 0;
|
||||
}
|
||||
|
||||
typedef hash_map<ast,foci2::ast> AstToNode;
|
||||
AstToNode ast_to_node; // maps Z3 ast's to foci expressions
|
||||
|
||||
typedef hash_map<foci2::ast,ast> NodeToAst;
|
||||
NodeToAst node_to_ast; // maps Z3 ast's to foci expressions
|
||||
|
||||
typedef hash_map<symb,foci2::symb> FuncDeclToSymbol;
|
||||
FuncDeclToSymbol func_decl_to_symbol; // maps Z3 func decls to symbols
|
||||
|
||||
typedef hash_map<foci2::symb,symb> SymbolToFuncDecl;
|
||||
SymbolToFuncDecl symbol_to_func_decl; // maps symbols to Z3 func decls
|
||||
|
||||
int from_symb(symb func){
|
||||
std::string name = string_of_symbol(func);
|
||||
bool is_bool = is_bool_type(get_range_type(func));
|
||||
foci2::symb f;
|
||||
if(is_bool)
|
||||
f = foci->mk_pred(name);
|
||||
else
|
||||
f = foci->mk_func(name);
|
||||
symbol_to_func_decl[f] = func;
|
||||
func_decl_to_symbol[func] = f;
|
||||
return f;
|
||||
}
|
||||
|
||||
// create a symbol corresponding to a DeBruijn index of a particular type
|
||||
// the type has to be encoded into the name because the same index can
|
||||
// occur with different types
|
||||
foci2::symb make_deBruijn_symbol(int index, int type){
|
||||
std::ostringstream s;
|
||||
s << "#" << index << "#" << type;
|
||||
return foci->mk_func(s.str());
|
||||
}
|
||||
|
||||
int from_Z3_ast(ast t){
|
||||
std::pair<ast,foci2::ast> foo(t,0);
|
||||
std::pair<AstToNode::iterator, bool> bar = ast_to_node.insert(foo);
|
||||
int &res = bar.first->second;
|
||||
if(!bar.second) return res;
|
||||
int nargs = num_args(t);
|
||||
std::vector<foci2::ast> args(nargs);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
args[i] = from_Z3_ast(arg(t,i));
|
||||
|
||||
switch(op(t)){
|
||||
case True:
|
||||
res = foci->mk_true(); break;
|
||||
case False:
|
||||
res = foci->mk_false(); break;
|
||||
case And:
|
||||
res = foci->mk_op(foci2::And,args); break;
|
||||
case Or:
|
||||
res = foci->mk_op(foci2::Or,args); break;
|
||||
case Not:
|
||||
res = foci->mk_op(foci2::Not,args[0]); break;
|
||||
case Iff:
|
||||
res = foci->mk_op(foci2::Iff,args); break;
|
||||
case OP_OEQ: // bit of a mystery, this one...
|
||||
if(args[0] == args[1]) res = foci->mk_true();
|
||||
else res = foci->mk_op(foci2::Iff,args);
|
||||
break;
|
||||
case Ite:
|
||||
if(is_bool_type(get_type(t)))
|
||||
res = foci->mk_op(foci2::And,foci->mk_op(foci2::Or,foci->mk_op(foci2::Not,args[0]),args[1]),foci->mk_op(foci2::Or,args[0],args[2]));
|
||||
else
|
||||
res = foci->mk_op(foci2::Ite,args);
|
||||
break;
|
||||
case Equal:
|
||||
res = foci->mk_op(foci2::Equal,args); break;
|
||||
case Implies:
|
||||
args[0] = foci->mk_op(foci2::Not,args[0]); res = foci->mk_op(foci2::Or,args); break;
|
||||
case Xor:
|
||||
res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Iff,args)); break;
|
||||
case Leq:
|
||||
res = foci->mk_op(foci2::Leq,args); break;
|
||||
case Geq:
|
||||
std::swap(args[0],args[1]); res = foci->mk_op(foci2::Leq,args); break;
|
||||
case Gt:
|
||||
res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Leq,args)); break;
|
||||
case Lt:
|
||||
std::swap(args[0],args[1]); res = foci->mk_op(foci2::Not,foci->mk_op(foci2::Leq,args)); break;
|
||||
case Plus:
|
||||
res = foci->mk_op(foci2::Plus,args); break;
|
||||
case Sub:
|
||||
args[1] = foci->mk_op(foci2::Times,foci->mk_int("-1"),args[1]); res = foci->mk_op(foci2::Plus,args); break;
|
||||
case Uminus:
|
||||
res = foci->mk_op(foci2::Times,foci->mk_int("-1"),args[0]); break;
|
||||
case Times:
|
||||
res = foci->mk_op(foci2::Times,args); break;
|
||||
case Idiv:
|
||||
res = foci->mk_op(foci2::Div,args); break;
|
||||
case Mod:
|
||||
res = foci->mk_app(mod_op,args); break;
|
||||
case Select:
|
||||
res = foci->mk_app(select_op,args); break;
|
||||
case Store:
|
||||
res = foci->mk_app(store_op,args); break;
|
||||
case Distinct:
|
||||
res = foci->mk_op(foci2::Distinct,args); break;
|
||||
case Uninterpreted: {
|
||||
symb func = sym(t);
|
||||
FuncDeclToSymbol::iterator it = func_decl_to_symbol.find(func);
|
||||
foci2::symb f = (it == func_decl_to_symbol.end()) ? from_symb(func) : it->second;
|
||||
if(foci->get_symb(f).substr(0,3) == "lbl" && args.size()==1) // HACK to handle Z3 labels
|
||||
res = args[0];
|
||||
else if(foci->get_symb(f).substr(0,3) == "lbl" && args.size()==0) // HACK to handle Z3 labels
|
||||
res = foci->mk_true();
|
||||
else res = foci->mk_app(f,args);
|
||||
break;
|
||||
}
|
||||
case Numeral: {
|
||||
std::string s = string_of_numeral(t);
|
||||
res = foci->mk_int(s);
|
||||
}
|
||||
case Forall:
|
||||
case Exists: {
|
||||
bool is_forall = op(t) == Forall;
|
||||
foci2::ops qop = is_forall ? foci2::Forall : foci2::Exists;
|
||||
int bvs = get_quantifier_num_bound(t);
|
||||
std::vector<int> foci_bvs(bvs);
|
||||
for(int i = 0; i < bvs; i++){
|
||||
std::string name = get_quantifier_bound_name(t,i);
|
||||
//Z3_string name = Z3_get_symbol_string(ctx,sym);
|
||||
// type ty = get_quantifier_bound_type(t,i);
|
||||
foci2::symb f = foci->mk_func(name);
|
||||
foci2::ast v = foci->mk_app(f,std::vector<foci2::ast>());
|
||||
foci_bvs[i] = v;
|
||||
}
|
||||
foci2::ast body = from_Z3_ast(get_quantifier_body(t));
|
||||
foci_bvs.push_back(body);
|
||||
res = foci->mk_op(qop,foci_bvs);
|
||||
node_to_ast[res] = t; // desperate
|
||||
}
|
||||
case Variable: { // a deBruijn index
|
||||
int index = get_variable_index_value(t);
|
||||
type ty = get_type(t);
|
||||
foci2::symb symbol = make_deBruijn_symbol(index,(int)(ty));
|
||||
res = foci->mk_app(symbol,std::vector<foci2::ast>());
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::cerr << "iZ3: unsupported Z3 operator in expression\n ";
|
||||
print_expr(std::cerr,t);
|
||||
std::cerr << "\n";
|
||||
assert(0 && "iZ3: unsupported Z3 operator");
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// convert an expr to Z3 ast
|
||||
ast to_Z3_ast(foci2::ast i){
|
||||
std::pair<foci2::ast,ast> foo(i,(ast)0);
|
||||
std::pair<NodeToAst::iterator,bool> bar = node_to_ast.insert(foo);
|
||||
if(!bar.second) return bar.first->second;
|
||||
ast &res = bar.first->second;
|
||||
|
||||
if(i < 0){
|
||||
res = mk_not(to_Z3_ast(-i));
|
||||
return res;
|
||||
}
|
||||
|
||||
// get the arguments
|
||||
unsigned n = foci->get_num_args(i);
|
||||
std::vector<ast> args(n);
|
||||
for(unsigned j = 0; j < n; j++)
|
||||
args[j] = to_Z3_ast(foci->get_arg(i,j));
|
||||
|
||||
// handle operators
|
||||
foci2::ops o;
|
||||
foci2::symb f;
|
||||
std::string nval;
|
||||
if(foci->get_true(i))
|
||||
res = mk_true();
|
||||
else if(foci->get_false(i))
|
||||
res = mk_false();
|
||||
else if(foci->get_op(i,o)){
|
||||
switch(o){
|
||||
case foci2::And:
|
||||
res = make(And,args); break;
|
||||
case foci2::Or:
|
||||
res = make(Or,args); break;
|
||||
case foci2::Not:
|
||||
res = mk_not(args[0]); break;
|
||||
case foci2::Iff:
|
||||
res = make(Iff,args[0],args[1]); break;
|
||||
case foci2::Ite:
|
||||
res = make(Ite,args[0],args[1],args[2]); break;
|
||||
case foci2::Equal:
|
||||
res = make(Equal,args[0],args[1]); break;
|
||||
case foci2::Plus:
|
||||
res = make(Plus,args); break;
|
||||
case foci2::Times:
|
||||
res = make(Times,args); break;
|
||||
case foci2::Div:
|
||||
res = make(Div,args[0],args[1]); break;
|
||||
case foci2::Leq:
|
||||
res = make(Leq,args[0],args[1]); break;
|
||||
case foci2::Distinct:
|
||||
res = make(Distinct,args);
|
||||
break;
|
||||
case foci2::Tsym:
|
||||
res = mk_true();
|
||||
break;
|
||||
case foci2::Fsym:
|
||||
res = mk_false();
|
||||
break;
|
||||
case foci2::Forall:
|
||||
case foci2::Exists:
|
||||
{
|
||||
int nargs = n;
|
||||
std::vector<ast> bounds(nargs-1);
|
||||
for(int i = 0; i < nargs-1; i++)
|
||||
bounds[i] = args[i];
|
||||
opr oz = o == foci2::Forall ? Forall : Exists;
|
||||
res = make_quant(oz,bounds,args[nargs-1]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert("unknown built-in op");
|
||||
}
|
||||
}
|
||||
else if(foci->get_int(i,nval)){
|
||||
res = make_int(nval);
|
||||
}
|
||||
else if(foci->get_func(i,f)){
|
||||
if(f == select_op){
|
||||
assert(n == 2);
|
||||
res = make(Select,args[0],args[1]);
|
||||
}
|
||||
else if(f == store_op){
|
||||
assert(n == 3);
|
||||
res = make(Store,args[0],args[1],args[2]);
|
||||
}
|
||||
else if(f == mod_op){
|
||||
assert(n == 2);
|
||||
res = make(Mod,args[0],args[1]);
|
||||
}
|
||||
else {
|
||||
std::pair<int,symb> foo(f,(symb)0);
|
||||
std::pair<SymbolToFuncDecl::iterator,bool> bar = symbol_to_func_decl.insert(foo);
|
||||
symb &func_decl = bar.first->second;
|
||||
if(bar.second){
|
||||
std::cout << "unknown function symbol:\n";
|
||||
foci->show_ast(i);
|
||||
assert(0);
|
||||
}
|
||||
res = make(func_decl,args);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "iZ3: unknown FOCI expression kind\n";
|
||||
assert(0 && "iZ3: unknown FOCI expression kind");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int interpolate(const std::vector<ast> &cnsts, std::vector<ast> &itps){
|
||||
assert((int)cnsts.size() == frames);
|
||||
foci = foci2::create("lia");
|
||||
if(!foci){
|
||||
std::cerr << "iZ3: cannot find foci lia solver.\n";
|
||||
assert(0);
|
||||
}
|
||||
select_op = foci->mk_func("select");
|
||||
store_op = foci->mk_func("store");
|
||||
mod_op = foci->mk_func("mod");
|
||||
std::vector<foci2::ast> foci_cnsts(frames), foci_itps(frames-1), foci_parents;
|
||||
if(parents)
|
||||
foci_parents.resize(frames);
|
||||
for(int i = 0; i < frames; i++){
|
||||
foci_cnsts[i] = from_Z3_ast(cnsts[i]);
|
||||
if(parents)
|
||||
foci_parents[i] = parents[i];
|
||||
}
|
||||
int res = foci->interpolate(foci_cnsts, foci_itps, foci_parents);
|
||||
if(res == 0){
|
||||
assert((int)foci_itps.size() == frames-1);
|
||||
itps.resize(frames-1);
|
||||
for(int i = 0; i < frames-1; i++){
|
||||
// foci->show_ast(foci_itps[i]);
|
||||
itps[i] = to_Z3_ast(foci_itps[i]);
|
||||
}
|
||||
}
|
||||
ast_to_node.clear();
|
||||
node_to_ast.clear();
|
||||
func_decl_to_symbol.clear();
|
||||
symbol_to_func_decl.clear();
|
||||
delete foci;
|
||||
return res;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
iz3secondary *iz3foci::create(iz3mgr *mgr, int num, int *parents){
|
||||
return new iz3foci_impl(mgr,num,parents);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue