mirror of
https://github.com/Z3Prover/z3
synced 2025-04-10 19:27:06 +00:00
901 lines
24 KiB
C++
Executable file
901 lines
24 KiB
C++
Executable file
/*++
|
|
Copyright (c) 2011 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
iz3mgr.cpp
|
|
|
|
Abstract:
|
|
|
|
A wrapper around an ast manager, providing convenience methods.
|
|
|
|
Author:
|
|
|
|
Ken McMillan (kenmcmil)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#ifdef WIN32
|
|
#pragma warning(disable:4996)
|
|
#pragma warning(disable:4800)
|
|
#pragma warning(disable:4267)
|
|
#pragma warning(disable:4101)
|
|
#pragma warning(disable:4805)
|
|
#pragma warning(disable:4800)
|
|
#endif
|
|
|
|
#include "iz3mgr.h"
|
|
|
|
#include <stdio.h>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <ostream>
|
|
|
|
#include "expr_abstract.h"
|
|
#include "params.h"
|
|
|
|
|
|
#ifndef WIN32
|
|
using namespace stl_ext;
|
|
#endif
|
|
|
|
|
|
std::ostream &operator <<(std::ostream &s, const iz3mgr::ast &a){
|
|
return s;
|
|
}
|
|
|
|
|
|
iz3mgr::ast iz3mgr::make_var(const std::string &name, type ty){
|
|
symbol s = symbol(name.c_str());
|
|
return cook(m().mk_const(m().mk_const_decl(s, ty)));
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(opr op, int n, raw_ast **args){
|
|
switch(op) {
|
|
case True: return mki(m_basic_fid,OP_TRUE,n,args);
|
|
case False: return mki(m_basic_fid,OP_FALSE,n,args);
|
|
case Equal: return mki(m_basic_fid,OP_EQ,n,args);
|
|
case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args);
|
|
case Ite: return mki(m_basic_fid,OP_ITE,n,args);
|
|
case And: return mki(m_basic_fid,OP_AND,n,args);
|
|
case Or: return mki(m_basic_fid,OP_OR,n,args);
|
|
case Iff: return mki(m_basic_fid,OP_IFF,n,args);
|
|
case Xor: return mki(m_basic_fid,OP_XOR,n,args);
|
|
case Not: return mki(m_basic_fid,OP_NOT,n,args);
|
|
case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args);
|
|
case Oeq: return mki(m_basic_fid,OP_OEQ,n,args);
|
|
case Interp: return mki(m_basic_fid,OP_INTERP,n,args);
|
|
case Leq: return mki(m_arith_fid,OP_LE,n,args);
|
|
case Geq: return mki(m_arith_fid,OP_GE,n,args);
|
|
case Lt: return mki(m_arith_fid,OP_LT,n,args);
|
|
case Gt: return mki(m_arith_fid,OP_GT,n,args);
|
|
case Plus: return mki(m_arith_fid,OP_ADD,n,args);
|
|
case Sub: return mki(m_arith_fid,OP_SUB,n,args);
|
|
case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args);
|
|
case Times: return mki(m_arith_fid,OP_MUL,n,args);
|
|
case Div: return mki(m_arith_fid,OP_DIV,n,args);
|
|
case Idiv: return mki(m_arith_fid,OP_IDIV,n,args);
|
|
case Rem: return mki(m_arith_fid,OP_REM,n,args);
|
|
case Mod: return mki(m_arith_fid,OP_MOD,n,args);
|
|
case Power: return mki(m_arith_fid,OP_POWER,n,args);
|
|
case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args);
|
|
case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args);
|
|
case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args);
|
|
case Store: return mki(m_array_fid,OP_STORE,n,args);
|
|
case Select: return mki(m_array_fid,OP_SELECT,n,args);
|
|
case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args);
|
|
case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args);
|
|
case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args);
|
|
case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args);
|
|
case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args);
|
|
case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args);
|
|
case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args);
|
|
case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args);
|
|
case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args);
|
|
default:
|
|
assert(0);
|
|
return ast();
|
|
}
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::mki(family_id fid, decl_kind dk, int n, raw_ast **args){
|
|
return cook(m().mk_app(fid, dk, 0, 0, n, (expr **)args));
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(opr op, const std::vector<ast> &args){
|
|
static std::vector<raw_ast*> a(10);
|
|
if(a.size() < args.size())
|
|
a.resize(args.size());
|
|
for(unsigned i = 0; i < args.size(); i++)
|
|
a[i] = args[i].raw();
|
|
return make(op,args.size(), args.size() ? &a[0] : 0);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(opr op){
|
|
return make(op,0,0);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(opr op, const ast &arg0){
|
|
raw_ast *a = arg0.raw();
|
|
return make(op,1,&a);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1){
|
|
raw_ast *args[2];
|
|
args[0] = arg0.raw();
|
|
args[1] = arg1.raw();
|
|
return make(op,2,args);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1, const ast &arg2){
|
|
raw_ast *args[3];
|
|
args[0] = arg0.raw();
|
|
args[1] = arg1.raw();
|
|
args[2] = arg2.raw();
|
|
return make(op,3,args);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(symb sym, int n, raw_ast **args){
|
|
return cook(m().mk_app(sym, n, (expr **) args));
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(symb sym, const std::vector<ast> &args){
|
|
static std::vector<raw_ast*> a(10);
|
|
if(a.size() < args.size())
|
|
a.resize(args.size());
|
|
for(unsigned i = 0; i < args.size(); i++)
|
|
a[i] = args[i].raw();
|
|
return make(sym,args.size(), args.size() ? &a[0] : 0);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(symb sym){
|
|
return make(sym,0,0);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0){
|
|
raw_ast *a = arg0.raw();
|
|
return make(sym,1,&a);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1){
|
|
raw_ast *args[2];
|
|
args[0] = arg0.raw();
|
|
args[1] = arg1.raw();
|
|
return make(sym,2,args);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1, const ast &arg2){
|
|
raw_ast *args[3];
|
|
args[0] = arg0.raw();
|
|
args[1] = arg1.raw();
|
|
args[2] = arg2.raw();
|
|
return make(sym,3,args);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::make_quant(opr op, const std::vector<ast> &bvs, ast &body){
|
|
if(bvs.size() == 0) return body;
|
|
std::vector<raw_ast *> foo(bvs.size());
|
|
|
|
|
|
std::vector<symbol> names;
|
|
std::vector<class sort *> types;
|
|
std::vector<expr *> bound_asts;
|
|
unsigned num_bound = bvs.size();
|
|
|
|
for (unsigned i = 0; i < num_bound; ++i) {
|
|
app* a = to_app(bvs[i].raw());
|
|
symbol s(to_app(a)->get_decl()->get_name());
|
|
names.push_back(s);
|
|
types.push_back(m().get_sort(a));
|
|
bound_asts.push_back(a);
|
|
}
|
|
expr_ref abs_body(m());
|
|
expr_abstract(m(), 0, num_bound, &bound_asts[0], to_expr(body.raw()), abs_body);
|
|
expr_ref result(m());
|
|
result = m().mk_quantifier(
|
|
op == Forall,
|
|
names.size(), &types[0], &names[0], abs_body.get(),
|
|
0,
|
|
symbol("itp"),
|
|
symbol(),
|
|
0, 0,
|
|
0, 0
|
|
);
|
|
return cook(result.get());
|
|
}
|
|
|
|
// FIXME replace this with existing Z3 functionality
|
|
|
|
iz3mgr::ast iz3mgr::clone(const ast &t, const std::vector<ast> &_args){
|
|
if(_args.size() == 0)
|
|
return t;
|
|
|
|
ast_manager& m = m_manager;
|
|
expr* a = to_expr(t.raw());
|
|
static std::vector<raw_ast*> rargs(10);
|
|
if(rargs.size() < _args.size())
|
|
rargs.resize(_args.size());
|
|
for(unsigned i = 0; i < _args.size(); i++)
|
|
rargs[i] = _args[i].raw();
|
|
expr* const* args = (expr **)&rargs[0];
|
|
switch(a->get_kind()) {
|
|
case AST_APP: {
|
|
app* e = to_app(a);
|
|
if (e->get_num_args() != _args.size()) {
|
|
assert(0);
|
|
}
|
|
else {
|
|
a = m.mk_app(e->get_decl(), _args.size(), args);
|
|
}
|
|
break;
|
|
}
|
|
case AST_QUANTIFIER: {
|
|
if (_args.size() != 1) {
|
|
assert(0);
|
|
}
|
|
else {
|
|
a = m.update_quantifier(to_quantifier(a), args[0]);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return cook(a);
|
|
}
|
|
|
|
|
|
void iz3mgr::show(ast t){
|
|
if(t.null()){
|
|
std::cout << "(null)" << std::endl;
|
|
}
|
|
params_ref p;
|
|
p.set_bool("flat_assoc",false);
|
|
std::cout << mk_pp(t.raw(), m(), p) << std::endl;
|
|
}
|
|
|
|
void iz3mgr::show_symb(symb s){
|
|
std::cout << mk_pp(s, m()) << std::endl;
|
|
}
|
|
|
|
void iz3mgr::print_expr(std::ostream &s, const ast &e){
|
|
params_ref p;
|
|
p.set_bool("flat_assoc",false);
|
|
s << mk_pp(e.raw(), m(), p);
|
|
}
|
|
|
|
|
|
void iz3mgr::print_clause(std::ostream &s, std::vector<ast> &cls){
|
|
s << "(";
|
|
for(unsigned i = 0; i < cls.size(); i++){
|
|
if(i > 0) s << ",";
|
|
print_expr(s,cls[i]);
|
|
}
|
|
s << ")";
|
|
}
|
|
|
|
void iz3mgr::show_clause(std::vector<ast> &cls){
|
|
print_clause(std::cout,cls);
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void iz3mgr::print_lit(ast lit){
|
|
ast abslit = is_not(lit) ? arg(lit,0) : lit;
|
|
int f = op(abslit);
|
|
if(f == And || f == Or || f == Iff){
|
|
if(is_not(lit)) std::cout << "~";
|
|
std::cout << "[" << abslit << "]";
|
|
}
|
|
else
|
|
std::cout << lit;
|
|
}
|
|
|
|
|
|
static int pretty_cols = 79;
|
|
static int pretty_indent_chars = 2;
|
|
|
|
static int pretty_find_delim(const std::string &s, int pos){
|
|
int level = 0;
|
|
int end = s.size();
|
|
for(; pos < end; pos++){
|
|
int ch = s[pos];
|
|
if(ch == '(')level++;
|
|
if(ch == ')')level--;
|
|
if(level < 0 || (level == 0 && ch == ','))break;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
static void pretty_newline(std::ostream &f, int indent){
|
|
f << std::endl;
|
|
for(int i = 0; i < indent; i++)
|
|
f << " ";
|
|
}
|
|
|
|
void iz3mgr::pretty_print(std::ostream &f, const std::string &s){
|
|
int cur_indent = 0;
|
|
int indent = 0;
|
|
int col = 0;
|
|
int pos = 0;
|
|
while(pos < (int)s.size()){
|
|
int delim = pretty_find_delim(s,pos);
|
|
if(s[pos] != ')' && s[pos] != ',' && cur_indent > indent){
|
|
pretty_newline(f,indent);
|
|
cur_indent = indent;
|
|
col = indent;
|
|
continue;
|
|
}
|
|
if (col + delim - pos > pretty_cols) {
|
|
if (col > indent) {
|
|
pretty_newline(f,indent);
|
|
cur_indent = indent;
|
|
col = indent;
|
|
continue;
|
|
}
|
|
int paren = s.find('(',pos);
|
|
if(paren != (int)std::string::npos){
|
|
int chars = paren - pos + 1;
|
|
f << s.substr(pos,chars);
|
|
indent += pretty_indent_chars;
|
|
if(col) pretty_newline(f,indent);
|
|
cur_indent = indent;
|
|
pos += chars;
|
|
col = indent;
|
|
continue;
|
|
}
|
|
}
|
|
int chars = delim - pos + 1;
|
|
f << s.substr(pos,chars);
|
|
pos += chars;
|
|
col += chars;
|
|
if(s[delim] == ')')
|
|
indent -= pretty_indent_chars;
|
|
}
|
|
}
|
|
|
|
|
|
iz3mgr::opr iz3mgr::op(const ast &t){
|
|
ast_kind dk = t.raw()->get_kind();
|
|
switch(dk){
|
|
case AST_APP: {
|
|
expr * e = to_expr(t.raw());
|
|
func_decl *d = to_app(t.raw())->get_decl();
|
|
if (null_family_id == d->get_family_id())
|
|
return Uninterpreted;
|
|
// return (opr)d->get_decl_kind();
|
|
if (m_basic_fid == d->get_family_id()) {
|
|
switch(d->get_decl_kind()) {
|
|
case OP_TRUE: return True;
|
|
case OP_FALSE: return False;
|
|
case OP_EQ: return Equal;
|
|
case OP_DISTINCT: return Distinct;
|
|
case OP_ITE: return Ite;
|
|
case OP_AND: return And;
|
|
case OP_OR: return Or;
|
|
case OP_IFF: return Iff;
|
|
case OP_XOR: return Xor;
|
|
case OP_NOT: return Not;
|
|
case OP_IMPLIES: return Implies;
|
|
case OP_OEQ: return Oeq;
|
|
case OP_INTERP: return Interp;
|
|
default:
|
|
return Other;
|
|
}
|
|
}
|
|
if (m_arith_fid == d->get_family_id()) {
|
|
switch(d->get_decl_kind()) {
|
|
case OP_LE: return Leq;
|
|
case OP_GE: return Geq;
|
|
case OP_LT: return Lt;
|
|
case OP_GT: return Gt;
|
|
case OP_ADD: return Plus;
|
|
case OP_SUB: return Sub;
|
|
case OP_UMINUS: return Uminus;
|
|
case OP_MUL: return Times;
|
|
case OP_DIV: return Div;
|
|
case OP_IDIV: return Idiv;
|
|
case OP_REM: return Rem;
|
|
case OP_MOD: return Mod;
|
|
case OP_POWER: return Power;
|
|
case OP_TO_REAL: return ToReal;
|
|
case OP_TO_INT: return ToInt;
|
|
case OP_IS_INT: return IsInt;
|
|
default:
|
|
if (m().is_unique_value(e))
|
|
return Numeral;
|
|
return Other;
|
|
}
|
|
}
|
|
if (m_array_fid == d->get_family_id()) {
|
|
switch(d->get_decl_kind()) {
|
|
case OP_STORE: return Store;
|
|
case OP_SELECT: return Select;
|
|
case OP_CONST_ARRAY: return ConstArray;
|
|
case OP_ARRAY_DEFAULT: return ArrayDefault;
|
|
case OP_ARRAY_MAP: return ArrayMap;
|
|
case OP_SET_UNION: return SetUnion;
|
|
case OP_SET_INTERSECT: return SetIntersect;
|
|
case OP_SET_DIFFERENCE: return SetDifference;
|
|
case OP_SET_COMPLEMENT: return SetComplement;
|
|
case OP_SET_SUBSET: return SetSubSet;
|
|
case OP_AS_ARRAY: return AsArray;
|
|
default:
|
|
return Other;
|
|
}
|
|
}
|
|
|
|
return Other;
|
|
}
|
|
|
|
|
|
case AST_QUANTIFIER:
|
|
return to_quantifier(t.raw())->is_forall() ? Forall : Exists;
|
|
case AST_VAR:
|
|
return Variable;
|
|
default:;
|
|
}
|
|
return Other;
|
|
}
|
|
|
|
|
|
iz3mgr::pfrule iz3mgr::pr(const ast &t){
|
|
func_decl *d = to_app(t.raw())->get_decl();
|
|
assert(m_basic_fid == d->get_family_id());
|
|
return d->get_decl_kind();
|
|
}
|
|
|
|
void iz3mgr::print_sat_problem(std::ostream &out, const ast &t){
|
|
ast_smt_pp pp(m());
|
|
pp.set_simplify_implies(false);
|
|
pp.display_smt2(out, to_expr(t.raw()));
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::z3_simplify(const ast &e){
|
|
::expr * a = to_expr(e.raw());
|
|
params_ref p;
|
|
th_rewriter m_rw(m(), p);
|
|
expr_ref result(m());
|
|
m_rw(a, result);
|
|
return cook(result);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::z3_really_simplify(const ast &e){
|
|
::expr * a = to_expr(e.raw());
|
|
params_ref simp_params;
|
|
simp_params.set_bool(":som",true);
|
|
simp_params.set_bool(":sort-sums",true);
|
|
th_rewriter m_rw(m(), simp_params);
|
|
expr_ref result(m());
|
|
m_rw(a, result);
|
|
return cook(result);
|
|
}
|
|
|
|
|
|
#if 0
|
|
static rational lcm(const rational &x, const rational &y){
|
|
int a = x.numerator();
|
|
int b = y.numerator();
|
|
return rational(a * b / gcd(a, b));
|
|
}
|
|
#endif
|
|
|
|
static rational extract_lcd(std::vector<rational> &res){
|
|
if(res.size() == 0) return rational(1); // shouldn't happen
|
|
rational lcd = denominator(res[0]);
|
|
for(unsigned i = 1; i < res.size(); i++)
|
|
lcd = lcm(lcd,denominator(res[i]));
|
|
for(unsigned i = 0; i < res.size(); i++)
|
|
res[i] *= lcd;
|
|
return lcd;
|
|
}
|
|
|
|
void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector<ast>& coeffs){
|
|
std::vector<rational> rats;
|
|
get_farkas_coeffs(proof,rats);
|
|
coeffs.resize(rats.size());
|
|
for(unsigned i = 0; i < rats.size(); i++){
|
|
class sort *is = m().mk_sort(m_arith_fid, INT_SORT);
|
|
ast coeff = cook(m_arith_util.mk_numeral(rats[i],is));
|
|
coeffs[i] = coeff;
|
|
}
|
|
}
|
|
|
|
static void abs_rat(std::vector<rational> &rats){
|
|
// check that they are all non-neg -- if neg, take abs val and warn!
|
|
for(unsigned i = 0; i < rats.size(); i++)
|
|
if(rats[i].is_neg()){
|
|
// std::cout << "negative Farkas coeff!\n";
|
|
rats[i] = -rats[i];
|
|
}
|
|
}
|
|
|
|
bool iz3mgr::is_farkas_coefficient_negative(const ast &proof, int n){
|
|
rational r;
|
|
symb s = sym(proof);
|
|
bool ok = s->get_parameter(n+2).is_rational(r);
|
|
if(!ok)
|
|
throw "Bad Farkas coefficient";
|
|
return r.is_neg();
|
|
}
|
|
|
|
void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector<rational>& rats){
|
|
symb s = sym(proof);
|
|
int numps = s->get_num_parameters();
|
|
rats.resize(numps-2);
|
|
#if 0
|
|
if(num_prems(proof) < numps-2){
|
|
std::cout << "bad farkas rule: " << num_prems(proof) << " premises should be " << numps-2 << "\n";
|
|
}
|
|
#endif
|
|
for(int i = 2; i < numps; i++){
|
|
rational r;
|
|
bool ok = s->get_parameter(i).is_rational(r);
|
|
if(!ok)
|
|
throw "Bad Farkas coefficient";
|
|
#if 0
|
|
{
|
|
ast con = conc(prem(proof,i-2));
|
|
ast temp = make_real(r); // for debugging
|
|
opr o = is_not(con) ? op(arg(con,0)) : op(con);
|
|
if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt))
|
|
r = -r;
|
|
}
|
|
#endif
|
|
rats[i-2] = r;
|
|
}
|
|
#if 0
|
|
if(rats.size() != 0 && rats[0].is_neg()){
|
|
for(unsigned i = 0; i < rats.size(); i++){
|
|
assert(rats[i].is_neg());
|
|
rats[i] = -rats[i];
|
|
}
|
|
}
|
|
#endif
|
|
abs_rat(rats);
|
|
extract_lcd(rats);
|
|
}
|
|
|
|
void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector<ast>& coeffs){
|
|
std::vector<rational> rats;
|
|
get_assign_bounds_coeffs(proof,rats);
|
|
coeffs.resize(rats.size());
|
|
for(unsigned i = 0; i < rats.size(); i++){
|
|
coeffs[i] = make_int(rats[i]);
|
|
}
|
|
}
|
|
|
|
void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector<rational>& rats){
|
|
symb s = sym(proof);
|
|
int numps = s->get_num_parameters();
|
|
rats.resize(numps-1);
|
|
rats[0] = rational(1);
|
|
ast conseq = arg(conc(proof),0);
|
|
opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq);
|
|
bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt);
|
|
for(int i = 2; i < numps; i++){
|
|
rational r;
|
|
bool ok = s->get_parameter(i).is_rational(r);
|
|
if(!ok)
|
|
throw "Bad Farkas coefficient";
|
|
{
|
|
ast con = arg(conc(proof),i-1);
|
|
ast temp = make_real(r); // for debugging
|
|
opr o = is_not(con) ? op(arg(con,0)) : op(con);
|
|
if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt))
|
|
r = -r;
|
|
if(conseq_neg)
|
|
r = -r;
|
|
}
|
|
rats[i-1] = r;
|
|
}
|
|
#if 0
|
|
if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them
|
|
for(unsigned i = 1; i < rats.size(); i++){
|
|
if(!rats[i].is_neg())
|
|
throw "Bad Farkas coefficients";
|
|
rats[i] = -rats[i];
|
|
}
|
|
}
|
|
#endif
|
|
abs_rat(rats);
|
|
extract_lcd(rats);
|
|
}
|
|
|
|
void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector<ast>& coeffs){
|
|
std::vector<rational> rats;
|
|
get_assign_bounds_rule_coeffs(proof,rats);
|
|
coeffs.resize(rats.size());
|
|
for(unsigned i = 0; i < rats.size(); i++){
|
|
coeffs[i] = make_int(rats[i]);
|
|
}
|
|
}
|
|
|
|
void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector<rational>& rats){
|
|
symb s = sym(proof);
|
|
int numps = s->get_num_parameters();
|
|
rats.resize(numps-1);
|
|
rats[0] = rational(1);
|
|
ast conseq = arg(conc(proof),0);
|
|
opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq);
|
|
bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt);
|
|
for(int i = 2; i < numps; i++){
|
|
rational r;
|
|
bool ok = s->get_parameter(i).is_rational(r);
|
|
if(!ok)
|
|
throw "Bad Farkas coefficient";
|
|
{
|
|
ast con = conc(prem(proof,i-2));
|
|
ast temp = make_real(r); // for debugging
|
|
opr o = is_not(con) ? op(arg(con,0)) : op(con);
|
|
if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt))
|
|
r = -r;
|
|
if(conseq_neg)
|
|
r = -r;
|
|
}
|
|
rats[i-1] = r;
|
|
}
|
|
#if 0
|
|
if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them
|
|
for(unsigned i = 1; i < rats.size(); i++){
|
|
if(!rats[i].is_neg())
|
|
throw "Bad Farkas coefficients";
|
|
rats[i] = -rats[i];
|
|
}
|
|
}
|
|
#endif
|
|
abs_rat(rats);
|
|
extract_lcd(rats);
|
|
}
|
|
|
|
/** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */
|
|
|
|
void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q, bool round_off){
|
|
ast Qrhs;
|
|
bool qstrict = false;
|
|
if(is_not(Q)){
|
|
ast nQ = arg(Q,0);
|
|
switch(op(nQ)){
|
|
case Gt:
|
|
Qrhs = make(Sub,arg(nQ,1),arg(nQ,0));
|
|
break;
|
|
case Lt:
|
|
Qrhs = make(Sub,arg(nQ,0),arg(nQ,1));
|
|
break;
|
|
case Geq:
|
|
Qrhs = make(Sub,arg(nQ,1),arg(nQ,0));
|
|
qstrict = true;
|
|
break;
|
|
case Leq:
|
|
Qrhs = make(Sub,arg(nQ,0),arg(nQ,1));
|
|
qstrict = true;
|
|
break;
|
|
default:
|
|
throw "not an inequality";
|
|
}
|
|
}
|
|
else {
|
|
switch(op(Q)){
|
|
case Leq:
|
|
Qrhs = make(Sub,arg(Q,1),arg(Q,0));
|
|
break;
|
|
case Geq:
|
|
Qrhs = make(Sub,arg(Q,0),arg(Q,1));
|
|
break;
|
|
case Lt:
|
|
Qrhs = make(Sub,arg(Q,1),arg(Q,0));
|
|
qstrict = true;
|
|
break;
|
|
case Gt:
|
|
Qrhs = make(Sub,arg(Q,0),arg(Q,1));
|
|
qstrict = true;
|
|
break;
|
|
default:
|
|
throw "not an inequality";
|
|
}
|
|
}
|
|
bool pstrict = op(P) == Lt;
|
|
if(qstrict && round_off && (pstrict || !(c == make_int(rational(1))))){
|
|
Qrhs = make(Sub,Qrhs,make_int(rational(1)));
|
|
qstrict = false;
|
|
}
|
|
Qrhs = make(Times,c,Qrhs);
|
|
bool strict = pstrict || qstrict;
|
|
if(strict)
|
|
P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs));
|
|
else
|
|
P = make(Leq,arg(P,0),make(Plus,arg(P,1),Qrhs));
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::sum_inequalities(const std::vector<ast> &coeffs, const std::vector<ast> &ineqs, bool round_off){
|
|
ast zero = make_int("0");
|
|
ast thing = make(Leq,zero,zero);
|
|
for(unsigned i = 0; i < ineqs.size(); i++){
|
|
linear_comb(thing,coeffs[i],ineqs[i], round_off);
|
|
}
|
|
thing = simplify_ineq(thing);
|
|
return thing;
|
|
}
|
|
|
|
void iz3mgr::mk_idiv(const ast& t, const rational &d, ast &whole, ast &frac){
|
|
opr o = op(t);
|
|
if(o == Plus){
|
|
int nargs = num_args(t);
|
|
for(int i = 0; i < nargs; i++)
|
|
mk_idiv(arg(t,i),d,whole,frac);
|
|
return;
|
|
}
|
|
else if(o == Times){
|
|
rational coeff;
|
|
if(is_numeral(arg(t,0),coeff)){
|
|
if(gcd(coeff,d) == d){
|
|
whole = make(Plus,whole,make(Times,make_int(coeff/d),arg(t,1)));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
frac = make(Plus,frac,t);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::mk_idiv(const ast& q, const rational &d){
|
|
ast t = z3_simplify(q);
|
|
if(d == rational(1))
|
|
return t;
|
|
else {
|
|
ast whole = make_int("0");
|
|
ast frac = whole;
|
|
mk_idiv(t,d,whole,frac);
|
|
return z3_simplify(make(Plus,whole,make(Idiv,z3_simplify(frac),make_int(d))));
|
|
}
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::mk_idiv(const ast& t, const ast &d){
|
|
rational r;
|
|
if(is_numeral(d,r))
|
|
return mk_idiv(t,r);
|
|
return make(Idiv,t,d);
|
|
}
|
|
|
|
|
|
// does variable occur in expression?
|
|
int iz3mgr::occurs_in1(stl_ext::hash_map<ast,bool> &occurs_in_memo,ast var, ast e){
|
|
std::pair<ast,bool> foo(e,false);
|
|
std::pair<hash_map<ast,bool>::iterator,bool> bar = occurs_in_memo.insert(foo);
|
|
bool &res = bar.first->second;
|
|
if(bar.second){
|
|
if(e == var) res = true;
|
|
int nargs = num_args(e);
|
|
for(int i = 0; i < nargs; i++)
|
|
res |= occurs_in1(occurs_in_memo,var,arg(e,i));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
int iz3mgr::occurs_in(ast var, ast e){
|
|
hash_map<ast,bool> memo;
|
|
return occurs_in1(memo,var,e);
|
|
}
|
|
|
|
|
|
bool iz3mgr::solve_arith(const ast &v, const ast &x, const ast &y, ast &res){
|
|
if(op(x) == Plus){
|
|
int n = num_args(x);
|
|
for(int i = 0; i < n; i++){
|
|
if(arg(x,i) == v){
|
|
res = z3_simplify(make(Sub, y, make(Sub, x, v)));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// find a controlling equality for a given variable v in a term
|
|
// a controlling equality is of the form v = t, which, being
|
|
// false would force the formula to have the specifid truth value
|
|
// returns t, or null if no such
|
|
|
|
iz3mgr::ast iz3mgr::cont_eq(stl_ext::hash_set<ast> &cont_eq_memo, bool truth, ast v, ast e){
|
|
if(is_not(e)) return cont_eq(cont_eq_memo, !truth,v,arg(e,0));
|
|
if(cont_eq_memo.find(e) != cont_eq_memo.end())
|
|
return ast();
|
|
cont_eq_memo.insert(e);
|
|
if(!truth && op(e) == Equal){
|
|
if(arg(e,0) == v) return(arg(e,1));
|
|
if(arg(e,1) == v) return(arg(e,0));
|
|
ast res;
|
|
if(solve_arith(v,arg(e,0),arg(e,1),res)) return res;
|
|
if(solve_arith(v,arg(e,1),arg(e,0),res)) return res;
|
|
}
|
|
if((!truth && op(e) == And) || (truth && op(e) == Or)){
|
|
int nargs = num_args(e);
|
|
for(int i = 0; i < nargs; i++){
|
|
ast res = cont_eq(cont_eq_memo, truth, v, arg(e,i));
|
|
if(!res.null()) return res;
|
|
}
|
|
}
|
|
if(truth && op(e) == Implies){
|
|
ast res = cont_eq(cont_eq_memo, !truth, v, arg(e,0));
|
|
if(!res.null()) return res;
|
|
res = cont_eq(cont_eq_memo, truth, v, arg(e,1));
|
|
if(!res.null()) return res;
|
|
}
|
|
return ast();
|
|
}
|
|
|
|
// substitute a term t for unbound occurrences of variable v in e
|
|
|
|
iz3mgr::ast iz3mgr::subst(stl_ext::hash_map<ast,ast> &subst_memo, ast var, ast t, ast e){
|
|
if(e == var) return t;
|
|
std::pair<ast,ast> foo(e,ast());
|
|
std::pair<hash_map<ast,ast>::iterator,bool> bar = subst_memo.insert(foo);
|
|
ast &res = bar.first->second;
|
|
if(bar.second){
|
|
int nargs = num_args(e);
|
|
std::vector<ast> args(nargs);
|
|
for(int i = 0; i < nargs; i++)
|
|
args[i] = subst(subst_memo,var,t,arg(e,i));
|
|
opr f = op(e);
|
|
if(f == Equal && args[0] == args[1]) res = mk_true();
|
|
else res = clone(e,args);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::subst(ast var, ast t, ast e){
|
|
hash_map<ast,ast> memo;
|
|
return subst(memo,var,t,e);
|
|
}
|
|
|
|
iz3mgr::ast iz3mgr::subst(stl_ext::hash_map<ast,ast> &subst_memo,ast e){
|
|
std::pair<ast,ast> foo(e,ast());
|
|
std::pair<hash_map<ast,ast>::iterator,bool> bar = subst_memo.insert(foo);
|
|
ast &res = bar.first->second;
|
|
if(bar.second){
|
|
int nargs = num_args(e);
|
|
std::vector<ast> args(nargs);
|
|
for(int i = 0; i < nargs; i++)
|
|
args[i] = subst(subst_memo,arg(e,i));
|
|
opr f = op(e);
|
|
if(f == Equal && args[0] == args[1]) res = mk_true();
|
|
else res = clone(e,args);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// apply a quantifier to a formula, with some optimizations
|
|
// 1) bound variable does not occur -> no quantifier
|
|
// 2) bound variable must be equal to some term -> substitute
|
|
|
|
iz3mgr::ast iz3mgr::apply_quant(opr quantifier, ast var, ast e){
|
|
if((quantifier == Forall && op(e) == And)
|
|
|| (quantifier == Exists && op(e) == Or)){
|
|
int n = num_args(e);
|
|
std::vector<ast> args(n);
|
|
for(int i = 0; i < n; i++)
|
|
args[i] = apply_quant(quantifier,var,arg(e,i));
|
|
return make(op(e),args);
|
|
}
|
|
if(!occurs_in(var,e))return e;
|
|
hash_set<ast> cont_eq_memo;
|
|
ast cterm = cont_eq(cont_eq_memo, quantifier == Forall, var, e);
|
|
if(!cterm.null()){
|
|
return subst(var,cterm,e);
|
|
}
|
|
std::vector<ast> bvs; bvs.push_back(var);
|
|
return make_quant(quantifier,bvs,e);
|
|
}
|
|
|
|
#if 0
|
|
void iz3mgr::get_bound_substitutes(stl_ext::hash_map<ast,bool> &memo, const ast &e, const ast &var, std::vector<ast> &substs){
|
|
std::pair<ast,bool> foo(e,false);
|
|
std::pair<hash_map<ast,bool>::iterator,bool> bar = memo.insert(foo);
|
|
if(bar.second){
|
|
if(op(e) ==
|
|
}
|
|
|
|
}
|
|
#endif
|