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 test_undirected_graph_node_add_edge(): # Make graph g = make_g1() assert out_degree(u, g) == 0 assert num_edges(g) == 0 # Add e1 (e1, added1) = add_edge(u, v, g) assert added1 (e, found) = edge(u, v, g) assert found assert e == e1 assert out_degree(u, g) == 1 assert num_edges(g) == 1 # No arc (e, found) = edge(u, w, g) assert not found assert {e for e in out_edges(u, g)} == {e1} # Add e2 (e2, added2) = add_edge(u, w, g) assert added2 assert {e for e in out_edges(u, g)} == {e1, e2} assert out_degree(u, g) == 2 assert num_edges(g) == 2
def make_g2() -> UndirectedGraph: g2 = make_g1() add_edge(u, v, g2) add_edge(u, v, g2) # parallel edge add_edge(u, w, g2) add_edge(v, w, g2) add_edge(w, w, g2) return g2
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_undirected_graph(): g = UndirectedGraph() 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(v, u, 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("In-edges(%s) = %s" % (u, {e for e in in_edges(u, g)})) assert in_degree(u, g) == 3 assert in_degree(v, g) == 3 assert in_degree( w, g) == 2, "in_edges(%s) = %s" % (w, {u for u in in_edges(w, 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) == 3 assert out_degree(w, g) == 2 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) == 1 assert in_degree(u, g) == 1 assert in_degree(w, g) == 1
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 test_undirected_graph_add_vertex(): g = make_g2() assert num_vertices(g) == 3 assert num_edges(g) == 5 # Add vertex x x = add_vertex(g) assert num_vertices(g) == 4 # Add edge (v -> x) add_edge(v, x, g) assert num_edges(g) == 6 assert out_degree(v, g) == 4
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 on_operation(self, a, op :Op, u :int, vs :list) -> int: """ Build edges from an operator to its operand in the `self.ast` AST. Args: a: `str` represening the processed operator. op: `Op` specification of `a`. u: parent vertex descriptor (operator). vs: list of child vertex descriptors (operands). Returns: The parent vertex descriptor. """ for v in vs: add_edge(u, v, self.ast) return u
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_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_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 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 on_edge(self, line: str, u_alias: int, v_alias: int, opts: str) -> EdgeDescriptor: u = self.m_aliases[u_alias] v = self.m_aliases[v_alias] (e, added) = add_edge(u, v, self.m_g) assert added if self.on_install_edge_property: l = re.findall("\\w+=[^\\s]+", opts) # CRAPPY split for opt in l: key, value = opt.split("=") key = key.strip().strip(",") value = value.strip().strip(",") self.on_install_edge_property(e, self.m_g, key, value) return e
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 make_binary_tree(n=10): g = DirectedGraph(n) for u in range(n - 1): add_edge(int(u / 2), u + 1, g) return g
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 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 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 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_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]