Пример #1
0
 def test_matrix_to_adj(self):
     a = Matrix(size=2)
     a.add_edge(0, 1)
     nodes = [
         Node(colour=Colour.BLUE, id=1),
         Node(colour=Colour.BLACK, id=2)
     ]
     result = utils.matrix_to_adj(nodes, a)
     assert result.get(nodes[0], []) == [nodes[1]]
    def test_equal_size(self):
        a = Matrix(size = 3)
        a.add_edge(0, 1)
        b = Matrix(size = 4)
        b.add_edge(0, 1)

        assert not a.equals(b)
Пример #3
0
def combine_adj_matrix(starting_node: int, graph1: Matrix, graph2: Matrix,
                       target_nodes: List[int]) -> Matrix:
    if graph1.equals(graph2):
        return graph1
    elif graph1.subset(graph2):
        return graph1
    elif graph2.subset(graph1):
        return graph2

    out = Matrix(graph1.size())

    def does_lead_to_target(curr_node, visited: Set[int]):
        if curr_node not in target_nodes:
            if curr_node not in visited:
                all_outgoing = set(
                    graph1.get_connected_lst(curr_node) +
                    graph2.get_connected_lst(curr_node))
                visited.add(curr_node)
                for outgoing in all_outgoing:
                    if outgoing not in visited:
                        # out.add_edge(curr_node, outgoing)
                        if does_lead_to_target(outgoing, visited):
                            return True
            return False
        else:
            return True

    def traverse(curr_node, visited: Set[int]):
        # Do nothing if we already visited the node
        if curr_node not in visited:
            # Get all outgoing edges
            all_outgoing = set(
                graph1.get_connected_lst(curr_node) +
                graph2.get_connected_lst(curr_node))
            visited.add(curr_node)
            for outgoing in all_outgoing:
                # Make sure we don't go in circles, make sure to prune any extraneous edges
                if outgoing not in visited and does_lead_to_target(
                        outgoing, deepcopy(visited)):
                    out.add_edge(curr_node, outgoing)
                    traverse(outgoing, visited)

    traverse(starting_node, set())
    return out
Пример #4
0
def find_children(graph: Matrix, starting_node: int, has_visited: List[int],
                  remaining_targets: List[int],
                  curr_matrix: Matrix) -> Iterator[Matrix]:
    # Get all children of root.
    children_of_root = graph.get_connected_lst(starting_node)

    for child in children_of_root:
        if child == starting_node:
            logging.debug("Skipping duplicate node: {0}".format(child))
            continue

        if child in has_visited:
            logging.debug("Skipping visited child: {0}".format(child))
            continue

        if child in remaining_targets:  # We found one of our target nodes!
            logging.debug("Found a child node: {0}".format(child))
            # TODO: Bug here is two found nodes have the same parent, (not in serial), this algorithm fails.

            # Remove child from target nodes, and recurse
            remaining_children = [x for x in remaining_targets if x != child]
        else:
            # We didn't hit a child, so no changes.
            remaining_children = remaining_targets

        # Add an edge between the current node and the child
        new_matrix = deepcopy(curr_matrix)
        new_matrix.add_edge(starting_node, child)

        if len(remaining_children) == 0:
            # We've found all children, we're done!
            yield new_matrix
        else:
            yield from find_children(
                graph=graph,
                starting_node=child,
                # Make sure we don't go in circles
                has_visited=has_visited + [child],
                remaining_targets=remaining_children,
                curr_matrix=new_matrix)
Пример #5
0
def traverse_graph(graph: Dict[Node, List[Node]], target_colours: List[Colour]) \
        -> Iterator[Dict[Node, List[Node]]]:
    nodes = list(graph.keys())
    num_nodes = len(nodes)
    graph_matrix = utils.adj_to_matrix(graph)

    # Lookup all nodes with that same colour
    node_colour_lookup: Dict[Colour, List[Node]] = build_node_colour_lookup(
        list(graph.keys()))

    target_node_sets: Iterator[List[int]] = get_all_target_nodes(
        nodes=nodes, targets=target_colours, node_colours=node_colour_lookup)
    green_nodes: List[int] = utils.node_to_index(
        nodes, node_colour_lookup.get(Colour.GREEN, []))
    all_final_mat_output: List[Matrix] = []
    # We must start at the green nodes, so if they aren't present, we know there's no solution
    # Try it from every green node
    for green in green_nodes:
        # Get every set of end-nodes, try and build a graph to each set
        for target_nodes_set in target_node_sets:
            # store adjacency matrix from the particular green node to the particular target node
            green_to_target: List[Matrix] = []
            # Go to each individual target node
            for target_node in target_nodes_set:
                green_to_target.extend(
                    list(
                        find_children(
                            graph=graph_matrix,
                            starting_node=green,
                            has_visited=[green
                                         ],  # Make sure we don't go in circles
                            remaining_targets=[target_node],
                            curr_matrix=Matrix(size=num_nodes))))
            if len(target_nodes_set) == 1:
                # There's only one node we're looking for, so output all paths to that node
                for completed_matrix in green_to_target:
                    completed_adj = utils.matrix_to_adj(
                        nodes, completed_matrix)
                    yield completed_adj
            else:
                # Once we've gotten paths between that green node and every target node in the set, it's time to combine them and check!
                for combination in itertools.combinations(
                        range(len(green_to_target)), r=len(target_nodes_set)):
                    # Create the merged graph
                    merged = Matrix(size=num_nodes)
                    for c in combination:
                        merged = combine_adj_matrix(green, green_to_target[c],
                                                    merged, target_nodes_set)

                    # G1 and G2 are the two adjacency lists to combine from green_to_target
                    # They will have the same starting node, but different ending node
                    # Determine if we've already output it
                    if not utils.has_prev_output_graph(all_final_mat_output,
                                                       merged):
                        # Determine if it meets all criteria
                        # (does it contain all of the target nodes)
                        did_get_all_targets = True
                        for target in target_nodes_set:
                            did_get_all_targets = did_get_all_targets and len(
                                merged.inward_edges_lst(target)) > 0

                        # Determine if we got them all
                        if did_get_all_targets:
                            all_final_mat_output.append(merged)
                            merged_adj = utils.matrix_to_adj(nodes, merged)
                            yield merged_adj
 def test_add_edge(self):
     m = Matrix(size = 3)
     m.add_edge(0, 1)
     assert m.get_edge(0, 1)
 def test_create_matrix_size(self):
     m = Matrix(size = 3)
     assert m.size() == 3
 def test_connected(self):
     m = Matrix(size = 3)
     m.add_edge(0, 1)
     assert 1 in m.get_connected_lst(0)
Пример #9
0
 def test_matrix_to_adj_debug(self):
     a = Matrix(size=2)
     a.add_edge(0, 1)
     result = utils.matrix_to_adj_debug(a)
     assert result.get(0, []) == [1]
Пример #10
0
    def test_has_prev_output(self):
        a = Matrix(size=3)
        b = Matrix(size=3)
        c = Matrix(size=3)

        a.add_edge(0, 1)
        b.add_edge(1, 2)
        c.add_edge(0, 2)

        prev_output = [a, b]
        assert not utils.has_prev_output_graph(prev_output, c)
        assert utils.has_prev_output_graph(prev_output, a)