Search code examples
pythonfunctionloopsgenetic-algorithm

Problem looping the crossing of parents of a genetic algorithm in python


I have the following function in python used to generate the children of a genetic algorithm

def cruce(padres):
    mitadHerencia =  len(padres[0])//2
    hijo1 = np.concatenate((padres[0][:mitadHerencia], padres[1][mitadHerencia:]))
    hijo2 = np.concatenate((padres[1][:mitadHerencia], padres[0][mitadHerencia:]))
    hijo3 = np.concatenate((padres[0][:mitadHerencia], padres[2][mitadHerencia:]))
    hijo4 = np.concatenate((padres[2][:mitadHerencia], padres[0][mitadHerencia:]))
    hijo5 = np.concatenate((padres[1][:mitadHerencia], padres[2][mitadHerencia:]))
    return hijo1, hijo2, hijo3, hijo4, hijo5

where padres can be defined as

padres=np.array([[1,0,0,0,1,0],[0,1,1,1,1,0],[1,0,1,0,1,1],[0,1,1,0,1,0],[0,0,0,0,1,0],[1,0,0,0,0,0],[1,1,1,0,1,0],[0,0,1,1,0,0],[0,1,1,0,1,0],[1,0,1,0,1,0]],np.int32)

This is the particular case of a genetic algorithm in which I cross the first element with the second to produce two children, the same with the first and third and so on. I would like to do this using a loop, but I haven't found a way to do this. Can someone please offer me some guidance?


Solution

  • You can generate a list of tuples for the indices of padres and create a list of all hijo which can be unpacked when the function returns:

    def cruce(padres):
        mitadHerencia =  len(padres[0])//2
        num_offspring = len(padres)//2
        
        parts = []
        i, j = 0, 0
        while len(parts) < num_offspring:
            i += 1
            if i >= j:
                i = 0
                j += 1
            parts.extend([(i, j), (j, i)])
        parts = parts[:num_offspring]
    
        hijo = [np.concatenate((padres[x][:mitadHerencia], padres[y][mitadHerencia:])) for x, y in parts]
        return hijo
    

    While I think there exists a cleaner solution to create the parts list, I was unable to. This method iteratively appends the combinations in order and slices it at the end to account for uneven numbers of offspring.

    The loop ranges over j and increments i up to it. If it is equal or greater, it moves on to the next parent. This may be more clear when I show you the output:

    (0, 1) | (0, 2), (1, 2) | (0, 3), (1, 3), (2, 3) | (0, 4), ...
    

    And of course, we also add the pairs in flipped order.