Ejemplo n.º 1
0
def graph_to_adj_matrix(graph: Graph):
    vertex_count = graph.vertex_len
    adj_matrix = [([0] * vertex_count) for _ in range(vertex_count)]
    for u in graph.vertex_keys():
        for v, _ in graph.get_vertex(u).successors():
            adj_matrix[u][v] = 1
    return adj_matrix
Ejemplo n.º 2
0
def dfs_internal(graph: Graph, src_key, pre_visit_func: Callable[[Any], bool],
                 post_visit_func: Callable[[Any], bool], result: DFSResult,
                 time: TimeCounter) -> bool:
    if not pre_visit_func(src_key):
        return False
    stack = [(src_key, graph.get_vertex(src_key).successors())]
    result.came_from[src_key] = None
    result.discover_times[src_key] = time.next()
    default_next_item = object()
    while stack:
        cur_key, iter = stack[-1]
        next_item = next(iter, default_next_item)
        if next_item == default_next_item:
            stack.pop(-1)
            result.finish_times[cur_key] = time.next()
            if not post_visit_func(cur_key):
                return False
            continue
        successor_key = next_item[0]
        if successor_key in result.discover_times:
            continue
        if not pre_visit_func(successor_key):
            return False
        result.came_from[successor_key] = cur_key
        result.discover_times[successor_key] = time.next()
        stack.append(
            (successor_key, graph.get_vertex(successor_key).successors()))
    return True
Ejemplo n.º 3
0
def get_transpose(graph: Graph):
    """Ex 22.1-3."""
    tr = Graph()
    for v in graph.vertex_keys():
        tr.add_vertex(Vertex(v))
    for u in graph.vertex_keys():
        for v, weight in graph.get_vertex(u).successors():
            tr.add_edge(v, u, weight)
    return tr
Ejemplo n.º 4
0
def _tree_diameter_recur_internal(tree: Graph, root_key, parents: set) -> Tuple[int, int]:
    diameter, depth = 0, 0
    root = tree.get_vertex(root_key)
    parents.add(root_key)
    successor_len = 0
    for v_key, _ in root.successors():
        if v_key not in parents:
            successor_len += 1
    if successor_len <= 0:
        # print('root_key=%d, diameter=%d, depth=%d (leaf)' % (root_key, diameter, depth))
        return diameter, depth
    max_sub_diameter, max_sub_depth, second_sub_depth = 0, -1, -1
    for v_key, _ in root.successors():
        if v_key in parents:
            continue
        sub_diameter, sub_depth = _tree_diameter_recur_internal(tree, v_key, parents)
        max_sub_diameter = max(max_sub_diameter, sub_diameter)
        if max_sub_depth < 0:
            max_sub_depth = sub_depth
        elif sub_depth >= max_sub_depth:
            second_sub_depth = max_sub_depth
            max_sub_depth = sub_depth
        elif sub_depth >= second_sub_depth:
            second_sub_depth = sub_depth
    depth = max_sub_depth + 1
    diameter = max(max_sub_depth + 1 if second_sub_depth < 0 else max_sub_depth + second_sub_depth + 2,
                   max_sub_diameter)

    # print('root_key=%d, diameter=%d, depth=%d' % (root_key, diameter, depth))
    return diameter, depth
Ejemplo n.º 5
0
 def _check_topological_sort_result(self, graph: Graph, result: Sequence):
     # result = list(result)
     self.assertEqual(graph.vertex_len, len(result))
     for i in range(len(result) - 1):
         for j in range(i + 1, len(result)):
             # print('edge "%s" -> "%s" does not exist.' % (result[j], result[i]))
             self.assertFalse(graph.has_edge(result[j], result[i]))
Ejemplo n.º 6
0
def scc_tarjan(graph: Graph) -> List[List]:
    sccs = []
    cache = TarjanCache()
    time = TimeCounter()
    for v_key in graph.vertex_keys():
        if v_key not in cache.discover_times:
            _tarjan_internal(graph, v_key, sccs, cache, time)
    return sccs
