使用累积量

Mor*_*enM 4 prolog sicstus-prolog clpfd

我正在研究一个使用cumulatives/[2,3]谓词的问题.但是当我尝试将其与minimizein 相结合时,我的表现会非常糟糕labeling

我有以下演示.10个任务,所有持续时间为1,4的机器,所有容量均为1.我的目标是尽量减少总时间,即minimize(maximum(Es)):

:- use_module(library(clpfd)).
:- use_module(library(lists)).

go( Ss, Es, Ms, Tm, Lab ) :-

    Ss = [S1, S2, S3, S4,S5,S6,S7,S8,S9,S10], %Starttimes
    Es = [E1, E2, E3, E4,E5,E6,E7,E8,E9,E10], %Endtimeds
    Ms = [M1, M2, M3, M4,M5,M6,M7,M8,M9,M10], %MachineIds


    domain(Ss, 1, 20),
    domain(Es, 1, 20),
    domain(Ms, 1, 10),

    %All task has duration = 1
    Tasks = [
        task(  S1, 1,  E1,  1, M1 ), 
        task(  S2, 1,  E2,  1, M2 ), 
        task(  S3, 1,  E3,  1, M3 ), 
        task(  S4, 1,  E4,  1, M4 ), 
        task(  S5, 1,  E5,  1, M5 ), 
        task(  S6, 1,  E6,  1, M6 ), 
        task(  S7, 1,  E7,  1, M7 ), 
        task(  S8, 1,  E8,  1, M8 ), 
        task(  S9, 1,  E9,  1, M9 ), 
        task( S10, 1,  E10, 1, M10 ) 
    ],

    %All machines has resource capacity = 1
    Machines = [
        machine(  1, 1 ),
        machine(  2, 1 ),
        machine(  3, 1 ),
        machine(  4, 1 ) 
    ],

    cumulatives(Tasks, Machines, [bound(upper)] ),

    maximum( MaxEndTime, Es ),

    %Make the list of options to pass to the labeling predicate
    append( [ [minimize(MaxEndTime)], [time_out( Tm, _)], Lab ], LabOpt ),
    %The variables to lable:
    append([Ms, Ss ], Vars),

    labeling( LabOpt, Vars). 
Run Code Online (Sandbox Code Playgroud)

如果我现在运行并解决1秒钟,我得到:

| ?- go( S, E, M, 1000, []).
E = [2,3,4,5,6,7,8,9,10,11],
M = [1,1,1,1,1,1,1,1,1,1],
S = [1,2,3,4,5,6,7,8,9,10] ? 
Run Code Online (Sandbox Code Playgroud)

即所有任务都已安排在机器1上运行

在看到任何最小化迹象之前,我需要运行求解器30秒:

| ?- go( S, E, M, 30000, []).
E = [2,3,4,5,6,7,8,9,10,2],
M = [1,1,1,1,1,1,1,1,1,2],
S = [1,2,3,4,5,6,7,8,9,1] ? 
Run Code Online (Sandbox Code Playgroud)

如果我跑了60秒,我开始得到可接受的结果:

| ?- go( S, E, M, 60000, []).
E = [2,3,4,2,3,4,2,3,4,2],
M = [1,1,1,2,2,2,3,3,3,4],
S = [1,2,3,1,2,3,1,2,3,1] ? 
Run Code Online (Sandbox Code Playgroud)

我觉得这花了太长时间.为什么需要这么长时间的任何评论?

Mat*_*son 5

我找到了两个标准技巧来加速你的代码.

首先,变量订单.您在S变量之前标记了所有M变量.这需要大约51秒.一次修复一个任务的S和M要好得多.即可变顺序[S1,M1,S2,M2,S3,M3,S4,M4,S5,M5,S6,M6,S7,M7,S8,M8,S9,M9,S10,M10].这将时间缩短到2秒左右.

其次,您的任务是可以互换的,您的机器也是如此.也许并非总是如此,如果你的代码是一个玩具的例子,而不是真实的东西.但是如果你有这样的对称性,你可以通过打破对称性来防止搜索进入大量的culs de sac,例如:

lex_chain([[S1,M1],[S2,M2],[S3,M3],[S4,M4],[S5,M5],[S6,M6],[S7,M7],[S8,M8],[S9,M9],[S10,M10]]),
Run Code Online (Sandbox Code Playgroud)

这将时间缩短到10毫秒.

这些技巧都是约束编程技术的标准.


Mor*_*enM 3

通过在谓词task_intervals(true)上使用选项,cumulatives速度确实得到了提高:

cumulatives(Tasks, Machines, [bound(upper),task_intervals(true)] )
Run Code Online (Sandbox Code Playgroud)

在不改变任何其他内容的情况下,原始问题中的代码的求解时间为 2 毫秒。