def test_simple_graph(): # Prepare graph, just a 0 -> 1 arc g = DirectedGraph() u = add_vertex(g) v = add_vertex(g) e, added = add_edge(u, v, g) assert added w = 1 map_eweight = { e: w, } # Call Dijkstra map_vpreds = defaultdict(set) map_vdist = dict() dijkstra_shortest_paths(g, u, make_assoc_property_map(map_eweight), make_assoc_property_map(map_vpreds), make_assoc_property_map(map_vdist)) # Check assert map_vpreds == { v: {e}, } assert map_vdist == {u: 0, v: w}
def test_graph_dp_dot(): g_expected = make_g() for gdp in make_gdps(): g = DirectedGraph() # Try to load graphviz # TODO: fix read_graphviz read_graphviz(gdp.to_dot(), g)
def test_parallel_edges(): # Prepare graph, two parallel edges from 0 to 1 g = DirectedGraph() u = add_vertex(g) v = add_vertex(g) (e1, added) = add_edge(u, v, g) assert added (e2, added) = add_edge(u, v, g) assert added w = 1 map_eweight = { e1: w, e2: w, } # Call Dijkstra map_vpreds = defaultdict(set) map_vdist = dict() dijkstra_shortest_paths(g, u, make_assoc_property_map(map_eweight), make_assoc_property_map(map_vpreds), make_assoc_property_map(map_vdist)) # Check assert map_vpreds == { v: {e1, e2}, } assert map_vdist == {u: 0, v: w}
def make_graph(links: list, pmap_eweight: ReadWritePropertyMap, directed: bool = True, build_reverse_edge=True): def add_node(un, g, d): u = d.get(un) if not u: u = add_vertex(g) d[un] = u return u g = DirectedGraph() if directed else UndirectedGraph() d = dict() for (un, vn, w) in links: u = add_node(un, g, d) v = add_node(vn, g, d) (e, added) = add_edge(u, v, g) assert added pmap_eweight[e] = w if build_reverse_edge: (e, added) = add_edge(v, u, g) assert added pmap_eweight[e] = w return g
def make_g2(directed: bool) -> Graph: g2 = DirectedGraph(4) if directed else UndirectedGraph(4) add_edge(0, 1, g2) add_edge(1, 2, g2) add_edge(1, 3, g2) add_edge(3, 0, g2) add_edge(3, 2, g2) return g2
def test_graph_extract_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) pmap_eweight = make_assoc_property_map({ e01 : 83, e02 : 3, e04 : 78, e12 : 92, e23 : 7, e24 : 18, e40 : 51, e44 : 84, }) extracted_edges = set() pmap_erelevant = make_func_property_map(lambda e: pmap_eweight[e] >= threshold) graph_extract( 0, g, pmap_erelevant = pmap_erelevant, callback_edge_extract = lambda e, g: extracted_edges.add(e) ) if in_ipynb(): pmap_extracted = make_func_property_map(lambda e: e in extracted_edges) html(dotstr_to_html(GraphDp( g, dpe = { "color" : make_func_property_map(lambda e : "darkgreen" if pmap_extracted[e] else "lightgrey"), "style" : make_func_property_map(lambda e : "solid" if pmap_extracted[e] else "dashed"), "label" : pmap_eweight, } ).to_dot()) ) expected_edges = None if threshold == 0: expected_edges = {e for e in edges(g)} elif threshold == 50: expected_edges = {e12, e40, e44, e04, e01} elif threshold > 100: expected_edges = set() if expected_edges is not None: assert (extracted_edges == expected_edges), """Invalid edges: For threshold = %s: extracted: %s expected: %s """ % (threshold, sorted(extracted_edges), sorted(expected_edges))
def make_g1(directed: bool) -> Graph: g1 = DirectedGraph(7) if directed else UndirectedGraph(7) add_edge(0, 1, g1) add_edge(1, 2, g1) add_edge(2, 3, g1) add_edge(3, 1, g1) add_edge(3, 4, g1) add_edge(4, 5, g1) add_edge(5, 6, g1) add_edge(6, 4, g1) return g1
def test_cut_diamond(): g = DirectedGraph(4) (e01, _) = add_edge(0, 1, g) (e02, _) = add_edge(0, 2, g) (e13, _) = add_edge(1, 3, g) (e23, _) = add_edge(2, 3, g) obtained = cut(0, g, lambda e, g: e in {e01, e02}) assert obtained == {1, 2} obtained = cut(0, g, lambda e, g: e in {e13, e23}) assert obtained == {3}
def make_graph(edges_set: set) -> DirectedGraph: g = DirectedGraph() n = 0 for (u, v) in edges_set: assert u >= 0 while n <= u: add_vertex(g) n += 1 while n <= v: add_vertex(g) n += 1 add_edge(u, v, g) return g
def test_directed_graph(): g = DirectedGraph() assert num_vertices(g) == 0 u = add_vertex(g) assert num_vertices(g) == 1 v = add_vertex(g) assert num_vertices(g) == 2 w = add_vertex(g) assert num_vertices(g) == 3 assert num_edges(g) == 0 e_uv, _ = add_edge(u, v, g) assert num_edges(g) == 1 e_uv1, _ = add_edge(u, v, g) assert num_edges(g) == 2 e_uw, _ = add_edge(u, w, g) assert num_edges(g) == 3 e_vw, _ = add_edge(v, w, g) assert num_edges(g) == 4 print("Edges = %s" % {e for e in edges(g)}) print("Out-edges(%s) = %s" % (u, {e for e in out_edges(u, g)})) assert out_degree(u, g) == 3 assert out_degree(v, g) == 1 assert out_degree(w, g) == 0 print("Removing %s" % e_uv) remove_edge(e_uv, g) assert num_edges(g) == 3 print("Removing %s" % e_uv1) remove_edge(e_uv1, g) assert num_edges(g) == 2 print("Removing %s" % v) remove_vertex(v, g) assert num_vertices(g) == 2 print("Edges = %s" % {e for e in edges(g)}) assert num_edges(g) == 1 print("Out-edges(%s) = %s" % (u, {e for e in out_edges(u, g)})) assert out_degree(u, g) == 1 assert out_degree(w, g) == 0 print(g.to_dot())
def test_cut(): g = DirectedGraph(3) (e01, _) = add_edge(0, 1, g) (e12, _) = add_edge(1, 2, g) obtained = cut(0, g, lambda e, g: e in {e01}) assert obtained == {1} obtained = cut(0, g, lambda e, g: e in {e12}) assert obtained == {2} obtained = cut(0, g, lambda e, g: False) assert obtained == {2} obtained = cut(0, g, lambda e, g: True) assert obtained == {1}
def test_isolated_vertices(): # Create 10 isolated vertices infty = sys.maxsize g = DirectedGraph(10) map_eweight = dict() for s in vertices(g): map_vpreds = defaultdict(set) map_vdist = dict() dijkstra_shortest_paths(g, s, make_assoc_property_map(map_eweight), make_assoc_property_map(map_vpreds), make_assoc_property_map(map_vdist)) # No incident arc in the shortest path DAG assert map_vpreds == dict() # Every target are at infinite distance excepted the source node. assert map_vdist == {u: infty if u != s else 0 for u in vertices(g)}
def test_cut_tree(): g = DirectedGraph(9) (e01, _) = add_edge(0, 1, g) (e02, _) = add_edge(0, 2, g) (e23, _) = add_edge(2, 3, g) (e24, _) = add_edge(2, 4, g) (e35, _) = add_edge(3, 5, g) (e36, _) = add_edge(3, 6, g) (e45, _) = add_edge(4, 7, g) (e46, _) = add_edge(4, 8, g) (e19, _) = add_edge(1, 9, g) obtained = cut(0, g, lambda e, g: e in {e01, e02}) assert obtained == {1, 2} obtained = cut(0, g, lambda e, g: False) assert obtained == {5, 6, 7, 8, 9} obtained = cut(0, g, lambda e, g: e in {e01, e23, e24}) assert obtained == {1, 3, 4} obtained = cut(0, g, lambda e, g: e in {e23, e24}) assert obtained == {3, 4, 9}
def test_strong_components(): # Create the graph g = DirectedGraph(7) add_edge(0, 1, g) add_edge(1, 2, g) add_edge(2, 3, g) add_edge(3, 1, g) add_edge(3, 4, g) add_edge(4, 5, g) add_edge(5, 6, g) add_edge(6, 4, g) # Find strong connected components map_component = {u : None for u in vertices(g)} pmap_component = make_assoc_property_map(map_component) strong_components(g, pmap_component) # Rendering pmap_color = make_assoc_property_map({ 0 : "red", 1 : "blue", 2 : "green", 3 : "purple" }) assert map_component == { 0 : 2, 1 : 1, 2 : 1, 3 : 1, 4 : 0, 5 : 0, 6 : 0, } if in_ipynb(): html(strong_components_to_html(g, pmap_color, pmap_component).replace("\\n", ""))
def make_g() -> DirectedGraph: g = DirectedGraph(3) e01, _ = add_edge(0, 1, g) e12, _ = add_edge(1, 2, g) e02, _ = add_edge(0, 2, g) return 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 test_topological_sort(): g = DirectedGraph(6) for (u, v) in [(0, 1), (2, 4), (2, 5), (0, 3), (1, 4), (4, 3)]: add_edge(u, v, g) l = topological_sort(g) assert list(l) == [2, 5, 0, 1, 4, 3]
def make_binary_tree(n=10): g = DirectedGraph(n) for u in range(n - 1): add_edge(int(u / 2), u + 1, g) return g