Ejemplo n.º 7
0
def topological_sort_kahn(graph: Graph) -> list:
    """
    Ex 22.4-5. If return list is shorter than graph vertex length, it means the topological sort cannot be performed.
    O(V + E) time.
    """
    in_degrees = {}
    ret = []
    for v_key in graph.vertex_keys():
        in_degrees[v_key] = 0
    for u_key in graph.vertex_keys():
        for v_key, _ in graph.get_vertex(u_key).successors():
            in_degrees[v_key] += 1

    zero_in_degree_set = deque()
    for v_key in graph.vertex_keys():
        if in_degrees[v_key] == 0:
            zero_in_degree_set.append(v_key)

    while zero_in_degree_set:
        u_key = zero_in_degree_set.popleft()
        ret.append(u_key)
        for v_key, _ in list(graph.get_vertex(u_key).successors()):
            graph.remove_edge(u_key, v_key)
            in_degrees[v_key] -= 1
            if in_degrees[v_key] == 0:
                zero_in_degree_set.append(v_key)
    return ret
Ejemplo n.º 8
0
def euler_tour_undirected(graph: Graph) -> list:
    ret = []
    if graph.vertex_len == 0:
        return ret
    for v_key in graph.vertex_keys():
        ret.append(v_key)
        break
    ret, _ = _euler(graph, ret, 0)
    return ret
Ejemplo n.º 9
0
def _euler(graph: Graph, path: list, src_index: int) -> Tuple[list, int]:
    src_key = path[src_index]
    src = graph.get_vertex(src_key)
    u = src
    sub_path = [src_key]
    while u.successor_len > 0:
        v = None
        for v_key, _ in u.successors():
            v = graph.get_vertex(v_key)
            break
        graph.remove_edge(u.key, v.key)
        graph.remove_edge(v.key, u.key)
        sub_path.append(v.key)
        u = v
    i = 1
    while i < len(sub_path):
        sub_path, delta_len = _euler(graph, sub_path, i)
        i += delta_len

    path = path[0:src_index] + sub_path + path[src_index + 1:]
    return path, len(sub_path)
Ejemplo n.º 10
0
    def test_topological_sort_with_loop(self):
        cases = []
        graph = Graph()
        graph.add_vertex(Vertex(0))
        graph.add_edge(0, 0)
        cases.append(graph)

        graph = self._graph_from_figure_22_8()
        graph.add_edge("v", "p")  # Add an edge to form a loop
        cases.append(graph)

        for graph in cases:
            self.assertLess(len(topological_sort_kahn(graph)),
                            graph.vertex_len)
Ejemplo n.º 11
0
def bfs(graph: Graph, visit_func: Callable[[Any], bool]=None) -> Tuple[dict, dict]:
    open_set = deque()
    came_from = {}
    depths = {}
    visited = set()   # Gray or black nodes
    if not visit_func:
        def visit_func(_): return True

    for v in graph.vertex_keys():
        if v in visited:
            continue
        _bfs_internal(graph, v, visit_func, open_set, came_from, depths, visited)
    return came_from, depths
Ejemplo n.º 12
0
def astar(graph: Graph,
          src_key,
          dst_key,
          heuristic_func: Callable[[Any], float] = None) -> dict:
    open_set = {src_key: 0}
    closed_set = set()
    came_from = {src_key: None}

    while open_set:
        u, u_cost = extract_min(open_set, heuristic_func)  # Diff from Dijkstra
        closed_set.add(u)

        if u == dst_key:  # Diff from dijkstra
            break

        for v, w in graph.get_vertex(u).successors():
            if v in closed_set:
                continue
            new_cost = u_cost + graph.edge_weight(u, v)
            if v not in open_set or open_set[v] > new_cost:
                open_set[v] = new_cost
                came_from[v] = u
    return came_from
Ejemplo n.º 13
0
def dijkstra(graph: Graph, src_key) -> dict:
    open_set = {src_key: 0}
    closed_set = set()
    came_from = {src_key: None}
    while open_set:
        u, u_cost = extract_min(open_set)
        closed_set.add(u)
        for v, w in graph.get_vertex(u).successors():
            if v in closed_set:
                continue
            new_cost = u_cost + w
            if v not in open_set or open_set[v] > new_cost:
                came_from[v] = u
                open_set[v] = new_cost
    return came_from
