Пример #1
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
Пример #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
Пример #3
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
Пример #4
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
Пример #5
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
Пример #6
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)
Пример #7
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
Пример #8
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
Пример #9
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)
Пример #10
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]
Пример #11
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