def apply_result(self, result, children):
        if isinstance(result, str):
            children = [(result, [])]
        elif isinstance(result, list):
            symbol_indexes = [
                i for i, c in enumerate(children) if is_nonterminal(c[0])
            ]

            for index, value in enumerate(result):
                if value is not None:
                    child_index = symbol_indexes[index]
                    if not isinstance(value, str):
                        value = repr(value)
                    if self.log:
                        print("Replacing",
                              all_terminals(children[child_index]), "by",
                              value)

                    # children[child_index] = (value, [])
                    child_symbol, _ = children[child_index]
                    children[child_index] = (child_symbol, [(value, [])])
        elif result is None:
            pass
        elif isinstance(result, bool):
            pass
        else:
            if self.log:
                print("Replacing",
                      "".join([all_terminals(c) for c in children]), "by",
                      result)

            children = [(repr(result), [])]

        return children
    def run_post_functions(self, tree, depth=float("inf")):
        symbol, children = tree
        if children == []:
            return True, children  # Terminal symbol

        try:
            expansion = self.find_expansion(tree)
        except KeyError:
            # Expansion (no longer) found - ignore
            return True, children

        result = True
        function = exp_post_expansion_function(expansion)
        if function is not None:
            result = self.eval_function(tree, function)
            if isinstance(result, bool) and not result:
                if self.log:
                    print(all_terminals(tree), "did not satisfy", symbol,
                          "constraint")
                return False, children

            children = self.apply_result(result, children)

        if depth > 0:
            for c in children:
                result, _ = self.run_post_functions(c, depth - 1)
                if isinstance(result, bool) and not result:
                    return False, children

        return result, children
    def run_post_functions_locally(self, new_tree):
        symbol, _ = new_tree

        result, children = self.run_post_functions(new_tree, depth=0)
        if not isinstance(result, bool) or result:
            # No constraints, or constraint satisfied
            # children = self.apply_result(result, children)
            new_tree = (symbol, children)
            return new_tree

        # Replace tree by unexpanded symbol and try again
        if self.log:
            print(
                all_terminals(new_tree),
                "did not satisfy",
                symbol,
                "constraint")

        if self.replacement_attempts_counter > 0:
            if self.log:
                print("Trying another expansion")
            self.replacement_attempts_counter -= 1
            return (symbol, None)

        if self.log:
            print("Starting from scratch")
        raise RestartExpansionException
def expansion_key(symbol, expansion):
    """Convert (symbol, children) into a key.  `children` can be an expansion string or a derivation tree."""
    if isinstance(expansion, tuple):
        expansion = expansion[0]
    if not isinstance(expansion, str):
        children = expansion
        expansion = all_terminals((symbol, children))
    return symbol + " -> " + expansion
Beispiel #5
0
    def reduce_tree(self, tree):
        # Find possible reductions
        smallest_tree = tree
        tree_reductions = self.reductions(tree)
        print("Alternatives: " + queue_to_string(tree_reductions))

        while len(tree_reductions) > 0:
            t = tree_reductions[0]
            tree_reductions = tree_reductions[1:]
            s = all_terminals(t)
            if self.test(s) == Runner.FAIL:
                # Found new smallest tree; try to reduce that one further
                smallest_tree = t
                tree_reductions = self.reductions(t)
                tree_reductions.sort(key=lambda tree: -number_of_nodes(tree))
                print("New smallest tree: " + all_terminals(smallest_tree))

        return smallest_tree
    def eval_function(self, tree, function):
        symbol, children = tree

        assert callable(function)

        args = []
        for (symbol, exp) in children:
            if exp != [] and exp is not None:
                symbol_value = all_terminals((symbol, exp))
                args.append(symbol_value)

        result = function(*args)
        if self.log:
            print(repr(function) + repr(tuple(args)), "=", repr(result))

        return result
    def choose_node_expansion(self, node, possible_children):
        (symbol, tree) = node
        expansions = self.grammar[symbol]
        probabilities = exp_probabilities(expansions)

        weights = []
        for child in possible_children:
            expansion = all_terminals((node, child))
            child_weight = probabilities[expansion]
            if self.log:
                print(repr(expansion), "p =", child_weight)
            weights.append(child_weight)

        if sum(weights) == 0:
            # No alternative (probably expanding at minimum cost)
            weights = None

        return random.choices(range(len(possible_children)),
                              weights=weights)[0]
Beispiel #8
0
    def reduce_subtree(self, tree, subtree, depth=-1):
        symbol, children = subtree
        if len(children) == 0:
            return False

        if self.log_reduce:
            print("Reducing", all_terminals(subtree), "with depth", depth)

        reduced = False
        while True:
            reduced_child = False
            for i, child in enumerate(children):
                (child_symbol, _) = child
                for reduction in self.symbol_reductions(
                        child, child_symbol, depth):
                    if number_of_nodes(reduction) >= number_of_nodes(child):
                        continue

                    # Try this reduction
                    if self.log_reduce:
                        print(
                            "Replacing",
                            all_terminals(
                                children[i]),
                            "by",
                            all_terminals(reduction))
                    children[i] = reduction
                    if self.test(all_terminals(tree)) == Runner.FAIL:
                        # Success
                        if self.log_reduce:
                            print("New tree:", all_terminals(tree))
                        reduced = reduced_child = True
                        break
                    else:
                        # Didn't work out - restore
                        children[i] = child

            if not reduced_child:
                if self.log_reduce:
                    print("Tried all alternatives for", all_terminals(subtree))
                break

        # Run recursively
        for c in children:
            if self.reduce_subtree(tree, c, depth):
                reduced = True

        return reduced
