El algoritmo genético resuelve el problema del vendedor ambulante TSP (numpy, pandas)

inserte la descripción de la imagen aquí

El trabajo duro no es ser mediocre ~

La mayor razón para aprender es deshacerse de la mediocridad, un día antes, habrá más esplendor en la vida, un día después, un día más mediocridad.

Tabla de contenido

I. Introducción

principio:

pregunta:

2. Pasos de la idea

 3. Pasos de escritura de código

A. El método, propósito y significado de cada paso del código

1. Importe las bibliotecas requeridas:

2. Parte de los datos del proceso:

3. Obtenga la parte de la matriz de distancia:

4. Establecer los parámetros del algoritmo genético:

5. Calcular la función de fitness:

6. Mejora de la población inicial:

7. Selección natural:

8. Cruzamiento:

9. Operación de mutación:

10. La función de get_result

11. Inicializar la población

12. Proceso iterativo

13. Convierte la ruta del individuo óptimo al orden de las ciudades

14. Traza el resultado

B. Diagrama de flujo del algoritmo genético para resolver el problema TSP

 4. Código completo

conjunto de datos


I. Introducción

principio:

El problema del viajante de comercio, problema TSP (Traveling Salesman Problem) es uno de los problemas más famosos en el campo de las matemáticas. Suponiendo que un hombre de negocios viajero quiere visitar n ciudades, debe elegir el camino que quiere tomar, el límite de la ruta es que cada ciudad solo puede ser visitada una vez, y finalmente debe regresar a la ciudad original de donde partió. El objetivo de la selección de ruta es que la distancia de ruta requerida sea el valor mínimo entre todas las rutas. El problema TSP es un problema de optimización combinatoria. Se puede demostrar que el problema tiene complejidad computacional NPC. Por lo tanto, cualquier método que pueda simplificar la solución de este problema será muy evaluado y se le prestará atención.

La idea básica del algoritmo genético se basa en imitar el proceso genético de la genética biológica. Representa los parámetros del problema con los genes, y la solución del problema con los cromosomas (expresados ​​en códigos binarios en la computadora), para obtener un grupo compuesto por individuos con diferentes cromosomas. El grupo compite por la supervivencia en un entorno de problema específico, y el más apto tiene la mejor oportunidad de sobrevivir y producir descendencia. Los descendientes heredan al azar los mejores rasgos de sus padres y continúan este proceso bajo el control de su entorno. Los cromosomas de la población se irán adaptando gradualmente al entorno, seguirán evolucionando y finalmente convergerán en un grupo de individuos similares que sean los más adecuados para el entorno, es decir, para obtener la solución óptima al problema. Se requiere utilizar el algoritmo genético para resolver el camino más corto del problema TSP.

pregunta:

1. Consulte el algoritmo genético proporcionado por el sistema experimental para realizar operaciones relacionadas, use el algoritmo genético para resolver el problema de optimización de TSP y analice el rendimiento del algoritmo del algoritmo genético para resolver problemas de TSP de diferentes escalas.

2. Para el mismo problema de TSP, analice el impacto del tamaño de la población, la probabilidad de cruce y la probabilidad de mutación en los resultados del algoritmo.

3. Dibuje el diagrama de flujo del algoritmo genético para resolver el problema TSP.

4. Analizar el rendimiento del algoritmo del algoritmo genético para resolver problemas TSP de diferentes escalas.

5. Para el mismo problema TSP, analice el impacto del tamaño de la población, la probabilidad de cruce y la probabilidad de mutación en los resultados del algoritmo.

2. Pasos de la idea

1. Después del procesamiento de datos y el cálculo de la matriz de distancia, definimos algunos parámetros que deben usarse en el algoritmo, como el número de poblaciones, el número de iteraciones, la probabilidad de selección óptima, la probabilidad de supervivencia de los débiles y el tasa de mutación.

2. Luego, definimos una función get_total_distance(x) que calcula la aptitud individual (longitud del camino). Esta función atraviesa cada ciudad en el individuo, calcula la distancia entre ciudades y acumula la longitud total de la ruta.

3. A continuación, definimos una función de mejora gailiang(x), que se utiliza para mejorar los individuos de la población inicial. La función selecciona aleatoriamente dos ciudades, intercambia sus ubicaciones y actualiza al individuo si el individuo mejorado tiene una ruta de acceso más corta.

