Exemplo n.º 1
0
    def rewrite(self, match):
        reason = ByRule(self, match)

        # If there are nodes in rhs that has no corresponding match from the lhs, we should create
        # new nodes for them (like x -> and(x, or(x, y)), y is such a node)
        for n in self._rhs_leaf_nodes:
            if not n in match:
                match = dict(match)
                match[n] = Node()

        if isinstance(self._rhs, Term):
            to_add = list_term_elements(self._rhs.apply_map(match),
                                        top_node=match[self._lhs],
                                        reason=reason)
            if self.destructive:
                return {'remove': [match[self._lhs_hyperedge]], 'add': to_add}
            else:
                return {'add': to_add}
        else:
            to_merge = [(match[self._lhs], self._rhs.apply_map(match), reason)]
            if self.destructive:
                return {
                    'remove': [match[self._lhs_hyperedge]],
                    'merge': to_merge
                }
            else:
                return {'merge': to_merge}
 def smallest_matches(self, node, top_node=None):
     for p in self._smallest_term_matches(node):
         yield {
             k: v
             for k, v in zip(list_term_elements(p[0], top_node=top_node),
                             p[1])
         }
Exemplo n.º 3
0
    def __init__(self, equality, reverse=False, destructive=False, name=None):
        equality = parse(equality)

        if name is None:
            name = ("(rev)" if reverse else "") + ("(des)" if destructive else
                                                   "") + equality.name

        lhs = equality.lhs
        rhs = equality.rhs

        if reverse:
            lhs, rhs = rhs, lhs

        if isinstance(lhs, Term):
            node, lhs_hyperedge, *_ = list_term_elements(lhs)
            lhs = node
        else:
            lhs_hyperedge = None
            if destructive:
                logging.warning("LHS is a node, destructivity is ignored")
                destructive = False

        if not isinstance(lhs,
                          (Term, Node)) or not isinstance(rhs, (Term, Node)):
            raise ValueError(
                "Both lhs and rhs of the equality should be Terms or nodes: {} = {}"
                .format(lhs, rhs))

        self.equality = equality
        self.reverse = reverse
        self.destructive = destructive
        self.name = name
        self.trigger = lhs

        self._lhs = lhs
        self._rhs = rhs
        self._lhs_hyperedge = lhs_hyperedge
        self._rhs_leaf_nodes = leaf_nodes(rhs)
Exemplo n.º 4
0
    def add_trigger(self, pattern, callback):
        if isinstance(pattern, Term):
            pattern = list_term_elements(pattern)[0]

        assert isinstance(pattern, Node)

        if len(pattern.outgoing) == 0:
            # special case
            def _on_new_node(node, pattern=pattern, callback=callback):
                callback({pattern: node})

            self._node_callbacks.append(_on_new_node)
            return

        multerm, matchlist = self._pattern_to_multerm(pattern)

        # printind("\n================")
        # printind(pattern)
        # printind(multerm)
        # printind(matchlist)
        # printind("================\n")

        pat_to_index = {}
        index_mergelist = []
        for i, e in enumerate(matchlist):
            if e in pat_to_index:
                if isinstance(e, Node):
                    index_mergelist.append((pat_to_index[e], i))
            else:
                pat_to_index[e] = i

        def _on_this_multerm(matches,
                             pat_to_index=pat_to_index,
                             index_mergelist=index_mergelist,
                             self=self,
                             callback=callback):
            # printind()
            # printind("Multerm", multerm)
            # printind("Matched", matches)
            for matched in self._matches_to_matchlists(matches):
                # printind("    list", matched)
                # printind("matchlist", matchlist)
                need_merged = [(matched[p[0]], matched[p[1]])
                               for p in index_mergelist]

                # printind("need merged", need_merged)

                def _on_pattern_matched(matched=matched,
                                        pat_to_index=pat_to_index,
                                        self=self,
                                        callback=callback):
                    match = {
                        n: matched[i].follow()
                        for n, i in pat_to_index.items()
                    }
                    if all(e in self.hypergraph for e in match.values()):
                        callback(match)

                self._add_multimerge_callback(need_merged, _on_pattern_matched)

        self._multerm_callbacks.setdefault(multerm,
                                           []).append(_on_this_multerm)

        # Since existing nodes may match the multerm, we have to trigger the new callback
        for n in self.hypergraph.nodes():
            existing_matches = self._get_node_matches(n, multerm)
            if existing_matches:
                _on_this_multerm(existing_matches)

        # We do this at the end because this will immediately trigger stuff for existing hyperedges
        self._add_multerm(multerm)
 def smallest_term_match_single(self, node, top_node=None):
     p = self._smallest_term_matches_single(node)
     return p[0], {
         k: v
         for k, v in zip(list_term_elements(p[0], top_node=top_node), p[1])
     }
Exemplo n.º 6
0
def run_script(hypergraph, script, cache=None):
    if cache is None:
        cache = {}

    if isinstance(script, RunAllScript):
        result = [run_script(hypergraph, s, cache) for s in script.subscripts]
    elif isinstance(script, IthElementScript):
        result = run_script(hypergraph, script.script, cache)[script.index]
    elif isinstance(script, IncidentNode):
        result = run_script(hypergraph, script.hyperedge,
                            cache).incident(script.index)
    elif script in cache:
        result = cache[script]
    elif isinstance(script, FreeNodeScript):
        added = hypergraph.rewrite(add=Node())[0]
        cache[script] = added
        result = added
    elif isinstance(script, MatchScript):
        match = {}
        elements = script.elements
        for e in elements:
            if isinstance(e, Hyperedge):
                match[e] = run_script(hypergraph, script.hyperedge_scripts[e],
                                      cache)

        for in1, in2, ms in script.merge_scripts:
            n1 = match[in1.hyperedge].incident(in1.index).follow()
            n2 = match[in2.hyperedge].incident(in2.index).follow()
            if n1 != n2:
                run_script(hypergraph, ms, cache)

        for e in elements:
            if isinstance(e, Node):
                if not e in match:
                    if e in script.node_scripts:
                        match[e] = run_script(hypergraph,
                                              script.node_scripts[e], cache)
                    else:
                        # As noted somewhere else, there may be no e.outgoing and e.incoming
                        for h in match:
                            if isinstance(h, Hyperedge):
                                incs = IncidentNode.all_of(h, e)
                                if incs:
                                    match[e] = match[h].incident(incs[0].index)
                                    break
                        assert match[e] is not None

        match = match_follow(match)

        if not still_match(match, hypergraph):
            raise RuntimeError("The match built according to the script "
                               "doesn't match the hypergraph")

        cache[script] = match
        result = match
    elif isinstance(script, RuleApplicationScript):
        match = run_script(hypergraph, script.match_script, cache)
        match = match_follow(match)

        rw = script.rule.rewrite(match)
        added = hypergraph.rewrite(**rw)

        cache[script] = added
        result = added
    elif isinstance(script, AddTermsScript):
        added = hypergraph.rewrite(add=script.terms)[len(script.terms):]
        res = []
        start = 0
        for t in script.terms:
            tsize = len(list_term_elements(t))
            res.append(added[start:start + tsize])
            start += tsize
        cache[script] = res
        result = res
    else:
        raise ValueError("Don't know how to run this script {}".format(script))

    return result