为什么我的时间折叠优化没有正确执行硬约束?

问题描述 投票:0回答:1

我正在研究时间折叠优化问题,根据技术人员技能和能力等限制将技术人员分配给设备。然而,硬性约束(例如技术人员能力)并未得到正确执行。特别是,我注意到一些技术人员超出了他们的可用工作时间(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)
        )
    )
)

调试步骤:

  1. 我打印了每个技术人员的总分配时间(rbh_norm), 并且在很多情况下,这个值超过了 rbh_to_plan。
  2. HardSoftScore.ONE_HARD 用于惩罚硬约束 违规,但似乎没有正确触发。
  3. 我的软约束,例如奖励技术人员任务,是 按预期工作。

问题:

  • 为什么不对技术人员能力施加硬性约束 正确吗?
  • 我对 rbh_norm 进行分组和求和的方式是否存在问题 约束中的值?
  • 调试约束提供程序问题的最佳实践是什么 在时间折叠中?
python optaplanner timefold
1个回答
0
投票
  1. 我怀疑发生的事情是

    rbh_norm
    是一个浮点数,所以当它被用作
    ConstraintCollector.sum
    中的返回值时,它被转换为int(丢失小数点后的任何值)。
    ConstraintCollector.sum
    的单参数变体需要一个返回
    int
    的函数。

  2. 该约束有效,前提是

    rbh_norm
    int

  3. 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)"))
© www.soinside.com 2019 - 2024. All rights reserved.