【问题标题】:MILP constraint for cyclic task scheduling循环任务调度的 MILP 约束
【发布时间】:2022-12-21 16:59:04
【问题描述】:

我正在开发处理循环任务的 MILP 数学模型。我处于必须在这方面设计约束的阶段。这是问题的简化版本。

有 4 个 A 类型的任务:[A1、A2、A3、A4]。我需要一个约束

  • 首先确保任务有序
  • 其次,在计划范围内,任务 A4 之后又是 A1。这个循环将一直持续到规划范围结束。

我已经创建了约束来验证任务的顺序:

X_A:= 1 如果任务 A 正在完成

索引 a:任务 {1, 2, .... , A}

规划范围内的总和 (X_a) >= 规划范围内的总和 (X_a+1) 对于 {1,2, ... A-1} 中的所有 a

我坚持写一个约束以确保在最后一个任务完成后的计划范围内并开始第一个任务并重复循环。

【问题讨论】:

    标签: mixed-integer-programming


    【解决方案1】:

    我已经使用 Google_ortool 的 CP-SAT 求解器(python API)来解决这个问题。 因此,如果您需要计划任务的总视野长度 = 51 个单位, 并且您的任务是tasks = {"a1" : 2, "a2" : 3, "a3" : 7, "a4" : 9, "a5" : 1},其中“a1”是任务,2 是任务的长度,那么解决方案将如下所示:

    (cycle, task ==> whether task was performed ==> task duration)
    (0, 'a1') ==> 1 ==> 2
    (0, 'a2') ==> 1 ==> 3
    (0, 'a3') ==> 1 ==> 7
    (0, 'a4') ==> 1 ==> 9
    (0, 'a5') ==> 1 ==> 1
    (1, 'a1') ==> 1 ==> 2
    (1, 'a2') ==> 1 ==> 3
    (1, 'a3') ==> 1 ==> 7
    (1, 'a4') ==> 1 ==> 9
    (1, 'a5') ==> 1 ==> 1
    (2, 'a1') ==> 1 ==> 2
    (2, 'a2') ==> 1 ==> 3
    (2, 'a3') ==> 0 ==> 0
    (2, 'a4') ==> 0 ==> 0
    (2, 'a5') ==> 0 ==> 0
    
    total length = 49, which is less than the horizon length 51, we
    cant take up a3 because its length is 7 and 49 + 7 >= 51. So we
    stop at a2 only.
    

    python 中的代码清单

    from ortools.sat.python import cp_model as cp
    import numpy as np
    
    planning_horizon_length = 51
    
    # tasks and their corresponding duration
    tasks = {"a1" : 2,
             "a2" : 3,
             "a3" : 7,
             "a4" : 9,
             "a5" : 1
           }
    
    total_task_length = sum(tasks.values())
    
    # how many cycles we would require
    num_cycles = int(np.ceil(planning_horizon_length / total_task_length))
    
    model = cp.CpModel()
    
    # decision variable : for each cycle - task whether it will be done or not
    cycle_tasks = []
    dv_cycle_task = {}
    for i in range(num_cycles):
        for j in tasks:
            dv_cycle_task[(i, j)] = model.NewBoolVar("cycle : " + str(i) + " & " + "task : " + str(j))
            cycle_tasks.append((i, j))
    
    # precedence constraint : for each cycle, a1 should come before a2 and so on
    for i, j in enumerate(cycle_tasks):
        if i < len(cycle_tasks) - 1:
            model.Add(dv_cycle_task[cycle_tasks[i]] >= dv_cycle_task[cycle_tasks[i + 1]])
     
    # capture total run length
    total_run_length = model.NewIntVar(0, planning_horizon_length, "")
    model.Add(total_run_length == sum(dv_cycle_task[(i, j)] * tasks[j] for (i, j) in cycle_tasks))
    
    # total run length should be lower than planning_horizon_length
    model.Add(total_run_length <= planning_horizon_length)
    
    
    # we want total run length should be as close to planning_horizon_length i.e. 51
    model.Maximize(total_run_length - planning_horizon_length)
    
    solver = cp.CpSolver()
    solver.Solve(model) 
    
    # objective function value : how extra we went
    solver.Value(total_run_length)
    
    # inspect the solution
    for (i, j) in cycle_tasks:
        print(str((i, j)) + " ==> " + str(solver.Value(dv_cycle_task[(i, j)])) + " ==> " + str(solver.Value(dv_cycle_task[(i, j)]) * tasks[j]))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-11
      • 2018-12-29
      • 2019-12-30
      • 2020-08-14
      • 1970-01-01
      • 2023-01-13
      • 2011-04-28
      • 2017-08-04
      相关资源
      最近更新 更多