I am trying to generate 2 children from 2 parents by crossover. I want to fix a part from parent A and fill the blanks with elements from parent B.
I was able to mask both parents and get the elements on another array, but I am not able to fill in the gaps from the fixed part of Parent A with the fill elements from Parent B
Here's what I have tried so far:
import numpy as np
from numpy.random import default_rng
rng = default_rng()
numMachines = 5
numJobs = 5
population =[[[4, 0, 2, 1, 3],
[4, 2, 0, 1, 3],
[4, 2, 0, 1, 3],
[4, 0, 3, 2, 1],
[2, 3, 4, 1, 0]],
[[2, 0, 1, 3, 4],
[4, 3, 1, 2, 0],
[2, 0, 3, 4, 1],
[4, 3, 1, 0, 2],
[4, 0, 3, 1, 2]]]
parentA = np.array(population[0])
parentB = np.array(population[1])
childA = np.zeros((numJobs, numMachines))
np.copyto(childA, parentA)
childB = np.zeros((numJobs, numMachines))
np.copyto(childB, parentB)
subJobs = np.stack([rng.choice(numJobs ,size=int(np.max([2, np.floor(numJobs/2)])), replace=False) for i in range(numMachines)])
maskA = np.stack([(np.isin(childA[i], subJobs[i])) for i in range(numMachines)])
invMaskA = np.invert(maskA)
maskB = np.stack([(np.isin(childB[i], subJobs[i])) for i in range(numMachines)])
invMaskB = np.invert(maskB)
maskedChildAFixed = np.ma.masked_array(childA, maskA)
maskedChildBFixed = np.ma.masked_array(childB, maskB)
maskedChildAFill = np.ma.masked_array(childA, invMaskA)
maskedChildBFill = np.ma.masked_array(childB, invMaskB)
maskedChildAFill = np.stack([maskedChildAFill[i].compressed() for i in range(numMachines)])
maskedChildBFill = np.stack([maskedChildBFill[i].compressed() for i in range(numMachines)])
EDIT:
Sorry, I was so frustrated with this yesterday that I forgot to add some more information to make it more clear. First, I have fixed the code so it now runs by just copying and pasting (I forgot to add some import calls and some variables).
This is a fixed portion from Parent A that won't change in child A.
>>> print(maskedChildAFixed)
[[-- 0.0 2.0 -- 3.0]
[4.0 -- 0.0 1.0 --]
[4.0 -- -- 1.0 3.0]
[-- 0.0 3.0 2.0 --]
[-- -- 4.0 1.0 0.0]]
I need to fill in these blank parts with the fill part from parent B.
>>> print(maskedChildBFill)
[[1. 4.]
[3. 2.]
[2. 0.]
[4. 1.]
[3. 2.]]
For my children to be legal I can't repeat an integer in each row. If I try to use the "np.na.filled()" function with the compressed maskedChildBFill it gives me an error.
>>> print(np.ma.filled(maskedChildAFixed, fill_value=maskedChildBFill))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Rafael\.conda\envs\CoutoBinario\lib\site-packages\numpy\ma\core.py", line 639, in filled
return a.filled(fill_value)
File "C:\Users\Rafael\.conda\envs\CoutoBinario\lib\site-packages\numpy\ma\core.py", line 3752, in filled
np.copyto(result, fill_value, where=m)
File "<__array_function__ internals>", line 6, in copyto
ValueError: could not broadcast input array from shape (5,2) into shape (5,5)
I'll now coment the part of the code that compresses the fill portion (lines 46 and 47). It won't delete the blank spaces from the maskedChildBFill so that the size of the matrices are preserved.
>>> print(np.ma.filled(maskedChildAFixed, fill_value=maskedChildBFill))
[[2. 0. 2. 3. 3.]
[4. 3. 0. 1. 0.]
[4. 0. 3. 1. 3.]
[4. 0. 3. 2. 2.]
[4. 0. 4. 1. 0.]]
See how I get an invalid individual? Note the repeated integers in row 1. The individual should look like this:
[[1.0 0.0 2.0 4.0 3.0]
[4.0 3.0 0.0 1.0 2.0]
[4.0 2.0 0.0 1.0 3.0]
[4.0 0.0 3.0 2.0 1.0]
[3.0 2.0 4.0 1.0 0.0]]
I hope this update makes it easier to understand what I am trying to do. Thanks for all the help so far! <3
EDIT 2
I was able to work around by converting everything to list and then with for loops substitute the values in place, but this should be super slow. There might be a way to do this using numpy.
maskedChildAFill = maskedChildAFill.tolist()
maskedChildBFill = maskedChildBFill.tolist()
maskedChildAFixed = maskedChildAFixed.tolist()
maskedChildBFixed = maskedChildBFixed.tolist()
for i in range(numMachines):
counterA = 0
counterB = 0
for n, j in enumerate(maskedChildAFixed[i]):
if maskedChildAFixed[i][n] is None:
maskedChildAFixed[i][n] = maskedChildBFill[i][counterA]
counterA += 1
for n, j in enumerate(maskedChildBFixed[i]):
if maskedChildBFixed[i][n] is None:
maskedChildBFixed[i][n] = maskedChildAFill[i][counterB]
counterB += 1