Spaces:
Sleeping
Sleeping
File size: 1,918 Bytes
e40294e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
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"
@constraint_provider
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)
)
|