Skip to content

Commit bd353b0

Browse files
committed
NEW
1 parent c6eefbb commit bd353b0

File tree

3 files changed

+972
-0
lines changed

3 files changed

+972
-0
lines changed

extend/backup/10.20.md

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# 并行机器调度问题的Gurobi实现
2+
3+
## 目标函数:
4+
5+
最小化所有任务的总拖期(Total Tardiness),其数学表达式为:
6+
7+
$$
8+
\text{最小化} \quad \sum_{j=1}^{n} \max(0, C_j - d_j)
9+
$$
10+
11+
其中:
12+
13+
- \( C_j \):任务 \( J_j \) 的完成时间。
14+
- \( d_j \):任务 \( J_j \) 的交付期限(Due Date)。
15+
16+
## 约束条件:
17+
18+
### 1. 每个任务必须分配给一台机器:
19+
20+
$$
21+
\sum_{i \in M} Y_{ij} = 1, \quad \forall j \in J
22+
$$
23+
24+
其中:
25+
26+
- \( Y_{ij} \):二进制变量,表示任务 \( J_j \) 是否分配给机器 \( M_i \) (1为分配,0为不分配)。
27+
28+
### 2. 前后任务顺序约束(每个任务在其分配的机器上只能有一个前序任务和一个后序任务):
29+
30+
$$
31+
Y_{ig} = \sum_{j \in J', j \neq g} X_{ijg}, \quad \forall g \in J, \forall i \in M
32+
$$
33+
34+
$$
35+
Y_{ij} = \sum_{g \in J', g \neq j} X_{ijg}, \quad \forall j \in J, \forall i \in M
36+
$$
37+
38+
其中:
39+
40+
- \( X_{ijg} \):二进制变量,表示任务 \( J_j \) 是否排在任务 \( J_g \) 之前。
41+
42+
### 3. 每台机器只能有一个首个任务:
43+
44+
$$
45+
\sum_{j \in J} X_{i0j} \leq 1, \quad \forall i \in M
46+
$$
47+
48+
### 4. 任务的完成时间和设置时间约束:
49+
50+
确保任务只能在其释放时间后开始加工,且考虑到家族设置时间的影响:
51+
52+
$$
53+
C_j + V (1 - Y_{ij}) \geq \frac{p_j}{v_i} + r_j, \quad \forall i \in M, \forall j \in J
54+
$$
55+
56+
$$
57+
C_g - C_j + V (1 - X_{ijg}) \geq S_{jg} + \frac{p_g}{v_i}, \quad \forall j \in J', \forall g \in J, j \neq g, \forall i \in M
58+
$$
59+
60+
其中:
61+
62+
- \( r_j \):任务的释放时间。
63+
- \( S_{jg} \):家族设置时间(如果任务 \( J_j \)\( J_g \) 来自不同家族,则有设置时间)。
64+
65+
### 5. 每台机器的初始状态:
66+
67+
$$
68+
C_0 = 0
69+
$$
70+
71+
### 6. 变量定义:
72+
73+
$$
74+
X_{ijg} \in \{0, 1\}, \quad Y_{ij} \in \{0, 1\}, \quad C_j > 0
75+
$$
76+
77+
- \( X_{ijg} \):二进制变量,表示任务 \( J_j \) 是否排在任务 \( J_g \) 之前。
78+
- \( Y_{ij} \):二进制变量,表示任务 \( J_j \) 是否分配给机器 \( M_i \)
79+
- \( C_j \):任务 \( J_j \) 的完成时间。
80+
81+
## 总结
82+
83+
通过上述目标函数和约束条件,你可以使用 Gurobi 来实现并行机器调度问题的求解。
84+
85+
```
86+
# PMSP调度问题
87+
"""
88+
目标函数:
89+
- 最小化总延迟
90+
"""
91+
92+
#
93+
"""
94+
约束条件:
95+
- 每个作业只能分配给一个机器
96+
- 每个机器上有且仅有一个前驱作业
97+
- 每个机器上有且仅有一个后继作业
98+
- 每台机器上最多只能有一个作业作为第一个作业
99+
- 作业只能在到达时间之后开始处理
100+
- 作业之间的重叠和设置时间的约束,我这里默认任何一个作业到另一个作业的转换设置时间都为1
101+
- 每台机器上的作业的完成时间初始值都是0
102+
"""
103+
#
104+
"""
105+
决策变量:
106+
- 作业Jj完成的时间
107+
- 如果作业Jj是作业Jg在机器Mi上的前驱,则为1,否则为0
108+
- 如果作业Jj被分配给机器Mi,则为1,否则为0
109+
"""
110+
from dataclasses import dataclass
111+
from gurobipy import GRB
112+
import gurobipy
113+
import numpy
114+
115+
V = 0xffffff
116+
117+
@dataclass
118+
class Job:
119+
jobId : int
120+
processTime : int
121+
arrivalTime : int
122+
endTime : int
123+
124+
def __post_init__(self):
125+
self.name = "Job%d" % self.jobId
126+
127+
@dataclass
128+
class Machine:
129+
machId : int
130+
speed : int
131+
132+
def __post_init__(self):
133+
self.name = "Machine%d" % self.machId
134+
135+
# 机器
136+
machines = [
137+
Machine(0, 1),
138+
Machine(1, 2),
139+
Machine(2, 1),
140+
Machine(3, 3),
141+
Machine(4, 2)
142+
]
143+
144+
# 工作
145+
jobs = [
146+
Job(0, 3, 0, 7),
147+
Job(1, 2, 1, 4),
148+
Job(2, 4, 2, 20),
149+
Job(3, 1, 3, 15),
150+
Job(4, 3, 5, 10),
151+
Job(5, 2, 5, 15),
152+
Job(6, 4, 7, 18),
153+
Job(7, 3, 10, 25),
154+
Job(8, 2, 11, 25),
155+
Job(9, 1, 13, 26),
156+
Job(10, 5, 14, 30),
157+
Job(11, 3, 15, 35),
158+
Job(12, 2, 16, 40)
159+
]
160+
161+
num_jobs = len(jobs)
162+
num_machines = len(machines)
163+
164+
# 创建模型
165+
model = gurobipy.Model("Model")
166+
167+
# 决策变量
168+
# 如果作业Jj是作业Jg在机器Mi上的前驱,则为1,否则为0
169+
# X = model.addVars(num_machines, num_jobs, num_jobs, vtype=GRB.BINARY, name='X')
170+
X = {}
171+
for i in range(num_machines):
172+
for j in range(num_jobs):
173+
for g in range(num_jobs):
174+
if j != g:
175+
X[i, j, g] = model.addVar(vtype=GRB.BINARY)
176+
177+
# 如果作业Jj被分配给机器Mi,则为1,否则为0
178+
Y = model.addVars(num_machines, num_jobs, vtype=GRB.BINARY, name='Y')
179+
# 作业Jj完成的时间
180+
C = model.addVars(num_jobs, vtype=GRB.CONTINUOUS, name='C')
181+
# S是Jg紧接着转向Jj作业之后设置的时间,设置了1
182+
S = numpy.full([num_jobs, num_jobs], 1)
183+
184+
# 传递变量
185+
# for i in range(num_jobs):
186+
# model.addConstr(C[i] == 0)
187+
188+
# 1.每个作业只能分配给一个机器
189+
for j in range(num_jobs):
190+
model.addConstr(
191+
gurobipy.quicksum(Y[i, j] for i in range(num_machines)) == 1
192+
)
193+
194+
# 2.每个机器上有且仅有一个前驱作业
195+
for i in range(num_machines):
196+
for g in range(num_jobs):
197+
model.addConstr(
198+
gurobipy.quicksum(
199+
X[i, j, g] for j in range(num_jobs) if j != g
200+
) == Y[i, g]
201+
)
202+
203+
# 3.每个机器上有且仅有一个后继作业
204+
for i in range(num_machines):
205+
for j in range(num_jobs):
206+
model.addConstr(
207+
gurobipy.quicksum(
208+
X[i, j, g] for g in range(num_jobs) if g != j
209+
) == Y[i, j]
210+
)
211+
212+
# 4.每台机器上最多只能有一个作业作为第一个作业
213+
for i in range(num_machines):
214+
model.addConstr(
215+
gurobipy.quicksum(
216+
X[i, 0, j] for j in range(num_jobs) if j != 0
217+
) <= 1
218+
)
219+
220+
# 5.作业只能在到达时间之后开始处理
221+
for j in range(num_jobs):
222+
for i in range(num_machines):
223+
model.addConstr(
224+
C[j] + V * (1 - Y[i, j]) >= jobs[j].arrivalTime + jobs[j].processTime / machines[i].speed
225+
)
226+
227+
# 6.作业之间的重叠和设置时间的约束,我这里默认任何一个作业到另一个作业的转换设置时间都为1
228+
for i in range(num_machines):
229+
for g in range(num_jobs):
230+
for j in range(num_jobs):
231+
if j != g:
232+
model.addConstr(
233+
C[g] - C[j] + V * (1 - X[i, j, g]) >= S[g][j] + jobs[g].processTime / machines[i].speed
234+
)
235+
236+
# 7.作业的完成时间也需要更新,这应该是最后一个约束公式想表达的意思
237+
for i in range(num_machines):
238+
for j in range(num_jobs):
239+
for g in range(num_jobs):
240+
if j != g:
241+
model.addConstr(
242+
C[g] >= C[j] + jobs[j].processTime / machines[i].speed - V * (1 - X[i, j, g])
243+
)
244+
245+
# 目标函数:最小化总延迟
246+
Total_times = []
247+
248+
# 遍历每个作业,计算完成时间与截止时间之间的延迟
249+
for j in range(num_jobs):
250+
diff_var = model.addVar(vtype=GRB.CONTINUOUS) # 常量不能直接和变量参与计算,通过变换到变量约束
251+
model.addConstr(diff_var == C[j] - jobs[j].endTime)
252+
delay_var = model.addVar(vtype=GRB.CONTINUOUS)
253+
model.addGenConstrMax(delay_var, [0, diff_var])
254+
Total_times.append(delay_var)
255+
256+
model.setObjective(gurobipy.quicksum(Total_times), gurobipy.GRB.MINIMIZE)
257+
258+
model.update()
259+
model.optimize()
260+
261+
if model.status == GRB.OPTIMAL:
262+
print("Get Optimal Solution:")
263+
for j in range(num_jobs):
264+
for i in range(num_machines):
265+
if Y[i, j].x > 0: # 判断作业是否分配给机器
266+
print(f"Job {j} assigned to Machine {i}, Completion Time: {C[j].x}")
267+
else:
268+
print("No optimal solution found.")
269+
# Get Optimal Solution:
270+
# Job 0 assigned to Machine 4, Completion Time: 7.0
271+
# Job 1 assigned to Machine 0, Completion Time: 4.0
272+
# Job 2 assigned to Machine 3, Completion Time: 20.0
273+
# Job 3 assigned to Machine 1, Completion Time: 15.0
274+
# Job 4 assigned to Machine 0, Completion Time: 10.0
275+
# Job 5 assigned to Machine 0, Completion Time: 15.0
276+
# Job 5 assigned to Machine 1, Completion Time: 15.0
277+
# Job 5 assigned to Machine 2, Completion Time: 15.0
278+
# Job 5 assigned to Machine 3, Completion Time: 15.0
279+
# Job 5 assigned to Machine 4, Completion Time: 15.0
280+
# Job 6 assigned to Machine 3, Completion Time: 18.0
281+
# Job 7 assigned to Machine 2, Completion Time: 25.0
282+
# Job 8 assigned to Machine 1, Completion Time: 25.0
283+
# Job 9 assigned to Machine 4, Completion Time: 26.0
284+
# Job 10 assigned to Machine 3, Completion Time: 30.0
285+
# Job 11 assigned to Machine 2, Completion Time: 35.0
286+
# Job 12 assigned to Machine 4, Completion Time: 40.0
287+
```

0 commit comments

Comments
 (0)