Как решить проблему TSP с помощью пакета pyGAD?

Используя пакет PyGAD, как сгенерировать элемент популяций с элементом, не повторяющимся между 1 и 12? В случайной совокупности он всегда имеет двойное значение. У меня нет идеала, как этого избежать. Или мне следует манипулировать функцией обратного вызова при создании новой популяции?

import pandas as pd
import numpy as np
import pygad
xs = [8, 50, 18, 35, 90, 40, 84, 74, 34, 40, 60, 74]
ys = [3, 62, 0, 25, 89, 71, 7, 29, 45, 65, 69, 47]
cities = ['Z', 'P', 'A', 'K', 'O', 'Y', 'N', 'X', 'G', 'Q', 'S', 'J']
locations = list(zip(xs, ys, cities))

def fitness_func(solution, solution_idx):
    # Calculating the fitness value of each solution in the current population.
    # The fitness function calulates the sum of products between each input and its corresponding weight.
    # output = numpy.sum(solution*function_inputs)
    # fitness = 1.0 / numpy.abs(output - desired_output)
    
    total_length = 0
    itemidx=0
    
    for loc in solution:
        if itemidx>0 :
            cityidx1 = loc-1
            cityidx2 =solution[itemidx-1]-1   
            total_length +=((xs[cityidx1] - xs[cityidx2]) ** 2 + (ys[cityidx1] - ys[cityidx2]) ** 2) ** (1 / 2)  
            # print(xs[cityidx1],ys[cityidx1], xs[cityidx1], ys[cityidx2],total_length )
        elif  itemidx==solution.size :
            cityidx1 = loc-1
            cityidx2 =solution[itemidx-1]-1 
            total_length +=((xs[cityidx1] - xs[cityidx2]) ** 2 + (ys[cityidx1] - ys[cityidx2]) ** 2) ** (1 / 2)  
            if ((xs[cityidx1] - xs[cityidx2]) ** 2 + (ys[cityidx1] - ys[cityidx2]) ** 2) ** (1 / 2)  <0:
                print('ERROR',((xs[cityidx1] - xs[cityidx2]) ** 2 + (ys[cityidx1] - ys[cityidx2]) ** 2) ** (1 / 2)  )
            # print(xs[cityidx1],ys[cityidx1], xs[cityidx1], ys[cityidx2],total_length )
            
            cityidx2 =solution[0] 
            total_length +=((xs[itemidx] - xs[0]) ** 2 + (ys[itemidx] - ys[0]) ** 2) ** (1 / 2) 
            # print(total_length)
        itemidx += 1
    #print("fitness_func",total_length,solution,solution_idx)    
    return total_length*-1 #fitness

fitness_function = fitness_func
num_generations = 50 # Number of generations.
num_parents_mating = 7 # Number of solutions to be selected as parents in the mating pool.
sol_per_pop = 50 # Number of solutions in the population.
num_genes = 12  

init_range_low = 1
init_range_high = 12

parent_selection_type = "rank" # Type of parent selection.
keep_parents = 7 # Number of parents to keep in the next population. -1 means keep all parents and 0 means keep nothing.

crossover_type = "single_point" # Type of the crossover operator.

# Parameters of the mutation operation.
mutation_type = "swap" # Type of the mutation operator.
mutation_percent_genes = 10 

last_fitness = 0
population_list=[]
gene_space = [i for i in range(1, 13)]
for i in range(sol_per_pop):
    nxm_random_num=list(np.random.permutation(gene_space)) 
    population_list.append(nxm_random_num) # add to the population_list
ga_instance = pygad.GA(num_generations=num_generations,
                       num_parents_mating=num_parents_mating, 
                       fitness_func=fitness_function,
                       sol_per_pop=sol_per_pop, 
                       initial_population=population_list,
                       num_genes=num_genes,

                       gene_space = gene_space, #  
                    #    init_range_low=init_range_low,
                    #    init_range_high=init_range_high,

                       parent_selection_type=parent_selection_type,
                       keep_parents=keep_parents,
                       crossover_type=crossover_type,
                       mutation_type=mutation_type,
                       mutation_percent_genes=mutation_percent_genes
                       )
ga_instance.run()
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("best_solution: {solution}".format(solution =solution)) 

