def gaussian(ind, Pm, std, x_min, x_max): '''Gaussian mutation with rate of success Pm. If the mutation results in genes outside the specified bounds, they are set equal to the nearest bound. Arguments: ind {'individual' object} -- The individual. Pm {float} -- The rate of mutation as a decimal probability. std {float} -- Standard deviation for the gaussian function. x_min {float} -- Minimum bound on gene values. x_max {float} -- Maximum bound on gene values. Returns: 'individual' object -- The mutated individual, or None. ''' if ind: values = [] for x in ind.values: if r.random() < Pm: values.append(x + np.random.normal(0, std)) else: values.append(x) #stay within bounds if values[-1] < x_min: values[-1] = x_min if values[-1] > x_max: values[-1] = x_max return individual(values) return None
def two_point(Parents, n, Pc): '''Two point crossover. Same as single point except a second crossover point is calculated where the genome goes back to the first parent. Arguments: Parents {2-tuple of class 'individual'} -- The parents. n {int} -- The genome length Pc {float} -- The rate of success as a decimal propbability. Returns: 'individual' object -- The child, or None. ''' if r.random() < Pc: child_values = [] crosspoint1 = r.randint(0, n) crosspoint2 = r.randint(crosspoint1, n) for i in range(n): if i < crosspoint1: child_values.append(Parents[0].values[i]) elif i >= crosspoint1 and i < crosspoint2: child_values.append(Parents[1].values[i]) else: child_values.append(Parents[0].values[i]) return individual(child_values) return None #regenerate parent pair
def single_run(fdistr='RWS', fsamp='p_sample', fcross='single_point', fmut='uniform'): '''Driver for a single run of the GA. Genetic manipulation methods can be left blank or supplied for varying outcomes. Arguments: fdistr {str} -- RWS or distribution method if provided. fsamp {str} -- Proportional or sampling method if provided. fcross {str} -- Single-Point or crossover method if provided. fmut {str} -- Uniform or mutation method if provided. Returns: 'individual' object -- The best-of-run individual. ''' #initialize best_of_run = individual([0] * n) #start with worst gen_count = 1 P = [] while len(P) < N: P.append(individual(None, n)) while gen_count <= max_generations: distr(P, fdistr) #calculate distribution for i in P: #check if any are better than current BOR. if i.f > best_of_run.f: best_of_run = i P_next = [] while len(P_next) < N: #build next generation i = mut(cross((sample(P, fsamp), sample(P, fsamp)), fcross), fmut) if i: #if not None P_next.append(i) gen_count += 1 P = P_next print('Total evaluations for run:', ind.evals) return best_of_run
def uniform(ind, Pm, x_min, x_max): '''Uniform random mutation method. Replaces gene values regardless of current value. Arguments: ind {'individual' object} -- The individual. Pm {float} -- The rate of mutation as a decimal probability. x_min {float} -- Minimum bound on gene values. x_max {float} -- Maximum bound on gene values. Returns: 'individual' object -- The mutated individual, or None. ''' if ind: values = [] for _ in ind.values: values.append(r.uniform(x_min, x_max)) return individual(values) return None
def arithmatic(Parents, n, Pc, weight): '''Arithmatic crossover. Each gene is calculated as ax[i] + (1-a)y[i]. Arguments: Parents {2-tuple of class 'individual'} -- The parents. n {int} -- The genome length Pc {float} -- The rate of success as a decimal propbability. weight {float} -- The weight that the first parent's genes have. 0.5 will result in each parent contributing equally. Returns: 'individual' object -- The child, or None. ''' if r.random() < Pc: child_values = [] for i in range(n): child_values.append( (weight * Parents[0].values[i]) + \ ((1-weight) * Parents[1].values[i]) ) return individual(child_values) return None
def single_point(Parents, n, Pc): '''Single point crossover with rate of success = Pc Arguments: Parents {2-tuple of class 'individual'} -- The parents. n {int} -- The genome length Pc {float} -- The rate of success as a decimal propbability. Returns: 'individual' object -- The child, or None. ''' if r.random() < Pc: child_values = [] crosspoint = r.randint(0, n) for i in range(n): if i < crosspoint: child_values.append(Parents[0].values[i]) else: child_values.append(Parents[1].values[i]) return individual(child_values) return None #regenerate parent pair