def testAbsConv(self): nat0 = Const("zero", natT) nat1 = Const("one", natT) f = Const("f", TFun(natT, natT)) g = Const("g", TFun(natT, natT)) x = Var("x", natT) thy.add_theorem("f_eq_g", eq(f(x), g(x))) t = Term.mk_abs(x, f(x)) cv = abs_conv(rewr_conv("f_eq_g")) res_th = eq(t, Term.mk_abs(x, g(x))) self.assertEqual(cv.eval(thy, t), res_th) prf = cv.get_proof_term(thy, t).export() self.assertEqual(thy.check_proof(prf), res_th)
def testRule4(self): n = Var('n', natT) goal = Thm([], Term.mk_equals(plus(n, zero), n)) inst = {'P': Term.mk_abs(n, goal.prop), 'x': n} pt = tactic.rule().get_proof_term(thy, ProofTerm.sorry(goal), args=('nat_induct', ({}, inst))) prf = pt.export() self.assertEqual(thy.check_proof(prf), goal)
def testInferPrintedType(self): t = Const("nil", listT(Ta)) infer_printed_type(thy, t) self.assertTrue(hasattr(t, "print_type")) t = list.cons(Ta)(Var("a", Ta)) infer_printed_type(thy, t) self.assertFalse(hasattr(t.fun, "print_type")) t = Term.mk_equals(Const("nil", listT(Ta)), Const("nil", listT(Ta))) infer_printed_type(thy, t) self.assertFalse(hasattr(t.fun.fun, "print_type")) self.assertTrue(hasattr(t.arg1, "print_type")) self.assertFalse(hasattr(t.arg, "print_type")) t = Term.mk_equals(list.mk_append(list.nil(Ta), list.nil(Ta)), list.nil(Ta)) infer_printed_type(thy, t) self.assertTrue(hasattr(t.arg1.arg1, "print_type")) self.assertFalse(hasattr(t.arg1.arg, "print_type")) self.assertFalse(hasattr(t.arg, "print_type")) t = Term.mk_abs(Var("x", Ta), Term.mk_equals(Var("x", Ta), Var("x", Ta))) infer_printed_type(thy, t)
def mk_exists(x, body): """Given a variable x and a term t possibly depending on x, return the term ?x. t. """ exists_t = Const("exists", TFun(TFun(x.T, boolT), boolT)) return exists_t(Term.mk_abs(x, body))
def testAddZeroRightWithMacro(self): """Proof of n + 0 = n by induction, using macros.""" thy = basic.load_theory('nat') n = Var("n", nat.natT) eq = Term.mk_equals plus = nat.plus zero = nat.zero S = nat.Suc prf = Proof() prf.add_item(0, "reflexive", args=zero) prf.add_item(1, "rewrite_goal", args=("plus_def_1", eq(plus(zero, zero), zero)), prevs=[0]) prf.add_item(2, "assume", args=eq(plus(n, zero), n)) prf.add_item(3, "arg_combination", args=S, prevs=[2]) prf.add_item(4, "rewrite_goal", args=("plus_def_2", eq(plus(S(n), zero), S(n))), prevs=[3]) prf.add_item(5, "implies_intr", args=eq(plus(n, zero), n), prevs=[4]) prf.add_item(6, "forall_intr", args=n, prevs=[5]) prf.add_item(7, "apply_theorem_for", args=("nat_induct", {}, { "P": Term.mk_abs(n, eq(plus(n, zero), n)), "x": n }), prevs=[1, 6]) th = Thm.mk_equals(plus(n, zero), n) self.assertEqual(thy.check_proof(prf), th)
def compute_wp(thy, T, c, Q): """Compute the weakest precondition for the given command and postcondition. The computation is by case analysis on the form of c. Returns the validity theorem. """ if c.head.is_const_name("Assign"): # Assign a b a, b = c.args s = Var("s", T) P2 = Term.mk_abs(s, Q(function.mk_fun_upd(s, a, b(s).beta_conv()))) return apply_theorem(thy, "assign_rule", inst={"b": b}, concl=Valid(T)(P2, c, Q)) elif c.head.is_const_name("Seq"): # Seq c1 c2 c1, c2 = c.args wp1 = compute_wp(thy, T, c2, Q) # Valid Q' c2 Q wp2 = compute_wp(thy, T, c1, wp1.prop.args[0]) # Valid Q'' c1 Q' return apply_theorem(thy, "seq_rule", wp2, wp1) elif c.head.is_const_name("While"): # While b I c _, I, _ = c.args pt = apply_theorem(thy, "while_rule", concl=Valid(T)(I, c, Q)) pt0 = ProofTerm.assume(pt.assums[0]) pt1 = vcg(thy, T, pt.assums[1]) return ProofTerm.implies_elim(pt, pt0, pt1) else: raise NotImplementedError
def abstraction(x, th): """Derivation rule ABSTRACTION: A |- t1 = t2 ------------------------ A |- (%x. t1) = (%x. t2) where x does not occur in A. """ if any(hyp.occurs_var(x) for hyp in th.hyps): raise InvalidDerivationException("abstraction") elif th.prop.is_equals(): t1, t2 = th.prop.args try: t1_new, t2_new = (Term.mk_abs(x, t1), Term.mk_abs(x, t2)) except TermSubstitutionException: raise InvalidDerivationException("abstraction") return Thm(th.hyps, Term.mk_equals(t1_new, t2_new)) else: raise InvalidDerivationException("abstraction")
def get_proof_term(self, thy, goal, *, args=None, prevs=None): th_name, var = args P = Term.mk_abs(var, goal.prop) th = thy.get_theorem(th_name) f, args = th.concl.strip_comb() if len(args) != 1: raise NotImplementedError inst = {f.name: P, args[0].name: var} return rule().get_proof_term(thy, goal, args=(th_name, ({}, inst)))
def process_file(input, output): thy = basic.load_theory('hoare') dn = os.path.dirname(os.path.realpath(__file__)) with open(os.path.join(dn, 'examples/' + input + '.json'), encoding='utf-8') as a: data = json.load(a) output = json_output.JSONTheory(output, ["hoare"], "Generated from " + input) content = data['content'] eval_count = 0 vcg_count = 0 for run in content: if run['ty'] == 'eval': com = parse_hoare(run['com']) st1 = mk_const_fun(nat.natT, nat.zero) for k, v in sorted(run['init'].items()): st1 = mk_fun_upd(st1, nat.to_binary(str_to_nat(k)), nat.to_binary(v)) st2 = mk_const_fun(nat.natT, nat.zero) for k, v in sorted(run['final'].items()): st2 = mk_fun_upd(st2, nat.to_binary(str_to_nat(k)), nat.to_binary(v)) Sem = hoare.Sem(natFunT) goal = Sem(com, st1, st2) prf = ProofTermDeriv("eval_Sem", thy, goal, []).export() rpt = ProofReport() th = thy.check_proof(prf, rpt) output.add_theorem("eval" + str(eval_count), th, prf) eval_count += 1 elif run['ty'] == 'vcg': com = parse_hoare(run['com']) pre = Term.mk_abs(st, parse_cond(run['pre'])) post = Term.mk_abs(st, parse_cond(run['post'])) Valid = hoare.Valid(natFunT) goal = Valid(pre, com, post) prf = hoare.vcg_solve(thy, goal).export() rpt = ProofReport() th = thy.check_proof(prf, rpt) output.add_theorem("vcg" + str(vcg_count), th, prf) vcg_count += 1 else: raise TypeError() output.export_json()
def testMultZeroRight(self): """Proof of n * 0 = 0 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.times(n, nat.zero), nat.zero)), "x": n }, prevs=[0]) prf.add_item(2, "beta_norm", prevs=[1]) prf.add_item(3, "theorem", args="times_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.times(n, nat.zero), nat.zero)) prf.add_item(7, "theorem", args="times_def_2") prf.add_item(8, "substitution", args={ "m": n, "n": nat.zero }, prevs=[7]) prf.add_item(9, "theorem", args="plus_def_1") prf.add_item(10, "substitution", args={"n": nat.times(n, nat.zero)}, prevs=[9]) prf.add_item(11, "transitive", prevs=[8, 10]) prf.add_item(12, "transitive", prevs=[11, 6]) prf.add_item(13, "implies_intr", args=eq(nat.times(n, nat.zero), nat.zero), prevs=[12]) prf.add_item(14, "forall_intr", args=n, prevs=[13]) prf.add_item(15, "implies_elim", prevs=[5, 14]) th = Thm.mk_equals(nat.times(n, nat.zero), nat.zero) self.assertEqual(thy.check_proof(prf), th)
def testBetaNorm(self): thy = basic.load_theory('logic_base') t = Term.mk_abs(x, f(x)) prf = Proof(Term.mk_equals(t(x), y)) prf.add_item(1, "beta_norm", prevs=[0]) prf.add_item(2, "implies_intr", args=Term.mk_equals(t(x), y), prevs=[1]) th = Thm.mk_implies(Term.mk_equals(t(x), y), Term.mk_equals(f(x), y)) rpt = ProofReport() self.assertEqual(thy.check_proof(prf, rpt), th) self.assertEqual(rpt.prim_steps, 8) rpt2 = ProofReport() self.assertEqual(thy.check_proof(prf, rpt2, check_level=1), th) self.assertEqual(rpt2.prim_steps, 2) self.assertEqual(rpt2.macro_steps, 1)
def testMultZeroRightWithMacro(self): """Proof of n * 0 = 0 by induction, using macros.""" thy = basic.load_theory('nat') n = Var("n", nat.natT) eq = Term.mk_equals zero = nat.zero plus = nat.mk_plus times = nat.mk_times S = nat.Suc prf = Proof() prf.add_item(0, "reflexive", args=zero) prf.add_item(1, "rewrite_goal", args=("times_def_1", eq(times(zero, zero), zero)), prevs=[0]) prf.add_item(2, "assume", args=eq(times(n, zero), zero)) prf.add_item(3, "reflexive", args=times(n, zero)) prf.add_item(4, "rewrite_goal", args=("plus_def_1", eq(plus(zero, times(n, zero)), times(n, zero))), prevs=[3]) prf.add_item(5, "transitive", prevs=[4, 2]) prf.add_item(6, "rewrite_goal", args=("times_def_2", eq(times(S(n), zero), zero)), prevs=[5]) prf.add_item(7, "implies_intr", args=eq(times(n, zero), zero), prevs=[6]) prf.add_item(8, "forall_intr", args=n, prevs=[7]) prf.add_item(9, "apply_theorem_for", args=("nat_induct", {}, { "P": Term.mk_abs(n, eq(times(n, zero), zero)), "x": n }), prevs=[1, 8]) th = Thm.mk_equals(times(n, zero), zero) self.assertEqual(thy.check_proof(prf), th)
def while_cmd(self, b, c): While = hoare.While(natFunT) return While(Term.mk_abs(st, b), Term.mk_abs(st, logic.true), c)
def if_cmd(self, b, c1, c2): Cond = hoare.Cond(natFunT) return Cond(Term.mk_abs(st, b), c1, c2)
def assign_cmd(self, v, e): Assign = hoare.Assign(nat.natT, nat.natT) return Assign(nat.to_binary(str_to_nat(v)), Term.mk_abs(st, e))
def while_cmd_inv(self, b, inv, c): While = hoare.While(natFunT) return While(Term.mk_abs(st, b), Term.mk_abs(st, inv), c)
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
def testExistsConj(self): """Proof of (?x. A x & B x) --> (?x. A x) & (?x. B x).""" thy = basic.load_theory('logic_base') Ta = TVar("a") A = Var("A", TFun(Ta, boolT)) B = Var("B", TFun(Ta, boolT)) x = Var("x", Ta) conjAB = logic.mk_conj(A(x), B(x)) exists_conj = logic.mk_exists(x, conjAB) exists_A = logic.mk_exists(x, A(x)) exists_B = logic.mk_exists(x, B(x)) conj_exists = logic.mk_conj(exists_A, exists_B) prf = Proof(exists_conj) prf.add_item(1, "assume", args=conjAB) prf.add_item(2, "theorem", args="conjD1") prf.add_item(3, "substitution", args={"A": A(x), "B": B(x)}, prevs=[2]) prf.add_item(4, "implies_elim", prevs=[3, 1]) prf.add_item(5, "theorem", args="conjD2") prf.add_item(6, "substitution", args={"A": A(x), "B": B(x)}, prevs=[5]) prf.add_item(7, "implies_elim", prevs=[6, 1]) prf.add_item(8, "theorem", args="exI") prf.add_item(9, "substitution", args={"P": A, "a": x}, prevs=[8]) prf.add_item(10, "implies_elim", prevs=[9, 4]) prf.add_item(11, "substitution", args={"P": B, "a": x}, prevs=[8]) prf.add_item(12, "implies_elim", prevs=[11, 7]) prf.add_item(13, "implies_intr", args=conjAB, prevs=[10]) prf.add_item(14, "implies_intr", args=conjAB, prevs=[12]) prf.add_item(15, "forall_intr", args=x, prevs=[13]) prf.add_item(16, "forall_intr", args=x, prevs=[14]) prf.add_item(17, "theorem", args="exE") prf.add_item(18, "substitution", args={ "P": Term.mk_abs(x, conjAB), "C": exists_A }, prevs=[17]) prf.add_item(19, "beta_norm", prevs=[18]) prf.add_item(20, "implies_elim", prevs=[19, 0]) prf.add_item(21, "implies_elim", prevs=[20, 15]) prf.add_item(22, "substitution", args={ "P": Term.mk_abs(x, conjAB), "C": exists_B }, prevs=[17]) prf.add_item(23, "beta_norm", prevs=[22]) prf.add_item(24, "implies_elim", prevs=[23, 0]) prf.add_item(25, "implies_elim", prevs=[24, 16]) prf.add_item(26, "theorem", args="conjI") prf.add_item(27, "substitution", args={ "A": exists_A, "B": exists_B }, prevs=[26]) prf.add_item(28, "implies_elim", prevs=[27, 21]) prf.add_item(29, "implies_elim", prevs=[28, 25]) prf.add_item(30, "implies_intr", args=exists_conj, prevs=[29]) th = Thm.mk_implies(exists_conj, conj_exists) self.assertEqual(thy.check_proof(prf), th)