def fitness(self, net, proc, id_for_printing=-1): total_weights = net.num_edges() total_delays = net.num_edges() total_thresholds = net.num_nodes() dec = [8] * total_weights + [4] * total_delays + [7] * total_thresholds leap_decoder = BinaryToIntDecoder(*dec) problem = NetworkProblem(net, proc, self) genome_len = 8 * total_weights + 4 * total_delays + 7 * total_thresholds parents = Individual.create_population( 10, initialize=create_binary_sequence(genome_len), decoder=leap_decoder, problem=problem) parents = Individual.evaluate_population(parents) max_generation = 10 #stdout_probe = probe.FitnessStatsCSVProbe(context, stream=sys.stdout) generation_counter = util.inc_generation(context=context) while generation_counter.generation() < max_generation: offspring = pipe( parents, ops.tournament_selection, ops.clone, mutate_bitflip, ops.uniform_crossover, ops.evaluate, ops.pool(size=len(parents))) #, # accumulate offspring #stdout_probe) parents = offspring generation_counter() # increment to the next generation best = probe.best_of_gen(parents).decode() set_weights(best, net) return self.get_fitness_score(net, proc, id_for_printing)
def test_segmented_copy(): original = Individual([[0, 0], [1, 1]]) mutated = next(copy_segment(iter([original]), probability=1.0, append=True)) possible_outcomes = [ [[0, 0], [1, 1], [0, 0]], [[0, 0], [1, 1], [1, 1]], ] assert mutated.genome in possible_outcomes possible_outcomes = [ [[0, 0], [0, 0], [1, 1]], [[0, 0], [1, 1], [0, 0]], [[1, 1], [0, 0], [1, 1]], [[0, 0], [1, 1], [1, 1]], ] # TODO: it would be better to build a histogram of expected outcomes and # do the chi square test for i in range(20): original = Individual([[0, 0], [1, 1]]) mutated = next( copy_segment(iter([original]), probability=1.0, append=False)) assert mutated.genome in possible_outcomes
def collect_two_gene_mutation_counts(mutator, N: int): """Helper to collect the distribution of results when we apply mutation to two small individuals.""" # Set up arrays to collect the values of 4 different loci after mutation ind0_gene0_values = [] ind0_gene1_values = [] ind1_gene0_values = [] ind1_gene1_values = [] for _ in range(N): # Set up two parents with fixed genomes, two genes each ind1 = Individual(np.array([0, 0])) ind2 = Individual(np.array([1, 1])) population = iter([ind1, ind2]) # Mutate the parents result = mutator(population) result = list(result) # Pulse the iterator # Collect the values of each of the genes after mutation ind0_gene0_values.append(result[0].genome[0]) ind0_gene1_values.append(result[0].genome[1]) ind1_gene0_values.append(result[1].genome[0]) ind1_gene1_values.append(result[1].genome[1]) # Count the number of times that each gene value occurs at each locus ind0_gene0_counts = Counter(ind0_gene0_values) ind0_gene1_counts = Counter(ind0_gene1_values) ind1_gene0_counts = Counter(ind1_gene0_values) ind1_gene1_counts = Counter(ind1_gene1_values) return [ [ ind0_gene0_counts, ind0_gene1_counts ], [ ind1_gene0_counts, ind1_gene1_counts ] ]
def test_koza_maximization(): """ Tests the koza_parsimony() function for maximization problems """ problem = SpheroidProblem(maximize=True) pop = [] # We set up three individuals in ascending order of fitness of # [0, 1, 2] pop.append(Individual(np.array([0]), problem=problem)) pop.append(Individual(np.array([1]), problem=problem)) pop.append(Individual(np.array([0, 0, 1, 1]), problem=problem)) pop = Individual.evaluate_population(pop) # Now truncate down to the "best" that should be the third one best = ops.truncation_selection(pop, size=1) assert np.all(best[0].genome == [0, 0, 1, 1]) # This is just to look at the influence of the parsimony pressure on # the order of the individual. You should observe that the order is now # ([0,0,1,1], [0], [1]) because now their biased fitnesses are respectively # (-2, -1, 0) pop.sort(key=koza_parsimony(penalty=1)) # Ok, now we want to turn on parsimony pressure, which should knock the # really really really long genome out of the running for "best" best = ops.truncation_selection(pop, size=1, key=koza_parsimony(penalty=1)) assert np.all(best[0].genome == [1])
def test_n_ary_crossover_bad_crossover_points(): """ Test assertions for having more crossover points than genome length """ pop = [Individual(np.array([0, 0])), Individual(np.array([1, 1]))] i = ops.naive_cyclic_selection(pop) with pytest.raises(RuntimeError): new_pop = list( itertools.islice(ops.n_ary_crossover(i, num_points=3), 2))
def test_mutate_randint1(): """If you send me two individuals with two genes each and keep the default mutation rate, then on average, each gene has a probability of 0.5 of being mutated.""" N = 1000 # We'll sample 1,000 independent genomes # Set up arrays to collect the values of 4 different loci after mutation ind0_gene0_values = [] ind0_gene1_values = [] ind1_gene0_values = [] ind1_gene1_values = [] for _ in range(N): # Set up two parents with fixed genomes, two genes each ind1 = Individual([0, 0]) ind2 = Individual([1, 1]) population = iter([ind1, ind2]) # Mutate the parents result = ops.mutate_randint(population, bounds=[(0, 1), (0, 1)]) result = list(result) # Pulse the iterator # Collect the values of each of the genes after mutation ind0_gene0_values.append(result[0].genome[0]) ind0_gene1_values.append(result[0].genome[1]) ind1_gene0_values.append(result[1].genome[0]) ind1_gene1_values.append(result[1].genome[1]) # Count the number of times that each gene value occurs at each locus ind0_gene0_counts = Counter(ind0_gene0_values) ind0_gene1_counts = Counter(ind0_gene1_values) ind1_gene0_counts = Counter(ind1_gene0_values) ind1_gene1_counts = Counter(ind1_gene1_values) # Expected distribution of mutations. # We arrive at this by the following reasoning: each gene has a 1/L = 0.5 # chance of not being mutated, in which case it keeps it original value. # Otherwise, it's value is sampled uniformly from the set {0, 1}. expected_ind0_gene0 = {0: 0.5 * N + 0.25 * N, 1: 0.25 * N} expected_ind0_gene1 = expected_ind0_gene0 expected_ind1_gene0 = {0: 0.25 * N, 1: 0.5 * N + 0.25 * N} expected_ind1_gene1 = expected_ind1_gene0 # Use a chi2 test to see if the observed gene-value counts are # differ significantly from the expected distributions. p = 0.001 assert (stat.stochastic_equals(expected_ind0_gene0, ind0_gene0_counts, p=p)) assert (stat.stochastic_equals(expected_ind0_gene1, ind0_gene1_counts, p=p)) assert (stat.stochastic_equals(expected_ind1_gene0, ind1_gene0_counts, p=p)) assert (stat.stochastic_equals(expected_ind1_gene1, ind1_gene1_counts, p=p))
def test_mutate_binomial_err1(): """If we fail to provide either expected_num_mutations or a probability parameter, an exception should occur when the operator is used.""" mutator = intrep_ops.mutate_binomial(std=1, bounds=[(0, 1), (0, 1)]) ind1 = Individual(np.array([0, 0])) ind2 = Individual(np.array([1, 1])) population = iter([ind1, ind2]) result = mutator(population) with pytest.raises(ValueError): # Pulse the iterator so mutation gets executed result = list(result)
def test_tournament_selection(): """ This simple binary tournament_selection selection """ # Make a population where binary tournament_selection has an obvious reproducible choice pop = [ Individual([0, 0, 0], decoder=IdentityDecoder(), problem=MaxOnes()), Individual([1, 1, 1], decoder=IdentityDecoder(), problem=MaxOnes()) ] # We first need to evaluate all the individuals so that truncation selection has fitnesses to compare pop = Individual.evaluate_population(pop) best = next(ops.tournament_selection(pop)) pass
def spheroid_sample(): """A uniform sample of individuals on the spheroid function.""" DIMENSIONS = 10 N_SAMPLES = 50*DIMENSIONS problem = problems.SpheroidProblem() representation = Representation( initialize=initializers.create_real_vector(bounds=[(-5.12, 5.12)]*DIMENSIONS) ) initial_sample = representation.create_population(N_SAMPLES, problem) Individual.evaluate_population(initial_sample) return problem, representation, initial_sample
def test_n_ary_crossover_probability2(): """If we perform uniform crossover with a probabilty of 1.0, then we should see genes swapped by default with probability 0.2.""" N = 5000 observed_dist = { 'Unmodified': 0, 'Only left swapped': 0, 'Only right swapped': 0, 'Both swapped': 0 } # Run crossover N times on a fixed pair of two-gene individuals for i in range(N): pop = [Individual(np.array([0, 0])), Individual(np.array([1, 1]))] i = ops.naive_cyclic_selection(pop) new_pop = list( itertools.islice(ops.uniform_crossover(i, p_xover=1.0), 2)) # There are four possible outcomes, which we will count the occurence of if np.all(new_pop[0].genome == [0, 0]) and np.all( new_pop[1].genome == [1, 1]): observed_dist['Unmodified'] += 1 elif np.all(new_pop[0].genome == [1, 0]) and np.all( new_pop[1].genome == [0, 1]): observed_dist['Only left swapped'] += 1 elif np.all(new_pop[0].genome == [0, 1]) and np.all( new_pop[1].genome == [1, 0]): observed_dist['Only right swapped'] += 1 elif np.all(new_pop[0].genome == [1, 1]) and np.all( new_pop[1].genome == [0, 0]): observed_dist['Both swapped'] += 1 else: assert (False) assert (N == sum(observed_dist.values())) p = 0.01 p_swap = 0.2 # This is the count we expect to see of each combination # Each locus swaps with p_swap. expected_dist = { 'Unmodified': int((1 - p_swap) * (1 - p_swap) * N), 'Only left swapped': int(p_swap * (1 - p_swap) * N), 'Only right swapped': int((1 - p_swap) * p_swap * N), 'Both swapped': int(p_swap**2 * N) } # Use a χ-squared test to see if our experiment matches what we expect assert (stat.stochastic_equals(expected_dist, observed_dist, p=p))
def test_n_ary_crossover(): """If we crossover two individuals with two bits each, the children should either be swapped copies of their parents, or they should exchange the second bit and keep the first bit unmodified.""" pop = [Individual(np.array([0, 0])), Individual(np.array([1, 1]))] i = ops.naive_cyclic_selection(pop) new_pop = list(itertools.islice(ops.n_ary_crossover(i, num_points=1), 2)) # Given that there are only two genes, one [0,0] and the other [1,1] and a single crossover point, and that the # only two valid crossover points are 0 or 1, then there are two possible valid states for offspring with single # point crossover. assert np.all(pop[0].genome == [1, 1]) or np.all(pop[0].genome == [0, 1]) assert np.all(pop[1].genome == [0, 0]) or np.all(pop[1].genome == [1, 0])
def test_mutate_randint6(): """If we provide a value for both expected_num_mutations and the probability parameter, an exception should occur when the operator is used.""" mutator = intrep_ops.mutate_randint(bounds=[(0, 1), (0, 1)], expected_num_mutations=1, probability=0.1) ind1 = Individual(np.array([0, 0])) ind2 = Individual(np.array([1, 1])) population = iter([ind1, ind2]) result = mutator(population) with pytest.raises(ValueError): # Pulse the iterator so mutation gets executed result = list(result)
def test_simple_evaluate(): # Let's try evaluating a single individual pop = [Individual(np.array([1, 1]), problem=MaxOnes())] evaluated_individual = next(ops.evaluate(iter(pop))) assert evaluated_individual.fitness == 2
def test_simple_evaluate(): # Let's try evaluating a single individual pop = [Individual([1, 1], decoder=IdentityDecoder(), problem=MaxOnes())] evaluated_individual = next(ops.evaluate(iter(pop))) assert evaluated_individual.fitness == 2
def test_mutate_randint2(): """If we set the expected number of mutations to 2 when our genomes have only 2 genes, then each gene is always mutated, meaning individuals are completely resampled from a uniform distribution.""" N = 1000 # We'll sample 1,000 independent genomes # Set up arrays to collect the values of 4 different loci after mutation ind0_gene0_values = [] ind0_gene1_values = [] ind1_gene0_values = [] ind1_gene1_values = [] for _ in range(N): # Set up two parents with fixed genomes, two genes each ind1 = Individual([0, 0]) ind2 = Individual([1, 1]) population = iter([ind1, ind2]) # Mutate the parents result = ops.mutate_randint(population, bounds=[(0, 1), (0, 1)], expected_num_mutations=2) result = list(result) # Pulse the iterator # Collect the values of each of the genes after mutation ind0_gene0_values.append(result[0].genome[0]) ind0_gene1_values.append(result[0].genome[1]) ind1_gene0_values.append(result[1].genome[0]) ind1_gene1_values.append(result[1].genome[1]) # Count the number of times that each gene value occurs at each locus ind0_gene0_counts = Counter(ind0_gene0_values) ind0_gene1_counts = Counter(ind0_gene1_values) ind1_gene0_counts = Counter(ind1_gene0_values) ind1_gene1_counts = Counter(ind1_gene1_values) # Expected distribution of mutations. # We arrive at this by the following reasoning: since we only have # two genes, our mutation probability is 2/L = 1.0. So all four genes # should be sampled uniformly from the set {0, 1}. expected = {0: 0.5 * N, 1: 0.5 * N} p = 0.001 assert (stat.stochastic_equals(expected, ind0_gene0_counts, p=p)) assert (stat.stochastic_equals(expected, ind0_gene1_counts, p=p)) assert (stat.stochastic_equals(expected, ind1_gene0_counts, p=p)) assert (stat.stochastic_equals(expected, ind1_gene1_counts, p=p))
def test_uniform_crossover(): pop = [Individual(np.array([0, 0])), Individual(np.array([1, 1]))] # We need a cyclic generator because there are only two individuals in the population, and once the first two # are selected for uniform crossover, the next two parents are selected and crossed over. The cyclic iterator # ensures we just select the same two individuals again even though the yield statements in the uniform # crossover operator are not invoked again. i = ops.naive_cyclic_selection(pop) # Do swap with 100% certainty, which will cause the two individuals' genomes to exchange values new_pop = list(itertools.islice(ops.uniform_crossover(i, p_swap=1.0), 2)) assert np.all(new_pop[0].genome == [1, 1]) assert np.all(new_pop[1].genome == [0, 0]) # Note because we didn't clone the selected individuals, *the original population was changed*. assert np.all(pop[0].genome == [1, 1]) assert np.all(pop[1].genome == [0, 0])
def test_multiple_evaluations(): # Let's try evaluating a single individual pop = [ Individual(np.array([0, 0]), problem=MaxOnes()), Individual(np.array([0, 1]), problem=MaxOnes()), Individual(np.array([1, 0]), problem=MaxOnes()), Individual(np.array([1, 1]), problem=MaxOnes()) ] evaluated_individuals = Individual.evaluate_population(pop) # Since this is the MAX ONES problem, we just count the ones ahead of # time, and ensure that the actual fitnesses match up. expected_fitnesses = [0, 1, 1, 2] for individual, fitness in zip(evaluated_individuals, expected_fitnesses): assert individual.fitness == fitness
def test_apply_mutation(): """Applying segment-wise mutation operators with expected_num_mutations=len(genome) should result in every gene of every segment being mutated.""" mutation_op = apply_mutation(mutator=genome_mutate_bitflip, expected_num_mutations=4) original = Individual([np.array([0, 0]), np.array([1, 1])]) mutated = next(mutation_op(iter([original]))) assert np.all(mutated.genome[0] == [1, 1]) \ and np.all(mutated.genome[1] == [0, 0])
def test_koza_minimization(): """ Tests the koza_parsimony() function for _minimization_ problems. """ problem = SpheroidProblem(maximize=False) pop = [] # First individual has a fitness of three but len(genome) of 4 pop.append(Individual(np.array([0, 1, 1, 1]), problem=problem)) # Second has a fitness of 4, but len(genome) of 1 pop.append(Individual(np.array([2]), problem=problem)) pop = Individual.evaluate_population(pop) best = ops.truncation_selection(pop, size=1, key=koza_parsimony(penalty=1)) assert np.all(best[0].genome == [2])
def test_truncation_selection(): """ Basic truncation selection test""" pop = [ Individual([0, 0, 0], decoder=IdentityDecoder(), problem=MaxOnes()), Individual([0, 0, 1], decoder=IdentityDecoder(), problem=MaxOnes()), Individual([1, 1, 0], decoder=IdentityDecoder(), problem=MaxOnes()), Individual([1, 1, 1], decoder=IdentityDecoder(), problem=MaxOnes()) ] # We first need to evaluate all the individuals so that truncation selection has fitnesses to compare pop = Individual.evaluate_population(pop) truncated = ops.truncation_selection(pop, 2) assert len(truncated) == 2 # Just to make sure, check that the two best individuals from the original population are in the selected population assert pop[2] in truncated assert pop[3] in truncated
def _compute_deltas(self): """Sample additional points by create a convex combination of random pairs of individuals in the original design. Returns a list of :math:`\\delta` values, calculated as :math:`\\delta = f(p) - \\text{comb}(f(x), f(y))`, where :math:`p` is the individual resulting from the complex combination of the pair, a :math:`\\text{comb}(f(x), f(y))` is the complex combination of the *objective values* for each pair. """ pairs = [] combinations = [] deltas = [] for _ in range(self.num_convexity_tests): # Choose two individuals from the initial experiment design without replacement # (so the same individual is not chosen twice) x, y = np.random.choice(self.design_individuals, size=2, replace=False) pairs.append((x, y)) # Find the convex combination of the original fitnesses a = np.random.uniform(0, 1) b = 1.0 - a f = a * x.fitness + b * y.fitness # Sample another point by taking the same convex combination of x and y x_genome = x.genome y_genome = y.genome p_genome = a * x_genome + b * y_genome # Evalute the new point's fitness p = Individual(p_genome, problem=self.problem, decoder=self.representation.decoder ) # Need a decoder; can't assume IdentityDecoder p.evaluate() combinations.append((f, p)) delta = p.fitness - f deltas.append(delta) return pairs, combinations, deltas
def test_n_ary_crossover_probability(): """If we perform crossover with a probabilty of 0.5, then the individuals will be unmodified 50% of the time.""" N = 1000 unmodified_count = 0 for i in range(N): pop = [Individual([0, 0]), Individual([1, 1])] i = ops.naive_cyclic_selection(pop) new_pop = list(itertools.islice(ops.n_ary_crossover(i, p=0.5), 2)) if new_pop[0].genome == [0, 0] and new_pop[1].genome == [1, 1]: unmodified_count += 1 p = 0.01 observed_dist = { 'Unmodified': unmodified_count, 'Modified': N - unmodified_count } assert (stat.equals_uniform(observed_dist, p=p))
def test_naive_cyclic_selection(): """ Test of the naive deterministic cyclic selection """ pop = [ Individual([0, 0], decoder=IdentityDecoder(), problem=MaxOnes()), Individual([0, 1], decoder=IdentityDecoder(), problem=MaxOnes()) ] # This selection operator will deterministically cycle through the # given population selector = ops.naive_cyclic_selection(pop) selected = next(selector) assert selected.genome == [0, 0] selected = next(selector) assert selected.genome == [0, 1] # And now we cycle back to the first individual selected = next(selector) assert selected.genome == [0, 0]
def test_lexical_minimization(): """ Tests lexical_parsimony() for minimization problems """ problem = SpheroidProblem(maximize=False) pop = [] # fitness=4, len(genome)=1 pop.append(Individual(np.array([2]), problem=problem)) # fitness=4, len(genome)=4 pop.append(Individual(np.array([1, 1, 1, 1]), problem=problem)) pop = Individual.evaluate_population(pop) best = ops.truncation_selection(pop, size=1, key=lexical_parsimony) # prefers the shorter of the genomes with equivalent fitness assert np.all(best[0].genome == [2])
def test_segmented_crossover(): """ test that k-ary crossover works as expected for fixed and variable length segments """ a = Individual([[0, 0], [1, 1]]) b = Individual([[1, 1], [0, 0]]) result = n_ary_crossover(iter([a, b])) c = next(result) d = next(result) possible_outcomes = [[[0, 0], [1, 1]], [[1, 1], [0, 0]], [[0, 0], [0, 0]], [[1, 1], [1, 1]]] assert c.genome in possible_outcomes and d.genome in possible_outcomes # Now for genomes of different lengths # TODO I need to *carefully* review the possible crossover possibilities possible_outcomes = [ [], [[0, 0]], [[1, 1]], [[2, 2]], [[0, 0], [1, 1]], [[1, 1], [2, 2]], [[2, 2], [1, 1]], [[2, 2], [0, 0], [1, 1]], [[0, 0], [2, 2], [1, 1]], [[0, 0], [1, 1], [2, 2]], ] for _ in range(20): a = Individual([[0, 0], [1, 1]]) b = Individual([[2, 2]]) result = n_ary_crossover(iter([a, b])) c = next(result) d = next(result) assert c.genome in possible_outcomes assert d.genome in possible_outcomes
def test_lexical_maximization(): """ Tests the lexical_parsimony() for maximization problems """ problem = MaxOnes() # fitness=3, len(genome)=6 pop = [Individual(np.array([0, 0, 0, 1, 1, 1]), problem=problem)] # fitness=2, len(genome)=2 pop.append(Individual(np.array([1, 1]), problem=problem)) # fitness=3, len(genome)=3 pop.append(Individual(np.array([1, 1, 1]), problem=problem)) pop = Individual.evaluate_population(pop) best = ops.truncation_selection(pop, size=1, key=lexical_parsimony) # prefers the shorter of the 3 genomes assert np.all(best[0].genome == [1, 1, 1])
def test_cgp_mutate1(test_2layer_circuit): genome, _, decoder = test_2layer_circuit N = 1000 mutator = cgp.cgp_mutate(decoder) parents = (Individual(genome[:]) for _ in range(N) ) # Copying the parent N times, since mutation is destructive offspring = list(mutator(parents)) observed = {} observed[0] = Counter([ind.genome[0] for ind in offspring]) observed[1] = Counter([ind.genome[1] for ind in offspring]) observed[2] = Counter([ind.genome[2] for ind in offspring]) observed[3] = Counter([ind.genome[3] for ind in offspring]) observed[4] = Counter([ind.genome[4] for ind in offspring]) observed[5] = Counter([ind.genome[5] for ind in offspring]) observed[6] = Counter([ind.genome[6] for ind in offspring]) expected = {} # Genes 0, 3, 6, and 9 specify primitives. Since we only have one # primitive, this gene will not change. expected[0] = {0: N} expected[3] = {0: N} expected[6] = {0: N} expected[9] = {0: N} # We expect the mutation chance to be 1/L p_mut = 1 / len(genome) p_stay = 1 - p_mut # Genes 1 and 2 may be mutated to one of the input nodes, # with probability 1/L and uniform sampling expected[1] = { 0: floor((p_stay + p_mut * 0.5) * N), 1: ceil(p_mut * 0.5 * N) } expected[2] = { 0: floor(p_mut * 0.5 * N), 1: ceil((p_stay + p_mut * 0.5) * N) } expected[4] = { 0: floor(p_mut * 0.5 * N), 1: ceil((p_stay + p_mut * 0.5) * N) } expected[5] = { 0: floor((p_stay + p_mut * 0.5) * N), 1: ceil(p_mut * 0.5 * N) } p = 0.001 for i in range(7): print(f"Gene {i}, expected={expected[i]}, observed={observed[i]}") assert (stat.stochastic_equals(expected[i], observed[i], p=p))
def test_mutate_randint_pipe(): """ This tests pipeline integration """ ind1 = Individual(np.array([0, 0, 0])) ind2 = Individual(np.array([1, 1, 1])) population = iter([ind1, ind2]) bounds = [(-100, 100), (0, 25), (-10, 10)] # Test that mutate_randint can be plugged into a pipeline since we # were experiencing an error when trying to do this. The error turned out # to be that `bounds=` wasn't included in the call, which meant that python # tried to immediately invoke the `mutate_randint` instead of delaying # execution per the pipeline calls. results = toolz.pipe(population, leap_ec.ops.clone, intrep_ops.mutate_randint(bounds=bounds, expected_num_mutations=1), # intrep_ops.mutate_randint(bounds), INCORRECT USAGE leap_ec.ops.pool(size=2)) assert len(results)
def _build_test_pop(): """Construct a synthetic population for illustrating example operations.""" pop = [ Individual([1, 0, 1, 1, 0], IdentityDecoder(), MaxOnes()), Individual([0, 0, 1, 0, 0], IdentityDecoder(), MaxOnes()), Individual([0, 1, 1, 1, 1], IdentityDecoder(), MaxOnes()), Individual([1, 0, 0, 0, 1], IdentityDecoder(), MaxOnes()) ] pop = Individual.evaluate_population(pop) # Assign distinct values to an attribute on each individual attrs = [('foo', ['GREEN', 15, 'BLUE', 72.81]), ('bar', ['Colorless', 'green', 'ideas', 'sleep']), ('baz', [['a', 'b', 'c'], [1, 2, 3], [None, None, None], [0.1, 0.2, 0.3]])] for attr, vals in attrs: for (ind, val) in zip(pop, vals): ind.__dict__[attr] = val return pop
def test_uniform_crossover_probability1(): """If we perform uniform rossover with a probabilty of 0.0, then the individuals will always be unmodified. This test calls the crossover opererator, which is stochastic, but we haven't marked it as part of the stochastic test suite because there is no chance of a false failure (i.e. a test that fails even when there is no fault in the code) in this case.""" N = 20 unmodified_count = 0 for i in range(N): pop = [Individual(np.array([0, 0])), Individual(np.array([1, 1]))] i = ops.naive_cyclic_selection(pop) new_pop = list( itertools.islice(ops.uniform_crossover(i, p_xover=0.0), 2)) if np.all(new_pop[0].genome == [0, 0]) and np.all( new_pop[1].genome == [1, 1]): unmodified_count += 1 assert (unmodified_count == N)