Create a structured way to perform mutation/create new individuals.
Currently, creating a new individual or mutating one is done at random. Only after creation we make sure that the individual is actually new, and if not, start over. This means that we need to apply the operation possibly multiple times and just hope to get a good one, which is not an elegant solution (and one that might still result in no new individual, at that).
The desired behavior is that when making or mutating an individual is to take into account previous individuals to try. I don't know a good way to do this. Perhaps something with keeping a graph of created individuals? And you can create/mutate an individual by traversing/looking at the graph? Will this require too many resources (either cpu or memory)?
Related bug in current version: sometimes two individuals are marked as being able to perform crossover, but they will never give a new individual. This happens for pipelines with the shape A(B()) and C(B()), which are marked for crossover because they can exchange their sub-pipeline B(), but if B() is the same in both pipelines, crossover is meaningless.