4. Luego, definimos la función de selección natural nature_select(población). Esta función clasifica la población de acuerdo con la aptitud de los individuos y selecciona a los individuos con mayor aptitud como los fuertes, y selecciona a algunos individuos con menor aptitud como los débiles de acuerdo con la probabilidad de selección óptima.

5. A continuación, definimos la función de cruce crossover(parents). Esta función selecciona aleatoriamente dos individuos de la generación de padres y selecciona aleatoriamente un punto de intersección, intercambia los segmentos de genes entre los puntos de intersección y genera dos individuos descendientes.

6. Luego, definimos la función de operación de mutación mutación (hijos). Esta función atraviesa los individuos descendientes, selecciona aleatoriamente dos posiciones de genes según la tasa de mutación e intercambia sus valores, introduciendo aleatoriedad y aumentando la diversidad de la población.

7. Después de completar la operación principal del algoritmo genético, inicializamos la población y comenzamos la optimización iterativa. En cada generación, primero llevamos a cabo la operación de selección natural y seleccionamos a los individuos con mayor aptitud como padres. Luego genera descendencia de individuos a través de la operación de cruzamiento. A continuación, se realiza la operación de mutación en los individuos descendientes. Finalmente, la población se actualiza y los padres e hijos se fusionan en una nueva población.

8. Después del final de cada generación, calculamos la aptitud y la longitud del camino del mejor individuo de la población, y agregamos la longitud del camino a la lista de distancias.

9. Al iterar varias veces y actualizar continuamente la población, encontramos gradualmente al individuo con la aptitud más alta, es decir, el camino óptimo para resolver el problema TSP.

10. Finalmente, imprimimos el orden de la ruta óptima y la distancia correspondiente, y dibujamos un diagrama del proceso de optimización para mostrar el cambio de la ruta y el progreso de la optimización.

A través de un proceso iterativo de este tipo, el algoritmo genético puede optimizar gradualmente la población y encontrar al individuo con la aptitud más alta, es decir, el camino óptimo.

 3. Pasos de escritura de código

A. El método, propósito y significado de cada paso del código

1. Importe las bibliotecas requeridas:

    

 Estas bibliotecas se utilizan para funciones como el cálculo numérico, la manipulación de datos, el trazado y la generación de números aleatorios.

2. Parte de los datos del proceso:

 Esta parte del código lee los datos de coordenadas del archivo y los almacena en una matriz NumPy llamada coordenadas. Primero, abra el archivo y lea el contenido del archivo línea por línea, luego divida cada línea y agregue los valores de coordenadas obtenidos a la lista de coordenadas. A continuación, convierta la lista de coordenadas en una matriz NumPy e inicialice una matriz de coordenadas de cero con el mismo tamaño que la matriz de coordenadas. Finalmente, convierta los valores de las coordenadas en la matriz de coordenadas a coma flotante y guárdelos en la matriz de coordenadas.

3. Obtenga la parte de la matriz de distancia:

 Esta parte del código se usa para calcular la distancia euclidiana entre ciudades y construir una matriz de distancia. Primero, cree una distancia de matriz bidimensional de todos los ceros con un tamaño de (w, w), donde w es el número de ciudades. Luego, use un ciclo de dos capas para iterar sobre todas las combinaciones de ciudades y calcular la distancia euclidiana entre cada par de ciudades. Finalmente, la distancia calculada se asigna a la posición correspondiente en la matriz de distancia y se garantiza la simetría, es decir, el valor de distancia de la posición simétrica se actualiza al mismo tiempo.

De esta forma, hemos completado el procesamiento de los datos y el cálculo de la matriz de distancia. A continuación, realizaremos el proceso de solución del algoritmo genético.

4. Establecer los parámetros del algoritmo genético:

 Estos parámetros se utilizan para controlar el funcionamiento del algoritmo genético. count indica el número de individuos en la población, iter_time indica el número de iteraciones del algoritmo genético, sustain_rate indica la probabilidad de que se seleccione el individuo con la aptitud más alta, random_select_rate indica la probabilidad de que se seleccione el individuo con una aptitud más baja, tasa_mutación indica la probabilidad de mutación, gailiang_N indica mejora el número de iteraciones.

