def initialize_randomly(problem, population_size): """ Initialize a population of solutions (feasible solution) for an evolutionary algorithm Required: @ problem - problem's build solution function knows how to create an individual in accordance with the encoding. @ population_size - to define the size of the population to be returned. """ solution_list = [] i = 0 # generate a population of admissible solutions (individuals) for _ in range(0, population_size): s = problem.build_solution() # check if the solution is admissible while not problem.is_admissible(s): s = problem.build_solution() s.id = [0, i] i += 1 problem.evaluate_solution(s) solution_list.append(s) # print([x.fitness for x in solution_list]) population = Population(problem=problem, maximum_size=population_size, solution_list=solution_list) return population
def initialize_using_hc(problem, population_size): """ Initialize a population of solutions (feasible solution) for an evolutionary algorithm using Hill Climbing Required: @ problem - problem's build solution function knows how to create an individual in accordance with the encoding. @ population_size - to define the size of the population to be returned. """ solution_list = [] # generate a population of admissible solutions (individuals) for i in range(0, population_size): s = problem.build_solution(method='Hill Climbing') # check if the solution is admissible while not problem.is_admissible(s): s = problem.build_solution(method='Hill Climbing') s.id = [0, i] problem.evaluate_solution(s) solution_list.append(s) population = Population( problem = problem, maximum_size = population_size, solution_list = solution_list ) return population
def initialize_using_multiple(problem, population_size): """ Initialize a population of solutions (feasible solution) for an evolutionary algorithm using multiple algorithms: - One solution from greedy initialization - One solution from hill climbing initialization - The rest of the solutions from random initialization Required: @ problem - problem's build solution function knows how to create an individual in accordance with the encoding. @ population_size - to define the size of the population to be returned. """ solution_list = [] i = 0 # generate a population of admissible solutions (individuals) if population_size >= 10: while i in range(0, population_size): if i > 10: s = problem.build_solution(method='Random') elif i < 5: s = problem.build_solution(method='Greedy') else: s = problem.build_solution(method='Hill Climbing') if problem.is_admissible(s): s.id = [0, i] problem.evaluate_solution(s) solution_list.append(s) i += 1 else: while i in range(0, population_size): if i > 2: s = problem.build_solution(method='Random') elif i == 0: s = problem.build_solution(method='Greedy') else: s = problem.build_solution(method='Hill Climbing') if problem.is_admissible(s): s.id = [0, i] problem.evaluate_solution(s) solution_list.append(s) i += 1 population = Population( problem = problem, maximum_size = population_size, solution_list = solution_list ) return population
def initialize_using_sa(problem, population_size): params = {"Internal-Loop-Iterations": 20, "Max-Iterations": 250} sa = SimulatedAnnealing( problem_instance=problem, neighborhood_function=problem.get_neighbors, feedback=None, config=params, ) solution_list = [] population = Population(problem=problem, maximum_size=population_size, solution_list=solution_list) return population
def initialize_using_sa(problem, population_size, params={}): """ Initialize a population of solutions (feasible solution) for an evolutionary algorithm Required: @ problem - problem's build solution function knows how to create an individual in accordance with the encoding. @ population_size - to define the size of the population to be returned. @ params - the parameters to create the Simulated Annealing object (default: empty dictionary) """ solution_list = [] neighborhood_function = params["Neighborhood-Function"] # generate a population of admissible solutions (individuals) for _ in range(0, population_size): # initialize the Simulated Annealing class # notice that we need to create a new Simulated Annealing object for every iteration # because the initial value of C has to be always the same sa = SimulatedAnnealing(problem_instance=problem, neighborhood_function=neighborhood_function, params=params) # search for the optimal solution using Simulated Annealing s = sa.search() # there's no need to check if the solution is admissible # because Simulated Annealing already generates admissible solutions # get the fitness of the solution problem.evaluate_solution(s) # add the solution to the population solution_list.append(s) # create the Population object population = Population(problem=problem, maximum_size=population_size, solution_list=solution_list) return population
def initialize_using_ta(problem, population_size): params = {"Internal-Loop-Iterations": 50, "Max-Iterations": 800} ta = ThresholdAcceptance( problem_instance=problem, neighborhood_function=problem.get_single_neighbor, feedback=None, config=params, ) solution_list = [] for i in range(0, population_size): nn = ta.search() nn.id = [0, i] solution_list.append(nn) population = Population(problem=problem, maximum_size=population_size, solution_list=solution_list) return population
def initialize_using_ts(problem, population_size, params={}): """ Initialize a population of solutions (feasible solution) for an evolutionary algorithm Required: @ problem - problem's build solution function knows how to create an individual in accordance with the encoding. @ population_size - to define the size of the population to be returned. @ params - the parameters to create the Tabu Search object (default: empty dictionary) """ solution_list = [] neighborhood_function = params["Neighborhood-Function"] # initialize the Tabu Search class ts = TabuSearch(problem_instance=problem, neighborhood_function=neighborhood_function, params=params) # generate a population of admissible solutions (individuals) for _ in range(0, population_size): # find the optimal solution using Tabu Search s = ts.search() # there's no need to check if the solution is admissible # because Tabu Search already generates admissible solutions # get the fitness of the solution problem.evaluate_solution(s) # add the solution to the population solution_list.append(s) # create the Population object population = Population(problem=problem, maximum_size=population_size, solution_list=solution_list) return population
def initialize_using_hc(problem, population_size): params = { "Maximum-Iterations": 200, "Stop-Conditions": "Classical", "Neighborhood-Size": -1, } hc = HillClimbing( problem_instance=problem, neighborhood_function=problem.get_neighbors, feedback=None, params=params, ) solution_list = [] for i in range(0, population_size): nn = hc.search() nn.id = [0, i] solution_list.append(nn) population = Population(problem=problem, maximum_size=population_size, solution_list=solution_list) return population
def search(self): """ Genetic Algorithm - Search Algorithm 1. Initial population 2. Repeat n generations )(#1 loop ) 2.1. Repeat until generate the next generation (#2 loop ) 1. Selection 2. Try Apply Crossover (depends on the crossover probability) 3. Try Apply Mutation (depends on the mutation probability) 2.2. Replacement 3. Return the best solution """ problem = self._problem_instance select = self._selection_approach cross = self._crossover_approach mutate = self._mutation_approach replace = self._replacement_approach is_admissible = self._problem_instance.is_admissible self._generation = 0 self._notify(message="Genetic Algorithm") # 1. Initial population self._population = self._initialize(problem, self._population_size) self._fittest = self._population.fittest self._best_solution = self._fittest self._notify() #2. Repeat n generations )(#1 loop ) for self._generation in range(1, self._number_of_generations + 1): new_population = Population(problem=problem, maximum_size=self._population_size, solution_list=[]) i = 0 # 2.1. Repeat until generate the next generation (#2 loop ) while new_population.has_space: # 2.1.1. Selection parent1, parent2 = select(self._population, problem.objective, self._params) offspring1 = deepcopy(parent1) # parent1.clone() offspring2 = deepcopy(parent2) # parent2.clone() # 2.1.2. Try Apply Crossover (depends on the crossover probability) if self.apply_crossover: offspring1, offspring2 = cross(problem, parent1, parent2) offspring1.id = [self._generation, i] i += 1 offspring2.id = [self._generation, i] #i += 2 i += 1 # 2.1.3. Try Apply Mutation (depends on the mutation probability) if self.apply_mutation: offspring1 = mutate(problem, offspring1) offspring1.id = [self._generation, i] i += 1 if self.apply_mutation: offspring2 = mutate(problem, offspring2) offspring2.id = [self._generation, i] i += 1 # in our opinion the id's should be added after applying crossover and/or mutation, but we will not # change because it is not relevant # add the offsprings in the new population (New Generation) if new_population.has_space and is_admissible(offspring1): problem.evaluate_solution(offspring1) new_population.solutions.append(offspring1) if new_population.has_space and is_admissible(offspring2): problem.evaluate_solution(offspring2) new_population.solutions.append(offspring2) #print(f'Added O2 - {offspring2.id}-{offspring2.representation}') self._population = replace(problem, self._population, new_population) self._fittest = self._population.fittest self.find_best_solution() self._notify() self._notify(message="Fittest Solution") return self._fittest
def search(self): """ Genetic Algorithm - Search Algorithm 1. Initial population 2. Repeat n generations )(#1 loop ) 2.1. Repeat until generate the next generation (#2 loop ) 1. Selection 2. Try Apply Crossover (depends on the crossover probability) 3. Try Apply Mutation (depends on the mutation probability) 2.2. Replacement 3. Return the best solution """ problem = self._problem_instance select = self._selection_approach cross = self._crossover_approach mutate = self._mutation_approach replace = self._replacement_approach is_admissible = self._problem_instance.is_admissible self._generation = 0 self._notify(message="Genetic Algorithm") # 1. Initial population self._population = self._initialize(problem, self._population_size) self._fittest = self._population.fittest self._notify() self._store_population() # 2. Repeat n generations )(#1 loop ) for self._generation in range(1, self._number_of_generations + 1): new_population = Population(problem=problem, maximum_size=self._population_size, solution_list=[]) i = 0 # 2.1. Repeat until generate the next generation (#2 loop ) while new_population.has_space: # 2.1.1. Selection parent1, parent2 = select(self._population, problem.objective, self._params) offspring1 = problem.fast_solution_copy( parent1.representation) # parent1.clone() offspring2 = problem.fast_solution_copy( parent2.representation) # parent1.clone() # offspring1 = problem.build_solution(parent1.representation[:]) # parent2.clone() # offspring2 = problem.build_solution(parent2.representation[:]) # parent2.clone() # 2.1.2. Try Apply Crossover (depends on the crossover probability) if self.apply_crossover: offspring1, offspring2 = cross( problem, offspring1, offspring2 ) # I guess this was wrong here, I've replaced 'solution' by 'offspring' offspring1.id = [self._generation, i] i += 1 offspring2.id = [self._generation, i] i += 1 # 2.1.3. Try Apply Mutation (depends on the mutation probability) if self.apply_mutation: offspring1 = mutate(problem, offspring1) offspring1.id = [self._generation, i] i += 1 if self.apply_mutation: offspring2 = mutate(problem, offspring2) offspring2.id = [self._generation, i] i += 1 # # Don't allow Twins # solReps = [x.representation for x in new_population.solutions] # if offspring1.representation in solReps: # offspring1 = problem.get_single_neighbor(offspring1, problem) # if offspring2.representation in solReps: # offspring2 = problem.get_single_neighbor(offspring2, problem) # add the offsprings in the new population (New Generation) if new_population.has_space and is_admissible(offspring1): problem.evaluate_solution(offspring1) new_population.solutions.append(offspring1) if new_population.has_space and is_admissible(offspring2): problem.evaluate_solution(offspring2) new_population.solutions.append(offspring2) # print(f'Added O2 - {offspring2.id}-{offspring2.representation}') self._population = replace(problem, self._population, new_population) self._fittest = self._population.fittest self._notify() self._store_population() self._notify(message="Fittest Solution") return self._fittest