def setUp(self): super(TestObjectiveFunctionsExtended, self).setUp() self.partitions = [] # alternate with selfloop self.graph = nx.Graph() self.number_of_nodes = 10 for i in range(self.number_of_nodes): self.graph.add_edge(i, (i + 1) % self.number_of_nodes) # beside complete circle add one edge to connect all blocks self.graph.add_edge(0, 2) # include one self loop self.graph.add_edge(0, 0) self.partition = sbm.NxPartition(graph=self.graph, number_of_blocks=3, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self._fixed_starting_point() self.partitions.append(self.partition) # generate some random graphs with increasing chance for i in range(8): graph = nx.gnp_random_graph(10, i * .1 + .1) partition = sbm.NxPartition(graph=graph, number_of_blocks=3, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self.partitions.append(partition)
def setUp(self): self.graphs = [ nx.Graph(), nx.Graph(), nx.Graph(), nx.Graph(), nx.Graph() ] nx.add_path(self.graphs[0], [0, 0, 1, 2, 3]) nx.add_path(self.graphs[1], [0, 1, 2, 3, 0]) nx.add_path(self.graphs[2], [0, 1, 2, 3, 0, 0]) nx.add_path(self.graphs[4], [0, 1, 2, 3, 0, 4]) self.graphs[3] = self.graphs[2].copy() self.graphs[3].add_edge(2, 2) self.partitions = [] for graph in self.graphs: partition = sbm.NxPartition(graph=graph, number_of_blocks=2) self.partitions.append(partition) partition.set_from_representation( {node: node % partition.B for node in graph}) # information about graphs below self.likelihood = ModelLikelihoodOfFlatMicrocanonicalDegreeCorrectedSbm( )
def create_parameters_for_model_selection_function( self, graph, partition_representation): """ Creates from the given information the parameters for the model selection function :param graph: graph which nodes are clustered :param partition_representation: dictionary containing the clustering of the nodes, with the nodes as key and the communities labeled starting from 0 :type graph: nx.Graph :type partition_representation dict :return: """ parameters = {"is_degree_corrected": self.is_degree_corrected} if self.function_needs_partition: parameters["partition"] = sbm.NxPartition( graph, representation=partition_representation) if self.function_needs_partition_representation: parameters["partition_representation"] = partition_representation if self.function_needs_number_of_nodes: parameters["number_of_nodes"] = len(graph.nodes()) if self.function_needs_number_of_edges: parameters["number_of_edges"] = len(graph.edges()) if self.function_needs_is_directed: parameters["is_directed"] = graph.is_directed() if self.additional_fixed_key_arguments is not None: parameters.update(**self.additional_fixed_key_arguments) return parameters
def test_cleanup_block_merges(self): """Test cleaning merges""" # prepare a bigger graph (10 nodes) self.graph.add_edges_from([(5, 6), (7, 8), (8, 9)]) self.partition = sbm.NxPartition(graph=self.graph, number_of_blocks=2, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self.inference = sbm.PeixotoInference(self.graph, self.objective_function, self.partition) # minimum move on (delta, block_1, block_2) merges_with_delta = [(0, 8, 4), (0, 1, 2), (0, 1, 0), (0, 5, 6), (0, 2, 4)] result, new_block_number = self.inference._cleanup_merges( merges_with_delta) # no loop therefore decrease by length self.assertEqual(new_block_number, 5) # test if all higher blocks are shifted for i in range(new_block_number, 10): self.assertTrue(i in result) self.assertLess(result[i], new_block_number) # Check merges for block in [1, 2, 4, 8]: self.assertEqual(result[block], 0) self.assertEqual(result[5], result[6]) # next try with some loops merges_with_delta = [(0, 8, 4), (0, 1, 2), (0, 1, 8), (0, 4, 2), (0, 3, 6), (0, 6, 3)] result, new_block_number = self.inference._cleanup_merges( merges_with_delta) self.assertEqual(new_block_number, 6) # test if all higher blocks are shifted for i in range(new_block_number, 10): self.assertTrue(i in result) self.assertLess(result[i], new_block_number) # Check merges for block in [2, 4, 8]: self.assertEqual(result[block], 1) self.assertEqual(result[6], 3) # test right updating of observed merges_with_delta = [(0, 2, 1), (0, 3, 0), (0, 2, 3), (0, 5, 4), (0, 6, 7), (0, 5, 6)] result, new_block_number = self.inference._cleanup_merges( merges_with_delta) self.assertEqual(new_block_number, 4) # test if all higher blocks are shifted for i in range(new_block_number, 10): self.assertTrue(i in result) self.assertLess(result[i], new_block_number)
def setUp(self): # basically we only set up the test with different graphs and # after that the same tests as before apply super(TestObjectiveFunctionsDirected, self).setUp() self.partitions = [] self.graph = nx.DiGraph() self.number_of_nodes = 10 for i in range(self.number_of_nodes): self.graph.add_edge(i, (i + 1) % self.number_of_nodes) # beside complete circle add one edge to connect all blocks self.graph.add_edge(0, 2) # here first without selfloops and undirected self.partition = sbm.NxPartition(graph=self.graph, number_of_blocks=4, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self._fixed_starting_point() self.partitions.append(self.partition) # with selfloop self.graph = self.graph.copy() self.graph.add_edge(0, 0) self.partition = sbm.NxPartition(graph=self.graph, number_of_blocks=3, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self._fixed_starting_point() self.partitions.append(self.partition) for i in range(1, 10): # attention creates MultiDigraph graph = nx.scale_free_graph(i * 10 + 1) # at the moment algorithms can only handle DiGraphs therefore cast partition = sbm.NxPartition(graph=nx.DiGraph(graph), number_of_blocks=rd.randint(2, 9), calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self.partitions.append(partition) for objective_function in self.objective_functions: objective_function.is_directed = True
def test_base_class(self): """Test correct mapping of functions and switch on is_directed""" objective_function = sbm.ObjectiveFunction( self.partition.is_graph_directed(), lambda x: "complete undirected", lambda x: "complete directed", lambda *args: "delta undirected", lambda *args: "delta directed") if self.partition.is_graph_directed(): self.assertEqual(objective_function.calculate(self.partition), "complete directed") self.assertEqual( objective_function.calculate_delta(self.partition, 0, 1), "delta directed") else: self.assertEqual(objective_function.calculate(self.partition), "complete undirected") self.assertEqual( objective_function.calculate_delta(self.partition, 0, 1), "delta undirected") objective_function.is_directed = True digraph = nx.DiGraph() digraph.add_edge(0, 1) directed_partition = sbm.NxPartition(digraph, number_of_blocks=1) self.assertEqual(objective_function.calculate(directed_partition), "complete directed") self.assertEqual( objective_function.calculate_delta(directed_partition, 0, 1), "delta directed") objective_function.is_directed = False graph = nx.Graph() graph.add_edge(0, 1) undirected_partition = sbm.NxPartition(graph, number_of_blocks=1) self.assertEqual(objective_function.calculate(undirected_partition), "complete undirected") self.assertEqual( objective_function.calculate_delta(undirected_partition, 0, 1), "delta undirected")
def test_infer_stochastic_block_model(self): # dummy objective function objective_function = sbm.DegreeCorrectedUnnormalizedLogLikelyhood( is_directed=False) graph = nx.DiGraph() graph.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3), (4, 5), (4, 6), (4, 7), (5, 6), (5, 7), (6, 7), (0, 4)]) graph[0][1]['weight'] = 20 representation = {0: 0, 1: 0, 2: 0, 3: 0, 4: 1, 5: 1, 6: 1, 7: 1} partition = sbm.NxPartition(graph, 2, True, True, False, False, False, representation) x = sbm.SpectralInference(graph, objective_function, partition) a = x.infer_stochastic_block_model()
def setUp(self): self.graph = nx.DiGraph(nx.karate_club_graph()) self.partition = sbm.NxPartition(graph=self.graph, number_of_blocks=2, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self.objective_function = sbm.TraditionalUnnormalizedLogLikelyhood( is_directed=True) # set up -> worse enough random partition # optimum by around -240 start at least below -260 while self.objective_function.calculate(self.partition) > -260: self.partition.random_partition(number_of_blocks=2)
def setUp(self): self.graph = nx.Graph() self.number_of_nodes = 10 for i in range(self.number_of_nodes): self.graph.add_edge(i, (i + 1) % self.number_of_nodes) # beside complete circle add one edge to connect all blocks self.graph.add_edge(0, 2) # here first without selfloops and undirected self.partition = sbm.NxPartition(graph=self.graph, number_of_blocks=3, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self._fixed_starting_point() self.objective_functions = [] self.objective_functions.append( sbm.TraditionalUnnormalizedLogLikelyhood(is_directed=False)) self.objective_functions.append( sbm.DegreeCorrectedUnnormalizedLogLikelyhood(is_directed=False)) self.objective_functions.append( sbm.TraditionalMicrocanonicalEntropy(is_directed=False)) self.objective_functions.append( sbm.TraditionalMicrocanonicalEntropyDense(is_directed=False)) self.objective_functions.append( sbm.DegreeCorrectedMicrocanonicalEntropy(is_directed=False)) self.objective_functions.append( sbm.IntegratedCompleteLikelihoodExactJeffrey(is_directed=False)) self.objective_functions.append( sbm.IntegratedCompleteLikelihoodExactUniform(is_directed=False)) self.objective_functions.append( sbm.NewmanReinertDegreeCorrected(is_directed=False)) self.objective_functions.append( sbm.NewmanReinertDegreeCorrected(is_directed=False)) self.objective_functions.append( sbm.NewmanReinertNonDegreeCorrected(is_directed=False)) self.objective_functions.append( sbm.LogLikelihoodOfFlatMicrocanonicalNonDegreeCorrected( is_directed=False)) self.objective_functions.append( sbm.LogLikelihoodOfFlatMicrocanonicalDegreeCorrectedUniform( is_directed=False)) self.objective_functions.append( sbm. LogLikelihoodOfFlatMicrocanonicalDegreeCorrectedUniformHyperprior( is_directed=False))
def setUp(self): # first check probabilities of new block self.graph = nx.Graph() # create graph # 0 - 1 # | \ | /\ 4 # 3 - 2 self.graph.add_edges_from([(0, 1), (1, 2), (2, 3), (0, 2), (1, 4), (2, 4)]) self.partition = sbm.NxPartition(graph=self.graph, number_of_blocks=2, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True) self.objective_function = sbm.TraditionalUnnormalizedLogLikelyhood( is_directed=False) self.inference = sbm.PeixotoInference(self.graph, self.objective_function, self.partition) self.inference.epsilon = 0.0
def test_empty_to_group(self): objective_function = self.objective_functions[0] graph = nx.complete_graph(5) if objective_function.is_directed: graph = nx.DiGraph(graph) partition = sbm.NxPartition(graph, representation={ 0: 2, 1: 1, 2: 0, 3: 0, 4: 0 }) partition.move_node(1, 0) precalc_info = partition.precalc_move((0, 2, 1), objective_function) for objective_function in self.objective_functions: objective_function.calculate_delta(partition, 2, 1, *precalc_info) # first find generator = test_ground.PlantedPartitionGenerator( 4, 32, 0.9696969696969697, 0.0) graph, _, _ = generator.generate(directed=False, seed=0) if objective_function.is_directed: graph = nx.DiGraph(graph) partition = sbm.NxPartition(graph, representation={ 0: 2, 1: 2, 2: 2, 3: 2, 4: 2, 5: 2, 6: 2, 7: 2, 8: 2, 9: 2, 10: 2, 11: 2, 12: 2, 13: 2, 14: 2, 15: 2, 16: 2, 17: 2, 18: 2, 19: 2, 20: 2, 21: 2, 22: 2, 23: 2, 24: 2, 25: 2, 26: 2, 27: 2, 28: 2, 29: 2, 30: 2, 31: 2, 32: 3, 33: 3, 34: 3, 35: 3, 36: 3, 37: 3, 38: 3, 39: 3, 40: 3, 41: 3, 42: 3, 43: 3, 44: 3, 45: 3, 46: 3, 47: 3, 48: 3, 49: 3, 50: 3, 51: 3, 52: 3, 53: 3, 54: 3, 55: 3, 56: 3, 57: 3, 58: 3, 59: 3, 60: 3, 61: 3, 62: 3, 63: 3, 64: 2, 65: 2, 66: 2, 67: 2, 68: 2, 69: 2, 70: 2, 71: 2, 72: 2, 73: 2, 74: 2, 75: 2, 76: 2, 77: 2, 78: 2, 79: 2, 80: 2, 81: 2, 82: 2, 83: 2, 84: 2, 85: 2, 86: 2, 87: 2, 88: 2, 89: 2, 90: 2, 91: 2, 92: 2, 93: 2, 94: 2, 95: 2, 96: 0, 97: 0, 98: 0, 99: 0, 100: 0, 101: 0, 102: 0, 103: 0, 104: 0, 105: 0, 106: 0, 107: 0, 108: 0, 109: 0, 110: 0, 111: 0, 112: 0, 113: 0, 114: 0, 115: 0, 116: 0, 117: 0, 118: 0, 119: 0, 120: 0, 121: 0, 122: 0, 123: 0, 124: 0, 125: 0, 126: 0, 127: 0 }) precalc_info = partition.precalc_move((0, 2, 1), objective_function) for objective_function in self.objective_functions: objective_function.calculate_delta(partition, 2, 1, *precalc_info)
def test_inference(self): graph = nx.Graph() graph.add_edges_from([(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 10), (0, 11), (0, 12), (0, 13), (0, 17), (0, 19), (0, 21), (0, 31), (1, 2), (1, 3), (1, 7), (1, 13), (1, 17), (1, 19), (1, 21), (1, 30), (2, 3), (2, 7), (2, 8), (2, 9), (2, 13), (2, 27), (2, 28), (2, 32), (3, 7), (3, 12), (3, 13), (4, 6), (4, 10), (5, 6), (5, 10), (5, 16), (6, 16), (8, 30), (8, 32), (8, 33), (9, 33), (13, 33), (14, 32), (14, 33), (15, 32), (15, 33), (18, 32), (18, 33), (19, 33), (20, 32), (20, 33), (22, 32), (22, 33), (23, 25), (23, 27), (23, 29), (23, 32), (23, 33), (24, 25), (24, 27), (24, 31), (25, 31), (26, 29), (26, 33), (27, 33), (28, 31), (28, 33), (29, 32), (29, 33), (30, 32), (30, 33), (31, 32), (31, 33), (32, 33)]) partition = sbm.NxPartition(graph, representation={ 0: 1, 1: 1, 2: 1, 3: 1, 4: 0, 5: 0, 6: 1, 7: 0, 8: 0, 9: 0, 10: 1, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 1, 17: 0, 18: 0, 19: 0, 20: 0, 21: 0, 22: 0, 23: 1, 24: 1, 25: 0, 26: 1, 27: 0, 28: 0, 29: 0, 30: 1, 31: 1, 32: 1, 33: 1 }) objective_function = sbm.DegreeCorrectedUnnormalizedLogLikelyhood( is_directed=False) inference = sbm.KerninghanLinInference(graph, objective_function, partition) inference.infer_stochastic_block_model()
def setUp(self): # unconnected example graph = nx.Graph() # create graph(s) # 0 - 1 # 2 - 3 - 4 # 6 - 5 -7 # 8 - 9 # | | # 10 - 11 # 12 - 13 (selfloop to 13) # 14 - 15 (selfloop) - 16 - 17 (selfloop) - 18 # ensure that each node can be moved, i.e. in every block are at least 2 nodes graph.add_edges_from([(0, 1), (2, 3), (3, 4), (5, 6), (5, 7), (8, 9), (9, 10), (10, 11), (11, 8), (12, 13), (13, 13), (14, 15), (15, 15), (15, 16), (16, 17), (17, 17), (17, 18)]) self.partition = sbm.NxPartition(graph=graph, number_of_blocks=2, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True, weighted_graph=False) # set defined block state for node in range(self.partition.get_number_of_nodes()): self.partition.move_node(node, node % 2) self.objective_function = ObjectiveFunctionDummy(is_directed=False) self.inference = sbm.MetropolisHastingInference( graph, self.objective_function, self.partition) # same with 3 blocks partition_3 = sbm.NxPartition(graph=graph, number_of_blocks=3, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True, weighted_graph=False) # set defined block state for node in range(self.partition.get_number_of_nodes()): partition_3.move_node(node, node % 3) inference_3 = sbm.MetropolisHastingInference(graph, self.objective_function, partition_3) # create directed graph with the same examples like before, # i.e. always insert both possible edges digraph = nx.DiGraph(graph) # add directed cycle # 19 -> 20 -> 21 # | <- - - - | digraph.add_edges_from([(19, 20), (20, 21), (21, 19)]) self.dipartition = sbm.NxPartition(graph=digraph, number_of_blocks=2, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True, weighted_graph=False) # set defined block state for node in range(self.dipartition.get_number_of_nodes()): self.dipartition.move_node(node, node % 2) self.di_inference = sbm.MetropolisHastingInference( digraph, self.objective_function, self.dipartition) dipartition_3 = sbm.NxPartition(graph=digraph, number_of_blocks=3, calculate_degree_of_blocks=True, save_neighbor_edges=True, save_neighbor_of_blocks=True, weighted_graph=False) # set defined block state for node in range(self.dipartition.get_number_of_nodes()): dipartition_3.move_node(node, node % 3) di_inference_3 = sbm.MetropolisHastingInference( digraph, self.objective_function, dipartition_3) self.test_cases = [ (self.partition, self.inference), (partition_3, inference_3), (self.dipartition, self.di_inference), (dipartition_3, di_inference_3), ]