def __init__(self, rule, args, prevs=None, th=None): typecheck.checkinstance('ProofTerm', rule, str) self.rule = rule if prevs is None: prevs = [] prev_ths = [prev.th for prev in prevs] if rule == 'atom': assert th is not None, "ProofTerm: must provide th for atom." self.th = th elif rule == 'sorry': assert th is not None, "ProofTerm: must provide th for sorry." self.th = th elif rule == 'variable': nm, T = args self.th = Thm.mk_VAR(Var(nm, T)) elif rule == 'theorem': self.th = theory.get_theorem(args) elif rule in primitive_deriv: rule_fun, _ = primitive_deriv[rule] self.th = rule_fun(*prev_ths) if args is None else rule_fun(args, *prev_ths) else: macro = theory.get_macro(rule) if th is None: self.th = macro.eval(args, prev_ths) else: self.th = th self.args = args self.prevs = prevs if self.rule == 'sorry': self.gaps = [self.th] else: self.gaps = list(set(sum([prev.gaps for prev in self.prevs], [])))
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