def run(self, generations, p_mutate, p_crossover, elitist=True, two_point_crossover=False,<EOL>refresh_after=None, quit_after=None):
start_time = time.time()<EOL>assert <NUM_LIT:0> <= p_mutate <= <NUM_LIT:1><EOL>assert <NUM_LIT:0> <= p_crossover <= <NUM_LIT:1><EOL>self.min_fit_ever =  <NUM_LIT><EOL>self.max_fit_ever = -<NUM_LIT><EOL>self.generation_fittest.clear()<EOL>self.generation_fittest_fit.clear()<EOL>self.overall_fittest_fit.clear()<EOL>self.new_fittest_generations.clear()<EOL>overall_fittest = self.get_fittest()<EOL>overall_fittest_fit = self.get_fitness(overall_fittest)<EOL>gens_since_upset = <NUM_LIT:0><EOL>for gen in range(<NUM_LIT:1>, generations + <NUM_LIT:1>):<EOL><INDENT>survivors = self.compete(self.chromosomes)<EOL>self.chromosomes = self.reproduce(survivors, p_crossover, two_point_crossover=two_point_crossover)<EOL>self.mutate(self.chromosomes, p_mutate)<EOL>gen_fittest = self.get_fittest().copy()<EOL>gen_fittest_fit = self.get_fitness(gen_fittest)<EOL>if gen_fittest_fit > overall_fittest_fit:<EOL><INDENT>overall_fittest = gen_fittest<EOL>overall_fittest_fit = gen_fittest_fit<EOL>self.new_fittest_generations.append(gen)<EOL>gens_since_upset = <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>gens_since_upset += <NUM_LIT:1><EOL>if elitist:<EOL><INDENT>self.sort(self.chromosomes)<EOL>self.chromosomes[<NUM_LIT:0>].dna = overall_fittest.dna<EOL><DEDENT><DEDENT>if quit_after and gens_since_upset >= quit_after:<EOL><INDENT>print("<STR_LIT>", gen, "<STR_LIT>", quit_after, "<STR_LIT>")<EOL>break<EOL><DEDENT>if refresh_after and gens_since_upset >= refresh_after:<EOL><INDENT>print("<STR_LIT>", gen)<EOL>self.mutate(self.chromosomes, <NUM_LIT:0.5>)<EOL>gens_since_upset = <NUM_LIT:0><EOL><DEDENT>self.generation_fittest[gen] = gen_fittest<EOL>self.generation_fittest_fit[gen] = gen_fittest_fit<EOL>self.overall_fittest_fit[gen] = overall_fittest_fit<EOL>if self.should_terminate(overall_fittest):<EOL><INDENT>break<EOL><DEDENT>self.fitness_cache.clear()<EOL><DEDENT>self.run_time_s = time.time() - start_time<EOL>return overall_fittest<EOL>
Run a standard genetic algorithm simulation for a set number
of generations (iterations), each consisting of the following
ordered steps:

  1. competition/survival of the fittest (``compete`` method)
  2. reproduction (``reproduce`` method)
  3. mutation (``mutate`` method)
  4. check if the new population's fittest is fitter than the overall fittest
  4a.  if not and the ``elitist`` option is active, replace the weakest solution
       with the overall fittest

generations:  how many generations to run
p_mutate:  probability of mutation in [0, 1]
p_crossover:  probability in [0, 1] that a crossover event will occur for each offspring
elitist (default=True):  option to replace the weakest solution with the 
                         strongest if a new one is not found each generation
two_point_crossover (default=False):  whether 2-point crossover is used
refresh_after:  number of generations since the last upset after which to randomly generate a new population
quit_after:  number of generations since the last upset after which to stop the run, possibly before reaching
             ``generations`` iterations

return:  the overall fittest solution (chromosome)