def test_status(self): # For different graphs # G0: 0 -- 1 -- 2 -- 3 # \ / # 4 -- 5 -- 6 # # G1: 10 -- 12 -- 13 # \ / # 14 -- 11 -- 15 -- 16 # # G2: 21 -- 23 -- 25 -- 20 -- 26 -- 22 # \ / # 24 # # G3: 30 -- 32 -- 34 -- 35 -- 36 # \ / # 31 -- 33 G0 = create_graph_helper(edges=[[0, 1], [1, 2], [2, 3], [3, 4], [2, 4], [4, 5], [5, 6]]) G1 = create_graph_helper(edges=[[10, 12], [12, 13], [12, 14], [13, 14], [11, 14], [11, 15], [15, 16]]) G2 = create_graph_helper(edges=[[21, 23], [23, 25], [20, 25], [20, 24], [24, 25], [20, 26], [22, 26]]) G3 = create_graph_helper(edges=[[30, 32], [32, 34], [34, 35], [35, 36], [31, 35], [31, 36], [31, 33]]) coloring13 = create_coloring_helper(G1.vertices + G3.vertices, {0: [10, 33], 1: [16, 30], 2: [11, 34], 3: [13, 36], 4: [15, 32], 5: [12, 31], 6: [14, 35]}) coloring02 = create_coloring_helper(G0.vertices + G2.vertices, {0: [0, 6, 21, 22], 1: [1, 5, 23, 26], 2: [3, 24], 3: [2, 4, 20, 25]}) coloring01 = create_coloring_helper(G0.vertices + G1.vertices, {0: [0, 6], 1: [1, 5], 2: [2, 4], 3: [3], 4: [10], 5: [11], 6: [12], 7: [13], 8: [14], 9: [15], 10: [16]}) unbalanced_coloring = create_coloring_helper(G0.vertices + G1.vertices, {0: [0, 1], 1: [10, 11]}) self.assertEqual("Bijection", coloring13.status(G1, G3)) self.assertEqual(None, coloring02.status(G1, G3)) self.assertEqual("Unbalanced", coloring01.status(G1, G3)) self.assertEqual("Unbalanced", unbalanced_coloring.status(G0, G1)) # Automorphism G0copy = G0.deepcopy() coloring0 = create_coloring_helper(G0.vertices, {0: [0, 6], 1: [1, 5], 2: [2, 4], 3: [3]}) coloring0.add([G0copy.vertices[0], G0copy.vertices[6]], 0) coloring0.add([G0copy.vertices[1], G0copy.vertices[5]], 1) coloring0.add([G0copy.vertices[2], G0copy.vertices[4]], 2) coloring0.set(G0copy.vertices[3], 3) self.assertEqual(None, coloring0.status(G0, G0copy))
def test_initialize_and_unit_coloring(self): # empty graph g = Graph(False) init_coloring = initialize_coloring(g) self.assertEqual(0, len(init_coloring)) # 1 - 2 - 3 g = tools.create_graph_helper([(1, 2), (2, 3)]) v_g1, v_g2, v_g3 = g.vertices init_coloring = initialize_coloring(g) self.assertEqual(2, len(init_coloring)) self.assertListEqual([v_g1, v_g3], list(init_coloring.get(1))) self.assertListEqual([v_g2], list(init_coloring.get(2))) # 1 - 2 - 3 # | # 4 - 6 - 7 # | # 5 g = tools.create_graph_helper([(1, 2), (2, 3), (2, 4), (4, 5), (4, 6), (6, 7)]) v_g1, v_g2, v_g3, v_g4, v_g5, v_g6, v_g7 = g.vertices init_coloring = initialize_coloring(g) self.assertEqual(3, len(init_coloring)) self.assertListEqual([v_g1, v_g3, v_g5, v_g7], list(init_coloring.get(1))) self.assertListEqual([v_g6], list(init_coloring.get(2))) self.assertListEqual([v_g2, v_g4], list(init_coloring.get(3))) # 1 - 2 - 3 # | # 4 - 6 - 7 # | # 5 8 v_g8 = Vertex(g) g.add_vertex(v_g8) init_coloring = initialize_coloring(g) self.assertEqual(4, len(init_coloring)) self.assertListEqual([v_g8], list(init_coloring.get(0))) self.assertListEqual([v_g1, v_g3, v_g5, v_g7], list(init_coloring.get(1))) self.assertListEqual([v_g6], list(init_coloring.get(2))) self.assertListEqual([v_g2, v_g4], list(init_coloring.get(3)))
def test_moeilijkere_graaf(self): # Dit assert nu niks, maar deze method is wel een begin g = create_graph_helper( [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (5, 7), (5, 8), (3, 8), (3, 9), (1, 9), (2, 9), (1, 10), (6, 11), (7, 11), (11, 12), (11, 13), (11, 14), (12, 13), (12, 14), (13, 14)]) h = g.deepcopy() md = graph_to_modules(g + h) graph_md, modular_iso = modules_to_graph_with_module_isomorphism(md)
def test_has_same_color_neighbours(self): # 1 - 2 - 3 - 4 # | # 5 g = tools.create_graph_helper([[1, 2], [2, 3], [3, 4], [3, 5]]) v_g1, v_g2, v_g3, v_g4, v_g5 = g.vertices coloring = tests.create_coloring_helper_vertex({ 0: [v_g1], 1: [v_g4, v_g5], 2: [v_g2], 3: [v_g3] }) self.assertTrue(has_same_color_neighbours(v_g4, v_g5, coloring)) self.assertFalse(has_same_color_neighbours(v_g1, v_g4, coloring))
def test_modules_to_graph(self): tests.set_up_test_graphs() modules = graph_to_modules(tests.non_trivial_graph) graph, _ = modules_to_graph(modules) labels = [vertex.label for vertex in graph.vertices] expected_labels = ["0", "1", "2+4", "3"] self.assertTrue(set(labels) == set(expected_labels)) modules = graph_to_modules(tests.modular_decomposition_graph) graph, _ = modules_to_graph(modules) labels = [vertex.label for vertex in graph.vertices] expected_labels = ["0+1+4", "2+3", "5+6"] self.assertTrue(set(labels) == set(expected_labels)) modules = graph_to_modules(tests.butterfly) graph, _ = modules_to_graph(modules) labels = [vertex.label for vertex in graph.vertices] expected_labels = ["0", "1+4", "2+3"] self.assertTrue(set(labels) == set(expected_labels)) modules2 = graph_to_modules(graph) graph2, _ = modules_to_graph(modules2) labels = [vertex.label for vertex in graph2.vertices] expected_labels = ["0", "1+4+2+3"] self.assertTrue(set(labels) == set(expected_labels)) modules3 = graph_to_modules(graph2) graph3, _ = modules_to_graph(modules3) labels = [vertex.label for vertex in graph3.vertices] expected_labels = ["0+1+4+2+3"] self.assertTrue(set(labels) == set(expected_labels)) modules4 = graph_to_modules(graph3) graph4, _ = modules_to_graph(modules4) labels = [vertex.label for vertex in graph4.vertices] expected_labels = ["0+1+4+2+3"] self.assertTrue(set(labels) == set(expected_labels)) g = tools.create_graph_helper([[1, 2], [1, 3], [2, 3]]) modules_triangle = graph_to_modules(g) graph, _ = modules_to_graph(modules_triangle) labels = [vertex.label for vertex in graph.vertices] expected_labels = ["1+2+3"] self.assertTrue(set(labels) == set(expected_labels))
def modules_to_graph( modules: ModularDecomposition) -> (Graph, { Vertex: Vertex }): """ Returns a new Graph object with Modules compressed to a Vertex :param modules: list of modules :return: new Graph """ label_mapping = {} edges_list = [] for module in modules: for vertex in module: edges_list += get_edges_of_vertex(vertex) for module in modules: if len(module) > 1: new_label = create_new_label(module) for vertex in module: label_mapping[vertex] = new_label edges_list = relabel_edges(module, edges_list, new_label) edges = set() for edge in edges_list: if edge[0] != edge[1]: edges.add(tuple(sorted(edge))) if not edges: graph = Graph(False) if edges_list: vertex = Vertex(graph, edges_list[0][0]) graph.add_vertex(vertex) else: graph = create_graph_helper(sorted(list(edges))) old_new_vertex_mapping = {} for vertex, label in label_mapping.items(): old_new_vertex_mapping[vertex] = graph.find_vertex(label) return graph, old_new_vertex_mapping
def test_group_by(self): # group_by(List[int]) groups by number a = [1, 2, 3, 2, 3] expected = {1: [1], 2: [2, 2], 3: [3, 3]} self.assertEqual(expected, group_by(a)) # group_by(List[Vertex], key=Vertex.degree) # 0 -- 1 -- 2 # 7 -- 4 # / \ # 6 - 5 # \ / # 3 g = tools.create_graph_helper([(0, 1), (1, 2), (4, 7), (3, 5), (3, 6), (5, 7), (6, 7), (5, 6)]) vertices = sorted(g.vertices, key=lambda vertex: vertex.label) expected = { 1: [vertices[0], vertices[2], vertices[4]], 2: [vertices[1], vertices[3]], 3: [vertices[5], vertices[6], vertices[7]] } actual = group_by(g.vertices, lambda v: v.degree) self.assertEqual(expected.keys(), actual.keys()) for key in expected.keys(): self.assertTrue( compare(expected[key], actual[key], lambda v: v.label)) # group_by(dict{List}, key = lambda x: len(x)) groups by length of the lists degrees = { 1: [vertices[0], vertices[2], vertices[4]], 2: [vertices[1], vertices[3]], 3: [vertices[5], vertices[6], vertices[7]] } expected = {2: [2], 3: [1, 3]} self.assertEqual(expected, group_by(degrees, lambda k: len(degrees[k]))) # group by amount of neighbours with a given color # [x]: node with color/degree 1 # [0] -- 1 -- [2] # 7 -- [4] # / \ # 6 - 5 # \ / # 3 degree_coloring = group_by(g.vertices, lambda v: v.degree) for c in degree_coloring: for v in degree_coloring[c]: v.colornum = c n_neighbors_of_color1 = group_by( vertices, lambda v: len([w for w in v.neighbours if w.colornum == 1])) expected = { 0: [ vertices[0], vertices[2], vertices[3], vertices[4], vertices[5], vertices[6] ], 1: [vertices[7]], 2: [vertices[1]] } self.assertEqual(expected.keys(), n_neighbors_of_color1.keys()) for key in expected.keys(): self.assertEqual( len(expected[key]), len(n_neighbors_of_color1[key]), "Expect key " + str(key) + ' to have ' + str(len(expected[key])) + ' vertices') self.assertTrue( compare(expected[key], n_neighbors_of_color1[key], lambda v: v.label))
def set_up_test_graphs(): global empty_graph, connected_graph_order_2, disconnected_graph_order_2, non_trivial_graph, \ non_trivial_graph_different_label, non_trivial_graph_different_weight, non_trivial_graph_complement, \ isomorphic_graphs, anisomorphic_graphs, v4e4_connected, v5e4loop_unconnected, v5e7, v3e2_connected, \ v5e4_connected, v8e7loop_unconnected, modular_decomposition_graph, butterfly, v8e7loop_unconnected2 # Prepare some vertex labels for general use vertex_labels = ['spam', 'ham', 'eggs', 'foo', 'bar', 'baz', 'qux', 'quux', 'quuz', 'corge', 'grault', 'garply', 'waldo', 'fred', 'plugh', 'xyzzy', 'thud'] # Instantiate the empty graph empty_graph = Graph(directed=False) # Instantiate a connected graph of order 2 # connected_graph_order_2 = # spam - ham connected_graph_order_2 = create_graph_helper([(vertex_labels[0], vertex_labels[1])]) # Instantiate a non-trivial graph # non_trivial_graph = # 2 # / \ # 0 - 1 3 # \ / # 4 non_trivial_graph = create_graph_helper([(0, 1), (1, 2), (1, 4), (2, 3), (3, 4)]) non_trivial_graph.name = 'non_trivial_graph' # Instantiate the non-trivial graph's complement # non_trivial_graph_complement = # 2 # / \ # 1 - 3 - 0 - 4 non_trivial_graph_complement = create_graph_helper([(2, 0), (3, 0), (4, 0), (3, 1), (4, 2)]) non_trivial_graph_complement.name = 'non_trivial_graph_complement' # Instantiate some isomorphic graphs # iso_0 = # - 0 - # / \ # 3 - 4 - 1 - 5 # \ / # - 2 - # iso_1 = # - 2 - # / \ # 3 - 4 - 0 - 5 # \ / # - 1 - # iso_2 = # - 1 - # / \ # 3 - 4 - 2 - 5 # \ / # - 0 - changing_labels = [0, 1, 2] isomorphic_graphs = [] for _ in range(len(changing_labels)): # Because changing_labels changes, this can't simply be changing_labels _0 = changing_labels[0] _1 = changing_labels[1] _2 = changing_labels[2] isomorphism = create_graph_helper([(3, 4), (4, _0), (_0, 5), (4, _1), (_1, 5), (4, _2), (_2, 5)]) isomorphism.name = f'isomorphism_{_0}_{_1}_{_2}' isomorphic_graphs.append(isomorphism) changing_labels = [changing_labels.pop()] + changing_labels # Instantiate some anisomorphic graphs # anisomorphism_0 = # - 4 - # / | \ # 3 - 0 1 2 # \ | / # - 5 - # anisomorphism_1 = # - 4 - # / | \ # 3 - 0 - 1 2 # \ / # - 5 - anisomorphism_0 = create_graph_helper([(3, 0), (0, 4), (4, 1), (4, 2), (0, 5), (1, 5), (2, 5)]) anisomorphism_0.name = 'anisomorphism_0' anisomorphism_1 = create_graph_helper([(3, 0), (0, 4), (4, 1), (4, 2), (0, 5), (1, 0), (2, 5)]) anisomorphism_1.name = 'anisomorphism_1' anisomorphic_graphs = [anisomorphism_0, anisomorphism_1] # Create a graph with 4 vertices and 4 edges with a cycle: # v4e4_connected = # 1 - 2 - 3 # \ / # 4 v4e4_connected = create_graph_helper([(1, 2), (2, 3), (2, 4), (3, 4)]) v4e4_connected.name = 'v4e4' # Create a graph with 5 vertices and 4 edges, including looped egde at vertex 4: # v5e4loop_unconnected = # 1 - 2 - 3 4= # | # 5 v5e4loop_unconnected = create_graph_helper([(1, 2), (2, 3), (3, 5), (4, 4)]) v5e4loop_unconnected.name = 'v5e4_loop4' # Create a graph with 8 vertices and 7 edges, unconnected: # # v8e7_unconnected = # 1 - 2 - 3 5 - 6 8= # | \ / # 4 7 v8e7loop_unconnected = create_graph_helper([(1, 2), (2, 3), (3, 4), (5, 6), (6, 7), (5, 7), (8, 8)]) v8e7loop_unconnected.name = 'v8e7loop_unconnected' # Create a graph with 8 vertices and 7 edges, unconnected: # # v8e7_unconnected2 = # 1 - 2 - 3 5 - 6 8= # | \ / # 4 7 v8e7loop_unconnected2 = create_graph_helper([(1, 2), (2, 3), (3, 4), (5, 6), (6, 7), (5, 7), (8, 8)]) v8e7loop_unconnected2.name = 'v8e7loop_unconnected2' # Create a graph where the complement should be taken during preprocessing : # v5e7 = # 5 -- # / \ \ # 1 - 2 - 3 | # \ / / # 4 -- v5e7 = create_graph_helper([(0, 3), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]) v5e7.name = 'v5e7' # Create a graph with 3 vertices and 2 edges : # v3e2_connected = # 1 - 2 - 3 v3e2_connected = create_graph_helper([(1, 2), (2, 3)]) v3e2_connected.name = 'v3e2_connected' # Create a tree graph with 5 vertices and 4 edges : # v5e4_connected = # 1 - 2 - 3 - 4 # | # 5 v5e4_connected = create_graph_helper([(1, 2), (2, 3), (3, 5), (3, 4)]) v5e4_connected.name = 'v5e4_connected' # Instantiate a graph with three modules modular_decomposition_graph = create_graph_helper( [(6, 1), (6, 0), (6, 4), (5, 1), (5, 0), (5, 4), (2, 1), (2, 0), (2, 4), (3, 1), (3, 0), (3, 4), (2, 3)] ) # Instantiate a recursively modular decomposable graph butterfly = create_graph_helper([(0, 1), (0, 2), (0, 3), (0, 4), (1, 4), (2, 3)])