File size: 5,520 Bytes
668267d
 
 
 
 
 
 
 
f76f41d
 
668267d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2a62559
668267d
2a62559
 
 
 
 
668267d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2a62559
f76f41d
 
2a62559
668267d
 
 
 
 
 
 
 
 
 
 
 
 
 
2a62559
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import numpy as np
import random
from typing import List

class InputData(BaseModel):
    data: List[float]  # Lista de caracter铆sticas num茅ricas (flotantes)
    data2: List[int]

app = FastAPI()

# ------------- algoritmo genetico -------------
# Funci贸n para generar una poblaci贸n inicial aleatoria
def generar_poblacion(num_individuos, num_ciudades):
    poblacion = []
    for _ in range(num_individuos):
        individuo = list(range(num_ciudades))
        random.shuffle(individuo)
        poblacion.append(individuo)
    return poblacion

# Funci贸n para evaluar la aptitud de un individuo (distancia total del recorrido)
def calcular_aptitud(individuo, distancias, coordenadas):
    distancia_total = 0
    coordenadas_iguales = all(coord == coordenadas[0] for coord in coordenadas)

    if not coordenadas_iguales:
        for i in range(len(individuo) - 1):
            ciudad_actual = individuo[i]
            siguiente_ciudad = individuo[i + 1]
            distancia_total += distancias[ciudad_actual][siguiente_ciudad]

        distancia_total += distancias[individuo[-1]][individuo[0]]

    return distancia_total

# Funci贸n para seleccionar individuos para la reproducci贸n (torneo binario)
def seleccion_torneo(poblacion, distancias, coordenadas):
    seleccionados = []
    for _ in range(len(poblacion)):
        torneo = random.sample(poblacion, 2)
        aptitud_torneo = [
            calcular_aptitud(individuo, distancias, coordenadas) for individuo in torneo
        ]
        seleccionado = torneo[aptitud_torneo.index(min(aptitud_torneo))]
        seleccionados.append(seleccionado)
    return seleccionados

# Funci贸n para realizar el cruce de dos padres para producir un hijo
def cruzar(padre1, padre2):
    punto_cruce = random.randint(0, len(padre1) - 1)
    hijo = padre1[:punto_cruce] + [
        gen for gen in padre2 if gen not in padre1[:punto_cruce]
    ]
    return hijo
    

# Funci贸n para aplicar mutaciones en la poblaci贸n
def mutar(individuo, probabilidad_mutacion):
    if random.random() < probabilidad_mutacion:
        indices = random.sample(range(len(individuo)), 2)
        individuo[indices[0]], individuo[indices[1]] = (
            individuo[indices[1]],
            individuo[indices[0]],
        )
    return individuo

# Funci贸n para generar distancias aleatorias entre ciudades y sus coordenadas bidimensionales
def generar_distancias(num_ciudades, puntos_array):
    distancias = [[0] * num_ciudades for _ in range(num_ciudades)]
    coordenadas = []
    
    for i in range(0, len(puntos_array), 2):
        if i+1 < len(puntos_array):
            coordenadas.append((puntos_array[i], puntos_array[i+1]))

    for i in range(num_ciudades):
        for j in range(i + 1, num_ciudades):
            distancias[i][j] = distancias[j][i] = (
                sum((x - y) ** 2 for x, y in zip(coordenadas[i], coordenadas[j])) ** 0.5
            )

    return distancias, coordenadas

def algoritmo_genetico(num_generaciones,num_ciudades,num_individuos,probabilidad_mutacion,distancias,coordenadas):
    poblacion = generar_poblacion(num_individuos, num_ciudades)    
    for generacion in range(num_generaciones):
        poblacion = sorted(
            poblacion, key=lambda x: calcular_aptitud(x, distancias, coordenadas)
        )
        mejor_individuo = poblacion[0]
        mejor_distancia = calcular_aptitud(mejor_individuo, distancias, coordenadas)        
        seleccionados = seleccion_torneo(poblacion, distancias, coordenadas)
        nueva_poblacion = []
        for i in range(0, len(seleccionados), 2):
            padre1, padre2 = seleccionados[i], seleccionados[i + 1]
            hijo1 = cruzar(padre1, padre2)
            hijo2 = cruzar(padre2, padre1)
            hijo1 = mutar(hijo1, probabilidad_mutacion)
            hijo2 = mutar(hijo2, probabilidad_mutacion)
            nueva_poblacion.extend([hijo1, hijo2])
        poblacion = nueva_poblacion        
    mejor_solucion = poblacion[0]
    mejor_distancia = calcular_aptitud(mejor_solucion, distancias, coordenadas)
    return mejor_solucion, mejor_distancia

# Ruta de predicci贸n
@app.post("/predict/")
async def predict(data: InputData):
    print(f"Data: {data}")
    try:
        # Convertir la lista de entrada a un array de NumPy para la predicci贸n
        input_data = np.array(data.data).reshape(
            1, -1
        )  # Asumiendo que la entrada debe ser de forma (1, num_features)
        
        num_ciudades = int(input_data[0][0])
        num_individuos = int(input_data[0][1])
        probabilidad_mutacion = float(input_data[0][2])
        num_generaciones = int(input_data[0][3])

        puntos_array = data.data2
        
        distancias, coordenadas = generar_distancias(num_ciudades, puntos_array)
        
        mejor_solucion, mejor_distancia = algoritmo_genetico(num_generaciones,num_ciudades,num_individuos,probabilidad_mutacion,distancias,coordenadas)
        #print(type(mejor_solucion),mejor_solucion
        respuesta = list(mejor_solucion)
        print(respuesta)
        prediction = respuesta
        #return {"prediction": prediction.tolist()}
        return {
            "num_ciudades": num_ciudades,
            "distancia": int(mejor_distancia),
            "prediction": prediction,
            "cromosoma": mejor_solucion  # Esto ya es un array de ints
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))