Ejemplo n.º 14
0
def graph_from_adj_matrix(adj_matrix) -> Graph:
    vertex_count = len(adj_matrix)
    graph = Graph()
    for i in range(vertex_count):
        graph.add_vertex(Vertex(i))
    for i in range(vertex_count):
        for j in range(vertex_count):
            if adj_matrix[i][j]:
                graph.add_edge(i, j)
    return graph
Ejemplo n.º 15
0
 def test_mohammed_scimitars(self):
     graph = Graph()
     for i in range(11):
         graph.add_vertex(Vertex(i))
     for edge in ((0, 1), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (3, 5),
                  (3, 6), (4, 5), (4, 8), (5, 6), (5, 8), (6, 7), (6, 10),
                  (7, 8), (7, 9), (7, 10), (8, 9)):
         graph.add_2_edges(edge[0], edge[1])
     self.assertSequenceEqual(
         [0, 1, 2, 3, 5, 4, 8, 7, 6, 10, 7, 9, 8, 5, 6, 3, 1, 4, 0],
         euler_tour_undirected(graph))
Ejemplo n.º 16
0
def _bfs_internal(graph: Graph, src_key, visit_func: Callable[[Any], bool],
                  open_set: deque, came_from: dict, depths: dict, visited: set):
    open_set.appendleft(src_key)
    visited.add(src_key)
    depths[src_key] = 0

    while open_set:
        u = open_set.pop()
        if not visit_func(u):
            break
        for v, _ in graph.get_vertex(u).successors():
            if v in visited:
                continue
            came_from[v] = u
            open_set.appendleft(v)
            visited.add(v)
            depths[v] = depths[u] + 1
Ejemplo n.º 17
0
def dfs(graph: Graph, pre_visit_func: Callable[[Any], bool]=None, post_visit_func: Callable[[Any], bool]=None)\
        -> DFSResult:
    """Ex. 22.3-7"""
    if not pre_visit_func:

        def pre_visit_func(_):
            return True

    if not post_visit_func:

        def post_visit_func(_):
            return True

    result = DFSResult()
    time = TimeCounter()
    for v in graph.vertex_keys():
        if v not in result.discover_times and not dfs_internal(
                graph, v, pre_visit_func, post_visit_func, result, time):
            break
    return result
Ejemplo n.º 18
0
def count_simple_path(graph: Graph, src_key, dst_key) -> int:
    """Ex 22.4-2. O(V + E) time."""
    sort_result = topological_sort_dfs(graph)
    src_index, dst_index = -1, -1
    for i in range(len(sort_result)):
        if sort_result[i] == src_key:
            src_index = i
        if sort_result[i] == dst_key:
            dst_index = i
    assert src_index >= 0
    assert dst_index >= 0
    if src_index >= dst_index:
        return 0
    counts = [0] * (dst_index - src_index + 1)
    checked_vertices = {}
    for i in range(dst_index - 1, src_index - 1, -1):
        checked_vertices[sort_result[i]] = i
        for v_key, _ in graph.get_vertex(sort_result[i]).successors():
            if v_key == dst_key:
                counts[i] += 1
            elif v_key in checked_vertices:
                counts[i] += counts[checked_vertices[v_key]]
    return counts[0]
Ejemplo n.º 19
0
def _tarjan_internal(graph: Graph, src_key, sccs: List[List],
                     cache: TarjanCache, time: TimeCounter):
    cache.in_stack.add(src_key)
    cache.stack.append(src_key)
    cache.discover_times[src_key] = cache.low[src_key] = time.next()
    for v_key, _ in graph.get_vertex(src_key).successors():
        if v_key not in cache.discover_times:
            _tarjan_internal(graph, v_key, sccs, cache, time)
            cache.low[src_key] = min(cache.low[src_key], cache.low[v_key])
        elif v_key not in cache.finish_times:
            cache.low[src_key] = min(cache.low[src_key],
                                     cache.discover_times[v_key])
    cache.finish_times[src_key] = time.next()

    if cache.low[src_key] == cache.discover_times[src_key]:
        scc = []
        while True:
            v_key = cache.stack.pop()
            cache.in_stack.remove(v_key)
            scc.append(v_key)
            if v_key == src_key:
                break
        sccs.append(scc)
