def _generate_population(self): """ Generating initial population of individual solutions Regardless of strategy, we make 5 initial "warming" steps to make distribution closer to the problem. Strategies description: * Uniform: each cell has equal probability of being initialized as alive or dead. This will introduce no prior information at all * Covering: Each individual is generated with it's own probability of having each cell 'alive'. This gives on average higher initial fitness score, but has no observed effect on long-term behavior :return: initial population as a list of 20x20 arrays """ if type(self.initialization_strategy) is str: if self.initialization_strategy == 'uniform': initial_states = np.split(np.random.binomial(1, 0.5, (20 * self.population_size, 20)).astype('uint8'), self.population_size) return [life.make_move(state, 5) for state in initial_states] elif self.initialization_strategy == 'covering': """ Idea is to cover all the range of possible values for 'density' parameter """ alive_probabilities = np.linspace(0.01, 0.99, self.population_size) return [life.make_move(np.random.binomial(1, prob, size=(20, 20)), moves=5) for prob in alive_probabilities] else: raise NotImplementedError(self.initialization_strategy + " is not implemented!") else: """Assume initialization based on individual, just copy it over""" return [np.copy(self.initialization_strategy).reshape((20, 20)).astype('uint8') for i in range(self.population_size)]
def fitness(cls, start_field, end_field, delta): """ Calculate fitness for particular candidate (start configuration of the field) Currently unused, as fitness scoring was implemented directly into Cython `life` module. :param start_field: candidate (start configuration) :param end_field: target (stop configuration) :param delta: number of steps to proceed before comparing to stop configuration :return: value in range [0, 1] that indicates fractions of cells that match their state """ candidate = life.make_move(start_field, moves=delta) return (candidate == end_field).sum() / 400
def parallel_fitness(gene, Y, delta): candidate = life.make_move(gene, moves=delta) return (candidate == Y).sum() / 400