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

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
from datetime import datetime, timedelta
import random
from typing import Dict, List
from typing import Dict, List, Tuple, Any
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 = {}
flights_data = []
# Загрузить данные о полетах из запроса
flights = request.flights
@ -19,6 +23,15 @@ def load_graph_from_request(request) -> Dict[str, Dict[str, List]]:
departure_time = datetime.fromisoformat(flight.departureTime)
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:
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]
return graph, start_point, end_point
return graph, start_point, end_point, flights_data
# Функция для вычисления длины и времени пути с учетом минимального интервала времени
def path_length_and_time(path, graph):
length = 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]
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 = []
for i in range(size):
attempts = 0
@ -74,13 +87,12 @@ def generate_population(size, start, end, graph, max_attempts=100):
attempts += 1
return population
# Функция для селекции родителей
def select_parents(population, graph):
sorted_population = sorted(population, key=lambda p: path_length_and_time(p, graph)[0])
return sorted_population[:len(sorted_population) // 2]
# Функция для скрещивания (кроссинговера)
def crossover(parent1, parent2):
crossover_point = len(parent1) // 2
child = parent1[:crossover_point]
@ -90,7 +102,6 @@ def crossover(parent1, parent2):
return child
# Функция для мутации
def mutate(child):
if len(child) <= 2:
return child # Если путь состоит из одной вершины, мутация не требуется
@ -100,9 +111,18 @@ def mutate(child):
return child
# Главная функция генетического алгоритма
def genetic_algorithm(start, end, graph, population_size=100, generations=100):
def update_best_paths(best_paths, path, graph, max_best_paths=3):
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)
best_paths = {} # Словарь для хранения уникальных лучших маршрутов и их длин
for generation in range(generations):
parents = select_parents(population, graph)
new_population = parents[:]
@ -112,8 +132,35 @@ def genetic_algorithm(start, end, graph, population_size=100, generations=100):
child = crossover(parent1, parent2)
if random.random() < 0.1: # Вероятность мутации
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
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)
return best_path, best_length, start_time, end_time
best_paths = sorted(best_paths.items(), key=lambda item: item[1])
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/")
async def get_flight(request: TripRequest):
graph, start_point, end_point = load_graph_from_request(request)
best_path, best_length, start_time, end_time = genetic_algorithm(start_point, end_point, graph)
return best_path, best_length, start_time, end_time
graph, start_point, end_point, flights_data = load_graph_from_request(request)
result = genetic_algorithm(start_point, end_point, graph, flights_data)
if not result:
raise HTTPException(status_code=404, detail="No valid paths found")
return result
@router.get("/negative")
async def get_class_names() -> List[str]: