I have implemented a genetic algorithm in python 3, and have posted a question on code review with no answers yet, basically because my algorithm is running very slowly. By selectively commenting out different parts of my code, I have narrowed down the bottleneck to this section of code, the crossover algorithm:
def crossover(self, mum, dad):
"""Implements ordered crossover"""
size = len(mum.vertices)
# Choose random start/end position for crossover
alice, bob = [-1] * size, [-1] * size
start, end = sorted([random.randrange(size) for _ in range(2)])
# Replicate mum's sequence for alice, dad's sequence for bob
for i in range(start, end + 1):
alice[i] = mum.vertices[i]
bob[i] = dad.vertices[i]
# # Fill the remaining position with the other parents' entries
# current_dad_position, current_mum_position = 0, 0
#
# for i in chain(range(start), range(end + 1, size)):
#
# while dad.vertices[current_dad_position] in alice:
# current_dad_position += 1
#
# while mum.vertices[current_mum_position] in bob:
# current_mum_position += 1
#
# alice[i] = dad.vertices[current_dad_position]
# bob[i] = mum.vertices[current_mum_position]
#
# # Return twins
# return graph.Tour(self.g, alice), graph.Tour(self.g, bob)
return mum, dad
The part which is commented out makes my program runtime go from ~7 seconds to 5-6 minutes (I am running 5000 iterations of the GA). Is there any way this ordered crossover can be carried out more efficiently?
What the crossover function does
For those unfamiliar, I am implementing an order-based crossover (OX2). Given two arrays of consecutive integers (the parents), two random start/end positions are selected.
mum = 4 9 2 8 3 1 5 7 6
dad = 6 4 1 3 7 2 8 5 9
^ ^
start end
The two children then share the resulting slices:
child 1 = _ _ 2 8 3 1 _ _ _
child 2 = _ _ 1 3 7 2 _ _ _
^ ^
Now the remaining slots are filled in with the entries of the other parents in the order in which they appear, as long as repetitions are avoided. So since child 1 has their slice taken from mum, the rest of the entries are taken from dad. First we take 6, then 4, then next we take 7 (not taking 1 and 3 since they already appear in child 1 from mum), then 5, then 9. So
child 1 = 6 4 2 8 3 1 7 5 9
and similarly,
child 2 = 4 9 1 3 7 2 8 5 6
This is what I am implementing in the function.