diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp index e202f1f69..2a7de3176 100644 --- a/src/cmd_context/interpolant_cmds.cpp +++ b/src/cmd_context/interpolant_cmds.cpp @@ -31,6 +31,8 @@ Notes: #include"pp_params.hpp" #include"iz3interp.h" #include"iz3checker.h" +#include"iz3profiling.h" +#include"interp_params.hpp" static void show_interpolant_and_maybe_check(cmd_context & ctx, ptr_vector &cnsts, @@ -82,6 +84,10 @@ static void show_interpolant_and_maybe_check(cmd_context & ctx, ctx.m().dec_ref(interps[i]); } + interp_params itp_params(m_params); + if(itp_params.profile()) + profiling::print(ctx.regular_stream()); + } static void check_can_interpolate(cmd_context & ctx){ diff --git a/src/interp/iz3checker.cpp b/src/interp/iz3checker.cpp index b30e52d38..7792c2401 100755 --- a/src/interp/iz3checker.cpp +++ b/src/interp/iz3checker.cpp @@ -96,6 +96,19 @@ struct iz3checker : iz3base { lbool result = s->check_sat(0,0); if(result != l_false){ err << "interpolant " << i << " is incorrect"; + + s->pop(1); + for(unsigned j = 0; j < theory.size(); j++) + s->assert_expr(to_expr(theory[j].raw())); + for(unsigned j = 0; j < cnsts.size(); j++) + if(in_range(j,range_downward(i))) + s->assert_expr(to_expr(cnsts[j].raw())); + if(i != num-1) + s->assert_expr(to_expr(mk_not(itp[i]).raw())); + lbool result = s->check_sat(0,0); + if(result != l_false) + err << "interpolant " << i << " is not implied by its downeard closurn"; + return false; } s->pop(1); diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp index ac6970231..6767deacf 100755 --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -391,7 +391,9 @@ lbool iz3interpolate(ast_manager &_m_manager, iz3mgr::ast _tree = itp.cook(tree); std::vector _cnsts; itp.assert_conjuncts(s,_cnsts,_tree); + profiling::timer_start("solving"); lbool res = s.check_sat(0,0); + profiling::timer_stop("solving"); if(res == l_false){ ast *proof = s.get_proof(); iz3mgr::ast _proof = itp.cook(proof); diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp index 1b91fd521..bd82d235a 100644 --- a/src/interp/iz3mgr.cpp +++ b/src/interp/iz3mgr.cpp @@ -536,6 +536,56 @@ void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector& r } rats[i-1] = r; } + 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]; + } + } + extract_lcd(rats); +} + +void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector& coeffs){ + std::vector 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& 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(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]; + } + } extract_lcd(rats); } diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index a648c3f84..213c23e7e 100644 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -413,6 +413,10 @@ class iz3mgr { void get_assign_bounds_coeffs(const ast &proof, std::vector& rats); + void get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats); + + void get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats); + bool is_true(ast t){ return op(t) == True; } diff --git a/src/interp/iz3profiling.cpp b/src/interp/iz3profiling.cpp index f18866f30..262254271 100755 --- a/src/interp/iz3profiling.cpp +++ b/src/interp/iz3profiling.cpp @@ -24,18 +24,26 @@ Revision History: #include #include #include +#include "stopwatch.h" // FIXME fill in these stubs -#define clock_t int +#define clock_t double -static clock_t current_time(){ - return 0; +static double current_time() +{ + static stopwatch sw; + static bool started = false; + if(!started){ + sw.start(); + started = true; + } + return sw.get_current_seconds(); } static void output_time(std::ostream &os, clock_t time){ - os << ((double)time)/1000; + os << time; } diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index d786f95ab..3bf4dd620 100644 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -23,6 +23,7 @@ Revision History: using namespace stl_ext; #endif +// #define INVARIANT_CHECKING class iz3proof_itp_impl : public iz3proof_itp { @@ -124,11 +125,13 @@ class iz3proof_itp_impl : public iz3proof_itp { return it->second; ast &res = placeholders[t]; res = mk_fresh_constant("@p",get_type(t)); +#if 0 std::cout << "placeholder "; print_expr(std::cout,res); std::cout << " = "; print_expr(std::cout,t); std::cout << std::endl; +#endif return res; } @@ -188,62 +191,15 @@ class iz3proof_itp_impl : public iz3proof_itp { /* the mixed case is a bit complicated */ - return resolve_arith(pivot,conc,premise1,premise2); - } - -#if 0 - /* Handles the case of resolution on a mixed equality atom. */ - - ast resolve_equality(const ast &pivot, const std::vector &conc, node premise1, node premise2){ - ast atom = get_lit_atom(pivot); - - /* Get the A term in the mixed equality. */ - ast A_term = arg(atom,0); - if(get_term_type(A_term) != LitA) - A_term = arg(atom,1); - - /* Resolve it out. */ - hash_map memo; - // ast neg_pivot_placeholder = get_placeholder(mk_not(atom)); - ast neg_pivot_placeholder = mk_not(atom); - ast A_term_placeholder = get_placeholder(atom); - if(op(pivot) != Not) - std::swap(premise1,premise2); - return resolve_equality_rec(memo, neg_pivot_placeholder, premise1, A_term_placeholder, premise2); - } - - ast resolve_equality_rec(hash_map &memo, const ast &neg_pivot_placeholder, const ast &premise1, - const ast &A_term, const ast &premise2){ - ast &res = memo[premise1]; - if(!res.null()) - return res; - - if(op(premise1) == And - && num_args(premise1) == 2 - && arg(premise1,1) == neg_pivot_placeholder){ - ast common_term = arg(arg(premise1,0),1); - res = subst_term_and_simp(A_term,common_term,premise2); - } - else { - switch(op(premise1)){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(premise1); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = resolve_equality_rec(memo, neg_pivot_placeholder, arg(premise1,i), A_term, premise2); - ast foo = premise1; // get rid of const - res = clone(foo,args); - break; - } - default: - res = premise1; - } - } + static int non_local_count = 0; + ast res = resolve_arith(pivot,conc,premise1,premise2); +#ifdef INVARIANT_CHECKING + check_contra(conc,res); +#endif + non_local_count++; return res; } -#endif + /* Handles the case of resolution on a mixed arith atom. */ @@ -285,25 +241,6 @@ class iz3proof_itp_impl : public iz3proof_itp { return make(sum_op,sum_sides[0],sum_sides[1]); } -#if 0 - ast resolve_farkas(const ast &pivot1, const ast &conj1, const ast &implicant1, - const ast &pivot2, const ast &conj2, const ast &implicant2){ - std::vector resolvent; - ast coeff1 = get_farkas_coeff(pivot1); - ast coeff2 = get_farkas_coeff(pivot2); - ast s1 = resolve_arith_placeholders(pivot2,conj2,arg(conj1,0)); - ast s2 = resolve_arith_placeholders(pivot1,conj1,arg(conj2,0)); - resolvent.push_back(sum_ineq(coeff2,s1,coeff1,s2)); - collect_farkas_resolvents(pivot1,coeff2,conj1,resolvent); - collect_farkas_resolvents(pivot2,coeff1,conj2,resolvent); - ast res = make(And,resolvent); - if(implicant1.null() && implicant2.null()) - return res; - ast i1 = implicant1.null() ? mk_false() : resolve_arith_placeholders(pivot2,conj2,implicant1); - ast i2 = implicant2.null() ? mk_false() : resolve_arith_placeholders(pivot1,conj1,implicant2); - return make(Implies,res,my_or(i1,i2)); - } -#endif void collect_contra_resolvents(int from, const ast &pivot1, const ast &pivot, const ast &conj, std::vector &res){ int nargs = num_args(conj); @@ -349,14 +286,6 @@ class iz3proof_itp_impl : public iz3proof_itp { ast resolve_contra(const ast &pivot1, const ast &conj1, const ast &pivot2, const ast &conj2){ -#if 0 - int nargs = num_args(conj1); - for(int i = 0; i < nargs; i++){ - ast foo = arg(conj1,i); - if(!(foo == pivot1) && is_negative_equality(arg(foo,1))) - return resolve_contra_nf(pivot2, conj2, pivot1, conj1); - } -#endif if(arg(pivot1,0) != no_proof) return resolve_contra_nf(pivot1, conj1, pivot2, conj2); if(arg(pivot2,0) != no_proof) @@ -410,6 +339,7 @@ class iz3proof_itp_impl : public iz3proof_itp { return res; } + ast resolve_arith_rec1(hash_map &memo, const ast &neg_pivot_lit, const ast &itp1, const ast &itp2){ ast &res = memo[itp1]; if(!res.null()) @@ -439,26 +369,40 @@ class iz3proof_itp_impl : public iz3proof_itp { return res; } -#if 0 - ast resolve_arith_placeholders(const ast &pivot1, const ast &conj1, const ast &itp2){ - ast coeff = arg(pivot1,0); - ast val = arg(arg(conj1,0),1); - if(op(conj1)==Lt) - val = make(Sub,val,epsilon); // represent x < c by x <= c - epsilon - coeff = z3_simplify(coeff); - ast soln = mk_idiv(val,coeff); - int nargs = num_args(conj1); - for(int i = 1; i < nargs; i++){ - ast c = arg(conj1,i); - if(!(c == pivot1)){ - soln = make(Plus,soln,get_placeholder(arg(c,1))); + void check_contra(hash_set &memo, hash_set &neg_lits, const ast &foo){ + if(memo.find(foo) != memo.end()) + return; + memo.insert(foo); + if(op(foo) == Uninterpreted && sym(foo) == contra){ + ast neg_lit = arg(foo,1); + if(!is_false(neg_lit) && neg_lits.find(neg_lit) == neg_lits.end()) + throw "lost a literal"; + return; + } + else { + switch(op(foo)){ + case Or: + case And: + case Implies: { + unsigned nargs = num_args(foo); + std::vector args; args.resize(nargs); + for(unsigned i = 0; i < nargs; i++) + check_contra(memo, neg_lits, arg(foo,i)); + break; + } + default: break; } } - ast pl = get_placeholder(mk_not(arg(pivot1,1))); - ast res = subst_term_and_simp(pl,soln,itp2); - return res; } -#endif + + void check_contra(const std::vector &neg_lits, const ast &foo){ + hash_set memo; + hash_set neg_lits_set; + for(unsigned i = 0; i < neg_lits.size(); i++) + if(get_term_type(neg_lits[i]) == LitMixed) + neg_lits_set.insert(mk_not(neg_lits[i])); + check_contra(memo,neg_lits_set,foo); + } hash_map subst_memo; // memo of subst function @@ -681,7 +625,8 @@ class iz3proof_itp_impl : public iz3proof_itp { ast cond = mk_true(); ast equa = sep_cond(arg(pf,0),cond); if(is_equivrel_chain(equa)){ - ast ineqs= chain_ineqs(LitA,equa); + ast lhs,rhs; eq_from_ineq(arg(neg_equality,0),lhs,rhs); // get inequality we need to prove + ast ineqs= chain_ineqs(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) @@ -748,97 +693,63 @@ class iz3proof_itp_impl : public iz3proof_itp { throw cannot_simplify(); } -#if 0 - ast simplify_modpon(const std::vector &args){ - if(op(args[1]) == True){ - ast cond = mk_true(); - ast P = sep_cond(args[0],cond); - ast notQ = sep_cond(args[2],cond); - ast Q = mk_not(notQ); - ast d = op(notQ) == True ? P : op(P) == True ? notQ : mk_not(delta(P,Q)); - return my_implies(cond,d); - } - else { - ast cond = mk_true(); - ast P = sep_cond(args[0],cond); - ast PeqQ = sep_cond(args[1],cond); - ast Q2 = sep_cond(args[2],cond); - ast P1 = arg(PeqQ,0); - ast Q1 = arg(PeqQ,1); - if(op(P) == True){ - if(is_equivrel(P1) && is_equivrel(Q1)){ // special case of transitivity - if(arg(P1,0) == arg(Q1,0)) - if(op(args[2]) == True) - return my_implies(cond,make(op(P1),arg(P1,1),arg(Q1,1))); - } - if(op(args[2]) == True) - throw cannot_simplify(); // return my_implies(cond,make(rewrite(P1,Q1))); - ast A_rewrites = mk_true(); - ast foo = commute_rewrites(P1,Q1,mk_not(Q2),A_rewrites); - return my_implies(cond,my_implies(my_implies(A_rewrites,foo),mk_false())); - } - else if(op(args[2]) == True){ - ast P2 = apply_common_rewrites(P,P,P1,cond); - ast A_rewrites = mk_true(); - if(is_equivrel(P2)){ - try { - ast foo = commute_rewrites(arg(P2,0),arg(P2,1),arg(Q1,1),A_rewrites); - ast P3 = make(op(P1),arg(P1,0),foo); - if(P3 == P2) - return my_implies(cond,Q1); - // return my_implies(cond,make(rewrite,my_implies(A_rewrites,P3),Q1)); - } - catch(const rewrites_failed &){ - std::cout << "foo!\n"; - } - } - ast Q2 = apply_all_rewrites(P2,P1,Q1); - return my_implies(cond,Q2); - } - } - throw cannot_simplify(); - } -#else ast simplify_modpon_fwd(const std::vector &args, ast &cond){ ast P = sep_cond(args[0],cond); ast PeqQ = sep_cond(args[1],cond); ast chain; if(is_equivrel_chain(P)){ - ast split[2]; - split_chain(PeqQ,split); - chain = reverse_chain(split[0]); - chain = concat_rewrite_chain(chain,P); - chain = concat_rewrite_chain(chain,split[1]); + try { + ast split[2]; + split_chain(PeqQ,split); + chain = reverse_chain(split[0]); + chain = concat_rewrite_chain(chain,P); + chain = concat_rewrite_chain(chain,split[1]); + } + catch(const cannot_split &){ + static int this_count = 0; + this_count++; + ast tail, pref = get_head_chain(PeqQ,tail,false); // pref is x=y, tail is x=y -> x'=y' + ast split[2]; split_chain(tail,split); // rewrites from x to x' and y to y' + ast head = chain_last(pref); + ast prem = make_rewrite(rewrite_side(head),top_pos,rewrite_cond(head),make(Iff,mk_true(),mk_not(rewrite_lhs(head)))); + ast back_chain = chain_cons(mk_true(),prem); + back_chain = concat_rewrite_chain(back_chain,chain_pos_add(0,reverse_chain(chain_rest(pref)))); + ast cond = contra_chain(back_chain,P); + if(is_rewrite_side(LitA,head)) + cond = mk_not(cond); + ast fwd_rewrite = make_rewrite(rewrite_side(head),top_pos,cond,rewrite_rhs(head)); + P = chain_cons(mk_true(),fwd_rewrite); + chain = reverse_chain(split[0]); + chain = concat_rewrite_chain(chain,P); + chain = concat_rewrite_chain(chain,split[1]); + } } - else // if not an equavalence, 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; } -#if 0 - ast simplify_modpon(const std::vector &args){ - ast cond = mk_true(); - ast chain = simplify_modpon_fwd(args,cond); - ast Q2 = sep_cond(args[2],cond); - ast interp; - if(is_equivrel_chain(Q2)){ - chain = concat_rewrite_chain(chain,chain_pos_add(0,chain_pos_add(0,Q2))); - interp = my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); - } - else if(is_rewrite_side(LitB,chain_last(Q2))) - interp = my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); - else - interp = my_and(chain_conditions(LitB,chain),my_implies(chain_conditions(LitA,chain),mk_not(chain_formulas(LitB,chain)))); - return my_implies(cond,interp); - } -#endif - /* 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) if(is_equivrel_chain(pos_chain)){ - ast chain = concat_rewrite_chain(neg_chain,chain_pos_add(0,chain_pos_add(0,pos_chain))); - return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); + ast tail, pref = get_head_chain(neg_chain,tail); // pref is not(x=y), tail is not(x,y) -> not(x',y') + ast split[2]; split_chain(down_chain(tail),split); // rewrites from x to x' and y to y' + ast chain = split[0]; + chain = concat_rewrite_chain(chain,pos_chain); // rewrites from x to y' + chain = concat_rewrite_chain(chain,reverse_chain(split[1])); // rewrites from x to y + chain = concat_rewrite_chain(pref,chain_pos_add(0,chain_pos_add(0,chain))); // rewrites t -> not(y=y) + ast head = chain_last(pref); + if(is_rewrite_side(LitB,head)){ + ast condition = chain_conditions(LitB,chain); + return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),condition); + } + else { + ast condition = chain_conditions(LitA,chain); + return my_and(chain_conditions(LitB,chain),my_implies(condition,mk_not(chain_formulas(LitB,chain)))); + } + // ast chain = concat_rewrite_chain(neg_chain,chain_pos_add(0,chain_pos_add(0,pos_chain))); + // return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); } // otherwise, we reverse the derivation of t = P and use it to rewrite not(P) to not(t) ast chain = concat_rewrite_chain(neg_chain,chain_pos_add(0,reverse_chain(pos_chain))); @@ -853,7 +764,6 @@ class iz3proof_itp_impl : public iz3proof_itp { return my_implies(cond,interp); } -#endif bool is_equivrel(const ast &p){ opr o = op(p); @@ -1115,9 +1025,24 @@ class iz3proof_itp_impl : public iz3proof_itp { throw "bad term position!"; } + ast diff_chain(LitType t, const ast &pos, const ast &x, const ast &y, const ast &prefix){ + int nargs = num_args(x); + if(x == y) return prefix; + if(sym(x) == sym(y) && nargs == num_args(y)){ + ast res = prefix; + for(int i = 0; i < nargs; i++) + res = diff_chain(t,pos_add(i,pos),arg(x,i),arg(y,i),res); + return res; + } + return chain_cons(prefix,make_rewrite(t,pos,mk_true(),make_equiv_rel(x,y))); + } /* operations on rewrites */ ast make_rewrite(LitType t, const ast &pos, const ast &cond, const ast &equality){ +#if 0 + if(pos == top_pos && op(equality) == Iff && !is_true(arg(equality,0))) + throw "bad rewrite"; +#endif return make(t == LitA ? rewrite_A : rewrite_B, pos, cond, equality); } @@ -1189,6 +1114,10 @@ class iz3proof_itp_impl : public iz3proof_itp { return sym(rew) == rewrite_B; } + LitType rewrite_side(const ast &rew){ + return (sym(rew) == rewrite_A) ? LitA : LitB; + } + ast rewrite_to_formula(const ast &rew){ return my_implies(arg(rew,1),arg(rew,2)); } @@ -1312,6 +1241,24 @@ class iz3proof_itp_impl : public iz3proof_itp { return is_negation_chain(rest); } + // split a rewrite chain into head and tail at last top-level rewrite + ast get_head_chain(const ast &chain, ast &tail, bool is_not = true){ + ast last = chain_last(chain); + ast rest = chain_rest(chain); + ast pos = rewrite_pos(last); + if(pos == top_pos || (is_not && arg(pos,1) == top_pos)){ + tail = mk_true(); + return chain; + } + if(is_true(rest)) + throw "bad rewrite chain"; + ast head = get_head_chain(rest,tail,is_not); + tail = chain_cons(tail,last); + return head; + } + + struct cannot_split {}; + /** Split a chain of rewrites two chains, operating on positions 0 and 1. Fail if any rewrite in the chain operates on top position. */ void split_chain_rec(const ast &chain, ast *res){ @@ -1321,11 +1268,14 @@ class iz3proof_itp_impl : public iz3proof_itp { ast rest = chain_rest(chain); split_chain_rec(rest,res); ast pos = rewrite_pos(last); - if(pos == top_pos) - throw "bad rewrite chain"; + if(pos == top_pos){ + if(rewrite_lhs(last) == rewrite_rhs(last)) + return; // skip if it's a noop + throw cannot_split(); + } int arg = pos_arg(pos); if(arg<0 || arg > 1) - throw "bad position!"; + throw cannot_split(); res[arg] = chain_cons(res[arg],rewrite_up(last)); } @@ -1334,6 +1284,12 @@ class iz3proof_itp_impl : public iz3proof_itp { split_chain_rec(chain,res); } + ast down_chain(const ast &chain){ + ast split[2]; + split_chain(chain,split); + return split[0]; + } + ast chain_conditions(LitType t, const ast &chain){ if(is_true(chain)) return mk_true(); @@ -1356,19 +1312,51 @@ class iz3proof_itp_impl : public iz3proof_itp { return cond; } - ast chain_ineqs(LitType t, const ast &chain){ - if(is_true(chain)) - return mk_true(); + + ast chain_ineqs(LitType t, const ast &chain, const ast &lhs, const ast &rhs){ + if(is_true(chain)){ + if(lhs != rhs) + throw "bad ineq inference"; + return make(Leq,make_int(rational(0)),make_int(rational(0))); + } ast last = chain_last(chain); ast rest = chain_rest(chain); - ast cond = chain_ineqs(t,rest); + ast mid = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last)); + ast cond = chain_ineqs(t,rest,lhs,mid); if(is_rewrite_side(t,last)){ - ast equa = rewrite_equ(last); - cond = my_and(cond,z3_simplify(make(Leq,make_int("0"),make(Sub,arg(equa,1),arg(equa,0))))); + ast foo = z3_simplify(make(Leq,make_int("0"),make(Sub,mid,rhs))); + if(is_true(cond)) + cond = foo; + else { + linear_comb(cond,make_int(rational(1)),foo); + cond = simplify_ineq(cond); + } } return cond; } + ast ineq_to_lhs(const ast &ineq){ + ast s = make(Leq,make_int(rational(0)),make_int(rational(0))); + linear_comb(s,make_int(rational(1)),ineq); + return simplify_ineq(s); + } + + void eq_from_ineq(const ast &ineq, ast &lhs, ast &rhs){ + ast s = ineq_to_lhs(ineq); + ast srhs = arg(s,1); + if(op(srhs) == Plus && num_args(srhs) == 2){ + lhs = arg(srhs,0); + rhs = arg(srhs,1); + if(op(lhs) == Times) + std::swap(lhs,rhs); + if(op(rhs) == Times){ + rhs = arg(rhs,1); + return; + } + } + throw "bad ineq"; + } + ast chain_pos_add(int arg, const ast &chain){ if(is_true(chain)) return mk_true(); @@ -1395,6 +1383,10 @@ class iz3proof_itp_impl : public iz3proof_itp { ast make_local_rewrite(LitType t, const ast &p){ ast rew = is_equivrel(p) ? p : make(Iff,mk_true(),p); +#if 0 + if(op(rew) == Iff && !is_true(arg(rew,0))) + return diff_chain(t,top_pos,arg(rew,0),arg(rew,1), mk_true()); +#endif return chain_cons(mk_true(),make_rewrite(t, top_pos, mk_true(), rew)); } @@ -1466,7 +1458,7 @@ class iz3proof_itp_impl : public iz3proof_itp { } /* Resolve it with the premises */ - std::vector conc; conc.push_back(q); conc.push_back(mk_not(make(Equal,p,q))); + std::vector conc; conc.push_back(q); conc.push_back(mk_not(p_eq_q)); itp = make_resolution(p,conc,itp,prem1); conc.pop_back(); itp = make_resolution(p_eq_q,conc,itp,prem2); @@ -1555,8 +1547,6 @@ class iz3proof_itp_impl : public iz3proof_itp { ast x = arg(con,0); ast y = arg(con,1); ast p = make(op(con),y,x); - if(p == premcon) - std::cout << "ok\n"; if(get_term_type(con) != LitMixed) return prem; // symmetry shmymmetry... #if 0 @@ -1581,82 +1571,27 @@ class iz3proof_itp_impl : public iz3proof_itp { return itp; } + ast make_equiv_rel(const ast &x, const ast &y){ + if(is_bool_type(get_type(x))) + return make(Iff,x,y); + return make(Equal,x,y); + } + /** Make a transitivity node. This takes derivations of |- x = y and |- y = z produces | x = z */ virtual node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2){ /* Interpolate the axiom x=y,y=z,-> x=z */ - ast p = make(Equal,x,y); - ast q = make(Equal,y,z); - ast r = make(Equal,x,z); + ast p = make_equiv_rel(x,y); + ast q = make_equiv_rel(y,z); + ast r = make_equiv_rel(x,z); ast equiv = make(Iff,p,r); ast itp; itp = make_congruence(q,equiv,prem2); itp = make_mp(equiv,prem1,itp); -#if 0 - if(get_term_type(p) == LitA){ - if(get_term_type(q) == LitA){ - if(get_term_type(r) == LitA) - itp = mk_false(); - else - itp = r; - } - else { - if(get_term_type(r) == LitA) - itp = mk_not(q); - else { - if(get_term_type(r) == LitB) - itp = make(Equal,x,get_placeholder(q)); - else { - ast mid = (get_term_type(y) == LitA) ? get_placeholder(q) : y; - itp = make(And,make(Equal,x,mid),mk_not(r)); - } - } - } - } - else { - if(get_term_type(q) == LitA){ - if(get_term_type(r) == LitA) - itp = mk_not(p); - else { - if(get_term_type(r) == LitB) - itp = make(Equal,get_placeholder(p),z); - else { - ast mid = (get_term_type(y) == LitA) ? get_placeholder(p) : y; - itp = make(And,make(Equal,z,mid),mk_not(r)); - } - } - } - else { - if(get_term_type(r) == LitA){ - ast xr = (get_term_type(x) == LitA) ? get_placeholder(p) : x; - ast zr = (get_term_type(z) == LitA) ? get_placeholder(q) : z; - itp = mk_not(make(Equal,xr,zr)); - } - else { - LitType xt = get_term_type(x); - LitType zt = get_term_type(z); - if(xt == LitA && zt == LitB) - itp = make(And,make(Equal,x,get_placeholder(p)),mk_not(r)); - else if(zt == LitA && xt == LitB) - itp = make(And,make(Equal,z,get_placeholder(q)),mk_not(r)); - else - itp = mk_true(); - } - } - } - - /* Resolve it with the premises */ - std::vector conc; conc.push_back(r); conc.push_back(mk_not(q)); - itp = make_resolution(p,conc,itp,prem1); - conc.pop_back(); - itp = make_resolution(q,conc,itp,prem2); -#endif - - return itp; } @@ -1753,19 +1688,6 @@ class iz3proof_itp_impl : public iz3proof_itp { ast bar = make(cong,foo,make_int(rational(pos)),get_placeholder(mk_not(con))); conjs.push_back(mk_not(con)); return make_contra_node(bar,conjs); -#if 0 - ast A_term = x; - ast f_A_term = arg(con,0); - if(get_term_type(y) == LitA){ - A_term = y; - f_A_term = arg(con,1); - } - - - ast res = make(Equal,f_A_term,subst_in_arg_pos(pos,get_placeholder(make(Equal,x,y)),f_A_term)); - res = make(And,res,mk_not(con)); - return res; -#endif } ast subst_in_arg_pos(int pos, ast term, ast app){ @@ -1901,19 +1823,6 @@ class iz3proof_itp_impl : public iz3proof_itp { itp = mk_true(); break; default: { // mixed equality -#if 0 - ast mid = get_placeholder(make(Equal,x,y)); - if(get_term_type(y) == LitA){ - std::swap(x,y); - mid = make(Sub,x,mid); - } - else { - mid = make(Sub,mid,x); - } - ast zleqmid = make(Leq,make_int("0"),mid); - ast fark = make(contra,make_int("1"),mk_not(xleqy)); - itp = make(And,zleqmid,fark); -#endif std::vector conjs; conjs.resize(2); conjs[0] = make(Equal,x,y); conjs[1] = mk_not(xleqy); @@ -1942,12 +1851,6 @@ class iz3proof_itp_impl : public iz3proof_itp { conjs[1] = mk_not(con); itp = make(sum,get_placeholder(conjs[0]),d,get_placeholder(conjs[1])); itp = make_contra_node(itp,conjs); -#if 0 - ast t = arg(tleqc,0); - ast c = arg(tleqc,1); - ast thing = make(contra,make_int("1"),mk_not(con)); - itp = make(And,make(Leq,make_int("0"),make(Idiv,get_placeholder(tleqc),d)),thing); -#endif } } std::vector conc; conc.push_back(con); @@ -2073,7 +1976,7 @@ 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 - return add_quants(pf); + return add_quants(z3_simplify(pf)); } ast resolve_with_quantifier(const ast &pivot1, const ast &conj1, diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 2be7c22e5..26a1cc8fc 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -626,7 +626,7 @@ public: if(!is_literal_or_lit_iff(lit)){ if(is_not(lit)) std::cout << "~"; std::cout << "["; - print_expr(std::cout,abslit); + // print_expr(std::cout,abslit); std::cout << "]"; } else @@ -960,6 +960,52 @@ public: return res; } + ast AssignBoundsRule2Farkas(const ast &proof, const ast &con, std::vector prems){ + std::vector farkas_coeffs; + get_assign_bounds_rule_coeffs(proof,farkas_coeffs); + std::vector lits; + int nargs = num_prems(proof)+1; + if(nargs != (int)(farkas_coeffs.size())) + throw "bad assign-bounds theory lemma"; + std::vector my_coeffs; + std::vector my_cons; + for(int i = 1; i < nargs; i++){ + my_cons.push_back(conc(prem(proof,i-1))); + my_coeffs.push_back(farkas_coeffs[i]); + } + ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons)); + std::vector my_hyps; + for(int i = 1; i < nargs; i++) + my_hyps.push_back(prems[i-1]); + my_cons.push_back(mk_not(farkas_con)); + my_coeffs.push_back(make_int("1")); + my_hyps.push_back(iproof->make_hypothesis(mk_not(farkas_con))); + ast res = iproof->make_farkas(mk_false(),my_hyps,my_cons,my_coeffs); + res = iproof->make_cut_rule(farkas_con,farkas_coeffs[0],conc(proof),res); + return res; + } + + Iproof::node RewriteClause(Iproof::node clause, const ast &rew){ + if(pr(rew) == PR_MONOTONICITY){ + int nequivs = num_prems(rew); + for(int i = 0; i < nequivs; i++){ + Iproof::node equiv_pf = translate_main(prem(rew,i),false); + ast equiv = conc(prem(rew,i)); + clause = iproof->make_mp(equiv,clause,equiv_pf); + } + return clause; + } + if(pr(rew) == PR_TRANSITIVITY){ + clause = RewriteClause(clause,prem(rew,0)); + clause = RewriteClause(clause,prem(rew,1)); + return clause; + } + if(pr(rew) == PR_REWRITE){ + return clause; // just hope the rewrite does nothing! + } + throw unsupported(); + } + // translate a Z3 proof term into interpolating proof system Iproof::node translate_main(ast proof, bool expect_clause = true){ @@ -1015,11 +1061,19 @@ public: else lits.push_back(from_ast(con)); - // special case + // pattern match some idioms if(dk == PR_MODUS_PONENS && pr(prem(proof,0)) == PR_QUANT_INST && pr(prem(proof,1)) == PR_REWRITE ) { res = iproof->make_axiom(lits); return res; } + if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or){ + Iproof::node clause = translate_main(prem(proof,0),true); + res = RewriteClause(clause,prem(proof,1)); + return res; + } + + if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or) + std::cout << "foo!\n"; // translate all the premises std::vector args(nprems); @@ -1098,7 +1152,10 @@ public: break; } case AssignBoundsKind: { - res = AssignBounds2Farkas(proof,conc(proof)); + if(args.size() > 0) + res = AssignBoundsRule2Farkas(proof, conc(proof), args); + else + res = AssignBounds2Farkas(proof,conc(proof)); break; } default: