Esempio n. 1
0
class ProofState():
    """Represents proof state on the server side."""
    def __init__(self):
        """Empty proof state."""
        self.vars = []
        self.prf = Proof()
        self.rpt = None

    def get_vars(self, id):
        """Obtain the context at the given id."""
        id = ItemID(id)
        vars = dict()
        for v in self.vars:
            vars[v.name] = v.T

        prf = self.prf
        try:
            for n in id.id:
                for item in prf.items[:n + 1]:
                    if item.rule == "variable":
                        nm, T = item.args
                        vars[nm] = T
                prf = prf.items[n].subproof
            return vars
        except (AttributeError, IndexError):
            raise ProofStateException

    def __str__(self):
        vars = sorted(self.vars, key=lambda v: v.name)
        lines = "\n".join('var ' + v.name + ' :: ' + str(v.T) for v in vars)
        return lines + "\n" + str(self.prf)

    def __copy__(self):
        res = ProofState()
        res.vars = copy.copy(self.vars)
        res.prf = copy.copy(self.prf)
        res.rpt = copy.copy(self.rpt)
        return res

    def export_proof(self):
        return sum(
            [printer.export_proof_item(item) for item in self.prf.items], [])

    def json_data(self):
        """Export proof in json format."""
        with global_setting(unicode=True):
            vars = {v.name: printer.print_type(v.T) for v in self.vars}

        with global_setting(unicode=True, highlight=True):
            res = {
                "vars": vars,
                "proof": self.export_proof(),
                "num_gaps": len(self.rpt.gaps),
                "method_sig": method.get_method_sig(),
            }
        return res

    def check_proof(self, *, no_gaps=False, compute_only=False):
        """Check the given proof. Report is stored in rpt."""
        self.rpt = report.ProofReport()
        return theory.check_proof(self.prf,
                                  rpt=self.rpt,
                                  no_gaps=no_gaps,
                                  compute_only=compute_only)

    def add_line_before(self, id, n):
        """Add n lines before the given id."""
        id = ItemID(id)
        prf = self.prf.get_parent_proof(id)
        split = id.last()
        new_items = [ProofItem(id.incr_id(i), "") for i in range(n)]
        prf.items = prf.items[:split] + new_items + prf.items[split:]
        for item in prf.items[split + n:]:
            item.incr_proof_item(id, n)

        self.check_proof(compute_only=True)

    def remove_line(self, id):
        """Remove line with the given id."""
        id = ItemID(id)
        prf = self.prf.get_parent_proof(id)
        split = id.last()
        prf.items = prf.items[:split] + prf.items[split + 1:]
        for item in prf.items[split:]:
            item.decr_proof_item(id)

        self.check_proof(compute_only=True)

    def set_line(self, id, rule, *, args=None, prevs=None, th=None):
        """Set the item with the given id to the following data."""
        id = ItemID(id)
        prf = self.prf.get_parent_proof(id)
        prf.items[id.last()] = ProofItem(id,
                                         rule,
                                         args=args,
                                         prevs=prevs,
                                         th=th)
        self.check_proof(compute_only=True)

    def get_proof_item(self, id):
        """Obtain the proof item with the given id."""
        return self.prf.find_item(ItemID(id))

    def replace_id(self, old_id, new_id):
        """Replace old_id with new_id in prevs."""
        def replace(prf):
            for item in prf.items:
                item.prevs = [
                    new_id if id == old_id else id for id in item.prevs
                ]
                if item.subproof:
                    replace(item.subproof)

        prf = self.prf.get_parent_proof(old_id)
        replace(prf)

        self.remove_line(old_id)

    def find_goal(self, concl, goal_id):
        """Determine if the given conclusion is already proved,
        for the purpose of showing goal_id.

        Proof items that can be used include all items with id
        whose length is at most that of goal_id, where all but
        the last number agrees with that of goal_id, and the
        last number is less than the corresponding number in goal_id.

        """
        prf = self.prf
        try:
            for n in goal_id.id:
                for item in prf.items[:n]:
                    if item.th is not None and item.th.can_prove(concl):
                        return item.id
                prf = prf.items[n].subproof
        except (AttributeError, IndexError):
            raise ProofStateException

    def apply_search(self, id, method, prevs=None):
        id = ItemID(id)
        prevs = [ItemID(prev) for prev in prevs] if prevs else []
        return method.search(self, id, prevs)

    def search_method(self, id, prevs):
        """Perform search for each method."""
        id = ItemID(id)
        prevs = [ItemID(prev) for prev in prevs] if prevs else []
        results = []
        all_methods = method.get_all_methods()
        for name in all_methods:
            cur_method = all_methods[name]
            if hasattr(cur_method, 'no_order'):
                test_prevs = [prevs]
            else:
                test_prevs = itertools.permutations(prevs)
            for perm_prevs in test_prevs:
                res = cur_method.search(self, id, perm_prevs)
                for r in res:
                    r['method_name'] = name
                    r['goal_id'] = str(id)
                    if prevs:
                        r['fact_ids'] = list(str(id) for id in perm_prevs)
                    with global_setting(unicode=True, highlight=True):
                        r['display'] = method.output_hint(self, r)
                results.extend(res)

        # If there is an element in results that solves the goal,
        # output only results that solves.
        if any('_goal' in r and len(r['_goal']) == 0 for r in results):
            results = list(
                filter(lambda r: '_goal' in r and len(r['_goal']) == 0,
                       results))
        return results

    def apply_tactic(self, id, tactic, args=None, prevs=None):
        id = ItemID(id)
        prevs = [ItemID(prev) for prev in prevs] if prevs else []
        prevs = [
            ProofTerm.atom(prev,
                           self.get_proof_item(prev).th) for prev in prevs
        ]

        cur_item = self.get_proof_item(id)
        assert cur_item.rule == "sorry", "apply_tactic: id is not a gap"

        pt = tactic.get_proof_term(cur_item.th, args=args, prevs=prevs)
        new_prf = pt.export(prefix=id, subproof=False)

        self.add_line_before(id, len(new_prf.items) - 1)
        for i, item in enumerate(new_prf.items):
            cur_id = item.id
            prf = self.prf.get_parent_proof(cur_id)
            prf.items[cur_id.last()] = item
        self.check_proof(compute_only=True)

        # Test if the goals are already proved:
        for item in new_prf.items:
            if item.rule == 'sorry':
                new_id = self.find_goal(
                    self.get_proof_item(item.id).th, item.id)
                if new_id is not None:
                    self.replace_id(item.id, new_id)

        # Resolve trivial subgoals
        for item in new_prf.items:
            if item.rule == 'sorry':
                if logic.trivial_macro().can_eval(item.th.prop):
                    self.set_line(item.id, 'trivial', args=item.th.prop)

    def parse_steps(self, steps):
        """Parse and apply a list of steps to self.

        Return the output from the list of steps.

        """
        history = []
        for step in steps:
            with global_setting(unicode=True, highlight=True):
                step_output = method.output_step(self, step)
            history.append({
                'step_output': step_output,
                'goal_id': step['goal_id'],
                'fact_ids': step.get('fact_ids', [])
            })
            try:
                method.apply_method(self, step)
                self.check_proof(compute_only=True)
            except Exception as e:
                history[-1]['error'] = {
                    'err_type': e.__class__.__name__,
                    'err_str': str(e),
                    'trace': traceback2.format_exc()
                }

        return history
Esempio n. 2
0
class ProofState():
    """Represents proof state on the server side."""
    def __init__(self, thy):
        """Empty proof state."""
        self.thy = thy
        self.vars = []
        self.prf = Proof()

    def get_ctxt(self, id):
        """Obtain the context at the given id."""
        id = id_force_tuple(id)
        ctxt = {}
        for v in self.vars:
            ctxt[v.name] = v.T

        prf = self.prf
        try:
            for n in id:
                for item in prf.items[:n + 1]:
                    if item.rule == "variable":
                        nm, T = item.args
                        ctxt[nm] = T
                prf = prf.items[n].subproof
            return ctxt
        except (AttributeError, IndexError):
            raise TacticException()

    def __str__(self):
        vars = sorted(self.vars, key=lambda v: v.name)
        lines = "\n".join('var ' + v.name + ' :: ' + str(v.T) for v in vars)
        return lines + "\n" + str(self.prf)

    @staticmethod
    def init_state(thy, vars, assums, concl):
        """Construct initial partial proof for the given assumptions and
        conclusion.

        assums - assumptions A1, ... An.
        concl - conclusion C.
        
        Constructs:

        0: assume A1
        ...
        n-1: assume An
        n: C by sorry
        n+1: A1 --> ... --> An --> C by intros from 0, 1, ..., n.

        """
        assert all(isinstance(var, Term)
                   for var in vars), "init_state: vars must be terms."
        assert all(isinstance(a, Term)
                   for a in assums), "init_state: assums must be terms."
        assert isinstance(concl,
                          Term), "init_state: conclusion must be a term."
        state = ProofState(thy)

        state.vars = vars
        state.prf = Proof(*assums)
        n = len(assums)
        state.prf.add_item(n, "sorry", th=Thm(assums, concl))
        if len(assums) > 0:
            state.prf.add_item(n + 1, "intros", prevs=range(n + 1))
        state.check_proof(compute_only=True)
        return state

    @staticmethod
    def parse_init_state(thy, data):
        """Given data for a theorem statement, construct the initial partial proof.
        
        data['vars']: list of variables.
        data['prop']: proposition to be proved. In the form A1 --> ... --> An --> C.

        """
        ctxt = {}
        vars = []
        for name, str_T in data['vars'].items():
            T = parser.parse_type(thy, str_T)
            vars.append(Var(name, T))
            ctxt[name] = T
        prop = parser.parse_term(thy, ctxt, data['prop'])
        assums, concl = prop.strip_implies()

        return ProofState.init_state(thy, vars, assums, concl)

    def get_method_sig(self):
        """Obtain signature of all methods in the theory."""
        sig = {}
        for name, method in self.thy.get_data('method').items():
            sig[name] = method.sig
        return sig

    def json_data(self):
        """Export proof in json format."""
        self.check_proof()
        return {
            "vars": [{
                'name': v.name,
                'T': str(v.T)
            } for v in self.vars],
            "proof":
            sum([
                printer.export_proof_item(
                    self.thy, item, unicode=True, highlight=True)
                for item in self.prf.items
            ], []),
            "report":
            self.rpt.json_data(),
            "method_sig":
            self.get_method_sig()
        }

    @staticmethod
    def parse_proof(thy, data):
        """Obtain proof from json format."""
        ctxt = {}
        state = ProofState(thy)
        for name, str_T in data['vars'].items():
            T = parser.parse_type(thy, str_T)
            state.vars.append(Var(name, T))
            ctxt[name] = T
        state.prf = Proof()
        for line in data['proof']:
            if line['rule'] == "variable":
                nm, str_T = line['args'].split(',', 1)
                ctxt[nm] = parser.parse_type(thy, str_T.strip())
            item = parser.parse_proof_rule(thy, ctxt, line)
            state.prf.insert_item(item)

        state.check_proof(compute_only=True)
        return state

    def check_proof(self, *, no_gaps=False, compute_only=False):
        """Check the given proof. Report is stored in rpt."""
        self.rpt = report.ProofReport()
        return self.thy.check_proof(self.prf,
                                    rpt=self.rpt,
                                    no_gaps=no_gaps,
                                    compute_only=compute_only)

    def add_line_after(self, id):
        """Add given line after the given id."""
        id = id_force_tuple(id)
        prf = self.prf.get_parent_proof(id)
        new_id = incr_id(id, 1)
        split = new_id[-1]
        prf.items = prf.items[:split] + [ProofItem(new_id, "")
                                         ] + prf.items[split:]
        for item in prf.items[split + 1:]:
            incr_proof_item(item, new_id, 1)

        self.check_proof(compute_only=True)

    def add_line_before(self, id, n):
        """Add n lines before the given id."""
        id = id_force_tuple(id)
        prf = self.prf.get_parent_proof(id)
        split = id[-1]
        new_items = [ProofItem(incr_id(id, i), "") for i in range(n)]
        prf.items = prf.items[:split] + new_items + prf.items[split:]
        for item in prf.items[split + n:]:
            incr_proof_item(item, id, n)

        self.check_proof(compute_only=True)

    def remove_line(self, id):
        """Remove line with the given id."""
        id = id_force_tuple(id)
        prf = self.prf.get_parent_proof(id)
        split = id[-1]
        prf.items = prf.items[:split] + prf.items[split + 1:]
        for item in prf.items[split:]:
            decr_proof_item(item, id)

        self.check_proof(compute_only=True)

    def set_line(self, id, rule, *, args=None, prevs=None, th=None):
        """Set the item with the given id to the following data."""
        id = id_force_tuple(id)
        prf = self.prf.get_parent_proof(id)
        prf.items[id[-1]] = ProofItem(id, rule, args=args, prevs=prevs, th=th)
        self.check_proof(compute_only=True)

    def get_proof_item(self, id):
        """Obtain the proof item with the given id."""
        return self.prf.find_item(id)

    def replace_id(self, old_id, new_id):
        """Replace old_id with new_id in prevs."""
        def replace(prf):
            for item in prf.items:
                item.prevs = [
                    new_id if id == old_id else id for id in item.prevs
                ]
                if item.subproof:
                    replace(item.subproof)

        prf = self.prf.get_parent_proof(old_id)
        replace(prf)

        self.remove_line(old_id)

    def find_goal(self, concl, goal_id):
        """Determine if the given conclusion is already proved,
        for the purpose of showing goal_id.

        Proof items that can be used include all items with id
        whose length is at most that of goal_id, where all but
        the last number agrees with that of goal_id, and the
        last number is less than the corresponding number in goal_id.

        """
        prf = self.prf
        try:
            for n in goal_id:
                for item in prf.items[:n]:
                    if item.th is not None and item.th.can_prove(concl):
                        return item.id
                prf = prf.items[n].subproof
        except (AttributeError, IndexError):
            raise TacticException()

    def apply_search(self, id, method, prevs=None):
        id = id_force_tuple(id)
        prevs = [id_force_tuple(prev) for prev in prevs] if prevs else []
        return method.search(self, id, prevs)

    def search_method(self, id, prevs):
        """Perform search for each method."""
        id = id_force_tuple(id)
        prevs = [id_force_tuple(prev) for prev in prevs] if prevs else []
        results = []
        method_data = self.thy.get_data("method")
        for name, method in method_data.items():
            res = method.search(self, id, prevs)
            for r in res:
                r['_method_name'] = name
            results.extend(res)

        # If there is an element in results that solves the goal,
        # output only results that solves.
        if any('_goal' in r and len(r['_goal']) == 0 for r in results):
            results = list(
                filter(lambda r: '_goal' in r and len(r['_goal']) == 0,
                       results))
        return results

    def apply_tactic(self, id, tactic, args=None, prevs=None):
        id = id_force_tuple(id)
        prevs = [id_force_tuple(prev) for prev in prevs] if prevs else []
        prevs = [
            ProofTermAtom(prev,
                          self.get_proof_item(prev).th) for prev in prevs
        ]

        cur_item = self.get_proof_item(id)
        assert cur_item.rule == "sorry", "apply_tactic: id is not a gap"

        pt = tactic.get_proof_term(self.thy,
                                   cur_item.th,
                                   args=args,
                                   prevs=prevs)
        new_prf = pt.export(prefix=id, subproof=False)

        self.add_line_before(id, len(new_prf.items) - 1)
        for i, item in enumerate(new_prf.items):
            cur_id = item.id
            prf = self.prf.get_parent_proof(cur_id)
            prf.items[cur_id[-1]] = item
        self.check_proof(compute_only=True)

        # Test if the goals are already proved:
        for item in new_prf.items:
            new_id = self.find_goal(self.get_proof_item(item.id).th, item.id)
            if new_id is not None:
                self.replace_id(item.id, new_id)

    def apply_backward_step(self, id, th_name, *, prevs=None, instsp=None):
        """Apply backward step using the given theorem.
        
        prevs - list of previous proved facts to use.
        inst - existing instantiation.

        """
        self.apply_tactic(id,
                          tactic.rule(),
                          args=(th_name, instsp),
                          prevs=prevs)

    def apply_forward_step(self, id, th_name, prevs=None):
        """Apply forward step using the given theorem."""
        method.apply_method(
            self, {
                'method_name': 'apply_forward_step',
                'goal_id': id,
                'fact_ids': prevs,
                'theorem': th_name
            })

    def introduction(self, id, names=None):
        """Introduce variables and assumptions."""
        method.apply_method(
            self, {
                'method_name': 'introduction',
                'goal_id': id,
                'fact_ids': [],
                'names': names
            })

    def apply_forall_elim(self, id, prev, s):
        """Elimination of forall statement."""
        method.apply_method(
            self, {
                'method_name': 'forall_elim',
                'goal_id': id,
                'fact_ids': [prev],
                's': s
            })

    def apply_induction(self, id, th_name, var):
        """Apply induction using the given theorem and variable."""
        method.apply_method(
            self, {
                'method_name': 'induction',
                'goal_id': id,
                'fact_ids': [],
                'theorem': th_name,
                'var': var
            })

    def rewrite_goal(self, id, th_name, *, backward=False):
        """Apply an existing equality theorem to the given goal."""
        self.apply_tactic(id, tactic.rewrite(), args=th_name)

    def rewrite_goal_with_prev(self, id, prev):
        """Apply existence fact to the given goal."""
        self.apply_tactic(id, tactic.rewrite_goal_with_prev(), prevs=[prev])

    def apply_cases(self, id, A):
        """Apply case analysis on A."""
        self.apply_tactic(id, tactic.cases(), args=A)

    def apply_prev(self, id, prev):
        """Apply previously proved rule."""
        self.apply_tactic(id, tactic.apply_prev(), prevs=[prev])