# Roulette wheel

mattia gervaz at gmail.com
Thu Mar 5 16:48:01 CET 2009

```Il Wed, 04 Mar 2009 21:30:54 +0100, Peter Otten ha scritto:

> mattia wrote:
>
>> Hi everyone, I'm new to python and I want to create some simple code in
>> order to code the classical genetic algorithm example: given a
>> population of chromosomes, encoded using 1 and 0, find the chromosome
>> with the maximum number of 1s. Now, despite all the code used to
>> implement the solution, I'm wondering if there is a better way to use
>> the so-called roulette wheel selection in this problem. Here I paste
>
> Your code looks good to me.
>
>> from random import randint, random
>>
>> def create_chromosome(min, max, length):
>>     chromosome = []
>>     for i in range(length):
>>         chromosome.append(randint(min, max))
>>     return chromosome
>>
>> def fitness(chrm, ffunc=sum):
>>     return ffunc(chrm)
>
> fitness = sum
>
> has the same effect, without the extra indirection.
>
>> def create_population(nelem, min, max, length):
>>     return [create_chromosome(min, max, length) for i in range(nelem)]
>>
>> def get_fitness_and_population(population):
>>     return [(fitness(x), x) for x in population]
>>
>> def get_roulette_wheel(population):
>>     roulette_wheel = []
>>     index = 0
>>
>>     for x in get_fitness_and_population(population):
>>         for j in range(x[0]):
>>             roulette_wheel.append(index)
>>         index += 1
>
> Make that
>
>       for index, x in enumerate(get_fitness_and_population(population)):
>           ...
>
> I'd also pass the the fitness function explicitly around instead of
> making it a global.
>
>>     return roulette_wheel
>>
>> pop = create_population(5, 0, 1, 10)
>> rw = get_roulette_wheel(pop)
>> print(rw)
>> print(len(rw))
>> ri = randint(0, len(rw) - 1)
>> print("Random index:", rw[ri], ", value:", pop[rw[ri]])
>
> But these are minor nits :)
>
> Here's a slightly different approach:
>
> from random import randint, choice
>
> def create_chromosome(min, max, length):
>     return [randint(min, max) for i in range(length)]
>
> def create_population(nelem, min, max, length):
>     return [create_chromosome(min, max, length) for i in range(nelem)]
>
> def get_fitness_and_population(population, fitness):
>     return [(fitness(x), x) for x in population]
>
> def get_roulette_wheel(weight_value_pairs):
>     roulette_wheel = []
>     for weight, value in weight_value_pairs:
>         roulette_wheel += [value]*weight
>     return roulette_wheel
>
> if __name__ == "__main__":
>     pop = create_population(5, 0, 1, 10)
>     fap = get_fitness_and_population(pop, sum) rw =
>     get_roulette_wheel(fap)
>     print("Random value:", choice(rw))
>
> Note how get_roulette_wheel() is now completeley independent of the
> concrete problem you are using it for.
>
> Peter

The last question: how can I improve readability in this piece of code?

def crossover(pop, prob=0.6):
"""
With a crossover probability cross over the parents to form new
offspring. If no crossover was performed, offspring is the exact copy of parents.
"""
cpop = []
for i in range(0, len(pop), 2):
# crossover
if prob > random():
crossover_point = randint(0, len(pop[i])-1)
nchromosome1 = pop[i][:crossover_point] + pop[i+1][crossover_point:]
nchromosome2 = pop[i+1][:crossover_point] + pop[i][crossover_point:]
else:
nchromosome1 = pop[i][:]
nchromosome2 = pop[i+1][:]
cpop += [nchromosome1] + [nchromosome2]
return cpop

And with this one my example is complete!

```