Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| import numpy as np | |
| import random | |
| from typing import List, Dict | |
| class Point(BaseModel): | |
| id: str | |
| x: float | |
| y: float | |
| class PathRequest(BaseModel): | |
| points: List[Point] | |
| class BezierPoint(BaseModel): | |
| x: float | |
| y: float | |
| class PathResponse(BaseModel): | |
| path: List[str] | |
| distance: float | |
| bezierPoints: List[BezierPoint] | |
| class Config: | |
| allow_population_by_field_name = True | |
| alias_generator = lambda field_name: field_name.replace('_', '') | |
| class InputData(BaseModel): | |
| data: List[float] # Lista de caracter铆sticas num茅ricas (flotantes) | |
| app = FastAPI() | |
| def generate_bezier_points( | |
| path: List[str], | |
| points_dict: Dict[str, Point], | |
| segments: int = 50 | |
| ): | |
| bezier_points = [] | |
| if len(path) < 3: | |
| return bezier_points | |
| for i in range(len(path) - 2): | |
| p0 = points_dict[path[i]] | |
| p1 = points_dict[path[i+1]] | |
| p2 = points_dict[path[i+2]] | |
| for t in np.linspace(0, 1, segments): | |
| # B(t) = (1-t)虏P0 + 2(1-t)tP1 + t虏P2 | |
| x = round((1-t)**2 * p0.x + 2*(1-t)*t * p1.x + t**2 * p2.x, 3) | |
| y = round((1-t)**2 * p0.y + 2*(1-t)*t * p1.y + t**2 * p2.y, 3) | |
| bezier_points.append(BezierPoint(x=x, y=y)) | |
| return bezier_points | |
| # ------------- 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 | |
| def calcular_aptitud(individuo, distancias, coordenadas): | |
| # Funci贸n para evaluar la aptitud de | |
| # un individuo (distancia total del recorrido) | |
| 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): | |
| distancias = [[0] * num_ciudades for _ in range(num_ciudades)] | |
| coordenadas = [ | |
| (random.uniform(0, 100), random.uniform(0, 100)) | |
| for _ in range(num_ciudades) | |
| ] | |
| 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 | |
| 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]) | |
| distancias, coordenadas = generar_distancias(num_ciudades) | |
| 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 {"prediction": prediction} | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def find_shortest_path( | |
| request: PathRequest, | |
| population: int = 50, | |
| mutation_prob: float = 0.1, | |
| generations: int = 100 | |
| ): | |
| try: | |
| points = request.points | |
| num_cities = len(points) | |
| if num_cities < 3: | |
| raise HTTPException( | |
| status_code=400, | |
| detail="need at least 3 points" | |
| ) | |
| print( | |
| f"parametros: population={population}, mutation_prob={mutation_prob}, generations={generations}" | |
| ) | |
| distancias = [[0] * num_cities for _ in range(num_cities)] | |
| coordenadas = [(p.x, p.y) for p in points] | |
| points_dict = {p.id: p for p in points} | |
| for i in range(num_cities): | |
| for j in range(i + 1, num_cities): | |
| dist = ((coordenadas[i][0] - coordenadas[j][0])**2 + | |
| (coordenadas[i][1] - coordenadas[j][1])**2)**0.5 | |
| distancias[i][j] = distancias[j][i] = dist | |
| mejor_solucion, mejor_distancia = algoritmo_genetico( | |
| num_generaciones=generations, | |
| num_ciudades=num_cities, | |
| num_individuos=population, | |
| probabilidad_mutacion=mutation_prob, | |
| distancias=distancias, | |
| coordenadas=coordenadas | |
| ) | |
| path_ids = [points[i].id for i in mejor_solucion] | |
| bezier_points = generate_bezier_points(path_ids, points_dict) | |
| return PathResponse( | |
| path=path_ids, | |
| distance=mejor_distancia, | |
| bezierPoints=bezier_points | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=500, | |
| detail=str(e) | |
| ) | |