def get_best_n_members(members, n):
        half_members = []

        for gid, g in members.items():
            half_members.append((gid, g))

        half_members.sort(reverse=True, key=lambda x: x[1].fitness)

        return from_list_to_dict(half_members[:n])
    def calculateDifferentRanks(self):
        dominated_dict = self.population
        flag = True
        current_rank = 0
        dominated = []

        while len(dominated_dict) != 0 and flag:
            flag = False
            self.computeRank(dominated_dict)
            for gid, g in dominated_dict.items():
                if g.rank == 2:
                    flag = True
                    g.rank = current_rank
                else:
                    g.rank = None
                    dominated.append((gid, g))
            dominated_dict = from_list_to_dict(dominated)
            dominated = []
            current_rank += 1
    def run(self, fitness_function, n=None):
        # Variables needed to save archive on each update
        winner_name_prefix = "front_" + self.winner_name

        if self.config.no_fitness_termination and (n is None):
            raise RuntimeError(
                "Cannot have no generational limit with no fitness termination"
            )

        k = 0
        while n is None or k < n:
            k += 1
            front = []
            self.reporters.start_generation(self.generation)

            not_evaluated = {}
            evaluated = []
            # len(population) = 2*pop_size
            for gid, g in self.population.items():
                g.rank = None
                if g.fitness is None:
                    not_evaluated[gid] = g
                else:
                    evaluated.append((gid, g))

            # Evaluate all genomes using the user-provided function.
            fitness_function(list(iteritems(not_evaluated)), self.config)
            start_time_gen = time.time()

            # calculate distance on 2*pop_size
            if self.use_archive:
                self.KNNdistances(self.population,
                                  self.n_neighbors,
                                  archive=self.novelty_archive)
            else:
                self.KNNdistances(self.population, self.n_neighbors)
            self.calculateDifferentRanks()

            for gid, g in self.population.items():
                if self.use_archive and g not in self.novelty_archive and g.dist is not None and g.dist > self.novelty_threshold:
                    self.novelty_archive.append(g)
                    self.n_add_archive += 1
                    self.last_archive_modified = self.generation
                    with open("archive_" + self.winner_name, "wb") as f:
                        pickle.dump(self.novelty_archive, f)

            # fig = plt.figure()
            # ax = fig.add_subplot(111, label='')
            for elem in self.population.items():
                if elem[1].rank == 0:
                    front.append(elem)
            #         ax.scatter(elem[1].fitness, elem[1].dist, color='orange')
            #         ax.annotate(elem[1].rank, (elem[1].fitness, elem[1].dist))
            #     else:
            #         ax.scatter(elem[1].fitness, elem[1].dist, color='blue')
            #         ax.annotate(elem[1].rank, (elem[1].fitness, elem[1].dist))
            #
            # ax.set_xlabel('Fitness')
            # # ax.set_ylabel('Mean Height Pelvis')
            # ax.set_ylabel('Mean Diversity')
            # plt.axis((0, plt.axis()[1], 0, plt.axis()[3]))
            # plt.title('MO_NS_FO: POP=' + str(len(self.population)))
            # plt.savefig('MO_NS_FO/Figures/Figure'+str(self.generation)+'.png')
            # plt.close(fig)

            population = []
            for gid, g in self.population.items():
                population.append((gid, g))
            population.sort(reverse=False, key=lambda x: x[1].rank)
            self.population = population[:self.config.pop_size]
            self.population = from_list_to_dict(self.population)
            self.species.speciate(self.config, self.population,
                                  self.generation)

            # Gather and report statistics.
            best = None
            for g in itervalues(self.population):
                if best is None or g.fitness > best.fitness:
                    best = g

            with open(winner_name_prefix, "wb") as f:
                pickle.dump(front, f)

            self.reporters.post_evaluate(self.config, self.population,
                                         self.species, best)

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(
                        self.config.genome_type, self.config.genome_config,
                        self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            if not self.config.no_fitness_termination:
                # End if the fitness threshold is reached.
                fv = self.fitness_criterion(
                    g.dist for g in itervalues(self.population))
                if fv >= self.config.fitness_threshold:
                    self.reporters.found_solution(self.config, self.generation,
                                                  best)
                    break

            self.reporters.end_generation(self.config, self.population,
                                          self.species)

            # Create the next generation from the current generation.
            self.population = self.reproduction.reproduce(
                self.config, self.species, self.config.pop_size,
                self.generation)

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(
                        self.config.genome_type, self.config.genome_config,
                        self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            if self.use_archive:
                time_diff = self.generation - self.last_archive_modified

                if time_diff > 60:
                    self.novelty_threshold -= self.novelty_threshold * 0.05

                if self.n_add_archive > 4 and time_diff <= 30:
                    self.novelty_threshold += self.novelty_threshold * 0.05
                    self.n_add_archive = 0

                if time_diff > 30:
                    self.n_add_archive = 0

                self.reporters.info("Novelty's archive size: {}\n".format(
                    len(self.novelty_archive)))
            self.reporters.info("Front size: {}\n".format(len(front)))
            self.generation += 1

            diff = round(time.time() - start_time_gen, 3)
            self.sum_times += diff
            self.reporters.info("\nGen: " + str(k) + " tempo: " + str(diff) +
                                " sec\n")

        if self.config.no_fitness_termination:
            self.reporters.found_solution(self.config, self.generation,
                                          self.best_genome)

        self.reporters.info("Computation mean time: " +
                            str(self.sum_times / (self.generation + 1)))

        return front
    def run(self, fitness_function, n=None):
        # Variables needed to save winner
        winner_interval = 10
        winner_name_prefix = "winner_checkpoint_"
        last_winner_checkpoint = 0

        if self.config.no_fitness_termination and (n is None):
            raise RuntimeError("Cannot have no generational limit with no fitness termination")

        k = 0
        while n is None or k < n:
            k += 1
            self.reporters.start_generation(self.generation)
            start_time_gen = time.time()

            # Evaluate all genomes using the user-provided function.
            not_evaluated = {}
            evaluated = []
            # len(population) = 2*pop_size
            for gid, g in self.population.items():
                if g.fitness is None:
                    not_evaluated[gid] = g
                else:
                    evaluated.append((gid, g))

            diff = round(time.time() - start_time_gen, 3)
            self.sum_times += diff

            fitness_function(list(iteritems(not_evaluated)), self.config)

            start_time_gen = time.time()
            if self.random_replace:
                i = 0
                self.population = {}
                for gid, g in not_evaluated.items():
                    if len(evaluated) <= i or g.fitness > evaluated[i][1].fitness:
                        self.population[gid] = g
                    else:
                        self.population[evaluated[i][0]] = evaluated[i][1]
                    i = i + 1
                self.species.speciate(self.config, self.population, self.generation)
            elif self.mu_lambda:
                self.population = []
                self.population += evaluated
                for key, v in not_evaluated.items():
                    self.population.append((key, v))
                self.population.sort(reverse=True, key=lambda x: x[1].fitness)
                self.population = from_list_to_dict(self.population[:self.config.pop_size])
                self.species.speciate(self.config, self.population, self.generation)
            else:
                self.species.speciate(self.config, self.population, self.generation)
                dim = 0
                max_spec_dim = 0
                max_sid = -1
                for sid, s in iteritems(self.species):
                    s.members = self.get_best_half_members(s.members)
                    d = len(s.members)
                    if d > max_spec_dim:
                        max_spec_dim = d
                        max_sid = sid
                    dim += d
                diff = dim - self.config.pop_size
                if diff > 0 and diff > max_spec_dim:
                    s = self.species[max_sid]
                    s.members = s.members[:len(s.members) - diff]

            # Check for complete extinction.
            if not self.species.species:
                self.reporters.complete_extinction()

                # If requested by the user, create a completely new population,
                # otherwise raise an exception.
                if self.config.reset_on_extinction:
                    self.population = self.reproduction.create_new(self.config.genome_type,
                                                                   self.config.genome_config,
                                                                   self.config.pop_size)
                else:
                    raise CompleteExtinctionException()

            # Gather and report statistics.
            best = None
            for g in itervalues(self.population):
                if best is None or g.fitness > best.fitness:
                    best = g
            self.reporters.post_evaluate(self.config, self.population, self.species, best)

            # Track the best genome ever seen.
            if self.best_genome is None or best.fitness > self.best_genome.fitness:
                self.best_genome = best
                # Code to save the best after winner_interval generations
                if self.overwrite:
                    filename = winner_name_prefix
                else:
                    filename = '{0}{1}'.format(winner_name_prefix, self.generation)
                last_winner_checkpoint = self.generation
                with open(filename, 'wb') as f:
                    pickle.dump(self.best_genome, f)

            if not self.config.no_fitness_termination:
                # End if the fitness threshold is reached.
                fv = self.fitness_criterion(g.fitness for g in itervalues(self.population))
                if fv >= self.config.fitness_threshold:
                    self.reporters.found_solution(self.config, self.generation, best)
                    break

            self.reporters.end_generation(self.config, self.population, self.species)

            # Create the next generation from the current generation.
            self.population = self.reproduction.reproduce(self.config, self.species,
                                                          self.config.pop_size, self.generation)

            self.generation += 1

            print_file("\nGen: " + str(k) + " tempo: " + str(round(time.time() - start_time_gen,3)) + " sec\n")
            diff = round(time.time() - start_time_gen, 3)
            self.sum_times += diff
            self.reporters.info("\nGen: " + str(k) + " tempo: " + str(diff) + " sec\n")

        if self.config.no_fitness_termination:
            self.reporters.found_solution(self.config, self.generation, self.best_genome)

        self.reporters.info("Computation mean time: " + str(self.sum_times / (self.generation + 1)))

        return self.best_genome
    def reproduce(self, config, species, pop_size, generation):
        all_fitnesses = []
        remaining_species = []
        for stag_sid, stag_s, stagnant in self.stagnation.update(
                species, generation):
            if stagnant:
                self.reporters.species_stagnant(stag_sid, stag_s)
            else:
                all_fitnesses.extend(m.rank
                                     for m in itervalues(stag_s.members))
                remaining_species.append(stag_s)

        if not remaining_species:
            species.species = {}
            return {}

        min_fitness = min(all_fitnesses)
        max_fitness = max(all_fitnesses)

        fitness_range = max(1.0, max_fitness - min_fitness)
        for afs in remaining_species:
            # Compute adjusted fitness.
            msf = mean([m.rank for m in itervalues(afs.members)])
            af = (msf - min_fitness) / fitness_range
            afs.adjusted_fitness = af

        adjusted_fitnesses = [s.adjusted_fitness for s in remaining_species]
        avg_adjusted_fitness = mean(adjusted_fitnesses)  # type: float
        self.reporters.info(
            "Average adjusted fitness: {:.3f}".format(avg_adjusted_fitness))

        previous_sizes = [len(s.members) for s in remaining_species]
        min_species_size = self.reproduction_config.min_species_size

        min_species_size = max(min_species_size,
                               self.reproduction_config.elitism)
        spawn_amounts = self.compute_spawn(adjusted_fitnesses, previous_sizes,
                                           pop_size, min_species_size)

        new_population = {}
        all_old_members = []
        species.species = {}

        population = []
        for s in remaining_species:
            population += list(iteritems(s.members))

        for spawn, s in zip(spawn_amounts, remaining_species):

            spawn = max(spawn, self.reproduction_config.elitism)

            assert spawn > 0

            old_members = list(iteritems(s.members))
            all_old_members += old_members
            s.members = {}
            species.species[s.key] = s

            old_members.sort(reverse=False, key=lambda x: x[1].rank)

            if spawn <= 0:
                continue

            repro_cutoff = int(
                math.ceil(self.reproduction_config.survival_threshold *
                          len(old_members)))
            repro_cutoff = max(repro_cutoff, 2)
            old_members = old_members[:repro_cutoff]

            while spawn > 0:
                spawn -= 1

                if len(old_members) > 2:
                    parent1_id, parent1, parent2_id, parent2 = self.tournament(
                        old_members, self.tournament_threshold)
                else:
                    parent1_id, parent1 = random.choice(old_members)
                    parent2_id, parent2 = random.choice(old_members)

                gid = next(self.genome_indexer)
                child = config.genome_type(gid)
                child.configure_crossover(parent1, parent2,
                                          config.genome_config)
                child.mutate(config.genome_config)
                new_population[gid] = child
                self.ancestors[gid] = (parent1_id, parent2_id)

        all_old_members.sort(key=lambda x: x[0])
        all_old_members = from_list_to_dict(all_old_members)
        new_population.update(all_old_members)

        return new_population
    def reproduce(self, config, species, pop_size, generation):
        all_fitnesses = []
        remaining_species = []
        max_stagnation = self.stagnation.stagnation_config.max_stagnation
        # **************************** EXTINCTION STAGNANT SPECIES ***************************
        for stag_sid, stag_s, stagnant in self.stagnation.update(
                species, generation):
            if stagnant:
                self.reporters.species_stagnant(stag_sid, stag_s)
            else:
                all_fitnesses.extend(m.fitness
                                     for m in itervalues(stag_s.members))
                remaining_species.append(stag_s)

        if not remaining_species:
            species.species = {}
            return {}

        # ********************************* ADJUSTED FITNESS *********************************
        adjusted_fitnesses, avg_adjusted_fitness = self.compute_adjusted_fitness(
            all_fitnesses, remaining_species)
        self.reporters.info(
            "Average adjusted fitness: {:.3f}".format(avg_adjusted_fitness))

        # Compute the number of new members for each species in the new generation.
        previous_sizes = [len(s.members) for s in remaining_species]
        min_species_size = self.reproduction_config.min_species_size
        min_species_size = max(min_species_size,
                               self.reproduction_config.elitism)

        spawn_amounts = self.compute_spawn(adjusted_fitnesses, previous_sizes,
                                           pop_size, min_species_size)
        # 3 set
        new_population = {}
        all_old_members = []
        species.species = {}
        re_spawn = False
        for spawn, s in zip(spawn_amounts, remaining_species):
            # If elitism is enabled, each species always at least gets to retain its elites.
            spawn = max(spawn, self.reproduction_config.elitism)

            assert spawn > 0

            # The species has at least one member for the next generation, so retain it.
            old_members = list(iteritems(s.members))
            all_old_members += old_members
            s.members = {}
            species.species[s.key] = s

            # Sort members in order of descending fitness.
            old_members.sort(reverse=True, key=lambda x: x[1].fitness)

            if spawn <= 0:
                continue

            # Only use the survival threshold fraction to use as parents for the next generation.
            repro_cutoff = int(
                math.ceil(self.reproduction_config.survival_threshold *
                          len(old_members)))

            # Use at least two parents no matter what the threshold fraction result is.
            repro_cutoff = max(repro_cutoff, 2)
            old_members = old_members[:repro_cutoff]

            # **************************** CROSSOVER AND MUTATION ****************************
            while spawn > 0:
                spawn -= 1

                if len(old_members) > 2:
                    parent1_id, parent1, parent2_id, parent2 = self.tournament(
                        old_members, self.tournament_threshold)
                else:
                    parent1_id, parent1 = random.choice(old_members)
                    parent2_id, parent2 = random.choice(old_members)

                gid = next(self.genome_indexer)
                child = config.genome_type(gid)
                child.configure_crossover(parent1, parent2,
                                          config.genome_config)
                child.mutate(config.genome_config)
                new_population[gid] = child
                self.ancestors[gid] = (parent1_id, parent2_id)

        all_old_members.sort(key=lambda x: x[0])
        all_old_members = from_list_to_dict(all_old_members)
        new_population.update(all_old_members)

        return new_population