Ejemplo n.º 20
0
def dijkstra_basic_test_case():
    graph = Graph()
    vertices = [Vertex(i) for i in range(1, 8)]
    for v in vertices:
        graph.add_vertex(v)
    graph.add_edge(1, 2, 7)
    graph.add_edge(2, 1, 7)
    graph.add_edge(1, 3, 9)
    graph.add_edge(3, 1, 9)
    graph.add_edge(1, 6, 14)
    graph.add_edge(6, 1, 14)
    graph.add_edge(2, 3, 10)
    graph.add_edge(3, 2, 10)
    graph.add_edge(2, 4, 15)
    graph.add_edge(4, 2, 15)
    graph.add_edge(3, 4, 11)
    graph.add_edge(4, 3, 11)
    graph.add_edge(3, 6, 2)
    graph.add_edge(6, 3, 2)
    graph.add_edge(4, 5, 6)
    graph.add_edge(5, 4, 6)
    graph.add_edge(5, 6, 9)
    graph.add_edge(6, 5, 9)

    src = 1

    expected_results = {
        1: (1, ),
        2: (1, 2),
        3: (1, 3),
        4: (1, 3, 4),
        5: (1, 3, 6, 5),
        6: (1, 3, 6),
        7: (),
    }
    return graph, src, expected_results
Ejemplo n.º 21
0
    def test_euler_undirected(self):
        graph = Graph()
        for i in range(7, -1, -1):
            graph.add_vertex(Vertex(i))
        graph.add_2_edges(0, 1)
        graph.add_2_edges(1, 2)
        graph.add_2_edges(0, 3)
        graph.add_2_edges(1, 3)
        graph.add_2_edges(1, 4)
        graph.add_2_edges(2, 4)
        graph.add_2_edges(3, 5)
        graph.add_2_edges(3, 6)
        graph.add_2_edges(4, 6)
        graph.add_2_edges(4, 7)
        graph.add_2_edges(5, 6)
        graph.add_2_edges(6, 7)
        self.assertSequenceEqual([0, 1, 2, 4, 6, 3, 5, 6, 7, 4, 1, 3, 0],
                                 euler_tour_undirected(graph))

        graph = Graph()
        for i in range(6):
            graph.add_vertex(Vertex(i))
        graph.add_2_edges(0, 1)
        graph.add_2_edges(0, 2)
        graph.add_2_edges(0, 3)
        graph.add_2_edges(0, 4)
        graph.add_2_edges(1, 2)
        graph.add_2_edges(1, 3)
        graph.add_2_edges(1, 4)
        graph.add_2_edges(2, 3)
        graph.add_2_edges(3, 4)
        graph.add_2_edges(2, 5)
        graph.add_2_edges(4, 5)
        self.assertSequenceEqual([0, 1, 2, 3, 4, 5, 2, 0, 3, 1, 4, 0],
                                 euler_tour_undirected(graph))
