Example #1
0
 def beam_search(self, graph, source, destination, beam_width):
     print(f'doing beam search with beam width: {beam_width}')
     path = []
     for edge in nx.bfs_beam_edges(graph, source, lambda _: 1, beam_width):
         if edge[1] != destination:
             path.append(edge[1])
         else:
             break
     print(f'beam search cost: {len(path)}')
Example #2
0
 def test_narrow(self):
     """Tests that a narrow beam width may cause an incomplete search."""
     # In this search, we enqueue only the neighbor 3 at the first
     # step, then only the neighbor 2 at the second step. Once at
     # node 2, the search chooses node 3, since it has a higher value
     # that node 1, but node 3 has already been visited, so the
     # search terminates.
     G = nx.cycle_graph(4)
     edges = nx.bfs_beam_edges(G, 0, identity, width=1)
     assert_equal(list(edges), [(0, 3), (3, 2)])
Example #3
0
 def test_narrow(self):
     """Tests that a narrow beam width may cause an incomplete search."""
     # In this search, we enqueue only the neighbor 3 at the first
     # step, then only the neighbor 2 at the second step. Once at
     # node 2, the search chooses node 3, since it has a higher value
     # that node 1, but node 3 has already been visited, so the
     # search terminates.
     G = nx.cycle_graph(4)
     edges = nx.bfs_beam_edges(G, 0, identity, width=1)
     assert list(edges) == [(0, 3), (3, 2)]
Example #4
0
def progressive_widening_search(a: nx.classes.graph.Graph, s: int, v, con: Callable[[int], bool], initial_width: int = 1) -> int:
    if con(s):
        return s
    log_m = math.ceil(math.log2((len(a))))
    for i in range(log_m):
        width = initial_width * pow(2, i)
        for u, v in nx.bfs_beam_edges(a, s, v, width):
            if con(v):
                return v
    print(nx.NodeNotFound("no node"))
Example #5
0
def progressive_widening_search(G, source, value, condition, initial_width=1):
    if condition(source):
        return source
    log_m = math.ceil(math.log2(len(G)))
    for i in range(log_m):
        width = initial_width * pow(2, i)
        for u, v in nx.bfs_beam_edges(G, source, value, width):
            if condition(v):
                return v
    raise nx.NodeNotFound("no node satisfied the termination condition")
Example #6
0
def progressive_widening_search(G, source, value, condition, initial_width=1):
    """Progressive widening beam search to find a node.

    The progressive widening beam search involves a repeated beam
    search, starting with a small beam width then extending to
    progressively larger beam widths if the target node is not
    found. This implementation simply returns the first node found that
    matches the termination condition.

    `G` is a NetworkX graph.

    `source` is a node in the graph. The search for the node of interest
    begins here and extends only to those nodes in the (weakly)
    connected component of this node.

    `value` is a function that returns a real number indicating how good
    a potential neighbor node is when deciding which neighbor nodes to
    enqueue in the breadth-first search. Only the best nodes within the
    current beam width will be enqueued at each step.

    `condition` is the termination condition for the search. This is a
    function that takes a node as input and return a Boolean indicating
    whether the node is the target. If no node matches the termination
    condition, this function raises :exc:`NodeNotFound`.

    `initial_width` is the starting beam width for the beam search (the
    default is one). If no node matching the `condition` is found with
    this beam width, the beam search is restarted from the `source` node
    with a beam width that is twice as large (so the beam width
    increases exponentially). The search terminates after the beam width
    exceeds the number of nodes in the graph.

    """
    # Check for the special case in which the source node satisfies the
    # termination condition.
    if condition(source):
        return source
    # The largest possible value of `i` in this range yields a width at
    # least the number of nodes in the graph, so the final invocation of
    # `bfs_beam_edges` is equivalent to a plain old breadth-first
    # search. Therefore, all nodes will eventually be visited.
    #
    # TODO In Python 3.3+, this should be `math.log2(len(G))`.
    log_m = math.ceil(math.log(len(G), 2))
    for i in range(log_m):
        width = initial_width * pow(2, i)
        # Since we are always starting from the same source node, this
        # search may visit the same nodes many times (depending on the
        # implementation of the `value` function).
        for u, v in nx.bfs_beam_edges(G, source, value, width):
            if condition(v):
                return v
    # At this point, since all nodes have been visited, we know that
    # none of the nodes satisfied the termination condition.
    raise nx.NodeNotFound('no node satisfied the termination condition')
