Optimization 基于代码约束规划的作业计划优化

Optimization 基于代码约束规划的作业计划优化,optimization,mathematical-optimization,solver,constraint-programming,minizinc,Optimization,Mathematical Optimization,Solver,Constraint Programming,Minizinc,请您帮助优化工作代码: 任务:有一个会议有6倍的时间间隔。出席会议的发言者有3人,每个人都有特定的发言时间。每个扬声器将按预定的插槽数呈现 目标:制定演讲者最早完成的时间表 示例:发言者A、B和C。谈话持续时间=[1、2、1] 扬声器可用性: +---+------+------+------+ | | Sp.A | Sp.B | Sp.C | +---+------+------+------+ | 1 | | Busy | | | 2 | Busy | Busy |

请您帮助优化工作代码:

任务:有一个会议有6倍的时间间隔。出席会议的发言者有3人,每个人都有特定的发言时间。每个扬声器将按预定的插槽数呈现

目标:制定演讲者最早完成的时间表

示例:发言者A、B和C。谈话持续时间=[1、2、1]

扬声器可用性:

+---+------+------+------+
|   | Sp.A | Sp.B | Sp.C |
+---+------+------+------+
| 1 |      | Busy |      |
| 2 | Busy | Busy | Busy |
| 3 | Busy | Busy |      |
| 4 |      |      |      |
| 5 |      |      | Busy |
| 6 | Busy | Busy |      |
+---+------+------+------+
链接到工作代码:

我希望优化的内容:

% ensure allocated slots don't overlap and the allocated slot is free for the speaker
constraint 
    forall(i in 1..num_speakers) (
        ending_slot[i] = starting_slot[i] + app_durations[i] - 1
    ) /\
    forall(i,j in 1..num_speakers where i < j) (
        no_overlap(starting_slot[i], app_durations[i], starting_slot[j], app_durations[j])
    ) /\
    forall(i in 1..num_speakers) (
        forall(j in 1..app_durations[i]) (
            starting_slot[i]+j-1 in speaker_availability[i]
        )
    ) 
;
+---+----------+----------+----------+
|   |   Sp.A   |   Sp.B   |   Sp.C   |
+---+----------+----------+----------+
| 1 | SELECTED | Busy     |          |
| 2 | Busy     | Busy     | Busy     |
| 3 | Busy     | Busy     | SELECTED |
| 4 |          | SELECTED |          |
| 5 |          | SELECTED | Busy     |
| 6 | Busy     | Busy     |          |
+---+----------+----------+----------+
我是哈坎克(原始模型的作者)。如果我理解正确的话,您现在的问题是如何为最佳解决方案呈现表格,而不是如何找到解决方案本身(我测试的所有Flatzin解算器都很快解决了问题)

创建表格的一种方法是使用一个帮助矩阵(“m”),该矩阵包含以下信息:如果某个发言者被选中(1)、忙(-1)或不可用(0):

然后,必须将此矩阵中的信息与其他决策变量(“起始位置”和“结束位置”)连接起来:

] ;

和往常一样,有不止一种方法可以做到这一点,但我决定这样做,因为它非常直接

以下是完整的模型:

更新:添加模型的输出:

Starting:  [1, 4, 3]
Durations: [1, 2, 1]
Ends:      [1, 5, 3]
z:         5

SELECTED Busy             
Busy     Busy     Busy    
Busy     Busy     SELECTED
         SELECTED         
         SELECTED Busy    
Busy     Busy             
----------
==========
更新2: 另一种方法是使用累积/4,而不是应该更有效的无重叠/4,即

constraint 
    forall(i in 1..num_speakers) (
    ending_slot[i] = starting_slot[i] + app_durations[i] - 1
    ) 
    % /\ % use cumulative instead (see below)
    % forall(i,j in 1..num_speakers where i < j) (
    %   no_overlap(starting_slot[i], app_durations[i], starting_slot[j], app_durations[j])
    % ) 
    /\
    forall(i in 1..num_speakers) (
    forall(j in 1..app_durations[i]) (
        starting_slot[i]+j-1 in speaker_availability[i]
           )
    ) 

    /\ cumulative(starting_slot, app_durations, [1 | i in 1..num_speakers], 1)
