def testAddZeroRight(self): """Proof of n + 0 = n by induction.""" thy = basic.load_theory('nat') n = Var("n", nat.natT) eq = Term.mk_equals prf = Proof() prf.add_item(0, "theorem", args="nat_induct") prf.add_item(1, "substitution", args={ "P": Term.mk_abs(n, eq(nat.plus(n, nat.zero), n)), "x": n }, prevs=[0]) prf.add_item(2, "beta_norm", prevs=[1]) prf.add_item(3, "theorem", args="plus_def_1") prf.add_item(4, "substitution", args={"n": nat.zero}, prevs=[3]) prf.add_item(5, "implies_elim", prevs=[2, 4]) prf.add_item(6, "assume", args=eq(nat.plus(n, nat.zero), n)) prf.add_item(7, "theorem", args="plus_def_2") prf.add_item(8, "substitution", args={ "m": n, "n": nat.zero }, prevs=[7]) prf.add_item(9, "arg_combination", args=nat.Suc, prevs=[6]) prf.add_item(10, "transitive", prevs=[8, 9]) prf.add_item(11, "implies_intr", args=eq(nat.plus(n, nat.zero), n), prevs=[10]) prf.add_item(12, "forall_intr", args=n, prevs=[11]) prf.add_item(13, "implies_elim", prevs=[5, 12]) th = Thm.mk_equals(nat.plus(n, nat.zero), n) self.assertEqual(thy.check_proof(prf), th)
def handle_leq_stage1(self, pts): if not pts: return None, None, None # ⊢ max(max(...(max(x_1, x_2), x_3)...), x_n-1), x_n) < 0 max_pos_pt = functools.reduce( lambda pt1, pt2: logic.apply_theorem("max_less_0", pt1, pt2), pts[1:], pts[0]) # ⊢ 0 < 2 two_pos_pt = ProofTerm("real_compare", Real(2) > Real(0)) # ⊢ max(...) / 2 < 0 max_divides_two_pos = logic.apply_theorem("real_neg_div_pos", max_pos_pt, two_pos_pt) # ⊢ 2 ≥ 1 two_larger_one = ProofTerm("real_compare", Real(2) >= Real(1)) # ⊢ max(...) ≤ max(...) / 2 less_half_pt = logic.apply_theorem("real_neg_divides_larger_1", two_larger_one, max_pos_pt) # ⊢ max(...) / 2 = -δ delta_2 = Var("δ_2", RealType) pt_delta_eq = ProofTerm.assume(Eq(less_half_pt.prop.arg, -delta_2)) # ⊢ δ > 0 delta_pos_pt = max_divides_two_pos.on_prop( rewr_conv("real_le_gt"), top_conv(replace_conv(pt_delta_eq)), auto.auto_conv()) # max(...) ≤ -δ less_half_pt_delta = less_half_pt.on_prop( arg_conv(replace_conv(pt_delta_eq))) return less_half_pt_delta, delta_pos_pt, pt_delta_eq
def strip_all_implies(t, names, svar=True): """Given a term of the form !x_1 ... x_k. A_1 --> ... --> A_n --> C. Return the triple ([v_1, ..., v_k], [A_1, ... A_n], C), where v_1, ..., v_k are new variables with the given names, and A_1, ..., A_n, C are the body of the input term, with bound variables substituted for v_1, ..., v_k. """ if t.is_forall(): assert len(names) > 0, "strip_all_implies: not enough names input." assert isinstance(names[0], str), "strip_all_implies: names must be strings." if svar: v = SVar(names[0], t.arg.var_T) else: v = Var(names[0], t.arg.var_T) vars, As, C = strip_all_implies(t.arg.subst_bound(v), names[1:], svar=svar) return ([v] + vars, As, C) else: assert len(names) == 0, "strip_all_implies: too many names input." As, C = t.strip_implies() return ([], As, C)
def compute_wp(T, c, Q): """Compute the weakest precondition for the given command and postcondition. Here c is the program and Q is the postcondition. The computation is by case analysis on the form of c. The function returns a proof term showing [...] |- Valid P c Q, where P is the computed precondition, and [...] contains the additional subgoals. """ if c.is_const("Skip"): # Skip return apply_theorem("skip_rule", concl=Valid(T)(Q, c, Q)) elif c.is_comb("Assign", 2): # Assign a b a, b = c.args s = Var("s", T) P2 = Lambda(s, Q(function.mk_fun_upd(s, a, b(s).beta_conv()))) return apply_theorem("assign_rule", inst=Inst(b=b), concl=Valid(T)(P2, c, Q)) elif c.is_comb("Seq", 2): # Seq c1 c2 c1, c2 = c.args wp1 = compute_wp(T, c2, Q) # Valid Q' c2 Q wp2 = compute_wp(T, c1, wp1.prop.args[0]) # Valid Q'' c1 Q' return apply_theorem("seq_rule", wp2, wp1) elif c.is_comb("Cond", 3): # Cond b c1 c2 b, c1, c2 = c.args wp1 = compute_wp(T, c1, Q) wp2 = compute_wp(T, c2, Q) res = apply_theorem("if_rule", wp1, wp2, inst=Inst(b=b)) return res elif c.is_comb("While", 3): # While b I c _, I, _ = c.args pt = apply_theorem("while_rule", concl=Valid(T)(I, c, Q)) pt0 = ProofTerm.assume(pt.assums[0]) pt1 = vcg(T, pt.assums[1]) return pt.implies_elim(pt0, pt1) else: raise NotImplementedError
def testInductProd(self): Ta = TVar("a") Tb = TVar("b") Tab = Type("prod", Ta, Tb) prod_ext = induct.add_induct_type( "prod", ["a", "b"], [("Pair", TFun(Ta, Tb, Tab), ["a", "b"])]) a = Var("a", Ta) b = Var("b", Tb) a2 = Var("a'", Ta) b2 = Var("b'", Tb) pair = Const("Pair", TFun(Ta, Tb, Tab)) P = Var("P", TFun(Tab, boolT)) x = Var("x", Tab) res = [ AxType("prod", 2), AxConstant("Pair", TFun(Ta, Tb, Tab)), Theorem("prod_Pair_inject", Thm([], imp(eq(pair(a, b), pair(a2, b2)), conj(eq(a, a2), eq(b, b2))))), Theorem("prod_induct", Thm([], imp(all(a, all(b, P(pair(a, b)))), P(x)))), Attribute("prod_induct", "var_induct") ] self.assertEqual(prod_ext.data, res)
from kernel.thm import Thm from logic import basic from logic import logic from data import nat from data import real from data import list from data import set from data import string from data import function from data import interval from syntax import printer from syntax.settings import settings, global_setting basic.load_theory('list') A = Var("A", BoolType) B = Var("B", BoolType) C = Var("C", BoolType) Ta = TVar("a") a = Var("a", Ta) b = Var("b", Ta) P = Var("P", TFun(Ta, BoolType)) Q = Var("Q", TFun(Ta, BoolType)) R = Var("R", TFun(Ta, Ta, BoolType)) nn = Var("n", TFun(BoolType, BoolType)) m = Var("m", NatType) n = Var("n", NatType) p = Var("p", NatType) xs = Var("xs", TConst("list", Ta)) ys = Var("ys", TConst("list", Ta)) zs = Var("zs", TConst("list", Ta))
def match(pat, t, instsp, bd_vars): tyinst, inst = instsp # print("Match", pat, "with", t) if pat.head.is_var() and pat.head.name.startswith('_'): # Case where the head of the function is a variable. if pat.head.name not in inst: # If the variable is not instantiated, check that the # arguments are distinct bound variables, and all bound # variables appearing in t also appear as an argument. # If all conditions hold, assign appropriately. t_vars = term.get_vars(t) if any(v not in bd_vars for v in pat.args): raise MatchException if len(set(pat.args)) != len(pat.args): raise MatchException if any(v in t_vars and v not in pat.args for v in bd_vars): raise MatchException pat_T = TFun(*([v.T for v in pat.args] + [t.get_type()])) try: pat.head.T.match_incr(pat_T, tyinst, internal_only=True) except TypeMatchException: raise MatchException inst_t = t for v in reversed(pat.args): if inst_t.is_comb( ) and inst_t.arg == v and v not in term.get_vars( inst_t.fun): inst_t = inst_t.fun else: inst_t = Term.mk_abs(v, inst_t) inst[pat.head.name] = inst_t else: # If the variable is already instantiated, apply the # instantiation, simplify, and match again. pat2 = inst[pat.head.name](*pat.args).beta_norm() match(pat2, t.beta_norm(), instsp, bd_vars) elif pat.ty != t.ty: # In all other cases, top-level structure of the term # must agree. raise MatchException elif pat.is_var(): # The case where pat come from a bound variable. if pat.name != t.name: raise MatchException elif pat.is_const(): # When pat is a constant, t must also be a constant with # the same name and matching type. if pat.name != t.name: raise MatchException else: try: pat.T.match_incr(t.T, tyinst, internal_only=True) except TypeMatchException: raise MatchException elif pat.is_comb(): # In the combination case (where the head is not a variable), # match fun and arg. if is_pattern(pat.fun, list(instsp[1].keys())): match(pat.fun, t.fun, instsp, bd_vars) match(pat.arg, t.arg, instsp, bd_vars) else: match(pat.arg, t.arg, instsp, bd_vars) match(pat.fun, t.fun, instsp, bd_vars) elif pat.is_abs(): # When pat is a lambda term, t must also be a lambda term. # Replace bound variable by a variable, then match the body. try: pat.var_T.match_incr(t.var_T, tyinst, internal_only=True) except TypeMatchException: raise MatchException T = pat.var_T.subst(tyinst) v = Var(pat.var_name, T) pat_body = pat.subst_type(tyinst).subst_bound(v) t_body = t.subst_bound(v) match(pat_body, t_body, instsp, bd_vars + [v]) elif pat.is_bound(): raise MatchException else: raise TypeError
# Author: Bohua Zhan import unittest from kernel.type import TVar, TFun, NatType from kernel.term import Var, Eq, Nat from kernel.thm import Thm from kernel import theory from logic import basic from data import nat from data import function from data.function import mk_fun_upd, strip_fun_upd Ta = TVar("a") Tb = TVar("b") f = Var("f", TFun(Ta, Tb)) a1 = Var("a1", Ta) a2 = Var("a2", Ta) b1 = Var("b1", Ta) b2 = Var("b2", Ta) zero = nat.zero one = nat.one def fun_upd_of_seq(*ns): return mk_fun_upd(function.mk_const_fun(NatType, zero), *[Nat(n) for n in ns]) class FunctionTest(unittest.TestCase):
def testCheckProofFail7(self): """Typing error: type-checking failed.""" prf = Proof(Comb(Var("P", TFun(Tb, BoolType)), x)) self.assertRaisesRegex(CheckProofException, "typing error", theory.check_proof, prf)
def _check_proof_item(self, prf, seq, rpt, no_gaps, compute_only, check_level): """Check a single proof item. prf -- proof to be checked. seq -- proof item to be checked. rpt -- report for proof-checking. Modified by the function. no_gaps -- disable gaps. compute_only -- only executes rule if theorem is not present. check_level -- trust level for proof checking. Trust all macros with macro.level <= self.check_level. """ if seq.rule == "": # Empty line in the proof return None if seq.rule == "sorry": # Gap in the proof assert seq.th is not None, "sorry must have explicit statement." if no_gaps: raise CheckProofException("gaps are not allowed") if rpt is not None: rpt.add_gap(seq.th) return None if compute_only and seq.th is not None: # In compute_only mode, skip when a theorem exists. However, # subproofs still need to be checked. if seq.rule == "subproof": for s in seq.subproof.items: self._check_proof_item(prf, s, rpt, no_gaps, compute_only, check_level) return None if seq.rule == "theorem": # Copies an existing theorem in the theory into the proof. try: res_th = self.get_theorem(seq.args) if rpt is not None: rpt.apply_theorem(seq.args) except TheoryException: raise CheckProofException("theorem not found") elif seq.rule == "variable": # Declares a variable. Skip check. nm, T = seq.args res_th = Thm.mk_VAR(Var(nm, T)) elif seq.rule == "subproof": for s in seq.subproof.items: self._check_proof_item(prf, s, rpt, no_gaps, compute_only, check_level) res_th = seq.subproof.items[-1].th else: # Otherwise, apply one of the proof methods. First, we # obtain list of previous sequents used by the proof method: prev_ths = [] assert isinstance(seq.prevs, list), "prevs should be a list" for prev in seq.prevs: if not seq.id.can_depend_on(prev): raise CheckProofException("id %s cannot depend on %s" % (seq.id, prev)) try: prev_ths.append(prf.find_item(prev).th) except ProofStateException: raise CheckProofException("previous item not found") for prev, prev_th in zip(seq.prevs, prev_ths): if prev_th is None: raise CheckProofException("previous theorem %s is None" % prev) if seq.rule in primitive_deriv: # If the method is one of the primitive derivations, obtain and # apply that primitive derivation. rule_fun, _ = primitive_deriv[seq.rule] try: res_th = rule_fun( *prev_ths) if seq.args is None else rule_fun( seq.args, *prev_ths) if rpt is not None: rpt.apply_primitive_deriv() except InvalidDerivationException: raise CheckProofException("invalid derivation") except TypeError: raise CheckProofException("invalid input to derivation " + seq.rule) elif has_macro(seq.rule): # Otherwise, the proof method corresponds to a macro. If # the level of the macro is less than or equal to the current # trust level, simply evaluate the macro to check that results # match. Otherwise, expand the macro and check all of the steps. macro = get_macro(seq.rule) assert macro.level is None or (isinstance(macro.level, int) and macro.level >= 0), \ ("check_proof: invalid macro level " + str(macro.level)) if macro.level is not None and macro.level <= check_level: res_th = macro.eval(seq.args, prev_ths) if rpt is not None: rpt.eval_macro(seq.rule) else: seq.subproof = macro.expand(seq.id, seq.args, list(zip(seq.prevs, prev_ths))) if rpt is not None: rpt.expand_macro(seq.rule) for s in seq.subproof.items: self._check_proof_item(prf, s, rpt, no_gaps, compute_only, check_level) res_th = seq.subproof.items[-1].th seq.subproof = None else: raise CheckProofException("proof method not found: " + seq.rule) if seq.th is None: # No expected theorem is provided seq.th = res_th elif not res_th.can_prove(seq.th): # Resulting res_th is OK as long as the conclusion is the same, # and the assumptions is a subset of that of seq.th. raise CheckProofException("output does not match\n" + str(seq.th) + "\n vs.\n" + str(res_th)) # Check the current statement is correctly typed. try: seq.th.check_thm_type() except TypeCheckException: raise CheckProofException("typing error") return None
def exists_notype(self, var_name, body): exists_t = Const("exists", None) return exists_t( Abs(var_name, None, body.abstract_over(Var(var_name, None))))
def testForallElimFail2(self): P = Var("P", TFun(Ta, boolT)) th = Thm([], Term.mk_all(x, P(x))) self.assertRaises(InvalidDerivationException, Thm.forall_elim, A, th)
def testForallElim(self): P = Var("P", TFun(Ta, boolT)) th = Thm([], Term.mk_all(x, P(x))) self.assertEqual(Thm.forall_elim(y, th), Thm([], P(y)))
def testAbstractOverFail2(self): th = Thm.mk_equals(x, y) self.assertRaises(InvalidDerivationException, Thm.abstraction, Var("x", Tb), th)
def testSubstitutionFail(self): x_eq_y = Term.mk_equals(x, y) th = Thm([x_eq_y], x_eq_y) self.assertRaises(InvalidDerivationException, Thm.substitution, {"x": Var("a", Tb)}, th)
def abs_notype(self, var_name, body): return Abs(var_name, None, body.abstract_over(Var(var_name, None)))
def all_notype(self, var_name, body): all_t = Const("all", None) return all_t( Abs(var_name, None, body.abstract_over(Var(var_name, None))))
import unittest from kernel import type as hol_type from kernel.type import STVar, TVar, TFun, TyInst from kernel import term from kernel.term import SVar, Var, Const, Comb, Abs, Bound, And, Or, Lambda, Binary, Inst from kernel.term import TermException, TypeCheckException Ta = TVar("a") Tb = TVar("b") STa = STVar("a") STb = STVar("b") Taa = TFun(Ta, Ta) # 'a => 'a Tab = TFun(Ta, Tb) # 'a => 'b Taab = TFun(Ta, Ta, Tb) # 'a => 'a => 'b a = Var("a", Ta) b = Var("b", Tb) c = Const("c", Ta) f = Var("f", Tab) # f: 'a => 'b f2 = Var("f2", Taab) # f2: 'a => 'a => 'b g = Var("g", Taa) # g: 'a => 'a B0 = Bound(0) B1 = Bound(1) class TermTest(unittest.TestCase): def setUp(self): self.type_printer, self.term_printer = hol_type.type_printer, term.term_printer hol_type.type_printer, term.term_printer = None, None def tearDown(self):
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 testAbstractOverFail2(self): self.assertRaises(TermException, a.abstract_over, Var("a", Tb))
import unittest from kernel.type import TConst, TVar, STVar, TFun, BoolType from kernel.term import Term, SVar, Var, Const, Comb, Abs, Bound, Implies, Eq, Inst, TyInst from kernel.thm import Thm from kernel.proof import Proof, ItemID from kernel import theory from kernel.theory import Theory, TheoryException, CheckProofException from kernel import extension from kernel.report import ProofReport, ExtensionReport Ta = TVar("a") Tb = TVar("b") Tab = TFun(Ta, Tb) x = Var("x", Ta) y = Var("y", Ta) z = Var("z", Ta) f = Var("f", Tab) A = Var("A", BoolType) B = Var("B", BoolType) C = Var("C", BoolType) class TheoryTest(unittest.TestCase): def setUp(self): theory.thy = theory.EmptyTheory() def testEmptyTheory(self): self.assertEqual(theory.thy.get_type_sig("bool"), 0) self.assertEqual(theory.thy.get_type_sig("fun"), 2)
"Q": TFun(Ta, boolT), "R": TFun(Ta, Ta, boolT), "a": Ta, "b": Ta, "c": Ta, "f": TFun(Ta, Ta), "nn": TFun(boolT, boolT), "m": nat.natT, "n": nat.natT, "p": nat.natT, "xs": Type("list", Ta), "ys": Type("list", Ta), "zs": Type("list", Ta), } A = Var("A", boolT) B = Var("B", boolT) C = Var("C", boolT) class ParserTest(unittest.TestCase): def testParseType(self): test_data = [ "'b", "nat", "'a list", "nat list", "('a, 'b) prod", "nat list list", "(nat, 'a) prod", "'a => 'b",
def term(self): return Var(self.name)
import unittest from kernel.type import TVar, Type, TFun, boolT from kernel.term import Var, Const, Comb, Abs, Bound, Term from kernel.thm import Thm from logic import logic from logic import nat from logic import list from logic import set from logic import basic from logic import function from syntax import printer thy = basic.load_theory('list') A = Var("A", boolT) B = Var("B", boolT) C = Var("C", boolT) Ta = TVar("a") a = Var("a", Ta) b = Var("b", Ta) P = Var("P", TFun(Ta, boolT)) Q = Var("Q", TFun(Ta, boolT)) R = Var("R", TFun(Ta, Ta, boolT)) f = Var("f", TFun(Ta, Ta)) nn = Var("n", TFun(boolT, boolT)) m = Var("m", nat.natT) n = Var("n", nat.natT) p = Var("p", nat.natT) xs = Var("xs", Type("list", Ta)) ys = Var("ys", Type("list", Ta))
# Author: Bohua Zhan import unittest from kernel.type import TVar, TFun from kernel.term import Var, Term, Eq from kernel.thm import Thm from kernel.proof import Proof from kernel import theory from logic import basic from kernel.proofterm import ProofTerm basic.load_theory('logic_base') Ta = TVar("a") x = Var("x", Ta) y = Var("y", Ta) z = Var("z", Ta) f = Var("f", TFun(Ta, Ta, Ta)) class ProofTermTest(unittest.TestCase): 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 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 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 Implies(guard, inv_after) elif hint == PRE: return 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 = Inst((nm, Var(subst_var, NatType)) for nm, subst_var in zip(inv_var_nms, subst_vars)) inv_subst = inv.subst(subst) return Implies(inv_subst, guard, inv_after)
from kernel.thm import Thm from kernel.proof import Proof from kernel.report import ProofReport from logic import logic from logic import basic from logic import nat from logic import list from logic import function from syntax import printer from server import server from server import method from server.server import ProofState thy = basic.load_theory('logic_base') A = Var("A", boolT) B = Var("B", boolT) conj = logic.mk_conj disj = logic.mk_disj imp = Term.mk_implies neg = logic.neg exists = logic.mk_exists class ServerTest(unittest.TestCase): def testIncrIdAfter(self): test_data = [ (((0,), (0,), 1), (1,),), (((0, 1), (0,), 1), (1, 1)), (((1,), (2, 2), 1), (1,)), (((2, 1), (2, 2), 1), (2, 1)),
def get_nat_power_bounds(pt, n): """Given theorem of the form t Mem I, obtain a theorem of the form t ^ n Mem J. """ a, b = get_mem_bounds(pt) if not n.is_number(): raise NotImplementedError if eval_hol_expr(a) >= 0 and is_mem_closed(pt): pt = apply_theorem('nat_power_interval_pos_closed', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(a) >= 0 and is_mem_open(pt): pt = apply_theorem('nat_power_interval_pos_open', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(a) >= 0 and is_mem_lopen(pt): pt = apply_theorem('nat_power_interval_pos_lopen', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(a) >= 0 and is_mem_ropen(pt): pt = apply_theorem('nat_power_interval_pos_ropen', auto.auto_solve(real_nonneg(a)), pt, inst=Inst(n=n)) elif eval_hol_expr(b) <= 0 and is_mem_closed(pt): int_n = n.dest_number() if int_n % 2 == 0: even_pt = nat_as_even(int_n) pt = apply_theorem('nat_power_interval_neg_even_closed', auto.auto_solve(real_nonpos(b)), even_pt, pt) else: odd_pt = nat_as_odd(int_n) pt = apply_theorem('nat_power_interval_neg_odd_closed', auto.auto_solve(real_nonpos(b)), odd_pt, pt) elif eval_hol_expr(b) <= 0 and is_mem_open(pt): int_n = n.dest_number() if int_n % 2 == 0: even_pt = nat_as_even(int_n) pt = apply_theorem('nat_power_interval_neg_even_open', auto.auto_solve(real_nonpos(b)), even_pt, pt) else: odd_pt = nat_as_odd(int_n) pt = apply_theorem('nat_power_interval_neg_odd_open', auto.auto_solve(real_nonpos(b)), odd_pt, pt) elif is_mem_closed(pt): # Closed interval containing 0 t = pt.prop.arg1 assm1 = hol_set.mk_mem(t, real.closed_interval(a, Real(0))) assm2 = hol_set.mk_mem(t, real.closed_interval(Real(0), b)) pt1 = get_nat_power_bounds(ProofTerm.assume(assm1), n).implies_intr(assm1) pt2 = get_nat_power_bounds(ProofTerm.assume(assm2), n).implies_intr(assm2) x = Var('x', RealType) pt = apply_theorem('split_interval_closed', auto.auto_solve(real.less_eq(a, Real(0))), auto.auto_solve(real.less_eq(Real(0), b)), pt1, pt2, pt, inst=Inst(x=t, f=Lambda(x, x**n))) subset_pt = interval_union_subset(pt.prop.arg) pt = apply_theorem('subsetE', subset_pt, pt) elif is_mem_open(pt): # Open interval containing 0 t = pt.prop.arg1 assm1 = hol_set.mk_mem(t, real.open_interval(a, Real(0))) assm2 = hol_set.mk_mem(t, real.ropen_interval(Real(0), b)) pt1 = get_nat_power_bounds(ProofTerm.assume(assm1), n).implies_intr(assm1) pt2 = get_nat_power_bounds(ProofTerm.assume(assm2), n).implies_intr(assm2) x = Var('x', RealType) pt = apply_theorem('split_interval_open', auto.auto_solve(real.less_eq(a, Real(0))), auto.auto_solve(real.less_eq(Real(0), b)), pt1, pt2, pt, inst=Inst(x=t, f=Lambda(x, x**n))) subset_pt = interval_union_subset(pt.prop.arg) pt = apply_theorem('subsetE', subset_pt, pt) else: raise NotImplementedError return norm_mem_interval(pt)
def testRewriteGoalThms(self): thy = basic.load_theory('nat') n = Var("n", nat.natT) state = ProofState.init_state(thy, [n], [], Term.mk_equals(nat.plus(nat.zero, n), n)) search_res = state.apply_search(0, method.rewrite_goal()) self.assertEqual([res['theorem'] for res in search_res], ["plus_def_1"])