5. Calcular la función de fitness:

 Esta función se utiliza para calcular la distancia total para un camino dado x. Atraviesa cada ciudad de la ruta, calcula la distancia entre la ciudad actual y la ciudad siguiente y la suma a la distancia total. Si la ciudad actual es la última ciudad de la ruta, calcula la distancia entre la última ciudad y la ciudad inicial.

6. Mejora de la población inicial:

 Esta función se utiliza para mejorar los individuos en la población inicial. Genera nuevos caminos seleccionando aleatoriamente dos ciudades e intercambiando sus ubicaciones. Si la distancia total de la ruta nueva es menor que la distancia total de la ruta original, la ruta nueva reemplaza la ruta original para lograr una mejora. Este proceso se repetirá gailiang_N veces para mejorar la calidad de la población.

Ahora, los pasos principales del algoritmo genético están listos. A continuación, se realizarán operaciones de selección natural, cruzamiento y mutación para optimizar los individuos de la población.

7. Selección natural:

 Esta función se utiliza para la selección natural basada en la aptitud de los individuos. Primero, clasifique de acuerdo con el valor de aptitud de cada individuo y luego seleccione una parte de los individuos con mayor aptitud como los "fuertes" para sobrevivir. Luego, seleccione a los individuos con menor aptitud física con una cierta probabilidad para que tengan la oportunidad de sobrevivir. Finalmente, el individuo sobreviviente se devuelve como padre de la próxima generación.

8. Cruzamiento:

 Esta función se utiliza para realizar la operación de cruzamiento. Seleccione aleatoriamente a dos individuos de la generación de padres como padres, y luego cruce los genes de los padres seleccionando aleatoriamente un punto de cruce para generar dos descendientes. Los genes a la izquierda de la intersección permanecen sin cambios y los genes a la derecha se adquieren del otro padre. De esta manera, se pueden conservar algunas características de la generación parental y se pueden introducir nuevas combinaciones de genes para aumentar la diversidad de la población.

9. Operación de mutación:

 Esta función se utiliza para realizar operaciones de mutación. Iterar a través de cada descendiente individual y decidir si mutar de acuerdo con la tasa de mutación. Si se realiza una mutación, se seleccionan aleatoriamente dos posiciones de genes y se intercambian sus valores. A través de la operación de mutación, se puede introducir algo de aleatoriedad para aumentar la diversidad de la población y ayudar a evitar soluciones óptimas locales.

Los tres pasos anteriores constituyen la operación principal del algoritmo genético, a través de múltiples iteraciones y optimización, se encuentra gradualmente el individuo con mayor aptitud, es decir, el camino óptimo para resolver el problema TSP.

10. La función de get_result

 Esta parte del código define una función llamada get_result. Esta función acepta una población como parámetro y devuelve los individuos que mejor se ajustan a la población y sus valores de aptitud correspondientes. En primer lugar, al recorrer cada individuo de la población, la distancia total del individuo se calcula utilizando la función `get_total_distance`, y el individuo y su valor de aptitud se almacenan en la lista graduada bidimensional. Luego, use la función sorted para ordenar la lista de graduados, clasificando de valores de condición física pequeños a grandes. Finalmente, devolviendo grad[0][0] y grad[0][1], es decir, el mejor individuo y el valor de fitness correspondiente.

11. Inicializar la población

Esta parte del código se utiliza para inicializar la población. Primero, cree una población de lista vacía para almacenar los individuos en la población. Luego, se genera un cierto número de individuos mediante un bucle de rango (recuento). En cada bucle, primero se copia el índice de la lista de índices de ciudades, lo que garantiza que cada individuo tenga el mismo orden inicial. A continuación, use la función random.shuffle para mezclar aleatoriamente el orden de los individuos para aumentar la diversidad de la población. Finalmente, llame a la función gailiang para mejorar el individuo, optimizar aún más el orden del individuo y agregar el individuo a la población.

12. Proceso iterativo

Esta parte del código es el principal proceso iterativo del algoritmo genético. Primero, cree una lista vacía distance_list para almacenar el valor de fitness del mejor individuo de la población después de cada iteración. A continuación, llame a la función get_result para obtener el individuo con el mejor estado físico y su valor de estado físico en la población actual, y agregue el valor de estado físico a la lista lista_distancia.

Luego, use un ciclo while para múltiples iteraciones del algoritmo genético. En cada iteración, los siguientes pasos se realizan en secuencia:

