【发布时间】:2019-08-30 19:02:38
【问题描述】:
我正在使用 CLPFD 库在 SWI Prolog 中解决调度任务。由于这是我第一次解决比 sendmory 更严重的问题,我可能需要更有经验的用户提供一些好的建议。让我简要描述一下领域/任务。
域
我有一个月的“日历”。每天全天 2 个,整晚 2 个(长 12 小时服务)。还有,只有周一至周五 10 名以上的工人工作 8 小时(短期服务)。
显然,域约束是:
- 没有连续服务(没有昼夜交替,反之亦然,没有短日夜连夜服务)
- On worker 最多可以连续提供 2 次夜间服务
- 每个工人一个月的工作时间有限
- 有 19 名工人可用
我的做法如下:
变量
对于日历中的每个字段,我都定义了一个变量:
-
DxD_y其中x是当日编号,y是长日服务的 1 或 2 -
DxN_y其中x是当天的编号,y是长夜服务的 1 或 2 -
DxA_y其中x是当日编号,y是 0 .. 9 用于短日服务 -
SUM_x其中x是工人编号 (1..19),表示工人的小时总和
每个D 变量都有一个域1..19。现在为了简化它,SUM_X #=< 200 对应每个 X。
约束
-
all_distinct()对于同一天的每个变量 - 每个工人每天只能提供一项服务 -
global_cardinality()计算每个数字 1..19 的出现次数,用于短服务和长服务列表 - 这定义变量LSUM_X和SSUM_X- 在Long 或 @ 中工作人员X的出现次数987654342@hort 服务 -
SUM_X #= 12*LSUM_X + 8*SSUM_X每个工人 -
DxN_y #\= Dx+1D_z- 避免一晚后长时间服务- 一组类似的约束,如上述约束,涵盖所有域约束
-
DxNy #= Dx+1Ny #==> DxNy #\= Dx+2Ny- 为避免连续三个夜间服务,x和y的每个组合都有约束
注意事项
所有变量和约束都直接在pl脚本中说明。我不使用 prolog 谓词来生成约束 - 因为我在 .NET 应用程序(前端)中有一个模型,我可以轻松地将所有东西从 .NET 代码生成到 prolog 代码中。
我认为我的方法总体上不错。在一些较小的示例上运行调度程序效果很好(7 天,4 个长期服务,1 个短期服务,8 个工作人员)。此外,我还能够在完整的案例中获得一些有效的结果 - 30 天,19 名工人,每天 4 次长服务和 10 次短服务。
但是,我对目前的状态并不完全满意。让我解释一下原因。
问题
- 我阅读了一些关于建模调度问题的文章,其中一些使用了一些不同的方法 - 只为我的变量(日历字段)和 worker 的每个组合引入布尔变量,以标记是否将 worker 分配给特定的日历字段。这是更好的方法吗?
- 如果您计算日历中的总工作量限制和总小时数,您会发现工人的利用率不是 100%。但是求解器最有可能以这种方式创建解决方案:
utilize the first worker for 100% and then grab the next one。所以解决方案中的 SUM 看起来像[200,200,200...200,160,140,80,50,0,]。如果工人或多或少得到平等利用,我会很高兴。有没有一些简单/有效的方法来实现这一目标?我考虑过定义有点像定义工人之间的差异并将其最小化,但这对我来说听起来很复杂,恐怕我需要很长时间才能计算出来。我使用labeling([random_variable(29)], Vars),但它只对变量重新排序,所以仍然存在这些差距,只是顺序不同。可能我希望labeling过程以up或down以外的其他顺序获取值(以某种伪随机方式)。 - 我应该如何排序约束?我认为约束的顺序关系到标签的效率。
- 如何调试/优化标签性能?我希望解决这类任务需要几秒钟或最多几分钟,以防求和的条件非常紧张。例如,使用
bisect选项标记需要很长时间。
如果需要,我可以提供更多代码示例。
【问题讨论】:
标签: prolog scheduling swi-prolog clpfd clp