Beispiel #9
0
def shrink_tree(tree):
    name, children = tree
    if name in VAR_TOKENS:
        return (name, [(all_terminals(tree), [])])
    else:
        return (name, [shrink_tree(c) for c in children])
Beispiel #10
0
    mystring = '1+2'

A1_GRAMMAR = {
    "<start>": ["<expr>"],
    "<expr>": ["<expr>+<expr>", "<expr>-<expr>", "<integer>"],
    "<integer>": ["<digit><integer>", "<digit>"],
    "<digit>": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
}

if __name__ == "__main__":
    tree = ('<start>', [
        ('<expr>', [('<expr>', [('<integer>', [('<digit>', [('1', [])])])]),
                    ('+', []),
                    ('<expr>', [('<integer>', [('<digit>', [('2', [])])])])])
    ])
    assert mystring == all_terminals(tree)
    display_tree(tree)

A2_GRAMMAR = {
    "<start>": ["<expr>"],
    "<expr>": ["<integer><expr_>"],
    "<expr_>": ["+<expr>", "-<expr>", ""],
    "<integer>": ["<digit><integer_>"],
    "<integer_>": ["<integer>", ""],
    "<digit>": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
}

if __name__ == "__main__":
    tree = ('<start>', [('<expr>', [
        ('<integer>', [('<digit>', [('1', [])]), ('<integer_>', [('', [])])]),
        ('<expr_>', [('+', []),
Beispiel #11
0
 def reduce(self, inp):
     tree = self.parse(inp)
     self.reduce_tree(tree)
     return all_terminals(tree)
Beispiel #12
0
 def parse(self, inp):
     tree, *_ = self.parser.parse(inp)
     if self.log_reduce:
         print(all_terminals(tree))
     return tree
Beispiel #13
0
def tree_list_to_string(q):
    return "[" + ", ".join([all_terminals(tree) for tree in q]) + "]"
Beispiel #14
0
import copy

if __name__ == "__main__":
    new_derivation_tree = copy.deepcopy(derivation_tree)
    # We really should have some query language
    sub_expr_tree = new_derivation_tree[1][0][1][2]
    display_tree(sub_expr_tree)


if __name__ == "__main__":
    new_derivation_tree[1][0] = sub_expr_tree
    display_tree(new_derivation_tree)


if __name__ == "__main__":
    all_terminals(new_derivation_tree)


# ### Simplifying by Alternative Expansions

if __name__ == "__main__":
    print('\n### Simplifying by Alternative Expansions')




if __name__ == "__main__":
    term_tree = new_derivation_tree[1][0][1][0][1][0][1][1][1][0]
    display_tree(term_tree)

Beispiel #15
0
       ["<expr>"],
   "<expr>":
       ["<expr>+<expr>", "<expr>-<expr>", "<integer>"],
   "<integer>":
       ["<digit><integer>", "<digit>"],
   "<digit>":
        ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
}

if __name__ == "__main__":
    tree = ('<start>',[
        ('<expr>',[
            ('<expr>',[('<integer>',[('<digit>',[('1',[])])])]),
            ('+',[]),                           
            ('<expr>',[('<integer>',[('<digit>',[('2',[])])])])])])
    assert mystring == all_terminals(tree)
    display_tree(tree)


A2_GRAMMAR = {
   "<start>":
      ["<expr>"],
   "<expr>":
      ["<integer><expr_>"],
   "<expr_>":
      ["+<expr>", "-<expr>", ""],
   "<integer>":
      ["<digit><integer_>"],
   "<integer_>":
      ["<integer>", ""],
   "<digit>":
Beispiel #16
0
 def parse(self, inp):
     tree = self.parser.parse(inp)[0]
     print(all_terminals(tree))
     return tree
Beispiel #17
0
    def derivation_reductions(self, tree):
        (symbol, children) = tree
        if len(children) == 0:
            return []  # Terminal symbol

        print("Trying alternative expansions for " + symbol)

        # Possible expansions for this symbol
        expansions = self.grammar[symbol]
        print("Expansions: " + repr(expansions))

        alternatives = \
            [expansion_to_children(expansion) for expansion in expansions]

        reductions = []
        for alternative in alternatives:

            if len(alternative) > len(children):
                continue  # New alternative has more children

            match = True
            new_children_reductions = []
            # print("Trying alternative expansion " + queue_to_string(alternative))
            for alt_child in alternative:
                (alt_symbol, _) = alt_child
                child_reductions = subtrees_with_symbol(alt_symbol, tree)
                if len(child_reductions) == 0:
                    # Child not found; cannot apply rule
                    match = False
                    break

                # print("Found alternatives " + queue_to_string(child_reductions))
                new_children_reductions.append(child_reductions)

            if not match:
                continue  # Try next alternative

            # Go through the possible combinations
            for new_children in possible_combinations(new_children_reductions):
                new_tree = (symbol, new_children)

                if number_of_nodes(new_tree) >= number_of_nodes(tree):
                    continue  # No reduction

                reductions.append(new_tree)

        # Apply this recursively
        if children is not None:
            for i in range(0, len(children)):
                child = children[i]
                child_reductions = self.derivation_reductions(child)
                for reduced_child in child_reductions:
                    new_children = (children[:i] + [reduced_child] +
                                    children[i + 1:])
                    reductions.append((symbol, new_children))

        # Filter duplicates
        unique_reductions = []
        for r in reductions:
            if r not in unique_reductions:
                unique_reductions.append(r)
        reductions = unique_reductions

        if len(reductions) > 0:
            # We have a new expansion
            print("Can reduce " + symbol + " " + all_terminals(tree) +
                  " to reduced subtrees " + queue_to_string(reductions))

        return reductions