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 __call__(self, *args): if not (len(args) == 1 and isinstance(args[0], FactItem)): return [] t = args[0].prop pt = args[0].pt res = [] if self.prop.is_equals(): try: inst = matcher.first_order_match(self.prop.lhs, t) res.append(FactItem(self.pt.substitution(inst).equal_elim(pt))) except matcher.MatchException: pass elif self.prop.is_implies(): try: inst = matcher.first_order_match(self.prop.arg1, t) res.append( FactItem(self.pt.substitution(inst).implies_elim(pt))) except matcher.MatchException: pass else: pass return res
def get_proof_term(self, goal, *, args=None, prevs=None): if isinstance(args, tuple): th_name, inst = args else: th_name, inst = args, None assert isinstance(th_name, str), "rule: theorem name must be a string" if prevs is None: prevs = [] th = theory.get_theorem(th_name) As, C = th.assums, th.concl # Length of prevs is at most length of As assert len(prevs) <= len(As), "rule: too many previous facts" if inst is None: inst = Inst() # Match the conclusion and assumptions. Either the conclusion # or the list of assumptions must be a first-order pattern. if matcher.is_pattern(C, []): inst = matcher.first_order_match(C, goal.prop, inst) for pat, prev in zip(As, prevs): inst = matcher.first_order_match(pat, prev.prop, inst) else: for pat, prev in zip(As, prevs): inst = matcher.first_order_match(pat, prev.prop, inst) inst = matcher.first_order_match(C, goal.prop, inst) # Check that every variable in the theorem has an instantiation. unmatched_vars = [ v.name for v in term.get_svars(As + [C]) if v.name not in inst ] if unmatched_vars: raise theory.ParameterQueryException( list("param_" + name for name in unmatched_vars)) # Substitute and normalize As, _ = th.prop.subst_norm(inst).strip_implies() goal_Alen = len(goal.assums) if goal_Alen > 0: As = As[:-goal_Alen] pts = prevs + [ ProofTerm.sorry(Thm(goal.hyps, A)) for A in As[len(prevs):] ] # Determine whether it is necessary to provide instantiation # to apply_theorem. if set(term.get_svars(th.assums)) != set(th.prop.get_svars()) or \ set(term.get_stvars(th.assums)) != set(th.prop.get_stvars()) or \ not matcher.is_pattern_list(th.assums, []): return apply_theorem(th_name, *pts, inst=inst) else: return apply_theorem(th_name, *pts)
def get_proof_term(self, prevs, goal_lit): disj, *lit_pts = prevs pt_conj = lit_pts[0] for i in range(len(lit_pts)): pt = lit_pts[i] if not pt.prop.is_not(): lit_pts[i] = pt.on_prop(rewr_conv('double_neg', sym=True)) def conj_right_assoc(pts): """ Give a sequence of proof terms: ⊢ A, ⊢ B, ⊢ C, return ⊢ A ∧ (B ∧ C) """ if len(pts) == 1: return pts[0] else: return apply_theorem('conjI', pts[0], conj_right_assoc(pts[1:])) # get a /\ b /\ c pt_conj = conj_right_assoc(lit_pts) other_lits = [ l.prop.arg if l.prop.is_not() else Not(l.prop) for l in lit_pts ] # use de Morgan pt_conj1 = pt_conj.on_prop( bottom_conv(rewr_conv('de_morgan_thm2', sym=True))) # if len(other_lits) == 1 and other_lits[0].is_not(): # pt_conj1 = pt_conj.on_prop(rewr_conv('double_neg', sym=True)) # Equality for two disjunctions which literals are the same, but order is different. eq_pt = imp_disj_iff(Eq(disj.prop, Or(goal_lit, *other_lits))) new_disj_pt = disj.on_prop(top_conv(replace_conv(eq_pt))) # A \/ B --> ~B --> A pt = ProofTerm.theorem('force_disj_true1') A, B = pt.prop.strip_implies()[0] C = pt.prop.strip_implies()[1] inst1 = matcher.first_order_match(C, goal_lit) inst2 = matcher.first_order_match(A, Or(goal_lit, *other_lits), inst=inst1) inst3 = matcher.first_order_match(B, pt_conj1.prop, inst=inst2) pt_implies = apply_theorem('force_disj_true1', new_disj_pt, pt_conj1, inst=inst3) return pt_implies.on_prop(try_conv(rewr_conv('double_neg')))
def testFirstOrderMatchFun(self): """First-order matching of variables in function position.""" P = Var("P", TFun(Ta, boolT)) Q = Var("Q", TFun(Ta, boolT)) C = Const("C", TFun(boolT, boolT, boolT)) test_data = [ (abs(x, P(x)), abs(x, C(P(x), Q(x))), { "P": abs(x, C(P(x), Q(x))) }), (abs(x, C(P(x), Q(x))), abs(x, C(Q(x), P(x))), { "P": Q, "Q": P }), (abs(x, C(P(x), P(x))), abs(x, C(C(P(x), Q(x)), C(P(x), Q(x)))), { "P": abs(x, C(P(x), Q(x))) }), (exists(x, P(x)), exists(x, conj(P(x), Q(x))), { "P": abs(x, conj(P(x), Q(x))) }), ] for pat, t, inst in test_data: if inst is not None: self.assertEqual(matcher.first_order_match(pat, t)[1], inst) else: self.assertRaises(matcher.MatchException, matcher.first_order_match, pat, t)
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, t): if not t.is_compares(): raise ConvException('%s is not a comparison.' % str(t)) pt = refl(t) pt_norm_form = pt.on_rhs(norm_eq(), arg1_conv(omega_simp_full_conv())) summands = strip_plus(pt_norm_form.rhs.arg1) coeffs = [ int_eval(s.arg1) if not s.is_number() else int_eval(s) for s in summands ] g = functools.reduce(gcd, coeffs) if g <= 1: return pt vars = [s.arg for s in summands if not s.is_number()] elim_gcd_coeffs = [int(i / g) for i in coeffs] if len(vars) < len(coeffs): simp_t = sum([ coeff * v for coeff, v in zip(elim_gcd_coeffs[1:-1], vars[1:]) ], elim_gcd_coeffs[0] * vars[0]) + Int(elim_gcd_coeffs[-1]) else: simp_t = sum( [coeff * v for coeff, v in zip(elim_gcd_coeffs[1:], vars[1:])], elim_gcd_coeffs[0] * vars[0]) simp_t_times_gcd = Int(g) * simp_t pt_simp_t_times_gcd = refl(simp_t_times_gcd).on_rhs( omega_simp_full_conv()).symmetric() pt_c = ProofTerm('int_const_ineq', greater(IntType)(Int(g), Int(0))) if t.is_less(): gcd_pt = ProofTerm.theorem('int_simp_less') elif t.is_less_eq(): gcd_pt = ProofTerm.theorem('int_simp_leq') elif t.is_greater(): gcd_pt = ProofTerm.theorem('int_simp_gt') elif t.is_greater_eq(): gcd_pt = ProofTerm.theorem('int_simp_geq') inst1 = matcher.first_order_match(gcd_pt.prop.arg1, pt_c.prop) inst2 = matcher.first_order_match(gcd_pt.prop.arg.rhs.arg1, simp_t, inst=inst1) pt_simp = gcd_pt.substitution(inst2).implies_elim(pt_c).on_lhs( arg1_conv(omega_simp_full_conv())) return pt_norm_form.transitive(pt_simp).on_rhs(omega_form_conv())
def get_proof_term(self, goal, *, args=None, prevs=None): th_name, var = args P = Lambda(var, goal.prop) th = theory.get_theorem(th_name) f, args = th.concl.strip_comb() if len(args) != 1: raise NotImplementedError inst = matcher.first_order_match(args[0], var) inst[f.name] = P return rule().get_proof_term(goal, args=(th_name, inst))
def get_proof_term(self, args, pts): th_name, goal = args pt = ProofTerm.theorem(th_name) assert pt.prop.is_not(), "resolve_theorem_macro" # Match for variables in pt. inst = matcher.first_order_match(pt.prop.arg, pts[0].prop) pt = pt.subst_type(inst.tyinst).substitution(inst) pt = apply_theorem('negE', pt, pts[0]) # false return apply_theorem('falseE', pt, concl=goal)
def apply_theorem(th_name, *pts, concl=None, inst=None): """Wrapper for apply_theorem and apply_theorem_for macros. The function takes optional arguments concl, inst. Matching always starts with inst. If conclusion is specified, it is matched next. Finally, the assumptions are matched. """ typecheck.checkinstance('apply_theorem', pts, [ProofTerm]) if concl is None and inst is None: # Normal case, can use apply_theorem return ProofTerm("apply_theorem", th_name, pts) else: pt = ProofTerm.theorem(th_name) if inst is None: inst = Inst() if concl is not None: inst = matcher.first_order_match(pt.concl, concl, inst) for i, prev in enumerate(pts): inst = matcher.first_order_match(pt.assums[i], prev.prop, inst) return ProofTerm("apply_theorem_for", (th_name, inst), pts)
def get_proof_term(self, goal, *, args=None, prevs=None): assert isinstance(prevs, list) and len(prevs) >= 1, "apply_prev" pt, prev_pts = prevs[0], prevs[1:] # First, obtain the patterns new_names = logic.get_forall_names(pt.prop) new_vars, As, C = logic.strip_all_implies(pt.prop, new_names) assert len(prev_pts) <= len(As), "apply_prev: too many prev_pts" if args is None: inst = Inst() else: inst = args inst = matcher.first_order_match(C, goal.prop, inst) for idx, prev_pt in enumerate(prev_pts): inst = matcher.first_order_match(As[idx], prev_pt.prop, inst) unmatched_vars = [v for v in new_names if v not in inst] if unmatched_vars: raise theory.ParameterQueryException( list("param_" + name for name in unmatched_vars)) pt = pt.subst_type(inst.tyinst) for new_name in new_names: pt = pt.forall_elim(inst[new_name]) if pt.prop.beta_norm() != pt.prop: pt = pt.on_prop(beta_norm_conv()) inst_As, inst_C = pt.prop.strip_implies() inst_arg = [inst[new_name] for new_name in new_names] new_goals = [ ProofTerm.sorry(Thm(goal.hyps, A)) for A in inst_As[len(prev_pts):] ] if set(new_names).issubset({v.name for v in term.get_vars(As)}) and \ matcher.is_pattern_list(As, []): return ProofTerm('apply_fact', args=None, prevs=prevs + new_goals) else: return ProofTerm('apply_fact_for', args=inst_arg, prevs=prevs + new_goals)
def run_test(self, thy_name, pat, t, *, vars=None, svars=None, tyinst=None, inst=None, failed=None): context.set_context(thy_name, vars=vars, svars=svars) pat, t = Term(pat), Term(t) inst = Inst((nm, Term(s)) for nm, s in inst.items()) if inst is not None else Inst() if tyinst is not None: inst.tyinst = TyInst((nm, Type(s)) for nm, s in tyinst.items()) if failed is not None: self.assertRaises(failed, first_order_match, pat, t) return self.assertEqual(first_order_match(pat, t), inst)
def get_proof_term(self, t): # If self.eq_pt is not present, produce it from thy, self.pt # and self.sym. Decompose into self.As and self.C. if self.eq_pt is None: if isinstance(self.pt, str): self.eq_pt = ProofTerm.theorem(self.pt) else: self.eq_pt = self.pt self.As, self.C = self.eq_pt.prop.strip_implies() # The conclusion of eq_pt should be an equality, and the number of # assumptions in eq_pt should match number of conditions. assert self.C.is_equals(), "rewr_conv: theorem is not an equality." if len(self.As) != len(self.conds): raise ConvException("rewr_conv: number of conds does not agree") inst = Inst() ts = [cond.prop for cond in self.conds] if not self.sym: lhs = self.C.lhs else: lhs = self.C.rhs try: inst = matcher.first_order_match_list(self.As, ts, inst) inst = matcher.first_order_match(lhs, t, inst) except matcher.MatchException: raise ConvException("rewr_conv: cannot match left side") # Check that every variable in the theorem has an instantiation if set(term.get_svars(self.As + [lhs])) != set( term.get_svars(self.As + [self.C])): raise ConvException("rewr_conv: unmatched vars") pt = self.eq_pt pt = pt.substitution(inst) pt = pt.implies_elim(*self.conds) if self.sym: pt = pt.symmetric() assert pt.th.is_equals(), "rewr_conv: wrong result." if pt.th.prop.lhs != t: pt = pt.on_prop(beta_norm_conv()) if pt.th.prop.lhs != t: pt = pt.on_prop(eta_conv()) assert pt.th.prop.lhs == t, "rewr_conv: wrong result. Expected %s, got %s" % ( str(t), str(pt.th.prop.lhs)) return 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 testFirstOrderMatchType(self): test_data = [ (x, m, ({ "a": natT }, { "x": m })), (p, m, ({}, { "p": m })), ] for pat, t, instsp in test_data: if instsp is not None: self.assertEqual(matcher.first_order_match(pat, t), instsp) else: self.assertRaises(matcher.MatchException, matcher.first_order_match, pat, t)
def solve_fun(goal, pts): for th_name in th_names: if theory.thy.has_theorem(th_name): th = theory.get_theorem(th_name) try: inst = matcher.first_order_match(th.concl, goal) except matcher.MatchException: continue As, _ = th.prop.subst_norm(inst).strip_implies() try: pts = [solve(A, pts) for A in As] except TacticException: continue return apply_theorem(th_name, *pts, concl=goal) # Not solved raise TacticException
def get_proof_term(self, prevs, args): assert isinstance(prevs, ProofTerm) and prevs.prop.arg1.is_int( ) and prevs.prop.arg.is_zero(), "Unexpected %s" % str(prevs) assert isinstance( args, Term) and (args.is_less() or args.is_less_eq() or args.is_greater or args.is_greater_eq()) th_names = [ 'int_pos_mul_less', 'int_neg_mul_less', 'int_pos_mul_less_eq', 'int_neg_mul_less_eq', 'int_pos_mul_greater', 'int_neg_mul_greater', 'int_pos_mul_greater_eq', 'int_neg_mul_greater_eq' ] for th in th_names: try: th1 = get_theorem(th) inst = matcher.first_order_match(th1.prop.arg.lhs, args) pt_concl = apply_theorem(th, prevs, inst=inst) return pt_concl except: continue raise NotImplementedError
def norm_fun(t, pts): for th_name in th_names: if theory.thy.has_theorem(th_name): th = theory.get_theorem(th_name) else: continue try: inst = matcher.first_order_match(th.concl.lhs, t) except matcher.MatchException: continue As, C = th.prop.subst_norm(inst).strip_implies() try: pts = [solve(A, pts) for A in As] except TacticException: continue return apply_theorem(th_name, *pts, concl=C) # No rewriting available return refl(t)
def testFirstOrderMatch(self): test_data = [ (x, y, { "x": y }), (x, a, { "x": a }), (a, a, {}), (a, b, None), (f(x, y), f(a, b), { "x": a, "y": b }), (f(x, x), f(a, a), { "x": a }), (f(x, x), f(a, b), None), (abs(x, y), abs(x, a), { "y": a }), (abs(x, a), abs(x, a), {}), (abs(x, a), abs(x, b), None), (abs(x, y), abs(x, x), None), (abs(x, z), abs(x, abs(y, y)), { "z": abs(y, y) }), (abs(x, y), abs(x, abs(y, x)), None), (abs(x, x), abs(x, x), {}), (abs(x, abs(y, y)), abs(x, abs(y, x)), None), ] for pat, t, inst in test_data: if inst is not None: self.assertEqual(matcher.first_order_match(pat, t)[1], inst) else: self.assertRaises(matcher.MatchException, matcher.first_order_match, pat, t)
def get_proof_term(self, args, pts): if not self.with_inst: assert len(pts) >= 2, "apply fact: too few prevs" pt, pt_prevs = pts[0], pts[1:] # First, obtain the patterns new_names = get_forall_names(pt.prop) new_vars, As, C = strip_all_implies(pt.prop, new_names) assert len(pt_prevs) <= len(As), "apply_fact: too many prevs" if self.with_inst: assert len(args) == len(new_names), "apply_fact_macro: wrong number of args." inst = Inst({nm: v for nm, v in zip(new_names, args)}) else: inst = Inst() for idx, pt_prev in enumerate(pt_prevs): inst = matcher.first_order_match(As[idx], pt_prev.prop, inst) pt = pt.subst_type(inst.tyinst) for new_var in new_vars: if new_var.name in inst: pt = pt.forall_elim(inst[new_var.name]) else: pt = pt.forall_elim(new_var) if pt.prop.beta_norm() != pt.prop: pt = pt.on_prop(beta_norm_conv()) for prev_pt in pt_prevs: if prev_pt.prop != pt.assums[0]: prev_pt = prev_pt.on_prop(beta_norm_conv()) pt = pt.implies_elim(prev_pt) for new_var in new_vars: if new_var.name not in inst: pt = pt.forall_intr(new_var) return pt
def get_proof_term(self, args, prevs=None): """ Let x_i denotes greater comparison, x__i denotes less comparison, for the greater comparison, find the smallest number x_min = min(x_1, ..., x_n), since x_min is positive, x_min/2 > 0 ==> x_min >= x_min / 2 ==> x_1, ..., x_n >= x_min / 2 ==> ∃δ. δ > 0 ∧ x_1 >= δ ∧ ... ∧ x_n >= δ. for the less comparison, find the largest number x_max = max(x__1, ..., x__n), since x_max is negative, x_max < x_max/2 ==> x__1, ..., x__n <= x_max/2; let δ = min(x_min/2, -x_max/2), then all x_i >= δ as well as all x__i <= -δ. """ def need_convert(tm): return False if real_eval(tm.arg) != 0 else True original_ineq_pts = [ProofTerm.assume(ineq) for ineq in args] # record the ineq which rhs is not 0 need_convert_pt = {arg for arg in args if need_convert(arg)} # record the args order order_args = {args[i].arg1: i for i in range(len(args))} # convert all ineqs to x_i > 0 or x_i < 0 normal_ineq_pts = [ pt.on_prop(norm_real_ineq_conv()) if pt.prop.arg != Real(0) else pt for pt in original_ineq_pts ] # dividing less comparison and greater comparison greater_ineq_pts = [ pt for pt in normal_ineq_pts if pt.prop.is_greater() ] less_ineq_pts = [pt for pt in normal_ineq_pts if pt.prop.is_less()] # stage 1: get the max(min) pos bound # ⊢ min(...) ≥ δ_1, δ_1 > 0 # ⊢ max(...) ≤ δ_2, δ_2 < 0 pt_lower_bound, lower_bound_pos_pt, pt_assert_delta1 = self.handle_geq_stage1( greater_ineq_pts) pt_upper_bound, upper_bound_neg_pt, pt_assert_delta2 = self.handle_leq_stage1( less_ineq_pts) delta_1 = Var("δ_1", RealType) delta_2 = Var("δ_2", RealType) # generate the relaxed inequations if pt_lower_bound is None: # all comparisons are ≤ pts = self.handle_leq_stage2(pt_upper_bound, less_ineq_pts, delta_2) bound_pt = upper_bound_neg_pt delta = delta_2 pt_asserts = [pt_assert_delta2] elif pt_upper_bound is None: # all comparisons are ≥ pts = self.handle_geq_stage2(pt_lower_bound, greater_ineq_pts, delta_1) bound_pt = lower_bound_pos_pt delta = delta_1 pt_asserts = [pt_assert_delta1] else: # have both ≥ and ≤ # ⊢ δ_1 ≥ min(δ_1, δ_2) pt_min_lower_bound = logic.apply_theorem("real_greater_min", inst=matcher.Inst( x=delta_1, y=delta_2)) # ⊢ -δ_2 ≤ max(-δ_2, -δ_1) pt_max_upper_bound = logic.apply_theorem("real_less_max", inst=matcher.Inst( x=-delta_2, y=-delta_1)) # ⊢ max(-δ_2, -δ_1) = -min(δ_1, δ_2) pt_max_min = logic.apply_theorem("max_min", inst=matcher.Inst(x=delta_1, y=delta_2)) # ⊢ min(...) ≥ min(δ_1, δ_2) pt_new_lower_bound = logic.apply_theorem("real_geq_trans", pt_lower_bound, pt_min_lower_bound) # ⊢ -δ_2 ≤ -min(δ_1, δ_2) pt_max_upper_bound_1 = pt_max_upper_bound.on_prop( arg_conv(replace_conv(pt_max_min))) # ⊢ max(...) ≤ -min(δ_1, δ_2) pt_new_upper_bound = logic.apply_theorem("real_le_trans", pt_upper_bound, pt_max_upper_bound_1) # ⊢ min(δ_1, δ_2) > 0 pt_new_lower_bound_pos = logic.apply_theorem( "min_pos", lower_bound_pos_pt, upper_bound_neg_pt) # ⊢ min(δ_1, δ_2) = δ delta = Var("δ", RealType) pt_delta_eq = ProofTerm.assume( Eq(pt_min_lower_bound.prop.arg, delta)) pt_asserts = [pt_delta_eq, pt_assert_delta1, pt_assert_delta2] # ⊢ min(...) ≥ δ pt_new_lower_bound_delta = pt_new_lower_bound.on_prop( arg_conv(replace_conv(pt_delta_eq))) # ⊢ max(...) ≤ -δ pt_new_upper_bound_delta = pt_new_upper_bound.on_prop( top_conv(replace_conv(pt_delta_eq))) # use new bound pts_leq = self.handle_leq_stage2(pt_new_upper_bound_delta, less_ineq_pts, delta) pts_geq = self.handle_geq_stage2(pt_new_lower_bound_delta, greater_ineq_pts, delta) pts = pts_leq + pts_geq bound_pt = pt_new_lower_bound_pos.on_prop( arg1_conv(replace_conv(pt_delta_eq))) # sort_pts = sorted(pts, key=lambda pt: order_args[pt.prop.arg1]) pt_conj = functools.reduce( lambda x, y: logic.apply_theorem("conjI", y, x), reversed([bound_pt] + pts)) # get ⊢∃δ. δ > 0 ∧ x_1 >= δ ∧ ... ∧ x_n >= δ th = ProofTerm.theorem("exI") inst = matcher.first_order_match(th.prop.arg, Exists(delta, pt_conj.prop)) pt_conj_exists = logic.apply_theorem("exI", pt_conj, inst=inst) pt_final = pt_conj_exists for pt_subst in pt_asserts: lhs, rhs = pt_subst.prop.args if not rhs.is_uminus(): pt_final = pt_final.implies_intr(pt_subst.prop).forall_intr(rhs).\ forall_elim(lhs).implies_elim(ProofTerm.reflexive(lhs)) else: pt_final = pt_final.implies_intr(pt_subst.prop).forall_intr(rhs.arg).\ forall_elim(-lhs).on_prop(top_conv(rewr_conv("real_neg_neg"))).implies_elim(ProofTerm.reflexive(lhs)) return pt_final
def get_proof_term(self, t): if not t.is_conj(): return refl(t) d_pos = dict() d_neg = dict() qu = deque([ProofTerm.assume(t)]) # collect each conjunct's proof term in conjuntion while qu: pt = qu.popleft() if pt.prop.is_conj(): conj1, conj2 = pt.prop.arg1, pt.prop.arg pt_conj1, pt_conj2 = apply_theorem('conjD1', pt), apply_theorem( 'conjD2', pt) if conj1 == false: th = ProofTerm.theorem("falseE") inst = matcher.first_order_match(th.prop.arg, t) pt_false_implies_conj = th.substitution(inst) return ProofTerm.equal_intr(pt_conj1.implies_intr(t), pt_false_implies_conj) elif conj2 == false: th = ProofTerm.theorem("falseE") inst = matcher.first_order_match(th.prop.arg, t) pt_false_implies_conj = th.substitution(inst) return ProofTerm.equal_intr(pt_conj2.implies_intr(t), pt_false_implies_conj) if conj1.is_conj(): qu.appendleft(pt_conj1) else: if conj1.is_not(): d_neg[conj1] = pt_conj1 else: d_pos[conj1] = pt_conj1 if conj2.is_conj(): qu.appendleft(pt_conj2) else: if conj2.is_not(): d_neg[conj2] = pt_conj2 else: d_pos[conj2] = pt_conj2 else: if pt.prop.is_not(): d_neg[pt.prop] = pt else: d_pos[pt.prop] = pt # first check if there are opposite terms in conjunctions, if there exists, return a false proof term for key in d_pos: if Not(key) in d_neg: pos_pt, neg_pt = d_pos[key], d_neg[Not(key)] pt_conj_pos_neg = apply_theorem("conjI", pos_pt, neg_pt) pt_conj_implies_false = pt_conj_pos_neg.on_prop( rewr_conv("conj_pos_neg")).implies_intr(t) th = ProofTerm.theorem("falseE") inst = matcher.first_order_match(th.prop.arg, t) pt_false_implies_conj = th.substitution(inst) return ProofTerm.equal_intr(pt_conj_implies_false, pt_false_implies_conj) d_pos.update(d_neg) d = d_pos def right_assoc(ts): l = len(ts) if l == 1: return d[ts[0]] elif l == 2: return apply_theorem('conjI', d[ts[0]], d[ts[1]]) else: return apply_theorem('conjI', d[ts[0]], right_assoc(ts[1:])) # pt_right = functools.reduce(lambda x, y: apply_theorem('conjI', x, d[y]), sorted(d.keys()), d[sorted(d.keys())[0]]) if true not in d: sorted_keys = term_ord.sorted_terms(d.keys()) else: d_keys_without_true = term_ord.sorted_terms( [k for k in d if k != true]) sorted_keys = [true] + d_keys_without_true sorted_keys_num = len(sorted_keys) pt_right = functools.reduce(lambda x, y: apply_theorem('conjI', d[sorted_keys[sorted_keys_num - y - 2]], x), \ range(sorted_keys_num - 1), d[sorted_keys[-1]]) # pt_right = right_assoc(sorted_keys) # order implies original dd = dict() norm_conj = And(*sorted_keys) norm_conj_pt = ProofTerm.assume(norm_conj) for k in sorted_keys: if k != sorted_keys[-1]: dd[k] = apply_theorem('conjD1', norm_conj_pt) norm_conj_pt = apply_theorem('conjD2', norm_conj_pt) else: dd[k] = norm_conj_pt def traverse(t): if not t.is_conj(): return dd[t] else: return apply_theorem('conjI', traverse(t.arg1), traverse(t.arg)) pt_left = traverse(t) pt_final = ProofTerm.equal_intr(pt_right.implies_intr(t), pt_left.implies_intr(norm_conj)) if true in d: return pt_final.on_rhs(rewr_conv("conj_true_left"), top_sweep_conv(sort_disj())) else: return pt_final.on_rhs(top_sweep_conv(sort_disj()))