From 03deb5832b5b504ad7928ec99d23088cecd56f48 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Prado Date: Fri, 25 Oct 2019 21:38:49 +0200 Subject: [PATCH] * Now using "self.__iter__(...)" instead of "self.as_dict()" method. #49 --- jinete/algorithms/utils/breeders/flips.py | 2 +- jinete/models/abc.py | 18 ++++++-- jinete/models/jobs.py | 18 +++----- jinete/models/objectives.py | 2 +- jinete/models/planned_trips.py | 21 ++++----- jinete/models/plannings.py | 14 +++--- jinete/models/positions.py | 23 +++++++--- jinete/models/routes.py | 22 ++++----- jinete/models/services.py | 7 ++- jinete/models/stops.py | 21 +++------ jinete/models/surfaces.py | 14 +++--- jinete/models/trips.py | 19 ++++++-- jinete/models/vehicles.py | 54 +++++++---------------- jinete/storers/formatters/columnar.py | 2 +- 14 files changed, 121 insertions(+), 116 deletions(-) diff --git a/jinete/algorithms/utils/breeders/flips.py b/jinete/algorithms/utils/breeders/flips.py index 0da4ce07..ea3d8c70 100644 --- a/jinete/algorithms/utils/breeders/flips.py +++ b/jinete/algorithms/utils/breeders/flips.py @@ -13,7 +13,7 @@ class FlipBreeder(Breeder): def improve(self) -> Result: - for route in self.planning: + for route in self.planning.routes: cost = self.objective.optimization_function(route) for i in range(1, len(route.stops) - 1): diff --git a/jinete/models/abc.py b/jinete/models/abc.py index df20903b..d9f0b2c8 100644 --- a/jinete/models/abc.py +++ b/jinete/models/abc.py @@ -1,15 +1,27 @@ +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import Any, Dict +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import ( + Any, + Generator, + Tuple, + ) class Model(ABC): def __repr__(self): - return self._print(self.as_dict()) + return self._print(dict(self)) def _print(self, values): values = ', '.join(f'{key}={value}' for key, value in values.items()) return f'{self.__class__.__name__}({values})' + def _print_key_value(self, key: str, value: Any): + return f'{key}={value}' + @abstractmethod - def as_dict(self) -> Dict[str, Any]: + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: pass diff --git a/jinete/models/jobs.py b/jinete/models/jobs.py index fe2cf5f9..b69e5bdb 100644 --- a/jinete/models/jobs.py +++ b/jinete/models/jobs.py @@ -14,7 +14,8 @@ from typing import ( Set, Any, - Dict, + Generator, + Tuple, Type, Optional, ) @@ -45,16 +46,11 @@ def objective(self) -> Objective: self._objective = self.objective_cls(*self.args, **self.kwargs) return self._objective - def __iter__(self): - yield from self.trips - def __deepcopy__(self, memo) -> Job: return self - def as_dict(self) -> Dict[str, Any]: - trips_str = ', '.join(str(trip) for trip in self.trips) - dict_values = { - 'trips': f'{{{trips_str}}}', - 'objective': self.objective, - } - return dict_values + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('trip_identifiers', tuple(trip.identifier for trip in self.trips)), + ('objective', self.objective), + ) diff --git a/jinete/models/objectives.py b/jinete/models/objectives.py index 91b8170d..2dd0cb1b 100644 --- a/jinete/models/objectives.py +++ b/jinete/models/objectives.py @@ -65,7 +65,7 @@ def _result_optimization_function(self, result: Result) -> float: def _planning_optimization_function(self, planning: Planning) -> float: scoring = 0.0 - for route in planning: + for route in planning.routes: scoring += self._route_optimization_function(route) return scoring diff --git a/jinete/models/planned_trips.py b/jinete/models/planned_trips.py index 0d45a5ed..41bef9eb 100644 --- a/jinete/models/planned_trips.py +++ b/jinete/models/planned_trips.py @@ -14,9 +14,10 @@ if TYPE_CHECKING: from typing import ( - Dict, Any, Optional, + Generator, + Tuple, ) from uuid import ( UUID, @@ -113,15 +114,15 @@ def feasible(self) -> bool: def empty(self) -> bool: return self.trip.empty - def as_dict(self) -> Dict[str, Any]: - return { - 'route_uuid': self.route_uuid, - 'trip_identifier': self.trip_identifier, - 'pickup': self.pickup, - 'delivery': self.delivery, - 'down_time': self.down_time, - 'feasible': self.feasible, - } + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('route_uuid', self.route_uuid), + ('trip_identifier', self.trip_identifier), + ('pickup', self.pickup), + ('delivery', self.delivery), + ('down_time', self.down_time), + ('feasible', self.feasible), + ) def flush(self) -> None: self._feasible = None diff --git a/jinete/models/plannings.py b/jinete/models/plannings.py index 94064f3d..1516a0f4 100644 --- a/jinete/models/plannings.py +++ b/jinete/models/plannings.py @@ -16,6 +16,8 @@ Dict, Any, Iterator, + Generator, + Tuple, ) from .routes import ( Route, @@ -46,9 +48,6 @@ def __init__(self, routes: Set[Route] = None, uuid: UUID = None): self.routes = routes self.uuid = uuid - def __iter__(self): - yield from self.routes - @property def loaded_routes(self): return set(route for route in self.routes if route.loaded) @@ -62,10 +61,11 @@ def planned_trips(self) -> Iterator[PlannedTrip]: def trips(self) -> Iterator[Trip]: yield from (planned_trip.trip for planned_trip in self.planned_trips) - def as_dict(self) -> Dict[str, Any]: - return { - 'uuid': self.uuid, - } + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('uuid', self.uuid), + ('route_uuids', tuple(route.uuid for route in self.routes)) + ) def __deepcopy__(self, memo: Dict[int, Any]) -> Planning: planning = Planning() diff --git a/jinete/models/positions.py b/jinete/models/positions.py index 7c27ed3b..907f81e6 100644 --- a/jinete/models/positions.py +++ b/jinete/models/positions.py @@ -3,15 +3,21 @@ import logging from abc import ( ABC, + abstractmethod, ) from typing import ( TYPE_CHECKING, ) +from .abc import ( + Model, +) + if TYPE_CHECKING: from typing import ( Tuple, Sequence, + Generator, Dict, Any, ) @@ -22,16 +28,18 @@ logger = logging.getLogger(__name__) -class Position(ABC): +class Position(Model, ABC): def __init__(self, surface: Surface): self.surface = surface - def __eq__(self, other): - return hash(self) == hash(other) - def distance_to(self, other: Position) -> float: return self.surface.distance(self, other) + @property + @abstractmethod + def coordinates(self) -> Tuple[Any]: + pass + def time_to(self, other: Position, now: float = None) -> float: return self.surface.time(self, other, now=now) @@ -59,8 +67,13 @@ def __eq__(self, other) -> bool: def __ne__(self, other) -> bool: return self.coordinates != other.coordinates + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('coordinates', self.coordinates), + ) + def __str__(self): - c = ",".join(f"{x:07.3f}" for x in self) + c = ",".join(f"{x:07.3f}" for x in self.coordinates) return f'({c})' def __getitem__(self, item): diff --git a/jinete/models/routes.py b/jinete/models/routes.py index eaa6ca2c..47a257d2 100644 --- a/jinete/models/routes.py +++ b/jinete/models/routes.py @@ -27,6 +27,8 @@ Dict, Optional, Iterable, + Generator, + Tuple, ) from uuid import ( UUID, @@ -64,9 +66,6 @@ def __init__(self, vehicle: Vehicle, stops: List[Stop] = None, uuid: UUID = None else: self.stops = list(stops) - def __iter__(self): - yield from self.planned_trips - def __deepcopy__(self, memo: Dict[int, Any]) -> Route: vehicle = deepcopy(self.vehicle, memo) @@ -174,16 +173,17 @@ def last_stop(self) -> Stop: return stop @property - def vehicle_uuid(self) -> Optional[UUID]: + def vehicle_identifier(self) -> Optional[str]: if self.vehicle is None: return None - return self.vehicle.uuid - - def as_dict(self) -> Dict[str, Any]: - return { - 'uuid': self.uuid, - 'vehicle_uuid': self.vehicle_uuid, - } + return self.vehicle.identifier + + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('uuid', self.uuid), + ('vehicle_identifier', self.vehicle_identifier), + ('trip_identifiers', tuple(trip.identifier for trip in self.trips)) + ) def conjecture_trip(self, trip: Trip) -> PlannedTrip: pickup = Stop(self, trip.origin_position, self.last_stop) diff --git a/jinete/models/services.py b/jinete/models/services.py index ba438c45..f0196eb0 100644 --- a/jinete/models/services.py +++ b/jinete/models/services.py @@ -15,6 +15,8 @@ from typing import ( Dict, Any, + Generator, + Tuple, ) from .positions import ( Position, @@ -50,7 +52,7 @@ def __eq__(self, other: Service) -> bool: def __hash__(self): return hash(tuple(self)) - def __iter__(self): + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: yield from ( ('position', self.position), ('earliest', self.earliest), @@ -58,9 +60,6 @@ def __iter__(self): ('duration', self.duration), ) - def as_dict(self) -> Dict[str, Any]: - return dict(self) - def distance_to(self, other: Service) -> float: return self.position.distance_to(other.position) diff --git a/jinete/models/stops.py b/jinete/models/stops.py index e036d0a8..1b3c9884 100644 --- a/jinete/models/stops.py +++ b/jinete/models/stops.py @@ -9,15 +9,12 @@ ) if TYPE_CHECKING: - from uuid import ( - UUID, - ) from typing import ( - Dict, + Generator, + Tuple, Any, Optional, Iterable, - Tuple, List, ) from .positions import ( @@ -131,10 +128,6 @@ def load_time(self) -> float: def vehicle(self) -> Vehicle: return self.route.vehicle - @property - def vehicle_uuid(self) -> UUID: - return self.vehicle.uuid - @property def stops(self) -> List[Stop]: return self.route.stops @@ -180,11 +173,11 @@ def arrival_time(self): def departure_time(self) -> float: return self.arrival_time + self.load_time - def as_dict(self) -> Dict[str, Any]: - return { - 'vehicle_uuid': self.vehicle_uuid, - 'position': self.position, - } + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('route_uuid', self.route.uuid), + ('position', self.position), + ) def flush(self) -> None: self._down_time = None diff --git a/jinete/models/surfaces.py b/jinete/models/surfaces.py index 34f2352c..b4d1de6e 100644 --- a/jinete/models/surfaces.py +++ b/jinete/models/surfaces.py @@ -28,6 +28,8 @@ Set, Any, Dict, + Generator, + Tuple, ) from uuid import ( UUID, @@ -69,12 +71,10 @@ def distance(self, position_a: Position, position_b: Position) -> float: def time(self, position_a: Position, position_b: Position, **kwargs) -> float: pass - def as_dict(self) -> Dict[str, Any]: - positions_str = ', '.join(str(position) for position in self.positions) - dict_values = { - 'positions': f'{{{positions_str}}}' - } - return dict_values + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('position_coordinates', tuple(position.coordinates for position in self.positions)), + ) class GeometricSurface(Surface): @@ -93,7 +93,7 @@ def distance(self, position_a: Position, position_b: Position) -> float: try: distance = self.cached_distance[position_a][position_b] except KeyError: - distance = self.metric(position_a, position_b) + distance = self.metric(position_a.coordinates, position_b.coordinates) self.cached_distance[position_a][position_b] = distance return distance diff --git a/jinete/models/trips.py b/jinete/models/trips.py index d26ad057..dcb9d712 100644 --- a/jinete/models/trips.py +++ b/jinete/models/trips.py @@ -3,9 +3,10 @@ import logging from typing import ( TYPE_CHECKING, - Optional, ) - +from .abc import ( + Model, +) from .services import ( Service, ) @@ -14,6 +15,9 @@ from typing import ( Dict, Any, + Generator, + Tuple, + Optional, ) from .positions import ( Position, @@ -22,7 +26,7 @@ logger = logging.getLogger(__name__) -class Trip(object): +class Trip(Model): __slots__ = ( 'identifier', 'origin', @@ -92,3 +96,12 @@ def duration(self, now: float): def __deepcopy__(self, memo: Dict[int, Any]) -> Trip: return self + + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('identifier', self.identifier), + ('origin', tuple(self.origin)), + ('destination', tuple(self.destination)), + ('on_time_bonus', self.on_time_bonus), + ('capacity', self.capacity), + ) diff --git a/jinete/models/vehicles.py b/jinete/models/vehicles.py index c9b41b99..935119d7 100644 --- a/jinete/models/vehicles.py +++ b/jinete/models/vehicles.py @@ -1,15 +1,8 @@ from __future__ import annotations import logging -from typing import ( - TYPE_CHECKING, - Set, - Any, - Dict, -) -from uuid import ( - uuid4, -) +from typing import TYPE_CHECKING + from .abc import ( Model, ) @@ -18,8 +11,12 @@ ) if TYPE_CHECKING: - from uuid import ( - UUID, + from typing import ( + Set, + Any, + Dict, + Generator, + Tuple, ) from .positions import ( Position, @@ -33,13 +30,9 @@ class Vehicle(Model): origin: Service destination: Service capacity: float - uuid: UUID def __init__(self, identifier: str, origin: Service, destination: Service = None, capacity: float = 1.0, - route_timeout: float = None, trip_timeout: float = None, uuid: UUID = None): - if uuid is None: - uuid = uuid4() - + route_timeout: float = None, trip_timeout: float = None): self.identifier = identifier self.origin = origin @@ -51,8 +44,6 @@ def __init__(self, identifier: str, origin: Service, destination: Service = None self.route_timeout = route_timeout self.trip_timeout = trip_timeout - self.uuid = uuid - @property def origin_position(self) -> Position: return self.origin.position @@ -91,23 +82,15 @@ def destination_latest(self) -> float: def destination_duration(self) -> float: return self.destination.duration - def __iter__(self): + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: yield from ( - ('origin_position', self.origin_position), - ('origin_earliest', self.origin_earliest), - ('origin_latest', self.origin_latest), - ('destination_position', self.destination_position), - ('destination_earliest', self.destination_earliest), - ('destination_latest', self.destination_latest), + ('origin', tuple(self.origin)), + ('destination', tuple(self.destination)), ('capacity', self.capacity), ('route_timeout', self.route_timeout), ('trip_timeout', self.trip_timeout), - ('uuid', self.uuid), ) - def as_dict(self) -> Dict[str, Any]: - return dict(self) - def __deepcopy__(self, memo: Dict[int, Any]) -> Vehicle: return self @@ -118,15 +101,10 @@ class Fleet(Model): def __init__(self, vehicles: Set[Vehicle]): self.vehicles = vehicles - def __iter__(self): - yield from self.vehicles - - def as_dict(self) -> Dict[str, Any]: - vehicles_str = ', '.join(str(vehicle) for vehicle in self.vehicles) - dict_values = { - 'vehicles': f'{{{vehicles_str}}}' - } - return dict_values + def __iter__(self) -> Generator[Tuple[str, Any], None, None]: + yield from ( + ('vehicle_identifiers', tuple(vehicle.identifier for vehicle in self.vehicles)), + ) def __deepcopy__(self, memo: Dict[int, Any]) -> Fleet: return self diff --git a/jinete/storers/formatters/columnar.py b/jinete/storers/formatters/columnar.py index 6a86c78a..5434649b 100644 --- a/jinete/storers/formatters/columnar.py +++ b/jinete/storers/formatters/columnar.py @@ -18,7 +18,7 @@ def __init__(self, tab_character: str = ' ', *args, **kwargs): def vehicle_to_str(self, vehicle: Vehicle) -> List[str]: return [ - f'ID: "{vehicle.uuid}"', + f'ID: "{vehicle.identifier}"', f'Initial: {vehicle.origin_position}', f'Final: {vehicle.destination_position}', f'Earliest: {vehicle.origin_earliest:7.2f}',