Spaces:
Sleeping
Sleeping
| from solverforge_legacy.solver.test import ConstraintVerifier | |
| from vehicle_routing.domain import Location, Vehicle, VehicleRoutePlan, Visit | |
| from vehicle_routing.constraints import ( | |
| define_constraints, | |
| vehicle_capacity, | |
| service_finished_after_max_end_time, | |
| minimize_travel_time, | |
| ) | |
| from datetime import datetime, timedelta | |
| # Driving times calculated using Haversine formula for realistic geographic distances. | |
| # These test coordinates at 50 km/h average speed yield: | |
| # LOCATION_1 to LOCATION_2: 40018 seconds (~11.1 hours, ~556 km) | |
| # LOCATION_2 to LOCATION_3: 40025 seconds (~11.1 hours, ~556 km) | |
| # LOCATION_1 to LOCATION_3: 11322 seconds (~3.1 hours, ~157 km) | |
| LOCATION_1 = Location(latitude=0, longitude=0) | |
| LOCATION_2 = Location(latitude=3, longitude=4) | |
| LOCATION_3 = Location(latitude=-1, longitude=1) | |
| DEPARTURE_TIME = datetime(2020, 1, 1) | |
| MIN_START_TIME = DEPARTURE_TIME + timedelta(hours=2) | |
| MAX_END_TIME = DEPARTURE_TIME + timedelta(hours=5) | |
| SERVICE_DURATION = timedelta(hours=1) | |
| constraint_verifier = ConstraintVerifier.build( | |
| define_constraints, VehicleRoutePlan, Vehicle, Visit | |
| ) | |
| def test_vehicle_capacity_unpenalized(): | |
| vehicleA = Vehicle( | |
| id="1", name="Alpha", capacity=100, home_location=LOCATION_1, departure_time=DEPARTURE_TIME | |
| ) | |
| visit1 = Visit( | |
| id="2", | |
| name="John", | |
| location=LOCATION_2, | |
| demand=80, | |
| min_start_time=MIN_START_TIME, | |
| max_end_time=MAX_END_TIME, | |
| service_duration=SERVICE_DURATION, | |
| ) | |
| connect(vehicleA, visit1) | |
| ( | |
| constraint_verifier.verify_that(vehicle_capacity) | |
| .given(vehicleA, visit1) | |
| .penalizes_by(0) | |
| ) | |
| def test_vehicle_capacity_penalized(): | |
| vehicleA = Vehicle( | |
| id="1", name="Alpha", capacity=100, home_location=LOCATION_1, departure_time=DEPARTURE_TIME | |
| ) | |
| visit1 = Visit( | |
| id="2", | |
| name="John", | |
| location=LOCATION_2, | |
| demand=80, | |
| min_start_time=MIN_START_TIME, | |
| max_end_time=MAX_END_TIME, | |
| service_duration=SERVICE_DURATION, | |
| ) | |
| visit2 = Visit( | |
| id="3", | |
| name="Paul", | |
| location=LOCATION_3, | |
| demand=40, | |
| min_start_time=MIN_START_TIME, | |
| max_end_time=MAX_END_TIME, | |
| service_duration=SERVICE_DURATION, | |
| ) | |
| connect(vehicleA, visit1, visit2) | |
| ( | |
| constraint_verifier.verify_that(vehicle_capacity) | |
| .given(vehicleA, visit1, visit2) | |
| .penalizes_by(20) | |
| ) | |
| def test_service_finished_after_max_end_time_unpenalized(): | |
| vehicleA = Vehicle( | |
| id="1", name="Alpha", capacity=100, home_location=LOCATION_1, departure_time=DEPARTURE_TIME | |
| ) | |
| visit1 = Visit( | |
| id="2", | |
| name="John", | |
| location=LOCATION_3, | |
| demand=80, | |
| min_start_time=MIN_START_TIME, | |
| max_end_time=MAX_END_TIME, | |
| service_duration=SERVICE_DURATION, | |
| ) | |
| connect(vehicleA, visit1) | |
| ( | |
| constraint_verifier.verify_that(service_finished_after_max_end_time) | |
| .given(vehicleA, visit1) | |
| .penalizes_by(0) | |
| ) | |
| def test_service_finished_after_max_end_time_penalized(): | |
| vehicleA = Vehicle( | |
| id="1", name="Alpha", capacity=100, home_location=LOCATION_1, departure_time=DEPARTURE_TIME | |
| ) | |
| visit1 = Visit( | |
| id="2", | |
| name="John", | |
| location=LOCATION_2, | |
| demand=80, | |
| min_start_time=MIN_START_TIME, | |
| max_end_time=MAX_END_TIME, | |
| service_duration=SERVICE_DURATION, | |
| ) | |
| connect(vehicleA, visit1) | |
| # With Haversine formula: | |
| # Travel time to LOCATION_2: 40018 seconds = 11.12 hours | |
| # Arrival time: 2020-01-01 11:06:58 | |
| # Service duration: 1 hour | |
| # End service: 2020-01-01 12:06:58 | |
| # Max end time: 2020-01-01 05:00:00 | |
| # Delay: 7 hours 6 minutes 58 seconds = 426.97 minutes, rounded up = 427 minutes | |
| ( | |
| constraint_verifier.verify_that(service_finished_after_max_end_time) | |
| .given(vehicleA, visit1) | |
| .penalizes_by(427) | |
| ) | |
| def test_total_driving_time(): | |
| vehicleA = Vehicle( | |
| id="1", name="Alpha", capacity=100, home_location=LOCATION_1, departure_time=DEPARTURE_TIME | |
| ) | |
| visit1 = Visit( | |
| id="2", | |
| name="John", | |
| location=LOCATION_2, | |
| demand=80, | |
| min_start_time=MIN_START_TIME, | |
| max_end_time=MAX_END_TIME, | |
| service_duration=SERVICE_DURATION, | |
| ) | |
| visit2 = Visit( | |
| id="3", | |
| name="Paul", | |
| location=LOCATION_3, | |
| demand=40, | |
| min_start_time=MIN_START_TIME, | |
| max_end_time=MAX_END_TIME, | |
| service_duration=SERVICE_DURATION, | |
| ) | |
| connect(vehicleA, visit1, visit2) | |
| # With Haversine formula: | |
| # LOCATION_1 -> LOCATION_2: 40018 seconds | |
| # LOCATION_2 -> LOCATION_3: 40025 seconds | |
| # LOCATION_3 -> LOCATION_1: 11322 seconds | |
| # Total: 91365 seconds | |
| ( | |
| constraint_verifier.verify_that(minimize_travel_time) | |
| .given(vehicleA, visit1, visit2) | |
| .penalizes_by(91365) | |
| ) | |
| def connect(vehicle: Vehicle, *visits: Visit): | |
| vehicle.visits = list(visits) | |
| for i in range(len(visits)): | |
| visit = visits[i] | |
| visit.vehicle = vehicle | |
| if i > 0: | |
| visit.previous_visit = visits[i - 1] | |
| if i < len(visits) - 1: | |
| visit.next_visit = visits[i + 1] | |
| visit.update_arrival_time() | |