Испавил ген.алгоритм, надо только нормально по папочкам расскидать (мне сного шутить, что у меня нет папы?)

This commit is contained in:
maksim 2024-06-03 19:56:19 +04:00
parent 0c55d4912a
commit 82e6075f3f
2 changed files with 67 additions and 18 deletions

View File

@ -1,11 +1,15 @@
import json import json
from datetime import datetime, timedelta from datetime import datetime, timedelta
import random import random
from typing import Dict, List from typing import Dict, List, Tuple, Any
from fastapi import FastAPI, HTTPException, Request from fastapi import FastAPI, HTTPException, Request
def load_graph_from_request(request) -> Dict[str, Dict[str, List]]: from schemas import TripRequest
def load_graph_from_request(request: TripRequest) -> Tuple[Dict[str, Dict[str, List[Any]]], str, str, List[Dict]]:
graph = {} graph = {}
flights_data = []
# Загрузить данные о полетах из запроса # Загрузить данные о полетах из запроса
flights = request.flights flights = request.flights
@ -19,6 +23,15 @@ def load_graph_from_request(request) -> Dict[str, Dict[str, List]]:
departure_time = datetime.fromisoformat(flight.departureTime) departure_time = datetime.fromisoformat(flight.departureTime)
destination_time = datetime.fromisoformat(flight.destinationTime) destination_time = datetime.fromisoformat(flight.destinationTime)
# Сохранение данных о полете для вывода
flights_data.append({
"id": flight.id,
"departurePoint": departure_point,
"destinationPoint": destination_point,
"departureTime": departure_time,
"destinationTime": destination_time
})
# Проверка наличия вершин в графе и их создание при необходимости # Проверка наличия вершин в графе и их создание при необходимости
if departure_point not in graph: if departure_point not in graph:
graph[departure_point] = {} graph[departure_point] = {}
@ -28,9 +41,9 @@ def load_graph_from_request(request) -> Dict[str, Dict[str, List]]:
# Добавление ребра в граф # Добавление ребра в граф
graph[departure_point][destination_point] = [flight.distance, departure_time, destination_time] graph[departure_point][destination_point] = [flight.distance, departure_time, destination_time]
return graph, start_point, end_point return graph, start_point, end_point, flights_data
# Функция для вычисления длины и времени пути с учетом минимального интервала времени
def path_length_and_time(path, graph): def path_length_and_time(path, graph):
length = 0 length = 0
if path[0] not in graph or path[1] not in graph[path[0]]: if path[0] not in graph or path[1] not in graph[path[0]]:
@ -49,8 +62,8 @@ def path_length_and_time(path, graph):
end_time = graph[path[i]][path[i + 1]][2] end_time = graph[path[i]][path[i + 1]][2]
return length, start_time, end_time return length, start_time, end_time
# Функция для генерации начальной популяции
def generate_population(size, start, end, graph, max_attempts=100): def generate_population(size, start, end, graph, max_attempts=1000):
population = [] population = []
for i in range(size): for i in range(size):
attempts = 0 attempts = 0
@ -74,13 +87,12 @@ def generate_population(size, start, end, graph, max_attempts=100):
attempts += 1 attempts += 1
return population return population
# Функция для селекции родителей
def select_parents(population, graph): def select_parents(population, graph):
sorted_population = sorted(population, key=lambda p: path_length_and_time(p, graph)[0]) sorted_population = sorted(population, key=lambda p: path_length_and_time(p, graph)[0])
return sorted_population[:len(sorted_population) // 2] return sorted_population[:len(sorted_population) // 2]
# Функция для скрещивания (кроссинговера)
def crossover(parent1, parent2): def crossover(parent1, parent2):
crossover_point = len(parent1) // 2 crossover_point = len(parent1) // 2
child = parent1[:crossover_point] child = parent1[:crossover_point]
@ -90,7 +102,6 @@ def crossover(parent1, parent2):
return child return child
# Функция для мутации
def mutate(child): def mutate(child):
if len(child) <= 2: if len(child) <= 2:
return child # Если путь состоит из одной вершины, мутация не требуется return child # Если путь состоит из одной вершины, мутация не требуется
@ -100,9 +111,18 @@ def mutate(child):
return child return child
# Главная функция генетического алгоритма def update_best_paths(best_paths, path, graph, max_best_paths=3):
def genetic_algorithm(start, end, graph, population_size=100, generations=100): length, _, _ = path_length_and_time(path, graph)
if path not in best_paths:
best_paths[path] = length
if len(best_paths) > max_best_paths:
worst_path = max(best_paths, key=best_paths.get)
del best_paths[worst_path]
def genetic_algorithm(start, end, graph, flights_data, population_size=100, generations=100):
population = generate_population(population_size, start, end, graph) population = generate_population(population_size, start, end, graph)
best_paths = {} # Словарь для хранения уникальных лучших маршрутов и их длин
for generation in range(generations): for generation in range(generations):
parents = select_parents(population, graph) parents = select_parents(population, graph)
new_population = parents[:] new_population = parents[:]
@ -112,8 +132,35 @@ def genetic_algorithm(start, end, graph, population_size=100, generations=100):
child = crossover(parent1, parent2) child = crossover(parent1, parent2)
if random.random() < 0.1: # Вероятность мутации if random.random() < 0.1: # Вероятность мутации
child = mutate(child) child = mutate(child)
new_population.append(child) if child[-1] == end:
new_population.append(child)
update_best_paths(best_paths, tuple(child), graph)
population = new_population population = new_population
best_path = min(population, key=lambda p: path_length_and_time(p, graph)[0])
best_length, start_time, end_time = path_length_and_time(best_path, graph) best_paths = sorted(best_paths.items(), key=lambda item: item[1])
return best_path, best_length, start_time, end_time top_paths = [list(path) for path, _ in best_paths[:3]]
result = []
for path in top_paths:
path_data = []
for i in range(len(path) - 1):
for flight in flights_data:
if flight['departurePoint'] == path[i] and flight['destinationPoint'] == path[i + 1]:
path_data.append({
"id": flight['id'],
"departurePoint": flight['departurePoint'],
"destinationPoint": flight['destinationPoint']
})
break
length, start_time, end_time = path_length_and_time(path, graph)
# Проверка на корректность длины пути и времени
if length == float('inf') or start_time is None or end_time is None:
continue
result.append({
"to": path_data,
"start_time": start_time.isoformat() if start_time else None,
"end_time": end_time.isoformat() if end_time else None,
"best_length": length
})
return result

View File

@ -17,9 +17,11 @@ router = APIRouter(
@router.post("/get_flight/") @router.post("/get_flight/")
async def get_flight(request: TripRequest): async def get_flight(request: TripRequest):
graph, start_point, end_point = load_graph_from_request(request) graph, start_point, end_point, flights_data = load_graph_from_request(request)
best_path, best_length, start_time, end_time = genetic_algorithm(start_point, end_point, graph) result = genetic_algorithm(start_point, end_point, graph, flights_data)
return best_path, best_length, start_time, end_time if not result:
raise HTTPException(status_code=404, detail="No valid paths found")
return result
@router.get("/negative") @router.get("/negative")
async def get_class_names() -> List[str]: async def get_class_names() -> List[str]: