diff --git a/jinete/algorithms/utils/crossers/stateless.py b/jinete/algorithms/utils/crossers/stateless.py index 5be82762..af5e6cfc 100644 --- a/jinete/algorithms/utils/crossers/stateless.py +++ b/jinete/algorithms/utils/crossers/stateless.py @@ -3,6 +3,11 @@ import logging from typing import TYPE_CHECKING import itertools as it + +from cached_property import ( + cached_property, +) + from .abc import ( Crosser, ) @@ -24,20 +29,12 @@ class StatelessCrosser(Crosser): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._iterator = None - def flush(self): - self._iterator = None - - @property - def iterator(self): - if self._iterator is None: - self._iterator = self._calculate_iterator() - return self._iterator + for key in ('iterator',): + self.__dict__.pop(key, None) - def _calculate_iterator(self) -> Iterator[PlannedTrip]: + @cached_property + def iterator(self) -> Iterator[PlannedTrip]: for route, trip in it.product(self.attractive_routes, self.pending_trips): logger.debug(f'Yielding ({route}, {trip})...') planned_trip = route.conjecture_trip(trip) diff --git a/jinete/models/criterions.py b/jinete/models/criterions.py index ce38d3e5..5a4e5661 100644 --- a/jinete/models/criterions.py +++ b/jinete/models/criterions.py @@ -59,7 +59,7 @@ def scoring(self, planned_trip: PlannedTrip) -> float: if not planned_trip.feasible: return MAX_FLOAT - return planned_trip.delivery_time - planned_trip.route.last_departure_time + return planned_trip.pickup_time - planned_trip.route.last_departure_time class LongestTimePlannedTripCriterion(PlannedTripCriterion): @@ -75,7 +75,7 @@ def scoring(self, planned_trip: PlannedTrip) -> float: if not planned_trip.feasible: return MIN_FLOAT - return planned_trip.delivery_time - planned_trip.route.last_departure_time + return planned_trip.pickup_time - planned_trip.route.last_departure_time class LongestUtilTimePlannedTripCriterion(PlannedTripCriterion): diff --git a/jinete/models/planned_trips.py b/jinete/models/planned_trips.py index a0889a1d..afc6637a 100644 --- a/jinete/models/planned_trips.py +++ b/jinete/models/planned_trips.py @@ -113,9 +113,9 @@ def capacity(self): @cached_property def feasible(self) -> bool: - if not self.trip.origin_earliest <= self.pickup_time <= self.trip.origin_latest: + if not self.pickup_time <= self.trip.origin_latest: return False - if not self.trip.destination_earliest <= self.delivery_time <= self.trip.destination_latest: + if not self.delivery_time <= self.trip.destination_latest: return False time_to_return = self.trip.destination_position.time_to(self.vehicle.destination_position, self.delivery_time) diff --git a/jinete/models/stops.py b/jinete/models/stops.py index e8967eb9..b67ddda8 100644 --- a/jinete/models/stops.py +++ b/jinete/models/stops.py @@ -85,15 +85,21 @@ def extend_deliveries(self, iterable: Iterable[PlannedTrip]) -> None: @property def down_time(self) -> float: - return max((pt.down_time for pt in self.pickups), default=0.0) + if not any(self.pickups): + return 0.0 + return max(pt.down_time for pt in self.pickups) @property def earliest(self): - return max((pt.trip.origin_earliest for pt in self.pickups), default=0.0) + if not any(self.pickups): + return 0.0 + return max(pt.trip.origin_earliest for pt in self.pickups) @property def load_time(self) -> float: - return max((pt.trip.origin_duration for pt in self.planned_trips), default=0.0) + if not any(self.planned_trips): + return 0.0 + return max(pt.trip.origin_duration for pt in self.planned_trips) @property def vehicle(self) -> Vehicle: diff --git a/jinete/models/trips.py b/jinete/models/trips.py index 6303357d..65feb5e4 100644 --- a/jinete/models/trips.py +++ b/jinete/models/trips.py @@ -4,6 +4,9 @@ from typing import ( TYPE_CHECKING, ) + +from cached_property import cached_property + from .abc import ( Model, ) @@ -91,7 +94,7 @@ def destination_duration(self) -> float: def empty(self) -> bool: return self.capacity == 0 - @property + @cached_property def distance(self) -> float: return self.origin_position.distance_to(self.destination_position) diff --git a/tests/test_algorithms/test_utils/test_crossers/test_stateless.py b/tests/test_algorithms/test_utils/test_crossers/test_stateless.py index 18121ec2..88c2d7ff 100644 --- a/tests/test_algorithms/test_utils/test_crossers/test_stateless.py +++ b/tests/test_algorithms/test_utils/test_crossers/test_stateless.py @@ -17,8 +17,22 @@ def test_creation(self): job=job, fleet=fleet, ) - self.assertEqual(dispatcher.job, job) - self.assertEqual(dispatcher.fleet, fleet) + self.assertEqual(job, dispatcher.job) + self.assertEqual(fleet, dispatcher.fleet) + self.assertEqual(len(job.trips), len(list(dispatcher.iterator))) + + def test_flush(self): + job = jit.Job(generate_trips(10), objective_cls=jit.DialARideObjective) + fleet = jit.Fleet(generate_vehicles(10)) + dispatcher = jit.StatelessCrosser( + job=job, + fleet=fleet, + ) + self.assertNotIn('iterator', dispatcher.__dict__) + list(dispatcher.iterator) + self.assertIn('iterator', dispatcher.__dict__) + dispatcher.flush() + self.assertNotIn('iterator', dispatcher.__dict__) if __name__ == '__main__': diff --git a/tests/test_models/test_criterions/test_longest_time.py b/tests/test_models/test_criterions/test_longest_time.py index 0f65e03c..0c56945b 100644 --- a/tests/test_models/test_criterions/test_longest_time.py +++ b/tests/test_models/test_criterions/test_longest_time.py @@ -51,7 +51,7 @@ def setUpClass(cls) -> None: identifier='TEST_1', origin=jit.Service( position=surface.get_or_create_position([0, 0]), - earliest=0.0, + earliest=1.0, latest=20.0, ), destination=jit.Service( @@ -80,12 +80,12 @@ def test_scoring(self): criterion = jit.LongestTimePlannedTripCriterion() self.assertEqual( - 2.0, + 0.0, criterion.scoring(self.planned_trips[0]), ) self.assertEqual( - 20.0, + 1.0, criterion.scoring(self.planned_trips[1]), ) diff --git a/tests/test_models/test_criterions/test_shortest_time.py b/tests/test_models/test_criterions/test_shortest_time.py index 5b1c6147..2743fd94 100644 --- a/tests/test_models/test_criterions/test_shortest_time.py +++ b/tests/test_models/test_criterions/test_shortest_time.py @@ -53,7 +53,7 @@ def setUpClass(cls) -> None: identifier='TEST_1', origin=jit.Service( position=surface.get_or_create_position([0, 0]), - earliest=0.0, + earliest=1.0, latest=20.0, ), destination=jit.Service( @@ -82,12 +82,12 @@ def test_scoring(self): criterion = jit.ShortestTimePlannedTripCriterion() self.assertEqual( - 2.0, + 0.0, criterion.scoring(self.planned_trips[0]), ) self.assertEqual( - 20.0, + 1.0, criterion.scoring(self.planned_trips[1]), )