I am implementing Genetic Algorithm (GA).
There are 43
numbers [Ambulance Locations] to choose from (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39)
, I choose 3
places since I have 3
ambulances.
I can only put my ambulance in 3
locations among 1-39 locations
(Restriction).
A chromosome sample: [000010000000000000100000000000100000000]
. This represents that I want to put my Ambulance on the 5th, 19th, and 31 positions.
The bits against positions 5th
, 19th
, and 31
are 1
and rest positions are 0
. In other words, I am turning on 5-bit, 19-bit, and 31-bit
.
Let's say
Candidate solution 1 (111000000000000000000000000000000000000)
and
Candidate Solution 2 (000000000000000000000000000000000000111)
My candidate solutions are encoded in 39-bits,I want to do a cross-over these 39-bits. Above two candidates solutions are a bit weird. What can be done here?
What can be a good approach to perform cross-over while puting ambulances in 3
locations among 1-39 locations
?
OPs question
There are many ways to perform crossover - in this example as we must end up with the same number of bits in the input and the output I have used a crossover between the bits, allowing for 0-3 bits to get swapped between the two inputs.
The solution provided is dynamic and will work for any length chromosome with any number of flipped bits (1s).
import random
from typing import Union
def crossover(cs1: str, cs2: str) -> Union[str, str]:
if len(cs1) != len(cs2):
raise Exception("Candidate solutions input are of different length.")
# get the flipped bits in each string
cs1_bits = [index for index, gene in enumerate(cs1) if gene == "1"]
cs2_bits = [index for index, gene in enumerate(cs2) if gene == "1"]
if len(cs1_bits) != len(cs2_bits):
raise Exception("Candidate solutions input have different number of flipped bits.")
index: int = random.randint(0, len(cs1_bits))
sol1_bits, sol2_bits = cs1_bits[:index] + cs2_bits[index:], cs2_bits[:index] + cs1_bits[index:]
output_1 = ""
output_2 = ""
for i in range(len(cs1)):
if i in sol1_bits:
output_1 += "1"
else:
output_1 += "0"
if i in sol2_bits:
output_2 += "1"
else:
output_2 += "0"
return output_1, output_2
Example input/output for OPs solution.
# Input
"111000000000000000000000000000000000000", "000000000000000000000000000000000000111"
# Output
'110000000000000000000000000000000000001', '001000000000000000000000000000000000110'
How to perform standard crossover
You perform crossover in a genetic algorithm by selecting a random index along the length of the number of values, in your instance, you will choose a value between 0-38 (39 options).
You will then split both of the inputs and join the front of cs1
onto the back of cs2
and vice versa.
from typing import Union
import random
def crossover(cs1: str, cs2: str) -> Union[str, str]:
index: int = random.randint(0, len(cs1))
return cs1[:index] + cs2[index:], cs2[:index] + cs1[index:]
If you have the values:
cs1 = "111000000000000000000000000000000000000"
cs2 = "000000000000000000000000000000000000111"
Crossing over with an index of 1 will return:
output_1 = "100000000000000000000000000000000000111"
output_2 = "011000000000000000000000000000000000000"
Crossing over with an index of 5 will return:
output_1 = "111000000000000000000000000000000000111"
output_2 = "000000000000000000000000000000000000000"