我正在使用CLPFD库解决SWI Prolog中的调度任务。由于这是我第一次解决比情感问题更严重的事情,因此我可能需要经验丰富的用户提供一些好的建议。让我简要地描述领域/任务。
我有一个月的“日历”。每天一整天有2个,整夜有2个(长期12小时服务)。另外,只有周一至周五10个工人8小时(短期服务)。
域约束显然是:
我的方法如下:
对于日历中的每个字段,我都有一个定义的变量:
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
-工人的出现次数{ X
或L
园艺服务中的{1}} S
每个工人SUM_X #= 12*LSUM_X + 8*SSUM_X
-避免在一夜之后进行全天服务
DxN_y #\= Dx+1D_z
-为避免连续三天的夜间服务,DxNy #= Dx+1Ny #==> DxNy #\= Dx+2Ny
和x
的每种组合都有约束条件所有变量和约束条件都直接在pl脚本中说明。我不使用prolog谓词来生成约束-因为我在.NET应用程序(前端)中有一个模型,并且可以轻松地将所有内容从.NET代码生成为prolog代码。
我认为我的方法总体上是好的。在一些较小的示例上运行调度程序效果很好(7天,4个长期服务,1个短期服务,8个工人)。同样,在完整的案例中,我也能得到一些有效的结果-30天,19名工人,每天4个长期服务和10个短期服务。
但是,我对当前状态并不完全满意。让我解释一下原因。
y
。因此,解决方案中的SUM看起来像utilize the first worker for 100% and then grab the next one
。如果工人或多或少地得到同等的利用,我将感到高兴。是否有一些简单/有效的方法来实现这一目标?我曾考虑过定义一些定义,例如定义工作人员之间的差异并将其最小化,但这对我来说听起来很复杂,而且我担心我会花很多时间来计算出来。我使用[200,200,200...200,160,140,80,50,0,]
,但是它只对变量重新排序,因此仍然存在这些差距,只是顺序不同。可能我希望labeling([random_variable(29)], Vars)
过程将以除labeling
或up
之外的其他顺序(以某种伪随机方式)获取值。down
选项标记需要很长时间。如果需要,我可以提供更多代码示例。
答案 0 :(得分:2)
有很多问题,让我尝试解决一些问题。
...对于我的变量(日历字段)和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)一些不完整的搜索。 搜索树或搜索进度的可视化可以帮助定制启发式方法。您可以在chapter 6 of this online course中找到有关这些问题的一些讨论。