コード例 #1
0
ファイル: serial.py プロジェクト: jldaniel/Athena
class Serial(AlgorithmBase):
    """
    The serial implementation of NSGA-II
    """
    def __init__(self):
        """
        Initialize the Serial object
        @return: None
        """
        super(Serial, self).__init__()

    def initialize(self):
        """
        Randomly initialize a population
        @return: The initialize population
        @rtype: list(Individual)
        """
        self._logger.info('Initializing the population')
        pop = []

        # Randomly initialize the population
        for i in xrange(self._pop_size):
            ind = Individual()
            ind.id = i
            x_set = [None]*self._ndim

            for j in xrange(self._ndim):
                x_set[j] = self._rnd.uniform(self._lower_bound[j], self._upper_bound[j])

            ind.x = x_set
            pop.append(ind)
        return pop

    def run(self):
        """
        Run the optimization algorithm
        @return: The history from the run
        @rtype: History
        """
        # Initialize the population
        parent_pop = self.initialize()

        # Evaluate the population
        self.evaluate_population(parent_pop)

        # Perform selection to get the crowding distances
        parent_pop = self.selection(parent_pop, self._pop_size)
        pareto_front = self.nondominated_sort(parent_pop, len(parent_pop), first_front_only=True)
        self._converger = Converger(pareto_front[0], self._pop_size, self._true_pareto_front)

        # Initialize the archive
        if self._write_history is True:
            self._history.add_population(parent_pop)

        gen = 0
        converged = 0
        convergence_history = []

        while (gen < self._generations) and converged < 10:

            self._logger.info('Starting generation ' + repr(gen+1) + ' of ' + repr(self._generations))

            # Apply crossover to generate a child population
            child_pop = self.tournament_select(parent_pop, self._pop_size)[:]

            # Apply crossover and mutation
            for ind1, ind2 in zip(child_pop[::2], child_pop[1::2]):
                if self._rnd.random() <= self._p_cross:
                    self.mate(ind1, ind2)

                self.mutate(ind1)
                self.mutate(ind2)

            # Evaluate the child population
            self.evaluate_population(child_pop)

            # Update ID's
            for ind in child_pop:
                ind.id += self._pop_size

            # Perform NSGA-2 selection to pick the next generation
            parent_pop = self.selection(parent_pop + child_pop, self._pop_size)
            pareto_front = self.nondominated_sort(parent_pop, len(parent_pop), first_front_only=True)
            self._history.add_population(parent_pop)
            self._logger.info('Pareto Front Size: ' + repr(len(pareto_front[0])))

            # Check convergence
            convergence_metrics = \
                self._converger.check_convergence(pareto_front[0], self._pop_size)

            if self._write_history is True:
                convergence_history.append(convergence_metrics)

            self._logger.info('Frontier Goodness: ' + repr(convergence_metrics.fg))
            self._logger.info('Expansion Metric: ' + repr(convergence_metrics.expansion))
            self._logger.info('Density Metric: ' + repr(convergence_metrics.dm))
            self._logger.info('Distance Metric: ' + repr(convergence_metrics.distance))
            self._logger.info('Volume Ratio: ' + repr(convergence_metrics.volume_ratio))

            if self._conv_tol != 0:
                if max([convergence_metrics.fg, convergence_metrics.expansion, convergence_metrics.dm]) <= \
                        self._conv_tol:
                    converged += 1
                    self._logger.info('Converged Generations: ' + repr(converged))
                else:
                    converged = 0

            # Update
            gen += 1

        # Final solution
        solution = self.nondominated_sort(parent_pop, len(parent_pop), first_front_only=True)

        return self._history, convergence_history, solution[0]
