def test_simulation(): w = World(4) w.populate( Individual(is_zombie = True), 2, 1 ) w.populate( Individual(), 1, 2 ) w.simulate(moves = "DLUURR") score, positions = w.get_stats() # One victim assert 1 == score # Two zombies assert 2 == len(positions) # First at (3, 0) assert 3 == positions[0]['x'] assert 0 == positions[0]['y'] # Second at (2, 1) assert 2 == positions[1]['x'] assert 1 == positions[1]['y']
def populate(self, individual: Individual, x_coord: int = 0, y_coord: int = 0) -> None: """ Populate the world with an individual. Args: individual (Individual) : Individual of the world. Either a zombie or victim. x_coord (int) : The position, x coordinate, of the individual y_coord (int) : The position, y coordinate, of the individual """ # Save coordinates individual.x_coord = x_coord individual.y_coord = y_coord # Add to population self.population.append(individual) # Get the population index of this individual population_index = len(self.population) - 1 # Place the individual on the map self.map[x_coord][y_coord] = population_index # Add zombie to the queue to action if (individual.is_zombie): self.__enqueue(individual)
def test_moves(): individual = Individual(is_zombie=is_zombie, x_coord=x, y_coord=y, moves=moves) for m in moves: assert m.lower() == individual.get_move()
def test_add_score(): individual = Individual(is_zombie=is_zombie, x_coord=x, y_coord=y, moves=moves) individual.add_score(10) assert individual.score == 10
def ConstructPopulation(self): for _ in range(self.m_PopulationCount): individual = Individual(self.m_StopsCount, self.m_RoadLength, self.m_MutationProbability, self.m_MinStopsDistance, self.m_MaxStopsDistance, self.m_bannedAreas) individual.CreateIndividual() self.m_Population.append(individual)
def cabbage_growing(parent_1, parent_2): """ скрещивание 2х особей :param parent_1: родитель1 :param parent_2: родитель2 :return: 2 потомка особей """ # создание экземляров потомков son = Individual(GENE_LEN, gene_number) daughter = Individual(GENE_LEN, gene_number) if rnd.randint(0, 1): # псевдоравномерное скрещивание daughter.ind_gene = "".join(parent_2) son.ind_gene = "".join([ rnd.choices([parent_1, parent_2], [1, 1])[0][i] for i in range(GENE_LEN) ]) else: # создание 1 - точечного кроссовера border1 = rnd.randint(0, int(GENE_LEN // 2)) # son.ind_gene = "".join(parent_1[:border1] + parent_2[border1:]) daughter.ind_gene = "".join(parent_2[:(GENE_LEN - border1)] + parent_1[(GENE_LEN - border1):]) return son, daughter
def TournamentSelection(self): usedStops = [] newPopulation = [] while len(usedStops) < self.m_PopulationCount: firstChallanger = random.randint(0, self.m_PopulationCount - 1) secondChallanger = random.randint(0, self.m_PopulationCount - 1) if (firstChallanger not in usedStops and secondChallanger not in usedStops): usedStops.append(firstChallanger) usedStops.append(secondChallanger) if self.m_Population[ firstChallanger].m_Quality >= self.m_Population[ secondChallanger].m_Quality: newPopulation.append(self.m_Population[firstChallanger]) else: newPopulation.append(self.m_Population[secondChallanger]) self.m_Population = newPopulation for i in range(int(self.m_PopulationCount / 2), self.m_PopulationCount): self.m_Population.append( Individual(self.m_StopsCount, self.m_RoadLength, self.m_MutationProbability, self.m_MinStopsDistance, self.m_MaxStopsDistance, self.m_bannedAreas)) self.m_Population[i].CreateIndividual() self.m_Population[i].m_Quality = self.GoalFunction( self.m_Population[i]) x = lambda a: a.m_Quality self.m_Population.sort(key=x) if self.m_Population[0].m_Quality < self.m_AlfaMale.m_Quality: self.m_AlfaMale.m_Chromosome = self.m_Population[0].m_Chromosome[:] self.m_AlfaMale.m_Quality = self.m_Population[0].m_Quality
def __init__(self, halfPopulationCount, roadLength, stopsCount, popularPlaces, mutationProbability=0.05, mutationMethod='mr', iterationCount=10000, minStopsDistance=2, maxStopsDistance=8, bannedAreas=[]): self.m_PopulationCount = 2 * halfPopulationCount self.m_RoadLength = roadLength self.m_StopsCount = stopsCount self.m_PopularPlaces = popularPlaces self.m_Population = [] self.m_IterationCount = iterationCount self.m_MutationProbability = mutationProbability self.m_MutationMethod = mutationMethod self.m_MinStopsDistance = minStopsDistance self.m_MaxStopsDistance = maxStopsDistance self.m_bannedAreas = bannedAreas self.m_AlfaMale = Individual(self.m_StopsCount, self.m_RoadLength, self.m_MutationProbability, self.m_MinStopsDistance, self.m_MaxStopsDistance, self.m_bannedAreas) self.m_AlfaMale.m_Quality = math.inf
class Population: pop_size = 100 idv = Individual() def __init__(self): pass def creat_pop(self): P = [] for i in range(self.pop_size): P.append(self.idv.creat_one()) return P def next_Pop(self, Pop): n_P = [] idv = self.idv P = Pop p_size = len(P) for p in P: p = idv.reset_one(p) cp = idv.creat_one() cp.X[:] = p.X[:] cp.F_value[:] = p.F_value[:] n_P.append(cp) # 产生下一代 select(n_P) for i in range(p_size): j = np.random.randint(0, p_size, size=1)[0] cross(n_P[i], n_P[j]) n_P[j] = mutate(n_P[j]) return n_P
def __move(self, individual: Individual, direction: str) -> None: """ Move the individual around the map. This moves the individual according to the direction given. Zombie can move from one edge through the edge. Args: individual (Individual) : Individual of the world direction (str) : Direction for individual to move """ # Make sure to lowercase direction = direction.lower() # Going Up if (direction == 'u'): if (individual.y_coord == 0): if (individual.is_zombie): individual.y_coord = self.N - 1 else: individual.y_coord -= 1 # Going Down if (direction == 'd'): if (individual.y_coord == self.N - 1): if (individual.is_zombie): individual.y_coord = 0 else: individual.y_coord += 1 # Going Left if (direction == 'l'): if (individual.x_coord == 0): if (individual.is_zombie): individual.x_coord = self.N - 1 else: individual.x_coord -= 1 # Going Right if (direction == 'r'): if (individual.x_coord == self.N - 1): if (individual.is_zombie): individual.x_coord = 0 else: individual.x_coord += 1
def test_populate(): w = World(4) w.populate( Individual(), 1, 3 ) assert 1 == len(w.get_population())
def test_queeu_when_zombie_is_populated(): w = World(4) w.populate( Individual(is_zombie = True), 1, 3 ) assert 1 == len(w.get_queue())
def play(self) -> None: """ Run the world simulation """ i = 0 for inp in self.inputs: i += 1 print("Simulation: ", i) print("World: " + str(inp['n']) + " x " + str(inp['n'])) print() # Create world world = World(inp['n']) # Place zombie world.populate(Individual(is_zombie=True), inp['zombie']['x'], inp['zombie']['y']) # Place creatures for creature in inp['creatures']: world.populate(Individual(), creature['x'], creature['y']) # Simulate world.simulate(inp['moves']) # Get stats score, positions = world.get_stats() print("zombies' score: ", score) print("zombies' positions:") for position in positions: print("(" + str(position['x']) + ", " + str(position['y']) + ")", end=" ") print() print("---") print()
def test_has_no_move(): individual = Individual(is_zombie=is_zombie, x_coord=x, y_coord=y, moves=moves) while individual.has_move(): individual.get_move() assert individual.has_move() == False
def RankSelection(self): x = lambda a: a.m_Quality self.m_Population.sort(key=x) for i in range(int(self.m_PopulationCount / 2), self.m_PopulationCount): self.m_Population[i] = Individual(self.m_StopsCount, self.m_RoadLength, self.m_MutationProbability, self.m_MinStopsDistance, self.m_MaxStopsDistance, self.m_bannedAreas) self.m_Population[i].CreateIndividual() self.m_Population[i].m_Quality = self.GoalFunction( self.m_Population[i]) self.m_Population.sort(key=x) if self.m_Population[0].m_Quality < self.m_AlfaMale.m_Quality: self.m_AlfaMale.m_Chromosome = self.m_Population[0].m_Chromosome[:] self.m_AlfaMale.m_Quality = self.m_Population[0].m_Quality
def make_evaluation(population): """ проводит оценку особей популяции. :param population: оцениваемая популяция :return: лучшая особь """ master_individ = Individual( GENE_LEN, gene_number) # создание экземпляра доминантного индивида for i in range(POP_LEN): ind_list = list(population[i].ind_gene) degree = 1 for j in range(GENE_LEN): # оценка схожести с идеалом degree += 1 if GENE_LIST[j] == ind_list[j] else 0 population[i].ind_degree = degree # присвоение оценки # перезапись доминанта при совпадении условий master_individ = population[ i] if degree > master_individ.ind_degree else master_individ return master_individ
def RouletteSelection(self): goalFunctionSum = 0 for i in range(0, self.m_PopulationCount): goalFunctionSum += self.m_Population[i].m_Quality for i in range(0, self.m_PopulationCount): if random.random( ) < self.m_Population[i].m_Quality / goalFunctionSum: self.m_Population[i] = Individual(self.m_StopsCount, self.m_RoadLength, self.m_MutationProbability, self.m_MinStopsDistance, self.m_MaxStopsDistance, self.m_bannedAreas) self.m_Population[i].CreateIndividual() self.m_Population[i].m_Quality = self.GoalFunction( self.m_Population[i]) x = lambda a: a.m_Quality self.m_Population.sort(key=x) if self.m_Population[0].m_Quality < self.m_AlfaMale.m_Quality: self.m_AlfaMale.m_Chromosome = self.m_Population[0].m_Chromosome[:] self.m_AlfaMale.m_Quality = self.m_Population[0].m_Quality
def cabbage_growing(parent_1, parent_2): """ скрещивание 2х особей :param parent_1: родитель1 :param parent_2: родитель2 :return: 2 потомка особей """ # создание экземляров потомков son = Individual(GENE_LEN, gene_number) daughter = Individual(GENE_LEN, gene_number) parents = [parent_1, parent_2] # псевдоравномерное скрещивание son.ind_gene = "".join([ rnd.choices(parents, [1, rnd.uniform(1.1, 2.5)])[0][i] for i in range(GENE_LEN) ]) daughter.ind_gene = "".join([ rnd.choices(parents, [1, rnd.uniform(1.1, 2.5)])[0][i] for i in range(GENE_LEN) ]) # создание 1 - точечного кроссовера # recessive_gene = parents[0] # dominant_gene = parents[1] # border1 = rnd.randint(0, int(GENE_LEN//2)) # # son.ind_gene = "".join(recessive_gene[:border1] + # dominant_gene[border1:]) # daughter.ind_gene = "".join(dominant_gene[:(GENE_LEN-border1)] + # recessive_gene[(GENE_LEN-border1):]) return son, daughter
def __init__(self): self.populations = Population() ga.idv = Individual()
def test_coord(): individual = Individual(is_zombie=is_zombie, x_coord=x, y_coord=y, moves=moves) assert x == individual.x_coord and y == individual.y_coord
def make_genetic_algorithm(gene, gene_number): """ генетический алгоритм оптимизации :param gene: идеальный геном :param gene_number: возможная выборка генов :return: """ def make_evaluation(population): """ проводит оценку особей популяции. :param population: оцениваемая популяция :return: лучшая особь """ master_individ = Individual( GENE_LEN, gene_number) # создание экземпляра доминантного индивида for i in range(POP_LEN): ind_list = list(population[i].ind_gene) degree = 1 for j in range(GENE_LEN): # оценка схожести с идеалом degree += 1 if GENE_LIST[j] == ind_list[j] else 0 population[i].ind_degree = degree # присвоение оценки # перезапись доминанта при совпадении условий master_individ = population[ i] if degree > master_individ.ind_degree else master_individ return master_individ def get_selection(population): """ проведение селекции лучших особей методом рулетки :return: """ # делим популяцию поровну на готовых к селекции и нет best_individs = [] if rnd.randint(0, 1): # селекция рулеткой while len(best_individs) < 0.3 * POP_LEN: act_pop_len = len(population) # псевдослучайный выбор особи на скрещивание # winner = rnd.choices([i for i in range(act_pop_len)], # [population[i].ind_degree/act_pop_len for i in # range(act_pop_len)])[0] # winner = rnd.choices([i for i in range(act_pop_len)], # [population[i].ind_degree/math.log(math.e + (population[i].ind_degree)) for i in range(act_pop_len)])[0] # # турнир pretendents = [ rnd.randint(0, act_pop_len - 1) for i in range(1, 5) ] winner = rnd.choices( pretendents, [population[i].ind_degree for i in pretendents])[0] best_individs.append( population.pop(winner)) # добавление в список селекции else: # селекция усечением # сортировка популяции по оценкам и срез population = sorted(population, key=(lambda ind: ind.ind_degree)) best_individs = population[int(len(population) * 0.7):] population = population[:int(len(population) * 0.7)] return best_individs, population def cabbage_growing(parent_1, parent_2): """ скрещивание 2х особей :param parent_1: родитель1 :param parent_2: родитель2 :return: 2 потомка особей """ # создание экземляров потомков son = Individual(GENE_LEN, gene_number) daughter = Individual(GENE_LEN, gene_number) if rnd.randint(0, 1): # псевдоравномерное скрещивание daughter.ind_gene = "".join(parent_2) son.ind_gene = "".join([ rnd.choices([parent_1, parent_2], [1, 1])[0][i] for i in range(GENE_LEN) ]) else: # создание 1 - точечного кроссовера border1 = rnd.randint(0, int(GENE_LEN // 2)) # son.ind_gene = "".join(parent_1[:border1] + parent_2[border1:]) daughter.ind_gene = "".join(parent_2[:(GENE_LEN - border1)] + parent_1[(GENE_LEN - border1):]) return son, daughter def crossbreed_individs(best_individs): """ скрещивание особей :param best_individs: выборка особей на скрещивание :return: скрещенная популяция """ new_individs = [] ind_len = len(best_individs) while len(new_individs) < ind_len: # случайный выбор партнеров на скрешивание par_ind = [ rnd.randint(0, len(best_individs) - 1), rnd.randint(0, len(best_individs) - 1) ] # составление рабочих списков из выбранных особей degrees_list = sorted( [best_individs[par_ind[0]], best_individs[par_ind[1]]], key=lambda ind: ind.ind_degree) parents_list = [ list(degrees_list[0].ind_gene), list(degrees_list[1].ind_gene) ] coincidence = 0 # совпадение по генам for i in range(GENE_LEN): coincidence += 1 if parents_list[0][i] == parents_list[1][ i] == gene[i] else 0 " если худшая особь имеет некоторое количество оригинальных хороших" \ "генов, то пара скрещивается" if math.fabs(degrees_list[0].ind_degree - coincidence) >= 1: # скрещивание и добавление потомков в новую популяцию new_individs.extend( cabbage_growing(parents_list[0], parents_list[1])) # сокращение списка потенциальных партнеров best_individs = [ best_individs[i] for i in range(len(best_individs)) if i not in par_ind ] return new_individs def mutate_individs(feeble_individs): """ процесс мутации :param feeble_individs: :return: """ mutation_prob = 1 / GENE_LEN for i in range(len(feeble_individs)): individ_gene = list(feeble_individs[i].ind_gene) for j in range(GENE_LEN): if rnd.choices([0, 1], [1 - mutation_prob, math.fabs(mutation_prob)])[0]: individ_gene[j] = rnd.choice(gene_number) feeble_individs[i].ind_gene = "".join(individ_gene) return def output_inform(master): master_list = list(master.ind_gene) print( "".join([ "\033[34m{}".format(master_list[i]) if master_list[i] == GENE_LIST[i] else "\033[31m{}".format(master_list[i]) for i in range(GENE_LEN) ]), Style.RESET_ALL, master.ind_degree) def handle_genotype(pop): """ обработка популяции :param pop: популяция :return: новая популяция """ best_individs, feeble_individs = get_selection(pop) # селекция # print([best_individs[i].ind_degree for i in range(len(best_individs))], len(best_individs)) new_individs = crossbreed_individs(best_individs) # скрещивание mutate_individs(feeble_individs) # мутация return feeble_individs + new_individs # новая популяция GENE_LIST = list(gene) # разбивка строки на символьный список GENE_LEN = len(GENE_LIST) # длина генома POP_LEN = 20 # размер популяции STEP = 100 # шаг смены эры assert POP_LEN % 4 == 0, "Размер популяции приведет к зацикливанию" pop1 = [Individual(GENE_LEN, gene_number) for i in range(POP_LEN)] # создание новой популяции # pop2 = [Individual(GENE_LEN, gene_number) for j in range(POP_LEN)] # создание новой популяции # pop3 = [Individual(GENE_LEN, gene_number) for i in range(POP_LEN)] # создание новой популяции generation = 1 while True: print("\nERA:", generation // STEP, "GENERATION: ", generation % STEP) # оценка популяций master1 = make_evaluation(pop1) # master2 = make_evaluation(pop2) # master3 = make_evaluation(pop3) # вывод схожестей генов output_inform(master1) # output_inform(master2) # output_inform(master3) # условие выхода из алгоритма # if (master1.ind_degree > GENE_LEN) or (master2.ind_degree > GENE_LEN)\ # or (master3.ind_degree > GENE_LEN): break # if (master1.ind_degree > GENE_LEN) or (master2.ind_degree > GENE_LEN): break if (master1.ind_degree > GENE_LEN): break # проведение селекции, скрещивания и мутации pop1 = handle_genotype(pop1) # pop2 = handle_genotype(pop2) # pop3 = handle_genotype(pop3, master3.ind_degree) generation += 1
def test_is_zombie(): individual = Individual(is_zombie=is_zombie, x_coord=x, y_coord=y, moves=moves) assert is_zombie == individual.is_zombie
def test_has_move(): individual = Individual(is_zombie=is_zombie, x_coord=x, y_coord=y, moves=moves) assert individual.has_move() == True