Example #7
0
def neighbors_graph(ingraph, source, beamwidth=4, maxnodes=10):
    """ Neighbors of source node in ingraph """
    assert ingraph.is_directed(), "not implemented for undirected graphs"
    centrality = nx.eigenvector_centrality_numpy(
        ingraph)  # max_iter=10 tol=0.1
    outgraph = nx.MultiDiGraph()
    for u, v in nx.bfs_beam_edges(ingraph, source, centrality.get, beamwidth):
        if isinstance(ingraph, nx.MultiDiGraph):
            outgraph.add_edge(u, v, key=0, **(ingraph.get_edge_data(u, v)[0]))
        else:
            outgraph.add_edge(u, v, **(ingraph.get_edge_data(u, v)))
        if outgraph.number_of_nodes() >= maxnodes:
            break
    return outgraph
Example #8
0
 def test_wide(self):
     G = nx.cycle_graph(4)
     edges = nx.bfs_beam_edges(G, 0, identity, width=2)
     assert_equal(list(edges), [(0, 3), (0, 1), (3, 2)])
Example #9
0
 def test_wide(self):
     G = nx.cycle_graph(4)
     edges = nx.bfs_beam_edges(G, 0, identity, width=2)
     assert list(edges) == [(0, 3), (0, 1), (3, 2)]
Example #10
0
corner_tiles = [n[0] for n in G.degree() if n[1] == 2]

print(f"Product of edge tile ids: {math.prod(corner_tiles)}")

#%% Part 2

visited = {corner_tiles[0]}


def tile_score(x: int) -> int:
    return visited.add(x) or -sum(n in visited for n in G.neighbors(x))


c0 = corner_tiles[0]
tile_ids = [c0] + [v for _, v in nx.bfs_beam_edges(G, c0, tile_score, 4)]

tile_map = np.zeros((12, 12), dtype=int)
idx = np.argsort(np.add.outer(np.arange(12), np.arange(12)).ravel(), kind="stable")
tile_map.ravel()[idx] = np.array(tile_ids)

result = np.zeros((12*8, 12*8), dtype=int)

top_left_tile: ImageTile = tiles[tile_map[0, 0]]
top_left_tile.match_right(G.get_edge_data(tile_map[0, 0], tile_map[0, 1])["border"])
if top_left_tile.borders()[1] != G.get_edge_data(tile_map[0, 0], tile_map[1, 0])["border"]:
    top_left_tile.flip()
result[0:8, 0:8] = top_left_tile.data[1:9, 1:9]
for y in range(1, 12):
    tile_above: ImageTile = tiles[tile_map[y-1, 0]]
    tile: ImageTile = tiles[tile_map[y, 0]]
plt.savefig("Session8 Graph c BFS.png")
plt.title("Graph c BFS algorithm" , color='blue', fontweight='bold')
plt.show()

Successors=nx.bfs_successors(c_G,'B')
print("Successors: ",dict(Successors))
Predecessors=nx.bfs_predecessors(c_G,'B')
print("Predecessors: ",dict(Predecessors))

""" Beam seach algorithm  of Graph a with the width=2"""
print("###Grapg info and result of beam search of graph a############################")
print(nx.info(a_G))
eigen_centra=nx.eigenvector_centrality(a_G)
source = 'A'
width = 2
bfs_beam_edges=nx.bfs_beam_edges(a_G, source, eigen_centra.get, width)
beam_graph=nx.DiGraph()
beam_graph.add_edges_from(bfs_beam_edges)
print("\n Beam Search Result: ",list(beam_graph.edges))

color_map=[]
for node in beam_graph:
    if node =='A':
        color_map.append('pink')
    else: 
        color_map.append('blue')
figure(num=None, figsize=(14, 6), dpi=80, facecolor='w', edgecolor='k')
plt.subplot(121)
nx.draw(beam_graph, with_labels=True, node_color=color_map,node_size=500)