def testEvalFunUpd(self): f = fun_upd_of_seq(1, 5) cv = function.fun_upd_eval_conv() prf = cv.get_proof_term(thy, f(one)).export() self.assertEqual(thy.check_proof(prf), Thm.mk_equals(f(one), five)) prf = cv.get_proof_term(thy, f(zero)).export() self.assertEqual(thy.check_proof(prf), Thm.mk_equals(f(zero), zero))
def testRewrite2(self): Ta = TVar("a") a = Var("a", Ta) b = Var("b", Ta) eq_a = Term.mk_equals(a, a) goal = Thm.mk_equals(mk_if(eq_a, b, a), b) rewrite_tac = tactic.rewrite() pt = rewrite_tac.get_proof_term(thy, ProofTerm.sorry(goal), args='if_P') prf = pt.export() self.assertEqual(prf.items[0], ProofItem(0, 'sorry', th=Thm.mk_equals(a, a))) self.assertEqual(thy.check_proof(prf), goal)
def testExport3(self): """Case with atoms.""" pt1 = ProofTerm.atom(0, Thm.mk_equals(x, y)) pt2 = ProofTerm.atom(1, Thm.mk_equals(y, z)) pt3 = ProofTerm.transitive(pt1, pt2) prf = Proof() prf.add_item(0, rule="sorry", th=Thm.mk_equals(x, y)) prf.add_item(1, rule="sorry", th=Thm.mk_equals(y, z)) pt3.export(prf=prf) self.assertEqual(thy.check_proof(prf), Thm.mk_equals(x, z))
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 testRewrite(self): n = Var('n', natT) goal = Thm.mk_equals(plus(zero, n), n) rewrite_tac = tactic.rewrite() pt = rewrite_tac.get_proof_term(thy, ProofTerm.sorry(goal), args='plus_def_1') prf = pt.export() self.assertEqual(thy.check_proof(prf), goal)
def testCheckProofMacro(self): """Proof checking with simple macro.""" thy = Theory.EmptyTheory() thy.add_proof_macro("beta_conv_rhs", beta_conv_rhs_macro()) t = Comb(Abs("x", Ta, Bound(0)), x) prf = Proof() prf.add_item(0, "reflexive", args=t) prf.add_item(1, "beta_conv_rhs", prevs=[0]) th = Thm.mk_equals(t,x) # Check obtaining signature self.assertEqual(thy.get_proof_rule_sig("beta_conv_rhs"), Term) # Check proof without trusting beta_conv_rhs rpt = ProofReport() self.assertEqual(thy.check_proof(prf, rpt), th) self.assertEqual(rpt.steps_stat(), (0, 3, 0)) self.assertEqual(rpt.macros_expand, {"beta_conv_rhs"}) # Check proof while trusting beta_conv_rhs rpt = ProofReport() self.assertEqual(thy.check_proof(prf, rpt, check_level=1), th) self.assertEqual(rpt.steps_stat(), (0, 1, 1)) self.assertEqual(rpt.macros_eval, {"beta_conv_rhs"})
def testNormFull(self): test_data = [ ("(x * y) * (z * y)", "x * y * y * z"), ("(x + y) + (z + y)", "x + y * 2 + z"), ("(x + y) * (y + z)", "x * y + x * z + y * y + y * z"), ("(x + y) * (x + y)", "x * x + x * y * 2 + y * y"), ("0 + 1 * x + 0 * y", "x"), ("x + 2 + y + 3", "x + y + 5"), ("3 * x * 5 * x", "x * x * 15"), ("(x + 2 * y) * (y + 2 * x)", "x * x * 2 + x * y * 5 + y * y * 2"), ("3 + 5 * 2", "13"), ("x + Suc y", "x + y + 1"), ("Suc (x + Suc y)", "x + y + 2"), ("x * Suc y", "x + x * y"), ("x * 1 * 1 * 1", "x"), ] cv = nat.norm_full() ctxt = {"x": nat.natT, "y": nat.natT, "z": nat.natT} for expr, res in test_data: t = parser.parse_term(thy, ctxt, expr) t2 = parser.parse_term(thy, ctxt, res) res_th = Thm.mk_equals(t, t2) prf = cv.get_proof_term(thy, t).export() self.assertEqual(thy.check_proof(prf), res_th)
def testRewriteGoalWithAssum(self): Ta = TVar("a") a = Var("a", Ta) b = Var("b", Ta) eq_a = Term.mk_equals(a, a) if_t = logic.mk_if(eq_a, b, a) state = ProofState.init_state(thy, [a, b], [], Term.mk_equals(if_t, b)) state.rewrite_goal(0, "if_P") state.set_line(0, "reflexive", args=a) self.assertEqual(state.check_proof(no_gaps=True), Thm.mk_equals(if_t, b))
def testMultZeroRight(self): """Proof of n * 0 = 0 by induction.""" thy = basic.load_theory('nat') n = Var("n", nat.natT) state = ProofState.init_state(thy, [n], [], Term.mk_equals(nat.times(n, nat.zero), nat.zero)) state.apply_induction(0, "nat_induct", "n") state.rewrite_goal(0, "times_def_1") state.introduction(1, names=["n"]) state.rewrite_goal((1, 2), "times_def_2") state.rewrite_goal((1, 2), "plus_def_1") self.assertEqual(state.check_proof(no_gaps=True), Thm.mk_equals(nat.times(n, nat.zero), nat.zero))
def testSucConv(self): test_data = [ 0, 1, 2, 3, 4, 5, 6, 7, 19, 127, 1000, 1001, ] cv = nat.Suc_conv() for n in test_data: t = nat.Suc(nat.to_binary(n)) res_th = Thm.mk_equals(t, nat.to_binary(n + 1)) 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 testNatEqConv(self): test_data = [ ((zero, zero), logic.true), ((one, one), logic.true), ((zero, one), logic.false), ] cv = nat.nat_eq_conv() for (a, b), res in test_data: t = Term.mk_equals(a, b) prf = cv.get_proof_term(thy, t).export() res_th = Thm.mk_equals(t, res) self.assertEqual(thy.check_proof(prf), res_th)
def testNormConjAssoc(self): conj = logic.mk_conj test_data = [ (a, a), (conj(a, b), conj(a, b)), (conj(conj(a, b), conj(c, d)), conj(a, b, c, d)), (conj(conj(conj(a, b), c), d), conj(a, b, c, d)), ] thy = basic.load_theory('logic') for t, res in test_data: cv = logic.norm_conj_assoc() prf = cv.get_proof_term(thy, t).export() self.assertEqual(thy.check_proof(prf), Thm.mk_equals(t, res))
def testNormBoolExpr(self): neg, true, false = logic.neg, logic.true, logic.false test_data = [ (true, true), (false, false), (neg(true), false), (neg(false), true), ] thy = basic.load_theory('logic') for t, res in test_data: cv = logic.norm_bool_expr() prf = cv.get_proof_term(thy, t).export() self.assertEqual(thy.check_proof(prf), Thm.mk_equals(t, res))
def testAppendNil(self): """Proof of xs @ [] = xs by induction.""" thy = basic.load_theory('list') Ta = TVar("a") xs = Var("xs", list.listT(Ta)) nil = list.nil(Ta) state = ProofState.init_state(thy, [xs], [], Term.mk_equals(list.mk_append(xs, nil), xs)) state.apply_induction(0, "list_induct", "xs") state.apply_backward_step(0, "append_def_1") state.introduction(1, names=["x", "xs"]) state.rewrite_goal((1, 3), "append_def_2") self.assertEqual(state.get_ctxt((1, 3)), {'x': Ta, 'xs': list.listT(Ta)}) state.rewrite_goal_with_prev((1, 3), (1, 2)) self.assertEqual(state.check_proof(no_gaps=True), Thm.mk_equals(list.mk_append(xs, nil), xs))
def testUncheckedExtend(self): """Unchecked extension.""" thy = Theory.EmptyTheory() thy_ext = TheoryExtension() id_const = Const("id", TFun(Ta,Ta)) id_def = Abs("x", Ta, Bound(0)) id_simps = Term.mk_equals(id_const(x), x) thy_ext.add_extension(Constant("id", id_def)) thy_ext.add_extension(Theorem("id.simps", Thm([], id_simps))) self.assertEqual(thy.unchecked_extend(thy_ext), None) self.assertEqual(thy.get_term_sig("id"), TFun(Ta, Ta)) self.assertEqual(thy.get_theorem("id_def"), Thm.mk_equals(id_const, id_def)) self.assertEqual(thy.get_theorem("id.simps"), Thm([], id_simps))
def eval(self, thy, t): def val(t): """Evaluate the given term.""" if is_binary(t): return from_binary(t) else: if t.head == Suc: return val(t.arg) + 1 elif t.head == plus: return val(t.arg1) + val(t.arg) elif t.head == times: return val(t.arg1) * val(t.arg) else: raise ConvException() return Thm.mk_equals(t, to_binary(val(t)))
def testNatConv(self): test_data = [ ("2 + 3", 5), ("Suc (2 + 3)", 6), ("Suc (Suc (Suc 0))", 3), ("5 + 2 * 3", 11), ("(5 + 2) * 3", 21), ("5 * Suc (2 + 5)", 40), ] cv = nat.nat_conv() for expr, n in test_data: t = parser.parse_term(thy, {}, expr) res_th = Thm.mk_equals(t, nat.to_binary(n)) 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 load_system(filename): dn = os.path.dirname(os.path.realpath(__file__)) with open(os.path.join(dn, 'examples/' + filename + '.json'), encoding='utf-8') as a: data = json.load(a) thy = basic.load_theory('gcl') name = data['name'] vars = [] for nm, str_T in data['vars'].items(): T = parser.parse_type(thy, str_T) vars.append(Var(nm, T)) for i, nm in enumerate(data['states']): thy.add_term_sig(nm, natT) thy.add_theorem(nm + "_def", Thm.mk_equals(Const(nm, natT), to_binary(i))) states = [Const(nm, natT) for nm in data['states']] rules = [] for rule in data['rules']: if isinstance(rule['var'], str): rule_var = Var(rule['var'], natT) ctxt = dict((v.name, v.T) for v in vars + [rule_var]) else: assert isinstance(rule['var'], list) rule_var = [Var(nm, natT) for nm in rule['var']] ctxt = dict((v.name, v.T) for v in vars + rule_var) guard = parser.parse_term(thy, ctxt, rule['guard']) assign = dict() for k, v in rule['assign'].items(): assign[parser.parse_term(thy, ctxt, k)] = parser.parse_term(thy, ctxt, v) rules.append((rule_var, guard, assign)) invs = [] for inv in data['invs']: inv_vars = [Var(nm, natT) for nm in inv['vars']] ctxt = dict((v.name, v.T) for v in vars + inv_vars) prop = parser.parse_term(thy, ctxt, inv['prop']) invs.append((inv_vars, prop)) return ParaSystem(thy, name, vars, states, rules, invs)
def testNormFunUpd(self): test_data = [ ((0, 1), (0, 1)), ((1, 0, 0, 5), (0, 5, 1, 0)), ((0, 1, 1, 5), (0, 1, 1, 5)), ((2, 0, 1, 1), (1, 1, 2, 0)), ((2, 0, 1, 1, 0, 2), (0, 2, 1, 1, 2, 0)), ((0, 1, 0, 2), (0, 2)), ((2, 0, 1, 1, 2, 1, 1, 2), (1, 2, 2, 1)), ] for n_f, n_res in test_data: f = fun_upd_of_seq(*n_f) res = fun_upd_of_seq(*n_res) cv = function.fun_upd_norm_conv() prf = cv.get_proof_term(thy, f).export() self.assertEqual(thy.check_proof(prf), Thm.mk_equals(f, res))
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 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 testMultConv(self): test_data = [ (0, 2), (2, 0), (1, 2), (2, 1), (2, 2), (2, 3), (3, 2), (3, 3), (5, 5), (10, 5), (123,987), ] cv = nat.mult_conv() for m, n in test_data: t = nat.mk_times(nat.to_binary(m), nat.to_binary(n)) res_th = Thm.mk_equals(t, nat.to_binary(m * n)) 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 get_eq_thm(self): """Return the equality theorem to be added in the Constant extension.""" assert self.ty == Extension.CONSTANT, "get_eq_thm" return Thm.mk_equals(self.get_const_term(), self.expr)
def testForallIntr(self): th = Thm.mk_equals(x, y) t_res = Term.mk_all(x, Term.mk_equals(x, y)) self.assertEqual(Thm.forall_intr(x, th), Thm([], t_res))
def testAbstractOverFail3(self): th = Thm.mk_equals(x, y) self.assertRaises(InvalidDerivationException, Thm.abstraction, f(x), th)
def testForallIntr2(self): """Also OK if the variable does not appear in theorem.""" th = Thm.mk_equals(x, y) t_res = Term.mk_all(z, Term.mk_equals(x, y)) self.assertEqual(Thm.forall_intr(z, th), Thm([], t_res))
def testForallIntrFail2(self): th = Thm.mk_equals(x, y) self.assertRaises(InvalidDerivationException, Thm.forall_intr, Const("c", Ta), th)
def testForallElimFail(self): th = Thm.mk_equals(x, y) self.assertRaises(InvalidDerivationException, Thm.forall_elim, x, th)
def testReflexive(self): self.assertEqual(Thm.reflexive(x), Thm.mk_equals(x, x))
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 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 == "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 elif 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 v = Var(nm, T) res_th = Thm.mk_equals(v, v) 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: try: prev_ths.append(prf.find_item(prev).th) except ProofException: raise CheckProofException("previous item not found") 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 self.has_proof_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 = self.get_proof_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(self, seq.args, prev_ths) if rpt is not None: rpt.eval_macro(seq.rule) else: seq.subproof = macro.expand(seq.id, self, 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