pc1be / main.py
axvg's picture
init app
c0d78bc verified
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
@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])
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))
@app.post("/shortest-path/", response_model=PathResponse)
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)
)