def get_proof_term(self, thy, goal, *, args=None, prevs=None): assert isinstance(args, Term), "cases" As = goal.hyps C = goal.prop goal1 = ProofTerm.sorry(Thm(goal.hyps, Term.mk_implies(args, C))) goal2 = ProofTerm.sorry( Thm(goal.hyps, Term.mk_implies(logic.neg(args), C))) return apply_theorem(thy, 'classical_cases', goal1, goal2)
def get_proof(self): invC = Const("inv", TFun(gcl.stateT, boolT)) transC = Const("trans", TFun(gcl.stateT, gcl.stateT, boolT)) s1 = Var("s1", gcl.stateT) s2 = Var("s2", gcl.stateT) prop = Thm.mk_implies(invC(s1), transC(s1, s2), invC(s2)) # print(printer.print_thm(self.thy, prop)) trans_pt = ProofTerm.assume(transC(s1, s2)) # print(printer.print_thm(self.thy, trans_pt.th)) P = Term.mk_implies(invC(s1), invC(s2)) ind_pt = apply_theorem(self.thy, "trans_cases", inst={ "a1": s1, "a2": s2, "P": P }) # print(printer.print_thm(self.thy, ind_pt.th)) ind_As, ind_C = ind_pt.prop.strip_implies() for ind_A in ind_As[1:-1]: # print("ind_A: ", printer.print_term(self.thy, ind_A)) vars, As, C = logic.strip_all_implies(ind_A, ["s", "k"]) # for A in As: # print("A: ", printer.print_term(self.thy, A)) # print("C: ", printer.print_term(self.thy, C)) eq1 = ProofTerm.assume(As[0]) eq2 = ProofTerm.assume(As[1]) guard = ProofTerm.assume(As[2]) inv_pre = ProofTerm.assume(As[3]).on_arg(self.thy, rewr_conv(eq1)) \ .on_prop(self.thy, rewr_conv("inv_def")) C_goal = ProofTerm.assume(C).on_arg(self.thy, rewr_conv(eq2)) \ .on_prop(self.thy, rewr_conv("inv_def"))
def testInferType(self): test_data = [ # A1 --> A2 (Const("implies", None)(Var("A1", None), Var("A2", None)), Term.mk_implies(Var("A1", boolT), Var("A2", boolT))), # A1 = A2 (Const("equals", None)(Var("A1", boolT), Var("A2", None)), Term.mk_equals(Var("A1", boolT), Var("A2", boolT))), # a = b (Const("equals", None)(Var("a", None), Var("b", None)), Const("equals", TFun(Ta, Ta, boolT))(Var("a", Ta), Var("b", Ta))), # %x. P x (Abs("x", None, Var("P", None)(Bound(0))), Abs("x", Ta, Var("P", TFun(Ta, boolT))(Bound(0)))), # %x y. x = y (Abs("x", Ta, Abs("y", None, Const("equals", None)(Bound(1), Bound(0)))), Abs( "x", Ta, Abs("y", Ta, Const("equals", TFun(Ta, Ta, boolT))(Bound(1), Bound(0))))), # [a] (Const("cons", None)(Var("a", None), Const("nil", None)), list.cons(Ta)(Var("a", Ta), Const("nil", listT(Ta)))), ] for t, res in test_data: self.assertEqual(type_infer(thy, ctxt, t), res)
def implies_intr(A, th): """Derivation rule IMPLIES_INTR: A |- B ------------ |- A --> B """ return Thm(tuple(t for t in th.hyps if t != A), Term.mk_implies(A, th.prop))
def testPrintThmHighlight(self): """Test printing of theorems with highlight.""" # 0, 1, 2, 3 = NORMAL, BOUND, VAR, TVAR A = Var('A', boolT) B = Var('B', boolT) A_to_B = Term.mk_implies(A, B) th = Thm([A, A_to_B], B) res = printer.print_thm(thy, th, highlight=True) self.assertEqual(res, [('A',2),(', ',0),('A',2),(' --> ',0),('B',2),(' ',0),('|-',0),(' ',0),('B',2)])
def testCheckProof(self): """Proof of [A, A --> B] |- B.""" A_to_B = Term.mk_implies(A, B) prf = Proof(A_to_B, A) prf.add_item(2, "implies_elim", prevs=[0, 1]) rpt = ProofReport() self.assertEqual(thy.check_proof(prf, rpt), Thm([A_to_B, A], B)) self.assertEqual(rpt.steps, 3)
def testIntros(self): Ta = TVar('a') x = Var('x', Ta) P = Var('P', TFun(Ta, boolT)) Q = Var('Q', TFun(Ta, boolT)) goal = Thm([], Term.mk_all(x, Term.mk_implies(P(x), Q(x)))) intros_tac = tactic.intros() pt = intros_tac.get_proof_term(thy, ProofTerm.sorry(goal), args=['x']) prf = pt.export() self.assertEqual(thy.check_proof(prf), goal)
def testCheckTerm(self): test_data = [ x, Term.mk_equals(x, y), Term.mk_equals(f, f), Term.mk_implies(A, B), Abs("x", Ta, Term.mk_equals(x, y)), ] for t in test_data: self.assertEqual(thy.check_term(t), None)
def add_induct_predicate(name, T, props): """Add the given inductive predicate. The inductive predicate is specified by the name and type of the predicate, and a list of introduction rules, where each introduction rule must be given a name. """ exts = TheoryExtension() exts.add_extension(AxConstant(name, T)) for th_name, prop in props: exts.add_extension(Theorem(th_name, Thm([], prop))) exts.add_extension(Attribute(th_name, "hint_backward")) # Case rule Targs, _ = T.strip_type() vars = [] for i, Targ in enumerate(Targs): vars.append(Var("_a" + str(i + 1), Targ)) P = Var("P", boolT) pred = Const(name, T) assum0 = pred(*vars) assums = [] for th_name, prop in props: As, C = prop.strip_implies() assert C.head == pred, "add_induct_predicate: wrong form of prop." eq_assums = [ Term.mk_equals(var, arg) for var, arg in zip(vars, C.args) ] assum = Term.mk_implies(*(eq_assums + As), P) prop_vars = term.get_vars(prop) for var in reversed(term.get_vars(prop)): assum = Term.mk_all(var, assum) assums.append(assum) prop = Term.mk_implies(*([assum0] + assums + [P])) exts.add_extension(Theorem(name + "_cases", Thm([], prop))) return exts
def testRewrConvWithAssum(self): x = Const("x", natT) y = Const("y", natT) x_eq_y = Term.mk_equals(x, y) th = Thm([], Term.mk_implies(x_eq_y, x_eq_y)) cv = arg_conv(rewr_conv(ProofTerm.atom(0, th))) f = Const("f", TFun(natT, natT)) res = Thm([x_eq_y], Term.mk_equals(f(x), f(y))) self.assertEqual(cv.eval(thy, f(x)), res) prf = Proof() prf.add_item(0, "sorry", th=th) cv.get_proof_term(thy, f(x)).export(prf=prf) self.assertEqual(thy.check_proof(prf), res)
def add_semantics(self): """Add the semantics of the system in GCL.""" transC = Const("trans", TFun(gcl.stateT, gcl.stateT, boolT)) s = Var("s", gcl.stateT) props = [] for i, (_, guard, assign) in enumerate(self.rules): t = gcl.convert_term(self.var_map, s, guard) t2 = gcl.mk_assign(self.var_map, s, assign) props.append( ("trans_rule" + str(i), Term.mk_implies(t, transC(s, t2)))) exts = induct.add_induct_predicate("trans", TFun(gcl.stateT, gcl.stateT, boolT), props) self.thy.unchecked_extend(exts)
def eval(self, thy, args, prevs): tyinst, inst = dict(), dict() if self.with_inst: name, tyinst, inst = args else: name = args th = thy.get_theorem(name) if not self.with_inst: As = th.assums assert len(prevs) <= len( As), "apply_theorem_macro: too many prevs." for idx, prev_th in enumerate(prevs): matcher.first_order_match_incr(As[idx], prev_th.prop, (tyinst, inst)) As, C = logic.subst_norm(th.prop, (tyinst, inst)).strip_implies() new_prop = Term.mk_implies(*(As[len(prevs):] + [C])) prev_hyps = sum([prev.hyps for prev in prevs], ()) return Thm(th.hyps + prev_hyps, new_prop)
def testInductPredicate(self): nat = Type("nat") even = Const("even", TFun(nat, boolT)) zero = Const("zero", nat) Suc = Const("Suc", TFun(nat, nat)) n = Var("n", nat) prop_zero = even(zero) prop_Suc = Term.mk_implies(even(n), even(Suc(Suc(n)))) data = [("even_zero", prop_zero), ("even_Suc", prop_Suc)] even_ext = induct.add_induct_predicate("even", TFun(nat, boolT), data) a1 = Var("_a1", nat) P = Var("P", boolT) res = [ AxConstant("even", TFun(nat, boolT)), Theorem("even_zero", Thm([], even(zero))), Attribute("even_zero", "hint_backward"), Theorem("even_Suc", Thm.mk_implies(even(n), even(Suc(Suc(n))))), Attribute("even_Suc", "hint_backward"), Theorem("even_cases", Thm.mk_implies(even(a1), imp(eq(a1,zero), P), all(n, imp(eq(a1,Suc(Suc(n))), even(n), P)), P)) ] self.assertEqual(even_ext.data, res)
def testEqualIntrFail3(self): th1 = Thm([], Term.mk_implies(A, B)) th2 = Thm([], Term.mk_implies(A, B)) self.assertRaises(InvalidDerivationException, Thm.equal_intr, th1, th2)
def testImpliesElimFail2(self): th1 = Thm([], Term.mk_implies(A, B)) th2 = Thm([], B) self.assertRaises(InvalidDerivationException, Thm.implies_elim, th1, th2)
def testImpliesElim2(self): th1 = Thm([B], Term.mk_implies(A, B)) th2 = Thm([B], A) self.assertEqual(Thm.implies_elim(th1, th2), Thm([B], B))
def mk_implies(*args): """Returns the theorem s1 --> ... --> sn --> t.""" return Thm([], Term.mk_implies(*args))
def testEqualIntr(self): th1 = Thm([A], Term.mk_implies(A, B)) th2 = Thm([B], Term.mk_implies(B, A)) self.assertEqual(Thm.equal_intr(th1, th2), Thm([A, B], Term.mk_equals(A, B)))
def get_subgoal(self, inv_id, rule_id, case_id, hint): """Obtain the subgoal for the given case and hint. inv_id: index of the invariant to be shown at the end of the transition. rule_id: index of the transition rule. case_id: index of the case. The cases are as follows: - 0 to n-1: parameter in rule equals i'th parameter in inv. - n: parameter in rule does not equal any parameter in inv. hint: either: - GUARD: invariant is implied by the guard. - PRE: invariant is implied by the same invariant in the previous state. - INV, i, inst: Invariant is implied by the guard and a different invariant i in the previous state. inst is a list specifying how to instantiate the invariant. """ rule_var, guard, assigns = self.rules[rule_id] inv_vars, inv = self.invs[inv_id] assert case_id >= 0 and case_id <= len(inv_vars), \ "get_subgoal: unexpected case_id." # Obtain invariant on the updated state. def subst(t): if t.is_comb() and t.fun in self.vars and t.arg in inv_vars: # Substitution for a parameterized variable if case_id < len(inv_vars) and inv_vars[case_id] == t.arg and \ t.fun(rule_var) in assigns: return assigns[t.fun(rule_var)] elif t.fun in assigns: return assigns[t.fun](t.arg) else: return t elif t.is_var(): # Substitution for a non-parameterized variable if t in assigns: return assigns[t] else: return t elif t.is_const(): return t elif t.is_comb(): return subst(t.fun)(subst(t.arg)) else: raise NotImplementedError inv_after = subst(inv) if hint == GUARD: return Term.mk_implies(guard, inv_after) elif hint == PRE: return Term.mk_implies(inv, inv_after) else: hint_ty, hint_inv_id, subst_vars = hint if hint_ty == INV: inv_vars, inv = self.invs[hint_inv_id] inv_var_nms = [v.name for v in inv_vars] subst = dict((nm, Var(subst_var, natT)) for nm, subst_var in zip(inv_var_nms, subst_vars)) inv_subst = inv.subst(subst) return Term.mk_implies(inv_subst, guard, inv_after)
def imp(self, s, t): return Term.mk_implies(s, t)
def testEqualElimFail(self): th1 = Thm([A], Term.mk_implies(A, B)) th2 = Thm([B], A) self.assertRaises(InvalidDerivationException, Thm.equal_elim, th1, th2)
def add_induct_type(name, targs, constrs): """Add the given inductive type to the theory. The inductive type is specified by name, arity (as list of default names of type arguments), and a list of constructors (triple consisting of name of the constant, type of the constant, and a list of suggested names of the arguments). For example, the natural numbers is specified by: (nat, [], [(0, nat, []), (Suc, nat => nat, ["n"])]). List type is specified by: (list, ["a"], [(nil, 'a list, []), (cons, 'a => 'a list => 'a list, ["x", "xs"])]). """ exts = TheoryExtension() # Add to type and term signature. exts.add_extension(AxType(name, len(targs))) for cname, cT, _ in constrs: exts.add_extension(AxConstant(cname, cT)) # Add non-equality theorems. for (cname1, cT1, vars1), (cname2, cT2, vars2) in itertools.combinations(constrs, 2): # For each A x_1 ... x_m and B y_1 ... y_n, get the theorem # ~ A x_1 ... x_m = B y_1 ... y_n. argT1, _ = cT1.strip_type() argT2, _ = cT2.strip_type() lhs_vars = [Var(nm, T) for nm, T in zip(vars1, argT1)] rhs_vars = [Var(nm, T) for nm, T in zip(vars2, argT2)] A = Const(cname1, cT1) B = Const(cname2, cT2) lhs = A(*lhs_vars) rhs = B(*rhs_vars) neq = logic.neg(Term.mk_equals(lhs, rhs)) th_name = name + "_" + cname1 + "_" + cname2 + "_neq" exts.add_extension(Theorem(th_name, Thm([], neq))) # Add injectivity theorems. for cname, cT, vars in constrs: # For each A x_1 ... x_m with m > 0, get the theorem # A x_1 ... x_m = A x_1' ... x_m' --> x_1 = x_1' & ... & x_m = x_m' if vars: argT, _ = cT.strip_type() lhs_vars = [Var(nm, T) for nm, T in zip(vars, argT)] rhs_vars = [Var(nm + "'", T) for nm, T in zip(vars, argT)] A = Const(cname, cT) assum = Term.mk_equals(A(*lhs_vars), A(*rhs_vars)) concls = [ Term.mk_equals(var1, var2) for var1, var2 in zip(lhs_vars, rhs_vars) ] concl = logic.mk_conj(*concls) if len(concls) > 1 else concls[0] th_name = name + "_" + cname + "_inject" exts.add_extension(Theorem(th_name, Thm.mk_implies(assum, concl))) # Add the inductive theorem. tvars = [TVar(targ) for targ in targs] T = Type(name, *tvars) var_P = Var("P", TFun(T, boolT)) ind_assums = [] for cname, cT, vars in constrs: A = Const(cname, cT) argT, _ = cT.strip_type() args = [Var(nm, T2) for nm, T2 in zip(vars, argT)] C = var_P(A(*args)) As = [var_P(Var(nm, T2)) for nm, T2 in zip(vars, argT) if T2 == T] ind_assum = Term.mk_implies(*(As + [C])) for arg in reversed(args): ind_assum = Term.mk_all(arg, ind_assum) ind_assums.append(ind_assum) ind_concl = var_P(Var("x", T)) th_name = name + "_induct" exts.add_extension( Theorem(th_name, Thm.mk_implies(*(ind_assums + [ind_concl])))) exts.add_extension(Attribute(th_name, "var_induct")) return exts
def testAbstractOverFail4(self): th = Thm([], Term.mk_implies(x, y)) self.assertRaises(InvalidDerivationException, Thm.abstraction, x, th)
def testImpliesIntr3(self): th = Thm([], B) self.assertEqual(Thm.implies_intr(A, th), Thm([], Term.mk_implies(A, B)))
# Author: Bohua Zhan import unittest from kernel.type import boolT from kernel.term import Term, Var from kernel.thm import Thm from kernel.proof import ProofItem, Proof A = Var("A", boolT) B = Var("B", boolT) A_to_B = Term.mk_implies(A, B) class ProofTest(unittest.TestCase): def testProofItem(self): test_data = [ (ProofItem(0, "theorem", args="conjD1"), "0: theorem conjD1", { 'id': 0, 'th': '', 'rule': 'theorem', 'args': 'conjD1', 'prevs': [] }), (ProofItem(1, "assume", args=A_to_B), "1: assume implies A B", { 'id': 1, 'th': '', 'rule': 'assume', 'args': 'implies A B', 'prevs': [] }),