我目前正在处理 Optaplanner 中的一个问题,涉及时间粒度模式中的过度约束会议问题。该问题涉及 1500 个时间粒度、无休止的不同长度的会议、40 个房间和 50 位会议负责人——所有这些都有他们自己的个人时间粒度。我计划提前两周左右,并尝试根据几个限制找到最好的会议安排。
唯一的计划实体是将会议、人员、时间、房间结合起来的“任务”。
问题是,如果这 50 个人中的任何一个最终有空闲时间谷物,我需要奖励/惩罚。我正在考虑两种选择:
对于每个人:遍历所有1500个时间粒和所有预定的会议,交叉检查它们是否一次与一个时间粒发生碰撞,看看哪些被使用了,哪些闲置了,这将是O(N²)的一个大任务。
通过在安排会议时连续标记每个时间粒度来存储一些中间状态,使用 variableListener 设置安排的会议是否引用时间粒度,然后遍历时间粒度本身以查看在 O(n) 时间内有多少从未使用过。
但是,Optaplanner 文档指出,在求解过程中更改时间粒度等事实是一种糟糕的策略。所以,我想知道是否有更好的策略或第三种选择来解决这个问题。
谢谢
灵活的时间线建模是出了名的困难。到目前为止,我们最好的想法是编写一个自定义的
ConstraintCollector
,它按顺序排列事件并能够跟踪它们之间的中断。
可以在这里找到一个这样的收集器的例子。该约束采用所有班次,将它们放在一个时间轴上,将它们分组到由休息分隔的序列中。一旦数据像这样被预处理,惩罚/奖励区块就变得相对容易了。
一些注意事项:
optaplanner-examples
。您应该将其复制粘贴到您自己的代码中,并按照您认为合适的方式进行调整。我尝试了实验收集器,我的作品有点适合我使用。我需要找到中断而不是序列,它确实找到了序列,所以我希望它也能识别中断,但我没有找到。 Maybee 它与连接有关,只连接使用过的时间颗粒。
在 0-9 的 timegrainfact 列表中,我分配了 3 个会议,它确实找到了看起来的序列,但我没有得到任何我正在寻找的休息时间。我想我需要包括非参考 timegrains
ConstraintCollectors.consecutive:
Meetingassign ID: 6 Sequence [7, 5, 6]
Meetingassign ID: 5 Sequence [5, 6, 4]
Meetingassign ID: 4 Sequence [0,1]
ConstraintCollectors.breaks:
null
protected Constraint unusedTimeGrains(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(TimeGrain.class)
.join(MeetingAssignment.class,
Joiners.overlapping((TimeGrain timegrain)-> timegrain.getGrainIndex(),
(TimeGrain timegrain)-> timegrain.getGrainIndex()+1,
(MeetingAssignment assignment) ->assignment.getStartingTimeGrain().getGrainIndex(),
(MeetingAssignment assignment) ->assignment.getStartingTimeGrain().getGrainIndex() + assignment.getDurationInGrains()
)
)
.groupBy((timegrain, assingment) ->
timegrain,
(timegrain, assingment) -> assingment,
ConstraintCollectors.consecutive((timegrain, assingment) ->
timegrain,
TimeGrain::getGrainIndex
)
)
.flattenLast(ConsecutiveInfo::getConsecutiveSequences)
.penalizeConfigurable( (timegrain, assingment,shiftSequence) -> shiftSequence.getLength()) // not-e here is rewarded not penalized, as its overlaps not gaps that is found
.asConstraint(MeetingConstraintConfiguration.UNUSED_TIME_GRAIN);
}