blackopsrepl's picture
Upload 36 files
08e15f1 verified
from solverforge_legacy.solver.score import (
ConstraintFactory,
HardSoftScore,
constraint_provider,
)
from .domain import Vehicle, Visit
VEHICLE_CAPACITY = "vehicleCapacity"
MINIMIZE_TRAVEL_TIME = "minimizeTravelTime"
SERVICE_FINISHED_AFTER_MAX_END_TIME = "serviceFinishedAfterMaxEndTime"
MAX_ROUTE_DURATION = "maxRouteDuration"
@constraint_provider
def define_constraints(factory: ConstraintFactory):
return [
# Hard constraints
vehicle_capacity(factory),
service_finished_after_max_end_time(factory),
# max_route_duration(factory), # Optional extension - disabled by default
# Soft constraints
minimize_travel_time(factory),
]
##############################################
# Hard constraints
##############################################
def vehicle_capacity(factory: ConstraintFactory):
return (
factory.for_each(Vehicle)
.filter(lambda vehicle: vehicle.calculate_total_demand() > vehicle.capacity)
.penalize(
HardSoftScore.ONE_HARD,
lambda vehicle: vehicle.calculate_total_demand() - vehicle.capacity,
)
.as_constraint(VEHICLE_CAPACITY)
)
def service_finished_after_max_end_time(factory: ConstraintFactory):
return (
factory.for_each(Visit)
.filter(lambda visit: visit.is_service_finished_after_max_end_time())
.penalize(
HardSoftScore.ONE_HARD,
lambda visit: visit.service_finished_delay_in_minutes(),
)
.as_constraint(SERVICE_FINISHED_AFTER_MAX_END_TIME)
)
##############################################
# Soft constraints
##############################################
def minimize_travel_time(factory: ConstraintFactory):
return (
factory.for_each(Vehicle)
.penalize(
HardSoftScore.ONE_SOFT,
lambda vehicle: vehicle.calculate_total_driving_time_seconds(),
)
.as_constraint(MINIMIZE_TRAVEL_TIME)
)
##############################################
# Optional constraints (disabled by default)
##############################################
def max_route_duration(factory: ConstraintFactory):
"""
Hard constraint: Vehicle routes cannot exceed 8 hours total duration.
The limit of 8 hours is chosen based on typical driver shift limits:
- PHILADELPHIA: 55 visits across 6 vehicles, routes typically 4-6 hours
- FIRENZE: 77 visits across 6 vehicles, routes can approach 8 hours
Note: A limit that's too low may make the problem infeasible.
Always ensure your constraints are compatible with your data dimensions.
"""
MAX_DURATION_SECONDS = 8 * 60 * 60 # 8 hours
return (
factory.for_each(Vehicle)
.filter(lambda vehicle: len(vehicle.visits) > 0)
.filter(lambda vehicle:
(vehicle.arrival_time - vehicle.departure_time).total_seconds()
> MAX_DURATION_SECONDS
)
.penalize(
HardSoftScore.ONE_HARD,
lambda vehicle: int(
((vehicle.arrival_time - vehicle.departure_time).total_seconds()
- MAX_DURATION_SECONDS) / 60
),
)
.as_constraint(MAX_ROUTE_DURATION)
)