❮❮❮ ❮❮❮   ❯❯❯ ❯❯❯
Reading Notes: Comparison of MILP and CP models for balancing partially automated assembly lines
Reading notes, links and models.

Reading time: 15 min.

Metadata

Dimény, Imre; Koltai, Tamás Comparison of MILP and CP models for balancing partially automated assembly lines. Cent. Eur. J. Oper. Res. 32, No. 4, 945-959 (2024).

Links: doi zbMATH

Authors:

Summary

Questions

Notes

Glossary

Table 1: Notation

Inconsistent notation for multiplication

Constraint (4)

Constraint (6)

Index errors in constraints

Time constraints as variable bounds

Execution precedence constraints

The problem with constraint (15)

Precedence information transitiveness

Conditional scheduling constraints

Station allocation of workforce types in model 3

Missing checks on parameters

Problems with constraint (6)

Parameters

Optimal solution with model 1

Optimal solution with model 2

Possible fixes

Examples of execution precedence

Scenario 1

Scenario 2

Models

In ASCI-printable Symplex notation.

Model MILP1 as in paper

local W := {H, R}
index w on W
input I in {0, 1, ...}
index i on I
index k on I
input J in {0, 1, ...}
index j on I
input t[i][w] in [0, infinity[
input TC in [0, infinity[
input P[i] in {1, ..., I}
input L subsetof {1, ..., I}
check forall[l in L]: forall [i]: l not in P[i]

decision N in {0, 1, ...}
decision x[i][j][w] in {0, 1}

constraint EQ_2[i] is 
  sum[j][w in W] x[i][j][w] = 1
constraint EQ_3[i][k in P[i]] is 
  sum[j][w in W] j (x[i][j][w] - x[k][j][w]) >= 0
constraint EQ_4[j][w in W] is
  sum[i] x[i][j][w] t[i][w] <= TC
constraint EQ_5[i][j] is
  x[i][j][R] = 0
constraint EQ_6[j][w in W] is
  N >= sum[i in L] j * x[i][j][w]

minimize N

Model MILP1 rewritten

local Workforces := {Human, Robot}
input Tasks is distinct finite set
input NumberStations in {0, 1, ...}
local Stations := {1, ..., NumberStations}
input CycleTime in [0, infinity[
input TaskTime[Tasks][Workforces] in [0, CycleTime]
check sum[t in Tasks] TaskTime[t][Human] <= NumberStations * CycleTime
input Precedents[Tasks] in Tasks
local PrecedenceArcs := setunion[t in Tasks] { (tt, t) | tt in Precedents[t]}
check PrecedenceArcs is acyclic graph
local Antecedents[t in Tasks] := {tt in Tasks | t in Precedents[tt]}
local FinalTasks := {t in Tasks | Antecedents[t] = empty set}
check cardinality FinalTasks = 1

decision NumberWorkersUsed in Stations
decision Assign[Tasks][Stations][Workforces] in {0, 1}

constraint TaskWorked[t in Tasks] is 
  sum[s in Stations][w in Workforces] Assign[t][s][w] = 1
constraint TaskPrecedence[t in Tasks][k in Precedents[t]] is 
  sum[s in Stations][w in Workforces] s (Assign[t][s][w] - Assign[k][s][w]) >= 0
constraint CycleTimeLimit[s in Stations][w in Workforces] is
  sum[t in Tasks] Assign[t][s][w] TaskTime[t][w] <= CycleTime
constraint NoRobots[t in Tasks][s in Stations] is
  Assign[t][s][Robot] = 0
constraint FinalTasks[s in Stations][w in Workforces] is
  NumberWorkersUsed >= s * sum[t in FinalTasks] Assign[t][s][w]

minimize NumberWorkersUsed

Model MILP1 simplified

input NumberTasks in {0, 1, ...}
input Tasks is distinct finite set
local Stations := {1, ..., NumberStations}
input CycleTime in [0, infinity[
input TaskTime[Tasks] in [0, CycleTime]
check sum[t in Tasks] TaskTime[t] <= NumberStations * CycleTime
input Precedents[Tasks] in Tasks
local PrecedenceArcs := setunion[t in Tasks] { (tt, t) | tt in Precedents[t]}
check PrecedenceArcs is acyclic graph
local Antecedents[t in Tasks] := {tt in Tasks | t in Precedents[tt]}
local FinalTasks := {t in Tasks | Antecedents[t] = empty set}
check cardinality FinalTasks = 1

decision NumberStationsUsed in Stations
decision Assign[Tasks][Stations] in {0, 1}

constraint TaskWorked[t in Tasks] is 
  sum[s in Stations] Assign[t][s] = 1
constraint TaskPrecedence[t in Tasks][k in Precedents[t]] is 
  sum[s in Stations] s (Assign[t][s] - Assign[k][s]) >= 0
constraint CycleTimeLimit[s in Stations] is
  sum[t in Tasks] Assign[t][s] TaskTime[t] <= CycleTime
constraint FinalTasks[s in Stations] is
  NumberStationsUsed >= s * sum[t in FinalTasks] Assign[t][s]

minimize NumberStationsUsed

Model MILP2 as in paper

local W := {H, R}
index w on W
input I in {0, 1, ...}
index i on I
index k on I
input J in {0, 1, ...}
index j on I
input t[i][w] in [0, infinity[
input TC in [0, infinity[
input P[i] in {1, ..., I}
input L subsetof {1, ..., I}
check forall[l in L]: forall [i]: l not in P[i]
input NA[w] in {1, ..., I}

decision N in {0, 1, ...}
decision x[i][j][w] in {0, 1}
decision u[i][w] in {0, 1}

constraint EQ_2[i] is 
  sum[j][w in W] x[i][j][w] = 1
constraint EQ_3[i][k in P[i]] is 
  sum[j][w in W] j (x[i][j][w] - x[k][j][w]) >= 0
constraint EQ_4[j][w in W] is
  sum[i] x[i][j][w] t[i][w] <= TC

constraint EQ_7[w][j][i in NA[w]] is
  x[i][j][w] = 0
constraint EQ_8[j] is
  sum[w] u[j][w] = 1
constraint EQ_9[i][w] is
  sum[i] x[i][j][w] <= I * u[j][w]
constraint EQ_10[i][w] is
  sum[i] x[i][j][w] >= u[j][w]
constraint EQ_11 is
  N = sum[j] u[j][H]

minimize N

Model MILP2 rewritten

local Workforces := {Human, Robot}
input Tasks is distinct finite set
input NumberStations in {0, 1, ...}
local Stations := {1, ..., NumberStations}
input CycleTime in [0, infinity[
input TaskTime[Tasks][Workforces] in [0, CycleTime]
check sum[t in Tasks] min[w in Workforces] TaskTime[t][w] <= NumberStations * CycleTime
input Precedents[Tasks] in Tasks
local PrecedenceArcs := setunion[t in Tasks] { (tt, t) | tt in Precedents[t]}
check PrecedenceArcs is acyclic graph
local Antecedents[t in Tasks] := {tt in Tasks | t in Precedents[tt]}
local FinalTasks := {t in Tasks | Antecedents[t] = empty set}
check cardinality FinalTasks = 1
input NoAbility[Workforces] in Tasks

decision NumberWorkersUsed in Stations
decision Assign[Tasks][Stations][Workforces] in {0, 1}
decision UsesWorkforce[Stations][Workforces] in {0, 1}

constraint TaskWorked[t in Tasks] is 
  sum[s in Stations][w in Workforces] Assign[t][s][w] = 1
constraint TaskPrecedence[t in Tasks][k in Precedents[t]] is 
  sum[s in Stations][w in Workforces] s (Assign[t][s][w] - Assign[k][s][w]) >= 0
constraint CycleTimeLimit[s in Stations][w in Workforces] is
  sum[t in Tasks] Assign[t][s][w] TaskTime[t][w] <= CycleTime

constraint NoAbilityRespected[w in Workforces][s in Stations][t in NoAbility[w]] is
  Assign[t][s]][w] = 0
constraint EachStationAssigned[s in Stations] is
  sum[w in Workforces] UsesWorkforce[s][w] = 1
constraint AssignedTasksNeedWorkforcesAllocated[s in Stations][w in Workforces] is
  sum[t in Tasks] Assign[t][s][w] <= NumberTasks * UsesWorkforce[s][w]
constraint AllocatedWorkforcesGetTasksAssigned[s in Stations][w in Workforces] is
  sum[t in Tasks] Assign[t][s][w] >= UsesWorkforce[s][w]
constraint NumberWorkersUsedDef is
  NumberWorkersUsed = sum[s in Stations] UsesWorkforce[s][Human]

minimize NumberWorkersUsed

Model MILP3 as in paper

local W := {H, R}
index w on W
input I in {0, 1, ...}
index i on I
index k on I
input J in {0, 1, ...}
index j on I
input t[i][w] in [0, infinity[
input TC in [0, infinity[
input P[i] in {1, ..., I}
input L subsetof {1, ..., I}
check forall[l in L]: forall [i]: l not in P[i]
input NA[w] in {1, ..., I}

decision N in {0, 1, ...}
decision x[i][j][w] in {0, 1}
decision u[i][w] in {0, 1}
decision y[i][k] in {0, 1}
decision s[i] in [0, infinity[
decision e[i] in [0, infinity[

constraint EQ_2[i] is 
  sum[j][w in W] x[i][j][w] = 1
constraint EQ_3[i][k in P[i]] is 
  sum[j][w in W] j (x[i][j][w] - x[k][j][w]) >= 0

constraint EQ_7[w][j][i in NA[w]] is
  x[i][j][w] = 0
constraint EQ_8[j] is
  sum[w] u[j][w] = 1
constraint EQ_9[i][w] is
  sum[i] x[i][j][w] <= I * u[j][w]
constraint EQ_10[i][w] is
  sum[i] x[i][j][w] >= u[j][w]
constraint EQ_11 is
  N = sum[j] u[j][H]

constraint EQ_12 is
  sum[w] u[j][w] >= 1
constraint EQ_13[i] is
  y[i][i] = 0
constraint EQ_14[(i,k) | k not in P[i], i not in P[k], i <> k] is
  y[i][k] + y[k][i] = 1
constraint EQ_15[(i, k) | k not in P[i], i not in P[k], i <> k][j] is
  y[i][k] >= (sum[j_1 | j_1 < j][w] x[i][j][w] + x[k][j_1][w]) - 1
constraint EQ_16a[i] is
  e[i] >= 0
constraint EQ_16b[i] is
  s[i] >= 0
constraint EQ_17[i] is
  e[i] = s[i] + sum[j][w] x[i][j][w] * t[j][w]
constraint EQ_18[i] is
  e[i] <= T_c
constraint EQ_19[(i, k) | k not in P[i]][j] is
  s[i] >= e[k] - T_c * (2 - sum[w] (x[i][j][w] + x[i][k][w]))
constraint EQ_20[(i, k) | k not in P[i], i not in P[k], i <> k][j][w] is
  s[k] >= e[i] - T_c * (3 - y[i][k] - x[i][j][w] + x[i][k][w])
constraint EQ_21[(i, k) | k not in P[i], i not in P[k], i <> k][j] is
  s[k] >= s[i] - T_c * (3 - y[i][k] - sum[w] x[i][j][w] - sum[w] x[i][k][w])

minimize N

Model MILP3 rewritten

local Workforces := {Human, Robot}
input Tasks is distinct finite set
input NumberStations in {0, 1, ...}
local Stations := {1, ..., NumberStations}
input CycleTime in [0, infinity[
input TaskTime[Tasks][Workforces] in [0, CycleTime]
check sum[t in Tasks] min[w in Workforces] TaskTime[t][w] <= NumberStations * CycleTime
input Precedents[Tasks] in Tasks
check forall[t in Tasks][tt in Precedents[t]][ttt in Precedents[tt]]:
  ttt not in Precedents[t]
local PrecedenceArcs := setunion[t in Tasks] { (tt, t) | tt in Precedents[t]}
check PrecedenceArcs is acyclic graph
local Antecedents[t in Tasks] := {tt in Tasks | t in Precedents[tt]}
local FinalTasks := {t in Tasks | Antecedents[t] = empty set}
check cardinality FinalTasks = 1
input NoAbility[Workforces] in Tasks

decision NumberWorkersUsed in Stations
decision Assign[Tasks][Stations][Workforces] in {0, 1}
decision UsesWorkforce[Stations][Workforces] in {0, 1}
decision ExecOrder[i][k] in {0, 1}
decision StartTime[Tasks] in [0, CycleTime]
decision EndTime[Tasks] in [0, CycleTime]

constraint TaskWorked[t in Tasks] is 
  sum[s in Stations][w in Workforces] Assign[t][s][w] = 1
constraint TaskPrecedence[t in Tasks][k in Precedents[t]] is 
  sum[s in Stations][w in Workforces] s (Assign[t][s][w] - Assign[k][s][w]) >= 0

constraint NoAbilityRespected[w in Workforces][s in Stations][t in NoAbility[w]] is
  Assign[t][s]][w] = 0
constraint EachStationAssigned[s in Stations] is
  sum[w in Workforces] UsesWorkforce[s][w] = 1
constraint AssignedTasksNeedWorkforcesAllocated[s in Stations][w in Workforces] is
  sum[t in Tasks] Assign[t][s][w] <= NumberTasks * UsesWorkforce[s][w]
constraint AllocatedWorkforcesGetTasksAssigned[s in Stations][w in Workforces] is
  sum[t in Tasks] Assign[t][s][w] >= UsesWorkforce[s][w]
constraint NumberWorkersUsedDef is
  NumberWorkersUsed = sum[s in Stations] UsesWorkforce[s][Human]

constraint StationAllocatedWorkforce[s in Stations] is
  sum[w in Workforces] UsesWorkforce[s][w] >= 1
constraint NoSelfExecOrder[t in Tasks] is
  ExecOrder[t][t] = 0
local DiffNoArcs :=
  { (t, tt) in Task^2 | t not in Precedents[tt], tt not in Precedents[t], t not = tt }
constraint ExecOrderExists[(t, tt) in DiffNoArcs] is
  ExecOrder[t][tt] + ExecOrder[tt][t] = 1
constraint ExecOrderDefinition[(t, tt) in DiffNoArcs]][s in Stations] is
  ExecOrder[t][tt] >= 
    (sum[ss | ss < s][w in Workforces] Assign[t][ss][w])
    + (sum[w in Workforces] + Assign[tt][s][w])
    - 1

constraint TimeDefinition[t in Tasks] is
  EndTime[t] - StartTime[t] = 
    sum[s in Stations][w in Workforces] Assign[t][s][w] * TaskTime[t][w]

constraint SchedulingPreceding[t in Task][tt in Precedents[t]][s in Stations] is
  StartTime][t] >= 
    EndTime[tt]
    - CycleTime * (2 - sum[w in Workforces] (Assign[t][s][w] - Assign[tt][s][w]))
constraint SchedulingOthers[(t, tt) in DiffNoArcs][s in Stations][w in Workforces] is
  StartTime[tt] >= 
    EndTime[t] 
    - CycleTime * (3 - ExecOrder[t][tt] - Assign[t][s][w] + Assign[tt][s][w])
constraint SchedulingStarts[(t, tt) in DiffNoArcs][s in Stations] is
  StartTime[tt] >= 
    StartTime[t]
    - CycleTime * (3 - ExecOrder[t][tt] 
                     - (sum[w in Workforces] Assign[t][s][w])
                     - (sum[w in Workforces] Assign[tt][s][w])
                  )

minimize NumberWorkersUsed