①Selección natural: llame a la función nature_select para realizar la selección natural en la población actual y seleccione algunos individuos excelentes como padres.

②Reproducción: Llame a la función de cruce para cruzar a los individuos progenitores para generar una cierta cantidad de individuos descendientes.

③ Mutación: Llame a la función de mutación para realizar operaciones de mutación en individuos descendientes, introducir algo de aleatoriedad y aumentar la diversidad de la población.

④ Actualización: fusionar padres e hijos para formar una nueva población.

⑤ Obtener el mejor individuo: llame a la función get_result para obtener el individuo con el mejor fitness y su valor de fitness en la población actualizada.

⑥Registrar valor de condición física: agregue el valor de condición física a la lista de distancia_lista.

⑦ Contar el número de iteraciones: incrementar el contador de iteraciones i.

En cada iteración, imprima el individuo con la mejor aptitud y su valor de aptitud en la población en la iteración actual.

13. Convierte la ruta del individuo óptimo al orden de las ciudades

Esta parte del código se utiliza para convertir la ruta del individuo óptimo en el orden de las ciudades y construir una ruta cerrada. Primero, use un ciclo for para iterar sobre cada elemento en la lista result_cur_best, incrementando su valor en 1. Esto se debe a que en el procesamiento anterior las ciudades se indexaron desde 0, mientras que en la ruta de salida queremos que las ciudades se numeren desde 1.

Luego, asigne el result_cur_best actualizado a la variable result_path. A continuación, el primer elemento de la lista result_path se agrega al final de la lista, formando una ruta cerrada. Esto se debe a que en el problema TSP, el viaje debe regresar a la ciudad de origen. Imprima result_path, que es la ruta óptima.

14. Traza el resultado

Esta parte del código se utiliza para dibujar una visualización de los resultados. Primero, cree listas vacías X e Y para almacenar las coordenadas horizontales y verticales de cada ciudad. Al iterar sobre cada elemento en la lista result_path, agregue las coordenadas de la ciudad correspondiente a X e Y.

 

A continuación, establezca la fuente de matplotlib en chino y cree dos ventanas gráficas. En la primera ventana de gráficos, use la función de trazado para dibujar la ruta de la ciudad, conecte las ciudades configurando el estilo de línea en -o y dibuje puntos en cada ciudad. Use la función de texto para agregar el número de ciudad en la ubicación de cada ciudad. Establezca la etiqueta y el título de las coordenadas horizontales y verticales.

En la segunda ventana de gráficos, utilice la función de trazado para trazar el cambio de valor óptimo durante el proceso de optimización, es decir, la lista de distancia_lista. Establezca la etiqueta y el título de las coordenadas horizontales y verticales.

Finalmente, el gráfico se muestra usando la función mostrar.

B. Diagrama de flujo del algoritmo genético para resolver el problema TSP

 4. Código completo

#遗传算法求解TSP问题完整代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import math
import random

# 处理数据

coord = []
with open("data.txt", "r") as lines:
    lines = lines.readlines()
for line in lines:
    xy = line.split()
    coord.append(xy)

coord = np.array(coord)
w, h = coord.shape
coordinates = np.zeros((w, h), float)
for i in range(w):
    for j in range(h):
        coordinates[i, j] = float(coord[i, j])

# print(coordinates)

# 得到距离矩阵

distance = np.zeros((w, w))
for i in range(w):
    for j in range(w):
        distance[i, j] = distance[j, i] = np.linalg.norm(coordinates[i] - coordinates[j])

# 种群数
count = 300

# 进化次数
iter_time = 1000

# 最优选择概率
retain_rate = 0.3  # 适应度前30%可以活下来

# 弱者生存概率
random_select_rate = 0.5

# 变异
mutation_rate = 0.1

# 改良
gailiang_N = 3000


# 适应度
def get_total_distance(x):
    dista = 0
    for i in range(len(x)):
        if i == len(x) - 1:
            dista += distance[x[i]][x[0]]
        else:
            dista += distance[x[i]][x[i + 1]]
    return dista

# 初始种群的改良
def gailiang(x):
    distance = get_total_distance(x)
    gailiang_num = 0
    while gailiang_num < gailiang_N:
        while True:
            a = random.randint(0, len(x) - 1)
            b = random.randint(0, len(x) - 1)
            if a != b:
                break
        new_x = x.copy()
        temp_a = new_x[a]
        new_x[a] = new_x[b]
        new_x[b] = temp_a
        if get_total_distance(new_x) < distance:
            x = new_x.copy()
        gailiang_num += 1


