def get_proof_term(self, goal, *, args=None, prevs=None): if isinstance(args, tuple): th_name, inst = args else: th_name, inst = args, None assert isinstance(th_name, str), "rule: theorem name must be a string" if prevs is None: prevs = [] th = theory.get_theorem(th_name) As, C = th.assums, th.concl # Length of prevs is at most length of As assert len(prevs) <= len(As), "rule: too many previous facts" if inst is None: inst = Inst() # Match the conclusion and assumptions. Either the conclusion # or the list of assumptions must be a first-order pattern. if matcher.is_pattern(C, []): inst = matcher.first_order_match(C, goal.prop, inst) for pat, prev in zip(As, prevs): inst = matcher.first_order_match(pat, prev.prop, inst) else: for pat, prev in zip(As, prevs): inst = matcher.first_order_match(pat, prev.prop, inst) inst = matcher.first_order_match(C, goal.prop, inst) # Check that every variable in the theorem has an instantiation. unmatched_vars = [ v.name for v in term.get_svars(As + [C]) if v.name not in inst ] if unmatched_vars: raise theory.ParameterQueryException( list("param_" + name for name in unmatched_vars)) # Substitute and normalize As, _ = th.prop.subst_norm(inst).strip_implies() goal_Alen = len(goal.assums) if goal_Alen > 0: As = As[:-goal_Alen] pts = prevs + [ ProofTerm.sorry(Thm(goal.hyps, A)) for A in As[len(prevs):] ] # Determine whether it is necessary to provide instantiation # to apply_theorem. if set(term.get_svars(th.assums)) != set(th.prop.get_svars()) or \ set(term.get_stvars(th.assums)) != set(th.prop.get_stvars()) or \ not matcher.is_pattern_list(th.assums, []): return apply_theorem(th_name, *pts, inst=inst) else: return apply_theorem(th_name, *pts)
def get_proof_term(self, t): # If self.eq_pt is not present, produce it from thy, self.pt # and self.sym. Decompose into self.As and self.C. if self.eq_pt is None: if isinstance(self.pt, str): self.eq_pt = ProofTerm.theorem(self.pt) else: self.eq_pt = self.pt self.As, self.C = self.eq_pt.prop.strip_implies() # The conclusion of eq_pt should be an equality, and the number of # assumptions in eq_pt should match number of conditions. assert self.C.is_equals(), "rewr_conv: theorem is not an equality." if len(self.As) != len(self.conds): raise ConvException("rewr_conv: number of conds does not agree") inst = Inst() ts = [cond.prop for cond in self.conds] if not self.sym: lhs = self.C.lhs else: lhs = self.C.rhs try: inst = matcher.first_order_match_list(self.As, ts, inst) inst = matcher.first_order_match(lhs, t, inst) except matcher.MatchException: raise ConvException("rewr_conv: cannot match left side") # Check that every variable in the theorem has an instantiation if set(term.get_svars(self.As + [lhs])) != set( term.get_svars(self.As + [self.C])): raise ConvException("rewr_conv: unmatched vars") pt = self.eq_pt pt = pt.substitution(inst) pt = pt.implies_elim(*self.conds) if self.sym: pt = pt.symmetric() assert pt.th.is_equals(), "rewr_conv: wrong result." if pt.th.prop.lhs != t: pt = pt.on_prop(beta_norm_conv()) if pt.th.prop.lhs != t: pt = pt.on_prop(eta_conv()) assert pt.th.prop.lhs == t, "rewr_conv: wrong result. Expected %s, got %s" % ( str(t), str(pt.th.prop.lhs)) return pt
def has_rewrite(th, t, *, sym=False, conds=None): """Returns whether a rewrite is possible on a subterm of t. This can serve as a pre-check for top_sweep_conv, top_conv, and bottom_conv applied to rewr_conv. th -- either the name of a theorem, or the theorem itself. t -- target of rewriting. conds -- optional list of theorems matching assumptions of th. """ if isinstance(th, str): th = theory.get_theorem(th) if sym: th = Thm.symmetric(th) As, C = th.prop.strip_implies() if conds is None: conds = [] if not C.is_equals() or len(As) != len(conds): return False if set(term.get_svars(As + [C.lhs])) != set(term.get_svars(As + [C])): return False ts = [cond.prop for cond in conds] inst = Inst() try: inst = matcher.first_order_match_list(As, ts, inst) except matcher.MatchException: return False def rec(t): if not t.is_open() and matcher.can_first_order_match(C.lhs, t, inst): return True if t.is_comb(): return rec(t.fun) or rec(t.arg) elif t.is_abs(): _, body = t.dest_abs() return rec(body) else: return False return rec(t)
def is_pattern_list(ts, matched_vars, bd_vars=None): """Test whether a list of ts can be matched.""" if len(ts) == 0: return True elif len(ts) == 1: return is_pattern(ts[0], matched_vars, bd_vars) else: if is_pattern(ts[0], matched_vars): all_vars = list( set(matched_vars + [v.name for v in ts[0].get_svars()])) return is_pattern_list(ts[1:], all_vars, bd_vars) else: if not is_pattern_list(ts[1:], matched_vars, bd_vars): return False all_vars = list( set(matched_vars + [v.name for v in term.get_svars(ts[1:])])) return is_pattern(ts[0], all_vars, bd_vars)
def apply(self, state, id, data, prevs): inst = Inst() with context.fresh_context(vars=state.get_vars(id)): for key, val in data.items(): if key.startswith("param_"): if val != '': inst[key[6:]] = parser.parse_term(val) th = theory.get_theorem(data['theorem']) # Check whether to ask for parameters As, C = th.prop.strip_implies() match_svars = term.get_svars(As[:len(prevs)]) all_svars = th.prop.get_svars() param_svars = [ v for v in all_svars if v not in match_svars and 'param_' + v.name not in data ] if param_svars: raise theory.ParameterQueryException( list("param_" + v.name for v in param_svars)) # First test apply_theorem prev_ths = [state.get_proof_item(prev).th for prev in prevs] macro = logic.apply_theorem_macro(with_inst=True) res_th = macro.eval((data['theorem'], inst), prev_ths) state.add_line_before(id, 1) if inst: state.set_line(id, 'apply_theorem_for', args=(data['theorem'], inst), prevs=prevs) else: state.set_line(id, 'apply_theorem', args=data['theorem'], prevs=prevs) id2 = id.incr_id(1) new_id = state.find_goal(state.get_proof_item(id2).th, id2) if new_id is not None: state.replace_id(id2, new_id)