class Algorithm(object): """ Runs the wintermute algorithm """ def __init__(self, model, options): """ Initialize the algorithm :return: None """ self._model = model self._options = options self._history = History() self._surrogate = None self._rnd = None def run(self): """ Run the optimization algorithm :return: The run history :rtype: History """ self._rnd = Random() # TODO (JLD): Set the seed from the options self._rnd.seed() # Determine the initial population size based on the requirements for an initial surrogate model parent_pop = self.get_initial_population() # Evaluate the initial population self.evaluate(parent_pop) self._history.add_population(parent_pop) # Generate a surrogate model self._surrogate = Surrogate(parent_pop) # Apply the moving operators to generate a child population self.sort_population(parent_pop) pop_size = self.culling_function(len(parent_pop)) child_pop = [ind.copy() for ind in parent_pop[0:pop_size]] # Flag children for movement for ind in child_pop: if # Sort the parent population and using the culling function, select the N+1 population size of individual # to apply the moving operators on # flag individuals for movement # Apply the global moving operator # Apply the local moving operator # Sort the combined parent and child population and select the best N+1 population size individuals # to become the new parent population # Check convergence (depends on dynamic culling functions as well) # Repeat pass def set_model(self, model): """ Set the model for the algorithm to use :param model: The model to set :type model: Model :return: None """ self._model = model def set_options(self, options): """ Set the algorithm options :param options: The options to set :type options: Options :return: None """ self._options = options def get_initial_population(self): """ Generate an initial populaion :return: An initial population :rtype: list(Individual) """ # Determine the initial population size # Initial popualtion size depends on the number of dimensions and minimum number of points # to generate an initial surrogate model # Rule of thumb (D+1)(D+2) # Require 2x the number of points 1) L2 Orthogonal Array 2) Latin Hypercube # TODO (JLD): Look into DOE methods for large dimensionality space # Given the model bounds, first generate an L2 orthogonal array DOE of size (n/2) and initialize # the individuals at those points, and add them to the list. # Then for the remaining n/2 individual, initialize them using a latin hypercube sampling and add them # to the list # return the population return [] def get_initial_population_size(self): """ Get the initial population size :return: The initial population size :trype: int """ pass def evaluate(self, population): """ Evaluate the population :param population: The population to evaluate :type population: list(Individual) :return: None """ for ind in population: f, h, g = self._model.evaluate(ind.x) ind.f = f ind.h = h ind.g = g def select_for_movement(self, population): pass def culling_function(self, pop_size): """ Given the current population size, return the size of the next population :param pop_size: The current population size :return: The next generation's population size """ return len(pop_size) - 1 def sort_population(self, population): """ Sort the population and return the size best individuals, if size=None than the entire population is sorted and returned :param population: THe population to sort :param size: The maximum number of individuals to return """ pass def move_popualation(self, population): """ Apply local or global movement operations to construct a new population. :param population: The population to move :return: The new population """ # Sort the population into local and global movement and make a copy # Apply local movement # For each individual in the local movement population # Optimize using the surrogate model with the location of the local individual as the start point # Use the converged location as the new location for the individual (this means that the optimizer # can operate on the individual object in place) # Apply global movement # Apply the crossover and mutation genetic operators on the population # TODO (JLD): Research crossover and mutation operators that do not require user input # return the new population. pass