mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 09:35:32 +00:00
Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable
This commit is contained in:
commit
8fb36bd41d
31 changed files with 2230 additions and 195 deletions
|
@ -24,6 +24,16 @@ Revision History:
|
|||
#include "iz3mgr.h"
|
||||
#include "iz3scopes.h"
|
||||
|
||||
namespace hash_space {
|
||||
template <>
|
||||
class hash<func_decl *> {
|
||||
public:
|
||||
size_t operator()(func_decl * const &s) const {
|
||||
return (size_t) s;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Base class for interpolators. Includes an AST manager and a scoping
|
||||
object as bases. */
|
||||
|
||||
|
@ -182,6 +192,4 @@ class iz3base : public iz3mgr, public scopes {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -51,6 +51,13 @@ public:
|
|||
typedef hash_map<foci2::ast,ast> NodeToAst;
|
||||
NodeToAst node_to_ast; // maps Z3 ast's to foci expressions
|
||||
|
||||
// We only use this for FuncDeclToSymbol, which has no range destructor
|
||||
struct symb_hash {
|
||||
size_t operator()(const symb &s) const {
|
||||
return (size_t) s;
|
||||
}
|
||||
};
|
||||
|
||||
typedef hash_map<symb,foci2::symb> FuncDeclToSymbol;
|
||||
FuncDeclToSymbol func_decl_to_symbol; // maps Z3 func decls to symbols
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ namespace std {
|
|||
|
||||
#ifndef WIN32
|
||||
|
||||
#if 0
|
||||
namespace stl_ext {
|
||||
template <class T>
|
||||
class hash<T *> {
|
||||
|
@ -150,6 +151,7 @@ namespace stl_ext {
|
|||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -75,15 +75,16 @@ struct frame_reducer : public iz3mgr {
|
|||
}
|
||||
}
|
||||
|
||||
void get_frames(const std::vector<ast> &z3_preds,
|
||||
void get_frames(const std::vector<std::vector<ast> >&z3_preds,
|
||||
const std::vector<int> &orig_parents,
|
||||
std::vector<ast> &assertions,
|
||||
std::vector<std::vector<ast> >&assertions,
|
||||
std::vector<int> &parents,
|
||||
z3pf proof){
|
||||
frames = z3_preds.size();
|
||||
orig_parents_copy = orig_parents;
|
||||
for(unsigned i = 0; i < z3_preds.size(); i++)
|
||||
frame_map[z3_preds[i]] = i;
|
||||
for(unsigned j = 0; j < z3_preds[i].size(); j++)
|
||||
frame_map[z3_preds[i][j]] = i;
|
||||
used_frames.resize(frames);
|
||||
hash_set<ast> memo;
|
||||
get_proof_assumptions_rec(proof,memo,used_frames);
|
||||
|
@ -202,7 +203,7 @@ public:
|
|||
}
|
||||
|
||||
void proof_to_interpolant(z3pf proof,
|
||||
const std::vector<ast> &cnsts,
|
||||
const std::vector<std::vector<ast> > &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
std::vector<ast> &interps,
|
||||
const std::vector<ast> &theory,
|
||||
|
@ -212,11 +213,12 @@ public:
|
|||
test_secondary(cnsts,parents,interps);
|
||||
return;
|
||||
#endif
|
||||
|
||||
profiling::timer_start("Interpolation prep");
|
||||
|
||||
// get rid of frames not used in proof
|
||||
|
||||
std::vector<ast> cnsts_vec;
|
||||
std::vector<std::vector<ast> > cnsts_vec;
|
||||
std::vector<int> parents_vec;
|
||||
frame_reducer fr(*this);
|
||||
fr.get_frames(cnsts,parents,cnsts_vec,parents_vec,proof);
|
||||
|
@ -235,10 +237,7 @@ public:
|
|||
#define BINARY_INTERPOLATION
|
||||
#ifndef BINARY_INTERPOLATION
|
||||
// create a translator
|
||||
std::vector<std::vector<ast> > cnsts_vec_vec(cnsts_vec.size());
|
||||
for(unsigned i = 0; i < cnsts_vec.size(); i++)
|
||||
cnsts_vec_vec[i].push_back(cnsts_vec[i]);
|
||||
iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec_vec,parents_vec,theory);
|
||||
iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec,parents_vec,theory);
|
||||
tr_killer.set(tr);
|
||||
|
||||
// set the translation options, if needed
|
||||
|
@ -273,7 +272,8 @@ public:
|
|||
std::vector<std::vector<ast> > cnsts_vec_vec(2);
|
||||
for(unsigned j = 0; j < cnsts_vec.size(); j++){
|
||||
bool is_A = the_base.in_range(j,rng);
|
||||
cnsts_vec_vec[is_A ? 0 : 1].push_back(cnsts_vec[j]);
|
||||
for(unsigned k = 0; k < cnsts_vec[j].size(); k++)
|
||||
cnsts_vec_vec[is_A ? 0 : 1].push_back(cnsts_vec[j][k]);
|
||||
}
|
||||
|
||||
killme<iz3translation> tr_killer_i;
|
||||
|
@ -308,6 +308,19 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void proof_to_interpolant(z3pf proof,
|
||||
std::vector<ast> &cnsts,
|
||||
const std::vector<int> &parents,
|
||||
std::vector<ast> &interps,
|
||||
const std::vector<ast> &theory,
|
||||
interpolation_options_struct *options = 0
|
||||
){
|
||||
std::vector<std::vector<ast> > cnsts_vec(cnsts.size());
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
cnsts_vec[i].push_back(cnsts[i]);
|
||||
proof_to_interpolant(proof,cnsts_vec,parents,interps,theory,options);
|
||||
}
|
||||
|
||||
// same as above, but represents the tree using an ast
|
||||
|
||||
void proof_to_interpolant(const z3pf &proof,
|
||||
|
@ -322,7 +335,6 @@ public:
|
|||
|
||||
to_parents_vec_representation(_cnsts, tree, cnsts, parents, theory, pos_map);
|
||||
|
||||
|
||||
//use the parents vector representation to compute interpolant
|
||||
proof_to_interpolant(proof,cnsts,parents,interps,theory,options);
|
||||
|
||||
|
@ -397,6 +409,35 @@ void iz3interpolate(ast_manager &_m_manager,
|
|||
interps[i] = itp.uncook(_interps[i]);
|
||||
}
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const ::vector<ptr_vector<ast> > &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory,
|
||||
interpolation_options_struct * options)
|
||||
{
|
||||
iz3interp itp(_m_manager);
|
||||
if(options)
|
||||
options->apply(itp);
|
||||
std::vector<std::vector<iz3mgr::ast> > _cnsts(cnsts.size());
|
||||
std::vector<int> _parents(parents.size());
|
||||
std::vector<iz3mgr::ast> _interps;
|
||||
std::vector<iz3mgr::ast> _theory(theory.size());
|
||||
for(unsigned i = 0; i < cnsts.size(); i++)
|
||||
for(unsigned j = 0; j < cnsts[i].size(); j++)
|
||||
_cnsts[i].push_back(itp.cook(cnsts[i][j]));
|
||||
for(unsigned i = 0; i < parents.size(); i++)
|
||||
_parents[i] = parents[i];
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
_theory[i] = itp.cook(theory[i]);
|
||||
iz3mgr::ast _proof = itp.cook(proof);
|
||||
itp.proof_to_interpolant(_proof,_cnsts,_parents,_interps,_theory,options);
|
||||
interps.resize(_interps.size());
|
||||
for(unsigned i = 0; i < interps.size(); i++)
|
||||
interps[i] = itp.uncook(_interps[i]);
|
||||
}
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const ptr_vector<ast> &cnsts,
|
||||
|
@ -461,5 +502,3 @@ void interpolation_options_struct::apply(iz3base &b){
|
|||
b.set_option((*it).first,(*it).second);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -56,6 +56,16 @@ void iz3interpolate(ast_manager &_m_manager,
|
|||
const ptr_vector<ast> &theory,
|
||||
interpolation_options_struct * options = 0);
|
||||
|
||||
/* Same as above, but each constraint is a vector of formulas. */
|
||||
|
||||
void iz3interpolate(ast_manager &_m_manager,
|
||||
ast *proof,
|
||||
const vector<ptr_vector<ast> > &cnsts,
|
||||
const ::vector<int> &parents,
|
||||
ptr_vector<ast> &interps,
|
||||
const ptr_vector<ast> &theory,
|
||||
interpolation_options_struct * options = 0);
|
||||
|
||||
/* Compute an interpolant from a proof. This version uses the ast
|
||||
representation, for compatibility with the new API. */
|
||||
|
||||
|
|
|
@ -190,7 +190,7 @@ iz3mgr::ast iz3mgr::make_quant(opr op, const std::vector<ast> &bvs, ast &body){
|
|||
op == Forall,
|
||||
names.size(), &types[0], &names[0], abs_body.get(),
|
||||
0,
|
||||
symbol(),
|
||||
symbol("itp"),
|
||||
symbol(),
|
||||
0, 0,
|
||||
0, 0
|
||||
|
@ -761,6 +761,19 @@ int iz3mgr::occurs_in(ast var, ast 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
|
||||
|
@ -774,6 +787,9 @@ iz3mgr::ast iz3mgr::cont_eq(stl_ext::hash_set<ast> &cont_eq_memo, bool truth, as
|
|||
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);
|
||||
|
@ -815,11 +831,35 @@ iz3mgr::ast iz3mgr::subst(ast var, ast t, ast e){
|
|||
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);
|
||||
|
|
|
@ -65,7 +65,7 @@ class ast_i {
|
|||
return _ast == other._ast;
|
||||
}
|
||||
bool lt(const ast_i &other) const {
|
||||
return _ast < other._ast;
|
||||
return _ast->get_id() < other._ast->get_id();
|
||||
}
|
||||
friend bool operator==(const ast_i &x, const ast_i&y){
|
||||
return x.eq(y);
|
||||
|
@ -76,7 +76,7 @@ class ast_i {
|
|||
friend bool operator<(const ast_i &x, const ast_i&y){
|
||||
return x.lt(y);
|
||||
}
|
||||
size_t hash() const {return (size_t)_ast;}
|
||||
size_t hash() const {return _ast->get_id();}
|
||||
bool null() const {return !_ast;}
|
||||
};
|
||||
|
||||
|
@ -140,7 +140,8 @@ namespace std {
|
|||
class less<ast_r> {
|
||||
public:
|
||||
bool operator()(const ast_r &s, const ast_r &t) const {
|
||||
return s.raw() < t.raw(); // s.raw()->get_id() < t.raw()->get_id();
|
||||
// return s.raw() < t.raw();
|
||||
return s.raw()->get_id() < t.raw()->get_id();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -359,6 +360,12 @@ class iz3mgr {
|
|||
return fid == m().get_basic_family_id() && k == BOOL_SORT;
|
||||
}
|
||||
|
||||
bool is_array_type(type t){
|
||||
family_id fid = to_sort(t)->get_family_id();
|
||||
decl_kind k = to_sort(t)->get_decl_kind();
|
||||
return fid == m_array_fid && k == ARRAY_SORT;
|
||||
}
|
||||
|
||||
type get_range_type(symb s){
|
||||
return to_func_decl(s)->get_range();
|
||||
}
|
||||
|
@ -631,6 +638,9 @@ class iz3mgr {
|
|||
|
||||
ast subst(ast var, ast t, ast e);
|
||||
|
||||
// apply a substitution defined by a map
|
||||
ast subst(stl_ext::hash_map<ast,ast> &map, ast e);
|
||||
|
||||
// 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
|
||||
|
@ -683,13 +693,14 @@ class iz3mgr {
|
|||
|
||||
protected:
|
||||
ast_manager &m_manager;
|
||||
int occurs_in(ast var, ast e);
|
||||
|
||||
private:
|
||||
ast mki(family_id fid, decl_kind sk, int n, raw_ast **args);
|
||||
ast make(opr op, int n, raw_ast **args);
|
||||
ast make(symb sym, int n, raw_ast **args);
|
||||
int occurs_in1(stl_ext::hash_map<ast,bool> &occurs_in_memo, ast var, ast e);
|
||||
int occurs_in(ast var, ast e);
|
||||
bool solve_arith(const ast &v, const ast &x, const ast &y, ast &res);
|
||||
ast cont_eq(stl_ext::hash_set<ast> &cont_eq_memo, bool truth, ast v, ast e);
|
||||
ast subst(stl_ext::hash_map<ast,ast> &subst_memo, ast var, ast t, ast e);
|
||||
|
||||
|
|
|
@ -40,6 +40,20 @@ Revision History:
|
|||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
// We promise not to use this for hash_map with range destructor
|
||||
namespace stl_ext {
|
||||
template <>
|
||||
class hash<expr *> {
|
||||
public:
|
||||
size_t operator()(const expr *p) const {
|
||||
return (size_t) p;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// TBD: algebraic data-types declarations will not be printed.
|
||||
class free_func_visitor {
|
||||
ast_manager& m;
|
||||
|
|
|
@ -118,6 +118,30 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
where t is an arbitrary term */
|
||||
symb rewrite_B;
|
||||
|
||||
/* a normalization step is of the form (lhs=rhs) : proof, where "proof"
|
||||
is a proof of lhs=rhs and lhs is a mixed term. If rhs is a mixed term
|
||||
then it must have a greater index than lhs. */
|
||||
symb normal_step;
|
||||
|
||||
/* A chain of normalization steps is either "true" (the null chain)
|
||||
or normal_chain(<step> <tail>), where step is a normalization step
|
||||
and tail is a normalization chain. The lhs of <step> must have
|
||||
a less term index than any lhs in the chain. Moreover, the rhs of
|
||||
<step> may not occur as the lhs of step in <tail>. If we wish to
|
||||
add lhs=rhs to the beginning of <tail> and rhs=rhs' occurs in <tail>
|
||||
we must apply transitivity, transforming <step> to lhs=rhs'. */
|
||||
|
||||
symb normal_chain;
|
||||
|
||||
/* If p is a proof of Q and c is a normalization chain, then normal(p,c)
|
||||
is a proof of Q(c) (that is, Q with all substitutions in c performed). */
|
||||
|
||||
symb normal;
|
||||
|
||||
/** Stand-ins for quantifiers */
|
||||
|
||||
symb sforall, sexists;
|
||||
|
||||
|
||||
ast get_placeholder(ast t){
|
||||
hash_map<ast,ast>::iterator it = placeholders.find(t);
|
||||
|
@ -209,6 +233,10 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
ast neg_pivot_lit = mk_not(atom);
|
||||
if(op(pivot) != Not)
|
||||
std::swap(premise1,premise2);
|
||||
if(op(pivot) == Equal && op(arg(pivot,0)) == Select && op(arg(pivot,1)) == Select){
|
||||
neg_pivot_lit = mk_not(neg_pivot_lit);
|
||||
std::swap(premise1,premise2);
|
||||
}
|
||||
return resolve_arith_rec1(memo, neg_pivot_lit, premise1, premise2);
|
||||
}
|
||||
|
||||
|
@ -333,7 +361,13 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
res = itp2;
|
||||
{
|
||||
symb s = sym(itp2);
|
||||
if(s == sforall || s == sexists)
|
||||
res = make(s,arg(itp2,0),resolve_arith_rec2(memo, pivot1, conj1, arg(itp2,1)));
|
||||
else
|
||||
res = itp2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
@ -363,7 +397,13 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
res = itp1;
|
||||
{
|
||||
symb s = sym(itp1);
|
||||
if(s == sforall || s == sexists)
|
||||
res = make(s,arg(itp1,0),resolve_arith_rec1(memo, neg_pivot_lit, arg(itp1,1), itp2));
|
||||
else
|
||||
res = itp1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
@ -451,7 +491,12 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
hash_map<ast,ast> simplify_memo;
|
||||
|
||||
ast simplify(const ast &t){
|
||||
return simplify_rec(t);
|
||||
ast res = normalize(simplify_rec(t));
|
||||
#ifdef BOGUS_QUANTS
|
||||
if(localization_vars.size())
|
||||
res = add_quants(z3_simplify(res));
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
ast simplify_rec(const ast &e){
|
||||
|
@ -521,12 +566,18 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
throw cannot_simplify();
|
||||
}
|
||||
|
||||
bool is_normal_ineq(const ast &ineq){
|
||||
if(sym(ineq) == normal)
|
||||
return is_ineq(arg(ineq,0));
|
||||
return is_ineq(ineq);
|
||||
}
|
||||
|
||||
ast simplify_sum(std::vector<ast> &args){
|
||||
ast cond = mk_true();
|
||||
ast Aproves = mk_true(), Bproves = mk_true();
|
||||
ast ineq = args[0];
|
||||
if(!is_ineq(ineq)) throw cannot_simplify();
|
||||
sum_cond_ineq(ineq,cond,args[1],args[2]);
|
||||
return my_implies(cond,ineq);
|
||||
if(!is_normal_ineq(ineq)) throw cannot_simplify();
|
||||
sum_cond_ineq(ineq,args[1],args[2],Aproves,Bproves);
|
||||
return my_and(Aproves,my_implies(Bproves,ineq));
|
||||
}
|
||||
|
||||
ast simplify_rotate_sum(const ast &pl, const ast &pf){
|
||||
|
@ -539,29 +590,42 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return sym(chain) == concat;
|
||||
}
|
||||
|
||||
ast ineq_from_chain(const ast &chain, ast &cond){
|
||||
if(is_rewrite_chain(chain)){
|
||||
ast last = chain_last(chain);
|
||||
ast rest = chain_rest(chain);
|
||||
if(is_true(rest) && is_rewrite_side(LitA,last)
|
||||
&& is_true(rewrite_lhs(last))){
|
||||
cond = my_and(cond,rewrite_cond(last));
|
||||
return rewrite_rhs(last);
|
||||
}
|
||||
if(is_rewrite_side(LitB,last) && is_true(rewrite_cond(last)))
|
||||
return ineq_from_chain(rest,cond);
|
||||
#if 0
|
||||
ast ineq_from_chain_simple(const ast &chain, ast &cond){
|
||||
if(is_true(chain))
|
||||
return chain;
|
||||
ast last = chain_last(chain);
|
||||
ast rest = chain_rest(chain);
|
||||
if(is_true(rest) && is_rewrite_side(LitA,last)
|
||||
&& is_true(rewrite_lhs(last))){
|
||||
cond = my_and(cond,rewrite_cond(last));
|
||||
return rewrite_rhs(last);
|
||||
}
|
||||
if(is_rewrite_side(LitB,last) && is_true(rewrite_cond(last)))
|
||||
return ineq_from_chain_simple(rest,cond);
|
||||
return chain;
|
||||
}
|
||||
#endif
|
||||
|
||||
ast ineq_from_chain(const ast &chain, ast &Aproves, ast &Bproves){
|
||||
if(is_rewrite_chain(chain))
|
||||
return rewrite_chain_to_normal_ineq(chain,Aproves,Bproves);
|
||||
return chain;
|
||||
}
|
||||
|
||||
void sum_cond_ineq(ast &ineq, ast &cond, const ast &coeff2, const ast &ineq2){
|
||||
|
||||
void sum_cond_ineq(ast &ineq, const ast &coeff2, const ast &ineq2, ast &Aproves, ast &Bproves){
|
||||
opr o = op(ineq2);
|
||||
if(o == Implies){
|
||||
sum_cond_ineq(ineq,cond,coeff2,arg(ineq2,1));
|
||||
cond = my_and(cond,arg(ineq2,0));
|
||||
sum_cond_ineq(ineq,coeff2,arg(ineq2,1),Aproves,Bproves);
|
||||
Bproves = my_and(Bproves,arg(ineq2,0));
|
||||
}
|
||||
else {
|
||||
ast the_ineq = ineq_from_chain(ineq2,cond);
|
||||
ast the_ineq = ineq_from_chain(ineq2,Aproves,Bproves);
|
||||
if(sym(ineq) == normal || sym(the_ineq) == normal){
|
||||
sum_normal_ineq(ineq,coeff2,the_ineq,Aproves,Bproves);
|
||||
return;
|
||||
}
|
||||
if(is_ineq(the_ineq))
|
||||
linear_comb(ineq,coeff2,the_ineq);
|
||||
else
|
||||
|
@ -569,6 +633,27 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
}
|
||||
}
|
||||
|
||||
void destruct_normal(const ast &pf, ast &p, ast &n){
|
||||
if(sym(pf) == normal){
|
||||
p = arg(pf,0);
|
||||
n = arg(pf,1);
|
||||
}
|
||||
else {
|
||||
p = pf;
|
||||
n = mk_true();
|
||||
}
|
||||
}
|
||||
|
||||
void sum_normal_ineq(ast &ineq, const ast &coeff2, const ast &ineq2, ast &Aproves, ast &Bproves){
|
||||
ast in1,in2,n1,n2;
|
||||
destruct_normal(ineq,in1,n1);
|
||||
destruct_normal(ineq2,in2,n2);
|
||||
ast dummy1, dummy2;
|
||||
sum_cond_ineq(in1,coeff2,in2,dummy1,dummy2);
|
||||
n1 = merge_normal_chains(n1,n2, Aproves, Bproves);
|
||||
ineq = make_normal(in1,n1);
|
||||
}
|
||||
|
||||
bool is_ineq(const ast &ineq){
|
||||
opr o = op(ineq);
|
||||
if(o == Not) o = op(arg(ineq,0));
|
||||
|
@ -577,6 +662,12 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
|
||||
// divide both sides of inequality by a non-negative integer divisor
|
||||
ast idiv_ineq(const ast &ineq1, const ast &divisor){
|
||||
if(sym(ineq1) == normal){
|
||||
ast in1,n1;
|
||||
destruct_normal(ineq1,in1,n1);
|
||||
in1 = idiv_ineq(in1,divisor);
|
||||
return make_normal(in1,n1);
|
||||
}
|
||||
if(divisor == make_int(rational(1)))
|
||||
return ineq1;
|
||||
ast ineq = ineq1;
|
||||
|
@ -585,17 +676,23 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return make(op(ineq),mk_idiv(arg(ineq,0),divisor),mk_idiv(arg(ineq,1),divisor));
|
||||
}
|
||||
|
||||
ast rotate_sum_rec(const ast &pl, const ast &pf, ast &cond, ast &ineq){
|
||||
ast rotate_sum_rec(const ast &pl, const ast &pf, ast &Bproves, ast &ineq){
|
||||
if(pf == pl)
|
||||
return my_implies(cond,simplify_ineq(ineq));
|
||||
return my_implies(Bproves,simplify_ineq(ineq));
|
||||
if(op(pf) == Uninterpreted && sym(pf) == sum){
|
||||
if(arg(pf,2) == pl){
|
||||
sum_cond_ineq(ineq,cond,make_int("1"),arg(pf,0));
|
||||
ast Aproves = mk_true();
|
||||
sum_cond_ineq(ineq,make_int("1"),arg(pf,0),Aproves,Bproves);
|
||||
if(!is_true(Aproves))
|
||||
throw "help!";
|
||||
ineq = idiv_ineq(ineq,arg(pf,1));
|
||||
return my_implies(cond,ineq);
|
||||
return my_implies(Bproves,ineq);
|
||||
}
|
||||
sum_cond_ineq(ineq,cond,arg(pf,1),arg(pf,2));
|
||||
return rotate_sum_rec(pl,arg(pf,0),cond,ineq);
|
||||
ast Aproves = mk_true();
|
||||
sum_cond_ineq(ineq,arg(pf,1),arg(pf,2),Aproves,Bproves);
|
||||
if(!is_true(Aproves))
|
||||
throw "help!";
|
||||
return rotate_sum_rec(pl,arg(pf,0),Bproves,ineq);
|
||||
}
|
||||
throw cannot_simplify();
|
||||
}
|
||||
|
@ -605,28 +702,30 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
ast equality = arg(neg_equality,0);
|
||||
ast x = arg(equality,0);
|
||||
ast y = arg(equality,1);
|
||||
ast cond1 = mk_true();
|
||||
ast xleqy = round_ineq(ineq_from_chain(arg(pf,1),cond1));
|
||||
ast yleqx = round_ineq(ineq_from_chain(arg(pf,2),cond1));
|
||||
ast Aproves1 = mk_true(), Bproves1 = mk_true();
|
||||
ast xleqy = round_ineq(ineq_from_chain(arg(pf,1),Aproves1,Bproves1));
|
||||
ast yleqx = round_ineq(ineq_from_chain(arg(pf,2),Aproves1,Bproves1));
|
||||
ast ineq1 = make(Leq,make_int("0"),make_int("0"));
|
||||
sum_cond_ineq(ineq1,cond1,make_int("-1"),xleqy);
|
||||
sum_cond_ineq(ineq1,cond1,make_int("-1"),yleqx);
|
||||
cond1 = my_and(cond1,z3_simplify(ineq1));
|
||||
ast cond2 = mk_true();
|
||||
sum_cond_ineq(ineq1,make_int("-1"),xleqy,Aproves1,Bproves1);
|
||||
sum_cond_ineq(ineq1,make_int("-1"),yleqx,Aproves1,Bproves1);
|
||||
Bproves1 = my_and(Bproves1,z3_simplify(ineq1));
|
||||
ast Aproves2 = mk_true(), Bproves2 = mk_true();
|
||||
ast ineq2 = make(Leq,make_int("0"),make_int("0"));
|
||||
sum_cond_ineq(ineq2,cond2,make_int("1"),xleqy);
|
||||
sum_cond_ineq(ineq2,cond2,make_int("1"),yleqx);
|
||||
cond2 = z3_simplify(ineq2);
|
||||
sum_cond_ineq(ineq2,make_int("1"),xleqy,Aproves2,Bproves2);
|
||||
sum_cond_ineq(ineq2,make_int("1"),yleqx,Aproves2,Bproves2);
|
||||
Bproves2 = z3_simplify(ineq2);
|
||||
if(!is_true(Aproves1) || !is_true(Aproves2))
|
||||
throw "help!";
|
||||
if(get_term_type(x) == LitA){
|
||||
ast iter = z3_simplify(make(Plus,x,get_ineq_rhs(xleqy)));
|
||||
ast rewrite1 = make_rewrite(LitA,top_pos,cond1,make(Equal,x,iter));
|
||||
ast rewrite2 = make_rewrite(LitB,top_pos,cond2,make(Equal,iter,y));
|
||||
ast rewrite1 = make_rewrite(LitA,top_pos,Bproves1,make(Equal,x,iter));
|
||||
ast rewrite2 = make_rewrite(LitB,top_pos,Bproves2,make(Equal,iter,y));
|
||||
return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2);
|
||||
}
|
||||
if(get_term_type(y) == LitA){
|
||||
ast iter = z3_simplify(make(Plus,y,get_ineq_rhs(yleqx)));
|
||||
ast rewrite2 = make_rewrite(LitA,top_pos,cond1,make(Equal,iter,y));
|
||||
ast rewrite1 = make_rewrite(LitB,top_pos,cond2,make(Equal,x,iter));
|
||||
ast rewrite2 = make_rewrite(LitA,top_pos,Bproves1,make(Equal,iter,y));
|
||||
ast rewrite1 = make_rewrite(LitB,top_pos,Bproves2,make(Equal,x,iter));
|
||||
return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2);
|
||||
}
|
||||
throw cannot_simplify();
|
||||
|
@ -649,11 +748,18 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
ast equa = sep_cond(arg(pf,0),cond);
|
||||
if(is_equivrel_chain(equa)){
|
||||
ast lhs,rhs; eq_from_ineq(arg(neg_equality,0),lhs,rhs); // get inequality we need to prove
|
||||
ast ineqs= chain_ineqs(op(arg(neg_equality,0)),LitA,equa,lhs,rhs); // chain must be from lhs to rhs
|
||||
cond = my_and(cond,chain_conditions(LitA,equa));
|
||||
ast Bconds = chain_conditions(LitB,equa);
|
||||
if(is_true(Bconds) && op(ineqs) != And)
|
||||
return my_implies(cond,ineqs);
|
||||
LitType lhst = get_term_type(lhs), rhst = get_term_type(rhs);
|
||||
if(lhst != LitMixed && rhst != LitMixed){
|
||||
ast ineqs= chain_ineqs(op(arg(neg_equality,0)),LitA,equa,lhs,rhs); // chain must be from lhs to rhs
|
||||
cond = my_and(cond,chain_conditions(LitA,equa));
|
||||
ast Bconds = z3_simplify(chain_conditions(LitB,equa));
|
||||
if(is_true(Bconds) && op(ineqs) != And)
|
||||
return my_implies(cond,ineqs);
|
||||
}
|
||||
else {
|
||||
ast itp = make(Leq,make_int(rational(0)),make_int(rational(0)));
|
||||
return make_normal(itp,cons_normal(fix_normal(lhs,rhs,equa),mk_true()));
|
||||
}
|
||||
}
|
||||
}
|
||||
throw cannot_simplify();
|
||||
|
@ -757,11 +863,57 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
chain = concat_rewrite_chain(chain,split[1]);
|
||||
}
|
||||
}
|
||||
else // if not an equivalence, must be of form T <-> pred
|
||||
else { // if not an equivalence, must be of form T <-> pred
|
||||
chain = concat_rewrite_chain(P,PeqQ);
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
void get_subterm_normals(const ast &ineq1, const ast &ineq2, const ast &chain, ast &normals,
|
||||
const ast &pos, hash_set<ast> &memo, ast &Aproves, ast &Bproves){
|
||||
opr o1 = op(ineq1);
|
||||
opr o2 = op(ineq2);
|
||||
if(o1 == Not || o1 == Leq || o1 == Lt || o1 == Geq || o1 == Gt || o1 == Plus || o1 == Times){
|
||||
int n = num_args(ineq1);
|
||||
if(o2 != o1 || num_args(ineq2) != n)
|
||||
throw "bad inequality rewriting";
|
||||
for(int i = 0; i < n; i++){
|
||||
ast new_pos = add_pos_to_end(pos,i);
|
||||
get_subterm_normals(arg(ineq1,i), arg(ineq2,i), chain, normals, new_pos, memo, Aproves, Bproves);
|
||||
}
|
||||
}
|
||||
else if(get_term_type(ineq2) == LitMixed && memo.find(ineq2) == memo.end()){
|
||||
memo.insert(ineq2);
|
||||
ast sub_chain = extract_rewrites(chain,pos);
|
||||
if(is_true(sub_chain))
|
||||
throw "bad inequality rewriting";
|
||||
ast new_normal = make_normal_step(ineq2,ineq1,reverse_chain(sub_chain));
|
||||
normals = merge_normal_chains(normals,cons_normal(new_normal,mk_true()), Aproves, Bproves);
|
||||
}
|
||||
}
|
||||
|
||||
ast rewrite_chain_to_normal_ineq(const ast &chain, ast &Aproves, ast &Bproves){
|
||||
ast tail, pref = get_head_chain(chain,tail,false); // pref is x=y, tail is x=y -> x'=y'
|
||||
ast head = chain_last(pref);
|
||||
ast ineq1 = rewrite_rhs(head);
|
||||
ast ineq2 = apply_rewrite_chain(ineq1,tail);
|
||||
ast nc = mk_true();
|
||||
hash_set<ast> memo;
|
||||
get_subterm_normals(ineq1,ineq2,tail,nc,top_pos,memo, Aproves, Bproves);
|
||||
ast itp;
|
||||
if(is_rewrite_side(LitA,head)){
|
||||
itp = ineq1;
|
||||
ast mc = z3_simplify(chain_side_proves(LitB,pref));
|
||||
Bproves = my_and(Bproves,mc);
|
||||
}
|
||||
else {
|
||||
itp = make(Leq,make_int(rational(0)),make_int(rational(0)));
|
||||
ast mc = z3_simplify(chain_side_proves(LitA,pref));
|
||||
Aproves = my_and(Aproves,mc);
|
||||
}
|
||||
return make_normal(itp,nc);
|
||||
}
|
||||
|
||||
/* Given a chain rewrite chain deriving not P and a rewrite chain deriving P, return an interpolant. */
|
||||
ast contra_chain(const ast &neg_chain, const ast &pos_chain){
|
||||
// equality is a special case. we use the derivation of x=y to rewrite not(x=y) to not(y=y)
|
||||
|
@ -790,11 +942,18 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
}
|
||||
|
||||
ast simplify_modpon(const std::vector<ast> &args){
|
||||
ast cond = mk_true();
|
||||
ast chain = simplify_modpon_fwd(args,cond);
|
||||
ast Q2 = sep_cond(args[2],cond);
|
||||
ast interp = is_negation_chain(chain) ? contra_chain(chain,Q2) : contra_chain(Q2,chain);
|
||||
return my_implies(cond,interp);
|
||||
ast Aproves = mk_true(), Bproves = mk_true();
|
||||
ast chain = simplify_modpon_fwd(args,Bproves);
|
||||
ast Q2 = sep_cond(args[2],Bproves);
|
||||
ast interp;
|
||||
if(is_normal_ineq(Q2)){ // inequalities are special
|
||||
ast nQ2 = rewrite_chain_to_normal_ineq(chain,Aproves,Bproves);
|
||||
sum_cond_ineq(nQ2,make_int(rational(1)),Q2,Aproves,Bproves);
|
||||
interp = normalize(nQ2);
|
||||
}
|
||||
else
|
||||
interp = is_negation_chain(chain) ? contra_chain(chain,Q2) : contra_chain(Q2,chain);
|
||||
return my_and(Aproves,my_implies(Bproves,interp));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1035,6 +1194,12 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return make(add_pos,make_int(rational(arg)),pos);
|
||||
}
|
||||
|
||||
ast add_pos_to_end(const ast &pos, int i){
|
||||
if(pos == top_pos)
|
||||
return pos_add(i,pos);
|
||||
return make(add_pos,arg(pos,0),add_pos_to_end(arg(pos,1),i));
|
||||
}
|
||||
|
||||
/* return the argument number of position, if not top */
|
||||
int pos_arg(const ast &pos){
|
||||
rational r;
|
||||
|
@ -1170,6 +1335,10 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return make(sym(rew),pos_add(apos,arg(rew,0)),arg(rew,1),arg(rew,2));
|
||||
}
|
||||
|
||||
ast rewrite_pos_set(const ast &pos, const ast &rew){
|
||||
return make(sym(rew),pos,arg(rew,1),arg(rew,2));
|
||||
}
|
||||
|
||||
ast rewrite_up(const ast &rew){
|
||||
return make(sym(rew),arg(arg(rew,0),1),arg(rew,1),arg(rew,2));
|
||||
}
|
||||
|
@ -1317,6 +1486,28 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
split_chain_rec(chain,res);
|
||||
}
|
||||
|
||||
ast extract_rewrites(const ast &chain, const ast &pos){
|
||||
if(is_true(chain))
|
||||
return chain;
|
||||
ast last = chain_last(chain);
|
||||
ast rest = chain_rest(chain);
|
||||
ast new_rest = extract_rewrites(rest,pos);
|
||||
ast p1 = rewrite_pos(last);
|
||||
ast diff;
|
||||
switch(pos_diff(p1,pos,diff)){
|
||||
case -1: {
|
||||
ast new_last = rewrite_pos_set(diff, last);
|
||||
return chain_cons(new_rest,new_last);
|
||||
}
|
||||
case 1:
|
||||
if(rewrite_lhs(last) != rewrite_rhs(last))
|
||||
throw "bad rewrite chain";
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
return new_rest;
|
||||
}
|
||||
|
||||
ast down_chain(const ast &chain){
|
||||
ast split[2];
|
||||
split_chain(chain,split);
|
||||
|
@ -1381,7 +1572,7 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
// ast s = ineq_to_lhs(ineq);
|
||||
// ast srhs = arg(s,1);
|
||||
ast srhs = arg(ineq,0);
|
||||
if(op(srhs) == Plus && num_args(srhs) == 2){
|
||||
if(op(srhs) == Plus && num_args(srhs) == 2 && arg(ineq,1) == make_int(rational(0))){
|
||||
lhs = arg(srhs,0);
|
||||
rhs = arg(srhs,1);
|
||||
// if(op(lhs) == Times)
|
||||
|
@ -1393,6 +1584,11 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if(op(ineq) == Leq || op(ineq) == Geq){
|
||||
lhs = srhs;
|
||||
rhs = arg(ineq,1);
|
||||
return;
|
||||
}
|
||||
throw "bad ineq";
|
||||
}
|
||||
|
||||
|
@ -1404,7 +1600,204 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return chain_cons(rest,last);
|
||||
}
|
||||
|
||||
ast apply_rewrite_chain(const ast &t, const ast &chain){
|
||||
if(is_true(chain))
|
||||
return t;
|
||||
ast last = chain_last(chain);
|
||||
ast rest = chain_rest(chain);
|
||||
ast mid = apply_rewrite_chain(t,rest);
|
||||
ast res = subst_in_pos(mid,rewrite_pos(last),rewrite_rhs(last));
|
||||
return res;
|
||||
}
|
||||
|
||||
ast drop_rewrites(LitType t, const ast &chain, ast &remainder){
|
||||
if(!is_true(chain)){
|
||||
ast last = chain_last(chain);
|
||||
ast rest = chain_rest(chain);
|
||||
if(is_rewrite_side(t,last)){
|
||||
ast res = drop_rewrites(t,rest,remainder);
|
||||
remainder = chain_cons(remainder,last);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
remainder = mk_true();
|
||||
return chain;
|
||||
}
|
||||
|
||||
// Normalization chains
|
||||
|
||||
ast cons_normal(const ast &first, const ast &rest){
|
||||
return make(normal_chain,first,rest);
|
||||
}
|
||||
|
||||
ast normal_first(const ast &t){
|
||||
return arg(t,0);
|
||||
}
|
||||
|
||||
ast normal_rest(const ast &t){
|
||||
return arg(t,1);
|
||||
}
|
||||
|
||||
ast normal_lhs(const ast &t){
|
||||
return arg(arg(t,0),0);
|
||||
}
|
||||
|
||||
ast normal_rhs(const ast &t){
|
||||
return arg(arg(t,0),1);
|
||||
}
|
||||
|
||||
ast normal_proof(const ast &t){
|
||||
return arg(t,1);
|
||||
}
|
||||
|
||||
ast make_normal_step(const ast &lhs, const ast &rhs, const ast &proof){
|
||||
return make(normal_step,make_equiv(lhs,rhs),proof);
|
||||
}
|
||||
|
||||
ast make_normal(const ast &ineq, const ast &nrml){
|
||||
if(!is_ineq(ineq))
|
||||
throw "what?";
|
||||
return make(normal,ineq,nrml);
|
||||
}
|
||||
|
||||
ast fix_normal(const ast &lhs, const ast &rhs, const ast &proof){
|
||||
LitType rhst = get_term_type(rhs);
|
||||
if(rhst != LitMixed || ast_id(lhs) < ast_id(rhs))
|
||||
return make_normal_step(lhs,rhs,proof);
|
||||
else
|
||||
return make_normal_step(rhs,lhs,reverse_chain(proof));
|
||||
}
|
||||
|
||||
ast chain_side_proves(LitType side, const ast &chain){
|
||||
LitType other_side = side == LitA ? LitB : LitA;
|
||||
return my_and(chain_conditions(other_side,chain),my_implies(chain_conditions(side,chain),chain_formulas(side,chain)));
|
||||
}
|
||||
|
||||
// Merge two normalization chains
|
||||
ast merge_normal_chains_rec(const ast &chain1, const ast &chain2, hash_map<ast,ast> &trans, ast &Aproves, ast &Bproves){
|
||||
if(is_true(chain1))
|
||||
return chain2;
|
||||
if(is_true(chain2))
|
||||
return chain1;
|
||||
ast f1 = normal_first(chain1);
|
||||
ast f2 = normal_first(chain2);
|
||||
ast lhs1 = normal_lhs(f1);
|
||||
ast lhs2 = normal_lhs(f2);
|
||||
int id1 = ast_id(lhs1);
|
||||
int id2 = ast_id(lhs2);
|
||||
if(id1 < id2) return cons_normal(f1,merge_normal_chains_rec(normal_rest(chain1),chain2,trans,Aproves,Bproves));
|
||||
if(id2 < id1) return cons_normal(f2,merge_normal_chains_rec(chain1,normal_rest(chain2),trans,Aproves,Bproves));
|
||||
ast rhs1 = normal_rhs(f1);
|
||||
ast rhs2 = normal_rhs(f2);
|
||||
LitType t1 = get_term_type(rhs1);
|
||||
LitType t2 = get_term_type(rhs2);
|
||||
int tid1 = ast_id(rhs1);
|
||||
int tid2 = ast_id(rhs2);
|
||||
ast pf1 = normal_proof(f1);
|
||||
ast pf2 = normal_proof(f2);
|
||||
ast new_normal;
|
||||
if(t1 == LitMixed && (t2 != LitMixed || tid2 > tid1)){
|
||||
ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2);
|
||||
new_normal = f2;
|
||||
trans[rhs1] = make_normal_step(rhs1,rhs2,new_proof);
|
||||
}
|
||||
else if(t2 == LitMixed && (t1 != LitMixed || tid1 > tid2))
|
||||
return merge_normal_chains_rec(chain2,chain1,trans,Aproves,Bproves);
|
||||
else if(t1 == LitA && t2 == LitB){
|
||||
ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2);
|
||||
ast Bproof, Aproof = drop_rewrites(LitB,new_proof,Bproof);
|
||||
ast mcA = chain_side_proves(LitB,Aproof);
|
||||
Bproves = my_and(Bproves,mcA);
|
||||
ast mcB = chain_side_proves(LitA,Bproof);
|
||||
Aproves = my_and(Aproves,mcB);
|
||||
ast rep = apply_rewrite_chain(rhs1,Aproof);
|
||||
new_proof = concat_rewrite_chain(pf1,Aproof);
|
||||
new_normal = make_normal_step(rhs1,rep,new_proof);
|
||||
}
|
||||
else if(t1 == LitA && t2 == LitB)
|
||||
return merge_normal_chains_rec(chain2,chain1,trans,Aproves,Bproves);
|
||||
else if(t1 == LitA) {
|
||||
ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2);
|
||||
ast mc = chain_side_proves(LitB,new_proof);
|
||||
Bproves = my_and(Bproves,mc);
|
||||
new_normal = f1; // choice is arbitrary
|
||||
}
|
||||
else { /* t1 = t2 = LitB */
|
||||
ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2);
|
||||
ast mc = chain_side_proves(LitA,new_proof);
|
||||
Aproves = my_and(Aproves,mc);
|
||||
new_normal = f1; // choice is arbitrary
|
||||
}
|
||||
return cons_normal(new_normal,merge_normal_chains_rec(normal_rest(chain1),normal_rest(chain2),trans,Aproves,Bproves));
|
||||
}
|
||||
|
||||
ast trans_normal_chain(const ast &chain, hash_map<ast,ast> &trans){
|
||||
if(is_true(chain))
|
||||
return chain;
|
||||
ast f = normal_first(chain);
|
||||
ast r = normal_rest(chain);
|
||||
ast rhs = normal_rhs(f);
|
||||
hash_map<ast,ast>::iterator it = trans.find(rhs);
|
||||
ast new_normal;
|
||||
if(it != trans.end()){
|
||||
const ast &f2 = it->second;
|
||||
ast pf = concat_rewrite_chain(normal_proof(f),normal_proof(f2));
|
||||
new_normal = make_normal_step(normal_lhs(f),normal_rhs(f2),pf);
|
||||
}
|
||||
else
|
||||
new_normal = f;
|
||||
return cons_normal(new_normal,trans_normal_chain(r,trans));
|
||||
}
|
||||
|
||||
ast merge_normal_chains(const ast &chain1, const ast &chain2, ast &Aproves, ast &Bproves){
|
||||
hash_map<ast,ast> trans;
|
||||
ast res = merge_normal_chains_rec(chain1,chain2,trans,Aproves,Bproves);
|
||||
res = trans_normal_chain(res,trans);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool destruct_cond_ineq(ast t, ast &Aproves, ast &Bproves, ast&ineq){
|
||||
if(op(t) == And){
|
||||
Aproves = arg(t,0);
|
||||
t = arg(t,1);
|
||||
}
|
||||
else
|
||||
Aproves = mk_true();
|
||||
if(op(t) == Implies){
|
||||
Bproves = arg(t,0);
|
||||
t = arg(t,1);
|
||||
}
|
||||
else
|
||||
Bproves = mk_true();
|
||||
if(is_normal_ineq(t)){
|
||||
ineq = t;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ast cons_cond_ineq(const ast &Aproves, const ast &Bproves, const ast &ineq){
|
||||
return my_and(Aproves,my_implies(Bproves,ineq));
|
||||
}
|
||||
|
||||
ast normalize(const ast &ct){
|
||||
ast Aproves,Bproves,t;
|
||||
if(!destruct_cond_ineq(ct,Aproves,Bproves,t))
|
||||
return ct;
|
||||
if(sym(t) != normal)
|
||||
return ct;
|
||||
ast chain = arg(t,1);
|
||||
hash_map<ast,ast> map;
|
||||
for(ast c = chain; !is_true(c); c = normal_rest(c)){
|
||||
ast first = normal_first(c);
|
||||
ast lhs = normal_lhs(first);
|
||||
ast rhs = normal_rhs(first);
|
||||
map[lhs] = rhs;
|
||||
}
|
||||
ast res = subst(map,arg(t,0));
|
||||
return cons_cond_ineq(Aproves,Bproves,res);
|
||||
}
|
||||
|
||||
/** Make an assumption node. The given clause is assumed in the given frame. */
|
||||
virtual node make_assumption(int frame, const std::vector<ast> &assumption){
|
||||
if(!weak){
|
||||
|
@ -1522,9 +1915,22 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return itp;
|
||||
}
|
||||
|
||||
ast capture_localization(ast e){
|
||||
// #define CAPTURE_LOCALIZATION
|
||||
#ifdef CAPTURE_LOCALIZATION
|
||||
for(int i = localization_vars.size() - 1; i >= 0; i--){
|
||||
LocVar &lv = localization_vars[i];
|
||||
if(occurs_in(lv.var,e)){
|
||||
symb q = (pv->in_range(lv.frame,rng)) ? sexists : sforall;
|
||||
e = make(q,make(Equal,lv.var,lv.term),e); // use Equal because it is polymorphic
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return e;
|
||||
}
|
||||
|
||||
/** Make an axiom node. The conclusion must be an instance of an axiom. */
|
||||
virtual node make_axiom(const std::vector<ast> &conclusion){
|
||||
prover::range frng = pv->range_full();
|
||||
virtual node make_axiom(const std::vector<ast> &conclusion, prover::range frng){
|
||||
int nargs = conclusion.size();
|
||||
std::vector<ast> largs(nargs);
|
||||
std::vector<ast> eqs;
|
||||
|
@ -1546,7 +1952,11 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
|
||||
for(unsigned i = 0; i < eqs.size(); i++)
|
||||
itp = make_mp(eqs[i],itp,pfs[i]);
|
||||
return itp;
|
||||
return capture_localization(itp);
|
||||
}
|
||||
|
||||
virtual node make_axiom(const std::vector<ast> &conclusion){
|
||||
return make_axiom(conclusion,pv->range_full());
|
||||
}
|
||||
|
||||
/** Make a Contra node. This rule takes a derivation of the form
|
||||
|
@ -1939,6 +2349,8 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
*/
|
||||
|
||||
ast make_refl(const ast &e){
|
||||
if(get_term_type(e) == LitA)
|
||||
return mk_false();
|
||||
return mk_true(); // TODO: is this right?
|
||||
}
|
||||
|
||||
|
@ -1972,7 +2384,8 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
int nargs = num_args(e);
|
||||
if(nargs > 0 /* && (!is_local(e) || flo <= hi || fhi >= lo) */){
|
||||
prover::range frng = rng;
|
||||
if(op(e) == Uninterpreted){
|
||||
opr o = op(e);
|
||||
if(o == Uninterpreted){
|
||||
symb f = sym(e);
|
||||
prover::range srng = pv->sym_range(f);
|
||||
if(pv->ranges_intersect(srng,rng)) // localize to desired range if possible
|
||||
|
@ -1980,6 +2393,9 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
else
|
||||
frng = srng; // this term will be localized
|
||||
}
|
||||
else if(o == Plus || o == Times){ // don't want bound variables inside arith ops
|
||||
frng = erng; // this term will be localized
|
||||
}
|
||||
std::vector<ast> largs(nargs);
|
||||
std::vector<ast> eqs;
|
||||
std::vector<ast> pfs;
|
||||
|
@ -2006,6 +2422,9 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
if(pv->ranges_intersect(pv->ast_scope(e),rng))
|
||||
return e; // this term occurs in range, so it's O.K.
|
||||
|
||||
if(is_array_type(get_type(e)))
|
||||
throw "help!";
|
||||
|
||||
// choose a frame for the constraint that is close to range
|
||||
int frame = pv->range_near(pv->ast_scope(e),rng);
|
||||
|
||||
|
@ -2018,12 +2437,89 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
return new_var;
|
||||
}
|
||||
|
||||
ast delete_quant(hash_map<ast,ast> &memo, const ast &v, const ast &e){
|
||||
std::pair<ast,ast> foo(e,ast());
|
||||
std::pair<hash_map<ast,ast>::iterator,bool> bar = memo.insert(foo);
|
||||
ast &res = bar.first->second;
|
||||
if(bar.second){
|
||||
opr o = op(e);
|
||||
switch(o){
|
||||
case Or:
|
||||
case And:
|
||||
case Implies: {
|
||||
unsigned nargs = num_args(e);
|
||||
std::vector<ast> args; args.resize(nargs);
|
||||
for(unsigned i = 0; i < nargs; i++)
|
||||
args[i] = delete_quant(memo, v, arg(e,i));
|
||||
res = make(o,args);
|
||||
break;
|
||||
}
|
||||
case Uninterpreted: {
|
||||
symb s = sym(e);
|
||||
ast w = arg(arg(e,0),0);
|
||||
if(s == sforall || s == sexists){
|
||||
res = delete_quant(memo,v,arg(e,1));
|
||||
if(w != v)
|
||||
res = make(s,w,res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
res = e;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ast insert_quants(hash_map<ast,ast> &memo, const ast &e){
|
||||
std::pair<ast,ast> foo(e,ast());
|
||||
std::pair<hash_map<ast,ast>::iterator,bool> bar = memo.insert(foo);
|
||||
ast &res = bar.first->second;
|
||||
if(bar.second){
|
||||
opr o = op(e);
|
||||
switch(o){
|
||||
case Or:
|
||||
case And:
|
||||
case Implies: {
|
||||
unsigned nargs = num_args(e);
|
||||
std::vector<ast> args; args.resize(nargs);
|
||||
for(unsigned i = 0; i < nargs; i++)
|
||||
args[i] = insert_quants(memo, arg(e,i));
|
||||
res = make(o,args);
|
||||
break;
|
||||
}
|
||||
case Uninterpreted: {
|
||||
symb s = sym(e);
|
||||
if(s == sforall || s == sexists){
|
||||
opr q = (s == sforall) ? Forall : Exists;
|
||||
ast v = arg(arg(e,0),0);
|
||||
hash_map<ast,ast> dmemo;
|
||||
ast body = delete_quant(dmemo,v,arg(e,1));
|
||||
body = insert_quants(memo,body);
|
||||
res = apply_quant(q,v,body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
res = e;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ast add_quants(ast e){
|
||||
#ifdef CAPTURE_LOCALIZATION
|
||||
if(!localization_vars.empty()){
|
||||
hash_map<ast,ast> memo;
|
||||
e = insert_quants(memo,e);
|
||||
}
|
||||
#else
|
||||
for(int i = localization_vars.size() - 1; i >= 0; i--){
|
||||
LocVar &lv = localization_vars[i];
|
||||
opr quantifier = (pv->in_range(lv.frame,rng)) ? Exists : Forall;
|
||||
e = apply_quant(quantifier,lv.var,e);
|
||||
}
|
||||
#endif
|
||||
return e;
|
||||
}
|
||||
|
||||
|
@ -2035,7 +2531,11 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
/* Return an interpolant from a proof of false */
|
||||
ast interpolate(const node &pf){
|
||||
// proof of false must be a formula, with quantified symbols
|
||||
#ifndef BOGUS_QUANTS
|
||||
return add_quants(z3_simplify(pf));
|
||||
#else
|
||||
return z3_simplify(pf);
|
||||
#endif
|
||||
}
|
||||
|
||||
ast resolve_with_quantifier(const ast &pivot1, const ast &conj1,
|
||||
|
@ -2055,7 +2555,7 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
ast npP = make_mp(make(Iff,nPloc,nP),npPloc,neqpf);
|
||||
ast nrP = make_resolution(nP,conj2,npP);
|
||||
ast res = make_resolution(Ploc,rP,nrP);
|
||||
return res;
|
||||
return capture_localization(res);
|
||||
}
|
||||
|
||||
ast get_contra_coeff(const ast &f){
|
||||
|
@ -2141,6 +2641,16 @@ public:
|
|||
m().inc_ref(rewrite_A);
|
||||
rewrite_B = function("@rewrite_B",3,boolboolbooldom,bool_type());
|
||||
m().inc_ref(rewrite_B);
|
||||
normal_step = function("@normal_step",2,boolbooldom,bool_type());
|
||||
m().inc_ref(normal_step);
|
||||
normal_chain = function("@normal_chain",2,boolbooldom,bool_type());
|
||||
m().inc_ref(normal_chain);
|
||||
normal = function("@normal",2,boolbooldom,bool_type());
|
||||
m().inc_ref(normal);
|
||||
sforall = function("@sforall",2,boolbooldom,bool_type());
|
||||
m().inc_ref(sforall);
|
||||
sexists = function("@sexists",2,boolbooldom,bool_type());
|
||||
m().inc_ref(sexists);
|
||||
}
|
||||
|
||||
~iz3proof_itp_impl(){
|
||||
|
|
|
@ -70,6 +70,9 @@ class iz3proof_itp : public iz3mgr {
|
|||
/** Make an axiom node. The conclusion must be an instance of an axiom. */
|
||||
virtual node make_axiom(const std::vector<ast> &conclusion) = 0;
|
||||
|
||||
/** Make an axiom node. The conclusion must be an instance of an axiom. Localize axiom instance to range*/
|
||||
virtual node make_axiom(const std::vector<ast> &conclusion, prover::range) = 0;
|
||||
|
||||
/** Make a Contra node. This rule takes a derivation of the form
|
||||
Gamma |- False and produces |- \/~Gamma. */
|
||||
|
||||
|
|
|
@ -109,36 +109,49 @@ public:
|
|||
symbols and assign each to a frame. THe assignment is heuristic.
|
||||
*/
|
||||
|
||||
void scan_skolems_rec(hash_set<ast> &memo, const ast &proof){
|
||||
std::pair<hash_set<ast>::iterator,bool> bar = memo.insert(proof);
|
||||
if(!bar.second)
|
||||
return;
|
||||
int scan_skolems_rec(hash_map<ast,int> &memo, const ast &proof, int frame){
|
||||
std::pair<ast,int> foo(proof,INT_MAX);
|
||||
std::pair<AstToInt::iterator, bool> bar = memo.insert(foo);
|
||||
int &res = bar.first->second;
|
||||
if(!bar.second) return res;
|
||||
pfrule dk = pr(proof);
|
||||
if(dk == PR_SKOLEMIZE){
|
||||
if(dk == PR_ASSERTED){
|
||||
ast ass = conc(proof);
|
||||
res = frame_of_assertion(ass);
|
||||
}
|
||||
else if(dk == PR_SKOLEMIZE){
|
||||
ast quanted = arg(conc(proof),0);
|
||||
if(op(quanted) == Not)
|
||||
quanted = arg(quanted,0);
|
||||
range r = ast_range(quanted);
|
||||
if(range_is_empty(r))
|
||||
r = ast_scope(quanted);
|
||||
// range r = ast_range(quanted);
|
||||
// if(range_is_empty(r))
|
||||
range r = ast_scope(quanted);
|
||||
if(range_is_empty(r))
|
||||
throw "can't skolemize";
|
||||
int frame = range_max(r);
|
||||
if(frame == INT_MAX || !in_range(frame,r))
|
||||
frame = range_max(r); // this is desperation -- may fail
|
||||
if(frame >= frames) frame = frames - 1;
|
||||
add_frame_range(frame,arg(conc(proof),1));
|
||||
r = ast_scope(arg(conc(proof),1));
|
||||
}
|
||||
else if(dk==PR_MODUS_PONENS_OEQ){
|
||||
frame = scan_skolems_rec(memo,prem(proof,0),frame);
|
||||
scan_skolems_rec(memo,prem(proof,1),frame);
|
||||
}
|
||||
else {
|
||||
unsigned nprems = num_prems(proof);
|
||||
for(unsigned i = 0; i < nprems; i++){
|
||||
scan_skolems_rec(memo,prem(proof,i));
|
||||
int bar = scan_skolems_rec(memo,prem(proof,i),frame);
|
||||
if(res == INT_MAX || res == bar) res = bar;
|
||||
else if(bar != INT_MAX) res = -1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void scan_skolems(const ast &proof){
|
||||
hash_set<ast> memo;
|
||||
scan_skolems_rec(memo,proof);
|
||||
hash_map<ast,int> memo;
|
||||
scan_skolems_rec(memo,proof, INT_MAX);
|
||||
}
|
||||
|
||||
// determine locality of a proof term
|
||||
|
@ -1364,6 +1377,18 @@ public:
|
|||
return eq2;
|
||||
}
|
||||
|
||||
bool get_store_array(const ast &t, ast &res){
|
||||
if(op(t) == Store){
|
||||
res = t;
|
||||
return true;
|
||||
}
|
||||
int nargs = num_args(t);
|
||||
for(int i = 0; i < nargs; i++)
|
||||
if(get_store_array(arg(t,i),res))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// translate a Z3 proof term into interpolating proof system
|
||||
|
||||
Iproof::node translate_main(ast proof, bool expect_clause = true){
|
||||
|
@ -1448,6 +1473,21 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/* this is the symmetry rule for ~=, that is, takes x ~= y and yields y ~= x.
|
||||
the proof idiom uses commutativity, monotonicity and mp, but we replace it here
|
||||
with symmtrey and resolution, that is, we prove y = x |- x = y, then resolve
|
||||
with the proof of ~(x=y) to get ~y=x. */
|
||||
if(dk == PR_MODUS_PONENS && pr(prem(proof,1)) == PR_MONOTONICITY && pr(prem(prem(proof,1),0)) == PR_COMMUTATIVITY && num_prems(prem(proof,1)) == 1){
|
||||
Iproof::node ante = translate_main(prem(proof,0),false);
|
||||
ast eq0 = arg(conc(prem(prem(proof,1),0)),0);
|
||||
ast eq1 = arg(conc(prem(prem(proof,1),0)),1);
|
||||
Iproof::node eq1hy = iproof->make_hypothesis(eq1);
|
||||
Iproof::node eq0pf = iproof->make_symmetry(eq0,eq1,eq1hy);
|
||||
std::vector<ast> clause; // just a dummy
|
||||
res = iproof->make_resolution(eq0,clause,ante,eq0pf);
|
||||
return res;
|
||||
}
|
||||
|
||||
// translate all the premises
|
||||
std::vector<Iproof::node> args(nprems);
|
||||
for(unsigned i = 0; i < nprems; i++)
|
||||
|
@ -1578,9 +1618,13 @@ public:
|
|||
throw unsupported();
|
||||
}
|
||||
break;
|
||||
case ArrayTheory: // nothing fancy for this
|
||||
res = iproof->make_axiom(lits);
|
||||
case ArrayTheory: {// nothing fancy for this
|
||||
ast store_array;
|
||||
if(!get_store_array(con,store_array))
|
||||
throw unsupported();
|
||||
res = iproof->make_axiom(lits,ast_scope(store_array));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw unsupported();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,24 @@ Revision History:
|
|||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
/* This can introduce an address dependency if the range type of hash_map has
|
||||
a destructor. Since the code in this file is not used and only here for
|
||||
historical comparisons, we allow this non-determinism.
|
||||
*/
|
||||
namespace stl_ext {
|
||||
template <class T>
|
||||
class hash<T *> {
|
||||
public:
|
||||
size_t operator()(const T *p) const {
|
||||
return (size_t) p;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static int lemma_count = 0;
|
||||
static int nll_lemma_count = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue