def _get_lower_bound_of_ap_nodes(G, c=1.0): """ Returns the articulation points and lower bound for each of them. Procedure 3 of https://dl.acm.org/profile/81484650642 Parameters ---------- G : graph An undirected graph. c : float To define zeta: zeta = c * (n*n*n), and zeta is the large value assigned as the shortest distance of two unreachable vertices. Default is 1. """ v_ap = [] lower_bound = dict() N_G = len(G) zeta = c * math.pow(N_G, 3) components = connected_components(G) for component in components: component_subgraph = G.nodes_subgraph(from_nodes=list(component)) articulation_points = list( generator_articulation_points(component_subgraph)) N_component = len(component_subgraph) for articulation in articulation_points: component_subgraph_after_remove = component_subgraph.copy() component_subgraph_after_remove.remove_node(articulation) lower_bound_value = 0 lower_bound_value += sum([(len(temp) * (N_G - len(temp))) for temp in components]) lower_bound_value += sum([ (len(temp) * (N_component - 1 - len(temp))) for temp in connected_components( component_subgraph_after_remove) ]) lower_bound_value += (2 * N_component - 2 * N_G) lower_bound_value *= zeta v_ap.append(articulation) lower_bound[articulation] = lower_bound_value del component_subgraph_after_remove del component_subgraph return v_ap, lower_bound
def procedure1(G, c=1.0): """ Procedure 1 of https://dl.acm.org/profile/81484650642 Parameters ----------- G : graph c : float To define zeta: zeta = c * (n*n*n) Default is 1. """ components = connected_components(G) upper_bound = 0 for component in components: component_subgraph = G.nodes_subgraph(from_nodes=list(component)) spanning_tree = _get_spanning_tree_of_component(component_subgraph) random_root = list(spanning_tree.nodes)[random.randint( 0, len(spanning_tree) - 1)] num_subtree_nodes = _get_num_subtree_nodes(spanning_tree, random_root) N_tree = num_subtree_nodes[random_root] for node, num in num_subtree_nodes.items(): upper_bound += 2 * num * (N_tree - num) del component_subgraph, spanning_tree N_G = len(G) zeta = c * math.pow(N_G, 3) for component in components: N_c = len(component) upper_bound += N_c * (N_G - N_c) * zeta return upper_bound
def _get_upper_bound_of_non_ap_nodes(G, ap: list, c=1.0): """ Returns the upper bound value for each non-articulation points. Eq.(14) of https://dl.acm.org/profile/81484650642 Parameters ---------- G : graph An undirected graph. ap : list Articulation points of G. c : float To define zeta: zeta = c * (n*n*n), and zeta is the large value assigned as the shortest distance of two unreachable vertices. Default is 1. """ upper_bound = [] N_G = len(G) zeta = c * math.pow(N_G, 3) components = connected_components(G) for component in components: non_articulation_points = component - set(ap) for node in non_articulation_points: upper_bound_value = 0 upper_bound_value += sum( (len(temp) * (N_G - len(temp))) for temp in components) upper_bound_value += (2 * len(component) + 1 - 2 * N_G) upper_bound_value *= zeta upper_bound.append(upper_bound_value) return upper_bound
def procedure2(G, c=1.0): """ Procedure 2 of https://dl.acm.org/profile/81484650642 Parameters ----------- G : graph c : float To define zeta: zeta = c * (n*n*n) Default is 1. """ components = connected_components(G) C = 0 N_G = len(G) zeta = c * math.pow(N_G, 3) for component in components: component_subgraph = G.nodes_subgraph(from_nodes=list(component)) C_l = _get_sum_all_shortest_paths_of_component(component_subgraph) N_c = len(component) C += (C_l + N_c * (N_G - N_c) * zeta) del component_subgraph return C