def test_no_contraction_if_each_edge_is_different(self): g = self.create_graph(number_nodes=6) g.add_edge( Edge(s=0, t=1, forward=True, backward=True, data=self.edge_data(name="a")) ) g.add_edge( Edge( s=1, t=2, forward=True, backward=True, data=self.edge_data(name="a", highway="b"), ) ) g.add_edge( Edge( s=2, t=3, forward=True, backward=False, data=self.edge_data(name="a", highway="b"), ) ) g.add_edge( Edge( s=3, t=4, forward=True, backward=True, data=self.edge_data(name="a", highway="b"), ) ) g.add_edge( Edge( s=4, t=5, forward=True, backward=True, data=self.edge_data(name="a", highway="b", max_v=123), ) ) contracted_graph = ContractGraph(g).contract() self.assertEqual(len(contracted_graph.vertices), 6) self.assertEqual(len(contracted_graph.edges), 5) result_edge_data = [e.data for e in contracted_graph.edges] expected_edge_data = [ self.edge_data(name="a"), self.edge_data(name="a", highway="b"), self.edge_data(name="a", highway="b"), self.edge_data(name="a", highway="b"), self.edge_data(name="a", highway="b", max_v=123), ] self.assertCountEqual(result_edge_data, expected_edge_data)
def test_contract_a_path_to_two_nodes_and_one_edge(self): g = self.create_graph(number_nodes=3) g.add_edge(Edge(s=0, t=1, forward=True, backward=True, data=self.edge_data())) g.add_edge(Edge(s=1, t=2, forward=True, backward=True, data=self.edge_data())) contracted_graph = ContractGraph(g).contract() self.assertEqual(len(contracted_graph.vertices), 2) self.assertEqual(len(contracted_graph.edges), 1)
def test_three_vertex_should_three_edges_test(self): v1 = Vertex(23, VertexData(1, 1)) v2 = Vertex(24, VertexData(2, 1)) v3 = Vertex(1, VertexData(5, 6)) e1 = Edge(v1.id, v2.id, True, True, EdgeData(123, "", 50, "")) e2 = Edge(v2.id, v3.id, True, True, EdgeData(123, "", 50, "")) e3 = Edge(v1.id, v3.id, True, True, EdgeData(123, "", 50, "")) g = gf.build_graph_from_vertices_edges([v1, v2, v3], [e1, e2, e3]) self.assertTrue(len(g.vertices) == 3) self.assertTrue(len(g.edges) == 3)
def test_add_edges_correct_in_out_neighbors_test(self): g = Graph() v1, v2, v3, v4 = ( self._get_vertex(0), self._get_vertex(1), self._get_vertex(2), self._get_vertex(3), ) e_forward = Edge(v1.id, v2.id, True, False, EdgeData(1, " ", 100, "Test")) e_backward = Edge(v2.id, v3.id, False, True, EdgeData(1, " ", 100, "Test")) e_nothing = Edge(v3.id, v4.id, False, False, EdgeData(1, " ", 100, "Test")) e_both = Edge(v4.id, v1.id, True, True, EdgeData(1, " ", 100, "Test")) g.add_node(v1) g.add_node(v2) g.add_node(v3) g.add_node(v4) g.add_edge(e_forward) g.add_edge(e_backward) g.add_edge(e_nothing) g.add_edge(e_both) self.assertEqual(len(g.edges), 4) self.assertEqual(g.edges[0], e_forward) self.assertEqual(g.edges[1], e_backward) self.assertEqual(g.edges[2], e_nothing) self.assertEqual(g.edges[3], e_both) self.assertIn(e_forward.s, g.inneighbors[e_forward.t]) self.assertIn(e_forward.t, g.outneighbors[e_forward.s]) self.assertNotIn(e_forward.s, g.outneighbors[e_forward.t]) self.assertNotIn(e_forward.t, g.inneighbors[e_forward.s]) self.assertNotIn(e_backward.s, g.inneighbors[e_backward.t]) self.assertNotIn(e_backward.t, g.outneighbors[e_backward.s]) self.assertIn(e_backward.s, g.outneighbors[e_backward.t]) self.assertIn(e_backward.t, g.inneighbors[e_backward.s]) self.assertNotIn(e_nothing.s, g.inneighbors[e_nothing.t]) self.assertNotIn(e_nothing.t, g.outneighbors[e_nothing.s]) self.assertNotIn(e_nothing.s, g.outneighbors[e_nothing.t]) self.assertNotIn(e_nothing.t, g.inneighbors[e_nothing.s]) self.assertIn(e_both.s, g.inneighbors[e_both.t]) self.assertIn(e_both.t, g.outneighbors[e_both.s]) self.assertIn(e_both.s, g.outneighbors[e_both.t]) self.assertIn(e_both.t, g.inneighbors[e_both.s])
def test_contract_loop_to_nothing(self): g = self.create_graph(number_nodes=4) # loop g.add_edge(Edge(s=0, t=1, forward=True, backward=True, data=self.edge_data())) g.add_edge(Edge(s=1, t=2, forward=True, backward=True, data=self.edge_data())) g.add_edge(Edge(s=2, t=0, forward=True, backward=True, data=self.edge_data())) # connection (otherwise no intersections will be found) g.add_edge(Edge(s=0, t=3, forward=True, backward=True, data=self.edge_data())) contracted_graph = ContractGraph(g).contract() self.assertEqual(len(contracted_graph.vertices), 2) self.assertEqual(len(contracted_graph.edges), 1)
def test_two_vertex_should_fail_test(self): v1 = Vertex(23, VertexData(1, 1)) v2 = Vertex(24, VertexData(2, 1)) e = Edge(21, 24, True, True, EdgeData(123, "", 50, "")) g = gf.build_graph_from_vertices_edges([v1, v2], [e]) self.assertTrue(len(g.vertices) == 2) self.assertTrue(len(g.edges) == 0)
def test_if_data_is_converted(self): g = self.create_graph(number_nodes=2) edge_data = self.edge_data() g.add_edge(Edge(s=0, t=1, forward=True, backward=True, data=edge_data)) nx_graph = convert_to_networkx(g) self.assertEqual(len(nx_graph.nodes), 2) self.assertEqual(len(nx_graph.edges), 2) nx_edges = nx_graph.edges(data=True) e0, e1 = nx_edges self.assertCountEqual([(e0[0], e0[1]), (e1[0], e1[1])], [(0, 1), (1, 0)]) self.assertDictEqual( e0[2], { "highway": edge_data.highway, "length": edge_data.length, "max_v": edge_data.max_v, "name": edge_data.name, }, ) self.assertDictEqual( e1[2], { "highway": edge_data.highway, "length": edge_data.length, "max_v": edge_data.max_v, "name": edge_data.name, }, )
def test_two_vertex_should_be_one_edge_test(self): v1 = Vertex(23, VertexData(1, 1)) v2 = Vertex(24, VertexData(2, 1)) e = Edge(23, 24, True, True, EdgeData(123, "", 50, "")) g = gf.build_graph_from_vertices_edges([v1, v2], [e]) self.assertTrue(len(g.vertices) == 2) self.assertTrue(len(g.edges) == 1) self.assertEqual(g.edges[0].data.length, 123)
def add_edges_correct_in_out_neighbors_test(self): g = Graph() v1, v2, v3, v4 = self.get_vertex(0), self.get_vertex( 1), self.get_vertex(2), self.get_vertex(3) e_forward = Edge(v1.id, v2.id, 1, " ", 100, True, False, "Test") e_backward = Edge(v2.id, v3.id, 1, " ", 100, False, True, "Test") e_nothing = Edge(v3.id, v4.id, 1, " ", 100, False, False, "Test") e_both = Edge(v4.id, v1.id, 1, " ", 100, True, True, "Test") g.add_node(v1) g.add_node(v2) g.add_node(v3) g.add_node(v4) g.add_edge(e_forward) g.add_edge(e_backward) g.add_edge(e_nothing) g.add_edge(e_both) self.assertEqual(len(g.edges), 4) self.assertEqual(g.edges[0], e_forward) self.assertEqual(g.edges[1], e_backward) self.assertEqual(g.edges[2], e_nothing) self.assertEqual(g.edges[3], e_both) self.assertTrue(e_forward.s in g.inneighbors[e_forward.t]) self.assertTrue(e_forward.t in g.outneighbors[e_forward.s]) self.assertTrue(e_forward.s not in g.outneighbors[e_forward.t]) self.assertTrue(e_forward.t not in g.inneighbors[e_forward.s]) self.assertTrue(e_backward.s not in g.inneighbors[e_backward.t]) self.assertTrue(e_backward.t not in g.outneighbors[e_backward.s]) self.assertTrue(e_backward.s in g.outneighbors[e_backward.t]) self.assertTrue(e_backward.t in g.inneighbors[e_backward.s]) self.assertTrue(e_nothing.s not in g.inneighbors[e_nothing.t]) self.assertTrue(e_nothing.t not in g.outneighbors[e_nothing.s]) self.assertTrue(e_nothing.s not in g.outneighbors[e_nothing.t]) self.assertTrue(e_nothing.t not in g.inneighbors[e_nothing.s]) self.assertTrue(e_both.s in g.inneighbors[e_both.t]) self.assertTrue(e_both.t in g.outneighbors[e_both.s]) self.assertTrue(e_both.s in g.outneighbors[e_both.t]) self.assertTrue(e_both.t in g.inneighbors[e_both.s])
def test_add_edges_correct_set_of_neighbors_test(self): g = Graph() v1, v2, v3 = self._get_vertex(0), self._get_vertex(1), self._get_vertex(2) e_forward = Edge(v1.id, v2.id, True, False, EdgeData(1, " ", 100, "Test")) e_backward = Edge(v2.id, v3.id, False, True, EdgeData(1, " ", 100, "Test")) e_both = Edge(v3.id, v1.id, True, True, EdgeData(1, " ", 100, "Test")) g.add_node(v1) g.add_node(v2) g.add_node(v3) g.add_edge(e_forward) g.add_edge(e_backward) g.add_edge(e_both) self.assertTrue(self._checkEqual([v2.id, v3.id], g.all_neighbors(v1.id))) self.assertTrue(self._checkEqual([v1.id, v3.id], g.all_neighbors(v2.id))) self.assertTrue(self._checkEqual([v1.id, v2.id], g.all_neighbors(v3.id)))
def add_edge_adds_one_edge_test(self): g = Graph() v1, v2 = self.get_vertex(0), self.get_vertex(1) e = Edge(v1.id, v2.id, 1, " ", 100, True, True, "Test") g.add_node(v1) g.add_node(v2) g.add_edge(e) self.assertEqual(len(g.edges), 1) self.assertEqual(g.edges[0], e)
def test_add_edge_adds_one_edge_test(self): g = Graph() v1, v2 = self._get_vertex(0), self._get_vertex(1) data = EdgeData(23.4, "", 100, "") e = Edge(v1.id, v2.id, True, True, data) g.add_node(v1) g.add_node(v2) g.add_edge(e) self.assertEqual(len(g.edges), 1) self.assertEqual(g.edges[0], e)
def test_converting_K4_graph(self): g = self.create_graph(number_nodes=4) g.add_edge( Edge(s=0, t=1, forward=True, backward=True, data=self.edge_data())) g.add_edge( Edge(s=1, t=2, forward=True, backward=True, data=self.edge_data())) g.add_edge( Edge(s=2, t=3, forward=True, backward=True, data=self.edge_data())) g.add_edge( Edge(s=3, t=0, forward=True, backward=True, data=self.edge_data())) g.add_edge( Edge(s=1, t=3, forward=True, backward=True, data=self.edge_data())) g.add_edge( Edge(s=0, t=2, forward=True, backward=True, data=self.edge_data())) nx_graph = convert_to_networkx(g) self.assertEqual(len(nx_graph.nodes), 4) self.assertEqual(len(nx_graph.edges), 12)
def test_contracting_stops_at_intersections(self): g = self.create_graph(number_nodes=7) # path of 5 nodes g.add_edge(Edge(s=0, t=1, forward=True, backward=True, data=self.edge_data())) g.add_edge(Edge(s=1, t=2, forward=True, backward=True, data=self.edge_data())) g.add_edge(Edge(s=2, t=3, forward=True, backward=True, data=self.edge_data())) g.add_edge(Edge(s=3, t=4, forward=True, backward=True, data=self.edge_data())) # path of two nodes attached in the middle of the path above g.add_edge(Edge(s=2, t=5, forward=True, backward=True, data=self.edge_data())) g.add_edge(Edge(s=5, t=6, forward=True, backward=True, data=self.edge_data())) # expected outcome: 4 nodes remain, and 3 edges, one deg 3 node, all others are deg 1 nodes contracted_graph = ContractGraph(g).contract() self.assertEqual(len(contracted_graph.vertices), 4) self.assertEqual(len(contracted_graph.edges), 3) nmb_neigbors = [len(contracted_graph.all_neighbors(n_id)) for n_id in range(4)] self.assertCountEqual(nmb_neigbors, [3, 1, 1, 1])
def test_contracting_stops_if_edge_is_different(self): g = self.create_graph(number_nodes=10) g.add_edge( Edge( s=0, t=1, forward=True, backward=True, data=self.edge_data(length=2, name="abc"), ) ) g.add_edge( Edge( s=1, t=2, forward=True, backward=True, data=self.edge_data(length=3, name="abc"), ) ) g.add_edge( Edge( s=2, t=3, forward=True, backward=True, data=self.edge_data(length=5, name="def"), ) ) g.add_edge( Edge( s=3, t=4, forward=True, backward=True, data=self.edge_data(length=7, name="def"), ) ) g.add_edge( Edge( s=4, t=5, forward=True, backward=True, data=self.edge_data(length=11, name="ghi"), ) ) g.add_edge( Edge( s=5, t=6, forward=True, backward=True, data=self.edge_data(length=13, name="ghi"), ) ) g.add_edge( Edge( s=6, t=7, forward=True, backward=True, data=self.edge_data(length=17, name="jkl"), ) ) g.add_edge( Edge( s=7, t=8, forward=True, backward=True, data=self.edge_data(length=23, name="mno"), ) ) g.add_edge( Edge( s=8, t=9, forward=True, backward=True, data=self.edge_data(length=29, name="mno"), ) ) # input: 0-1-2-3-4-5-6-7-8-9 # expected outcome: 0-2-4-6-7-9 contracted_graph = ContractGraph(g).contract() self.assertEqual(len(contracted_graph.vertices), 6) self.assertEqual(len(contracted_graph.edges), 5) result_edge_data = [e.data for e in contracted_graph.edges] expected_edge_data = [ self.edge_data(length=5, name="abc"), self.edge_data(length=12, name="def"), self.edge_data(length=24, name="ghi"), self.edge_data(length=17, name="jkl"), self.edge_data(length=52, name="mno"), ] self.assertCountEqual(result_edge_data, expected_edge_data)
def _find_new_edges(self) -> Set[Edge]: # maintain a list L of nodes from which we want to start searches to find new contracted edges # initialize L with all intersection nodes (i.e., all nodes with degree != 2) # for each node n in L # for each of n's neighbor # search until: # - an intersection node is found or edge is found # - the next edge is different in it's structure (e.g., different highway type, different max speed, ...) self.start_nodes = self._find_all_intersections() self.seen_start_nodes = set(self.start_nodes) new_edges = set() bidirectional_edges: Set[Tuple[int, int]] = set() out_edges_per_node = self._get_out_edges() while len(self.start_nodes) > 0: node_id = self.start_nodes.popleft() out_edges = out_edges_per_node[node_id] for first_out_edge in out_edges: start_node_id = node_id edges_to_merge, final_node_id = self._find_edges_to_merge( start_node_id, first_out_edge ) if len(edges_to_merge) == 0: continue sum_edge_lengths = sum([e.data.length for e in edges_to_merge]) data = replace(edges_to_merge[0].data, length=sum_edge_lengths) if edges_to_merge[0].backward: # deduplication measure; if not for this for bidirectional edges, that are # removed between intersections, 2 new edges would be created smaller_node_id = ( start_node_id if start_node_id < final_node_id else final_node_id ) bigger_node_id = ( start_node_id if start_node_id > final_node_id else final_node_id ) if (smaller_node_id, bigger_node_id) in bidirectional_edges: # already added this edge skip it continue bidirectional_edges.add((smaller_node_id, bigger_node_id)) merged_edge = Edge( smaller_node_id, bigger_node_id, True, edges_to_merge[0].backward, data, ) else: merged_edge = Edge( start_node_id, final_node_id, True, edges_to_merge[0].backward, data, ) new_edges.add(merged_edge) return new_edges