def compute(instance): """Return the Kou et al 2-approx algorithm""" dists, paths = all_shp_between_sources(instance.g, instance.terms, instance.weights) gc = UndirectedGraph() nodes = {x: gc.add_node() for x in instance.terms} nodesback = {v: x for x, v in nodes.items()} weights = {} for i, x1 in enumerate(instance.terms): v1 = nodes[x1] for x2 in instance.terms[i + 1:]: v2 = nodes[x2] e = gc.add_edge(v1, v2) try: weights[e] = dists[x1][x2] except KeyError: weights[e] = dists[x2][x1] treec = kruskal(gc, weights) tree = set([]) for ec in treec: v1, v2 = ec.extremities x1 = nodesback[v1] x2 = nodesback[v2] try: path = paths[x1][x2] except KeyError: path = paths[x2][x1] for e in path: tree.add(e) return tree
def test_remove_node_raise_NodeMembershipError_with_not_contained_node( self): u = self.g.add_node() v = self.g.add_node() self.g.add_arc(u, v) g2 = DirectedGraph() v3 = g2.add_node() v4 = g2.add_node() g2.add_arc(v3, v4) g3 = UndirectedGraph() v5 = g3.add_node() v6 = g3.add_node() g3.add_edge(v5, v6) with self.assertRaises(NodeMembershipError): self.g.remove_node(v3) with self.assertRaises(NodeMembershipError): self.g.remove_node(v5)
def read_input_from_file(f): """Read the input from file""" f.readline() size = int(f.readline().split()[-1]) nb_edges = int(f.readline().split()[-1]) g = UndirectedGraph() if parameters.DEBUG: print('Build nodes') nodes = [g.add_node() for _ in range(size)] if parameters.DEBUG: print('Build edges') edges = [] weights = {} i = 0 for i in range(nb_edges): if parameters.DEBUG: i += 1 if i % 1000 == 0: print('Edge %d / %d' % (i, nb_edges)) line = f.readline() _, u, v, w = line.split() e = g.add_edge(nodes[int(u) - 1], nodes[int(v) - 1]) weights[e] = int(w) edges.append((int(u), int(v), int(w))) line = f.readline() while 'Terminals' not in line: line = f.readline() if 'SECTION' in line: line = f.readline() while 'Terminals' not in line: line = f.readline() nb_terms = int(line.split()[-1]) terms = [] for i in range(nb_terms): line = f.readline() _, t = line.split() terms.append(nodes[int(t) - 1]) return instances.SteinerInstance(g, terms, weights)
def test_remove_arc_raise_LinkMembershipError_with_not_contained_arc(self): v1 = self.g.add_node() v2 = self.g.add_node() self.g.add_arc(v1, v2) g2 = DirectedGraph() v3 = g2.add_node() v4 = g2.add_node() e2 = g2.add_arc(v3, v4) g3 = UndirectedGraph() v5 = g3.add_node() v6 = g3.add_node() e3 = g3.add_edge(v5, v6) with self.assertRaises(LinkMembershipError): self.g.remove_arc(e2) with self.assertRaises(LinkMembershipError): self.g.remove_arc(e3)
class TestEdge(unittest.TestCase): def setUp(self): self.g = UndirectedGraph() v1 = self.g.add_node() v2 = self.g.add_node() v3 = self.g.add_node() v4 = self.g.add_node() v5 = self.g.add_node() v6 = self.g.add_node() v7 = self.g.add_node() v8 = self.g.add_node() self.nodes = [v1, v2, v3, v4, v5, v6, v7, v8] self.couples = [(v1, v5), (v2, v6), (v3, v7), (v4, v8), (v1, v2), (v2, v3), (v3, v4), (v4, v1)] self.edges = [self.g.add_edge(u, v) for u, v in self.couples] def test_edge_is_undirected(self): for e in self.edges: self.assertFalse(e.directed) def test_edge_extremities_are_nodes_defined_by_add_edge(self): for e, couple in zip(self.edges, self.couples): c1 = set(e.extremities) c2 = set(couple) self.assertEqual(c1, c2) def test_neighbor_return_other_extremity_of_edge(self): for e, couple in zip(self.edges, self.couples): u, v = couple self.assertEqual(u, e.neighbor(v)) self.assertEqual(v, e.neighbor(u)) def test_neighbor_raise_TypeError_with_not_node(self): u = self.g.add_node() v = self.g.add_node() e = self.g.add_edge(u, v) e1 = self.edges[0] with self.assertRaises(TypeError): e1.neighbor(1) with self.assertRaises(TypeError): e1.neighbor('abc') with self.assertRaises(TypeError): e1.neighbor((u, v)) with self.assertRaises(TypeError): e1.neighbor(None) with self.assertRaises(TypeError): e1.neighbor(e) def test_neighbor_raise_LinkError_with_not_extremity(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes u = self.g.add_node() g2 = DirectedGraph() w = g2.add_node() e1 = self.edges[0] for v in self.nodes: if v == v1 or v == v5: continue with self.assertRaises(LinkError): e1.neighbor(v) with self.assertRaises(LinkError): e1.neighbor(u) with self.assertRaises(LinkError): e1.neighbor(w)
class MelhornTwoApprox: def __init__(self, instance): dists, paths, closest_sources, limits = voronoi( instance.g, instance.terms, instance.weights) self.instance = instance self.dists = dists self.paths = paths self.closest_sources = closest_sources self.limits = limits self.gc = UndirectedGraph() self.treec = None self.nontree_edges = SortedListWithKey(key=lambda ec: self.weights[ec]) self.sources = set(self.instance.terms) self.nodes = {x: self.gc.add_node() for x in self.instance.terms} self.nodesback = {v: x for x, v in self.nodes.items()} self.weights = {} self.pathslinks = {} for x, limit_nodes in self.limits.items(): xc = self.nodes[x] for u, edges in limit_nodes.items(): for e in edges: v = e.neighbor(u) y = self.closest_sources[v] yc = self.nodes[y] wc = self.dists[x][u] + self.instance.weights[ e] + self.dists[y][v] try: ec = xc.get_incident_edge(yc) if self.weights[ec] > wc: self.weights[ec] = wc self.pathslinks[ec] = (u, v, e) except NodeError: ec = self.gc.add_edge(xc, yc) self.weights[ec] = wc self.pathslinks[ec] = (u, v, e) self.treec = kruskal(self.gc, self.weights) edges = set(self.treec) for ec in self.gc.edges: if ec not in edges: self.nontree_edges.add(ec) def compute(self): return self.current_tree() def current_tree(self): tree = Tree(self.instance.g, self.instance.weights) for ec in self.treec: vuc, vvc = ec.extremities xu = self.nodesback[vuc] xv = self.nodesback[vvc] u, v, e = self.pathslinks[ec] try: pathu = self.paths[xu][u] pathv = self.paths[xv][v] except KeyError: pathu = self.paths[xu][v] pathv = self.paths[xv][u] for f in pathu: tree.add_edge(f) for f in pathv: tree.add_edge(f) tree.add_edge(e) tree.simplify(self.instance.terms) return tree def current_cost(self): return self.treec.cost def _add_edge(self, ec): fc = self.treec.add_edge(ec) if fc is not None: self.nontree_edges.add(fc) def _decrease_edge_key(self, ec, wc, pathlink): if ec in self.nontree_edges: self.nontree_edges.remove(ec) self.weights[ec] = wc self.nontree_edges.add(ec) else: self.weights[ec] = wc self.pathslinks[ec] = pathlink def _remove_edges(self, rem_edges): for ec in rem_edges: try: self.nontree_edges.remove(ec) except ValueError: self.treec.remove_edge(ec) del self.weights[ec] del self.pathslinks[ec] to_remove_from_non_tree = [] for ec in self.nontree_edges: remove_edge = self.treec.add_edge(ec, handle_conflict=False) if remove_edge is None: to_remove_from_non_tree.append(ec) if len(self.treec) == len(self.gc) - 1: break for ec in to_remove_from_non_tree: self.nontree_edges.remove(ec) def add_sources(self, new_terms): incremental_voronoi(self.instance.g, self.sources, self.instance.weights, self.dists, self.paths, self.closest_sources, self.limits, new_terms) rem_edges = [] for ec in self.gc.edges: vuc, vvc = ec.extremities xu = self.nodesback[vuc] xv = self.nodesback[vvc] u, v, e = self.pathslinks[ec] if self.closest_sources[u] != xu and self.closest_sources[u] != xv or \ self.closest_sources[v] != xu and self.closest_sources[v] != xv: rem_edges.append(ec) self.sources |= set(new_terms) nodes = {x: self.gc.add_node() for x in new_terms} self.nodes.update(nodes) self.nodesback.update({v: x for x, v in nodes.items()}) add_edges = [] for x in new_terms: xc = self.nodes[x] limit_nodes = self.limits[x] for u, edges in limit_nodes.items(): for e in edges: v = e.neighbor(u) y = self.closest_sources[v] yc = self.nodes[y] wc = self.dists[x][u] + self.instance.weights[ e] + self.dists[y][v] try: ec = xc.get_incident_edge(yc) if self.weights[ec] > wc: self.weights[ec] = wc self.pathslinks[ec] = (u, v, e) except NodeError: ec = self.gc.add_edge(xc, yc) self.weights[ec] = wc self.pathslinks[ec] = (u, v, e) add_edges.append(ec) for ec in add_edges: self._add_edge(ec) self._remove_edges(rem_edges) for ec in rem_edges: self.gc.remove_edge(ec) def rem_sources(self, rem_terms): neighbor_sources = decremental_voronoi(self.instance.g, self.sources, self.instance.weights, self.dists, self.paths, self.closest_sources, self.limits, rem_terms) self.sources -= set(rem_terms) rem_nodes = set() for x in rem_terms: xc = self.nodes.pop(x) del self.nodesback[xc] rem_nodes.add(xc) add_edges = set() decrease_key_edges = {} for x in neighbor_sources: xc = self.nodes[x] limit_nodes = self.limits[x] for u, edges in limit_nodes.items(): for e in edges: v = e.neighbor(u) y = self.closest_sources[v] if y not in neighbor_sources: continue yc = self.nodes[y] wc = self.dists[x][u] + self.instance.weights[ e] + self.dists[y][v] try: ec = xc.get_incident_edge(yc) if self.weights[ec] > wc: if ec not in add_edges: decrease_key_edges[ec] = (wc, (u, v, e)) else: self.weights[ec] = wc self.pathslinks[ec] = (u, v, e) except NodeError: ec = self.gc.add_edge(xc, yc) self.weights[ec] = wc self.pathslinks[ec] = (u, v, e) add_edges.add(ec) for ec, val in decrease_key_edges.items(): wc, pathlink = val self._decrease_edge_key(ec, wc, pathlink) for ec in add_edges: self._add_edge(ec) for xc in rem_nodes: self._remove_edges(set(xc.incident_edges)) self.gc.remove_node(xc)
class TestUndirectedNode(unittest.TestCase): def setUp(self): self.g = UndirectedGraph() v1 = self.g.add_node() v2 = self.g.add_node() v3 = self.g.add_node() v4 = self.g.add_node() v5 = self.g.add_node() v6 = self.g.add_node() v7 = self.g.add_node() v8 = self.g.add_node() self.nodes = [v1, v2, v3, v4, v5, v6, v7, v8] self.couples = [(v1, v5), (v2, v6), (v3, v7), (v4, v8), (v1, v2), (v2, v3), (v3, v4), (v4, v1)] self.edges = [self.g.add_edge(u, v) for u, v in self.couples] def test_add_node_increase_index(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes self.assertEqual(v1.index + 1, v2.index) self.assertEqual(v2.index + 1, v3.index) self.assertEqual(v3.index + 1, v4.index) self.assertEqual(v4.index + 1, v5.index) self.assertEqual(v5.index + 1, v6.index) self.assertEqual(v6.index + 1, v7.index) self.assertEqual(v7.index + 1, v8.index) def test_add_edge_increase_nb_neighbors(self): sizes = [3, 3, 3, 3, 1, 1, 1, 1] for v, size in zip(self.nodes, sizes): self.assertEqual(len(v), size) self.assertEqual(v.nb_neighbors, size) def test_add_node_do_not_increase_nb_neighbors(self): self.g.add_node() self.g.add_node() self.g.add_node() sizes = [3, 3, 3, 3, 1, 1, 1, 1] for v, size in zip(self.nodes, sizes): self.assertEqual(len(v), size) self.assertEqual(v.nb_neighbors, size) def test_remove_node_decrease_nb_neighbors_of_neighbors(self): self.g.remove_node(self.nodes[0]) sizes = [2, 3, 2, 0, 1, 1, 1] for v, size in zip(self.nodes[1:], sizes): self.assertEqual(len(v), size) self.assertEqual(v.nb_neighbors, size) self.g.remove_node(self.nodes[5]) sizes = [1, 3, 2, 0, 1, 1] for v, size in zip(self.nodes[1:5] + self.nodes[6:], sizes): self.assertEqual(len(v), size) self.assertEqual(v.nb_neighbors, size) def test_remove_edge_decrease_nb_neighbors_of_extremities(self): self.g.remove_edge(self.edges[0]) sizes = [2, 3, 3, 3, 0, 1, 1, 1] for v, size in zip(self.nodes, sizes): self.assertEqual(len(v), size) self.assertEqual(v.nb_neighbors, size) self.g.remove_edge(self.edges[4]) sizes = [1, 2, 3, 3, 0, 1, 1, 1] for v, size in zip(self.nodes, sizes): self.assertEqual(len(v), size) self.assertEqual(v.nb_neighbors, size) for i, e in enumerate(self.edges): if i != 0 and i != 4: self.g.remove_edge(e) for v in self.nodes: self.assertEqual(len(v), 0) self.assertEqual(v.nb_neighbors, 0) def test_add_edge_add_neighbors(self): for u in self.g: for v in self.g: if u == v: continue if (u, v) in self.couples: self.assertTrue(v.is_neighbor_of(u)) self.assertTrue(u.is_neighbor_of(v)) elif (v, u) not in self.couples: self.assertFalse(v.is_neighbor_of(u)) self.assertFalse(u.is_neighbor_of(v)) def test_add_node_do_not_add_neighbors(self): u = self.g.add_node() v = self.g.add_node() w = self.g.add_node() for v2 in self.nodes: self.assertFalse(u.is_neighbor_of(v2)) self.assertFalse(v.is_neighbor_of(v2)) self.assertFalse(w.is_neighbor_of(v2)) self.assertFalse(v2.is_neighbor_of(u)) self.assertFalse(v2.is_neighbor_of(v)) self.assertFalse(v2.is_neighbor_of(w)) def test_remove_node_remove_neighbor_of_neighbors(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes self.g.remove_node(v1) self.assertFalse(v2.is_neighbor_of(v1)) self.assertFalse(v4.is_neighbor_of(v1)) self.assertFalse(v5.is_neighbor_of(v1)) self.assertFalse(v1.is_neighbor_of(v2)) self.assertFalse(v1.is_neighbor_of(v4)) self.assertFalse(v1.is_neighbor_of(v5)) def test_remove_edge_remove_neighbors_of_extremities(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes self.g.remove_edge(self.edges[0]) self.assertFalse(v1.is_neighbor_of(v5)) self.assertFalse(v5.is_neighbor_of(v1)) self.g.remove_edge(self.edges[7]) self.assertFalse(v1.is_neighbor_of(v4)) self.assertFalse(v4.is_neighbor_of(v1)) def test_add_edge_add_neighbors_2(self): for u in self.g: for v in self.g: if u == v: continue if (u, v) in self.couples: self.assertIn(u, list(v.neighbors)) self.assertIn(v, list(u.neighbors)) elif (v, u) not in self.couples: self.assertNotIn(u, list(v.neighbors)) self.assertNotIn(v, list(u.neighbors)) def test_add_node_do_not_add_neighbors_2(self): u = self.g.add_node() v = self.g.add_node() w = self.g.add_node() for v2 in self.nodes: self.assertNotIn(v2, list(u.neighbors)) self.assertNotIn(v2, list(v.neighbors)) self.assertNotIn(v2, list(w.neighbors)) self.assertNotIn(u, list(v2.neighbors)) self.assertNotIn(v, list(v2.neighbors)) self.assertNotIn(w, list(v2.neighbors)) def test_remove_node_remove_neighbor_of_neighbors_2(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes self.g.remove_node(v1) self.assertNotIn(v1, list(v2.neighbors)) self.assertNotIn(v1, list(v4.neighbors)) self.assertNotIn(v1, list(v5.neighbors)) self.assertNotIn(v2, list(v1.neighbors)) self.assertNotIn(v4, list(v1.neighbors)) self.assertNotIn(v5, list(v1.neighbors)) def test_remove_edge_remove_neighbors_of_extremities_2(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes self.g.remove_edge(self.edges[0]) self.assertNotIn(v5, list(v1.neighbors)) self.assertNotIn(v1, list(v5.neighbors)) self.g.remove_edge(self.edges[7]) self.assertNotIn(v4, list(v1.neighbors)) self.assertNotIn(v1, list(v4.neighbors)) def test_nb_neighbors_equal_nb_incident_edges(self): for v in self.nodes: self.assertEqual(v.nb_neighbors, len(list(v.incident_edges))) def test_add_edge_add_incident_edge(self): for e, couple in zip(self.edges, self.couples): u, v = couple for w in self.nodes: if w != u and w != v: self.assertFalse(w.is_incident_to(e)) else: self.assertTrue(w.is_incident_to(e)) def test_new_node_are_not_incident_to_previous_edges(self): u = self.g.add_node() v = self.g.add_node() w = self.g.add_node() for e in self.edges: self.assertFalse(u.is_incident_to(e)) self.assertFalse(v.is_incident_to(e)) self.assertFalse(w.is_incident_to(e)) def test_remove_node_remove_incident_edges_of_neighbors(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes e1, e2, e3, e4, e5, e6, e7, e8 = self.edges self.g.remove_node(v1) self.assertFalse(v2.is_incident_to(e5)) self.assertFalse(v5.is_incident_to(e1)) self.assertFalse(v4.is_incident_to(e8)) def test_remove_edge_remove_incident_edges_extremities(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes e1, e2, e3, e4, e5, e6, e7, e8 = self.edges self.g.remove_edge(e1) self.assertFalse(v1.is_incident_to(e1)) self.assertFalse(v5.is_incident_to(e1)) self.g.remove_edge(e8) self.assertFalse(v1.is_incident_to(e8)) self.assertFalse(v4.is_incident_to(e8)) def test_add_edge_add_incident_edge_2(self): for e, couple in zip(self.edges, self.couples): u, v = couple for w in self.nodes: if w != u and w != v: self.assertNotIn(e, list(w.incident_edges)) else: self.assertIn(e, list(w.incident_edges)) def test_new_node_are_not_incident_to_previous_edges_2(self): u = self.g.add_node() v = self.g.add_node() w = self.g.add_node() for e in self.edges: self.assertNotIn(e, list(u.incident_edges)) self.assertNotIn(e, list(v.incident_edges)) self.assertNotIn(e, list(w.incident_edges)) def test_remove_node_remove_incident_edges_of_neighbors_2(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes e1, e2, e3, e4, e5, e6, e7, e8 = self.edges self.g.remove_node(v1) self.assertNotIn(e5, list(v2.incident_edges)) self.assertNotIn(e1, list(v5.incident_edges)) self.assertNotIn(e8, list(v4.incident_edges)) def test_remove_edge_remove_incident_edges_extremities_2(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes e1, e2, e3, e4, e5, e6, e7, e8 = self.edges self.g.remove_edge(e1) self.assertNotIn(e1, list(v1.incident_edges)) self.assertNotIn(e1, list(v5.incident_edges)) self.g.remove_edge(e8) self.assertNotIn(e8, list(v1.incident_edges)) self.assertNotIn(e8, list(v4.incident_edges)) def test_add_edge_add_incident_edge_3(self): for e, couple in zip(self.edges, self.couples): u, v = couple self.assertEqual(e, u.get_incident_edge(v)) self.assertEqual(e, v.get_incident_edge(u)) def test_get_incident_edge_raise_TypeError_with_not_node(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes e1, e2, e3, e4, e5, e6, e7, e8 = self.edges g2 = DirectedGraph() v = g2.add_node() with self.assertRaises(TypeError): v1.get_incident_edge(1) with self.assertRaises(TypeError): v1.get_incident_edge('abc') with self.assertRaises(TypeError): v1.get_incident_edge((v1, v2)) with self.assertRaises(TypeError): v1.get_incident_edge(e5) with self.assertRaises(TypeError): v1.get_incident_edge(None) with self.assertRaises(TypeError): v1.get_incident_edge(v) def test_get_incident_edge_raise_NodeError_with_not_neighbor(self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes g2 = UndirectedGraph() v = g2.add_node() with self.assertRaises(NodeError): v1.get_incident_edge(v3) with self.assertRaises(NodeError): v1.get_incident_edge(v) def test_get_incident_edge_raise_NodeError_with_not_neighbor_due_to_remove_edge( self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes e1, e2, e3, e4, e5, e6, e7, e8 = self.edges self.g.remove_edge(e1) with self.assertRaises(NodeError): v1.get_incident_edge(v5) with self.assertRaises(NodeError): v5.get_incident_edge(v1) def test_get_incident_edge_raise_NodeError_with_not_neighbor_due_to_remove_node( self): v1, v2, v3, v4, v5, v6, v7, v8 = self.nodes self.g.remove_node(v5) with self.assertRaises(NodeError): v1.get_incident_edge(v5)
}, v5: { v6: 10 }, v6: { v7: 9 }, v7: { v8: 4 }, }) waux = defaultdict(dict) for u in weights: for v in weights[u]: g.add_edge(u, v) waux[v][u] = weights[u][v] for v in waux: weights[v].update(waux[v]) gd = GraphDrawer(g) gd.move_node(v1, 100, 100) gd.move_node(v2, 300, 100) gd.move_node(v3, 500, 100) gd.move_node(v4, 700, 100) gd.move_node(v5, 100, 200) gd.move_node(v6, 300, 200) gd.move_node(v7, 500, 200) gd.move_node(v8, 700, 200) for e in g.edges:
def is_root(self): return self.father is None def __str__(self): return str(self.node) def __repr__(self): return str(self) if __name__ == '__main__': from dynamicgraphviz.graph.undirectedgraph import UndirectedGraph g = UndirectedGraph() v1, v2, v3, v4, v5, v6, v7, v8 = [g.add_node() for _ in range(8)] e0 = g.add_edge(v8, v1) e1 = g.add_edge(v1, v2) e2 = g.add_edge(v1, v3) e3 = g.add_edge(v3, v4) e4 = g.add_edge(v3, v5) e5 = g.add_edge(v4, v6) e6 = g.add_edge(v4, v7) e7 = g.add_edge(v2, v6) weights = { e0: 1, e1: 1, e2: 1, e3: 3, e4: 1, e5: 1, e6: 1,