I am writing a simple genetic algorithm in python, and when I try to find the average fitness of a set of haploids, it gives it to me with the remainder dropped, I can't figure out why it is doing this. Below is the full source
import random
def generate_random_haploid(haploid_length):
haploid = []
for x in range(haploid_length):
haploid.append(random.randint(0,1))
return haploid
def crossover_haploid(haploid_1, haploid_2):
locus = random.randint(1, len(haploid_1))
for x in range(locus - 1):
haploid_1[x] = haploid_2[x]
for x in range(len(haploid_2) - locus):
haploid_2[x + locus] = haploid_1[x + locus]
return [haploid_1, haploid_2]
def crossover_diploid(diploid_1, diploid_2):
children_1, children_2 = crossover_haploid(diploid_1[0], diploid_1[1]), crossover_haploid(diploid_2[0], diploid_2[1])
return crossover_haploid(children_1[0], children_2[1])
def flipbit(bit):
if bit == 1:
bit = 0
elif bit == 0:
bit = 1
return bit
def mutate_haploid(haploid, mutate_prob):
for x in haploid:
if random.randint(0, mutate_prob) <= mutate_prob:
haploid[x] = flipbit(haploid[x])
return haploid
def average_fitness(haploid_list):
return sum(haploid_list[0]) / len(haploid_list)
def fitness(haploid):
fitness = 0
for x in range(len(haploid)):
if haploid[x] == 1:
fitness += 1
return fitness
def print_haploid(haploid):
print(haploid, "Fitness: ", fitness(haploid))
x = generate_random_haploid(4)
y = generate_random_haploid(4)
print_haploid(x)
print_haploid(y)
print("-------------------------------")
children = crossover_haploid(x, y)
print_haploid(children[0])
print_haploid(children[1])
print("-------------------------------")
print("Parent Fitness: ", average_fitness([x, y]) )
print("-------------------------------")
print("Children Fitness: ", average_fitness([children[0], children[1]]) )
This is because python integer is meant to truncate down to the lowest value. You have a bunch of options to get around this:
>>> 5 / 2
2
Cast one of your values as float and python will automatically up-cast all other int types
>>> 5 / 2
2
>>> float(5) / 2
2.5
Correction to your code:
def average_fitness(haploid_list):
return float(sum(haploid_list[0])) / len(haploid_list)
Add this to the top of your script
from __future__ import division
Now, 5 / 2
will yield 2.5
and you don't need to change your average_fitness
method as shown in option 1. The __future__
refers to python3 in which the /
operator by default performs float divisions. By import that feature, you will now use the float
division operator /
everywhere in your code instead of python2's int
division operator
You can replace the /
with the //
operator
>>> 5 / 2
2
>>> 5 // 2
2.5
Correction to your code:
def average_fitness(haploid_list):
return float(sum(haploid_list[0])) // len(haploid_list)