;
约束
forall(1..num_扬声器中的i)(
结束\u插槽[i]=开始\u插槽[i]+应用\u持续时间[i]-1
) 
%/\%改为使用累积(见下文)
%forall(1..num_扬声器中的i,j,其中i
这是修改过的版本(给出了相同的结果) (我还跳过了演示矩阵“m”,在输出部分进行所有演示。)


对于这个简单的问题实例,没有明显的区别,但是对于更大的实例,这应该更快。(对于更大的实例,可能需要测试不同的搜索启发式,而不是“求解最小化z”。

正如我在前面的问题上所评论的,累积约束适用于此。我手头没有Minizing代码,但是ECLiPSe()中有一个模型:


你尝试过不同的解决方案吗?你会在这里找到一个列表,如果可用的解算器,这里也有Minizing挑战结果。你会对最佳解算器有一个想法。因为在Minizing中进行实验并不那么容易,这里有一个Picat模型,使用相同的方法:它解决了20个扬声器的问题(其中一些扬声器有2个插槽可以说话)我在第二个Minizin模型(scheduling_speakers_optimize2.mzn)中添加了一个50个扬声器x 60个插槽的问题。用Gecode、Google或tools、Choco3在0.1s内解决;大多数其他解算器的时间小于1秒。G12迷你锌解算器(“fd”、“惰性”和“cpx”)需要很长时间才能解决50x60问题,可能是因为它们的“累积”不够强。谷歌或工具可以从下载。Gecode可以在此处下载:。对于这些日程安排问题的一个子集-当所有插槽中必须只有一个扬声器时-我制作了一个Minizing模型,该模型对于Minizing解算器要快得多:。MiniZin“fd”解算器在4秒内解算50x60实例(其中大部分时间为FlatZin展平)。请注意,此模型无法解决原始问题,因为它在明细表中有漏洞。(这可能通过添加虚拟扬声器来修复。)我现在已经更改,因此它现在可以检测明细表中是否有漏洞(即当总和(app_durations)% ... ++ [ if s = 1 then "\n" else " " endif ++ if fix(m[t,s]) = -1 then "Busy " elseif fix(m[t,s]) = 1 then "SELECTED" else " " endif | t in 1..num_slots, s in 1..num_speakers
Starting:  [1, 4, 3]
Durations: [1, 2, 1]
Ends:      [1, 5, 3]
z:         5

SELECTED Busy             
Busy     Busy     Busy    
Busy     Busy     SELECTED
         SELECTED         
         SELECTED Busy    
Busy     Busy             
----------
==========
constraint 
    forall(i in 1..num_speakers) (
    ending_slot[i] = starting_slot[i] + app_durations[i] - 1
    ) 
    % /\ % use cumulative instead (see below)
    % forall(i,j in 1..num_speakers where i < j) (
    %   no_overlap(starting_slot[i], app_durations[i], starting_slot[j], app_durations[j])
    % ) 
    /\
    forall(i in 1..num_speakers) (
    forall(j in 1..app_durations[i]) (
        starting_slot[i]+j-1 in speaker_availability[i]
           )
    ) 

    /\ cumulative(starting_slot, app_durations, [1 | i in 1..num_speakers], 1)
;
:- lib(ic).
:- lib(ic_edge_finder).
:- lib(branch_and_bound).

solve(JobStarts, Cost) :-
    AllUnavStarts = [[2,6],[1,6],[2,5]],
    AllUnavDurs   = [[2,1],[3,1],[1,1]],
    AllUnavRess   = [[1,1],[1,1],[1,1]],
    JobDurs = [1,2,1],
    Ressources = [1,1,1],
    length(JobStarts, 3),
    JobStarts :: 1..9,

    % the jobs must not overlap with each other
    cumulative(JobStarts, JobDurs, Ressources, 1),

    % for each speaker, no overlap of job and unavailable periods
    (
        foreach(JobStart,JobStarts),
        foreach(JobDur,JobDurs),
        foreach(UnavStarts,AllUnavStarts),
        foreach(UnavDurs,AllUnavDurs),
        foreach(UnavRess,AllUnavRess)
    do
        cumulative([JobStart|UnavStarts], [JobDur|UnavDurs], [1|UnavRess], 1)
    ),

    % Cost is the maximum end date
    ( foreach(S,JobStarts), foreach(D,JobDurs), foreach(S+D,JobEnds) do true ),
    Cost #= max(JobEnds),

    minimize(search(JobStarts,0,smallest,indomain,complete,[]), Cost).