def mutateLearners(self, team): # Since we will remove Learners from the Team while iterating over them, # grab a copy of the list of Learner references. We will iterate through # the copy while mutating the original list learners = team.learners.copy() # Probabalistically mutate Learners in the Team for learner in learners: # Most Learners will be skipped and not mutated if not weightedCoinFlip(Trainer.P_MUT_LEARNER): continue # Sanity check if team.countAtomicActions() == 0: print( "WARNING - Trainer::mutateLearners - No atomic actions in Team!" ) # If this Team only has one Learner with an atomic action and it # happens to be this Learner, remove the possibility of setting the # new action to a Team pointer p_atomic = Trainer.P_ATOMIC if learner.isActionAtomic() and team.countAtomicActions() == 1: p_atomic = 1.0 # Copy Learner. The copy will be mutated and added to the pool of # Learners. This is done to ensure that, in the event that this Learner # is also used to great success in another Team, that other Team # still points to the original functional Learner. learner_prime = Learner(learner=learner) # Remove original Learner from Team and replace it with the new one. team.removeLearner(learner) team.addLearner(learner_prime) # Mutate the new Learner learner_prime.mutateProgram() # Probabalistically mutate the new Learner's action if weightedCoinFlip(Trainer.P_MUT_LEARNER_ACTION): self.mutateLearnerAction(learner_prime, p_atomic) # Sanity check if team.countAtomicActions() == 0: print( "WARNING - Trainer::mutateLearners - No atomic actions in Team after mutation!" ) # Add new Learner to the pool of Learners self.learner_pop.append(learner_prime)