def test_fitness(self): """Test fitness computation.""" family_size = 126 n_days = 11 df_families = get_df_families(n_days, family_size) df_families.iloc[0]['n_people'] += 1 families = np.array([i for i in range(1, n_days + 1)]) days = {i: family_size for i in range(n_days)} days[0] += 1 expected_fitness = 50 * 2 + 100 + 200 * 2 + 300 * 2 + 400 + 500 * 2 expected_fitness += (9 * 3 + 18 * 2 + 36 * 4 + 199 + 398) * family_size expected_fitness += 1 / 400. * family_size ** (1 / 2.) * (n_days - 1) expected_fitness += 2 / 400. * (family_size + 1) ** (1 / 2. + 1 / 50.) antibody = Antibody(families=families, days=days) antibody.fitness(df_families) self.assertAlmostEqual( antibody.fitness_value, expected_fitness, places=7, msg=f'Fitness of antibody is `{antibody.fitness_value}`, expected ' f'`{expected_fitness}`.' )
def test_generate_solution(self): """Test random solution generating.""" expected_min_day_size = 125 expected_max_day_size = 300 real_data_path = 'data/family_data.csv' dfs = [get_df_families(1000, 20)] if os.path.isfile(real_data_path): dfs.append(pd.read_csv(real_data_path)) for df_families in dfs: antibody = Antibody() antibody.generate_solution(df_families) day_sizes = {} for i, day in enumerate(antibody.families): value = day_sizes.get(day, 0) day_sizes[day] = value + df_families.iloc[i]['n_people'] for key, size in antibody.days.items(): expected_day_size = day_sizes[key] self.assertTrue( expected_min_day_size <= size <= expected_max_day_size, msg=f'Number of people scheduled for `{key + 1}th` day is ' f'`{size}`, expected to be ' f'in `<{expected_min_day_size}, ' f'{expected_max_day_size}>`.' ) self.assertEqual( size, expected_day_size, msg=f'Number of people scheduled for `{key + 1}th` day is ' f'{size}, expected `{expected_day_size}`.' )
def test_basic_mutate_solutions(self): """ Test whether created `Antibody` was mutated by `BasicMutator` class. """ fitness_value = 125 n_mutations = 5 n_performed_mutations = 0 n_families, family_size = 1000, 20 df_families = get_df_families(n_families, family_size) antibody = Antibody() antibody.generate_solution(df_families) antibody.fitness_value = fitness_value basic_mutator = BasicMutator() mutated_antibody = basic_mutator.mutate([[copy.deepcopy(antibody)]], df_families=df_families)[0][0] for i in range(n_families): if antibody.families[i] != mutated_antibody.families[i]: n_performed_mutations += 1 self.assertEqual( n_mutations, n_performed_mutations, msg=f'Number of mutations was `{n_performed_mutations}`, expected ' f'`{n_mutations}`.')
def test_basic_clone_solutions(self): """ Test number of clones created by clone method of `BasicClonator` class. """ antibodies = [] # Pairs of antibody fitness and expected number of clones fitness_clones_pair = [[128, 7], [64, 8], [256, 1], [127, 7], [254, 1]] for fitness, _ in fitness_clones_pair: antibody = Antibody() antibody.fitness_value = fitness antibodies.append(antibody) basic_clonator = BasicClonator() clones_lists = basic_clonator.clone(antibodies) self.assertEqual( len(clones_lists), len(fitness_clones_pair), msg=f'Number of lists of clones is `{len(clones_lists)}`, ' f'expected `{len(fitness_clones_pair)}`.') for ((_, n_clones), clones) in zip(fitness_clones_pair, clones_lists): self.assertEqual( len(clones), n_clones, msg=f'Number of created clones is `{len(clones)}`, ' f'expected `{n_clones}`.')
def test_preference_mutate_solutions(self): """ Test whether created `Antibody` was mutated by `PreferenceMutator` and `AdvancedPreferenceMutator` classes. """ fitness_value = 125 n_mutations = 5 n_performed_mutations, n_advanced_performed_mutations = 0, 0 n_families, family_size = 1000, 20 df_families = get_df_families(n_families, family_size) antibody = Antibody() antibody.generate_solution(df_families) antibody.fitness_value = fitness_value preference_mutator = PreferenceMutator() mutated_antibody = preference_mutator.mutate( [[copy.deepcopy(antibody)]], df_families=df_families)[0][0] advanced_preference_mutator = AdvancedPreferenceMutator() advanced_mutated_antibody = advanced_preference_mutator.mutate( [[copy.deepcopy(antibody)]], df_families=df_families)[0][0] families_choices = df_families[[f'choice_{i}' for i in range(10)]] \ .values for i in range(n_families): if antibody.families[i] != mutated_antibody.families[i]: n_performed_mutations += 1 self.assertTrue( mutated_antibody.families[i] in families_choices[i], msg=f'Day mutated family is going to workshop is ' f'{mutated_antibody.families[i]}, expected one of ' f'{families_choices[i]}.') if antibody.families[i] != advanced_mutated_antibody.families[i]: n_advanced_performed_mutations += 1 self.assertTrue( advanced_mutated_antibody.families[i] in families_choices[i], msg=f'Day advanced mutated family is going to workshop is ' f'{advanced_mutated_antibody.families[i]}, expected ' f'one of {families_choices[i]}.') self.assertEqual( n_mutations, n_performed_mutations, msg=f'Number of mutations was `{n_performed_mutations}`, expected ' f'`{n_mutations}`.') self.assertEqual(n_mutations, n_advanced_performed_mutations, msg=f'Number of advanced mutations was ' f'`{n_advanced_performed_mutations}`, expected ' f'`{n_mutations}`.')
def test_affinity(self): """Test affinity computation.""" population = ( Antibody(families=np.array([10, 20, 13, 15])), Antibody(families=np.array([10, 22, 13, 15])), Antibody(families=np.array([11, 20, 14, 1])), ) expected_affinities = [4, 3, 1] ArtificialImmuneSystem.affinity(population) affinities = [a.affinity_value for a in population] self.assertEqual( affinities, expected_affinities, msg=f'Affinities values are `{affinities}`, expected ' f'`{expected_affinities}`.' )
def test_percentile_affinity_select_solutions(self): """ Test whether selected `Antibody` objects were selected according to `PercentileAffinitySelector` rules. """ antibodies = [] affinities = [15, 20, 25, 30, 35, 40, 45, 50, 55, 60] negative_filtered_affinities = [[15, 20, 25, 30, 35], [15, 20, 25], [15, 20], [15]] positive_filtered_affinities = [[40, 45, 50, 55, 60], [50, 55, 60], [55, 60], [60]] for affinity in affinities: antibody = Antibody() antibody.affinity_value = affinity antibodies.append(antibody) negative_percentile_selector = PercentileAffinitySelector( affinity_threshold=50, select_type='negative') filtered_antibodies = copy.deepcopy(antibodies) for affinities_list in negative_filtered_affinities: filtered_antibodies = negative_percentile_selector.select( filtered_antibodies) for i, antibody in enumerate(filtered_antibodies): self.assertEqual(antibody.affinity_value, affinities_list[i], msg=f'Antibody had affinity value ' f'`{antibody.affinity_value}`, expected ' f'`{affinities_list[i]}`.') positive_percentile_selector = PercentileAffinitySelector( affinity_threshold=50, select_type='positive') filtered_antibodies = copy.deepcopy(antibodies) for affinities_list in positive_filtered_affinities: filtered_antibodies = positive_percentile_selector.select( filtered_antibodies) for i, antibody in enumerate(filtered_antibodies): self.assertEqual(antibody.affinity_value, affinities_list[i], msg=f'Antibody had affinity value ' f'`{antibody.affinity_value}`, expected ' f'`{affinities_list[i]}`.')
def test_affinity(self): """Test affinity computation.""" combinations = ( (np.array([10, 20, 13, 15]), np.array([10, 20, 13, 15]), 4), (np.array([10, 20, 13, 15]), np.array([11, 20, 14, 1]), 1), (np.array([10, 22, 13, 15]), np.array([11, 20, 14, 1]), 0) ) for families1, families2, expected_affinity in combinations: a1 = Antibody(families=families1) a2 = Antibody(families=families2) affinity = a1.affinity(a2) self.assertEqual( affinity, expected_affinity, msg=f'Affinity value between families `{families1}` and ' f'`{families2}` is `{a1.affinity_value}`, expected ' f'`{expected_affinity}`.' )
def test_select_best(self): """ Test selecting of best antibodies from population and clones. """ ais = ArtificialImmuneSystem( df_families=None, clonator=None, mutator=None, selector=None, population_size=0, n_generations=0 ) population_fitness = [25, 15, 5, 38] clones_fitness = [[20, 20], [16, 16], [20, 15], [10, 40]] min_fitnesses = [20, 15, 5, 10] population, clones = [], [] for fitness in population_fitness: antibody = Antibody() antibody.fitness_value = fitness population.append(antibody) for list_of_fitnesses in clones_fitness: clones_list = [] for fitness in list_of_fitnesses: antibody = Antibody() antibody.fitness_value = fitness clones_list.append(antibody) clones.append(clones_list) new_population = ais.select_best(population, clones) for antibody, expected_fitness in zip(new_population, min_fitnesses): self.assertEqual( antibody.fitness_value, expected_fitness, msg=f'Fitness of antibody is `{antibody.fitness_value}`, ' f'expected `{expected_fitness}`.' )
def test_basic_select_solutions(self): """ Test whether selected `Antibody` objects were selected according to `BasicSelector` rules. """ antibodies = [] affinity_threshold = 30 affinities = [15, 20, 25, 30, 35, 40, 45, 50, 55, 60] negative_filtered_affinities = [15, 20, 25, 30] positive_filtered_affinities = [30, 35, 40, 45, 50, 55, 60] for affinity in affinities: antibody = Antibody() antibody.affinity_value = affinity antibodies.append(antibody) negative_basic_selector = BasicSelector( affinity_threshold=affinity_threshold, select_type='negative') selected_antibodies = negative_basic_selector.select(antibodies) for antibody in selected_antibodies: self.assertTrue( antibody.affinity_value in negative_filtered_affinities, msg=f'Antibody had affinity value ' f'`{antibody.affinity_value}`, expected value smaller or ' f'equal to `{affinity_threshold}`.') positive_basic_selector = BasicSelector( affinity_threshold=affinity_threshold, select_type='positive') selected_antibodies = positive_basic_selector.select(antibodies) for antibody in selected_antibodies: self.assertTrue( antibody.affinity_value in positive_filtered_affinities, msg=f'Antibody had affinity value ' f'`{antibody.affinity_value}`, expected value greater or ' f'equal to `{affinity_threshold}`.')
def test_fitness(self): """Test fitness computation.""" n_families, family_size = 3, 125 df_families = get_df_families(n_families, family_size) days = {i: family_size for i in range(n_families)} population = ( Antibody(families=np.array([1, 2, 3]), days=days), Antibody(families=np.array([3, 3, 3]), days=days), Antibody(families=np.array([1, 1, 2]), days=days), ) fitnesses = ( 50 * 2 + 9 * family_size, (50 + 9 * family_size) * n_families, 50 ) expected_fitness_min = np.min(fitnesses) expected_fitness_avg = np.mean(fitnesses) ais = ArtificialImmuneSystem( df_families=df_families, clonator=None, mutator=None, selector=None, population_size=0, n_generations=0, n_cpu=7 ) _, best_antibody, fitness_avg = ais.fitness(population) fitness_min = best_antibody.fitness_value self.assertAlmostEqual( fitness_min, expected_fitness_min, places=7, msg=f'Minimum fitness is `{fitness_min}`, expected ' f'`{expected_fitness_min}`.' ) self.assertAlmostEqual( fitness_avg, expected_fitness_avg, places=7, msg=f'Average fitness is `{fitness_avg}`, expected ' f'`{expected_fitness_avg}`.' )
def fitness(self, population): """ Compute fitness of each antibody in `population`. :param population: list, list of `Antibody` objects. :return: list, list of antibodies with calculated fitness values. Antibody, antibody with minimum fitness value. float, average fitness value. """ sum_fitness = 0 best_antibody = Antibody() best_antibody.fitness_value = 999999999999 with multiprocessing.Pool(self.n_cpu) as pool: fn = partial(self._fitness, df_families=self.df_families) population = pool.map(fn, population) for antibody in population: sum_fitness += antibody.fitness_value if antibody.fitness_value < best_antibody.fitness_value: best_antibody = antibody return population, best_antibody, sum_fitness / len(population)
def test_lower_than(self): """Test less than comparison between two antibodies.""" fitnesses = ((0, 1), (5, 10)) for f1, f2 in fitnesses: a1 = Antibody() a1.fitness_value = f1 a2 = Antibody() a2.fitness_value = f2 self.assertLess( a1, a2, msg=f'Antibody `{a1}` should be less than `{a2}`.' )
def test_equal(self): """Test equal comparison between two antibodies.""" fitnesses = (0, 5, 10) for fitness in fitnesses: a1 = Antibody() a1.fitness_value = fitness a2 = Antibody() a2.fitness_value = fitness self.assertEqual( a1, a2, msg=f'Antibody `{a1}` should equal to `{a2}`.' )
def generate_population(self, n=None): """ Generate random population of antibodies of size `self.population_size`. :param n: int (default: None), size of population to be generated. If `None` then population of size `self.population_size` will be generated. :return: list, list of `Antibody` object. """ n = self.population_size if n is None else n population = [] with multiprocessing.Pool(self.n_cpu) as pool: for _ in range(n): pool.apply_async( Antibody().generate_solution, args=[self.df_families], callback=lambda x: population.append(x) ) pool.close() pool.join() return population