首页 > 解决方案 > Optaplanner 中的建模活动调度

问题描述

我正在尝试解决 Optaplanner 中的一个特定问题,但我无法弄清楚如何将其最好地融入域模型。

我的问题涉及许多“组”实体,每个实体每天有 3 个时段,在这些时段中他们可以有几个活动中的任何一个。同样,每个组对他们在两周的时间表中可以进行的每个活动的确切数量都有独特的要求。对于这个问题,我考虑有四个主要对象:组、活动、日和周期。在这种情况下,我应该使用什么作为我的 PlanningEntity 和 PlanningVariable?

标签: javaoptimizationoptaplanner

解决方案


看起来您将需要一个额外的类来充当您的 PlanningEntity,这将是一个多对多的“加入”类。类似于 ActivityAssignment 的东西,它将具有 Group、Period 和 Activity PlanningVariable 字段。

活动实例仅代表可能活动的列表。ActivityAssignment 是活动与组和时间(或时期)相关联的地方。

Day 和 Period 类也稍微复杂一些。您需要在日程表中的每一天都有一个 Day 实例。如果这是一个重复的时间表,那么 Day 可能在概念上代表第 1 周的星期一;周二,第 1 周;...; 到第 2 周的星期五。如果不是重复的时间表,那么每个 Day 实例将代表一个日历日期。无论如何,Day 类可以有三个 Period 成员:Period1、Period2 和 Period3(或者,如果将来可能增长,您可以使用 Periods 的集合。根据规则逻辑,实现规则取决于您使用的是集合还是三个离散的期间字段)。

Period 将与 Day 具有双向关系。Day 会有 getPeriod1()、getPeriod2()、getPeriod3() 等方法。Period 会有一个方法 getDay()。这就是您确定特定 ActivityAssignment 所属的时期和日期的方式,例如 activityAssignment.getPeriod().getDay()。

要计算一个组的活动数量,您可以实施一个 drools 规则或查询以选择所有 ActivityAssignments ($aa) 其中 $aa.group.id == "this_group" 和 $aa.activity.id == "that_activity ”。如果该数字大于组允许的最大值(可能类似于 group.getMaxActivityCount("that_activity")),则向 scoreHolder 添加适当的惩罚。

编辑:为了完整起见,您将拥有一个带有 @PlanningSolution 注释的解决方案类,其中包含组、活动和期间的问题事实集合。您将在循环中使用 3 个 Period 实例初始化所有 Day 实例,但您还将每个 Period 实例添加到一个单独的列表中,然后您将在 PlanningSolution 类上设置该列表。

您将有一个类似这样的规划解决方案类:

@PlanningSolution
public class ActivitySchedule {

    @ValueRangeProvider(id = "groupRange")
    private List<Group> groups;

    @ValueRangeProvider(id = "periodRange")
    private List<Period> periods;

    @ValueRangeProvider(id = "activityRange")
    private List<Activity> activities;

    private HardSoftScore score;

    //...
}

初始化解决方案时,请执行以下操作:

// Coded for clarity, not for efficiency ;)
for(int dayCount = 0; dayCount < 10; dayCount++){
    Day day = new Day();
    day.setIndex(dayCount);
    //...

    Period period1 = new Period(day);
    day.setPeriod1(period1);

    Period period2 = new Period(day);
    day.setPeriod2(period1);

    Period period3 = new Period(day);
    day.setPeriod3(period3);

    dayList.add(day);
    periodList.add(period1);
    periodList.add(period2);
    periodList.add(period3);
}

activitySolution.setDays(dayList);
activitySolution.setPeriods(periodList);
activitySolution.setActivities(activityList);
//...

推荐阅读