GeneticAlgorithmPython icon indicating copy to clipboard operation
GeneticAlgorithmPython copied to clipboard

Enforcing Percentage (Genes Must Sum to 1)

Open Matheus-Schmitz opened this issue 3 years ago • 3 comments

The values I'm trying to optimize are percentages, such that the sum of all genes should be exactly 1. Is there a way to enfoce this in PyGAD? I can keep each gene individually bound [0, 1] with the gene_space hyperparameter, but I haven't yet managed to apply the "sum" constrain. From the sequencing in the algorithm, would a custom function called on_generation perhaps be able to handle this? I couldn't yet crack that but I think it might be a solution.

Matheus-Schmitz avatar Mar 13 '22 16:03 Matheus-Schmitz

This is not yet a supported feature in PyGAD but I am working on finding a way to apply conditions between some individual genes (e.g. a gene must satisfy a condition like gene1<gene2+gene3) and also across all genes.

At the current moment, there are some things that might help you.

  1. An easy way, as you suggested, is to check the values of all genes in the population in either the on_mutation() or the on_generation() callback functions. There, you handle the gene values in case the sum exceeds 1. You can access to the population through the population property.
  2. I do not know if this is applicable to your case but you may split the 0-1 range across your genes in gene_space so that you are confident that the sum will be 1.
  3. Implement your own mutation function because mutation is what changes the genes' values. But this would need some effort.

ahmedfgad avatar Mar 13 '22 17:03 ahmedfgad

I'll try handling it using on_generation() then! Just one follow up question which I couldn't get from the docs, besides "stop" what is the expected return from on_generation()? i.e. should it try to modify the ga_instance in place or should it return a new ga_instance?

Matheus-Schmitz avatar Mar 13 '22 17:03 Matheus-Schmitz

The return value from the on_generation() function is optional. You are not asked to return anything.

For your case, you can just overwrite the population property.

def on_generation(ga_instance):
    ga_instance.population = ...

Caution: In case you returned "stop", then the algorithm will stop without going through the remaining generations.

ahmedfgad avatar Mar 13 '22 17:03 ahmedfgad