Ejemplo n.º 22
0
    def test_dfs(self):
        graph = Graph()
        graph.add_vertex(Vertex('s'))
        graph.add_vertex(Vertex('t'))
        graph.add_vertex(Vertex('u'))
        graph.add_vertex(Vertex('v'))
        graph.add_vertex(Vertex('w'))
        graph.add_vertex(Vertex('x'))
        graph.add_vertex(Vertex('y'))
        graph.add_vertex(Vertex('z'))
        graph.add_edge('z', 'y')
        graph.add_edge('s', 'z')
        graph.add_edge('y', 'x')
        graph.add_edge('x', 'z')
        graph.add_edge('z', 'w')
        graph.add_edge('s', 'w')
        graph.add_edge('v', 's')
        graph.add_edge('t', 'v')
        graph.add_edge('t', 'u')
        graph.add_edge('u', 't')
        graph.add_edge('w', 'x')
        graph.add_edge('v', 'w')
        graph.add_edge('u', 'v')

        pre_visit_array = []

        def pre_visit(v):
            pre_visit_array.append(v)
            return True

        post_visit_array = []

        def post_visit(v):
            post_visit_array.append(v)
            return True

        result = dfs(graph, pre_visit, post_visit)

        expected_result = DFSResult()
        expected_result.discover_times = {
            's': 1,
            'w': 2,
            'x': 3,
            'z': 4,
            'y': 5,
            't': 11,
            'u': 12,
            'v': 13
        }
        expected_result.finish_times = {
            'y': 6,
            'z': 7,
            'x': 8,
            'w': 9,
            's': 10,
            'v': 14,
            'u': 15,
            't': 16
        }
        expected_result.came_from = {
            's': None,
            'w': 's',
            'x': 'w',
            'z': 'x',
            'y': 'z',
            't': None,
            'u': 't',
            'v': 'u'
        }
        expected_pre_visit_array = ['s', 'w', 'x', 'z', 'y', 't', 'u', 'v']
        expected_post_visit_array = ['y', 'z', 'x', 'w', 's', 'v', 'u', 't']
        self.assertEqual(expected_result, result)
        self.assertSequenceEqual(expected_pre_visit_array, pre_visit_array)
        self.assertSequenceEqual(expected_post_visit_array, post_visit_array)
Ejemplo n.º 23
0
def terrain_to_graph(terrain):
    graph = Graph()
    if not terrain or not terrain[0]:
        return graph
    h = len(terrain)
    w = len(terrain[0])
    for x in range(0, w):
        for y in range(0, h):
            graph.add_vertex(Vertex((x, y)))

    for x in range(0, w):
        for y in range(0, h):
            if terrain[y][x] < 0:
                continue
            if x - 1 >= 0 and terrain[y][x - 1] >= 0:
                graph.add_edge((x, y), (x - 1, y), terrain[y][x])
            if y - 1 >= 0 and terrain[y - 1][x] >= 0:
                graph.add_edge((x, y), (x, y - 1), terrain[y][x])
            if x + 1 < w and terrain[y][x + 1] >= 0:
                graph.add_edge((x, y), (x + 1, y), terrain[y][x])
            if y + 1 < h and terrain[y + 1][x] >= 0:
                graph.add_edge((x, y), (x, y + 1), terrain[y][x])
    return graph
Ejemplo n.º 24
0
 def _graph_from_figure_22_9() -> Graph:
     graph = Graph()
     graph.add_vertex(Vertex('a'))
     graph.add_vertex(Vertex('b'))
     graph.add_vertex(Vertex('c'))
     graph.add_vertex(Vertex('d'))
     graph.add_vertex(Vertex('e'))
     graph.add_vertex(Vertex('f'))
     graph.add_vertex(Vertex('g'))
     graph.add_vertex(Vertex('h'))
     graph.add_edge('a', 'b')
     graph.add_edge('b', 'c')
     graph.add_edge('b', 'e')
     graph.add_edge('b', 'f')
     graph.add_edge('c', 'd')
     graph.add_edge('c', 'g')
     graph.add_edge('d', 'c')
     graph.add_edge('d', 'h')
     graph.add_edge('e', 'a')
     graph.add_edge('e', 'f')
     graph.add_edge('f', 'g')
     graph.add_edge('g', 'f')
     graph.add_edge('g', 'h')
     graph.add_edge('h', 'h')
     return graph
Ejemplo n.º 25
0
 def _graph_from_figure_22_7(self):
     graph = Graph()
     graph.add_vertex(Vertex("undershorts"))
     graph.add_vertex(Vertex("socks"))
     graph.add_vertex(Vertex("watch"))
     graph.add_vertex(Vertex("pants"))
     graph.add_vertex(Vertex("shoes"))
     graph.add_vertex(Vertex("belt"))
     graph.add_vertex(Vertex("shirt"))
     graph.add_vertex(Vertex("tie"))
     graph.add_vertex(Vertex("jacket"))
     graph.add_edge("undershorts", "pants")
     graph.add_edge("undershorts", "shoes")
     graph.add_edge("socks", "shoes")
     graph.add_edge("pants", "shoes")
     graph.add_edge("pants", "belt")
     graph.add_edge("shirt", "belt")
     graph.add_edge("shirt", "tie")
     graph.add_edge("tie", "jacket")
     graph.add_edge("belt", "jacket")
     return graph
