def make_dag(g: DirectedGraph, s: int, t: int, pmap_vpreds: ReadPropertyMap, single_path: bool = False) -> set: """ Extracts the arcs related to shortest paths from `s` to `t` in a graph `g` given the predecessors map computed using `dijkstra_shortest_paths` from `s`. Args: g: The graph. s: The target's vertex descriptor. t: The target's vertex descriptor. pmap_vpreds: The `ReadPropertyMap{int : set(int)}` mapping each vertex with its set of (direct) predecessors. single_path: Pass True to extract a single path. If multiple paths exist from `s` to `t`, this extracts an arbitrary path instead of all of them. Returns: The corresponding set of `EdgeDescriptor`s. """ kept_edges = set() n_prev = -1 n = 0 to_process = {t} done = set() while to_process: es = {e for u in to_process if pmap_vpreds[u] for e in pmap_vpreds[u]} if single_path and es: es = {es.pop()} kept_edges |= es predecessors = {source(e, g) for e in es if e not in done} done |= to_process to_process = predecessors - done return kept_edges
def examine_relevant_edge(self, e: EdgeDescriptor, g: Graph): u = source(e, g) v = target(e, g) u_dup = self.m_pmap_vertices[u] v_dup = self.m_pmap_vertices[ v] if v in self.m_dup_vertices else self.dup_vertex(v, g) (e_dup, _) = add_edge(u_dup, v_dup, self.m_g_dup) if self.m_pmap_edges: self.m_pmap_edges[e] = e_dup if self.m_callback_dup_edge: self.m_callback_dup_edge(e, g, e_dup, self.m_g_dup)
def make_gdp2() -> GraphDp: g = make_g() vlabel = {u : "v%s" % u for u in vertices(g)} elabel = {e : "e%s%s" % (source(e, g), target(e, g)) for e in edges(g)} gdp = GraphDp( g, dpv = { "label" : make_assoc_property_map(vlabel), "color" : make_func_property_map(lambda q: "red" if q % 2 else "green"), }, dpe = { "label" : make_assoc_property_map(elabel), "color" : make_func_property_map(lambda e: "red" if target(e, g) % 2 else "green"), } ) return gdp
def edge_color(e, g, pmap_component, pmap_color, default_color = "black"): """ Returns the color assigned to an edge. Args: e: An EdgeDescriptor. g: A DirectedGraph. pmap_component: A ReadPropertyMap, mapping a vertex with its strongly connected component. pmap_color: A ReadPropertyMap, mapping a component ID with a color. default_color: color returned if the color of the source and the target of e mismatch. """ u = source(e, g) v = target(e, g) color_u = pmap_color[pmap_component[u]] color_v = pmap_color[pmap_component[v]] return color_u if color_u == color_v else default_color
def cut(s: int, g: Graph, in_cut) -> set: """ Find a vertex cut given an edge cut. Args: g: A `Graph` instance corresponding to an acyclic graph. s: The `VertexDescriptor` corresponding to the source vertex. in_cut: `Callback(EdgeDescriptor, Graph) -> bool` indicating whether an edge belong to the considered cut. """ class LeavesVisitor(DefaultDepthFirstSearchVisitor): def __init__(self, leaves: set): self.leaves = leaves def examine_edge(self, e: EdgeDescriptor, g: Graph): u = source(e, g) self.leaves.discard(u) def discover_vertex(self, u: int, g: Graph): self.leaves.add(u) class IfPush: def __init__(self, in_cut, cutting_edges: set): self.in_cut = in_cut self.cutting_edges = cutting_edges def __call__(self, e: EdgeDescriptor, g: Graph) -> bool: is_cutting_edge = self.in_cut(e, g) if is_cutting_edge: self.cutting_edges.add(e) return not is_cutting_edge leaves = set() cutting_edges = set() map_vcolor = defaultdict(int) depth_first_search(s, g, pmap_vcolor=make_assoc_property_map(map_vcolor), vis=LeavesVisitor(leaves), if_push=IfPush(in_cut, cutting_edges)) return {target(e, g) for e in cutting_edges } | {u for u in leaves} - {source(e, g) for e in cutting_edges}
def test_directed_graph(links: list = LINKS): map_eweight = dict() pmap_eweight = make_assoc_property_map(map_eweight) g = make_graph(LINKS, pmap_eweight, directed=True, build_reverse_edge=False) map_vpreds = defaultdict(set) map_vdist = dict() dijkstra_shortest_paths(g, 0, pmap_eweight, make_assoc_property_map(map_vpreds), make_assoc_property_map(map_vdist)) infty = sys.maxsize E = {(source(e, g), target(e, g)): e for e in edges(g)} assert map_vpreds == { 1: {E[0, 1]}, 2: {E[1, 2]}, 3: {E[1, 3]}, 4: {E[3, 4]}, 5: {E[4, 5]}, 6: {E[4, 6]}, 7: {E[6, 7]}, 8: {E[7, 8]}, 9: {E[7, 9]} } assert map_vdist == { 0: 0, 1: 1, 2: 2, 3: 4, 4: 5, 5: 6, 6: 6, 7: 14, 8: 15, 9: 15, 10: infty }
def make_path(g: DirectedGraph, s: int, t: int, pmap_vpreds: ReadPropertyMap) -> list: """ Extract the path from `s` to `t` in a graph `g` gien to `t` in a graph `g` given the predecessors map computed using `dijkstra_shortest_paths` from `s`. Args: g: The graph. s: The target's vertex descriptor. t: The target's vertex descriptor. pmap_vpreds: A `ReadPropertyMap{int : set(int)}` mapping each vertex with its set of (direct) predecessors. Returns: A list of consecutive arcs forming a shortest path from `s` of `t`. If several shortest paths exist from `s` to `t`, this function returns an arbitrary path. """ arcs = make_dag(g, s, t, pmap_vpreds, single_path=True) path = list(arcs) path.sort(key=lambda e: (source(e, g), target(e, g))) return path
def edge_to_pair(e: EdgeDescriptor, g: DirectedGraph) -> tuple: return (source(e, g), target(e, g))
def test_graph_copy_small(threshold :int = 50): g = DirectedGraph(5) (e01, _) = add_edge(0, 1, g) (e02, _) = add_edge(0, 2, g) (e04, _) = add_edge(0, 4, g) (e12, _) = add_edge(1, 2, g) (e23, _) = add_edge(2, 3, g) (e24, _) = add_edge(2, 4, g) (e40, _) = add_edge(4, 0, g) (e44, _) = add_edge(4, 4, g) map_eweight = { e01 : 83, e02 : 3, e04 : 78, e12 : 92, e23 : 7, e24 : 18, e40 : 51, e44 : 84, } pmap_eweight = make_assoc_property_map(map_eweight) pmap_erelevant = make_func_property_map(lambda e: pmap_eweight[e] >= threshold) g_dup = DirectedGraph(0) # Edge duplicate map_eweight_dup = dict() pmap_eweight_dup = make_assoc_property_map(map_eweight_dup) def callback_dup_edge(e, g, e_dup, g_dup): pmap_eweight_dup[e_dup] = pmap_eweight[e] # Vertex mapping map_vertices = dict() pmap_vertices = make_assoc_property_map(map_vertices) map_edges = dict() pmap_edges = make_assoc_property_map(map_edges) graph_copy( 0, g, g_dup, pmap_erelevant = pmap_erelevant, pmap_vertices = pmap_vertices, pmap_edges = pmap_edges, callback_dup_edge = callback_dup_edge ) if in_ipynb(): ori_html = dotstr_to_html( GraphDp( g, dpv = { "label" : make_func_property_map(lambda u: "%s<br/>(becomes %s)" % (u, pmap_vertices[u])) }, dpe = { "color" : make_func_property_map(lambda e : "darkgreen" if pmap_erelevant[e] else "lightgrey"), "style" : make_func_property_map(lambda e : "solid" if pmap_erelevant[e] else "dashed"), "label" : pmap_eweight, } ).to_dot() ) dup_html = dotstr_to_html( GraphDp( g_dup, dpe = { "label" : pmap_eweight_dup, } ).to_dot() ) html( """ <table> <tr> <th>Original</th> <th>Extracted</th> </tr><tr> <td>%s</td> <td>%s</td> </tr> </table> """ % (ori_html, dup_html) ) if threshold == 50: expected_num_edges = 5 assert map_vertices == { 0 : 0, 1 : 1, 2 : 2, 4 : 3 } for e, e_dup in map_edges.items(): u = source(e, g) v = target(e, g) u_dup = source(e_dup, g_dup) v_dup = target(e_dup, g_dup) assert u_dup == pmap_vertices[u], "u_dup = %s ; pmap_vertices[%s] = %s" % (u_dup, u, pmap_vertices[u]) assert v_dup == pmap_vertices[v], "v_dup = %s ; pmap_vertices[%s] = %s" % (v_dup, v, pmap_vertices[v]) assert pmap_eweight[e] == pmap_eweight_dup[e_dup] elif threshold < min([w for w in map_eweight.values()]): expected_num_edges = num_edges(g) elif threshold > max([w for w in map_eweight.values()]): expected_num_edges = 0 assert expected_num_edges == num_edges(g_dup), \ """ Invalid edge number: Expected: %s Obtained: %s """ % (expected_num_edges, num_edges(g_dup))
def examine_edge(self, e: EdgeDescriptor, g: Graph): u = source(e, g) self.leaves.discard(u)