# 自然选择

def nature_select(population):
    grad = [[x, get_total_distance(x)] for x in population]
    grad = [x[0] for x in sorted(grad, key=lambda x: x[1])]
    # 强者
    retain_length = int(retain_rate * len(grad))
    parents = grad[: retain_length]
    # 生存下来的弱者
    for ruozhe in grad[retain_length:]:
        if random.random() < random_select_rate:
            parents.append(ruozhe)
    return parents


# 交叉繁殖
def crossover(parents):
    target_count = count - len(parents)
    children = []
    while len(children) < target_count:
        while True:
            male_index = random.randint(0, len(parents)-1)
            female_index = random.randint(0, len(parents)-1)
            if male_index != female_index:
                break
        male = parents[male_index]
        female = parents[female_index]
        left = random.randint(0, len(male) - 2)
        right = random.randint(left, len(male) - 1)
        gen_male = male[left:right]
        gen_female = female[left:right]
        child_a = []
        child_b = []

        len_ca = 0
        for g in male:
            if len_ca == left:
                child_a.extend(gen_female)
                len_ca += len(gen_female)
            if g not in gen_female:
                child_a.append(g)
                len_ca += 1

        len_cb = 0
        for g in female:
            if len_cb == left:
                child_b.extend(gen_male)
                len_cb += len(gen_male)
            if g not in gen_male:
                child_b.append(g)
                len_cb += 1

        children.append(child_a)
        children.append(child_b)
    return children


# 变异操作
def mutation(children):
    for i in range(len(children)):
        if random.random() < mutation_rate:
            while True:
                u = random.randint(0, len(children[i]) - 1)
                v = random.randint(0, len(children[i]) - 1)
                if u != v:
                    break
            temp_a = children[i][u]
            children[i][u] = children[i][v]
            children[i][v] = temp_a


def get_result(population):
    grad = [[x, get_total_distance(x)] for x in population]
    grad = sorted(grad, key=lambda x: x[1])
    return grad[0][0], grad[0][1]


population = []
# 初始化种群
index = [i for i in range(w)]
for i in range(count):
    x = index.copy()
    random.shuffle(x)
    gailiang(x)
    population.append(x)

distance_list = []
result_cur_best, dist_cur_best = get_result(population)
distance_list.append(dist_cur_best)

i = 0
while i < iter_time:
    # 自然选择
    parents = nature_select(population)

    # 繁殖
    children = crossover(parents)

    # 变异
    mutation(children)

    # 更新
    population = parents + children

    result_cur_best, dist_cur_best = get_result(population)
    distance_list.append(dist_cur_best)
    i = i + 1
    print(result_cur_best)
    print(dist_cur_best)


for i in range(len(result_cur_best)):
    result_cur_best[i] += 1

result_path = result_cur_best
result_path.append(result_path[0])

print(result_path)

# 画图
X = []
Y = []
for index in result_path:
    X.append(coordinates[index-1, 0])
    Y.append(coordinates[index-1, 1])

plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
plt.figure(1)
plt.plot(X, Y, '-o')
for i in range(len(X)):
    plt.text(X[i] + 0.05, Y[i] + 0.05, str(result_path[i]), color='red')
plt.xlabel('横坐标')
plt.ylabel('纵坐标')
plt.title('轨迹图')

plt.figure(2)
plt.plot(np.array(distance_list))
plt.title('优化过程')
plt.ylabel('最优值')
plt.xlabel('代数({}->{})'.format(0, iter_time))
plt.show()

conjunto de datos

1.304 2.312
3.639 1.315
4.177 2.244
3.712 1.399
3.488 1.535
3.326 1.556
3.238 1.229
4.897 5.468
1.987 2.687
6.359 6.987
10.479 11.674
9.657 6.845
7.687 6.945
12.467 10.367
15.164 14.267
17.654 14.983
1.302 7.635
2.346 9.647
3.647 10.943
12.001 2.036
11.746 1.357
9.467 2.467
14.605 6.876
16.798 5.304
4.304 8.674
5.476 14.379
16.004 7.649

Supongo que te gusta

Origin blog.csdn.net/m0_63794226/article/details/131190752
Recomendado
Clasificación