Spaces:
Sleeping
Sleeping
File size: 4,497 Bytes
639f871 | 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 | """
core/models.py — Strutture dati fondamentali per il TOP-TW turistico.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
import math
class PoICategory(Enum):
MUSEUM = "museum"
MONUMENT = "monument"
RESTAURANT = "restaurant" # pranzo / cena formale
BAR = "bar" # caffè, aperitivo, sosta breve
GELATERIA = "gelateria" # sosta dolce pomeridiana
PARK = "park"
VIEWPOINT = "viewpoint"
@dataclass
class TimeWindow:
open: int # minuti dalla mezzanotte (es. 540 = 09:00)
close: int # minuti dalla mezzanotte (es. 1080 = 18:00)
def __repr__(self) -> str:
return f"{self.open//60:02d}:{self.open%60:02d}–{self.close//60:02d}:{self.close%60:02d}"
@dataclass
class PoI:
id: str
name: str
lat: float
lon: float
score: float # interesse normalizzato [0, 1]
visit_duration: int # minuti di visita stimati
time_window: TimeWindow
category: PoICategory
tags: list[str] = field(default_factory=list)
def __hash__(self):
return hash(self.id)
def __eq__(self, other):
return isinstance(other, PoI) and self.id == other.id
def __repr__(self):
return f"PoI({self.name!r}, score={self.score:.2f}, {self.time_window})"
@dataclass
class FitnessScore:
total_score: float = 0.0 # somma score PoI visitati
total_distance: float = 0.0 # km totali percorsi
total_time: int = 0 # minuti totali (spostamenti + visite)
is_feasible: bool = False # rispetta TW e budget?
scalar: float = 0.0 # valore aggregato per confronti rapidi
rank: int = 0 # rango Pareto (NSGA-II)
crowd: float = 0.0 # crowding distance (NSGA-II)
def dominates(self, other: FitnessScore) -> bool:
"""
self domina other se è ≥ su tutti gli obiettivi e > su almeno uno.
Obiettivi: massimizza score, minimizza distance, minimizza time.
"""
better_or_equal = (
self.total_score >= other.total_score and
self.total_distance <= other.total_distance and
self.total_time <= other.total_time
)
strictly_better = (
self.total_score > other.total_score or
self.total_distance < other.total_distance or
self.total_time < other.total_time
)
return better_or_equal and strictly_better
@dataclass
class ScheduledStop:
poi: PoI
arrival: int # minuti dalla mezzanotte
departure: int # minuti dalla mezzanotte
wait: int # minuti di attesa prima dell'apertura
@dataclass
class TourSchedule:
stops: list[ScheduledStop] = field(default_factory=list)
total_time: int = 0
total_distance: float = 0.0
total_wait: int = 0 # minuti di attesa cumulati (attese a TW)
is_feasible: bool = False
def summary(self) -> str:
lines = []
for s in self.stops:
a = f"{s.arrival//60:02d}:{s.arrival%60:02d}"
d = f"{s.departure//60:02d}:{s.departure%60:02d}"
w = f" (attesa {s.wait} min)" if s.wait > 0 else ""
lines.append(f" {a}–{d} {s.poi.name}{w}")
wait_note = f", attese {self.total_wait} min" if self.total_wait > 0 else ""
lines.append(
f" Totale: {self.total_time} min, "
f"{self.total_distance:.1f} km{wait_note}"
)
return "\n".join(lines)
class Individual:
"""
Cromosoma = lista ordinata di PoI che compongono il tour.
Il gene jolly (WildcardGene) è un placeholder che viene
materializzato al momento della decodifica.
"""
def __init__(self, genes: list[PoI]):
self.genes: list[PoI] = genes
self.fitness: FitnessScore = FitnessScore()
self._schedule: Optional[TourSchedule] = None # cache
def clone(self) -> Individual:
return Individual(genes=list(self.genes))
def invalidate_cache(self):
self._schedule = None
self.fitness = FitnessScore()
def __len__(self):
return len(self.genes)
def __repr__(self):
names = [p.name for p in self.genes]
return f"Individual([{', '.join(names)}], scalar={self.fitness.scalar:.3f})" |