def __init__( self, population_size: int, generations: int, solution_size: int, crossover: Callable[[IndividualStructure[Tuple[int, ...], int]], MultipleIndividualOperatorProtocol[Tuple[int, ...]], ], selector: Selector, crossover_probability: float, mutation_probability: float, lower_bound: int, upper_bound: int, elite_size: int = 0, ): individual_structure = UniformIndividualStructure( tuple( IntGene(lower_bound=lower_bound, upper_bound=upper_bound) for _ in range(solution_size))) super().__init__( population_size, generations, individual_structure=individual_structure, elite_size=elite_size, ) self.add_operator_instance(crossover(individual_structure), crossover_probability) self.add_operator_instance(MutationOperator(individual_structure), mutation_probability) self.selector(selector)
def test_initialization_with_tuple(): gene_1 = CharGene() gene_2 = IntGene(lower_bound=1, upper_bound=1) individual = MixedIndividualStructure((gene_1, gene_2)) assert len(individual) == 2 built = individual.build() assert type(built[0]) == str assert type(built[1]) == int assert individual[0] == gene_1 assert individual[1] == gene_2
def test_one_point_crossover(crossover_point): individual_structure = UniformIndividualStructure( tuple(IntGene(lower_bound=0, upper_bound=10) for _ in range(10)) ) ind1 = individual_structure.build() ind2 = individual_structure.build() operator = OnePointCrossoverOperator(individual_structure) expect(operator).crossover_point.once().and_return(crossover_point) child = operator(ind1, [ind2]) assert child[0:crossover_point] == ind1[0:crossover_point] assert child[crossover_point:] == ind2[crossover_point:]
def default_evolutionary_algorithm( default_score_function) -> EvolutionaryAlgorithm: return EvolutionaryAlgorithm( population_size=10, generations=10, selector=Tournament(selection_size=2, tournament_size=10), ranker=Ranker(default_score_function), individual_structure=UniformIndividualStructure( tuple(IntGene(lower_bound=0, upper_bound=10) for _ in range(10))), multiple_individual_operators=[], single_individual_operators=[], )
def test_iteration_regenerates_right_sized_population(): eva = EvolutionaryAlgorithm( ranker=Ranker(lambda x: 1.0), selector=Random(selection_size=1), population_size=5, generations=1, individual_structure=UniformIndividualStructure( IntGene(lower_bound=0, upper_bound=1)), multiple_individual_operators=[], single_individual_operators=[], ) eva.run() assert len(eva._population) == 5
def test_mutation_generates_right_number_of_mutations(genes_to_mutate): individual_structure = UniformIndividualStructure( tuple(IntGene(lower_bound=0, upper_bound=5) for _ in range(5)) ) ind = individual_structure.build() for gene_definition in individual_structure: allow(gene_definition).generate.once().and_return(6) mutation_operator = MutationOperator( individual_structure, genes_to_mutate=genes_to_mutate ) mutated = mutation_operator(ind) assert ind != mutated assert sum(int(i == 6) for i in mutated) == min(genes_to_mutate, 5) assert sum(int(i == j) for i, j in zip(ind, mutated)) == 5 - min(genes_to_mutate, 5)
def test_iteration_calls_selector(): selector = Random(selection_size=1) eva = EvolutionaryAlgorithm( ranker=Ranker(lambda x: 1.0), selector=selector, population_size=1, generations=1, individual_structure=UniformIndividualStructure( IntGene(lower_bound=0, upper_bound=1)), multiple_individual_operators=[], single_individual_operators=[], ) expect(selector).__call__.once().and_return([(1, )]) eva.run() assert eva._population[0] == (1, )
def test_progressive_initialization(): gene_1 = CharGene() gene_2 = IntGene(lower_bound=1, upper_bound=1) individual = MixedIndividualStructure(gene_1) assert len(individual) == 1 built = individual.build() assert len(built) == 1 assert type(built[0]) == str individual_2 = individual.add_gene(gene_2) assert len(individual_2) == 2 assert individual_2[0] == gene_1 assert individual_2[1] == gene_2 built2 = individual_2.build() assert len(built2) == 2 assert type(built2[0]) == str assert type(built2[1]) == int
def find_mixed_individual(): individual_structure = (MixedIndividualStructure( FloatGene(lower_bound=0, upper_bound=1)).add_gene( FloatGene(lower_bound=0, upper_bound=1)).add_gene( IntGene(lower_bound=0, upper_bound=129)).add_gene( CharGene()).add_gene(CharGene())) eva = (EvolutionaryAlgorithmBuilder( population_size=200, generations=2000, elite_size=10, individual_structure=individual_structure, ).selector(Tournament(tournament_size=3, selection_size=50)).add_operator( MutationOperator, 0.01).add_operator(OnePointCrossoverOperator, 0.8).initialize(evaluation) ).add_callback(lambda e: print(e.fittest)) eva.run()
def test_iteration_calls_ranker(): ranker = Ranker(lambda x: 1.0) assert not ranker.ranked_population eva = EvolutionaryAlgorithm( ranker=ranker, selector=Random(selection_size=1), population_size=1, generations=1, individual_structure=UniformIndividualStructure( IntGene(lower_bound=0, upper_bound=1)), multiple_individual_operators=[], single_individual_operators=[], ) eva.run() assert len(eva._population) == len(ranker.ranked_population) assert set(eva._population) == set(r[0] for r in ranker.ranked_population)
def test_iteration_calls_multiple_individual_operator(): individual_structure = UniformIndividualStructure( IntGene(lower_bound=0, upper_bound=1)) crossover_operator = OnePointCrossoverOperator(individual_structure) eva = EvolutionaryAlgorithm( ranker=Ranker(lambda x: 1.0), selector=Random(selection_size=1), population_size=1, generations=1, individual_structure=individual_structure, multiple_individual_operators=[(crossover_operator, 1)], single_individual_operators=[], ) expect(crossover_operator).__call__.once().and_return((1, )) eva.run() assert eva._population[0] == (1, )
def test_iterations_calls_callback(): counter = 0 def callback(_: Evolution): nonlocal counter counter += 1 eva = EvolutionaryAlgorithm( ranker=Ranker(lambda x: 1.0), selector=Random(selection_size=1), population_size=1, generations=1, individual_structure=UniformIndividualStructure( IntGene(lower_bound=0, upper_bound=1)), multiple_individual_operators=[], single_individual_operators=[], iteration_callbacks=[callback], ) eva.run() assert counter == 1
def test_iteration_calls_multiple_instances_of_single_individual_operator(): individual_structure = UniformIndividualStructure( IntGene(lower_bound=0, upper_bound=1)) mutation_operator = MutationOperator(individual_structure) mutation_operator_2 = MutationOperator(individual_structure) eva = EvolutionaryAlgorithm( ranker=Ranker(lambda x: 1.0), selector=Random(selection_size=1), population_size=1, generations=1, individual_structure=individual_structure, multiple_individual_operators=[], single_individual_operators=[(mutation_operator, 1), (mutation_operator_2, 1)], ) expect(mutation_operator).__call__.once().and_return((1, )) expect(mutation_operator_2).__call__.once().with_args((1, )).and_return( (0, )) eva.run() assert eva._population[0] == (0, )
def test_iteration_preserves_elites(): ranker = Ranker(lambda x: 1.0) expect(ranker).rank.once() ranker.ranked_population = [((0, ), 3)] + [((1, ), 0)] * 4 selector = Random(selection_size=1) expect(selector).__call__.once().and_return([(1, )]) eva = EvolutionaryAlgorithm( ranker=ranker, selector=selector, population_size=5, generations=1, individual_structure=UniformIndividualStructure( IntGene(lower_bound=0, upper_bound=1)), multiple_individual_operators=[], single_individual_operators=[], elite_size=1, ) # invert order, to make sure that we're indeed selecting the elites. eva.set_initial_population(ranker.ranked_population[-1:]) eva.run() assert eva._population[0] == (0, ) assert len(eva._population) == 5
def tree_structure(nodes: int): return TreeIndividualStructure( tuple(IntGene(lower_bound=0, upper_bound=50) for _ in range(nodes)))