def test_partial_membership(self): """ Test that having one group with less than full membership will result in the correct network. """ membership_perc = .25 group_to_membership = [membership_perc] expected_edges = int( (1 / 2) * ((membership_perc * self.N)**2 - membership_perc * self.N)) net = make_affiliation_network(group_to_membership, self.N, self.rng) self.assertEqual(net.N, self.N, f'Expected {self.N} nodes, got {net.N} nodes') actual_edges = len(tuple(net.G.edges)) leeway = expected_edges // 100 # Expected result can be 1% off in either direction self.assertTrue( expected_edges - leeway <= actual_edges <= expected_edges + leeway, f'Expected about {expected_edges} +/- {leeway} edges, ' f'got {actual_edges} edges') expected_components = self.N - int(membership_perc * self.N) + 1 self.assertEqual(expected_components, nx.number_connected_components(net.G))
def test_no_groups(self): """ Test that having no groups will create a disconnected network """ group_to_membership = [] net = make_affiliation_network(group_to_membership, self.N, self.rng) edges = tuple(net.G.edges) self.assertEqual(net.N, self.N, f'Expected {self.N} nodes, got {net.N} nodes') self.assertTrue( len(edges) == 0, f'Expected no edges, got {len(edges)} edges')
def test_one_group(self): """ Test that 1 group with 100% membership will create a complete network """ group_to_membership = [1.0] expected_edges = set(it.combinations(range(self.N), 2)) net = make_affiliation_network(group_to_membership, self.N, self.rng) self.assertEqual(net.N, self.N, f'Expected {self.N} nodes, got {net.N} nodes') for edge in expected_edges: with self.subTest('Searching for edge', e=edge): self.assertTrue(net.G.has_edge(edge[0], edge[1]), f'Network does not contain {edge}')
def evolve_affiliation_network( N: int, target_edge_density: float, target_clustering_coefficient: float) -> Network: # constants n_trials = 25 n_groups = 25 pop_size = 20 n_steps = 15 # objects and such for optimization rng = np.random.default_rng(501) objective = AffiliationObjective(N, target_edge_density, target_clustering_coefficient, n_trials, rng) next_gen = NextGenGroupMemberships(rng, .01) optimizer = ga.GAOptimizer( objective, next_gen, new_membership_population(n_groups, pop_size, rng), False, 4) # optimization loop pbar = tqdm(range(n_steps)) global_best: Tuple[float, np.ndarray] = None # type: ignore costs = np.zeros(n_steps) diversities = np.zeros(n_steps) for step in pbar: cost_to_encoding = optimizer.step() local_best = min(cost_to_encoding, key=lambda x: x[0]) if global_best is None or local_best[0] < global_best[0]: global_best = local_best costs[step] = local_best[0] diversities[step] = lib.calc_float_pop_diversity(cost_to_encoding) pbar.set_description( f'Cost: {local_best[0]:.3f} Diversity: {diversities[step]:.3f}') # pbar.set_description(f'Cost: {local_best[0]:.3f}') print(f'Total cache hits: {optimizer.num_cache_hits}') # show cost and diversity over time print(global_best[1]) plt.title('Cost') plt.plot(costs) plt.show(block=False) plt.figure() plt.title('Diversity') plt.plot(diversities) plt.show() return make_affiliation_network(global_best[1], N, rng) # type: ignore
def run(self, group_to_membership_percentage: np.ndarray)\ -> Tuple[float, np.ndarray, np.ndarray]: edge_densities = np.zeros(self._n_trials) clustering_coeffs = np.zeros(self._n_trials) for trial in range(self._n_trials): net: Network = make_affiliation_network( group_to_membership_percentage, # type: ignore self._N, self._rng) edge_densities[trial] = net.E / self._max_E clustering_coeffs[trial] = nx.average_clustering(net.G) avg_edge_density = np.average(edge_densities) avg_cc = np.average(clustering_coeffs) return ((np.abs(avg_edge_density - self._target_edge_density) + np.abs(avg_cc - self._target_clustering_coefficient)), edge_densities, clustering_coeffs)