def __check_prod_input(graph, prod_input): assert len(prod_input) == 1 i_id = prod_input[0] i_data = graph.nodes[i_id] i_layer = i_data['layer'] assert i_data['label'] == 'I' i_neighbors = get_neighbors_at(graph, i_id, i_layer) assert len(i_neighbors) == 3 nodes_with_other_neighbors = [ e for e in i_neighbors if all(n not in i_neighbors for n in get_neighbors_at(graph, e, i_layer)) ] assert len(nodes_with_other_neighbors) == 1 e1 = nodes_with_other_neighbors[0] (e2, e3) = [e for e in i_neighbors if e != e1] e12 = get_vertex_between(graph, e1, e2, i_layer, 'E') e13 = get_vertex_between(graph, e1, e3, i_layer, 'E') assert e12 is not None assert e13 is not None cycle_list = [e3, e13, e1, e12, e2] for i, e in enumerate(cycle_list): assert graph.nodes[e]['label'] == 'E' prev_e = cycle_list[(i - 1) % len(cycle_list)] next_e = cycle_list[(i + 1) % len(cycle_list)] assert all(n in get_neighbors_at(graph, e, i_layer) for n in [prev_e, next_e]) return e1, e2, e3, e12, e13
def test_happy_path(self): graph = Graph() e1 = gen_name() e2 = gen_name() e3 = gen_name() graph.add_node(e1, layer=1, position=(1.0, 2.0), label='E') graph.add_node(e2, layer=1, position=(1.0, 1.0), label='E') graph.add_node(e3, layer=1, position=(2.0, 1.0), label='E') graph.add_edge(e1, e2) graph.add_edge(e1, e3) graph.add_edge(e2, e3) i = add_interior(graph, e1, e2, e3) if visualize_tests: visualize_graph_3d(graph) pyplot.show() [i1] = P9().apply(graph, [i]) # if correct number of nodes and edges self.assertEqual(len(graph.nodes()), 8) self.assertEqual(len(graph.edges()), 13) # if cross-layer interior connections self.assertEqual(graph.nodes[i]['label'], 'i') self.assertTrue(graph.has_edge(i, i1)) # if new interior has correct label and layer self.assertEqual(graph.nodes[i1]['label'], 'I') self.assertEqual(graph.nodes[i1]['layer'], graph.nodes[i]['layer'] + 1) # if new interior has 3 neighbors i1_neighbors = get_neighbors_at(graph, i1, graph.nodes[i1]['layer']) self.assertEqual(len(i1_neighbors), 3) # if new nodes are in correct positions new_e1 = get_node_at(graph, 2, (1.0, 2.0)) new_e2 = get_node_at(graph, 2, (1.0, 1.0)) new_e3 = get_node_at(graph, 2, (2.0, 1.0)) self.assertIsNotNone(new_e1) self.assertIsNotNone(new_e2) self.assertIsNotNone(new_e3) # if each vertex has correct label for n in i1_neighbors: self.assertEqual(graph.nodes[n]['label'], 'E') # if each vertex has correct number of neighbors for n in i1_neighbors: node_neighbors = get_neighbors_at(graph, n, graph.nodes[n]['layer']) self.assertEqual(len(node_neighbors), 3) if visualize_tests: visualize_graph_3d(graph) pyplot.show()
def check_graph_integrity(self, graph, i_node_id, expected_label): i_node_data = graph.nodes[i_node_id] i_node_layer = i_node_data['layer'] self.assertEqual(i_node_data['label'], expected_label) neighbors = get_neighbors_at(graph, i_node_id, i_node_layer) self.assertEqual(len(neighbors), 3) for n_id in neighbors: self.assertEqual(graph.nodes[n_id]['label'], 'E') n_expected_neighbors = [x for x in neighbors if x != n_id] n_neighbors = get_neighbors_at(graph, n_id, i_node_layer) for expected_neighbor in n_expected_neighbors: self.assertTrue(expected_neighbor in n_neighbors)
def apply(self, graph: Graph, prod_input: List[str], orientation: int = 0, **kwargs) -> List[str]: [i] = prod_input i_data = graph.nodes[i] self.__check_prod_input(graph, prod_input) i_data['label'] = 'i' i_layer = i_data['layer'] new_layer = i_layer + 1 i_neighbors = get_neighbors_at(graph, i, i_layer) # e1 doesn't mean e1 with (x1, y1) vx_e1 = gen_name() vx_e2 = gen_name() vx_e3 = gen_name() e1_pos = graph.nodes[i_neighbors[0]]['position'] e2_pos = graph.nodes[i_neighbors[1]]['position'] e3_pos = graph.nodes[i_neighbors[2]]['position'] graph.add_node(vx_e1, layer=new_layer, position=e1_pos, label='E') graph.add_node(vx_e2, layer=new_layer, position=e2_pos, label='E') graph.add_node(vx_e3, layer=new_layer, position=e3_pos, label='E') graph.add_edge(vx_e1, vx_e2) graph.add_edge(vx_e2, vx_e3) graph.add_edge(vx_e3, vx_e1) sorted_segments = sort_segments_by_angle(graph, [(vx_e1, vx_e2), (vx_e2, vx_e3), (vx_e3, vx_e1)]) segment_to_break = sorted_segments[orientation % 3] b = add_break_in_segment(graph, segment_to_break) b_neighbors = get_neighbors_at(graph, b, i_layer + 1) remaining = [x for x in [vx_e1, vx_e2, vx_e3] if x not in b_neighbors][0] graph.add_edge(b, remaining) i1 = add_interior(graph, b_neighbors[0], b, remaining) i2 = add_interior(graph, b_neighbors[1], b, remaining) graph.add_edge(i1, i) graph.add_edge(i2, i) return [i1, i2]
def __check_prod_input(graph, prod_input): i_node_id = prod_input[0] i_node_data = graph.nodes[i_node_id] i_node_layer = i_node_data['layer'] assert i_node_data['label'] == 'I' neighbors = get_neighbors_at(graph, i_node_id, i_node_layer) assert len(neighbors) == 3 for n_id in neighbors: assert graph.nodes[n_id]['label'] == 'E' n_expected_neighbors = [x for x in neighbors if x != n_id] n_neighbors = get_neighbors_at(graph, n_id, i_node_layer) for expected_neighbor in n_expected_neighbors: assert expected_neighbor in n_neighbors
def apply(self, graph: Graph, prod_input: List[str], orientation: int = 0, **kwargs) -> List[str]: self.__check_prod_input(graph, prod_input) overlapping_vertices = find_overlapping_vertices(graph)[0] layer = graph.nodes()[prod_input[0]]['layer'] neighbours = set() for interior in prod_input: neighbours |= set(get_neighbors_at(graph, interior, layer)) vertices_to_join = [ neighbour for neighbour in neighbours if graph.nodes()[neighbour] ['position'] == graph.nodes()[overlapping_vertices[0]]['position'] ] if len(vertices_to_join) == 2: join_overlapping_vertices(graph, vertices_to_join[0], vertices_to_join[1], layer) return prod_input
def apply(self, graph: Graph, prod_input: List[str], orientation: int = 0, **kwargs) -> List[str]: # Production based on P6 prod_input = self.__sort_prod_input(graph, prod_input) self.__check_prod_input(graph, prod_input) up_layer = graph.nodes()[prod_input[0]]['layer'] down_layer = graph.nodes()[prod_input[3]]['layer'] v1_up, v2_up = get_common_neighbors(graph, prod_input[0], prod_input[1], up_layer) pos_v1 = graph.nodes()[v1_up]['position'] pos_v2 = graph.nodes()[v2_up]['position'] to_merge = [[], []] for interior in prod_input[2:]: for v in get_neighbors_at(graph, interior, down_layer): if graph.nodes()[v]['position'] == pos_v1: to_merge[0].append(v) elif graph.nodes()[v]['position'] == pos_v2: to_merge[1].append(v) for v1, v2 in to_merge: join_overlapping_vertices(graph, v1, v2, down_layer) return []
def __check_prod_input(graph, prod_input, eps): assert len(prod_input) == 1 i_node_id = prod_input[0] i_node_data = graph.nodes[i_node_id] i_node_layer = i_node_data['layer'] assert i_node_data['label'] == 'I' neighbours = get_neighbors_at(graph, i_node_id, i_node_layer) assert len(neighbours) == 3 for n_id in neighbours: assert graph.nodes[n_id]['label'] == 'E' for e1, e2 in zip(neighbours, neighbours[1:] + neighbours[:1]): # find common 'E' neighbours in the same layer and exactly in the middle of e1_e2 segment (e1_x, e1_y) = graph.nodes[e1]['position'] (e2_x, e2_y) = graph.nodes[e2]['position'] middle_position = ((e1_x + e2_x) / 2, (e1_y + e2_y) / 2) common_neighbours = [n for n in graph.neighbors(e1) if n in graph.neighbors(e2) and graph.nodes[n]['layer'] == i_node_layer and graph.nodes[n]['label'] == 'E' and P5.is_close(graph.nodes[n]['position'], middle_position, eps)] assert len(common_neighbours) == 1
def __check_prod_input(graph, prod_input): if len(prod_input) != 1: raise ValueError('wrong number of interiors') i_node_id = prod_input[0] i_node_data = graph.nodes[i_node_id] i_node_layer = i_node_data['layer'] if i_node_data['label'] != 'I': raise ValueError("wrong interior label") neighbors = get_neighbors_at(graph, i_node_id, i_node_layer) if len(neighbors) != 3: raise ValueError("interior with wrong number of edges") for n_id in neighbors: if graph.nodes[n_id]['label'] != 'E': raise ValueError("wrong vertex label") n_expected_neighbors = [x for x in neighbors if x != n_id] n_neighbors = get_neighbors_at(graph, n_id, i_node_layer) for expected_neighbor in n_expected_neighbors: if expected_neighbor not in n_neighbors: raise ValueError("missing edge between vertices")
def check_structure(interior_nodes, layer_num): for interior_node in interior_nodes: neighbours = get_neighbors_at(graph, interior_node, layer_num) if len(neighbours) > 3: raise ValueError( 'Wrong number of neighbours of an interior vertex') for n in neighbours: if graph.nodes()[n]['label'] != "E": raise ValueError('Vertex does not have "E" label') common_neighbors = get_common_neighbors(graph, interior_nodes[0], interior_nodes[1], layer_num) if len(common_neighbors) > 2: raise ValueError('Interiors have more than 2 common neighbors') return common_neighbors
def apply(self, graph: Graph, prod_input: List[str], orientation: int = 0, **kwargs) -> List[str]: """ Apply 6th production on graph `prod_input` is list of 6 interiors as follows: `[upper, upper, lower, lower, lower, lower]`, where `upper` is vertex on upper layer and `lower` on lower layer. Order of vertices in one layer is irrelevant. `orientation` and `**kwargs` are ignored Returns empty list, as no new vertices were added. """ self.__check_prod_input(graph, prod_input) up_layer = graph.nodes()[prod_input[0]]['layer'] down_layer = graph.nodes()[prod_input[2]]['layer'] v1_up, v2_up = get_common_neighbors(graph, prod_input[0], prod_input[1], up_layer) pos_v1 = graph.nodes()[v1_up]['position'] pos_v2 = graph.nodes()[v2_up]['position'] x = (pos_v1[0] + pos_v2[0]) / 2 y = (pos_v1[1] + pos_v2[1]) / 2 pos_center = (x, y) to_merge = [[], [], []] for interior in prod_input[2:]: for v in get_neighbors_at(graph, interior, down_layer): if graph.nodes()[v]['position'] == pos_v1: to_merge[0].append(v) elif graph.nodes()[v]['position'] == pos_v2: to_merge[1].append(v) elif graph.nodes()[v]['position'] == pos_center: if v not in to_merge[2]: to_merge[2].append(v) for v1, v2 in to_merge: join_overlapping_vertices(graph, v1, v2, down_layer) return []
def apply(self, graph: Graph, prod_input: List[str], orientation: int = 0, **kwargs) -> List[str]: # Production based on P2 self.__check_prod_input(graph, prod_input) [i] = prod_input i_data = graph.nodes[i] i_data['label'] = 'i' i_layer = i_data['layer'] new_layer = i_layer + 1 i_neighbors = get_neighbors_at(graph, i, i_layer) # create new 'E' nodes in the next layer new_e1 = gen_name() new_e2 = gen_name() new_e3 = gen_name() e1_pos = graph.nodes[i_neighbors[0]]['position'] e2_pos = graph.nodes[i_neighbors[1]]['position'] e3_pos = graph.nodes[i_neighbors[2]]['position'] graph.add_node(new_e1, layer=new_layer, position=e1_pos, label='E') graph.add_node(new_e2, layer=new_layer, position=e2_pos, label='E') graph.add_node(new_e3, layer=new_layer, position=e3_pos, label='E') # create edges between new 'E' nodes graph.add_edge(new_e1, new_e2) graph.add_edge(new_e2, new_e3) graph.add_edge(new_e3, new_e1) # create new 'I' node and edges between new 'I' nodes and new 'E' nodes i1 = add_interior(graph, new_e1, new_e2, new_e3) # create edges between new 'I' node and parent 'i' node graph.add_edge(i1, i) return [i1]
def get_corner_nodes(graph, i, i_layer, orientation): """ Get 'E' nodes that are neighbours of 'I' node at i_layer level. Order of returned nodes is not random. Methods returns nodes e1, e2 and e3 in counterclockwise order. Moreover we assume that the triangle will be cut into half by a segment from e2 to point in the middle of e1_e3 segment. If orientation is 0, method will assume that the longest segment is divided in half. If not, the segment is chosen by switching segment 'orientation' times in counterclockwise direction. """ [a, b, c] = get_neighbors_at(graph, i, i_layer) # find counterclockwise order of nodes (a_x, a_y) = graph.nodes[a]['position'] (b_x, b_y) = graph.nodes[b]['position'] (c_x, c_y) = graph.nodes[c]['position'] m = P5.calc_mean(a_x, a_y, b_x, b_y, c_x, c_y) ma_angle = angle_with_x_axis(m, (a_x, a_y)) mb_angle = angle_with_x_axis(m, (b_x, b_y)) mc_angle = angle_with_x_axis(m, (c_x, c_y)) angles_counterclockwise = sorted([(a, ma_angle), (b, mb_angle), (c, mc_angle)], key=lambda p: p[1]) nodes_counterclockwise = [p[0] for p in angles_counterclockwise] # find longest edge ab = P5.calc_distance_between(graph, a, b) bc = P5.calc_distance_between(graph, b, c) ca = P5.calc_distance_between(graph, c, a) if max(ab, bc, ca) == ab: middle_offset = nodes_counterclockwise.index(c) elif max(ab, bc, ca) == bc: middle_offset = nodes_counterclockwise.index(a) else: middle_offset = nodes_counterclockwise.index(b) offset = (orientation + (1 - middle_offset)) % 3 return nodes_counterclockwise[offset:] + nodes_counterclockwise[:offset] # rotate table according to offset
def __check_prod_input(graph, prod_input): if len(set(prod_input)) != 4: raise ValueError('too few interiors') layer = graph.nodes()[prod_input[0]]['layer'] if any(graph.nodes()[interior]['layer'] != layer for interior in prod_input[1:]): raise ValueError('interior vertices come from different layers') if any(graph.nodes()[interior]['label'] != 'I' for interior in prod_input): raise ValueError('interior vertices must have I label') all_neighbours = [] for interior in prod_input: interior_neighbours = get_neighbors_at(graph, interior, layer) if len(interior_neighbours) != 3: raise ValueError('wrongly connected interior vertices') for neighbour in interior_neighbours: if graph.nodes()[neighbour]['label'] != 'E': raise ValueError( 'interior vertices can be connect only with E vertices' ) all_neighbours.append(neighbour) if len(set(all_neighbours)) != 6: raise ValueError('incorrect number of E vertices') overlapping_vertices = find_overlapping_vertices(graph) if len(overlapping_vertices) != 2 or \ any(overlapping_vertice1 not in set(all_neighbours) or overlapping_vertice2 not in set(all_neighbours) for overlapping_vertice1, overlapping_vertice2 in overlapping_vertices): raise ValueError('incorrect shape of graph')
def test_happy_path(self): graph = Graph() e1 = gen_name() e2 = gen_name() e3 = gen_name() e4 = gen_name() e1_1 = gen_name() e1_2 = gen_name() e1_3 = gen_name() e2_1 = gen_name() e2_2 = gen_name() e2_4 = gen_name() e3_5 = gen_name() graph.add_node(e1, layer=1, position=(1.0, 1.0), label='E') graph.add_node(e2, layer=1, position=(2.0, 2.0), label='E') graph.add_node(e3, layer=1, position=(1.0, 2.0), label='E') graph.add_node(e4, layer=1, position=(2.0, 1.0), label='E') graph.add_node(e1_1, layer=2, position=(1.0, 1.0), label='E') graph.add_node(e1_2, layer=2, position=(2.0, 2.0), label='E') graph.add_node(e1_3, layer=2, position=(1.0, 2.0), label='E') graph.add_node(e2_1, layer=2, position=(1.0, 1.0), label='E') graph.add_node(e2_2, layer=2, position=(2.0, 2.0), label='E') graph.add_node(e2_4, layer=2, position=(2.0, 1.0), label='E') graph.add_node(e3_5, layer=2, position=(2.0, 3.0), label='E') graph.add_edge(e1, e2) graph.add_edge(e1, e3) graph.add_edge(e1, e4) graph.add_edge(e2, e3) graph.add_edge(e2, e4) graph.add_edge(e1_1, e1_2) graph.add_edge(e1_1, e1_3) graph.add_edge(e1_2, e1_3) graph.add_edge(e2_1, e2_2) graph.add_edge(e2_1, e2_4) graph.add_edge(e2_2, e2_4) graph.add_edge(e3_5, e1_2) graph.add_edge(e3_5, e1_3) i1 = add_interior(graph, e1, e2, e3) i2 = add_interior(graph, e1, e2, e4) i1_1 = add_interior(graph, e1_1, e1_2, e1_3) i2_1 = add_interior(graph, e2_1, e2_2, e2_4) i3_1 = add_interior(graph, e3_5, e1_2, e1_3) graph.nodes[i1]['label'] = 'i' graph.nodes[i2]['label'] = 'i' graph.add_edge(i1, i1_1) graph.add_edge(i2, i2_1) graph.add_edge(i1, i3_1) if visualize_tests: visualize_graph_3d(graph) pyplot.show() P12().apply(graph, [i1, i2, i1_1, i2_1]) # if correct number of nodes and edges self.assertEqual(len(graph.nodes()), 14) self.assertEqual(len(graph.edges()), 30) # if interiors has correct labels, layers and are connected self.assertEqual(graph.nodes[i1]['label'], 'i') self.assertEqual(graph.nodes[i2]['label'], 'i') self.assertEqual(graph.nodes[i1_1]['label'], 'I') self.assertEqual(graph.nodes[i2_1]['label'], 'I') self.assertEqual(graph.nodes[i1]['layer'], 1) self.assertEqual(graph.nodes[i2]['layer'], 1) self.assertEqual(graph.nodes[i1_1]['layer'], 2) self.assertEqual(graph.nodes[i2_1]['layer'], 2) self.assertTrue(graph.has_edge(i1, i1_1)) self.assertTrue(graph.has_edge(i2, i2_1)) # if each interior has 3 neighbors i1_neighbors = get_neighbors_at(graph, i1, graph.nodes[i1]['layer']) self.assertEqual(len(i1_neighbors), 3) i2_neighbors = get_neighbors_at(graph, i2, graph.nodes[i2]['layer']) self.assertEqual(len(i2_neighbors), 3) i1_1_neighbors = get_neighbors_at(graph, i1_1, graph.nodes[i1_1]['layer']) self.assertEqual(len(i1_1_neighbors), 3) i2_1_neighbors = get_neighbors_at(graph, i2_1, graph.nodes[i2_1]['layer']) self.assertEqual(len(i2_1_neighbors), 3) # if nodes in lower layer exists and are correctly connected new_e1 = get_node_at(graph, 2, (1.0, 1.0)) new_e2 = get_node_at(graph, 2, (2.0, 2.0)) new_e3 = get_node_at(graph, 2, (1.0, 2.0)) new_e4 = get_node_at(graph, 2, (2.0, 1.0)) self.assertIsNotNone(new_e1) self.assertIsNotNone(new_e2) self.assertIsNotNone(new_e3) self.assertIsNotNone(new_e4) self.assertTrue(graph.has_edge(new_e1, new_e2)) self.assertTrue(graph.has_edge(new_e1, new_e3)) self.assertTrue(graph.has_edge(new_e1, new_e4)) self.assertTrue(graph.has_edge(new_e2, new_e3)) self.assertTrue(graph.has_edge(new_e2, new_e4)) # if lower interiors connect with all 4 vertices all_neighbors = i1_1_neighbors + i2_1_neighbors all_neighbors = list(dict.fromkeys(all_neighbors)) # remove duplicates self.assertEqual(len(all_neighbors), 4) # if each vertex has correct label for n in all_neighbors: self.assertEqual(graph.nodes[n]['label'], 'E') # if each vertex has correct number of neighbors (based on neighbour interiors count) for n in all_neighbors: node_neighbors = get_neighbors_at(graph, n, graph.nodes[n]['layer']) i_neighbors = [ x for x in node_neighbors if graph.nodes[x]['label'] == 'I' ] if len(i_neighbors) == 1: self.assertEqual(len(node_neighbors), 3) elif len(i_neighbors) == 2: self.assertEqual(len(node_neighbors), 5) else: self.assertEqual(len(node_neighbors), 7) if visualize_tests: visualize_graph_3d(graph) pyplot.show()
def test_risky_triangle_break(self): graph = Graph() e1, e2, e3, e4, e5 = [gen_name() for _ in range(5)] e6 = gen_name() graph.add_node(e1, layer=1, position=(1.0, 2.0), label='E') graph.add_node(e2, layer=1, position=(1.0, 1.5), label='E') graph.add_node(e3, layer=1, position=(1.0, 1.0), label='E') graph.add_node(e4, layer=1, position=(2.0, 1.0), label='E') graph.add_node(e5, layer=1, position=(1.5, 1.5), label='E') graph.add_node(e6, layer=1, position=(0.0, 1.5), label='E') graph.add_edge(e1, e2) graph.add_edge(e2, e3) graph.add_edge(e3, e4) graph.add_edge(e4, e5) graph.add_edge(e5, e1) graph.add_edge(e1, e6) graph.add_edge(e6, e3) i = add_interior(graph, e1, e3, e4) if visualize_tests: visualize_graph_3d(graph) pyplot.show() [i1, i2, i3] = P4().apply(graph, [i]) self.assertEqual(len(graph.nodes()), 15) self.assertEqual(len(graph.edges()), 29) self.assertEqual(graph.nodes[i]['label'], 'i') self.assertTrue(graph.has_edge(i, i1)) self.assertTrue(graph.has_edge(i, i2)) self.assertTrue(graph.has_edge(i, i3)) self.assertEqual(graph.nodes[i1]['label'], 'I') self.assertEqual(graph.nodes[i2]['label'], 'I') self.assertEqual(graph.nodes[i3]['label'], 'I') self.assertEqual(graph.nodes[i1]['layer'], graph.nodes[i]['layer'] + 1) self.assertEqual(graph.nodes[i2]['layer'], graph.nodes[i]['layer'] + 1) self.assertEqual(graph.nodes[i3]['layer'], graph.nodes[i]['layer'] + 1) i1_neighbors = get_neighbors_at(graph, i1, graph.nodes[i1]['layer']) self.assertEqual(len(i1_neighbors), 3) i2_neighbors = get_neighbors_at(graph, i2, graph.nodes[i2]['layer']) self.assertEqual(len(i2_neighbors), 3) i3_neighbors = get_neighbors_at(graph, i3, graph.nodes[i3]['layer']) self.assertEqual(len(i3_neighbors), 3) i1_i2_n = [x for x in i1_neighbors if x in i2_neighbors] i1_i3_n = [x for x in i1_neighbors if x in i3_neighbors] i2_i3_n = [x for x in i2_neighbors if x in i3_neighbors] # Test i1-only neighbors for n in [ x for x in i1_neighbors if x not in i1_i2_n and x not in i1_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) # Test i2-only neighbors for n in [ x for x in i2_neighbors if x not in i1_i2_n and x not in i2_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i2]['layer']))) # Test i3-only neighbors for n in [ x for x in i3_neighbors if x not in i1_i3_n and x not in i2_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i3]['layer']))) # Test nodes connected to 2 interiors for n in [x for x in i1_i2_n if x not in i1_i3_n and x not in i2_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) for n in [x for x in i1_i3_n if x not in i1_i2_n and x not in i2_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) for n in [x for x in i2_i3_n if x not in i1_i2_n and x not in i1_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) # Test nodes connected to 3 interiors for n in [x for x in i2_i3_n if x in i1_i2_n and x in i1_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 7, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) if visualize_tests: visualize_graph_3d(graph) pyplot.show()
def test_happy_path(self): graph = Graph() e1 = gen_name() e2 = gen_name() e3 = gen_name() graph.add_node(e1, layer=0, position=(1.0, 2.0), label='E') graph.add_node(e2, layer=0, position=(1.0, 1.0), label='E') graph.add_node(e3, layer=0, position=(2.0, 1.0), label='E') graph.add_edge(e1, e2) graph.add_edge(e1, e3) graph.add_edge(e2, e3) i = add_interior(graph, e1, e2, e3) if visualize_tests: visualize_graph_3d(graph) pyplot.show() [i1, i2] = P2().apply(graph, [i]) self.assertIsNotNone(get_node_at(graph, 1, (1.0, 2.0))) self.assertIsNotNone(get_node_at(graph, 1, (1.0, 1.0))) self.assertIsNotNone(get_node_at(graph, 1, (2.0, 1.0))) self.assertIsNotNone(get_node_at(graph, 1, (1.5, 1.0))) (i1_x, i1_y) = graph.nodes[i1]['position'] (i2_x, i2_y) = graph.nodes[i2]['position'] self.assertTrue(isclose(i1_x, 1.166666, rel_tol=eps)) self.assertTrue(isclose(i1_y, 1.333333, rel_tol=eps)) self.assertTrue(isclose(i2_x, 1.5, rel_tol=eps)) self.assertTrue(isclose(i2_y, 1.333333, rel_tol=eps)) self.assertEqual(len(graph.nodes()), 10) self.assertEqual(len(graph.edges()), 19) self.assertEqual(graph.nodes[i]['label'], 'i') self.assertTrue(graph.has_edge(i, i1)) self.assertTrue(graph.has_edge(i, i2)) self.assertEqual(graph.nodes[i1]['label'], 'I') self.assertEqual(graph.nodes[i2]['label'], 'I') self.assertEqual(graph.nodes[i1]['layer'], graph.nodes[i]['layer'] + 1) self.assertEqual(graph.nodes[i2]['layer'], graph.nodes[i]['layer'] + 1) i1_neighbors = get_neighbors_at(graph, i1, graph.nodes[i1]['layer']) self.assertEqual(len(i1_neighbors), 3) i2_neighbors = get_neighbors_at(graph, i2, graph.nodes[i2]['layer']) self.assertEqual(len(i2_neighbors), 3) common_neighbors = [x for x in i1_neighbors if x in i2_neighbors] for n in i1_neighbors: if n not in common_neighbors: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( len(get_neighbors_at(graph, n, graph.nodes[i1]['layer'])), 3) for n in i2_neighbors: if n not in common_neighbors: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( len(get_neighbors_at(graph, n, graph.nodes[i2]['layer'])), 3) for c_neighbor in common_neighbors: self.assertEqual(graph.nodes[c_neighbor]['label'], 'E') self.assertEqual( len( get_neighbors_at(graph, c_neighbor, graph.nodes[i1]['layer'])), 5) if visualize_tests: visualize_graph_3d(graph) pyplot.show()
def test_in_bigger_graph(self): graph = Graph() # Base nodes e1, e2, e3, e4, e5 = [gen_name() for _ in range(5)] # Additional nodes e6, e7, e8, e9 = [gen_name() for _ in range(4)] graph.add_node(e1, layer=1, position=(1.0, 2.0), label='E') graph.add_node(e2, layer=1, position=(1.0, 1.5), label='E') graph.add_node(e3, layer=1, position=(1.0, 1.0), label='E') graph.add_node(e4, layer=1, position=(2.0, 1.0), label='E') graph.add_node(e5, layer=1, position=(1.5, 1.5), label='E') graph.add_node(e6, layer=1, position=(2.0, 2.0), label='E') graph.add_node(e7, layer=1, position=(1.0, 0.0), label='E') graph.add_node(e8, layer=1, position=(2.0, 0.0), label='E') graph.add_node(e9, layer=1, position=(1.5, -1.0), label='E') graph.add_edge(e1, e2) graph.add_edge(e2, e3) graph.add_edge(e3, e4) graph.add_edge(e4, e5) graph.add_edge(e5, e1) graph.add_edge(e1, e6) graph.add_edge(e6, e5) graph.add_edge(e7, e3) graph.add_edge(e7, e8) graph.add_edge(e7, e9) graph.add_edge(e8, e4) graph.add_edge(e8, e9) I = add_interior(graph, e1, e3, e4) I1 = add_interior(graph, e1, e5, e6) I2 = add_interior(graph, e7, e8, e4) I3 = add_interior(graph, e7, e8, e9) if visualize_tests: visualize_graph_3d(graph) pyplot.show() [i1, i2, i3] = P4().apply(graph, [I]) self.assertEqual(len(graph.nodes()), 21) self.assertEqual(len(graph.edges()), 43) self.assertEqual(graph.nodes[I]['label'], 'i') self.assertTrue(graph.has_edge(I, i1)) self.assertTrue(graph.has_edge(I, i2)) self.assertTrue(graph.has_edge(I, i3)) self.assertEqual(graph.nodes[i1]['label'], 'I') self.assertEqual(graph.nodes[i2]['label'], 'I') self.assertEqual(graph.nodes[i3]['label'], 'I') self.assertEqual(graph.nodes[i1]['layer'], graph.nodes[I]['layer'] + 1) self.assertEqual(graph.nodes[i2]['layer'], graph.nodes[I]['layer'] + 1) self.assertEqual(graph.nodes[i3]['layer'], graph.nodes[I]['layer'] + 1) i1_neighbors = get_neighbors_at(graph, i1, graph.nodes[i1]['layer']) self.assertEqual(len(i1_neighbors), 3) i2_neighbors = get_neighbors_at(graph, i2, graph.nodes[i2]['layer']) self.assertEqual(len(i2_neighbors), 3) i3_neighbors = get_neighbors_at(graph, i3, graph.nodes[i3]['layer']) self.assertEqual(len(i3_neighbors), 3) i1_i2_n = [x for x in i1_neighbors if x in i2_neighbors] i1_i3_n = [x for x in i1_neighbors if x in i3_neighbors] i2_i3_n = [x for x in i2_neighbors if x in i3_neighbors] # Test i1-only neighbors for n in [ x for x in i1_neighbors if x not in i1_i2_n and x not in i1_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) # Test i2-only neighbors for n in [ x for x in i2_neighbors if x not in i1_i2_n and x not in i2_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i2]['layer']))) # Test i3-only neighbors for n in [ x for x in i3_neighbors if x not in i1_i3_n and x not in i2_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i3]['layer']))) # Test nodes connected to 2 interiors for n in [x for x in i1_i2_n if x not in i1_i3_n and x not in i2_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) for n in [x for x in i1_i3_n if x not in i1_i2_n and x not in i2_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) for n in [x for x in i2_i3_n if x not in i1_i2_n and x not in i1_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) # Test nodes connected to 3 interiors for n in [x for x in i2_i3_n if x in i1_i2_n and x in i1_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 7, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) if visualize_tests: visualize_graph_3d(graph) pyplot.show()
def __check_prod_input(graph: Graph, prod_input: List[str]): # Check number of vertices delivered if len(set(prod_input)) != 4: raise ValueError('Wrong number of interiors') # Check layers layers = [] for interior in prod_input: layers.append(graph.nodes()[interior]['layer']) if layers[0] + 1 != layers[3]: raise ValueError('Interiors on wrong number of layers') if layers[0] != layers[1]: raise ValueError('Too few interiors in upper layer') if layers[2] != layers[3]: raise ValueError('Too few interiors in lower layer') up_layer = layers[0] down_layer = layers[3] # Check delivered vertices labels if any(graph.nodes()[interior]['label'] != 'i' for interior in prod_input[:2]): raise ValueError('Wrong label of vertices in upper layer') if any(graph.nodes()[interior]['label'] != 'I' for interior in prod_input[2:]): raise ValueError('Wrong label of vertices in lower layer') # Check connections between delivered vertices neighbors_in_lower_layer = {prod_input[0]: set(), prod_input[1]: set()} for upper_interior in prod_input[:2]: for bottom_neighbor in get_neighbors_at(graph, upper_interior, down_layer): neighbors_in_lower_layer[upper_interior].add(bottom_neighbor) for lower_interior in prod_input[2:]: if lower_interior not in neighbors_in_lower_layer[prod_input[0]]\ and lower_interior not in neighbors_in_lower_layer[prod_input[1]]: raise ValueError('Upper interiors not connected to lower ones') # maps lower interiors to its parent in upper layer lower_to_upper = dict() for upper in neighbors_in_lower_layer: for lower in neighbors_in_lower_layer[upper]: lower_to_upper[lower] = upper # Check common neighbors of upper interiors upper_neighbors = get_common_neighbors(graph, prod_input[0], prod_input[1], up_layer) if len(upper_neighbors) != 2: raise ValueError('Upper interiors don not have 2 common neighbors') # Get those neighbors and their positions as well as center position between them v1_up, v2_up = upper_neighbors pos_v1 = graph.nodes()[v1_up]['position'] pos_v2 = graph.nodes()[v2_up]['position'] # Check if they are connected if not graph.has_edge(v1_up, v2_up): raise ValueError('Upper vertices are not connected') # Prepare list of vertices in lower layer pairs_of_lower = [set(), set()] for interior in prod_input[2:]: for v in get_neighbors_at(graph, interior, down_layer): if graph.nodes()[v]['position'] == pos_v1: pairs_of_lower[0].add((v, lower_to_upper[interior])) elif graph.nodes()[v]['position'] == pos_v2: pairs_of_lower[1].add((v, lower_to_upper[interior])) # Check if pair is indeed pair of vertices for pair in pairs_of_lower: s = set(map(lambda x: x[0], pair)) if len(s) != 2: raise ValueError( 'Connections between lower vertices are incorrect') # separate vertices based on side it is on (vertices on one side are connected) vertices_by_side = {prod_input[0]: list(), prod_input[1]: list()} for pair in pairs_of_lower: for v in pair: vertices_by_side[v[1]].append(v[0]) # Now vertices_by_side should be dict where keys are id's of interiors in upper layer # and values are lists of vertices in lower layer on belonging to this parent # Check if vertices on opposite sides are connected # (they obviously shouldn't be right?) for v in vertices_by_side[prod_input[0]]: if any( graph.has_edge(v, v_other) for v_other in vertices_by_side[prod_input[1]]): raise ValueError( 'Connections between lower vertices are incorrect') # Check if labels are E all_vertices = vertices_by_side[prod_input[0]] + vertices_by_side[ prod_input[1]] + [v1_up, v2_up] if any(graph.nodes()[v]['label'] != 'E' for v in all_vertices): raise ValueError('Not all vertices have label E')
def test_parent_graph(self): graph = Graph() positions = [(1.0, 1.0), (1.0, 9.0), (9.0, 1.0), (9.0, 9.0), (5.0, 5.0), (3.0, 7.0), (7.0, 7.0), (6.0, 6.0), (4.0, 8.0)] [e0a, e1, e0b, e0c, e2, e12, e3, e23, e31] = self.create_nodes(graph, 1, 'E', positions) self.create_edges_chain(graph, [e0a, e1, e12, e0a, e2, e12]) self.create_edges_chain(graph, [e0a, e0b, e2, e23, e0b, e3, e23]) self.create_edges_chain(graph, [e0b, e0c, e3, e31, e0c, e1, e31]) i_0a_1_12 = add_interior(graph, e0a, e1, e12) i_0a_12_2 = add_interior(graph, e0a, e12, e2) i_0a_0b_2 = add_interior(graph, e0a, e0b, e2) i_0b_2_23 = add_interior(graph, e0b, e2, e23) i_0b_23_3 = add_interior(graph, e0b, e23, e3) i_0b_0c_3 = add_interior(graph, e0b, e3, e0c) i_0c_1_31 = add_interior(graph, e1, e31, e0c) i_0c_3_31 = add_interior(graph, e31, e3, e0c) i = add_interior(graph, e1, e2, e3) if visualize_tests: pyplot.title("Correct subgraph input", fontsize=16) visualize_graph_layer(graph, 1) pyplot.show() [i1, i3, i2a, i2b] = P5().apply(graph, [i]) if visualize_tests: pyplot.title("Correct subgraph output", fontsize=16) visualize_graph_3d(graph) pyplot.show() pyplot.title("Correct subgraph output (layer=1)", fontsize=16) visualize_graph_layer(graph, 1) pyplot.show() pyplot.title("Correct subgraph output (layer=2)", fontsize=16) visualize_graph_layer(graph, 2) pyplot.show() # if edges are unchanged self.assertTrue(graph.has_edge(e0a, e1)) self.assertTrue(graph.has_edge(e1, e12)) self.assertTrue(graph.has_edge(e12, e0a)) self.assertTrue(graph.has_edge(e0a, e2)) self.assertTrue(graph.has_edge(e2, e12)) self.assertTrue(graph.has_edge(e0a, e0b)) self.assertTrue(graph.has_edge(e0b, e2)) self.assertTrue(graph.has_edge(e2, e23)) self.assertTrue(graph.has_edge(e23, e0b)) self.assertTrue(graph.has_edge(e0b, e3)) self.assertTrue(graph.has_edge(e3, e23)) self.assertTrue(graph.has_edge(e0b, e0c)) self.assertTrue(graph.has_edge(e0c, e3)) self.assertTrue(graph.has_edge(e3, e31)) self.assertTrue(graph.has_edge(e31, e0c)) self.assertTrue(graph.has_edge(e0c, e1)) self.assertTrue(graph.has_edge(e1, e31)) # if interior links are unchanged self.assertTrue(graph.has_edge(i, e1)) self.assertTrue(graph.has_edge(i, e2)) self.assertTrue(graph.has_edge(i, e3)) self.assertTrue(graph.has_edge(i_0a_1_12, e0a)) self.assertTrue(graph.has_edge(i_0a_1_12, e1)) self.assertTrue(graph.has_edge(i_0a_1_12, e12)) self.assertTrue(graph.has_edge(i_0a_12_2, e0a)) self.assertTrue(graph.has_edge(i_0a_12_2, e12)) self.assertTrue(graph.has_edge(i_0a_12_2, e2)) self.assertTrue(graph.has_edge(i_0a_0b_2, e0a)) self.assertTrue(graph.has_edge(i_0a_0b_2, e0b)) self.assertTrue(graph.has_edge(i_0a_0b_2, e2)) self.assertTrue(graph.has_edge(i_0b_2_23, e0b)) self.assertTrue(graph.has_edge(i_0b_2_23, e2)) self.assertTrue(graph.has_edge(i_0b_2_23, e23)) self.assertTrue(graph.has_edge(i_0b_23_3, e0b)) self.assertTrue(graph.has_edge(i_0b_23_3, e23)) self.assertTrue(graph.has_edge(i_0b_23_3, e3)) self.assertTrue(graph.has_edge(i_0b_0c_3, e0b)) self.assertTrue(graph.has_edge(i_0b_0c_3, e3)) self.assertTrue(graph.has_edge(i_0b_0c_3, e0c)) self.assertTrue(graph.has_edge(i_0c_1_31, e1)) self.assertTrue(graph.has_edge(i_0c_1_31, e31)) self.assertTrue(graph.has_edge(i_0c_1_31, e0c)) self.assertTrue(graph.has_edge(i_0c_3_31, e31)) self.assertTrue(graph.has_edge(i_0c_3_31, e3)) self.assertTrue(graph.has_edge(i_0c_3_31, e0c)) # if vertex labels are unchanged self.assertEqual(graph.nodes[e0a]['label'], 'E') self.assertEqual(graph.nodes[e1]['label'], 'E') self.assertEqual(graph.nodes[e0b]['label'], 'E') self.assertEqual(graph.nodes[e0c]['label'], 'E') self.assertEqual(graph.nodes[e2]['label'], 'E') self.assertEqual(graph.nodes[e12]['label'], 'E') self.assertEqual(graph.nodes[e3]['label'], 'E') self.assertEqual(graph.nodes[e23]['label'], 'E') self.assertEqual(graph.nodes[e31]['label'], 'E') # if number of neighbors is unchanged # if each vertex has correct number of neighbors (based on neighbour interiors count) for n in [e0a, e1, e0b, e0c, e2, e12, e3, e23, e31]: node_neighbors = get_neighbors_at(graph, n, graph.nodes[n]['layer']) i_neighbors = [ x for x in node_neighbors if graph.nodes[x]['label'] == 'I' or graph.nodes[x]['label'] == 'i' ] e_neighbors = [ x for x in node_neighbors if graph.nodes[x]['label'] == 'E' or graph.nodes[x]['label'] == 'e' ] if len(e_neighbors) == len(i_neighbors): self.assertEqual(len(node_neighbors), len(i_neighbors) * 2) else: self.assertEqual(len(node_neighbors), (len(i_neighbors) * 2) + 1) # if vertices position is unchanged self.assertEqual(graph.nodes[e0a]['position'], (1.0, 1.0)) self.assertEqual(graph.nodes[e1]['position'], (1.0, 9.0)) self.assertEqual(graph.nodes[e0b]['position'], (9.0, 1.0)) self.assertEqual(graph.nodes[e0c]['position'], (9.0, 9.0)) self.assertEqual(graph.nodes[e2]['position'], (5.0, 5.0)) self.assertEqual(graph.nodes[e12]['position'], (3.0, 7.0)) self.assertEqual(graph.nodes[e3]['position'], (7.0, 7.0)) self.assertEqual(graph.nodes[e23]['position'], (6.0, 6.0)) self.assertEqual(graph.nodes[e31]['position'], (4.0, 8.0))
def test_in_bigger_graph(self): graph = Graph() positions = [(0, 0), (0, 1), (1, 0), (0, 0.5), (0.5, 0.5)] vx_e1 = gen_name() vx_e2 = gen_name() vx_e3 = gen_name() vx_e12 = gen_name() vx_e23 = gen_name() graph.add_node(vx_e1, layer=0, position=positions[0], label='E') graph.add_node(vx_e2, layer=0, position=positions[1], label='E') graph.add_node(vx_e3, layer=0, position=positions[2], label='E') graph.add_node(vx_e12, layer=0, position=positions[3], label='E') graph.add_node(vx_e23, layer=0, position=positions[4], label='E') graph.add_edge(vx_e1, vx_e12) graph.add_edge(vx_e12, vx_e2) graph.add_edge(vx_e2, vx_e23) graph.add_edge(vx_e23, vx_e3) graph.add_edge(vx_e3, vx_e1) vx_e1122 = gen_name() graph.add_node(vx_e1122, layer=0, position=(-0.5, 0.5), label='E') graph.add_edge(vx_e1, vx_e1122) graph.add_edge(vx_e12, vx_e1122) graph.add_edge(vx_e2, vx_e1122) vx_e2233 = gen_name() graph.add_node(vx_e2233, layer=0, position=(1, 1), label='E') graph.add_edge(vx_e2, vx_e2233) graph.add_edge(vx_e23, vx_e2233) graph.add_edge(vx_e3, vx_e2233) vx_e13 = gen_name() graph.add_node(vx_e13, layer=0, position=(0.5, -0.5), label='E') graph.add_edge(vx_e1, vx_e13) graph.add_edge(vx_e3, vx_e13) I = add_interior(graph, vx_e1, vx_e2, vx_e3) I1 = add_interior(graph, vx_e1122, vx_e1, vx_e12) I2 = add_interior(graph, vx_e1122, vx_e12, vx_e2) I3 = add_interior(graph, vx_e2233, vx_e2, vx_e23) I4 = add_interior(graph, vx_e2233, vx_e23, vx_e3) I5 = add_interior(graph, vx_e1, vx_e3, vx_e13) if visualize_tests: visualize_graph_3d(graph) pyplot.show() [i1, i2, i3] = P4().apply(graph, [I]) self.assertEqual(len(graph.nodes()), 22) self.assertEqual(len(graph.edges()), 50) self.assertEqual(graph.nodes[I]['label'], 'i') self.assertTrue(graph.has_edge(I, i1)) self.assertTrue(graph.has_edge(I, i2)) self.assertTrue(graph.has_edge(I, i3)) self.assertEqual(graph.nodes[i1]['label'], 'I') self.assertEqual(graph.nodes[i2]['label'], 'I') self.assertEqual(graph.nodes[i3]['label'], 'I') self.assertEqual(graph.nodes[i1]['layer'], graph.nodes[I]['layer'] + 1) self.assertEqual(graph.nodes[i2]['layer'], graph.nodes[I]['layer'] + 1) self.assertEqual(graph.nodes[i3]['layer'], graph.nodes[I]['layer'] + 1) i1_neighbors = get_neighbors_at(graph, i1, graph.nodes[i1]['layer']) self.assertEqual(len(i1_neighbors), 3) i2_neighbors = get_neighbors_at(graph, i2, graph.nodes[i2]['layer']) self.assertEqual(len(i2_neighbors), 3) i3_neighbors = get_neighbors_at(graph, i3, graph.nodes[i3]['layer']) self.assertEqual(len(i3_neighbors), 3) i1_i2_n = [x for x in i1_neighbors if x in i2_neighbors] i1_i3_n = [x for x in i1_neighbors if x in i3_neighbors] i2_i3_n = [x for x in i2_neighbors if x in i3_neighbors] # Test i1-only neighbors for n in [ x for x in i1_neighbors if x not in i1_i2_n and x not in i1_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) # Test i2-only neighbors for n in [ x for x in i2_neighbors if x not in i1_i2_n and x not in i2_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i2]['layer']))) # Test i3-only neighbors for n in [ x for x in i3_neighbors if x not in i1_i3_n and x not in i2_i3_n ]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 3, len(get_neighbors_at(graph, n, graph.nodes[i3]['layer']))) # Test nodes connected to 2 interiors for n in [x for x in i1_i2_n if x not in i1_i3_n and x not in i2_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) for n in [x for x in i1_i3_n if x not in i1_i2_n and x not in i2_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) for n in [x for x in i2_i3_n if x not in i1_i2_n and x not in i1_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 5, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) # Test nodes connected to 3 interiors for n in [x for x in i2_i3_n if x in i1_i2_n and x in i1_i3_n]: self.assertEqual(graph.nodes[n]['label'], 'E') self.assertEqual( 7, len(get_neighbors_at(graph, n, graph.nodes[i1]['layer']))) if visualize_tests: visualize_graph_3d(graph) pyplot.show()
def __check_prod_input(graph: Graph, prod_input: List[str]): # Check number of vertices delivered if len(set(prod_input)) != 6: raise ValueError('Too few interiors in prod_input (6 required)') # Check layers up_layer = graph.nodes()[prod_input[0]]['layer'] down_layer = graph.nodes()[prod_input[2]]['layer'] if any(graph.nodes()[interior]['layer'] != up_layer for interior in prod_input[:2]): raise ValueError('First two interior are not in the same layer') if any(graph.nodes()[interior]['layer'] != down_layer for interior in prod_input[2:]): raise ValueError('Four last interiors are not in the same layer') if up_layer + 1 != down_layer: raise ValueError('Upper layer is not right above lower one') # Check delivered vertices labels if any(graph.nodes()[interior]['label'] != 'i' for interior in prod_input[:2]): raise ValueError('First two interior don not have "i" label') if any(graph.nodes()[interior]['label'] != 'I' for interior in prod_input[2:]): raise ValueError('Four last interior don not have "I" label') # Check connections between delivered vertices neighbors_in_lower_layer = {prod_input[0]: set(), prod_input[1]: set()} for upper_interior in prod_input[:2]: for bottom_neighbor in get_neighbors_at(graph, upper_interior, down_layer): neighbors_in_lower_layer[upper_interior].add(bottom_neighbor) for lower_interior in prod_input[2:]: if lower_interior not in neighbors_in_lower_layer[prod_input[0]]\ and lower_interior not in neighbors_in_lower_layer[prod_input[1]]: raise ValueError( 'Upper interiors not connected properly to lower ones') if len(neighbors_in_lower_layer[prod_input[0]]) != 2: raise ValueError( 'Upper interiors not connected properly to lower ones') if len(neighbors_in_lower_layer[prod_input[1]]) != 2: raise ValueError( 'Upper interiors not connected properly to lower ones') # maps lower interiors to its parent in upper layer lower_to_upper = dict() for upper in neighbors_in_lower_layer: for lower in neighbors_in_lower_layer[upper]: lower_to_upper[lower] = upper # Check common neighbors of upper interiors upper_neighbors = get_common_neighbors(graph, prod_input[0], prod_input[1], up_layer) if len(upper_neighbors) != 2: raise ValueError('Upper interiors don not have 2 common neighbors') # Get those neighbors and their positions as well as center position between them v1_up, v2_up = upper_neighbors pos_v1 = graph.nodes()[v1_up]['position'] pos_v2 = graph.nodes()[v2_up]['position'] x = (pos_v1[0] + pos_v2[0]) / 2 y = (pos_v1[1] + pos_v2[1]) / 2 pos_center = (x, y) # Check if they are connected if not graph.has_edge(v1_up, v2_up): raise ValueError('Upper vertices are not connected') # Prepare list of vertices in lower layer pairs_of_lower = [set(), set(), set()] for interior in prod_input[2:]: for v in get_neighbors_at(graph, interior, down_layer): if graph.nodes()[v]['position'] == pos_v1: pairs_of_lower[0].add((v, lower_to_upper[interior])) elif graph.nodes()[v]['position'] == pos_v2: pairs_of_lower[1].add((v, lower_to_upper[interior])) elif graph.nodes()[v]['position'] == pos_center: if v not in pairs_of_lower[2]: pairs_of_lower[2].add((v, lower_to_upper[interior])) # Check if pair is indeed pair of vertices for pair in pairs_of_lower: s = set(map(lambda x: x[0], pair)) if len(s) != 2: raise ValueError( 'Connections between lower vertices are incorrect') # separate vertices based on side it is on (vertices on one side are connected) vertices_by_side = {prod_input[0]: list(), prod_input[1]: list()} for pair in pairs_of_lower: for v in pair: vertices_by_side[v[1]].append(v[0]) # Now vertices_by_side should be dict where keys are id's of interiors in upper layer # and values are lists of vertices in loser layer on belonging to this parent # also last element on this list is center between two previous # Check if vertices on one side are properly connected for side in vertices_by_side: v1, v2, v3 = vertices_by_side[side] if not graph.has_edge(v1, v3): raise ValueError( 'Connections between lower vertices are incorrect') if not graph.has_edge(v2, v3): raise ValueError( 'Connections between lower vertices are incorrect') # Check if middle vertices are properly connected to two interiors each for side in vertices_by_side: v1, v2, v3 = vertices_by_side[side] # v3 is vertex in the middle lower_interiors = get_neighbors_at(graph, side, down_layer) for interior in lower_interiors: if interior not in graph.neighbors(v3): raise ValueError( 'Connections between lower vertices are incorrect') # Check if vertices on opposite sides are connected # (they obviously shouldn't be right?) for v in vertices_by_side[prod_input[0]]: if any( graph.has_edge(v, v_other) for v_other in vertices_by_side[prod_input[1]]): raise ValueError( 'Connections between lower vertices are incorrect') # Check if labels are E all_vertices = vertices_by_side[prod_input[0]] + vertices_by_side[ prod_input[1]] + [v1_up, v2_up] if any(graph.nodes()[v]['label'] != 'E' for v in all_vertices): raise ValueError('Not all vertices have label E')
def apply(self, graph: Graph, prod_input: List[str], orientation: int = 0, **kwargs) -> List[str]: self.__check_prod_input(graph, prod_input) layer = graph.nodes()[prod_input[0]]['layer'] overlapping_vertices = find_overlapping_vertices(graph) vertices_to_join = set() for overlapping_vertice1, overlapping_vertice2 in overlapping_vertices: vertices_to_join.add(overlapping_vertice1) vertices_to_join.add(overlapping_vertice2) vertices_to_join_group1 = [ vertice for vertice in vertices_to_join if graph.nodes()[vertice]['position'] == graph.nodes()[list( vertices_to_join)[0]]['position'] ] vertices_to_join_group2 = [ vertice for vertice in vertices_to_join if vertice not in vertices_to_join_group1 ] vertice1_group1_neighbours = get_neighbors_at( graph, vertices_to_join_group1[0], layer) vertice2_group1_neighbours = get_neighbors_at( graph, vertices_to_join_group1[1], layer) vertice1_group2_neighbours = get_neighbors_at( graph, vertices_to_join_group2[0], layer) vertice2_group2_neighbours = get_neighbors_at( graph, vertices_to_join_group2[1], layer) vertice1_group1_I_neighbours = [ neighbour for neighbour in vertice1_group1_neighbours if graph.nodes()[neighbour]['label'] == "I" ] vertice2_group1_I_neighbours = [ neighbour for neighbour in vertice2_group1_neighbours if graph.nodes()[neighbour]['label'] == "I" ] vertice1_group2_I_neighbours = [ neighbour for neighbour in vertice1_group2_neighbours if graph.nodes()[neighbour]['label'] == "I" ] vertice2_group2_I_neighbours = [ neighbour for neighbour in vertice2_group2_neighbours if graph.nodes()[neighbour]['label'] == "I" ] common_I_neighbour_vertices_to_join = [] if vertice1_group1_I_neighbours == vertice1_group2_I_neighbours: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[0]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[0]) elif vertice1_group1_I_neighbours == vertice2_group2_I_neighbours: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[0]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[1]) elif vertice2_group1_I_neighbours == vertice1_group2_I_neighbours: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[1]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[0]) elif vertice2_group1_I_neighbours == vertice2_group2_I_neighbours: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[1]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[1]) if graph.has_edge(common_I_neighbour_vertices_to_join[0], common_I_neighbour_vertices_to_join[1]): graph.remove_edge(common_I_neighbour_vertices_to_join[0], common_I_neighbour_vertices_to_join[1]) join_overlapping_vertices(graph, vertices_to_join_group1[0], vertices_to_join_group1[1], layer) join_overlapping_vertices(graph, vertices_to_join_group2[0], vertices_to_join_group2[1], layer) return prod_input
def __check_prod_input(graph: Graph, prod_input: List[str]): # Check number of vertices delivered if len(prod_input) != 6: raise ValueError( 'Wrong number of interiors in prod_input (6 required)') nodes = [(node_id, graph.nodes()[node_id]) for node_id in prod_input] up_layer_nodes = [ node_id for node_id, data in nodes if data['label'] == 'i' ] down_layer_nodes = [ node_id for node_id, data in nodes if data['label'] == 'I' ] if len(up_layer_nodes) != 2: raise ValueError( 'Wrong number of interiors in first layer (2 required)') if len(down_layer_nodes) != 4: raise ValueError( 'Wrong number of interiors in second layer (4 required)') # Check layers up_layer = graph.nodes()[up_layer_nodes[0]]['layer'] down_layer = graph.nodes()[down_layer_nodes[0]]['layer'] if any(graph.nodes()[node]['layer'] != up_layer for node in up_layer_nodes): raise ValueError('"i" interiors are not in the same layer') if any(graph.nodes()[node]['layer'] != down_layer for node in down_layer_nodes): raise ValueError('"I" interiors are not in the same layer') if up_layer + 1 != down_layer: raise ValueError('Upper layer is not right above lower one') # Check connections between delivered vertices interior_neighbours0 = [ node_id for node_id in graph.neighbors(up_layer_nodes[0]) if graph.nodes()[node_id]['label'] == 'I' ] interior_neighbours1 = [ node_id for node_id in graph.neighbors(up_layer_nodes[1]) if graph.nodes()[node_id]['label'] == 'I' ] if len(interior_neighbours0) != len(interior_neighbours1) != 2: raise ValueError( 'Upper interiors not connected properly to lower ones') if len(common_elements(interior_neighbours0, interior_neighbours1)) != 0: raise ValueError( 'Upper interiors not connected properly to lower ones') if len(common_elements(interior_neighbours0, down_layer_nodes)) != 2: raise ValueError( 'Upper interiors not connected properly to lower ones') if len(common_elements(interior_neighbours1, down_layer_nodes)) != 2: raise ValueError( 'Upper interiors not connected properly to lower ones') # Check correctness of the graph connections def check_structure(interior_nodes, layer_num): for interior_node in interior_nodes: neighbours = get_neighbors_at(graph, interior_node, layer_num) if len(neighbours) > 3: raise ValueError( 'Wrong number of neighbours of an interior vertex') for n in neighbours: if graph.nodes()[n]['label'] != "E": raise ValueError('Vertex does not have "E" label') common_neighbors = get_common_neighbors(graph, interior_nodes[0], interior_nodes[1], layer_num) if len(common_neighbors) > 2: raise ValueError('Interiors have more than 2 common neighbors') return common_neighbors # Check correctness of upper layer up_e = check_structure(up_layer_nodes, up_layer) # Check correctness of lower layer check_structure(interior_neighbours0, down_layer) check_structure(interior_neighbours1, down_layer) if len(up_e) != 2: raise ValueError( 'Upper kayer interiors have less than 2 common neighbors') if not are_connected(graph, up_e): raise ValueError('E vertices in upper layer not connected') # check nodes with the same position n1 = sorted( set( get_neighbors_at(graph, interior_neighbours0[0], down_layer) + get_neighbors_at(graph, interior_neighbours0[1], down_layer))) n2 = sorted( set( get_neighbors_at(graph, interior_neighbours1[0], down_layer) + get_neighbors_at(graph, interior_neighbours1[1], down_layer))) c = common_elements(n1, n2) if len(c) != 1: raise ValueError( 'There is not exactly 1 common vertex on the line') nn = [ x for x in graph.neighbors(c[0]) if graph.nodes()[x]['label'] == 'I' ] if len(common_elements(nn, prod_input)) != 2: raise ValueError( 'Wrong number of interior neighbours of the common vertex') n1.remove(c[0]) n2.remove(c[0]) n1_pos = [graph.nodes()[n]['position'] for n in n1] n2_pos = [graph.nodes()[n]['position'] for n in n2] n1 = [ n for n in n1 for pos in n2_pos if graph.nodes()[n]['position'] == pos ] n2 = [ n for n in n2 for pos in n1_pos if graph.nodes()[n]['position'] == pos ] if len(n1) != 2: raise ValueError( 'There are not exactly 2 vertices with the same position') if len(n2) != 2: raise ValueError( 'There are not exactly 2 vertices with the same position') if not are_connected(graph, n1): raise ValueError('Vertices on the line not connected') if not are_connected(graph, n2): raise ValueError('Vertices on the line not connected') a1 = [ v for v in n1 if len( common_elements([ x for x in graph.neighbors(v) if graph.nodes()[x]['label'] == 'I' ], prod_input)) == 2 ] a2 = [ v for v in n2 if len( common_elements([ x for x in graph.neighbors(v) if graph.nodes()[x]['label'] == 'I' ], prod_input)) == 2 ] if len(a1) != 1: raise ValueError( 'Wrong interior connections for vertices on the line') if len(a2) != 1: raise ValueError( 'Wrong interior connections for vertices on the line') if not are_connected(graph, [a1[0], c[0]]): raise ValueError('Vertices on the line not connected') if not are_connected(graph, [a2[0], c[0]]): raise ValueError('Vertices on the line not connected') return down_layer, zip(n1, n2)
def test_happy_path(self): graph = Graph() positions = [(1.0, 1.0), (1.0, 2.0), (1.0, 3.0), (2.0, 3.0), (3.0, 3.0), (2.0, 2.0)] [e1, e12, e2, e23, e3, e31] = self.create_nodes(graph, 1, 'E', positions) self.create_edges_chain(graph, [e1, e12, e2, e23, e3, e31, e1]) i = add_interior(graph, e1, e2, e3) if visualize_tests: pyplot.title("Correct input", fontsize=16) visualize_graph_3d(graph) pyplot.show() [i1, i3, i2a, i2b] = P5().apply(graph, [i]) if visualize_tests: pyplot.title("Correct output", fontsize=16) visualize_graph_3d(graph) pyplot.show() pyplot.title("Correct output (layer = 1)", fontsize=16) visualize_graph_layer(graph, 1) pyplot.show() pyplot.title("Correct output (layer = 2)", fontsize=16) visualize_graph_layer(graph, 2) pyplot.show() # if correct number of nodes and edges self.assertEqual(len(graph.nodes()), 17) self.assertEqual(len(graph.edges()), 34) # if cross-layer interior connections self.assertEqual(graph.nodes[i]['label'], 'i') self.assertTrue(graph.has_edge(i, i1)) self.assertTrue(graph.has_edge(i, i3)) self.assertTrue(graph.has_edge(i, i2a)) self.assertTrue(graph.has_edge(i, i2b)) # if new interiors has correct labels and layers self.assertEqual(graph.nodes[i1]['label'], 'I') self.assertEqual(graph.nodes[i3]['label'], 'I') self.assertEqual(graph.nodes[i2a]['label'], 'I') self.assertEqual(graph.nodes[i2b]['label'], 'I') self.assertEqual(graph.nodes[i1]['layer'], graph.nodes[i]['layer'] + 1) self.assertEqual(graph.nodes[i3]['layer'], graph.nodes[i]['layer'] + 1) self.assertEqual(graph.nodes[i2a]['layer'], graph.nodes[i]['layer'] + 1) self.assertEqual(graph.nodes[i2b]['layer'], graph.nodes[i]['layer'] + 1) # if each new interior has 3 neighbors i1_neighbors = get_neighbors_at(graph, i1, graph.nodes[i1]['layer']) self.assertEqual(len(i1_neighbors), 3) i3_neighbors = get_neighbors_at(graph, i3, graph.nodes[i3]['layer']) self.assertEqual(len(i3_neighbors), 3) i2a_neighbors = get_neighbors_at(graph, i2a, graph.nodes[i2a]['layer']) self.assertEqual(len(i2a_neighbors), 3) i2b_neighbors = get_neighbors_at(graph, i2b, graph.nodes[i2b]['layer']) self.assertEqual(len(i2b_neighbors), 3) # if new nodes are in correct positions new_e1 = get_node_at(graph, 2, (1.0, 1.0)) new_e12 = get_node_at(graph, 2, (1.0, 2.0)) new_e2 = get_node_at(graph, 2, (1.0, 3.0)) new_e23 = get_node_at(graph, 2, (2.0, 3.0)) new_e3 = get_node_at(graph, 2, (3.0, 3.0)) new_e31 = get_node_at(graph, 2, (2.0, 2.0)) self.assertIsNotNone(new_e1) self.assertIsNotNone(new_e12) self.assertIsNotNone(new_e2) self.assertIsNotNone(new_e23) self.assertIsNotNone(new_e3) self.assertIsNotNone(new_e31) # if interiors connect with all new 6 vertices all_neighbors = i1_neighbors + i3_neighbors + i2a_neighbors + i2b_neighbors all_neighbors = list(dict.fromkeys(all_neighbors)) # remove duplicates self.assertEqual(len(all_neighbors), 6) # if each vertex has correct label for n in all_neighbors: self.assertEqual(graph.nodes[n]['label'], 'E') # if each vertex has correct number of neighbors (based on neighbour interiors count) for n in all_neighbors: node_neighbors = get_neighbors_at(graph, n, graph.nodes[n]['layer']) i_neighbors = [ x for x in node_neighbors if graph.nodes[x]['label'] == 'I' ] if len(i_neighbors) == 1: self.assertEqual(len(node_neighbors), 3) elif len(i_neighbors) == 2: self.assertEqual(len(node_neighbors), 5) else: # 4 self.assertEqual(len(node_neighbors), 9)
def __check_prod_input(graph, prod_input): if len(set(prod_input)) != 3: raise ValueError('too few interiors') layer = graph.nodes()[prod_input[0]]['layer'] if any(graph.nodes()[interior]['layer'] != layer for interior in prod_input[1:]): raise ValueError('interior vertices come from different layers') if any(graph.nodes()[interior]['label'] != 'I' for interior in prod_input): raise ValueError('interior vertices must have I label') all_I_neighbours = [] for interior in prod_input: interior_neighbours = get_neighbors_at(graph, interior, layer) if len(interior_neighbours) not in [2, 3]: raise ValueError('wrongly connected interior vertices') for neighbour in interior_neighbours: if graph.nodes()[neighbour]['label'] != 'E': raise ValueError( 'interior vertices can be connect only with E vertices' ) all_I_neighbours.append(neighbour) E_vertices = get_vertices_from_layer(graph, layer, "E") E_vertices_position_prev_layer = [] if any(E_vertice not in all_I_neighbours for E_vertice in E_vertices): raise ValueError('wrongly connected E vertices') for E_vertice in E_vertices: E_vertice_neighbours = get_neighbors_at(graph, E_vertice, layer) if len([ I_node for I_node in E_vertice_neighbours if graph.nodes()[I_node]['label'] == "I" ]) not in [1, 2]: raise ValueError( 'each E vertice must be connected with I vertice') E_vertice_E_neighbours = [ neighbour for neighbour in E_vertice_neighbours if graph.nodes()[neighbour]['label'] == "E" ] if len(E_vertice_E_neighbours) not in [1, 2, 3]: raise ValueError( 'each E vertice must be connected with at least one E vertice' ) corresponding_vertice = get_node_at( graph, layer - 1, graph.nodes()[E_vertice]['position']) if corresponding_vertice is not None: E_vertices_position_prev_layer.append(corresponding_vertice) if len(E_vertices_position_prev_layer) != 4 and len( E_vertices_position_prev_layer) != 6: raise ValueError( 'positions of corresponding vertices between layers are incorrect' ) corresponding_positions = [ graph.nodes()[E_vertice]['position'] for E_vertice in E_vertices_position_prev_layer ] noncorresponding_E_vertices = [ E_vertice for E_vertice in E_vertices if graph.nodes()[E_vertice] ['position'] not in corresponding_positions ] possible_positions = [] for i in range(len(corresponding_positions) - 1): x1, y1 = corresponding_positions[i] for j in range(i + 1, len(corresponding_positions)): x2, y2 = corresponding_positions[j] possible_positions.append(((x1 + x2) / 2, (y1 + y2) / 2)) for E_vertice in noncorresponding_E_vertices: x, y = graph.nodes()[E_vertice]['position'] if (x, y) not in possible_positions: raise ValueError( 'position of noncorresponding vertice is incorrect') overlapping_vertices = find_overlapping_vertices(graph) if len(overlapping_vertices) != 4 or \ any(overlapping_vertice1 not in set(all_I_neighbours) or overlapping_vertice2 not in set(all_I_neighbours) for overlapping_vertice1, overlapping_vertice2 in overlapping_vertices): raise ValueError('incorrect shape of graph') vertices_to_join = set() for overlapping_vertice1, overlapping_vertice2 in overlapping_vertices: vertices_to_join.add(overlapping_vertice1) vertices_to_join.add(overlapping_vertice2) if len(vertices_to_join) != 4: raise ValueError('too many overlapping vertices') vertices_to_join_group1 = [ vertice for vertice in vertices_to_join if graph.nodes()[vertice]['position'] == graph.nodes()[list( vertices_to_join)[0]]['position'] ] vertices_to_join_group2 = [ vertice for vertice in vertices_to_join if vertice not in vertices_to_join_group1 ] if len(vertices_to_join_group1) != 2 or len( vertices_to_join_group2) != 2: raise ValueError('too many overlapping vertices') vertice1_neighbours = get_neighbors_at(graph, vertices_to_join_group1[0], layer) vertice2_neighbours = get_neighbors_at(graph, vertices_to_join_group1[1], layer) vertice3_neighbours = get_neighbors_at(graph, vertices_to_join_group2[0], layer) vertice4_neighbours = get_neighbors_at(graph, vertices_to_join_group2[1], layer) I_neighbours_vertice1 = [ neighbour for neighbour in vertice1_neighbours if graph.nodes()[neighbour]['label'] == "I" ] I_neighbours_vertice2 = [ neighbour for neighbour in vertice2_neighbours if graph.nodes()[neighbour]['label'] == "I" ] I_neighbours_vertice3 = [ neighbour for neighbour in vertice3_neighbours if graph.nodes()[neighbour]['label'] == "I" ] I_neighbours_vertice4 = [ neighbour for neighbour in vertice4_neighbours if graph.nodes()[neighbour]['label'] == "I" ] if len(I_neighbours_vertice1) != 1 or len(I_neighbours_vertice2) != 1 or \ len(I_neighbours_vertice3) != 1 or len(I_neighbours_vertice4) != 1: raise ValueError( 'vertices to join wrongly connected with I vertices') common_I_neighbour_vertices_to_join = [] if I_neighbours_vertice1 == I_neighbours_vertice3: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[0]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[0]) elif I_neighbours_vertice1 == I_neighbours_vertice4: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[0]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[1]) elif I_neighbours_vertice2 == I_neighbours_vertice3: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[1]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[0]) elif I_neighbours_vertice2 == I_neighbours_vertice4: common_I_neighbour_vertices_to_join.append( vertices_to_join_group1[1]) common_I_neighbour_vertices_to_join.append( vertices_to_join_group2[1]) else: raise ValueError( 'vertices to join wrongly connected with I vertices') noncommon_I_neighbour_vertices_to_join = [ vertice for vertice in vertices_to_join if vertice not in common_I_neighbour_vertices_to_join ] if len(noncommon_I_neighbour_vertices_to_join) != 2: raise ValueError( 'vertices to join wrongly connected with I vertices') if len( set(common_I_neighbour_vertices_to_join).intersection( set(noncommon_I_neighbour_vertices_to_join))) != 0: raise ValueError('vertices to join wrongly connected') common_vertice1_neighbours = get_neighbors_at( graph, common_I_neighbour_vertices_to_join[0], layer) common_vertice2_neighbours = get_neighbors_at( graph, common_I_neighbour_vertices_to_join[1], layer) if common_I_neighbour_vertices_to_join[ 1] not in common_vertice1_neighbours: raise ValueError( 'vertices to join with common I neighbour are not connected') if len( set(common_vertice1_neighbours).intersection( set(common_vertice2_neighbours))) not in [1, 2]: raise ValueError( 'vertices to join with common I neighbour are wrongly connected' ) noncommon_vertice1_neighbours = get_neighbors_at( graph, noncommon_I_neighbour_vertices_to_join[0], layer) noncommon_vertice2_neighbours = get_neighbors_at( graph, noncommon_I_neighbour_vertices_to_join[1], layer) if noncommon_I_neighbour_vertices_to_join[ 1] in noncommon_vertice1_neighbours: raise ValueError( 'vertices to join with non-common I neighbour are connected') if len( set(noncommon_vertice1_neighbours).intersection( set(noncommon_vertice2_neighbours))) not in [1, 2]: raise ValueError( 'vertices to join with common I neighbour are wrongly connected' )
def __check_prod_input(graph, prod_input): if len(set(prod_input)) != 4: raise ValueError('too few interiors') layer = graph.nodes()[prod_input[0]]['layer'] if any(graph.nodes()[interior]['layer'] != layer for interior in prod_input[1:]): raise ValueError('interior vertices come from different layers') if any(graph.nodes()[interior]['label'] != 'I' for interior in prod_input): raise ValueError('interior vertices must have I label') all_I_neighbours = [] for interior in prod_input: interior_neighbours = get_neighbors_at(graph, interior, layer) if len(interior_neighbours) not in [2, 3]: raise ValueError('wrongly connected interior vertices') for neighbour in interior_neighbours: if graph.nodes()[neighbour]['label'] != 'E': raise ValueError( 'interior vertices can be connect only with E vertices' ) all_I_neighbours.append(neighbour) E_vertices = get_vertices_from_layer(graph, layer, 'E') E_vertices_position_prev_layer = [] if any(E_vertice not in all_I_neighbours for E_vertice in E_vertices): raise ValueError('wrongly connected E vertices') for E_vertice in E_vertices: E_vertice_neighbours = get_neighbors_at(graph, E_vertice, layer) if len([ I_node for I_node in E_vertice_neighbours if graph.nodes()[I_node]['label'] == "I" ]) != 2: raise ValueError( 'each E vertice must be connected with two I vertices') E_vertice_E_neighbours = [ neighbour for neighbour in E_vertice_neighbours if graph.nodes()[neighbour]['label'] == "E" ] if len(E_vertice_E_neighbours) not in [1, 2, 3, 4]: print(len(E_vertice_E_neighbours)) raise ValueError( 'each E vertice must be connected with at least one E vertice' ) corresponding_vertice = get_node_at( graph, layer - 1, graph.nodes()[E_vertice]['position']) if corresponding_vertice is not None: E_vertices_position_prev_layer.append(corresponding_vertice) if len(E_vertices_position_prev_layer) != 2 and len( E_vertices_position_prev_layer) != 4: raise ValueError( 'positions of corresponding vertices between layers are incorrect' ) corresponding_positions = [ graph.nodes()[E_vertice]['position'] for E_vertice in E_vertices_position_prev_layer ] noncorresponding_E_vertices = [ E_vertice for E_vertice in E_vertices if graph.nodes()[E_vertice] ['position'] not in corresponding_positions ] possible_positions = [] for i in range(len(corresponding_positions) - 1): x1, y1 = corresponding_positions[i] for j in range(i + 1, len(corresponding_positions)): x2, y2 = corresponding_positions[j] possible_positions.append(((x1 + x2) / 2, (y1 + y2) / 2)) for E_vertice in noncorresponding_E_vertices: x, y = graph.nodes()[E_vertice]['position'] if (x, y) not in possible_positions: raise ValueError( 'positions of noncorresponding vertices are incorrect') overlapping_vertices = find_overlapping_vertices(graph) if len(overlapping_vertices) != 2 or \ any(overlapping_vertice1 not in set(all_I_neighbours) or overlapping_vertice2 not in set(all_I_neighbours) for overlapping_vertice1, overlapping_vertice2 in overlapping_vertices): raise ValueError('incorrect shape of graph') vertices_to_join = [ neighbour for neighbour in set(all_I_neighbours) if graph.nodes()[neighbour]['position'] == graph.nodes()[ overlapping_vertices[0][0]]['position'] ] if len(vertices_to_join) != 2: raise ValueError('too many overlapping vertices') vertice1_neighbours = get_neighbors_at(graph, vertices_to_join[0], layer) vertice2_neighbours = get_neighbors_at(graph, vertices_to_join[1], layer) common_neighbours = set(vertice1_neighbours).intersection( set(vertice2_neighbours)) if len(common_neighbours) != 2: raise ValueError('vertices to join wrongly connected') I_neighbours_vertice1 = [ neighbour for neighbour in vertice1_neighbours if graph.nodes()[neighbour]['label'] == "I" ] I_neighbours_vertice2 = [ neighbour for neighbour in vertice2_neighbours if graph.nodes()[neighbour]['label'] == "I" ] if len(I_neighbours_vertice1) != 2 or len(I_neighbours_vertice2) != 2: raise ValueError( 'vertices to join wrongly connected with I vertices') if len(set(I_neighbours_vertice1).intersection( I_neighbours_vertice2)) != 0: raise ValueError('vertices to join have common I neighbour')
def __check_prod_input(graph, prod_input): assert len(prod_input) == 4 upper_layer = graph.nodes()[prod_input[0]]['layer'] lower_layer = graph.nodes()[prod_input[2]]['layer'] assert all(graph.nodes()[i]['layer'] == upper_layer for i in prod_input[:2]) assert all(graph.nodes()[i]['layer'] == lower_layer for i in prod_input[2:]) # upper layer means lower index assert upper_layer + 1 == lower_layer assert all(graph.nodes()[i]['label'] == 'i' for i in prod_input[:2]) assert all(graph.nodes()[i]['label'] == 'I' for i in prod_input[2:]) upper_i1, upper_i2 = prod_input[:2] upper_neighbors = get_common_neighbors(graph, upper_i1, upper_i2, upper_layer) assert len(upper_neighbors) == 2 upper_v1, upper_v2 = upper_neighbors pos_upper_v1, pos_upper_v2 = [ graph.nodes()[v]['position'] for v in upper_neighbors ] assert graph.has_edge(upper_v1, upper_v2) neighbors_in_lower_layer = {upper_i1: set(), upper_i2: set()} for upper_interior in upper_i1, upper_i2: for bottom_neighbor in get_neighbors_at(graph, upper_interior, lower_layer): neighbors_in_lower_layer[upper_interior].add(bottom_neighbor) if prod_input[2] in neighbors_in_lower_layer[upper_i1]: assert prod_input[2] in neighbors_in_lower_layer[upper_i1] \ and prod_input[3] in neighbors_in_lower_layer[upper_i2] lower_i1, lower_i2 = prod_input[2:] else: assert prod_input[3] in neighbors_in_lower_layer[upper_i1] \ and prod_input[2] in neighbors_in_lower_layer[upper_i2] lower_i2, lower_i1 = prod_input[2:] lower_connected_neighbors = get_common_neighbors( graph, lower_i1, lower_i2, lower_layer) assert len(lower_connected_neighbors) == 1 lower_connected_neighbor = lower_connected_neighbors[0] lower_i1_neighbors = get_neighbors_at(graph, lower_i1, lower_layer) lower_i1_neighbors.remove(lower_connected_neighbor) lower_i2_neighbors = get_neighbors_at(graph, lower_i2, lower_layer) lower_i2_neighbors.remove(lower_connected_neighbor) to_merge = [ (v1, v2) for v1, v2 in itertools.product(lower_i1_neighbors, lower_i2_neighbors) if graph.nodes()[v1]['position'] == graph.nodes()[v2]['position'] ] assert len(to_merge) == 1 to_merge = to_merge[0] pos_lower_connected_neighbor, pos_lower_to_merge = [ graph.nodes()[v]['position'] for v in [lower_connected_neighbor, to_merge[0]] ] if pos_lower_connected_neighbor == pos_upper_v1: assert pos_lower_connected_neighbor == pos_upper_v1 \ and pos_lower_to_merge == pos_upper_v2 else: assert pos_lower_to_merge == pos_upper_v1 \ and pos_lower_connected_neighbor == pos_upper_v2 all_vertices = upper_neighbors + lower_connected_neighbors + lower_i1_neighbors + lower_i2_neighbors for e in all_vertices: assert graph.nodes[e]['label'] == 'E' return to_merge
def test_happy_path(self): graph = Graph() e1_1, e2_1, e3_1, e4_1 = [gen_name() for _ in range(4)] graph.add_node(e1_1, layer=1, position=(0.0, 0.0), label='E') graph.add_node(e2_1, layer=1, position=(1.0, 0.0), label='E') graph.add_node(e3_1, layer=1, position=(0.5, 0.5), label='E') graph.add_node(e4_1, layer=1, position=(0.0, 1.0), label='E') graph.add_edge(e1_1, e2_1) graph.add_edge(e1_1, e3_1) graph.add_edge(e1_1, e4_1) graph.add_edge(e2_1, e3_1) graph.add_edge(e3_1, e4_1) i1_1 = add_interior(graph, e1_1, e2_1, e3_1) i2_1 = add_interior(graph, e1_1, e3_1, e4_1) graph.nodes[i1_1]['label'] = 'i' graph.nodes[i2_1]['label'] = 'i' e1_2, e2_2, e3_2, e4_2, e5_2 = [gen_name() for _ in range(5)] graph.add_node(e1_2, layer=2, position=(0.0, 0.0), label='E') graph.add_node(e5_2, layer=2, position=(0.0, 0.0), label='E') graph.add_node(e2_2, layer=2, position=(1.0, 0.0), label='E') graph.add_node(e3_2, layer=2, position=(0.5, 0.5), label='E') graph.add_node(e4_2, layer=2, position=(0.0, 1.0), label='E') graph.add_edge(e1_2, e2_2) graph.add_edge(e1_2, e3_2) graph.add_edge(e5_2, e4_2) graph.add_edge(e5_2, e3_2) graph.add_edge(e2_2, e3_2) graph.add_edge(e3_2, e4_2) i1_2 = add_interior(graph, e1_2, e2_2, e3_2) i2_2 = add_interior(graph, e5_2, e3_2, e4_2) graph.add_edge(i1_1, i1_2) graph.add_edge(i2_1, i2_2) if visualize_tests: visualize_graph_3d(graph) pyplot.show() P13().apply(graph, [i1_1, i2_1, i1_2, i2_2]) # based on test_p12 # if correct number of nodes and edges self.assertEqual(len(graph.nodes()), 12) self.assertEqual(len(graph.edges()), 24) # if interiors has correct labels, layers and are connected self.assertEqual(graph.nodes[i1_1]['label'], 'i') self.assertEqual(graph.nodes[i2_1]['label'], 'i') self.assertEqual(graph.nodes[i1_1]['layer'], 1) self.assertEqual(graph.nodes[i2_1]['layer'], 1) self.assertEqual(graph.nodes[i1_2]['label'], 'I') self.assertEqual(graph.nodes[i2_2]['label'], 'I') self.assertEqual(graph.nodes[i1_2]['layer'], 2) self.assertEqual(graph.nodes[i2_2]['layer'], 2) self.assertTrue(graph.has_edge(i1_1, i1_2)) self.assertTrue(graph.has_edge(i2_1, i2_2)) # if each interior has 3 neighbors on the corresponding layer i1_1_neighbors = get_neighbors_at(graph, i1_1, graph.nodes[i1_1]['layer']) self.assertEqual(len(i1_1_neighbors), 3) i2_1_neighbors = get_neighbors_at(graph, i2_1, graph.nodes[i2_1]['layer']) self.assertEqual(len(i2_1_neighbors), 3) i1_2_neighbors = get_neighbors_at(graph, i1_2, graph.nodes[i1_2]['layer']) self.assertEqual(len(i1_2_neighbors), 3) i2_2_neighbors = get_neighbors_at(graph, i2_2, graph.nodes[i2_2]['layer']) self.assertEqual(len(i2_2_neighbors), 3) # if nodes in lower layer exists and are correctly connected new_e1_2 = get_node_at(graph, 2, (0.0, 0.0)) new_e2_2 = get_node_at(graph, 2, (1.0, 0.0)) new_e3_2 = get_node_at(graph, 2, (0.5, 0.5)) new_e4_2 = get_node_at(graph, 2, (0.0, 1.0)) self.assertIsNotNone(new_e1_2) self.assertIsNotNone(new_e2_2) self.assertIsNotNone(new_e3_2) self.assertIsNotNone(new_e4_2) self.assertTrue(graph.has_edge(new_e1_2, new_e2_2)) self.assertTrue(graph.has_edge(new_e1_2, new_e3_2)) self.assertTrue(graph.has_edge(new_e1_2, new_e4_2)) self.assertTrue(graph.has_edge(new_e2_2, new_e3_2)) self.assertTrue(graph.has_edge(new_e3_2, new_e4_2)) # if lower interiors connect with all 4 vertices all_neighbors = i1_2_neighbors + i2_2_neighbors all_neighbors = list(dict.fromkeys(all_neighbors)) # remove duplicates self.assertEqual(len(all_neighbors), 4) # if each vertex has correct label for n in all_neighbors: self.assertEqual(graph.nodes[n]['label'], 'E') # if each vertex has correct number of neighbors (based on neighbour interiors count) for n in all_neighbors: node_neighbors = get_neighbors_at(graph, n, graph.nodes[n]['layer']) i_neighbors = [ x for x in node_neighbors if graph.nodes[x]['label'] == 'I' ] if len(i_neighbors) == 1: self.assertEqual(len(node_neighbors), 3) elif len(i_neighbors) == 2: self.assertEqual(len(node_neighbors), 5) else: self.assertEqual(len(node_neighbors), 7) if visualize_tests: visualize_graph_3d(graph) pyplot.show()