コード例 #2
0
ファイル: islands.py プロジェクト: jldaniel/Athena
class Islands(AlgorithmBase):
    """
    The Islands optimization algorithm.
    """
    def __init__(self):
        """
        Initialize the Islands algorithm.
        @return: None
        """
        super(Islands, self).__init__()

    def initialize(self):
        """
        Randomly initialize the island populations
        @return: The initialized islands
        @rtype: list(list(Individual))
        """
        self._logger.info('Initializing the islands')
        islands = []

        # TODO (JLD): Use _global_popsize where appropriate
        self._global_popsize = self._islands * self._pop_size

        # Randomly initialize each sub-population
        for k in xrange(self._islands):
            pop = []
            for i in xrange(self._pop_size):
                ind = Individual()
                ind.id = i
                x_set = [None]*self._ndim

                for j in xrange(self._ndim):
                    x_set[j] = self._rnd.uniform(self._lower_bound[j], self._upper_bound[j])

                ind.x = x_set
                pop.append(ind)

            islands.append(pop)
        return islands

    def run(self):
        """
        Run the optimization algorithm
        @return: The history from the run
        @rtype: History
        """
        # Initialize the islands
        islands = self.initialize()

        # Evaluate the individuals
        for island in islands:
            self.evaluate_population(island)

        # Perform selection to get the crowding distances
        parent_islands = []
        pareto_fronts = []
        for island in islands:
            parent_pop = self.selection(island, self._pop_size)
            parent_islands.append(parent_pop)

        # Get the global pareto front
        pareto_front = self.nondominated_sort(self.coalesce_populations(parent_islands),
                                              len(parent_islands)*self._pop_size, first_front_only=True)

        self._converger = Converger(pareto_front[0], len(pareto_front))

        # Initialize the archive
        self._history.add_population(parent_islands)

        gen = 0
        converged = 0
        # TODO (JLD): Make epoch a configuration property
        epoch = 5
        # TODO (JLD): Make number_of_migrants a configuration property
        number_of_migrants = 3

        while (gen < self._generations) and converged < 10:

            self._logger.info('Starting generation ' + repr(gen+1) + ' of ' + repr(self._generations))

            # Migration
            if (gen % epoch) == 0:
                self._logger.info('Epoch occurred, migrating...')
                self.migration(parent_islands, number_of_migrants)

            # Apply crossover to generate a child population
            child_islands = []
            for parent_pop in parent_islands:
                child_pop = self.tournament_select(parent_pop, self._pop_size)
                child_islands.append(child_pop)

            # Apply crossover and mutation
            for child_pop in child_islands:
                for ind1, ind2 in zip(child_pop[::2], child_pop[1::2]):
                    if self._rnd.random() <= self._p_cross:
                        self.mate(ind1, ind2)

                    self.mutate(ind1)
                    self.mutate(ind2)

            # Evaluate the child population
            for child_pop in child_islands:
                self.evaluate_population(child_pop)

            # Update ID's
            for child_pop in child_islands:
                for ind in child_pop:
                    ind.id += self._pop_size

            # Perform NSGA-2 selection to pick the next generation
            for parent_pop, child_pop in zip(parent_islands, child_islands):
                parent_pop = self.selection(parent_pop + child_pop, self._pop_size)

            pareto_front = self.nondominated_sort(self.coalesce_populations(parent_islands),
                                                  len(parent_islands)*self._pop_size, first_front_only=True)

            for parent_pop in parent_islands:
                self._history.add_population(parent_pop)


            convergence_metrics = self._converger.check_convergence(pareto_front[0], self._pop_size*self._islands)

            self._logger.info('Frontier Goodness: ' + repr(convergence_metrics.fg))
            self._logger.info('Expansion Metric: ' + repr(convergence_metrics.expansion))
            self._logger.info('Density Metric: ' + repr(convergence_metrics.dm))

            if max([convergence_metrics.fg, convergence_metrics.expansion, convergence_metrics.dm]) <= self._conv_tol:
                converged += 1
                self._logger.info('Converged Generations: ' + repr(converged))
            else:
                converged = 0

            # Update
            gen += 1

        # Final solution
        solution = []
        for parent_pop in parent_islands:
            for ind in parent_pop:
                solution.append(ind)

        # TODO (JLD): Add convergence history, and solution to outputs
        return self._history,

    # TODO (JLD): Add in different migration schemes
    def migration(self, islands, number_of_migrants):
        """
        Perform the migration operation in place on the sub populations
        @param islands: The sub populations to include in the migration
        @type islands: list(list(Individual))
        @param number_of_migrants: The number of migrants
        @type number_of_migrants: int
        @return: None
        """
        # Generate a migration pool, currently just selecting a random individual
        migrant_pool = []
        for island in islands:
            for i in xrange(number_of_migrants):
                random_index = self._rnd.randrange(0, len(island))
                migrant = island.pop(random_index)
                migrant_pool.append(migrant)

        # assign the migrants to an island
        for island in islands:
            for i in xrange(number_of_migrants):
                random_index = self._rnd.randrange(0, len(migrant_pool))
                immigrant = migrant_pool.pop(random_index)
                island.append(immigrant)