def create_tree(root_id): # odd numbers are ids of terminal nodes, the others are non-terminal nodes. n1 = node.Node(root_id) n2 = node.Node(2) n3 = node.Node(1) n4 = node.Node(3) n5 = node.Node(5) node.set_children(n1, [n2, n3]) node.set_children(n2, [n4, n5]) s = solution.Solution(n1) solution.set_previous_fitness(s, root_id) return s
def donate(self, recipient, cross_point, donor): """ Replace a sub-tree of the recipient with a donor :param recipient: solution object. recipient of the MLPS-GP crossover. :param cross_point: node object. a crossover point. :param donor: node object. root node of subtree(donor's root). :return: bool. if fitness is improved or not. """ stop = False previous_fitness = recipient.previous_fitness parent_node, index = cross_point pre_node = parent_node.children[index] # TODO: check if the pre_node and the donor is same sub-tree, if so, we don't have to check the fitness of the new solution. parent_node.children[index] = donor.root fitness = self.problem.fitness(recipient) if previous_fitness >= fitness: parent_node.children[index] = pre_node solution.set_previous_fitness(recipient, previous_fitness) else: stop = True return stop
def test_stop_improvement_with_shuffle(self): root = self.s1.root c1 = root.children[0] c2 = root.children[1] is_shuffle = True flg2 = False flg4 = False for i in range(100): improved = localsearch.stop_improvement(self.s1, root, self.problem, is_shuffle=is_shuffle) if i == 0: self.assertEqual(improved, True) if root.func_id == 2: flg2 = True node.set_id(root, self.root_id) solution.set_previous_fitness(self.s1, self.root_id) elif root.func_id == 4: flg4 = True node.set_id(root, self.root_id) solution.set_previous_fitness(self.s1, self.root_id) if flg2 and flg4: break self.assertEqual(flg2 and flg4, True) improved = localsearch.stop_improvement(self.s1, c1, self.problem, is_shuffle=is_shuffle) self.assertEqual(improved, False) improved = localsearch.stop_improvement(self.s1, c2, self.problem, is_shuffle=is_shuffle) self.assertEqual(improved, False)
def improve(target_solution, target_node, candidate_id, problem): """ Core function for local search. Replace the old function with a new function and then revert it if fitness is not improved. :param target_solution: solution object. target solution of local search. :param target_node: node object. target node of the target solution. :param candidate_id: int. ID of candidate function for local search. :param problem: problem object. problem for calculation of fitness. :return: bool. if improvement is success, return True. """ pre_id = target_node.func_id node.set_id(target_node, candidate_id) if target_solution.previous_fitness is None: # if the solution does not have previous fitness, calculate it. pre_fit = problem.fitness(target_solution) else: pre_fit = target_solution.previous_fitness new_fit = problem.fitness(target_solution) # check the fitness. if pre_fit >= new_fit: # if it is not success, revert the function. node.set_id(target_node, pre_id) solution.set_previous_fitness(target_solution, pre_fit) return False else: return True
def bihc(target_solution, node_list, fs_core): """ Best improvement hill climber (BIHC) function. :param node_list: list of node object. candidate node list. :param fs_core: function. search function for a target node. :return: solution object. """ pre_node = None while node_list: ori_fit = target_solution.previous_fitness best_fit = target_solution.previous_fitness best_node = None best_id = None for target_node in node_list: # Try to find the best-improving target node and the function id. ori_id = target_node.func_id fs_core(target_solution, target_node) if best_fit < target_solution.previous_fitness: best_node = target_node best_id = target_node.func_id # the target solution is reverted to the original for the next iteration. node.set_id(target_node, ori_id) solution.set_previous_fitness(target_solution, ori_fit) # If there is no improvement, end this local search. if best_node is None: break # Otherwise, adopt the improvement to the solution. node.set_id(best_node, best_id) solution.set_previous_fitness(target_solution, best_fit) if pre_node is not None: node_list.append(pre_node) node_list.remove(best_node) # remove the replaced node from candidate node list pre_node = best_node return target_solution
def fitness(self, target_solution_or_solutions): """ calculate the fitness of target solution(s) :param target_solution_or_solutions: solution object or list of solution objects. solution to calculate fitness. :return: fitness or list of fitness. """ if isinstance(target_solution_or_solutions, Solution): fitness = self._cal_fitness(target_solution=target_solution_or_solutions) self._eval_cnt += 1 solution.set_previous_fitness(target_solution_or_solutions, fitness) self._elite_fitness = max(self._elite_fitness, fitness) return fitness elif isinstance(target_solution_or_solutions, list): fitness_list = [] for target_solution in target_solution_or_solutions: fitness = self._cal_fitness(target_solution=target_solution) solution.set_previous_fitness(target_solution, fitness) fitness_list.append(fitness_list) self._elite_fitness = max(self._elite_fitness, fitness) self._eval_cnt += len(target_solution_or_solutions) return fitness_list else: raise TypeError("target_solution_or_solutions should be Solution object or list of Solution objects.")
def get_population(): s1 = solution.Solution(node.Node()) s2 = solution.Solution(node.Node()) s3 = solution.Solution(node.Node()) solution.set_previous_fitness(s1, 1) solution.set_previous_fitness(s2, 2) solution.set_previous_fitness(s3, 3) pop = [] for _ in range(2): pop.extend([s1, s2, s3]) pop = pop * 2 return pop
def __init__(self): self.population = [] self.n_set = 2 for i in range(self.n_set): s1 = self.create_tree_type1() s2 = self.create_tree_type2() s3 = self.create_tree_type3() solution.set_previous_fitness(s1, 1) solution.set_previous_fitness(s2, 2) solution.set_previous_fitness(s3, 3) self.population.append(s1) self.population.append(s2) self.population.append(s3) self.population = self.population * 2