Генетический алгоритм (GA) – это тип алгоритма, вдохновленного процессом естественного отбора для создания высококачественных решений для проблем, которые в противном случае были бы слишком сложно решить.
Путешествуя продавцом проблему или TSP для короткой, является печально известной проблемой, когда человек путешествует, где человек путешествует, чтобы путешествовать различные города с известным расстоянием и возвращение в город происхождения в кратчайшие сроки/путь.
Как приведено ниже, каждый круг – это городская и синяя линия – это маршрут, посещающий их.
Почему бы не грубые силы ??
Хорошо, давайте попробуем грубую силу, чтобы решить проблему. Для начала давайте возьму 5 городов, то есть, мы должны рассчитать 5!
, то есть 120 маршрутов, чтобы убедиться, что мы получили кратчайший путь.
Теперь, если мы должны сделать это за 50
города,
-
5!
10!
15!
20!
50!
Мы видим, насколько грубым принуждением наш путь просто не будет полезным здесь.
Давайте попробуем GA
Итак, мы увидим, как Генетический алгоритм
Может помочь нам найти оптимальный кратчайший путь здесь.
Простым, генетический алгоритм работает следующим образом,
- Выбор случайных начальных решений/хромосом (называется как
начальная популяция
или хромосомы) кроссовер
(генерируя новое решение или хромосому, по видам смешивания двух родительских хромосом/растворов)Мутате
(Делать незначительное изменение в решении)Фитнес
(Проверка, если решение полезно или полностью заполнено нашему требованию), если да, мы используем их для создания новых потомков (родители в следующем поколении), и цикл продолжается для многих поколений, которые мы хотим.
Так .. для наших TSP
Проблема, мы сделаем следующее:
Генерировать города
function generate_cities(number_of_cities, map_limit) cities = [] for city_counter in 1:number_of_cities push!(cities, Dict( "id" => city_counter, "x" => round(rand() * map_limit), "y" => round(rand() * map_limit) ) ) end println("Cities Generated:", size(cities)[1]) return cities end # calling generate_cities method to create cities generate_cities(5,500)
Мы храним город как словарь.
У каждого города есть ID
и (х, у)
место нахождения
("id" => 1,"x" => 480.0,"y" => 157.0) ("id" => 2,"x" => 4.0,"y" => 465.0) ("id" => 3,"x" => 57.0,"y" => 25.0) ("id" => 4,"x" => 411.0,"y" => 322.0) ("id" => 5,"x" => 44.0,"y" => 460.0)
Представляя решение как хромосома.
Решение для нашей проблемы – это маршрут из одного города в другой город. Мы можем написать его как массив целых чисел, где каждый номер представляет собой идентификатор города.
[1,2,5,4,3,1]
Итак, для вышеупомянутого маршрута или хромосомы, мы начинаем с City1 -> City 2 и так далее … наконец вернуться в City1.
Функция кроссовера
Здесь мы генерируем новую хромосому, принимая значения из двух родительских хромосом. Для этой проблемы мы просто должны обеспечить, чтобы гены/город города не повторяются, при создании новой хромосомы.
Есть много способов сделать кроссовер, как, UniPoint Crossover, многоточечный кроссовер и т. Д. Мы сделаем UniPoint Crossover, просто выбрав случайную точку в хромосоме и выполняющую простой своп, чтобы создать новую хромосому.
function crossover(parent_one_chromosome, parent_two_chromosome, crossover_point) offspring_part_one = parent_one_chromosome[1:crossover_point] for gene in offspring_part_one if gene in parent_two_chromosome gene_loc = findfirst(el -> el == gene, parent_two_chromosome) splice!(parent_two_chromosome, gene_loc) end end return vcat(offspring_part_one, parent_two_chromosome) end
Функция мутации
В простых терминах мутации можно определить как случайное изменение в хромосоме. Здесь мы просто поменяем два положения гена.
function mutate(offspring) random_mutation_point1 = rand(1:length(offspring)) random_mutation_point2 = rand(1:length(offspring)) offspring[random_mutation_point1], offspring[random_mutation_point2] = offspring[random_mutation_point2], offspring[random_mutation_point1] return offspring end
Фитнес функция
Ответственность Фитнес-функции заключается в том, чтобы рассчитать оценку каждого хромосома, чтобы мы могли решить, хотите ли мы использовать эту хромосому в следующем поколении или для отказа.
Для нашей проблемы счет – это расстояние поездки для данного маршрута/хромосомы. Нижнее расстояние перемещения лучше.
Для расчета расстояния поездки мы просто начнем с 1-го города, перейдите к следующему А потом к следующему, так и вернусь к городу происхождения, добавив расстояние, которое мы путешествовали, мы получаем счет этого конкретного маршрута.
function calculate_distance_between_two_points(point1, point2) return sqrt((((point2[1] - point1[1]))^2) + (((point2[2] - point1[2]))^2)) end function calculate_chromosome_travel_distance(chromosome) travel_distance = 0 chromosome = vcat(1, chromosome, 1) for geneId in 1:length(chromosome) - 1 point1 = ( cities[chromosome[geneId]]["x"], cities[chromosome[geneId]]["y"] ) point2 = ( cities[chromosome[geneId + 1]]["x"], cities[chromosome[geneId + 1]]["y"] ) travel_distance += calculate_distance_between_two_points(point1, point2) end println("travel distance:", chromosome, " : ", travel_distance) return travel_distance end
Генерация IISIAL населения:
Мы определим функцию, которая может генерировать начальные группы населения.
# We shuffle the chromosome here function shuffle_chromosome(chromosome) for i in 1:size(chromosome)[1] random_point = rand(1:5, 1)[1] chromosome[i], chromosome[random_point] = chromosome[random_point], chromosome[i] end println("Created chromosome", chromosome) return chromosome end function generate_initial_population(initial_population_size) chromosomes = [] for population_counter in 1:initial_population_size chromosome = shuffle_chromosome(copy(initial_chromosome)) push!(chromosomes, Dict( "chromosome" => chromosome, "distance" => calculate_chromosome_travel_distance(chromosome) ) ) end return chromosomes end
[3, 9, 4, 8, 10, 5, 1, 2, 7, 6] [8, 1, 6, 9, 10, 5, 2, 4, 3, 7] [2, 9, 10, 8, 5, 4, 6, 1, 3, 7] [5, 6, 10, 7, 4, 3, 1, 2, 8, 9] [2, 10, 9, 4, 6, 5, 1, 3, 8, 7]
основная часть
Здесь мы определили функцию, которая запускает GA для заданного количества поколений, и создает заданное количество потомков для каждого поколения, затем проверяет фитнес и цикл продолжается для каждого поколения.
function evolve(generation_count, offsprings_count, crossover_point) for generation in 1:generation_count for offspring_count in 1:offsprings_count println("generation: ", generation, " offspring: ", offspring_count) random_parent_one_id = rand(1:size(chromosomes)[1]) random_parent_two_id = rand(1:size(chromosomes)[1]) random_parent_one = copy(chromosomes[random_parent_one_id]["chromosome"]) random_parent_two = copy(chromosomes[random_parent_two_id]["chromosome"]) offspring = crossover(random_parent_one, random_parent_two, crossover_point) offspring = mutate(offspring) push!(chromosomes, Dict( "chromosome" => offspring, "distance" => calculate_chromosome_travel_distance(offspring) ) ) end sort!(chromosomes, by=x -> x["distance"], rev=false) splice!(chromosomes, 6:size(chromosomes)[1]) end end
Теперь давайте выполним GA
# creating 10 cities randomly cities = generate_cities(10, 500) initial_chromosome = [2:length(cities);] # generating 10 initial chromosomes chromosomes = generate_initial_population(10) # we are running GA for # 5 generations # 5 offsprings per generation # random crossover point as 2 evolve(5, 5, 2) println("--------------------------------------------------------") println("Optimal route:", vcat(1, chromosomes[1]["chromosome"], 1)) println("travel_distance:", chromosomes[1]["distance"])
Если мы выполним, мы получаем следующий вывод.
generation: 1 offspring: 1 travel distance:[1, 3, 9, 10, 7, 5, 4, 6, 8, 2, 1] : 2780.551726305925 generation: 1 offspring: 2 travel distance:[1, 5, 10, 6, 9, 3, 2, 4, 7, 8, 1] : 2236.035984494435 generation: 1 offspring: 3 travel distance:[1, 10, 7, 3, 9, 5, 4, 6, 8, 2, 1] : 2627.3533869849102 generation: 1 offspring: 4 travel distance:[1, 7, 6, 4, 10, 3, 5, 2, 8, 9, 1] : 3078.2871083508203 generation: 1 offspring: 5 travel distance:[1, 3, 9, 10, 7, 2, 4, 5, 8, 6, 1] : 3074.581278954089 generation: 2 offspring: 1 travel distance:[1, 9, 8, 5, 10, 4, 3, 2, 6, 7, 1] : 2882.8847896850843 generation: 2 offspring: 2 travel distance:[1, 5, 10, 6, 2, 3, 9, 4, 7, 8, 1] : 1864.9566066991729 generation: 2 offspring: 3 travel distance:[1, 9, 8, 5, 10, 2, 3, 4, 6, 7, 1] : 2889.200659672017 generation: 2 offspring: 4 travel distance:[1, 4, 10, 6, 9, 3, 2, 5, 7, 8, 1] : 2520.4527035595024 generation: 2 offspring: 5 travel distance:[1, 9, 10, 6, 3, 5, 2, 4, 7, 8, 1] : 2443.441192706744 generation: 3 offspring: 1 travel distance:[1, 2, 10, 6, 9, 8, 5, 7, 4, 3, 1] : 2177.1886229349225 generation: 3 offspring: 2 travel distance:[1, 2, 10, 5, 6, 9, 8, 7, 4, 3, 1] : 1745.6328718972204 generation: 3 offspring: 3 travel distance:[1, 5, 4, 2, 6, 9, 8, 7, 10, 3, 1] : 2491.210252809206 generation: 3 offspring: 4 travel distance:[1, 7, 5, 6, 9, 3, 2, 4, 10, 8, 1] : 2867.790574182069 generation: 3 offspring: 5 travel distance:[1, 10, 6, 5, 9, 3, 2, 7, 4, 8, 1] : 2158.331962819929 generation: 4 offspring: 1 travel distance:[1, 4, 10, 6, 2, 3, 9, 5, 7, 8, 1] : 2375.395804596975 generation: 4 offspring: 2 travel distance:[1, 4, 10, 2, 6, 9, 8, 5, 7, 3, 1] : 2696.2819714580255 generation: 4 offspring: 3 travel distance:[1, 5, 3, 6, 9, 10, 2, 7, 4, 8, 1] : 2585.1841206421177 generation: 4 offspring: 4 travel distance:[1, 4, 6, 2, 9, 8, 5, 7, 10, 3, 1] : 2927.589295286965 generation: 4 offspring: 5 travel distance:[1, 5, 3, 10, 6, 9, 7, 2, 4, 8, 1] : 2610.376635133937 generation: 5 offspring: 1 travel distance:[1, 3, 10, 5, 6, 9, 8, 7, 4, 2, 1] : 1919.461172591361 generation: 5 offspring: 2 travel distance:[1, 10, 6, 8, 9, 3, 2, 7, 4, 5, 1] : 2488.399757690674 generation: 5 offspring: 3 travel distance:[1, 6, 10, 3, 5, 9, 8, 7, 4, 2, 1] : 1962.725547491429 generation: 5 offspring: 4 travel distance:[1, 10, 6, 8, 9, 4, 2, 7, 3, 5, 1] : 2626.455096698985 generation: 5 offspring: 5 travel distance:[1, 2, 6, 5, 10, 3, 9, 4, 7, 8, 1] : 1631.463753062698 -------------------------------------------------------- Optimal route:[1, 2, 6, 5, 10, 3, 9, 4, 7, 8, 1] travel_distance:1631.463753062698
Я создал TSP-GA Playground, используя Tymdercript, оформить заказ, если вы хотите воспроизвести: https://dillir07.github.io/genetic-algorithm-tsp/
Julia – исходный код доступен в Гадость
Спасибо за чтение:) … Комментарии приветствуются.
Оригинал: “https://dev.to/dillir07/genetic-algorithm-travelling-salesman-with-julia-477a”