def get_proof_term(self, goal, *, args=None, prevs=None): assert isinstance(prevs, list) and len(prevs) == 1, "rewrite_goal_with_prev" pt = prevs[0] C = goal.prop # In general, we assume pt.th has forall quantification. # First, obtain the patterns new_names = logic.get_forall_names(pt.prop) new_vars, prev_As, prev_C = logic.strip_all_implies(pt.prop, new_names) # Fact used must be an equality assert len( prev_As) == 0 and prev_C.is_equals(), "rewrite_goal_with_prev" for new_var in new_vars: pt = pt.forall_elim(new_var) # Check whether rewriting using the theorem has an effect assert has_rewrite(pt.th, C), "rewrite_goal_with_prev" cv = then_conv(top_sweep_conv(rewr_conv(pt)), beta_norm_conv()) eq_th = cv.eval(C) new_goal = eq_th.prop.rhs prevs = list(prevs) if not new_goal.is_reflexive(): prevs.append(ProofTerm.sorry(Thm(goal.hyps, new_goal))) return ProofTerm('rewrite_goal_with_prev', args=C, prevs=prevs)
def get_proof_term(self, goal): th = theory.get_theorem(self.th_name) assum = th.assums[0] cond = self.cond if cond is None: # Find cond by matching with goal.hyps one by one for hyp in goal.hyps: try: inst = matcher.first_order_match(th.assums[0], hyp, self.inst) cond = hyp break except matcher.MatchException: pass if cond is None: raise TacticException('elim: cannot match assumption') try: inst = matcher.first_order_match(th.concl, goal.prop, inst) except matcher.MatchException: raise TacticException('elim: matching failed') if any(v.name not in inst for v in th.prop.get_svars()): raise TacticException('elim: not all variables are matched') pt = ProofTerm.theorem(self.th_name).substitution(inst).on_prop( beta_norm_conv()) pt = pt.implies_elim(ProofTerm.assume(cond)) for assum in pt.assums: pt = pt.implies_elim(ProofTerm.sorry(Thm(goal.hyps, assum))) return pt
def get_proof_term(self, goal, *, args=None, prevs=None): th_name = args C = goal.prop # Check whether rewriting using the theorem has an effect assert has_rewrite(th_name, C, sym=self.sym, conds=prevs), \ "rewrite: unable to apply theorem." cv = then_conv( top_sweep_conv(rewr_conv(th_name, sym=self.sym, conds=prevs)), beta_norm_conv()) eq_th = cv.eval(C) new_goal = eq_th.prop.rhs if self.sym: macro_name = 'rewrite_goal_sym' else: macro_name = 'rewrite_goal' if new_goal.is_equals() and new_goal.lhs == new_goal.rhs: return ProofTerm(macro_name, args=(th_name, C), prevs=prevs) else: new_goal = ProofTerm.sorry(Thm(goal.hyps, new_goal)) assert new_goal.prop != goal.prop, "rewrite: unable to apply theorem" return ProofTerm(macro_name, args=(th_name, C), prevs=[new_goal] + prevs)
def get_proof_term(self, goal, prevs=None): elems = goal.strip_disj() disjs = [tm.arg for tm in elems[:-1]] disj_pts = [ProofTerm.assume(disj) for disj in disjs] pt0 = disj_pts[0] for pt1 in disj_pts[1:]: if pt1.lhs == pt0.rhs: pt0 = pt0.transitive(pt1) elif pt1.lhs == pt0.lhs: pt0 = pt0.symmetric().transitive(pt1) elif pt1.rhs == pt0.lhs: pt0 = pt0.symmetric().transitive(pt1.symmetric()) elif pt1.rhs == pt0.rhs: pt0 = pt0.transitive(pt1.symmetric()) else: print(pt0.prop) print(pt1.prop) raise NotImplementedError if pt0.symmetric().prop == elems[-1]: pt0 = pt0.symmetric() assert pt0.prop == elems[-1], "%s \n %s" % (str( pt0.prop), str(goal.strip_disj()[-1])) return ProofTerm("imp_to_or", elems[:-1] + [goal], prevs=[pt0])
def get_proof_term(self, t): if not is_real_ineq(t): return refl(t) pt_refl = refl(t).on_rhs(real_norm_comparison()) left_expr = pt_refl.rhs.arg1 summands = integer.strip_plus(left_expr) first = summands[0] if not left_expr.is_plus() or not first.is_constant(): return pt_refl first_value = real_eval(first) if pt_refl.rhs.is_greater_eq(): pt_th = ProofTerm.theorem("real_sub_both_sides_geq") elif pt_refl.rhs.is_greater(): pt_th = ProofTerm.theorem("real_sub_both_sides_gt") elif pt_refl.rhs.is_less_eq(): pt_th = ProofTerm.theorem("real_sub_both_sides_leq") elif pt_refl.rhs.is_less(): pt_th = ProofTerm.theorem("real_sub_both_sides_le") else: raise NotImplementedError(str(t)) inst = matcher.first_order_match(pt_th.lhs, pt_refl.rhs, inst=matcher.Inst(c=first)) return pt_refl.transitive(pt_th.substitution(inst=inst)).on_rhs( auto.auto_conv())
def get_proof_term(self, goal, *, args=None, prevs=None): assert isinstance(args, Term), "cases" As = goal.hyps C = goal.prop goal1 = ProofTerm.sorry(Thm(goal.hyps, Implies(args, C))) goal2 = ProofTerm.sorry(Thm(goal.hyps, Implies(Not(args), C))) return apply_theorem('classical_cases', goal1, goal2)
def get_proof_term(self, tm): if not ((tm.is_compares() or tm.is_equals()) and \ tm.arg1.is_constant() and tm.arg.is_constant()): return refl(tm) pt = ProofTerm("int_const_ineq", tm) if pt.prop.is_not(): return pt.on_prop(rewr_conv("eq_false")) else: return pt.on_prop(rewr_conv("eq_true"))
def testExport(self): """Basic case.""" pt1 = ProofTerm.assume(Eq(x, y)) pt2 = ProofTerm.assume(Eq(y, z)) pt3 = pt1.transitive(pt2) prf = pt3.export() self.assertEqual(len(prf.items), 3) self.assertEqual(theory.check_proof(prf), pt3.th)
def testExport2(self): """Repeated theorems.""" pt1 = ProofTerm.assume(Eq(x, y)) pt2 = ProofTerm.reflexive(f) pt3 = pt2.combination(pt1) # f x = f y pt4 = pt3.combination(pt1) # f x x = f y y prf = pt4.export() self.assertEqual(len(prf.items), 4) self.assertEqual(theory.check_proof(prf), pt4.th)
def get_proof_term(self, goal, args, prevs): assert len(goal.hyps) == 0, "vcg_tactic" assert goal.prop.is_comb("Valid", 3), "vcg_tactic" P, c, Q = goal.prop.args # Obtain the theorem [...] |- Valid P c Q T = Q.get_type().domain_type() pt = vcg_norm(T, goal.prop) ptAs = [ProofTerm.sorry(Thm(goal.hyps, A)) for A in pt.assums] return ProofTerm("vcg", goal.prop, ptAs)
def encode(t): """Given a propositional formula t, compute its Tseitin encoding. The theorem is structured as follows: Each of the assumptions, except the last, is an equality, where the right side is either an atom or a logical operation between atoms. We call these assumptions As. The last assumption is the original formula. We call it F. The conclusion is in CNF. Each clause except the last is an expansion of one of As. The last clause is obtained by performing substitutions of As on F. """ # Mapping from subterms to newly introduced variables subterm_dict = dict() for i, subt in enumerate(logic_subterms(t)): subterm_dict[subt] = Var('x' + str(i + 1), BoolType) # Collect list of equations eqs = [] for subt in subterm_dict: r = subterm_dict[subt] if not is_logical(subt): eqs.append(Eq(r, subt)) elif subt.is_not(): r1 = subterm_dict[subt.arg] eqs.append(Eq(r, Not(r1))) else: r1 = subterm_dict[subt.arg1] r2 = subterm_dict[subt.arg] eqs.append(Eq(r, subt.head(r1, r2))) # Form the proof term eq_pts = [ProofTerm.assume(eq) for eq in eqs] encode_pt = ProofTerm.assume(t) for eq_pt in eq_pts: encode_pt = encode_pt.on_prop(top_conv(rewr_conv(eq_pt, sym=True))) for eq_pt in eq_pts: if is_logical(eq_pt.rhs): encode_pt = logic.apply_theorem('conjI', eq_pt, encode_pt) # Rewrite using Tseitin rules encode_thms = [ 'encode_conj', 'encode_disj', 'encode_imp', 'encode_eq', 'encode_not' ] for th in encode_thms: encode_pt = encode_pt.on_prop(top_conv(rewr_conv(th))) # Normalize the conjuncts return encode_pt.on_prop(logic.conj_norm())
def get_proof_term(self, goal, *, args=None, prevs=None): if args is None: var_names = [] else: var_names = args vars, As, C = logic.strip_all_implies(goal.prop, var_names, svar=False) pt = ProofTerm.sorry(Thm(list(goal.hyps) + As, C)) ptAs = [ProofTerm.assume(A) for A in As] ptVars = [ProofTerm.variable(var.name, var.T) for var in vars] return ProofTerm('intros', None, ptVars + ptAs + [pt])
def vcg_solve(goal): """Compute the verification conditions for a hoare triple, then solves the verification conditions using SMT. """ assert goal.is_comb("Valid", 3), "vcg_solve" P, c, Q = goal.args T = Q.get_type().domain_type() pt = vcg_norm(T, goal) vc_pt = [ProofTerm("z3", vc, []) for vc in pt.assums] return ProofTerm("vcg", goal, vc_pt)
def testExport3(self): """Case with atoms.""" pt1 = ProofTerm.atom(0, Thm([], Eq(x, y))) pt2 = ProofTerm.atom(1, Thm([], Eq(y, z))) pt3 = pt1.transitive(pt2) prf = Proof() prf.add_item(0, rule="sorry", th=Thm([], Eq(x, y))) prf.add_item(1, rule="sorry", th=Thm([], Eq(y, z))) pt3.export(prf=prf) self.assertEqual(theory.check_proof(prf), Thm([], Eq(x, z)))
def get_proof_term(self, args, pts): # First, find the pair i, j such that B_j = ~A_i or A_i = ~B_j, the # variable side records the side of the positive literal. pt1, pt2 = pts disj1 = strip_num(pt1.prop, args[0]) disj2 = strip_num(pt2.prop, args[1]) side = None for i, t1 in enumerate(disj1): for j, t2 in enumerate(disj2): if t2 == Not(t1): side = 'left' break elif t1 == Not(t2): side = 'right' break if side is not None: break assert side is not None, "resolution: literal not found" # If side is wrong, just swap: if side == 'right': return self.get_proof_term([args[1], args[0]], [pt2, pt1]) # Move items i and j to the front disj1 = [disj1[i]] + disj1[:i] + disj1[i + 1:] disj2 = [disj2[j]] + disj2[:j] + disj2[j + 1:] eq_pt1 = logic.imp_disj_iff(Eq(pt1.prop, Or(*disj1))) eq_pt2 = logic.imp_disj_iff(Eq(pt2.prop, Or(*disj2))) pt1 = eq_pt1.equal_elim(pt1) pt2 = eq_pt2.equal_elim(pt2) if len(disj1) > 1 and len(disj2) > 1: pt = logic.apply_theorem('resolution', pt1, pt2) elif len(disj1) > 1 and len(disj2) == 1: pt = logic.apply_theorem('resolution_left', pt1, pt2) elif len(disj1) == 1 and len(disj2) > 1: pt = logic.apply_theorem('resolution_right', pt1, pt2) else: pt = logic.apply_theorem('negE', pt2, pt1) # return pt.on_prop(disj_norm()) disj_new = set(disj1[1:] + disj2[1:]) # eq_pt_norm = logic.imp_disj_iff(Eq(pt.prop, Or(*disj_new))) implies_pt_norm = ProofTerm("imp_disj", Implies(pt.prop, Or(*disj_new))) pt_final = implies_pt_norm.implies_elim(pt) self.arity = len(disj_new) return pt_final.on_prop(conv.top_conv(conv.rewr_conv("double_neg")))
def get_proof_term(self, tm): if not tm.is_equals() or not int_eval(tm.lhs) != 0 or not int_eval( tm.rhs) == 0: raise ConvException(str(tm)) lhs_value = int_eval(tm.lhs) if lhs_value > 0: premise_pt = ProofTerm("int_const_ineq", greater(IntType)(Int(lhs_value), Int(0))) return apply_theorem("int_pos_neq_zero", premise_pt) else: premise_pt = ProofTerm("int_const_ineq", less(IntType)(Int(lhs_value), Int(0))) return apply_theorem("int_neg_neq_zero", premise_pt)
def get_proof_term(self, goal): th = theory.get_theorem(self.th_name) try: inst = matcher.first_order_match(th.concl, goal.prop, self.inst) except matcher.MatchException: raise TacticException('rule: matching failed') if any(v.name not in inst for v in th.prop.get_svars()): raise TacticException('rule: not all variables are matched') pt = ProofTerm.theorem(self.th_name).substitution(inst).on_prop( beta_norm_conv()) for assum in pt.assums: pt = pt.implies_elim(ProofTerm.sorry(Thm(goal.hyps, assum))) return pt
def handle_geq_stage2(self, pt_lower_bound, pts, delta): # get ⊢ x_i ≥ δ, i = 1...n geq_pt = [] pt_a = pt_lower_bound d = set() for i in range(len(pts)): if i != len(pts) - 1: pt = logic.apply_theorem("both_geq_min", pt_a) pt_1, pt_2 = logic.apply_theorem("conjD1", pt), logic.apply_theorem( "conjD2", pt) else: pt_2 = pt_a ineq = pt_2.prop if ineq.arg1.is_minus() and ineq.arg1.arg.is_number(): # move all constant term from left to right in pt_2's prop num = ineq.arg1.arg expr = greater_eq(ineq.arg1.arg1, num + delta) else: expr = greater_eq(ineq.arg1, Real(0) + delta) pt_eq_comp = ProofTerm("real_eq_comparison", Eq(ineq, expr)) geq_pt.insert(0, pt_2.on_prop(replace_conv(pt_eq_comp))) if i != len(pts) - 1: pt_a = pt_1 return geq_pt
def handle_leq_stage2(self, pt_upper_bound, pts, delta): # get ⊢ x_i ≤ -δ, for i = 1...n leq_pt = [] pt_b = pt_upper_bound for i in range(len(pts)): if i != len(pts) - 1: pt = logic.apply_theorem("both_leq_max", pt_b) pt_1, pt_2 = logic.apply_theorem("conjD1", pt), logic.apply_theorem( "conjD2", pt) else: pt_2 = pt_b ineq = pt_2.prop if ineq.arg1.is_minus() and ineq.arg1.arg.is_number(): num = ineq.arg1.arg expr = less_eq(ineq.arg1.arg1, num - delta) else: expr = less_eq(ineq.arg1, Real(0) - delta) pt_eq_comp = ProofTerm("real_eq_comparison", Eq(ineq, expr)) leq_pt.insert(0, pt_2.on_prop(replace_conv(pt_eq_comp))) if i != len(pts) - 1: pt_b = pt_1 return leq_pt
def testCombineFractionConv(self): test_data = [ ('1 / (x + 1) + 1 / (x - 1)', 'x Mem real_open_interval (-1/2) (1/2)', '2 * x / ((x + 1) * (x - 1))'), ("2 + 1 / (x + 1)", 'x Mem real_open_interval 0 1', '(3 + 2 * x) / (x + 1)'), ("(x + 1) ^ -(1::real)", 'x Mem real_open_interval 0 1', '1 / (x + 1)'), ("2 * (x * (x + 1) ^ -(1::real))", 'x Mem real_open_interval 0 1', '2 * x / (x + 1)'), ("2 - 1 / (x + 1)", 'x Mem real_open_interval 0 1', '(1 + 2 * x) / (x + 1)'), ("x ^ (1/2)", "x Mem real_open_interval 0 1", "x ^ (1/2) / 1"), ("x ^ -(1/2)", "x Mem real_open_interval 0 1", "1 / (x ^ (1/2))"), ("x ^ -(2::real)", "x Mem real_open_interval 0 1", "1 / (x ^ (2::nat))"), ] vars = {'x': 'real'} context.set_context('interval_arith', vars=vars) for s, cond, res in test_data: s = parser.parse_term(s) res = parser.parse_term(res) cond_t = parser.parse_term(cond) cv = proof.combine_fraction([ProofTerm.assume(cond_t)]) test_conv(self, 'interval_arith', cv, vars=vars, t=s, t_res=res, assms=[cond])
def testNormAbsoluteValue(self): test_data = [ ("abs x", ["x >= 0"], "x"), ("abs x", ["x Mem real_closed_interval 0 1"], "x"), ("abs x", ["x Mem real_closed_interval (-1) 0"], "-1 * x"), ("abs (sin x)", ["x Mem real_closed_interval 0 (pi / 2)"], "sin x"), ("abs (sin x)", ["x Mem real_closed_interval (-pi / 2) 0"], "-1 * sin x"), ("abs (log x)", ["x Mem real_open_interval (exp (-1)) 1"], "-1 * log x"), ] vars = {'x': 'real'} context.set_context('interval_arith', vars=vars) for t, conds, res in test_data: conds_pt = [ ProofTerm.assume(parser.parse_term(cond)) for cond in conds ] cv = auto.auto_conv(conds_pt) test_conv(self, 'interval_arith', cv, vars=vars, t=t, t_res=res, assms=conds)
def search(self, state, id, prevs, data=None): cur_item = state.get_proof_item(id) prevs = [ ProofTerm.atom(prev, state.get_proof_item(prev).th) for prev in prevs ] results = [] def search_thm(th_name): try: pt = tactic.resolve().get_proof_term(cur_item.th, args=th_name, prevs=prevs) results.append({ "theorem": th_name, "_goal": [gap.prop for gap in pt.gaps] }) except (AssertionError, matcher.MatchException): pass if data: search_thm(data['theorem']) else: for th_name in theory.thy.get_data("theorems"): if 'hint_resolve' in theory.thy.get_attributes(th_name): search_thm(th_name) return sorted(results, key=lambda d: d['theorem'])
def search(self, state, id, prevs, data=None): cur_item = state.get_proof_item(id) prevs = [ ProofTerm.atom(prev, state.get_proof_item(prev).th) for prev in prevs ] results = [] def search_thm(th_name): try: pt = tactic.rule().get_proof_term(cur_item.th, args=th_name, prevs=prevs) results.append({ "theorem": th_name, "_goal": [gap.prop for gap in pt.gaps] }) except theory.ParameterQueryException: # In this case, still suggest the result results.append({"theorem": th_name}) except (AssertionError, matcher.MatchException): pass if data: search_thm(data['theorem']) else: for th_name in theory.thy.get_data("theorems"): if 'hint_backward' in theory.thy.get_attributes(th_name) or \ ('hint_backward1' in theory.thy.get_attributes(th_name) and len(prevs) >= 1): search_thm(th_name) return sorted(results, key=lambda d: d['theorem'])
def apply(self, state, id, data, prevs): try: prev_pts = [ ProofTerm.atom(prev, state.get_proof_item(prev).th) for prev in prevs ] sym_b = 'sym' in data and data['sym'] == 'true' pt = logic.rewrite_fact_macro(sym=sym_b).get_proof_term( data['theorem'], prev_pts) except InvalidDerivationException as e: raise e state.add_line_before(id, 1) if 'sym' in data and data['sym'] == 'true': state.set_line(id, 'rewrite_fact_sym', args=data['theorem'], prevs=prevs) else: state.set_line(id, 'rewrite_fact', args=data['theorem'], prevs=prevs) id2 = id.incr_id(1) new_id = state.find_goal(state.get_proof_item(id2).th, id2) if new_id is not None: state.replace_id(id2, new_id)
def search(self, state, id, prevs, data=None): cur_item = state.get_proof_item(id) prevs = [ ProofTerm.atom(prev, state.get_proof_item(prev).th) for prev in prevs ] results = [] def search_thm(th_name, sym): try: sym_b = True if sym == 'true' else False pt = logic.rewrite_fact_macro(sym=sym_b).get_proof_term( th_name, prevs) results.append({ "theorem": th_name, "sym": sym, "_fact": [pt.prop] }) except (AssertionError, matcher.MatchException, InvalidDerivationException) as e: # print(e) pass if data: search_thm(data['theorem'], data['sym']) else: for th_name in theory.thy.get_data("theorems"): if 'hint_rewrite' in theory.thy.get_attributes(th_name): search_thm(th_name, 'false') if 'hint_rewrite_sym' in theory.thy.get_attributes(th_name): search_thm(th_name, 'true') return sorted(results, key=lambda d: d['theorem'])
def search(self, state, id, prevs, data=None): cur_item = state.get_proof_item(id) prevs = [ ProofTerm.atom(prev, state.get_proof_item(prev).th) for prev in prevs ] results = [] def search_thm(th_name, sym): try: sym_b = True if sym == 'true' else False pt = tactic.rewrite_goal(sym=sym_b).get_proof_term( cur_item.th, args=th_name, prevs=prevs) results.append({ "theorem": th_name, "sym": sym, "_goal": [gap.prop for gap in pt.gaps] }) except (AssertionError, matcher.MatchException) as e: pass if data: sym = 'false' if 'sym' in data: sym = data['sym'] search_thm(data['theorem'], sym) else: for th_name in theory.thy.get_data("theorems"): if 'hint_rewrite' in theory.thy.get_attributes(th_name): search_thm(th_name, 'false') if 'hint_rewrite_sym' in theory.thy.get_attributes(th_name): search_thm(th_name, 'true') return sorted(results, key=lambda d: d['theorem'])
def get_proof_term(self, t): if t.get_type() != RealType: return refl(t) simp_t = Real(real_eval(t)) if simp_t == t: return refl(t) return ProofTerm('real_eval', Eq(t, simp_t))
def apply_tactic(self, id, tactic, args=None, prevs=None): id = ItemID(id) prevs = [ItemID(prev) for prev in prevs] if prevs else [] prevs = [ ProofTerm.atom(prev, self.get_proof_item(prev).th) for prev in prevs ] cur_item = self.get_proof_item(id) assert cur_item.rule == "sorry", "apply_tactic: id is not a gap" pt = tactic.get_proof_term(cur_item.th, args=args, prevs=prevs) new_prf = pt.export(prefix=id, subproof=False) self.add_line_before(id, len(new_prf.items) - 1) for i, item in enumerate(new_prf.items): cur_id = item.id prf = self.prf.get_parent_proof(cur_id) prf.items[cur_id.last()] = item self.check_proof(compute_only=True) # Test if the goals are already proved: for item in new_prf.items: if item.rule == 'sorry': new_id = self.find_goal( self.get_proof_item(item.id).th, item.id) if new_id is not None: self.replace_id(item.id, new_id) # Resolve trivial subgoals for item in new_prf.items: if item.rule == 'sorry': if logic.trivial_macro().can_eval(item.th.prop): self.set_line(item.id, 'trivial', args=item.th.prop)
def get_proof_term(self, goal): if not goal.prop.is_implies(): raise TacticException('intro_imp: goal is not implies.') A, C = goal.prop.args new_goal = ProofTerm.sorry(Thm(list(goal.hyps) + [A], C)) return new_goal.implies_intr(A)
def get_proof_term(self, goal): if not goal.prop.is_forall(): raise TacticException('intro_forall: goal is not forall') v, body = goal.prop.arg.dest_abs(self.var_name) new_goal = ProofTerm.sorry(Thm(goal.hyps, body)) return new_goal.forall_intr(v)