def __init__(self): """ Make Experiment based on arbitrary keywords """ self.pop_size = 50 self.num_generations = 20 self.s_method = GreedySelection() self.s_method_string = "greedy" self.max_depth = 3 self.op_list = ['+', '-', '/', '*'] self.vars = 'x' self.constant_max = 5 self.constant_min = -5 self.constant_num = int(math.pow(2, self.max_depth)) #The rates must add up to 100! self.m_rate_const = 10 self.c_rate_const = 80 self.e_rate_const = 10 self.m_rate = None self.c_rate = None self.e_rate = None self.elitism_num = int(math.ceil(0.05*self.pop_size)) self.t_type = "full" #The function that will be attempted to be emulated: self.target_func = 'math.pow(x,2)' self.fitness_min = -2 self.fitness_max = 2 self.fitness_incr = 0.1 self.fitness_accuracy = np.arange(-2, 2, 0.1) self.fitness_cutoff = 0.75 #List for animation self.populations = [] #Variables for tree traversal self.traverse_num = 1 self.num = 1 self.subtree = None self.m_subtree = None self.f_subtree = None
def choose_selection_function(self): """ Chooses selection function based off of string """ if self.s_method_string == "greedy": self.s_method = GreedySelection() else: self.s_method = GreedySelection()
class Experiment(object): '''Experiment Class''' def __init__(self): """ Make Experiment based on arbitrary keywords """ self.pop_size = 50 self.num_generations = 20 self.s_method = GreedySelection() self.s_method_string = "greedy" self.max_depth = 3 self.op_list = ['+', '-', '/', '*'] self.vars = 'x' self.constant_max = 5 self.constant_min = -5 self.constant_num = int(math.pow(2, self.max_depth)) #The rates must add up to 100! self.m_rate_const = 10 self.c_rate_const = 80 self.e_rate_const = 10 self.m_rate = None self.c_rate = None self.e_rate = None self.elitism_num = int(math.ceil(0.05*self.pop_size)) self.t_type = "full" #The function that will be attempted to be emulated: self.target_func = 'math.pow(x,2)' self.fitness_min = -2 self.fitness_max = 2 self.fitness_incr = 0.1 self.fitness_accuracy = np.arange(-2, 2, 0.1) self.fitness_cutoff = 0.75 #List for animation self.populations = [] #Variables for tree traversal self.traverse_num = 1 self.num = 1 self.subtree = None self.m_subtree = None self.f_subtree = None def change_variable(self, **kwargs): """Changes an arbitrary parameter""" for key in kwargs: if key == 'pop_size': self.pop_size = kwargs[key] if key == 'num_generations': self.num_generations = kwargs[key] if key == 's_method': self.s_method_string = kwargs[key] if key == 'max_depth': self.max_depth = kwargs[key] if key == 'm_rate': self.m_rate_const = kwargs[key] if key == 'c_rate': self.c_rate_const = kwargs[key] if key == 'e_rate': self.e_rate_const = kwargs[key] if key == 'elitism_num': self.elitism_num = kwargs[key] if key == 't_type': self.t_type = kwargs[key] if key == 'constant_max': self.constant_max = kwargs[key] if key == 'constant_min': self.constant_min = kwargs[key] if key == 'constant_num': self.constant_num = kwargs[key] if key == 'target_func': self.target_func = kwargs[key] if key == 'fitness_max': self.fitness_max = kwargs[key] if key == 'fitness_min': self.fitness_min = kwargs[key] if key == 'fitness_incr': self.fitness_incr = kwargs[key] def start(self): """ Start the experiment """ self.check_input() self.standardize_rates() self.create_fitness_array() self.populations = [] self.pop = structures.Population() self.pop.make_constants(self.constant_min, self.constant_max, self.constant_num) self.pop.make_vars(self.vars) self.pop.make_operators() self.pop.populate(self.pop_size, self.max_depth, self.t_type) self.run_experiment(FGENERATION, self.pop) def check_input(self): """ Checks User Input""" try: self.pop_size = int(self.pop_size) self.num_generations = int(self.num_generations) self.max_depth = int(self.max_depth) self.c_rate_const = float(self.c_rate_const) self.e_rate_const = float(self.e_rate_const) self.m_rate_const = float(self.m_rate_const) self.elitism_num = int(self.elitism_num) self.constant_max = float(self.constant_max) self.constant_min = float(self.constant_min) self.constant_num = int(self.constant_num) self.fitness_max = float(self.fitness_max) self.fitness_min = float(self.fitness_min) self.fitness_incr = float(self.fitness_incr) self.fitness_cutoff = float(self.fitness_cutoff) except ValueError: raise InputError("Invalid Input", "Input was not valid. i.e. string for int") if self.pop_size <= 5: raise InputError("pop_size", "pop_size cannot be less than 6") if self.num_generations <= 0: raise InputError("num_generations", "num_generations cannot be less than 1") if self.s_method is None: raise InputError("s_method", "s_method does not exist!") if self.max_depth < 1: raise InputError("max_depth", "max_depth cannot be less than 1") if self.constant_max < self.constant_min: raise InputError("constant_max and constant_min", "constant_max must be >= than constant_min") if self.constant_num < 0: raise InputError("contant_num", "contant_num must be >= 0") if self.m_rate_const < 0: raise InputError("m_rate", "m_rate must be >= 0") if self.c_rate_const < 0: raise InputError("c_rate", "c_rate must be >= 0") if self.e_rate_const < 0: raise InputError("e_rate", "e_rate must be >= 0") if ((self.m_rate_const + self.c_rate_const + self.e_rate_const) != 100): raise InputError("all_rates", "Reproduction Rates must add up to 100!") if self.elitism_num < 0 or self.elitism_num > self.pop_size: raise InputError("elitism_num", "elitism_num must be >= 0 and <= pop_size") #Would be nice to access this from structures so its more adaptable if (not self.t_type == "grow" and not self.t_type == "full"): raise InputError("t_type", self.t_type + " does not exist!") try: x = 1 eval(self.target_func) except NameError: raise InputError("target_func", "target_func is not valid!") if (self.fitness_min > self.fitness_max): raise InputError("fitness_min and fitness_max", "fitness_max must be > fitness_min") if (self.fitness_incr <= 0): raise InputError("fitness_incr", "fitness_incr must be > 0") if (self.fitness_cutoff <=0 or self.fitness_cutoff > 1): raise InputError("fitness_cutoff", "fitness_cutoff must be > 0 and <= 1") self.choose_selection_function() if (self.s_method is None): raise InputError("s_method", "s_method is not valid!") def choose_selection_function(self): """ Chooses selection function based off of string """ if self.s_method_string == "greedy": self.s_method = GreedySelection() else: self.s_method = GreedySelection() def create_fitness_array(self): """Creates fitness aray from the userdefined parameters""" self.fitness_accuracy = np.arange(self.fitness_min, self.fitness_max, self.fitness_incr) def standardize_rates(self): """ Standardize the reproduction rates """ self.m_rate = self.m_rate_const self.c_rate = self.c_rate_const self.e_rate = self.e_rate_const self.c_rate += self.m_rate self.e_rate += self.c_rate def run_experiment(self, gen_num, population): """Run Experiment; a recursive function @param gen_num: The current generation number @param population: The current population """ next_gen = [] ordered_fit_list = self.eval_ffunctions(population) self.populations.append(copy.deepcopy(ordered_fit_list)) self.s_method.set_up(ordered_fit_list) for individual in xrange(self.elitism_num): next_gen.append(ordered_fit_list[individual][1]) while (len(next_gen) < self.pop_size): breed_method_num = 100* random.random() if (breed_method_num < self.c_rate and self.pop_size - len(next_gen) > 1): individual = self.s_method.select(2) individual = self.crossover(individual) elif breed_method_num < self.m_rate: individual = self.s_method.select(1) individual = self.mutate(individual) else: individual = self.s_method.select(1) for ind in individual: next_gen.append(ind) population.individuals = next_gen print gen_num, ordered_fit_list if self.criterion_satisfied(ordered_fit_list): print gen_num print ordered_fit_list [0][0] print ordered_fit_list[0][1] animated = Animation(self) animated() #would be nice to store ordered_fit_list to other function #that would allow users to plot any of the individuals return ordered_fit_list[0][1] if gen_num >= self.num_generations: print "FAILED" print ordered_fit_list [0][0] print ordered_fit_list[0][1] animated = Animation(self) animated() return ordered_fit_list[0][1] gen_num += 1 self.run_experiment(gen_num, population) def criterion_satisfied(self, fit_list): '''Does current pop contain goal specimen?''' if fit_list[0][0] > self.fitness_cutoff: return True def eval_ffunctions(self, current_pop): '''Evaluate Fitness User Specified Fitness Function @bug: only works for one variable at the moment @param current_pop: The current population, type Population @return: An ordered dictionary of fitness levels ''' fitness_dict = {} for individual in current_pop.individuals: #print "New Individual",individual residual_sum = 0 for input in self.fitness_accuracy: x = input theoretical = eval(self.target_func) experimental = individual([input]) residual = math.pow((experimental - theoretical), 2) residual_sum += residual adjusted_fitness = residual_sum + 1 adjusted_fitness = 1 / adjusted_fitness fitness_dict[adjusted_fitness] = individual fitness_list = sorted(fitness_dict.items(), reverse = True) return fitness_list def crossover(self, individuals): '''Crossover two different Parse-Trees with user defined constant @bug: will not handle any other trees than full @param individuals: The list of two individuals @return: the list of two crossed-over individuals ''' #print "old mother", individuals[0] #print "old father", individuals[1] mother = copy.deepcopy(individuals[0]) father = copy.deepcopy(individuals[1]) self.traverse(mother, True) self.traverse_num = 1 self.traverse(father, False) self.traverse_num = 1 ftemp = copy.deepcopy(self.f_subtree) mtemp = copy.deepcopy(self.m_subtree) self.m_subtree.root = ftemp.root self.m_subtree.branches = ftemp.branches self.m_subtree.var_to_val = ftemp.var_to_val self.m_subtree.max_depth = ftemp.max_depth self.m_subtree.vars = ftemp.vars self.f_subtree.root = mtemp.root self.f_subtree.branches = mtemp.branches self.f_subtree.var_to_val = mtemp.var_to_val self.f_subtree.max_depth = mtemp.max_depth self.f_subtree.vars = mtemp.vars #print "mother ",mother #print "father ",father return [mother, father] def mutate(self, individual): '''Mutate part of the genome with user defined constant @bug: will not handle any trees other than full @param individual: The list of one individual @return: The list of one mutated individual ''' ind = copy.deepcopy(individual[0]) self.num = 1 self.traverse(ind, True) branch_depth = random.randint(0, self.m_subtree.max_depth) temp = self.pop.make_individual(branch_depth, self.t_type) self.m_subtree.branches = temp.branches self.m_subtree.root = temp.root self.m_subtree.var_to_val = temp.var_to_val self.m_subtree.max_depth = temp.max_depth self.m_subtree.vars = temp.vars return [ind] def traverse(self, tree, is_mother): """Traverses a tree recursively """ if not tree.branches: rand = random.uniform(0, 1) if rand < (1.0 / self.traverse_num): if (is_mother): self.m_subtree = tree else: self.f_subtree = tree self.traverse_num = self.traverse_num + 1 return else: for branch in tree.branches: self.traverse(branch, is_mother) rand = random.uniform(0, 1) if rand < (1.0 / self.traverse_num): if (is_mother): self.m_subtree = tree else: self.f_subtree = tree self.traverse_num = self.traverse_num + 1 return