Ejemplo n.º 26
0
 def _graph_from_figure_22_8(self):
     graph = Graph()
     graph.add_vertex(Vertex("m"))
     graph.add_vertex(Vertex("n"))
     graph.add_vertex(Vertex("o"))
     graph.add_vertex(Vertex("p"))
     graph.add_vertex(Vertex("q"))
     graph.add_vertex(Vertex("r"))
     graph.add_vertex(Vertex("s"))
     graph.add_vertex(Vertex("t"))
     graph.add_vertex(Vertex("u"))
     graph.add_vertex(Vertex("v"))
     graph.add_vertex(Vertex("w"))
     graph.add_vertex(Vertex("x"))
     graph.add_vertex(Vertex("y"))
     graph.add_vertex(Vertex("z"))
     graph.add_edge("m", "q")
     graph.add_edge("m", "r")
     graph.add_edge("m", "x")
     graph.add_edge("n", "o")
     graph.add_edge("n", "q")
     graph.add_edge("n", "u")
     graph.add_edge("o", "r")
     graph.add_edge("o", "s")
     graph.add_edge("o", "v")
     graph.add_edge("p", "o")
     graph.add_edge("p", "s")
     graph.add_edge("p", "z")
     graph.add_edge("q", "t")
     graph.add_edge("r", "u")
     graph.add_edge("r", "y")
     graph.add_edge("s", "r")
     graph.add_edge("u", "t")
     graph.add_edge("v", "w")
     graph.add_edge("v", "x")
     graph.add_edge("w", "z")
     graph.add_edge("y", "v")
     return graph
Ejemplo n.º 27
0
    def test_bfs(self):
        # Figure 22-3
        graph = Graph()
        graph.add_vertex(Vertex('r'))
        graph.add_vertex(Vertex('s'))
        graph.add_vertex(Vertex('t'))
        graph.add_vertex(Vertex('u'))
        graph.add_vertex(Vertex('v'))
        graph.add_vertex(Vertex('w'))
        graph.add_vertex(Vertex('x'))
        graph.add_vertex(Vertex('y'))
        graph.add_2_edges('r', 's')
        graph.add_2_edges('r', 'v')
        graph.add_2_edges('s', 'w')
        graph.add_2_edges('t', 'u')
        graph.add_2_edges('t', 'w')
        graph.add_2_edges('t', 'x')
        graph.add_2_edges('u', 'x')
        graph.add_2_edges('u', 'y')
        graph.add_2_edges('w', 'x')
        graph.add_2_edges('x', 'y')

        came_from = bfs_with_src(graph, 's')[0]
        self.assertDictEqual({
            'v': 'r',
            'r': 's',
            'w': 's',
            't': 'w',
            'x': 'w',
            'y': 'x',
            'u': 't',
        }, came_from)
Ejemplo n.º 28
0
 def test_tree_diameter(self):
     methods = (tree_diameter_recur, tree_diameter_bfs)
     tree = Graph()
     for i in range(0, 16):
         tree.add_vertex(Vertex(i))
     tree.add_2_edges(0, 1)
     tree.add_2_edges(0, 2)
     tree.add_2_edges(0, 3)
     tree.add_2_edges(1, 4)
     tree.add_2_edges(1, 5)
     tree.add_2_edges(2, 6)
     tree.add_2_edges(3, 7)
     tree.add_2_edges(3, 8)
     tree.add_2_edges(4, 9)
     tree.add_2_edges(5, 10)
     tree.add_2_edges(5, 11)
     tree.add_2_edges(6, 12)
     tree.add_2_edges(6, 13)
     tree.add_2_edges(6, 14)
     tree.add_2_edges(14, 15)
     for tree_diameter_method in methods:
         for root in range(0, 16):
             # print('root: %d' % root)
             self.assertEqual(7, tree_diameter_method(tree, root))