def method1(ga): # Method 1 performs serial loops for crossover/mutation # Store parameters for readability population = ga.population pop_size = ga.ga_params['pop_size'] percent_crossover = ga.ga_params['percent_crossover'] percent_mutation = ga.ga_params['percent_mutation'] num_elite = ga.ga_params['num_elite'] # Sort population by fitness score (lowest score = most fit) population.sort(key=lambda x: x.fitness_score) # Calculate parents needed for crossover, ensure even number num_crossover = round((pop_size-num_elite)*percent_crossover) if (num_crossover % 2) != 0: # If odd, increment by 1 num_crossover += 1 # Calculate parents needed for mutation num_mutation = round((pop_size-num_elite)*percent_mutation) # Calculate remaining number of trusses in next population num_random = pop_size - num_elite - num_crossover - num_mutation if num_random < 0: # Raise exception if input params are unreasonable raise RuntimeError('Invalid GenAlg parameters.') # Instantiate objects selector = Selector(ga.selector_params) crossover = Crossover(ga.crossover_params) mutator = Mutator(ga.mutator_params) # Select parents as indices in current population crossover_parents = selector(num_crossover, population) mutation_parents = selector(num_mutation, population) # Save most fit trusses as elites pop_elite = population[:num_elite] # Portion of new population formed by crossover pop_crossover = [] for i in range(0, num_crossover, 2): parentindex1 = crossover_parents[i] parentindex2 = crossover_parents[i+1] parent1 = population[parentindex1] parent2 = population[parentindex2] child1, child2 = crossover(parent1, parent2) pop_crossover.extend((child1, child2)) # Portion of new population formed by mutation pop_mutation = [] for i in range(num_mutation): parentindex = mutation_parents[i] parent = population[parentindex] child = mutator(parent) pop_mutation.append(child) # Create new random trusses with remaining spots in generation pop_random = [ga.generate_random(2) for i in range(num_random)] # Append separate lists to form new generation population = pop_elite + pop_crossover + pop_mutation + pop_random # Update population attribute return population
def test_sanity(self): """Test to make sure parent arrays of 1's returns all 1's.""" array1 = np.ones((10, 1)) array2 = np.ones((10, 1)) check = np.ones((10, 1)) children = Crossover.two_points_split(array1, array2) np.testing.assert_array_equal(children[0], check) np.testing.assert_array_equal(children[1], check)
def testZeros(self): """Test to make sure parent arrays of 0s returns 0s.""" truss_1 = np.zeros(10, dtype=int) truss_2 = np.zeros(10, dtype=int) result = Crossover.uniform_crossover(truss_1, truss_2) np.testing.assert_array_equal(result[0], truss_1) np.testing.assert_array_equal(result[1], truss_2)
def testChildInParents(self): """Test to make sure that all values of the child arrays exist in the one of the two parent arrays.""" truss_1 = np.random.randint(10, size=25) truss_2 = np.random.randint(10, size=25) parents_combined = np.concatenate((truss_1, truss_2)) result = Crossover.uniform_crossover(truss_1, truss_2) child1_status = str(np.all(np.in1d(result[0], parents_combined))) child2_status = str(np.all(np.in1d(result[1], parents_combined))) np.testing.assert_string_equal(child1_status, str(True)) np.testing.assert_string_equal(child2_status, str(True))
def test_datatype(self): """Test to make sure the data type matches what is expected.""" array1 = np.ones((10, 1), dtype=int) array2 = np.ones((10, 1), dtype=int) check = np.ones((10, 1), dtype=int) children = Crossover.single_point_split(array1, array2) np.testing.assert_array_equal(children[0], check) np.testing.assert_array_equal(children[1], check) np.testing.assert_string_equal(str((children[0]).dtype), str(check.dtype)) np.testing.assert_string_equal(str((children[1]).dtype), str(check.dtype))
def testOutputTypeInt(self): """Test to make sure the data type matches what is expected.""" truss_1 = np.zeros(10, dtype=int) truss_2 = np.zeros(10, dtype=int) check = np.zeros(10, dtype=int) result = Crossover.uniform_crossover(truss_1, truss_2) np.testing.assert_array_equal(result[0], check) np.testing.assert_array_equal(result[1], check) np.testing.assert_string_equal(str((result[0]).dtype), str(check.dtype)) np.testing.assert_string_equal(str((result[1]).dtype), str(check.dtype))
def update_population(self): # Cristian ''' Creates new population by performing crossover and mutation, as well as taking elites and randomly generating trusses. First sorts the population by fitness score, from most fit to least fit. Creates selector object from population and method. Calls selector to get list of parents for crossover and mutation. Performs crossover and mutation. Args: None Returns: None ''' # Store parameters for readability population = self.population pop_size = self.ga_params['pop_size'] percent_crossover = self.ga_params['percent_crossover'] percent_mutation = self.ga_params['percent_mutation'] num_elite = self.ga_params['num_elite'] # Sort population by fitness score (lowest score = most fit) # population.sort(key=lambda x: x.fitness_score) #remove # Calculate parents needed for crossover, ensure even number num_crossover = round((pop_size - num_elite) * percent_crossover) if (num_crossover % 2) != 0: # If odd, decrement by 1 num_crossover -= 1 # Calculate parents needed for mutation num_mutation = round((pop_size - num_elite) * percent_mutation) # Calculate remaining number of trusses in next population num_random = pop_size - num_elite - num_crossover - num_mutation if num_random < 0: # Raise exception if input params are unreasonable raise RuntimeError('percent_crossover + percent_mutation > 1') # Instantiate objects selector = Selector(self.selector_params) crossover = Crossover(self.crossover_params) mutator = Mutator(self.mutator_params) # Select parents as indices in current population crossover_parents = selector(num_crossover, population) mutation_parents = selector(num_mutation, population) # Save most fit trusses as elites pop_elite = population[:num_elite] pbar = tqdm(total=(num_crossover + num_mutation + num_random), desc='Updating', position=1) # Portion of new population formed by crossover pop_crossover = [] for i in range(0, num_crossover, 2): parentindex1 = crossover_parents[i] parentindex2 = crossover_parents[i + 1] parent1 = population[parentindex1] parent2 = population[parentindex2] child1, child2 = crossover(parent1, parent2) pop_crossover.extend((child1, child2)) pbar.update(2) # Portion of new population formed by mutation pop_mutation = [] for i in range(num_mutation): parentindex = mutation_parents[i] parent = population[parentindex] child = mutator(parent) pop_mutation.append(child) pbar.update() # Create new random trusses with remaining spots in generation pop_random = [] for i in range(num_random): pop_random.append(self.generate_random()) pbar.update() # Append separate lists to form new generation population = pop_elite + pop_crossover + pop_mutation + pop_random pbar.close() # Update population attribute self.population = population return