我正在研究时间折叠优化问题,根据技术人员技能和能力等限制将技术人员分配给设备。然而,硬性约束(例如技术人员能力)并未得到正确执行。特别是,我注意到一些技术人员超出了他们的可用工作时间(rbh_to_plan)而没有受到惩罚,即使我在constraints.py中为此定义了约束。
以下是我的代码的关键部分:
1。技术人员和设备定义 (domain.py):
@dataclass
class Technician:
id: int
name: str
rbh_to_plan: float
rbh_assigned: float
iums: Set[str]
# Technician class with available hours and skills
@planning_entity
@dataclass
class Device:
index: int
ium: str
technician: Technician | None = field(default=None)
# Devices assigned to technicians
2。约束定义(constraints.py):
def technician_capacity_hard(constraint_factory: ConstraintFactory):
return (constraint_factory
.for_each(Device)
.filter(lambda device: device.technician is not None)
.group_by(lambda device: device.technician, ConstraintCollectors.sum(lambda device: device.rbh_norm))
.filter(lambda technician, total_rbh_norm: total_rbh_norm > technician.rbh_to_plan)
.penalize(HardSoftScore.ONE_HARD)
.as_constraint("Technician capacity (hard constraint)"))
3.主求解器代码(main.py):
solver_factory = SolverFactory.create(
SolverConfig(
solution_class=DeviceSchedule,
entity_class_list=[Device],
score_director_factory_config=ScoreDirectorFactoryConfig(
constraint_provider_function=define_constraints # Enabling constraints
),
termination_config=TerminationConfig(
best_score_limit="0hard/1000soft",
spent_limit=Duration(minutes=1)
)
)
)
调试步骤:
问题:
我怀疑发生的事情是
rbh_norm
是一个浮点数,所以当它被用作ConstraintCollector.sum
中的返回值时,它被转换为int(丢失小数点后的任何值)。 ConstraintCollector.sum
的单参数变体需要一个返回 int
的函数。
该约束有效,前提是
rbh_norm
和 int
。
ConstraintVerifier
是你的朋友。例如:
from timefold.solver.test import *
constraint_verifier = ConstraintVerifier.build(define_constraints, DeviceSchedule, Device)
# This will raise an AssertionError (due to float being cast to int)
# AssertionError: Broken expectation.
# Constraint: org.jpyinterpreter.user.__main__/Technician capacity (hard constraint)
# Expected penalty but there was none.
#
# Explanation of score (0hard/0soft):
# Constraint matches:
# 0: constraint (Technician capacity (hard constraint)) has 0 matches:
# Indictments:
tech = Technician(id=0, rbh_to_plan=0.1, ...)
(constraint_verifier.verify_that(technician_capacity_hard)
.given(Device(index=0, rbh_norm=0.1, technician=tech, ...),
Device(index=1, rbh_norm=0.1, technician=tech, ...))
.penalizes()
)
# This assertion would pass
tech = Technician(id=0, rbh_to_plan=1, ...)
(constraint_verifier.verify_that(technician_capacity_hard)
.given(Device(index=0, rbh_norm=1, technician=tech, ...),
Device(index=1, rbh_norm=1, technician=tech, ...))
.penalizes()
)
这允许您验证约束是否正确工作。 不幸的是,您无法使用 Python 调试器来调试约束,因为 它们是用 Java 进行评估的。调试它的方法可能是添加一个打印其参数的无操作过滤器:
def debug(*args):
print(args)
return True
def technician_capacity_hard(constraint_factory: ConstraintFactory):
return (constraint_factory
.for_each(Device)
.filter(lambda device: device.technician is not None)
.group_by(lambda device: device.technician, ConstraintCollectors.sum(lambda device: device.rbh_norm))
.filter(lambda a, b: debug(a, b))
.filter(lambda technician, total_rbh_norm: total_rbh_norm > technician.rbh_to_plan)
.penalize(HardSoftScore.ONE_HARD)
.as_constraint("Technician capacity (hard constraint)"))