During Population's run()-method, the mean/max/... fitness for each species gets first calculated. After this, the entire population gets recombined (during which new offspring gets made, some old genomes get removed, and the species size gets adjusted). These newly created genomes then get sorted into species again.
Afterwards, the fitness and size of each species get printed. However, at this point, new offspring already exist, for which no fitness values have been defined yet. In summary, the species size of generation n+1 gets printed together with the mean fitness values from generation n.
A short example to illustrate the above:
There are e.g. 6 genomes and 2 species A and B. A has 4 members, B has 2. After running the user-provided function in run(), their fitness values are as following:
A1: 1
A2: 2
A3: 1.5
A4: 1.5
B1: 3
B2: 6
Hence, species A's mean fitness is 1.5 and species B's mean fitness is 4.5.
After recombining, all species have e.g. 1 survivor, the rest get killed. A now has only 2 members, whereas B has 3. A new species C further appeared during recombination.
A2: 2
A5: --
B2: 6
B3: --
B4: --
C1: --
The print statement is now as follows:
"Species A has size 2 and fitness 1.5. Species B has size 3 and fitness 4.5. Species C has size 1 and fitness --."
The problem with this: Technically, at this point, species A does not have the mean fitness 1.5 anymore and B does not have the mean fitness of 4.5 anymore. A more correct print statement would e.g. instead be:
"Species A had size 4 and fitness 1.5. Species B had size 2 and fitness 4.5. Species A now has size 2, B has size 3 and species C has size 1."
Thanks for the report! I'm going to change the default reporting to be clearer about this, so there are fewer ways to have an "off by one generation" misunderstanding of the output.
Describe the bug. The print statement of each species' fitness value after each generation is slightly incorrect. In the following, I am referring to the source code of the Population-class (https://neat-python.readthedocs.io/en/latest/_modules/population.html).
During Population's run()-method, the mean/max/... fitness for each species gets first calculated. After this, the entire population gets recombined (during which new offspring gets made, some old genomes get removed, and the species size gets adjusted). These newly created genomes then get sorted into species again.
Afterwards, the fitness and size of each species get printed. However, at this point, new offspring already exist, for which no fitness values have been defined yet. In summary, the species size of generation n+1 gets printed together with the mean fitness values from generation n.
A short example to illustrate the above: There are e.g. 6 genomes and 2 species A and B. A has 4 members, B has 2. After running the user-provided function in run(), their fitness values are as following:
Hence, species A's mean fitness is 1.5 and species B's mean fitness is 4.5.
After recombining, all species have e.g. 1 survivor, the rest get killed. A now has only 2 members, whereas B has 3. A new species C further appeared during recombination.
The print statement is now as follows: "Species A has size 2 and fitness 1.5. Species B has size 3 and fitness 4.5. Species C has size 1 and fitness --."
The problem with this: Technically, at this point, species A does not have the mean fitness 1.5 anymore and B does not have the mean fitness of 4.5 anymore. A more correct print statement would e.g. instead be: "Species A had size 4 and fitness 1.5. Species B had size 2 and fitness 4.5. Species A now has size 2, B has size 3 and species C has size 1."