Esempio n. 1
0
    def search(self, state, id, prevs):
        prev_ths = [state.get_proof_item(prev).th for prev in prevs]
        thy = state.thy
        if len(prevs) == 0:
            return []

        results = []
        for name, th in thy.get_data("theorems").items():
            if 'hint_forward' not in thy.get_attributes(name):
                continue

            instsp = (dict(), dict())
            As, C = th.prop.strip_implies()

            if len(prevs) != len(As):
                continue

            if set(term.get_vars(As)) != set(term.get_vars(As + [C])):
                continue

            if not term.get_consts(As):
                continue

            try:
                for pat, prev in zip(As, prev_ths):
                    matcher.first_order_match_incr(pat, prev.concl, instsp)
            except matcher.MatchException:
                continue

            # All matches succeed
            t = logic.subst_norm(th.prop, instsp)
            _, new_fact = t.strip_implies()
            results.append({"theorem": name, "_fact": [new_fact]})
        return sorted(results, key=lambda d: d['theorem'])
Esempio n. 2
0
def is_pattern_list(ts, matched_vars):
    """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)
    else:
        if is_pattern(ts[0], matched_vars):
            all_vars = list(set(matched_vars + term.get_vars(ts[0])))
            return is_pattern_list(ts[1:], all_vars)
        elif is_pattern_list(ts[1:], matched_vars):
            all_vars = list(set(matched_vars + term.get_vars(ts[1:])))
            return is_pattern(ts[0], all_vars)
        else:
            return False
Esempio n. 3
0
def solve_core(s, t, debug=False):
    # First strip foralls from t.
    t = norm_term(t)
    new_names = logic.get_forall_names(t, svar=False)
    _, As, C = logic.strip_all_implies(t, new_names, svar=False)

    def print_debug(*args):
        if debug:
            print(*args)

    var_names = [v.name for v in term.get_vars(As + [C])]
    assms = dict()
    to_real = dict()
    for A in As:
        try:
            z3_A = convert(A, var_names, assms, to_real, s.ctx)
            print_debug('A', z3_A)
            s.add(z3_A)
        except Z3Exception as e:
            print_debug(e)
    try:
        z3_C = convert(C, var_names, assms, to_real, s.ctx)
        print_debug('C', z3_C)
        s.add(z3.Not(z3_C))
    except Z3Exception as e:
        print_debug(e)

    for nm, A in assms.items():
        print_debug('A', A)
        s.add(A)

    return s
Esempio n. 4
0
    def testGetVars(self):
        test_data = [
            (a, [a]),
            (f(a), [a, f]),
            (f(c), [f]),
            ([a, f(c)], [a, f]),
        ]

        for t, res in test_data:
            self.assertEqual(term.get_vars(t), res)
Esempio n. 5
0
    def search(self, state, id, prevs):
        goal_th = state.get_proof_item(id).th
        prev_ths = [state.get_proof_item(prev).th for prev in prevs]
        thy = state.thy

        results = []
        for name, th in thy.get_data("theorems").items():
            if 'hint_backward' not in thy.get_attributes(name):
                continue

            instsp = (dict(), dict())
            As, C = th.assums, th.concl
            # Only process those theorems where C and the matched As
            # contain all of the variables.
            if set(term.get_vars(As[:len(prevs)] + [C])) != set(
                    term.get_vars(As + [C])):
                continue

            # When there is no assumptions to match, only process those
            # theorems where C contains at least a constant (skip falseE,
            # induction theorems, etc).
            if len(prevs) == 0 and term.get_consts(C) == []:
                continue

            try:
                if matcher.is_pattern(C, []):
                    matcher.first_order_match_incr(C, goal_th.prop, instsp)
                    for pat, prev in zip(As, prev_ths):
                        matcher.first_order_match_incr(pat, prev.prop, instsp)
                else:
                    for pat, prev in zip(As, prev_ths):
                        matcher.first_order_match_incr(pat, prev.prop, instsp)
                    matcher.first_order_match_incr(C, goal_th.prop, instsp)
            except matcher.MatchException:
                continue

            # All matches succeed
            t = logic.subst_norm(th.prop, instsp)
            As, C = t.strip_implies()

            results.append({"theorem": name, "_goal": As[len(prevs):]})
        return sorted(results, key=lambda d: d['theorem'])
Esempio n. 6
0
def add_induct_predicate(name, T, props):
    """Add the given inductive predicate.

    The inductive predicate is specified by the name and type of
    the predicate, and a list of introduction rules, where each
    introduction rule must be given a name.

    """
    exts = TheoryExtension()
    exts.add_extension(AxConstant(name, T))

    for th_name, prop in props:
        exts.add_extension(Theorem(th_name, Thm([], prop)))
        exts.add_extension(Attribute(th_name, "hint_backward"))

    # Case rule
    Targs, _ = T.strip_type()
    vars = []
    for i, Targ in enumerate(Targs):
        vars.append(Var("_a" + str(i + 1), Targ))

    P = Var("P", boolT)
    pred = Const(name, T)
    assum0 = pred(*vars)
    assums = []
    for th_name, prop in props:
        As, C = prop.strip_implies()
        assert C.head == pred, "add_induct_predicate: wrong form of prop."
        eq_assums = [
            Term.mk_equals(var, arg) for var, arg in zip(vars, C.args)
        ]
        assum = Term.mk_implies(*(eq_assums + As), P)
        prop_vars = term.get_vars(prop)
        for var in reversed(term.get_vars(prop)):
            assum = Term.mk_all(var, assum)
        assums.append(assum)

    prop = Term.mk_implies(*([assum0] + assums + [P]))
    exts.add_extension(Theorem(name + "_cases", Thm([], prop)))

    return exts
Esempio n. 7
0
    def add_theorem(self, name, th, prf):
        """Add a theorem with proof to the file."""

        assert len(th.hyps) == 0, "add_theorem"
        vars = dict((v.name, str(v.T)) for v in get_vars(th.prop))
        data = {
            "name": name,
            "ty": "thm",
            "prop": printer.print_term(self.thy, th.prop),
            "vars": vars,
            "num_gaps": 0,
            "proof": sum([self.export_proof_json(item) for item in prf.items], []),
        }
        self.content.append(data)
Esempio n. 8
0
    def get_proof_term(self, thy, goal, *, args=None, prevs=None):
        if isinstance(args, tuple):
            th_name, instsp = args
        else:
            th_name = args
            instsp = None
        assert isinstance(th_name, str), "rule: theorem name must be a string"

        if prevs is None:
            prevs = []

        th = thy.get_theorem(th_name)
        As, C = th.assums, th.concl

        if instsp is None:
            instsp = (dict(), dict())
            if matcher.is_pattern(C, []):
                matcher.first_order_match_incr(C, goal.prop, instsp)
                for pat, prev in zip(As, prevs):
                    matcher.first_order_match_incr(pat, prev.prop, instsp)
            else:
                for pat, prev in zip(As, prevs):
                    matcher.first_order_match_incr(pat, prev.prop, instsp)
                matcher.first_order_match_incr(C, goal.prop, instsp)

        As, _ = logic.subst_norm(th.prop, instsp).strip_implies()
        pts = prevs + [
            ProofTerm.sorry(Thm(goal.hyps, A)) for A in As[len(prevs):]
        ]

        if set(term.get_vars(th.assums)) != set(term.get_vars(th.prop)) or \
           not matcher.is_pattern_list(th.assums, []):
            tyinst, inst = instsp
            return apply_theorem(thy, th_name, *pts, tyinst=tyinst, inst=inst)
        else:
            return apply_theorem(thy, th_name, *pts)
Esempio n. 9
0
    def search(self, state, id, prevs):
        cur_th = state.get_proof_item(id).th
        if len(cur_th.hyps) > 0:
            return []

        results = []
        for name, th in state.thy.get_data("theorems").items():
            if 'var_induct' not in state.thy.get_attributes(name):
                continue

            var_T = th.concl.arg.T
            vars = [v for v in term.get_vars(cur_th.prop) if v.T == var_T]
            if len(vars) == 1:
                results.append({'theorem': name, 'var': vars[0].name})
            elif len(vars) > 1:
                results.append({'theorem': name})
        return results
Esempio n. 10
0
    def get_proof_term(self, goal, *, args=None, prevs=None):
        assert isinstance(prevs, list) and len(prevs) >= 1, "apply_prev"
        pt, prev_pts = prevs[0], prevs[1:]

        # First, obtain the patterns
        new_names = logic.get_forall_names(pt.prop)
        new_vars, As, C = logic.strip_all_implies(pt.prop, new_names)
        assert len(prev_pts) <= len(As), "apply_prev: too many prev_pts"

        if args is None:
            inst = Inst()
        else:
            inst = args
        inst = matcher.first_order_match(C, goal.prop, inst)
        for idx, prev_pt in enumerate(prev_pts):
            inst = matcher.first_order_match(As[idx], prev_pt.prop, inst)

        unmatched_vars = [v for v in new_names if v not in inst]
        if unmatched_vars:
            raise theory.ParameterQueryException(
                list("param_" + name for name in unmatched_vars))

        pt = pt.subst_type(inst.tyinst)
        for new_name in new_names:
            pt = pt.forall_elim(inst[new_name])
        if pt.prop.beta_norm() != pt.prop:
            pt = pt.on_prop(beta_norm_conv())
        inst_As, inst_C = pt.prop.strip_implies()

        inst_arg = [inst[new_name] for new_name in new_names]
        new_goals = [
            ProofTerm.sorry(Thm(goal.hyps, A)) for A in inst_As[len(prev_pts):]
        ]
        if set(new_names).issubset({v.name for v in term.get_vars(As)}) and \
           matcher.is_pattern_list(As, []):
            return ProofTerm('apply_fact', args=None, prevs=prevs + new_goals)
        else:
            return ProofTerm('apply_fact_for',
                             args=inst_arg,
                             prevs=prevs + new_goals)
Esempio n. 11
0
    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
Esempio n. 12
0
def solve(goal, pts=None):
    """The main automation function.
    
    If the function succeeds, it should return a proof term whose
    proposition is the goal.

    """
    if debug_auto:
        print("Solve:", goal, [str(pt.prop) for pt in pts])

    if pts is None:
        pts = []
    elif isinstance(pts, tuple):
        pts = list(pts)

    # First handle the case where goal matches one of the conditions.
    for pt in pts:
        if goal == pt.prop:
            return pt

    # Next, consider the situation where one of the assumptions is
    # a conjunction or a disjunction.
    for i, pt in enumerate(pts):
        if pt.prop.is_conj():
            pt1 = apply_theorem('conjD1', pt)
            pt2 = apply_theorem('conjD2', pt)
            return solve(goal, [pt1, pt2] + pts[:i] + pts[i + 1:])

        if pt.prop.is_disj():
            a1, a2 = pt.prop.args
            assume_pt1 = ProofTerm.assume(a1)
            assume_pt2 = ProofTerm.assume(a2)
            pt1 = solve(goal, [assume_pt1] + pts[:i] + pts[i + 1:])
            pt1 = pt1.implies_intr(a1)
            pt2 = solve(goal, [assume_pt2] + pts[:i] + pts[i + 1:])
            pt2 = pt2.implies_intr(a2)
            return apply_theorem('disjE', pt, pt1, pt2)

    # Handle various logical connectives.
    if goal.is_conj():
        a1, a2 = goal.args
        pt1 = solve(a1, pts)
        pt2 = solve(a2, pts)
        return apply_theorem('conjI', pt1, pt2)

    if goal.is_disj():
        a1, a2 = goal.args
        try:
            pt1 = solve(a1, pts)
            return apply_theorem('disjI1', pt1, concl=goal)
        except TacticException:
            pt2 = solve(a2, pts)
            return apply_theorem('disjI2', pt2, concl=goal)

    if goal.is_implies():
        a1, a2 = goal.args
        assume_pt = ProofTerm.assume(a1)
        return solve(a2, [assume_pt] + pts).implies_intr(a1)

    if goal.is_forall():
        var_names = [
            v.name for v in term.get_vars([goal] + [pt.prop for pt in pts])
        ]
        nm = name.get_variant_name(goal.arg.var_name, var_names)
        v = Var(nm, goal.arg.var_T)
        t = goal.arg.subst_bound(v)
        return solve(t, pts).forall_intr(v)

    # Normalize goal
    eq_pt = norm(goal, pts)
    goal = eq_pt.rhs

    if goal.is_conj():
        pt = solve(goal, pts)
        return eq_pt.symmetric().equal_elim(pt)

    res_pt = None

    if not pts and goal in solve_record:
        res_pt = solve_record[goal]

    # Call registered functions
    elif goal.is_not() and goal.arg.head in global_autos_neg:
        for f in global_autos_neg[goal.arg.head]:
            try:
                res_pt = f(goal, pts)
                break
            except TacticException:
                pass

    elif goal.head in global_autos:
        for f in global_autos[goal.head]:
            try:
                res_pt = f(goal, pts)
                break
            except TacticException:
                pass

    if res_pt is not None:
        if not pts:
            solve_record[goal] = res_pt
        return eq_pt.symmetric().equal_elim(res_pt)
    else:
        raise TacticException('Cannot solve %s' % goal)