#best_solution: [ 3  4 12 10  6  9  2 10 12 10  6  9] 
#**Is any way to get new gerneration that elements not duplication**


Любая помощь будет высоко ценится!


person lokcyi    schedule 21.02.2021    source источник
comment
вы можете поделиться чем-нибудь, что вы написали? Минимум воспроизводимый код?   -  person Ajay    schedule 21.02.2021
comment
Обычно вы сортируете range (n), используя вектор решения в качестве ключевой функции, но было бы полезно иметь код.   -  person David Eisenstat    schedule 21.02.2021
comment
Пример кода прилагается. Любая помощь будет высоко ценится!   -  person lokcyi    schedule 23.02.2021
comment
@lokcyi где дублирование не ожидается. Внутри каждого элемента списка или между элементами списка? Если внутри каждого элемента, проверьте его наличие и продолжайте цикл, чтобы добавить еще один. Если между циклами у вас может не быть другого выбора, кроме как сохранить результирующие элементы списка, сгенерированные в общем хранилище списков, и проверить на дублирование и повторить цикл, чтобы добавить недубликат. Во-вторых, в Pandas есть функция удаления дубликатов и проверки дубликатов. Это работает для ваших нужд?   -  person Gary    schedule 23.02.2021
comment
@ Gary. Мой вопрос - это дублирование элементов в каждом списке. Как и в лучшем решении [3 4 12 10 6 9 2 10 12 10 6 9], 10 и 6 показаны дважды. Я хочу, чтобы каждый элемент был от 1 до 12 показывать один раз в одном списке. Но я понятия не имею, где и как манипулировать геном кроссовера нового поколения. Кажется, этот процесс автоматизируется самим пакетом.   -  person lokcyi    schedule 24.02.2021
comment
Привет, обратите внимание, что выпущен PyGAD 2.13.0, который поддерживает новый параметр bool, называемый allow_duplicate_genes. Если установлено значение False, то в растворе не будет дублирующихся генов. Подробнее читайте здесь: pygad.readthedocs.io/ ru / latest /   -  person Ahmed Gad    schedule 13.03.2021


Ответы (1)


Обновлять

Выпущен PyGAD 2.13.0, который поддерживает новый параметр типа bool с именем allow_duplicate_genes. Если установлено значение False, то в растворе не будет дублирующихся генов. Подробнее читайте здесь: https://pygad.readthedocs.io/en/latest/README_pygad_ReadTheDocs.html#prevent-duplicates-in-gene-values

.........................................

Благодарим за использование PyGAD :)

Функция отклонения повторяющихся генов в решении пока не поддерживается в PyGAD. Таким образом, вы можете ожидать повторяющихся значений.

Это очень хорошая функция для поддержки в следующем выпуске PyGAD (2.13.0). Спасибо, что задали этот вопрос.

До следующего выпуска вы можете создать свою собственную функцию мутации, чтобы отклонять повторяющиеся значения. Просто выполните следующие действия:

  1. Отключите мутацию, установив для аргумента mutation_type в конструкторе класса pygad.GA значение None:
mutation_type=None
  1. Создайте свою собственную операцию мутации, которая применяет мутацию без дубликатов:
def mut(...):
   result = ....
   return result 
  1. Реализуйте функцию обратного вызова on_crossover(). Эта функция вызывается сразу после завершения операции кроссовера. Там вы получаете сборку массива после кроссовера [который автоматически передается в качестве аргумента функции обратного вызова], применяете свою собственную мутацию и сохраняете результат обратно для использования PyGAD.

Вы можете проверить жизненный цикл PyGAD для получения дополнительной информации о функциях обратного вызова.

def on_crossover(ga_instance, offspring_crossover):
    # 1) Apply your mutation on the solutions in the offspring_crossover array.
    # Assume the mutation offspring is saved in the offspring_mutation array.
    offspring_mutation  = mut(offspring_crossover)

    2) Save the result in the last_generation_offspring_mutation attribute of ga_instance:
    ga_instance.last_generation_offspring_mutation = offspring_mutation

    # The previous links makes the next population to use your mutation offspring.
  1. Назначьте функцию обратного вызова кроссовера аргументу on_crossover в конструкторе класса pygad.GA:
on_crossover=on_crossover

Это все.

person Ahmed Gad    schedule 24.02.2021