繁体   English   中英

SWI Prolog CLP(FD)计划

[英]SWI Prolog CLP(FD) scheduling

我正在使用CLPFD库解决SWI Prolog中的计划任务。 由于这是我第一次解决比情感问题更严重的事情,因此我可能需要经验丰富的用户提供一些好的建议。 让我简要地描述领域/任务。

我有一个月历。 每天一整天有2个,整夜有2个(长期12小时服务)。 另外,只有周一至周五10个工人8小时(短期服务)。

域约束显然是:

  1. 没有连续的服务(晚上无夜服务,晚上无夜服务)
  2. 上班族可以连续最多连续2个夜间服务
  3. 每个工人一个月的工作时间有限
  4. 有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 为简化起见,每个X SUM_X #=< 200

约束

  • 同一天每个变量的all_distinct() -每个工作人员每天只能提供一项服务
  • global_cardinality()来计算的出现次数为短服务和长期服务列表中的每个数字1..19 -这个定义变量LSUM_XSSUM_X -工人的出现次数XL翁或S园艺服务
  • SUM_X #= 12*LSUM_X + 8*SSUM_X每个工作人员SUM_X #= 12*LSUM_X + 8*SSUM_X
  • DxN_y #\\= Dx+1D_z避免在一夜之后进行全天服务
    • 一堆类似的约束,例如上面的约束,涵盖了所有域约束
  • DxNy #= Dx+1Ny #==> DxNy #\\= Dx+2Ny为避免连续三个夜间服务, xy每种组合都有约束

笔记

所有变量和约束条件都直接在pl脚本中说明。 我不使用prolog谓词来生成约束-因为我在.NET应用程序(前端)中有一个模型,并且可以轻松地将所有内容从.NET代码生成为prolog代码。

我认为我的方法总体上是好的。 在一些较小的示例上运行调度程序效果很好(7天,4个长期服务,1个短期服务,8个工人)。 同样,在完整的案例中,我也能得到一些有效的结果-30天,19名工人,每天4个长期服务和10个短期服务。

但是,我对目前的状态并不完全满意。 让我解释一下原因。

问题

  1. 我阅读了一些有关对调度问题进行建模的文章,其中一些文章使用了一些不同的方法-对于变量(日历字段)和工作者的每种组合,仅介绍布尔变量,以在将工作人员分配给特定日历字段时进行标记。 这是更好的方法吗?
  2. 如果计算日历中的总工作量限制和总时数,您会发现工人并非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过程将以不同于updown (以某种伪随机方式)的其他顺序来获取值。
  3. 我应该如何订购约束? 我认为约束的顺序与标签的效率有关。
  4. 如何调试/优化标签性能? 我希望解决这种类型的任务将花费几秒钟或最多几分钟的时间,以防求和条件非常严格。 例如,使用bisect选项标记需要很长时间。

如果需要,我可以提供更多代码示例。

有很多问题,让我尝试解决一些问题。

...仅针对我的变量(日历字段)和worker的每种组合引入布尔变量,以标记是否将worker分配给特定的日历字段。 这是更好的方法吗?

通常,当使用MILP(混合整数线性规划)求解器时,必须将较高级别的概念(如alldifferent等)表示为线性不等式,才能完成此操作。 这样的公式通常需要大量的布尔变量。 约束编程在这里更加灵活,并且提供了更多的建模选择,但是不幸的是,没有简单的答案,这取决于问题。 您对变量的选择会影响表达问题约束的难度以及解决效率。

因此,解决方案中的SUM看起来像[200,200,200 ... 200,160,140,​​80,50,0,]。 如果工人或多或少地得到同等的利用,我将感到高兴。 是否有一些简单/有效的方法来实现这一目标?

您已经提到了最小化差异的想法,这就是通常要实现这种平衡要求的方式。 它不需要复杂。 如果最初我们有这个不平衡的第一个解决方案:

?- length(Xs,5), Xs#::0..9, sum(Xs)#=20, labeling(Xs).
Xs = [0, 0, 2, 9, 9]

那么只需最小化列表元素的最大值,便已经为您(结合总和约束)提供了一个平衡的解决方案:

?- length(Xs,5), Xs#::0..9, sum(Xs)#=20, Cost#=max(Xs), minimize(labeling(Xs),Cost).
Xs = [4, 4, 4, 4, 4]
Cost = 4

您还可以最小化最大值和最小值之间的差异:

?- length(Xs,5), Xs#::0..9, sum(Xs)#=20, Cost#=max(Xs)-min(Xs), minimize(labeling(Xs),Cost).
Xs = [4, 4, 4, 4, 4]
Cost = 0

甚至平方和 [对不起,我的示例是针对ECLiPSe的,而不是SWI / clpfd的,但应显示出大致的思路。]

我应该如何订购约束? 我认为约束的顺序与标签的效率有关。

您不必为此担心。 尽管它可能会产生一些影响,但是它太不可预测了,并且在很大程度上取决于实现细节,因此无法提出任何一般性建议。 这确实是求解程序实现者的工作。

如何调试/优化标签性能?

对于实际问题,您通常需要(a)针对特定问题的标签启发式方法,以及(b)各种不完整的搜索。 搜索树或搜索进度的可视化可以帮助定制启发式方法。 您可以在本在线课程的第6章中找到有关这些问题的一些讨论。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM