OptaPlanner 员工排班:在优先级 2 班次之前填充优先级 1 班次

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

我正在使用 OptaPlanner 开发员工排班系统,我面临着这样一种情况:我需要确保优先级 1 班次在优先级 2 班次之前被填补。轮班由 Shift 类中的优先级字段标识,该类充当规划实体。

这就是我想要实现的目标:

  • 优先级 1 的班次必须首先分配,并且它们具有更高的重要性。
  • 只有在分配了所有优先级 1 班次后,求解器才应考虑填充优先级 2 班次。 有人可以指导我如何设置 OptaPlanner 配置和约束来实现此行为吗?我尝试了几种方法,但我不确定如何确保求解器在分配班次时尊重此优先顺序。

任何有关如何构建此场景的约束配置的帮助、示例代码片段或指导将不胜感激。预先感谢您的协助!

OptaPlanner 版本:8.29.0.Final

我尝试创建这样的约束

Constraint constraint = constraintFactory.forEach(Shift.class)
                .groupBy(shift -> shift.getWorksite(), ConstraintCollectors.toList())
                .filter((worksite, shiftList) -> filterAlternateShifts(shiftList)).penalizeConfigurable((u, s) -> 20)
                .asConstraint(CONSTRAINT_ALTERNATES_SHOULD_NOT_BE_ASSIGNED_BEFORE_SCHEDULED);

过滤方法定义为:

    private boolean filterAlternateShifts(List<Shift> shiftList) {
        List<Shift> alternates = shiftList.stream().filter(s -> s.getRank().equals(SchedulingConstants.ALTERNATE_SHIFT))
                .collect(Collectors.toList());
        List<Shift> scheduled = shiftList.stream().filter(s -> s.getRank().equals(SchedulingConstants.SCHEDULED_SHIFT))
                .collect(Collectors.toList());

        boolean unassignedScheduledShiftExists = scheduled.stream().anyMatch(s -> s.getClinician() == null);

        boolean assignedAlternateExists = alternates.stream().anyMatch(s -> s.getClinician() != null);

        return unassignedScheduledShiftExists && assignedAlternateExists;

    }

但这不起作用。我尝试了另一种类似于已经定义的 allocateEveryShift 约束的方法


    Constraint assignEveryShift(ConstraintFactory constraintFactory) {
        LOG.trace(SchedulingConstants.METHOD_ENTRY);
        Constraint constraint = constraintFactory.forEachIncludingNullVars(Shift.class)
                .filter(shift -> shift.getClinician() == null).penalizeConfigurable()
                .asConstraint(CONSTRAINT_ASSIGN_EVERY_SHIFT);

        LOG.trace(SchedulingConstants.METHOD_EXIT);
        return constraint;
    }

    Constraint prioritizeScheduledRankShift(ConstraintFactory constraintFactory) {
        LOG.trace(SchedulingConstants.METHOD_ENTRY);
        Constraint constraint = constraintFactory.forEachIncludingNullVars(Shift.class).filter(
                shift -> shift.getClinician() == null && shift.getRank().equals(SchedulingConstants.SCHEDULED_SHIFT))
                .penalizeConfigurable().asConstraint(CONSTRAINT_SHIFT_ALLOCATION_PREFERENCE_TO_SCHEDULED_RANK);

        LOG.trace(SchedulingConstants.METHOD_EXIT);
        return constraint;
    }

不同的是我用硬分来惩罚它。这在一定程度上有效,但并非在所有情况下都有效,我担心它会破坏某些东西。

java constraints quarkus optaplanner timefold
1个回答
0
投票

在 Timefold 中,你不能真正说求解器应该只在完成另一个约束后才处理一个约束。求解器永远不会完成任何约束,并且它总是一起评估所有约束。

获得优先权的方法是惩罚不太重要的转变更多。要么分数水平较低,要么分数水平相同但分数更高;甚至可能显着更高的数量,

10x
100x
x^2
...求解器将努力提高分数,并且当它找到分数越来越好的解决方案时,实现您期望的目标的可能性正在增加。

在这种情况下,我建议将较高优先级的转变设置为硬约束,因为我假设未填充的较高优先级的转变是一个问题,因此该解决方案是不可行的。

但您最需要了解一件事 - 通过本地搜索,不能保证您会找到任何特定的解决方案。如果求解器只能找到打破硬约束的解决方案,那么这就是您将得到的。最终解决方案的质量将是移动多样性、分数计算速度和解决问题所花费的时间的因素。您可以将这些变量推得越高,您的解决方案质量就越好。

© www.soinside.com 2019 - 2024. All rights reserved.