Spaces:
Sleeping
Sleeping
| from solverforge_legacy.solver.score import ( | |
| constraint_provider, | |
| ConstraintFactory, | |
| HardSoftDecimalScore, | |
| ) | |
| from .domain import Trolley | |
| REQUIRED_NUMBER_OF_BUCKETS = "Required number of buckets" | |
| MINIMIZE_ORDER_SPLIT = "Minimize order split by trolley" | |
| MINIMIZE_DISTANCE = "Minimize total distance" | |
| def define_constraints(factory: ConstraintFactory): | |
| return [ | |
| # Hard constraints | |
| required_number_of_buckets(factory), | |
| # Soft constraints | |
| minimize_order_split_by_trolley(factory), | |
| minimize_total_distance(factory), | |
| ] | |
| def required_number_of_buckets(factory: ConstraintFactory): | |
| """ | |
| Hard: Ensure trolley has enough buckets for all orders. | |
| """ | |
| return ( | |
| factory.for_each(Trolley) | |
| .filter(lambda trolley: trolley.calculate_excess_buckets() > 0) | |
| .penalize( | |
| HardSoftDecimalScore.ONE_HARD, | |
| lambda trolley: trolley.calculate_excess_buckets() | |
| ) | |
| .as_constraint(REQUIRED_NUMBER_OF_BUCKETS) | |
| ) | |
| def minimize_order_split_by_trolley(factory: ConstraintFactory): | |
| """ | |
| Soft: Orders should ideally be on the same trolley. | |
| """ | |
| return ( | |
| factory.for_each(Trolley) | |
| .filter(lambda trolley: len(trolley.steps) > 0) | |
| .penalize( | |
| HardSoftDecimalScore.ONE_SOFT, | |
| lambda trolley: trolley.calculate_order_split_penalty() | |
| ) | |
| .as_constraint(MINIMIZE_ORDER_SPLIT) | |
| ) | |
| def minimize_total_distance(factory: ConstraintFactory): | |
| """ | |
| Soft: Minimize total distance traveled by all trolleys. | |
| Aggregated at Trolley level (like vehicle-routing) for performance. | |
| """ | |
| return ( | |
| factory.for_each(Trolley) | |
| .penalize( | |
| HardSoftDecimalScore.ONE_SOFT, | |
| lambda trolley: trolley.calculate_total_distance() | |
| ) | |
| .as_constraint(MINIMIZE_DISTANCE) | |
| ) | |