-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
636 lines (612 loc) · 157 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Hello World</title>
<url>/2024/05/05/hello-world/</url>
<content><![CDATA[<center>Hello World</center>
]]></content>
<tags>
<tag>随笔</tag>
</tags>
</entry>
<entry>
<title>epsilon-约束方法</title>
<url>/2024/05/06/epsilon-%E7%BA%A6%E6%9D%9F%E6%96%B9%E6%B3%95/</url>
<content><![CDATA[<h1 id="varepsilon-约束方法(这样GUROBI也能解多目标问题了!)"><a href="#varepsilon-约束方法(这样GUROBI也能解多目标问题了!)" class="headerlink" title="$\varepsilon$-约束方法(这样GUROBI也能解多目标问题了!)"></a>$\varepsilon$-约束方法(这样GUROBI也能解多目标问题了!)</h1><p>一般解决多目标优化问题的算法都是NSGA-II算法、MOEA-D算法等多目标智能算法。采用Gurobi精确求解的方法往往难以求出pareto最优解,只能通过对多个目标进行加权的方式求解。今天我们学习一种方法,借助它我们也可以使用Gurobi等求解工具求解多目标优化算法,且其求解效果比加权法更好。</p>
<p><img src="/../images/image-20240304112349257.png"></p>
<hr>
<h2 id="varepsilon-约束方法简介"><a href="#varepsilon-约束方法简介" class="headerlink" title="$\varepsilon$-约束方法简介"></a>$\varepsilon$-约束方法简介</h2><p>$\varepsilon$-约束方法是一种多目标优化算法。它基于约束优化的思想,通过引入一个参数$\varepsilon$来控制目标函数的权重,从而保证满足约束条件的前提下,寻找到最优解的近似解集。</p>
<p>通过选取一个主目标函数,将其余目标函数转化为约束,从而计算每个子优化目标,得到帕累托解集。</p>
<h2 id="过程"><a href="#过程" class="headerlink" title="过程"></a>过程</h2><p>针对一个多目标优化问题:<br>$$<br>min {f_1(x),f_2(x),f_3(x)} \<br>h(x)=0 \<br>g(x)\leq 0<br>$$</p>
<p>使用ε约束算法转化问题为:<br>$$<br>min f_1(x) \<br>f_2(x)\leq \epsilon_2,\cdots,f_n(x)\leq\epsilon_n \<br>h(x) = 0 \<br>g(x) \leq 0<br>$$<br>其中的每个参数$\epsilon_2,\epsilon_3,\cdots,\epsilon_n$通过计算payoff矩阵得到。</p>
<p>payoff的计算过程:</p>
<ol>
<li><p>求解出第i个目标函数的最优值$f_i(x_i^*)$,得到其最优解$x_i^*$;</p>
</li>
<li><p>将$x_i^*$代入其他目标函数得到${f_1(x_i^*),f_2(x_i^*),\cdots,f_n(x_i^*)}$;</p>
</li>
<li><p>对全部目标函数按照上述流程求解,得到payoff table矩阵如下:<br>$$<br>\begin{bmatrix}<br>f_1(x_1^*) & \cdots & f_i(x_1^*) &\cdots & f_n(x_1^*)\<br>\vdots& \ddots &&& \vdots\<br>f_1(x_i^*) & \cdots & f_i(x_i^*) &\cdots & f_n(x_i^*)\<br>\vdots& \ddots& & & \vdots \<br>f_1(x_n^*) & \cdots & f_i(x_n^*) &\cdots & f_n(x_n^*)\<br>\end{bmatrix}<br>$$</p>
</li>
</ol>
<p>该方法本质上与网格搜索法相同。得到了payoff矩阵之后,可以求出每个目标的最优值和最劣值(就是每个目标维度的最大和最小值)。记为最优解(U)和最劣解(SN)$f_i^U = f_i(x_i^*)$,$f_i^{SN} = f_i(x_j^*)$。</p>
<p>选择一个主目标函数$f_k(x)$。</p>
<p>对于主目标函数外的目标函数$f_{i}(x)$,设置一个网格化分数$q_{ij}∈{1,2,\cdots,q_i,max} $。</p>
<p>由此计算除了主目标函数外的其余目标函数的ε约束如下:<br>$$<br>ϵ_{ij}=f_i^{SN}−\frac{(f_i^{SN}−f_i^{U})}{q_{ij}}⋅j \qquad j=1,2,…,q_{i,max}<br>$$<br>得到每个优化子问题如下:<br>$$<br>min f_k(x)\<br>s.t. \qquad f_1(x)\leq \epsilon_{1j},f_2(x)\leq \epsilon_{1l},f_n(x)\leq \epsilon_{1m},h(x)=0,g(x)\leq0<br>$$<br>其中,$j=1,2,\cdots,q_{1,max};l=1,2,\cdots,q_{2,max};\cdots;m=1,2,\cdots,q_{n,max};$</p>
<p>每次求出一个最优解,若在可行域内则加入帕累托解集,若不在可行域内则丢弃。</p>
<h2 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h2><p>$$<br>min \quad f_1(x) = x_2-x_1 \<br>min \quad f_2(x) = x_1+x_2 \<br>s.t. \qquad x_1^2 - 2x_1 + 1 \leq x_2 \<br>0 \leq x_1 \leq 1 \<br>0 \leq x_2 \leq 1<br>$$</p>
<p>使用python+gurobi求解代码如下:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="comment"># @Time : 2024/3/3 11:35</span></span><br><span class="line"><span class="comment"># @Author : TUUG</span></span><br><span class="line"><span class="comment"># @Email : tr6666666@qq.com</span></span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">from</span> matplotlib <span class="keyword">import</span> pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">import</span> gurobipy <span class="keyword">as</span> gp</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">f1</span>(<span class="params">constraint=<span class="literal">None</span></span>):</span><br><span class="line"> model = gp.Model()</span><br><span class="line"> x1 = model.addVar(name=<span class="string">"X1"</span>,vtype=gp.GRB.CONTINUOUS,lb=<span class="number">0</span>,ub=<span class="number">1</span>)</span><br><span class="line"> x2 = model.addVar(name=<span class="string">"X2"</span>,vtype=gp.GRB.CONTINUOUS,lb=<span class="number">0</span>,ub=<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># 添加约束</span></span><br><span class="line"> model.addConstr(x1*x1-<span class="number">2</span>*x1+<span class="number">1</span><=x2)</span><br><span class="line"> <span class="keyword">if</span> constraint <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line"> model.addConstr(x1+x2<=constraint)</span><br><span class="line"> <span class="comment"># 定义目标函数</span></span><br><span class="line"> model.setObjective(x2-x1, sense = gp.GRB.MINIMIZE)</span><br><span class="line"> model.update()</span><br><span class="line"> <span class="comment"># 求解模型</span></span><br><span class="line"> model.optimize()</span><br><span class="line"> <span class="keyword">return</span> x1.x,x2.x</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">f2</span>():</span><br><span class="line"> <span class="comment"># 创建模型</span></span><br><span class="line"> m2 = gp.Model(<span class="string">"f2_optimization"</span>)</span><br><span class="line"> <span class="comment"># 定义变量</span></span><br><span class="line"> x1 = m2.addVar(name=<span class="string">"X1"</span>,vtype=gp.GRB.CONTINUOUS,lb=<span class="number">0</span>,ub=<span class="number">1</span>)</span><br><span class="line"> x2 = m2.addVar(name=<span class="string">"X2"</span>,vtype=gp.GRB.CONTINUOUS,lb=<span class="number">0</span>,ub=<span class="number">1</span>)</span><br><span class="line"> <span class="comment"># 添加约束</span></span><br><span class="line"> m2.addConstr(x1*x1-<span class="number">2</span>*x1+<span class="number">1</span><=x2)</span><br><span class="line"> <span class="comment"># model.addConstr(x2-x1>=cons)</span></span><br><span class="line"> <span class="comment"># 定义目标函数</span></span><br><span class="line"> m2.setObjective(x2+x1, sense = gp.GRB.MINIMIZE)</span><br><span class="line"> <span class="comment"># 求解模型</span></span><br><span class="line"> m2.optimize()</span><br><span class="line"> <span class="keyword">return</span> x1.x,x2.x</span><br><span class="line"></span><br><span class="line">f11,f12 = f1()</span><br><span class="line">f21,f22 = f2()</span><br><span class="line">f1_min = f12-f11</span><br><span class="line">f2_max = f11+f12</span><br><span class="line">f2_min = f21+f22</span><br><span class="line">f1_max = f22-f21</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'--------------'</span>)</span><br><span class="line"><span class="built_in">print</span>(f2_min,f2_max)</span><br><span class="line">soultion_pool = []</span><br><span class="line">q_n =<span class="number">10</span></span><br><span class="line"><span class="keyword">for</span> q <span class="keyword">in</span> <span class="built_in">range</span>(q_n):</span><br><span class="line"> constraint = f2_max-(f2_max-f2_min)/q_n*q</span><br><span class="line"> <span class="comment"># constraint = np.linspace(f2_min,f2_max,10)[q]</span></span><br><span class="line"> f11,f12 = f1(constraint=constraint)</span><br><span class="line"> soultion_pool.append([f12-f11,f11+f12])</span><br><span class="line"><span class="built_in">print</span>(soultion_pool)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line">pareto_front_solutions = np.array(soultion_pool)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 绘制 Pareto 前沿解</span></span><br><span class="line">plt.scatter(pareto_front_solutions[:, <span class="number">0</span>], pareto_front_solutions[:, <span class="number">1</span>], label=<span class="string">'Pareto Front'</span>)</span><br><span class="line">plt.xlabel(<span class="string">'f1(x)'</span>)</span><br><span class="line">plt.ylabel(<span class="string">'f2(x)'</span>)</span><br><span class="line">plt.title(<span class="string">'Pareto Front for Multi-objective Optimization'</span>)</span><br><span class="line">plt.legend()</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<p>求解结果展示如下</p>
<p>网格化分数取10时:</p>
<p><img src="/../images/image-20240304112820159.png"></p>
<p>网格化分数取20时:</p>
<p><img src="/../images/image-20240304112906514.png"></p>
<p>网格化分数取100时:</p>
<p><img src="/../images/image-20240304112938975.png"></p>
<p>可以看到,这个方法有一个很好的性质,就是可以通过增大网格化分数来改善求解结果,使其更接近真实帕累托前沿。如果求解时间过长可以减小网格化分数来缩短求解时间。</p>
<h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><p>[1] Ismail-Yahaya A, Messac A. Effective generation of the Pareto frontier using the normal constraint method[C]//40th AIAA Aerospace Sciences Meeting & Exhibit. 2002: 178.</p>
<p>[2] Fan Z, Li W, Cai X, et al. An improved epsilon constraint-handling method in MOEA/D for CMOPs with large infeasible regions[J]. Soft Computing, 2019, 23: 12491-12510.</p>
<p>[3] Yang Z, Cai X, Fan Z. Epsilon constrained method for constrained multi-objective optimization problems: some preliminary results[C]//Proceedings of the companion publication of the 2014 annual conference on genetic and evolutionary computation. 2014: 1181-1186.</p>
<p>[4] <a href="https://blog.csdn.net/weixin_44786238/article/details/126068290">【多目标规划问题求解】ε-约束算法_约束法多目标规划问题求解-CSDN博客</a></p>
]]></content>
<tags>
<tag>精确优化方法</tag>
</tags>
</entry>
<entry>
<title>资源受限项目调度程序RCPSP</title>
<url>/2024/05/06/%E8%B5%84%E6%BA%90%E5%8F%97%E9%99%90%E9%A1%B9%E7%9B%AE%E8%B0%83%E5%BA%A6%E7%A8%8B%E5%BA%8FRCPSP/</url>
<content><![CDATA[<h1 id="问题介绍"><a href="#问题介绍" class="headerlink" title="问题介绍"></a>问题介绍</h1><p>资源受限项目调度问题(Resource-Constrained Project Scheduling Problem,RCPSP)是一个经典的优化问题,涉及在有限资源的情况下安排项目任务,以最大化某种指标,比如项目完成时间、资源利用率或成本最小化等。在许多实际应用中,资源受限是常见的,例如在制造业、建筑业、信息技术和项目管理等领域。</p>
<p>在资源受限项目调度问题中,通常会给定以下几个方面的限制和条件:</p>
<ol>
<li>任务: 项目被分解为一系列可执行的任务,每个任务都有一个开始时间和结束时间。 </li>
<li>资源:项目所需的资源包括人力、设备、资金等,这些资源是有限的。 </li>
<li>约束: 每个任务对资源的需求是不同的,同时存在任务之间的先后顺序和依赖关系。</li>
<li>优化目标: 最常见的优化目标是最小化项目完成时间或最大化资源利用率,但也可能涉及其他目标,比如最小化成本或最大化利润等。</li>
</ol>
<p>资源受限项目调度问题是一个NP-难问题,因此没有多项式时间的解法。解决该问题的方法通常包括:</p>
<ol>
<li>启发式算法: 基于经验或直觉设计的算法,如遗传算法、模拟退火等。 </li>
<li>精确算法: 尝试找到最优解的算法,如动态规划、分支定界等。但这些算法在大规模问题上的效率通常较低。 混合方法。</li>
<li>结合启发式算法和精确算法,以在可接受的时间内找到较好的解决方案。</li>
</ol>
<p>资源受限项目调度问题在许多实际应用中都有广泛的应用,包括但不限于:</p>
<ol>
<li>生产制造: 在生产线上安排任务以最大化产量并最小化成本。</li>
<li>建筑业: 安排施工工序和资源以优化工程进度和资源利用率。 </li>
<li>信息技术:安排软件开发项目中的任务和团队资源。 </li>
<li>项目管理: 规划和安排复杂项目中的任务和资源分配。</li>
</ol>
<h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><p>某个项目包含9个活动,活动间先后关系如图所示:<br><img src="/../images/%E6%B4%BB%E5%8A%A8%E4%BC%98%E5%85%88%E5%85%B3%E7%B3%BB.png"><br>各活动工期如下:</p>
<table>
<thead>
<tr>
<th>活动</th>
<th>活动名称</th>
<th>活动持续时间</th>
<th>资源需求量</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>活动1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>2</td>
<td>活动2</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>3</td>
<td>活动3</td>
<td>7</td>
<td>8</td>
</tr>
<tr>
<td>4</td>
<td>活动4</td>
<td>6</td>
<td>10</td>
</tr>
<tr>
<td>5</td>
<td>活动5</td>
<td>5</td>
<td>6</td>
</tr>
<tr>
<td>6</td>
<td>活动6</td>
<td>4</td>
<td>3</td>
</tr>
<tr>
<td>7</td>
<td>活动7</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>8</td>
<td>活动8</td>
<td>4</td>
<td>3</td>
</tr>
<tr>
<td>9</td>
<td>活动9</td>
<td>7</td>
<td>5</td>
</tr>
</tbody></table>
<h1 id="启发规则求解"><a href="#启发规则求解" class="headerlink" title="启发规则求解"></a>启发规则求解</h1><p>采用最短工期活动最先开始调度规则,生成上述问题的结果如下:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">Author: TUUG</span></span><br><span class="line"><span class="string">Date: April 26, 2024 20:59</span></span><br><span class="line"><span class="string">Description: 求解资源受限项目调度问题并画图.</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"><span class="keyword">from</span> collections <span class="keyword">import</span> defaultdict</span><br><span class="line"><span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">import</span> random</span><br><span class="line"><span class="keyword">import</span> math</span><br><span class="line"></span><br><span class="line">plt.rcParams[<span class="string">"axes.labelsize"</span>]=<span class="number">14</span></span><br><span class="line">plt.rcParams[<span class="string">"xtick.labelsize"</span>]=<span class="number">12</span></span><br><span class="line">plt.rcParams[<span class="string">"ytick.labelsize"</span>]=<span class="number">12</span></span><br><span class="line">plt.rcParams[<span class="string">'font.sans-serif'</span>] = [<span class="string">'SimHei'</span>] <span class="comment"># 指定默认字体</span></span><br><span class="line">plt.rcParams[<span class="string">'axes.unicode_minus'</span>] = <span class="literal">False</span> <span class="comment"># 解决保存图像是负号'-'显示为方块的问题</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Activity</span>(<span class="title class_ inherited__">object</span>):</span><br><span class="line"> <span class="string">'''</span></span><br><span class="line"><span class="string"> 活动类:包含 1.活动ID 2.活动持续时间 3.活动资源需求量 4.活动紧前活动 5.活动最早开始时间 6.活动最晚开始时间 7.活动是否被访问</span></span><br><span class="line"><span class="string"> '''</span></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, <span class="built_in">id</span>, duration, resourceRequest, successor</span>):</span><br><span class="line"> self.<span class="built_in">id</span> = <span class="built_in">id</span></span><br><span class="line"> self.time_long = duration <span class="comment"># 活动总时长,固定不变</span></span><br><span class="line"> self.duration = duration <span class="comment"># 活动剩余时长,动态变化</span></span><br><span class="line"> self.resourceRequest = np.array(resourceRequest)[<span class="number">0</span>]</span><br><span class="line"> self.predecessor = <span class="literal">None</span></span><br><span class="line"> self.successor = successor</span><br><span class="line"> self.visited = <span class="literal">False</span></span><br><span class="line"> self.start = <span class="literal">None</span> <span class="comment"># 这里的start是时点数据,不是时段数据</span></span><br><span class="line"> self.end = <span class="literal">None</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Day</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self,<span class="built_in">id</span>,total_resource</span>):</span><br><span class="line"> self.<span class="built_in">id</span> = <span class="built_in">id</span></span><br><span class="line"> self.total_resource = total_resource</span><br><span class="line"> self.resource_used = <span class="number">0</span></span><br><span class="line"> self.resource_left = total_resource</span><br><span class="line"> self.act_list = []</span><br><span class="line"> </span><br><span class="line"> <span class="comment">#================修改代码=====================</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">start_act</span>(<span class="params">act,day,days</span>):</span><br><span class="line"> <span class="string">"""启动活动"""</span></span><br><span class="line"> <span class="keyword">if</span> act.visited == <span class="literal">False</span>:</span><br><span class="line"> act.visited = <span class="literal">True</span></span><br><span class="line"> act.start = day.<span class="built_in">id</span>-<span class="number">1</span></span><br><span class="line"> act.end = act.start + act.time_long</span><br><span class="line"> <span class="comment"># 如果活动时长大于0</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(act.time_long):</span><br><span class="line"> execute_act(act,days[days.index(day)+i]) <span class="comment"># 这里替换为执行活动函数</span></span><br><span class="line"> <span class="keyword">if</span> act.time_long == <span class="number">0</span>:</span><br><span class="line"> execute_act(act,day)</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">execute_act</span>(<span class="params">act,day</span>):</span><br><span class="line"> <span class="string">"""执行活动"""</span></span><br><span class="line"> act.duration -= <span class="number">1</span></span><br><span class="line"> day.resource_used += act.resourceRequest</span><br><span class="line"> day.resource_left -= act.resourceRequest</span><br><span class="line"> day.act_list.append(act.<span class="built_in">id</span>)</span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">can_start1</span>(<span class="params">act,day,days</span>):</span><br><span class="line"> <span class="comment"># 判断一个活动是否能开始,条件1:资源是否足够</span></span><br><span class="line"> a = days.index(day)</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(act.time_long):</span><br><span class="line"> <span class="keyword">if</span> days[<span class="built_in">min</span>(a+j,<span class="built_in">len</span>(days)-<span class="number">1</span>)].resource_left < act.resourceRequest:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">can_start2</span>(<span class="params">act,act_done</span>):</span><br><span class="line"> <span class="comment"># 判断一个活动是否能开始,条件2:该活动的前序活动是否已经完成</span></span><br><span class="line"> <span class="keyword">for</span> preAct <span class="keyword">in</span> act.predecessor:</span><br><span class="line"> <span class="keyword">if</span> preAct <span class="keyword">not</span> <span class="keyword">in</span> act_done:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">pre_done</span>(<span class="params">act,act_done,activities</span>):</span><br><span class="line"> <span class="comment"># 判断活动的所有前序活动是否都已完成,返回0则说明都已经完成</span></span><br><span class="line"> ans = [<span class="number">0</span> <span class="keyword">if</span> activities[i] <span class="keyword">in</span> act_done <span class="keyword">else</span> <span class="number">1</span> <span class="keyword">for</span> i <span class="keyword">in</span> act.predecessor]</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">sum</span>(ans) </span><br><span class="line"> <span class="comment">#================修改代码=====================</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">read_data_from_RCP_file</span>(<span class="params">file_name</span>):</span><br><span class="line"> <span class="string">'''</span></span><br><span class="line"><span class="string"> 读取标准化文件中的所有活动信息,包括 1.活动数 2.项目资源数 3.项目资源种类数 4.项目资源限量</span></span><br><span class="line"><span class="string"> 5.所有活动的ID,持续时间,资源需求,紧前活动</span></span><br><span class="line"><span class="string"> :param fileName:</span></span><br><span class="line"><span class="string"> :return: 标准化文件数据</span></span><br><span class="line"><span class="string"> '''</span></span><br><span class="line"> f = <span class="built_in">open</span>(file_name)</span><br><span class="line"> taskAndResourceType = f.readline().split(<span class="string">' '</span>) <span class="comment"># 第一行数据包含活动数和资源数</span></span><br><span class="line"> num_activities = <span class="built_in">int</span>(taskAndResourceType[<span class="number">0</span>]) <span class="comment"># 得到活动数</span></span><br><span class="line"> num_resource_type = <span class="built_in">int</span>(taskAndResourceType[<span class="number">1</span>]) <span class="comment"># 得到资源数</span></span><br><span class="line"> total_resource = np.array([<span class="built_in">int</span>(value) <span class="keyword">for</span> value <span class="keyword">in</span> f.readline().split(<span class="string">' '</span>)[:-<span class="number">1</span>]]) <span class="comment"># 获取资源限量</span></span><br><span class="line"> <span class="comment"># 将每个活动的所有信息存入到对应的Activity对象中去</span></span><br><span class="line"> activities = {}</span><br><span class="line"> preActDict = defaultdict(<span class="keyword">lambda</span>: [])</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(num_activities):</span><br><span class="line"> nextLine = [<span class="built_in">int</span>(value) <span class="keyword">for</span> value <span class="keyword">in</span> f.readline().split(<span class="string">' '</span>)[:-<span class="number">1</span>]]</span><br><span class="line"> <span class="comment"># task = Activity(i + 1, nextLine[0], nextLine[1:5], nextLine[6:])</span></span><br><span class="line"> task = Activity(i + <span class="number">1</span>, nextLine[<span class="number">0</span>], nextLine[<span class="number">1</span>:<span class="number">2</span>], nextLine[<span class="number">3</span>:])</span><br><span class="line"> activities[task.<span class="built_in">id</span>] = task</span><br><span class="line"> <span class="comment"># for act in nextLine[6:]:</span></span><br><span class="line"> <span class="keyword">for</span> act <span class="keyword">in</span> nextLine[<span class="number">3</span>:]:</span><br><span class="line"> preActDict[act].append(i + <span class="number">1</span>)</span><br><span class="line"> f.close()</span><br><span class="line"> <span class="comment"># 给每个活动加上紧前活动信息</span></span><br><span class="line"> <span class="keyword">for</span> actKey <span class="keyword">in</span> activities.keys():</span><br><span class="line"> activities[actKey].predecessor = preActDict[activities[actKey].<span class="built_in">id</span>].copy()</span><br><span class="line"> <span class="keyword">return</span> num_activities, num_resource_type, total_resource, activities </span><br><span class="line"></span><br><span class="line">file_name = <span class="string">r'D:/python代码库/实验/mv9.rcp'</span></span><br><span class="line">num_activities, num_resource_type, total_resource, activities = read_data_from_RCP_file(file_name)</span><br><span class="line">total_resource = total_resource[<span class="number">0</span>]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line">num_days = <span class="built_in">sum</span>([i.duration <span class="keyword">for</span> i <span class="keyword">in</span> activities.values()]) <span class="comment"># 总天数自动计算,不再需要手动指定</span></span><br><span class="line"><span class="comment"># num_days = 150</span></span><br><span class="line">days = [Day(i,total_resource) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>,num_days+<span class="number">1</span>)]</span><br><span class="line">act_list = [i <span class="keyword">for</span> i <span class="keyword">in</span> activities.values()]</span><br><span class="line">act_done = []</span><br><span class="line">act_candidate = [activities[<span class="number">1</span>]]</span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="comment"># ----------调度核心逻辑-------</span></span><br><span class="line"><span class="keyword">for</span> day <span class="keyword">in</span> days:</span><br><span class="line"> <span class="comment"># 首先考虑工期为0的活动</span></span><br><span class="line"> <span class="keyword">for</span> act <span class="keyword">in</span> act_candidate:</span><br><span class="line"> <span class="keyword">if</span> act.time_long == <span class="number">0</span>:</span><br><span class="line"> act.start = day.<span class="built_in">id</span>-<span class="number">1</span></span><br><span class="line"> act.end = day.<span class="built_in">id</span>-<span class="number">1</span></span><br><span class="line"> act_done.append(act)</span><br><span class="line"> act_candidate.remove(act)</span><br><span class="line"> <span class="comment"># act_candidate.append(act.successor)</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> act.successor:</span><br><span class="line"> act_candidate.append(activities[i])</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 遍历act_candidate列表,将能开启的工作全部启动</span></span><br><span class="line"> <span class="keyword">for</span> act <span class="keyword">in</span> act_candidate:</span><br><span class="line"> <span class="keyword">if</span> can_start1(act,day,days):</span><br><span class="line"> start_act(act,day,days)</span><br><span class="line"> <span class="comment"># -------更新act_done列表-----</span></span><br><span class="line"> <span class="keyword">for</span> act <span class="keyword">in</span> act_list:</span><br><span class="line"> <span class="keyword">if</span> act.end:</span><br><span class="line"> <span class="keyword">if</span> act.end <= day.<span class="built_in">id</span> <span class="keyword">and</span> act <span class="keyword">not</span> <span class="keyword">in</span> act_done:</span><br><span class="line"> act_done.append(act)</span><br><span class="line"> <span class="comment"># 更新act_candidate列表</span></span><br><span class="line"> <span class="keyword">for</span> act <span class="keyword">in</span> act_candidate:</span><br><span class="line"> <span class="keyword">for</span> suc <span class="keyword">in</span> act.successor:</span><br><span class="line"> <span class="keyword">if</span> pre_done(activities[suc],act_done,activities) == <span class="number">0</span>:</span><br><span class="line"> act_candidate.append(activities[suc]) </span><br><span class="line"> <span class="keyword">for</span> act <span class="keyword">in</span> act_candidate:</span><br><span class="line"> <span class="keyword">if</span> act <span class="keyword">in</span> act_done:</span><br><span class="line"> act_candidate.remove(act)</span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">plot_square</span>(<span class="params">matrix</span>):</span><br><span class="line"> <span class="comment"># plt.figure(figsize=(8, 8))</span></span><br><span class="line"> fig, ax = plt.subplots()</span><br><span class="line"> cmap = plt.get_cmap(<span class="string">'viridis'</span>) <span class="comment"># 使用 'viridis' colormap,你可以根据需要选择其他colormap</span></span><br><span class="line"> norm = plt.Normalize(vmin=<span class="number">0</span>, vmax=matrix.<span class="built_in">max</span>()) <span class="comment"># 指定归一化范围</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(matrix.shape[<span class="number">0</span>]):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(matrix.shape[<span class="number">1</span>]):</span><br><span class="line"> color = cmap(norm(matrix[i, j]))</span><br><span class="line"> <span class="keyword">if</span> matrix[i, j] == <span class="number">0</span>:</span><br><span class="line"> color = <span class="string">'white'</span></span><br><span class="line"> square = plt.Rectangle((j, total_resource-<span class="number">1</span>-i), <span class="number">1</span>, <span class="number">1</span>, fill=<span class="literal">True</span>, color=color, edgecolor=<span class="string">'black'</span>)</span><br><span class="line"> ax.add_patch(square)</span><br><span class="line"> <span class="keyword">if</span> matrix[i, j] != <span class="number">0</span>:</span><br><span class="line"> <span class="comment"># 在正方形中心位置添加数字</span></span><br><span class="line"> plt.text(j + <span class="number">0.5</span>, total_resource-<span class="number">1</span>-i + <span class="number">0.5</span>, <span class="built_in">str</span>(matrix[i, j]), color=<span class="string">'black'</span>,fontsize=<span class="number">12</span>, ha=<span class="string">'center'</span>, va=<span class="string">'center'</span>)</span><br><span class="line"> </span><br><span class="line"> ax.set_xlim(<span class="number">0</span>, matrix.shape[<span class="number">1</span>])</span><br><span class="line"> ax.set_ylim(<span class="number">0</span>, matrix.shape[<span class="number">0</span>])</span><br><span class="line"> ax.set_aspect(<span class="string">'equal'</span>, adjustable=<span class="string">'box'</span>)</span><br><span class="line"> ax.set_xlabel(<span class="string">'日期'</span>)</span><br><span class="line"> ax.set_ylabel(<span class="string">'资源'</span>)</span><br><span class="line"> plt.title(<span class="string">'项目调度图'</span>)</span><br><span class="line"> plt.show()</span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line">ans = [days[i].act_list <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(num_days)]</span><br><span class="line">ans.remove([])</span><br><span class="line">b = {}</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(activities)):</span><br><span class="line"> b[i+<span class="number">1</span>] = activities[i+<span class="number">1</span>].resourceRequest</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">copy</span>(<span class="params">sub_ans,b</span>):</span><br><span class="line"> result = [item <span class="keyword">for</span> item <span class="keyword">in</span> sub_ans <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(b.get(item, <span class="number">1</span>))]</span><br><span class="line"> <span class="keyword">return</span> result</span><br><span class="line">ans_new = [[]] * <span class="built_in">len</span>(ans)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(ans)):</span><br><span class="line"> ans_new[i] = copy(ans[i],b)</span><br><span class="line"><span class="comment"># print(ans_new)</span></span><br><span class="line"><span class="comment"># print('--------------各活动开始时间----------------')</span></span><br><span class="line">start_time = []</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>,<span class="built_in">len</span>(activities)+<span class="number">1</span>):</span><br><span class="line"> <span class="comment"># print('活动'+str(i)+'开始于'+str(activities[i].start))</span></span><br><span class="line"> start_time.append(activities[i].start)</span><br><span class="line"><span class="comment"># print(start_time)</span></span><br><span class="line"><span class="comment"># print('-------------活动总工期----------------')</span></span><br><span class="line">total_time = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>,<span class="built_in">len</span>(activities)+<span class="number">1</span>):</span><br><span class="line"> <span class="keyword">if</span> activities[i].successor == []:</span><br><span class="line"> total_time = activities[i].end+<span class="number">1</span></span><br><span class="line"><span class="comment"># print(total_time)</span></span><br><span class="line"><span class="comment"># 转成矩阵</span></span><br><span class="line">a = np.zeros((total_resource,<span class="built_in">len</span>(ans_new)),dtype=<span class="built_in">int</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(ans_new)):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(ans_new[i])):</span><br><span class="line"> a[total_resource-<span class="number">1</span>-j,i] = <span class="built_in">int</span>(ans_new[i][j])</span><br><span class="line"></span><br><span class="line">plot_square(a)</span><br><span class="line"><span class="comment"># print(a)</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h1 id="求解结果"><a href="#求解结果" class="headerlink" title="求解结果"></a>求解结果</h1><p>采用上述代码求解的项目调度图如图所示:<br><img src="/../images/%E9%BB%98%E8%AE%A4%E9%A1%BA%E5%BA%8F%E8%B0%83%E5%BA%A6%E6%96%B9%E6%A1%88.png"></p>
<p>采用最短时间活动最先开始规则生成图如下:<br><img src="/../images/%E5%90%AF%E5%8F%91%E8%A7%84%E5%88%99%E8%B0%83%E5%BA%A6%E6%96%B9%E6%A1%88.png"></p>
]]></content>
<tags>
<tag>项目调度,启发式规则</tag>
</tags>
</entry>
<entry>
<title>本地部署Graphhopper实现离线地图路径规划功能(小白放心食用版)</title>
<url>/2024/05/06/%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2Graphhopper%E5%AE%9E%E7%8E%B0%E7%A6%BB%E7%BA%BF%E5%9C%B0%E5%9B%BE%E8%B7%AF%E5%BE%84%E8%A7%84%E5%88%92%E5%8A%9F%E8%83%BD%EF%BC%88%E5%B0%8F%E7%99%BD%E6%94%BE%E5%BF%83%E9%A3%9F%E7%94%A8%E7%89%88%EF%BC%89/</url>
<content><![CDATA[<p>最近几天一直在做一个CVRP问题,需要计算两点之间的路径距离与时间,直接采用经纬度计算直线距离会有很大的误差。正常来说,直接调用百度或者高德地图提供的API接口即可轻松实现,但是由于项目最终需要部署在内网,所以只能采用离线地图来计算路径距离。</p>
<p>作为一个完全没接触过离线地图的小白,接到这个任务后内心是崩溃的。在找了无数的教程、看了无数的文档、踩了无数的坑之后,终于实现了这一功能,必须记录一下。</p>
<p>首先是工具与技术路线的选择,作为小白,经过一通搜索后,下载了无数的软件后,终于明白了,要做到离线路径规划或者导航,必须要有两要素。首先是地图数据(一般是地图瓦片,格式为jpg或者png,这里必须注意百度地图瓦片编号与高德地图瓦片编号规则是不同的!!!)以及路网数据(一般为pbf等格式),然后是本地服务(就是根据地图数据实现路径规划的算法等服务)。确定好需要的工具以及数据后,咱们直接开始!</p>
<h2 id="操作步骤"><a href="#操作步骤" class="headerlink" title="操作步骤"></a>操作步骤</h2><h3 id="地图"><a href="#地图" class="headerlink" title="地图"></a>地图</h3><p>地图数据去这里<a href="https://www.openstreetmap.org/%E6%88%96%E8%80%85%E8%BF%99%E9%87%8C[Geofabrik">https://www.openstreetmap.org/或者这里[Geofabrik</a> Download Server](<a href="https://download.geofabrik.de/)%E4%B8%8B%E8%BD%BD%E3%80%82%E6%AF%94%E5%A6%82%E6%88%91%E9%9C%80%E8%A6%81%E6%B5%99%E6%B1%9F%E7%9C%81%E7%9A%84%E5%9C%B0%E5%9B%BE%E8%B7%AF%E7%BD%91%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%B0%B1%E4%B8%8B%E8%BD%BD%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BA%E2%80%99zhejiang-latest.osm.pbf%E2%80%98%E7%9A%84%E6%96%87%E4%BB%B6%E3%80%82%E8%BF%99%E9%87%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%AD%A4%E4%B8%8B%E8%BD%BD%E6%B5%99%E6%B1%9F%E7%9C%81%E5%9C%B0%E5%9B%BE%E6%95%B0%E6%8D%AE%E3%80%82">https://download.geofabrik.de/)下载。比如我需要浙江省的地图路网数据,就下载一个名为’zhejiang-latest.osm.pbf‘的文件。这里也可以在此下载浙江省地图数据。</a></p>
<h3 id="搭建本地服务(window环境)"><a href="#搭建本地服务(window环境)" class="headerlink" title="搭建本地服务(window环境)"></a>搭建本地服务(window环境)</h3><p>地图准备好后,就需要搭建我们本地的服务了。这里注意,搭建本地服务需要准备好我们的本地环境,因我Graphhopper是基于java开发的,因此我们需要下载<strong>Java JDK</strong>,从Oracle官网下载并安装JDK,并配置好环境变量。然后是maven,同样下载安装配置环境变量,可以参考<a href="https://blog.csdn.net/qq_42006801/article/details/115640020">Maven安装与配置(详细步骤)_apachemaven安装与配置_liyitongxue的博客-CSDN博客</a>。</p>
<h3 id="下载Graphhopper"><a href="#下载Graphhopper" class="headerlink" title="下载Graphhopper"></a>下载Graphhopper</h3><p>然后我们可以开始下载Graphhopper,这里可以直接在GitHub搜索Graphhopper即可。</p>
<p><img src="/../images/ac2d62d546e648f9a608f0b487bc035e.png" alt="在这里插入图片描述"></p>
<p>这里建议<strong>不要</strong>直接克隆master分支,可以选择<strong>stable</strong>分支(踩了好多坑之后,才发现master分支好像没有graphhopper.sh文件,这个文件在后面很重要!)</p>
<p><img src="/../images/c89e702ea5bf4b46af6f490fa46fbad9.png" alt="在这里插入图片描述"></p>
<p>将该分支克隆到本地之后,会发现里面有一个文件名为config-example.yml的文件,采用文本编辑器打开,将文件开头数据修改成自己的文件路径,端口选择8989端口。<br><img src="/../images/f31c651486a9435fa42f660df98c3db4.png" alt="在这里插入图片描述"></p>
<p>到这里有些教程会让你直接在命令行执行以下命令构建路网数据,生成索引文件:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">./graphhopper.sh build</span><br></pre></td></tr></table></figure>
<p>然后执行</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">./graphhopper.sh web</span><br></pre></td></tr></table></figure>
<p>然后是打开网址<a href="http://127.0.0.1:8989即可。">http://127.0.0.1:8989即可。</a></p>
<p>但是对于像我这样的小白,这里可能会遇到很多问题,这里我们逐一展开解决(每一个都是让人心态崩溃的坑)。</p>
<h3 id="坑1-本地服务问题"><a href="#坑1-本地服务问题" class="headerlink" title="坑1-本地服务问题"></a>坑1-本地服务问题</h3><p>首先是本地服务问题,一般直接在浏览器里输入<a href="http://127.0.0.1:8989是会显示拒绝访问,这里的域名是本地服务器,这一般是由于没安装IIS服务。解决方法很简单:在控制面板/程序/启用或关闭Windows功能中选择以下两项安装。将两项全点上就行。如果输入ip地址http://127.0.0.1显示以下界面,就算是跳出这个坑了。">http://127.0.0.1:8989是会显示拒绝访问,这里的域名是本地服务器,这一般是由于没安装IIS服务。解决方法很简单:在控制面板/程序/启用或关闭Windows功能中选择以下两项安装。将两项全点上就行。如果输入ip地址http://127.0.0.1显示以下界面,就算是跳出这个坑了。</a><br><img src="/../images/0177ed1aa0c949d79299f093a54f223b.png" alt="在这里插入图片描述"><br><img src="/../images/3587bb7a924949f98ad55730f4b02f1d.png" alt="在这里插入图片描述"></p>
<h3 id="坑2-cygwin问题"><a href="#坑2-cygwin问题" class="headerlink" title="坑2-cygwin问题"></a>坑2-cygwin问题</h3><p>下一个坑是Cygwin,这里同样是下载安装。<a href="https://blog.csdn.net/hu_yinghui/article/details/125263154">windows下安装Cygwin详细教程_快乐小胡!的博客-CSDN博客</a></p>
<h3 id="坑3-wget问题"><a href="#坑3-wget问题" class="headerlink" title="坑3-wget问题"></a>坑3-wget问题</h3><p>如果到这里还是显示8989端口拒绝访问,可能是wget没有下载安装。这里的wget是linux里面的下载工具,我们在windows下可以搜索wget for windows下载安装。<a href="https://zhuanlan.zhihu.com/p/28826000">Wget for windows——优雅地实现批量下载 - 知乎 (zhihu.com)</a></p>
<h3 id="本地服务,启动!"><a href="#本地服务,启动!" class="headerlink" title="本地服务,启动!"></a>本地服务,启动!</h3><p>解决完以上问题之后,终于可以进行搭建我们自己的本地服务了。但是如果还是按照有些教程上进入graphhopper根目录后输入</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">./graphhopper.sh build</span><br></pre></td></tr></table></figure>
<p>还是会出现问题,会跳出以下窗口,几十秒后又会自动关闭。</p>
<p>这行命令的作用是:下载所需的依赖,构建GraphHopper的路网数据,并生成索引文件。经过多方查找资料,发现应该输入</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">先进入到graphhopper目录下,再执行以下语句</span></span><br><span class="line">./graphhopper.sh -a web -i china-latest.osm.pbf</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">china-latest.osm.pdf是下载的路图</span></span><br></pre></td></tr></table></figure>
<p>跳出以下界面则配置完成</p>
<p><img src="/../images/9eda1b49f747438e8bfd090470baedbe.png" alt="在这里插入图片描述"><br>如果报以下错误</p>
<p><code>-bash: ./graphhopper.sh: /bin/bash^M: bad interpreter: No such file or directory</code></p>
<p>可以尝试使用以下方式进行解决</p>
<p><code>sed -i 's/\r$//' ./graphhopper.sh #解决linux 跟Windows 对于换行符不同的区别</code></p>
<p>如果不成功可能是因为解析的地图数据过大导致内存溢出发生错误:<br>可以在执行启动之前先扩大内存</p>
<p><code>export JAVA_OPTS="-Xmx4g -Xms4g"#加大至4G内存</code></p>
<h2 id="最终效果"><a href="#最终效果" class="headerlink" title="最终效果"></a>最终效果</h2><p>到此,所有操作全部完成,在浏览器输入<a href="http://127.0.0.1:8989即可进入以下网页,进行路径规划。">http://127.0.0.1:8989即可进入以下网页,进行路径规划。</a></p>
<p>也可以通过python调用本地服务器接口,将结果传入python程序,进行后续一系列操作。<br><img src="/../images/87a27c28e3a54dae905273dfc1747aed.png" alt="在这里插入图片描述"></p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line">url = <span class="string">'http://127.0.0.1:8989/route?point=27.939648,120.934602&point=27.936577,120.931941&profile=car&layer=OpenStreetMap'</span></span><br><span class="line">response = requests.get(url) </span><br><span class="line">info = response.json()[<span class="string">'paths'</span>][<span class="number">0</span>]</span><br><span class="line"><span class="built_in">print</span>(info) <span class="comment"># 获取json</span></span><br><span class="line"><span class="comment"># print(info['distance']) # 获取路径距离,单位为米</span></span><br><span class="line"><span class="comment"># print(info['time']) # 获取路径时间,单位为毫秒</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">round</span>(info[<span class="string">'distance'</span>]/<span class="number">1000</span>,<span class="number">2</span>)) <span class="comment"># 单位转为千米</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">round</span>(info[<span class="string">'time'</span>]/(<span class="number">60</span>*<span class="number">1000</span>),<span class="number">0</span>)) <span class="comment"># 单位转为分钟</span></span><br></pre></td></tr></table></figure>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="https://juejin.cn/post/6955757106750292004">本地百度瓦片+GraphHopper搭建离线路径规划 - 掘金 (juejin.cn)</a></p>
<p><a href="https://blog.csdn.net/wml00000/article/details/84030182">基于Leaflet和GraphHopper实现离线路径规划_graphhooper_wml00000的博客-CSDN博客</a></p>
<p><a href="https://blog.csdn.net/wml00000/article/details/84108694">基于GraphHopper搭建离线路径规划服务并可视化_graph 路径规划_wml00000的博客-CSDN博客</a></p>
<p><a href="https://blog.csdn.net/Sysdark/article/details/111298945">离线路径规划服务Graphhopper_RobotMartin的博客-CSDN博客</a></p>
<p><a href="https://blog.csdn.net/qq_42006801/article/details/115640020">Maven安装与配置(详细步骤)_apachemaven安装与配置_liyitongxue的博客-CSDN博客</a></p>
<p><a href="https://blog.csdn.net/qq_42006801/article/details/115640020">Maven安装与配置(详细步骤)_apachemaven安装与配置_liyitongxue的博客-CSDN博客</a></p>
<p><a href="https://www.bilibili.com/read/cv22391502/">实现离线地图导航第一步!windows本地搭建GraphHopper服务 - 哔哩哔哩 (bilibili.com)</a></p>
]]></content>
<tags>
<tag>车辆路径规划</tag>
</tags>
</entry>
<entry>
<title>列生成算法简介</title>
<url>/2024/05/12/%E5%88%97%E7%94%9F%E6%88%90/</url>
<content><![CDATA[<h3 id="1-什么是列生成"><a href="#1-什么是列生成" class="headerlink" title="1. 什么是列生成"></a>1. 什么是列生成</h3><p>列生成算法是一种用于解决大规模线性规划问题的高效算法,它基于单纯形法的思想,通过求解子问题来找到可以进基的非基变量。在列生成算法中,每个变量都代表一列,因此称为列生成算法。该算法的优点在于其高效的计算性能和较好的收敛性,适用于处理大规模、复杂的线性规划问题。</p>
<p>在列生成算法的迭代过程中,因为会不断有变量入基,所以会导致限制主问题的列不断增加,所以叫做列生成算法。</p>
<h3 id="2-列生成的应用范围"><a href="#2-列生成的应用范围" class="headerlink" title="2. 列生成的应用范围"></a>2. 列生成的应用范围</h3><p>列生成被广泛应用于调度问题、切割问题、车辆路径问题、选址问题等。 该算法的优点在于其高效的计算性能和较好的收敛性,适用于处理大规模、复杂的线性规划问题。对于变量数目很多的线性优化问题,单纯形法速度很慢,可以用到列生成方法来加快求解速度。</p>
<h3 id="3-列生成的原理"><a href="#3-列生成的原理" class="headerlink" title="3. 列生成的原理"></a>3. 列生成的原理</h3><p>基本思路如下:</p>
<p>1、先把原问题限制到一个规模更小的限制主问题,在限制主问题的基础上用单纯形法求解,但此时的解并不是主问题的最优解。</p>
<p>2、通过一个子问题去检查那些未被考虑的变量中是否有使得reduced cost小于0的?如果有,就把这个变量的相关系数列加入到限制主问题的系数矩阵中,回到第一步。</p>
<p>经过反复迭代,知道子问题的reduced cost rate大于等于0,那么主问题就求到了最优解。</p>
<h3 id="4-基本概念"><a href="#4-基本概念" class="headerlink" title="4. 基本概念"></a>4. 基本概念</h3><h4 id="受限主问题"><a href="#受限主问题" class="headerlink" title="受限主问题"></a>受限主问题</h4><p>$$<br>min(y_1+y_2+\cdots+y_k)<br>$$</p>
<p>$s.t.$<br>$$<br>R_1: a_{11}y_1+\cdots+a_{1k}y_k \geq b_1<br>$$<br>$$<br>R_2: a_{21}y_1+\cdots+a_{2k}y_k \geq b_2<br>$$</p>
<p>$$<br>\cdots<br>$$</p>
<p>$$<br>R_m:a_{m1}y_1+\cdots+a_{mk}y_k \geq b_m<br>$$</p>
<p>就是从主问题中选取k个变量构成的松弛问题。</p>
<h4 id="子问题"><a href="#子问题" class="headerlink" title="子问题"></a>子问题</h4><p>通过求解RMP问题或者RMP对偶问题后,得到了想要的$c_BB^{-1}$以后,子问题就是通过$\sigma_j = c_j - c_BB^{-1}a_j$</p>
<p>这条公式,在$y_{k+1}、y_m$中寻找检验数为负且最小的变量,将变量对应的那一列添加到RMP中。</p>
<h2 id="列生成算法实现"><a href="#列生成算法实现" class="headerlink" title="列生成算法实现"></a>列生成算法实现</h2><h3 id="案例求解"><a href="#案例求解" class="headerlink" title="案例求解"></a>案例求解</h3><h4 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h4><p>cutting stock problem是采用列生成算法求解的经典案例。该问题如下:有一些纸筒,每个纸筒长度为16m。顾客需要25个3m,20个6m,15个7m的纸筒。要求在满足顾客需求的情况下,裁剪的纸筒数最小。</p>
<h4 id="建立模型"><a href="#建立模型" class="headerlink" title="建立模型"></a>建立模型</h4><p>可以采用启发式算法求解到一个初始解如下:</p>
<p>5个纸筒采用切割方案1:3,3,3,3,3;</p>
<p>10个纸筒采用切割方案2:6,6;</p>
<p>8个纸筒采用切割方案3:7,7;</p>
<p>总计23个纸筒。可以看出,采用23个纸筒是一定可以满足要求的,这是问题的一个上界(upper bound)。</p>
<p>该问题可行的切割方案很多,我们可以采用P表示所有可行裁剪方案的集合,里面的方案总数为n(这里的n并不需要知道其确切取值,一般来说n是一个很大的数)。$a_{ij}$表示第$j$种方案里类别$i$的个数,$y_j$表示第$j$种方案的选择个数。建立数学模型如下:<br>$$<br>min \quad y_1+y_2+\cdots+y_n<br>$$<br>$s.t.$<br>$$<br>R1:a_{11}y_1 + \cdots + a_{1n}y_n \geq 25<br>$$<br>$$<br>R2:a_{21}y_1 + \cdots + a_{2n}y_n \geq 20<br>$$</p>
<p>$$<br>R3:a_{31}y_1 + \cdots + a_{3n}y_n \geq 15<br>$$</p>
<p>约束中的每一列对应的是一种切割方案,前三种方案已知,就是我们前面采用启发式算法求解的三种方案。其它的$n-3$种切割方案未知。</p>
<h4 id="问题求解"><a href="#问题求解" class="headerlink" title="问题求解"></a>问题求解</h4><h5 id="第一轮循环"><a href="#第一轮循环" class="headerlink" title="第一轮循环"></a>第一轮循环</h5><p>首先从上述模型中选出一些列,构成问题的限制主问题,这里我们选取前3列。则限制主问题如下<br>$$<br>min \quad y_1 + y_2 + y_3<br>$$<br>$$<br>5y_1 + 0 y_2 + 0y_3 \geq 25<br>$$</p>
<p>$$<br>0y_1 + 2 y_2 + 0y_3 \geq 20<br>$$</p>
<p>$$<br>0y_1 + 0 y_2 + 2y_3 \geq 15<br>$$</p>
<p>使用python+gurobi求解上述线性规划问题</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> gurobipy <span class="keyword">as</span> gp</span><br><span class="line"><span class="comment"># 实例化模型</span></span><br><span class="line">m = gp.Model(<span class="string">'column generation'</span>)</span><br><span class="line">y = m.addVars(<span class="number">3</span>,vtype = gp.GRB.CONTINUOUS,name=<span class="string">'y'</span>,lb=<span class="number">0</span>)</span><br><span class="line">m.addConstr(<span class="number">5</span>*y[<span class="number">0</span>] >= <span class="number">25</span>)</span><br><span class="line">m.addConstr(<span class="number">2</span>*y[<span class="number">1</span>] >= <span class="number">20</span>)</span><br><span class="line">m.addConstr(<span class="number">2</span>*y[<span class="number">2</span>] >= <span class="number">15</span>)</span><br><span class="line">m.setObjective(y[<span class="number">0</span>]+y[<span class="number">1</span>]+y[<span class="number">2</span>],gp.GRB.MINIMIZE)</span><br><span class="line">m.setParam(<span class="string">'OutputFlag'</span>,<span class="number">0</span>)</span><br><span class="line">m.optimize()</span><br><span class="line">m.getAttr(gp.GRB.Attr.Pi)</span><br></pre></td></tr></table></figure>
<p>可以求解出对偶变量的取值为$c_BB^{-1}=[0.2,0.5,0.5]$。现在要找一列加入RMP,但是并不知道其取值,我们将其记作$\alpha_4 = [a_{14},a_{24},a_{34}]^T$。得到非基变量的检验数为$\sigma_4 = c_4 - c_BB^{-1}\alpha_4 = 1-0.2\alpha_{14} - 0.5\alpha_{24} - 0.5\alpha_{34}$</p>
<p>从而构造子问题如下:<br>$$<br>min(1-0.2a_{14} - 0.5a_{24} - 0.5a_{34})<br>$$<br>$s.t.$<br>$$<br>3a_{14}+6a_{24}+7a_{34} \leq 16<br>$$<br>$$<br>a_{ij} \in Z<br>$$</p>
<p>同样采用python+gurobi求解上述问题</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> gurobipy <span class="keyword">as</span> gp</span><br><span class="line">m1 = gp.Model(<span class="string">'subproblem'</span>)</span><br><span class="line">a = m1.addVars(<span class="number">3</span>,vtype=gp.GRB.INTEGER,lb=<span class="number">0</span>,name=<span class="string">'a'</span>)</span><br><span class="line">m1.setObjective(<span class="number">1</span>-<span class="number">0.2</span>*a[<span class="number">0</span>]-<span class="number">0.5</span>*a[<span class="number">1</span>]-<span class="number">0.5</span>*a[<span class="number">2</span>])</span><br><span class="line">m1.addConstr(<span class="number">3</span>*a[<span class="number">0</span>]+<span class="number">6</span>*a[<span class="number">1</span>]+<span class="number">7</span>*a[<span class="number">2</span>] <= <span class="number">16</span>) <span class="comment"># 列生成规则</span></span><br><span class="line">m1.setParam(<span class="string">'OutputFlag'</span>,<span class="number">0</span>)</span><br><span class="line">m1.optimize()</span><br><span class="line"><span class="built_in">print</span>(a[<span class="number">0</span>].x,a[<span class="number">1</span>].x,a[<span class="number">2</span>].x)</span><br></pre></td></tr></table></figure>
<p>求解出$\alpha_4 = [1,2,0]^T$,检验数为$\sigma_4 = c_4 - c_BB^{-1}\alpha_4 = 1-0.2\times1 - 0.5\times2 - 0.5\times0 = -0.2 < 0$,因为检验数小于0,所以需要将$y_4$入基,添加到主问题中,开始第二轮迭代。</p>
<h5 id="第二轮循环"><a href="#第二轮循环" class="headerlink" title="第二轮循环"></a>第二轮循环</h5><p>加入$y_4$后,限制主问题变为<br>$$<br>min \quad y_1 + y_2 + y_3 + y_4<br>$$<br>$$<br>5y_1 + 0 y_2 + 0y_3 + 1y_4\geq 25<br>$$</p>
<p>$$<br>0y_1 + 2 y_2 + 0y_3 + 2y_4 \geq 20<br>$$</p>
<p>$$<br>0y_1 + 0 y_2 + 2y_3 + 0y_4 \geq 15<br>$$</p>
<p>限制主问题与之前相比,多了一列,所以被称为列生成算法。求解该限制主问题,其对偶变量取值为$c_BB^{-1}=[0.2,0.4,0.5]$,下一个需要入基的变量记为$\alpha_5 = [a_{15},a_{25},a_{35}]^T$,构造子问题如下<br>$$<br>min(1-0.2a_{15} - 0.4a_{25} - 0.5a_{35})<br>$$<br>$s.t.$<br>$$<br>3a_{15}+6a_{25}+7a_{35} \leq 16<br>$$<br>$$<br>a_{ij} \in Z<br>$$</p>
<p>采用同样方法求解该子问题,得到结果$\alpha_5 = [3,0,1]^T$,检验数为$\sigma_5 = c_5 - c_BB^{-1}\alpha_5 = 1-0.2\times3 - 0.4\times0 - 0.5\times1 = -0.1 < 0$,因为检验数小于0,所以需要将$y_5$入基,添加到主问题中,开始下一轮迭代。</p>
<h5 id="第三轮循环"><a href="#第三轮循环" class="headerlink" title="第三轮循环"></a>第三轮循环</h5><p>加入$y_5$后,限制主问题变为<br>$$<br>min \quad y_1 + y_2 + y_3 + y_4 + y_5<br>$$<br>$$<br>5y_1 + 0 y_2 + 0y_3 + 1y_4 + 3y_5\geq 25<br>$$</p>
<p>$$<br>0y_1 + 2 y_2 + 0y_3 + 2y_4 + 0y_5 \geq 20<br>$$</p>
<p>$$<br>0y_1 + 0 y_2 + 2y_3 + 0y_4 + 1y_5 \geq 15<br>$$</p>
<p>还是求解限制主问题,其对偶变量取值为$c_BB^{-1}=[0.1667,0.4167,0.5]$,下一个需要入基的变量记为$\alpha_6 = [a_{16},a_{26},a_{36}]^T$,构造子问题如下<br>$$<br>min(1-0.1667a_{16} - 0.4167a_{26} - 0.5a_{36})<br>$$<br>$s.t.$<br>$$<br>3a_{16}+6a_{26}+7a_{36} \leq 16<br>$$<br>$$<br>a_{ij} \in Z<br>$$</p>
<p>求得结果$\alpha_5 = [1,1,1]^T$,检验数$\sigma_6= c_6 - c_BB^{-1}\alpha_6 = 1-0.1667\times1- 0.4167\times1 - 0.5\times1 = -0.08333 < 0$,所以将$y_6$代入</p>
<h5 id="第四轮循环"><a href="#第四轮循环" class="headerlink" title="第四轮循环"></a>第四轮循环</h5><p>加入$y_6$后,限制主问题变为<br>$$<br>min \quad y_1 + y_2 + y_3 + y_4 + y_5 + y_6<br>$$<br>$$<br>5y_1 + 0 y_2 + 0y_3 + 1y_4 + 3y_5 + y_6\geq 25<br>$$</p>
<p>$$<br>0y_1 + 2 y_2 + 0y_3 + 2y_4 + 0y_5 + y_6 \geq 20<br>$$</p>
<p>$$<br>0y_1 + 0 y_2 + 2y_3 + 0y_4 + 1y_5 + y_6 \geq 15<br>$$</p>
<p>还是求解限制主问题,其对偶变量取值为$c_BB^{-1}=[0.2,0.4,0.4]$,下一个需要入基的变量记为$\alpha_7 = [a_{17},a_{27},a_{37}]^T$,构造子问题如下<br>$$<br>min(1-0.2a_{17} - 0.4a_{27} - 0.4a_{37})<br>$$<br>$s.t.$<br>$$<br>3a_{17}+6a_{27}+7a_{37} \leq 16<br>$$<br>$$<br>a_{ij} \in Z<br>$$</p>
<p>求得结果$\alpha_5 = [5,0,0]^T$,检验数$\sigma_6= c_6 - c_BB^{-1}\alpha_6 = 1-0.2\times5- 0.4\times0 - 0.4\times0 = 0$,结束迭代,此时列生成算法结束。</p>
<p>此时,我们将$y_7$代入模型,此时求解结果就是最优解。</p>
<p>求解出最优解为$y=[1,0,0,3,1,14,0]$,此时目标函数值为19。</p>
<p>所以我们得到的最终切割方案为</p>
<table>
<thead>
<tr>
<th align="center">方案</th>
<th align="center">该方案的数量</th>
</tr>
</thead>
<tbody><tr>
<td align="center">3,3,3,3,3,3</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">3,6,6</td>
<td align="center">3</td>
</tr>
<tr>
<td align="center">3,3,3,7</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">3,6,7</td>
<td align="center">14</td>
</tr>
</tbody></table>
<h2 id="完整版列生成代码"><a href="#完整版列生成代码" class="headerlink" title="完整版列生成代码"></a>完整版列生成代码</h2><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> gurobipy <span class="keyword">as</span> grb</span><br><span class="line"><span class="keyword">from</span> gurobipy <span class="keyword">import</span> GRB</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">master_problem</span>(<span class="params">column, vtype</span>):</span><br><span class="line"> m = grb.Model()</span><br><span class="line"> x = m.addMVar(shape=column.shape[<span class="number">1</span>], lb=<span class="number">0</span>, vtype=vtype)</span><br><span class="line"> m.addConstr(lhs=column @ x >= demand_number_array)</span><br><span class="line"> m.setObjective(x.<span class="built_in">sum</span>(), GRB.MINIMIZE)</span><br><span class="line"> m.optimize()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> vtype == GRB.CONTINUOUS:</span><br><span class="line"> <span class="keyword">return</span> np.array(m.getAttr(<span class="string">'Pi'</span>, m.getConstrs()))</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> m.objVal, np.array(m.getAttr(<span class="string">'X'</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">restricted_lp_master_problem</span>(<span class="params">column</span>):</span><br><span class="line"> <span class="keyword">return</span> master_problem(column, GRB.CONTINUOUS)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">restricted_ip_master_problem</span>(<span class="params">column</span>):</span><br><span class="line"> <span class="keyword">return</span> master_problem(column, GRB.INTEGER)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">knapsack_subproblem</span>(<span class="params">kk</span>):</span><br><span class="line"> m = grb.Model()</span><br><span class="line"> x = m.addMVar(shape=kk.shape[<span class="number">0</span>], lb=<span class="number">0</span>, vtype=GRB.INTEGER)</span><br><span class="line"> m.addConstr(lhs=demand_width_array @ x <= roll_width)</span><br><span class="line"> m.setObjective(<span class="number">1</span> - kk @ x, GRB.MINIMIZE)</span><br><span class="line"> m.optimize()</span><br><span class="line"></span><br><span class="line"> flag_new_column = m.objVal < <span class="number">0</span></span><br><span class="line"> <span class="keyword">if</span> flag_new_column:</span><br><span class="line"> new_column = m.getAttr(<span class="string">'X'</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> new_column = <span class="literal">None</span></span><br><span class="line"> <span class="keyword">return</span> flag_new_column, new_column</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">roll_width = np.array(<span class="number">16</span>)</span><br><span class="line">demand_width_array = np.array([<span class="number">3</span>, <span class="number">6</span>, <span class="number">7</span>])</span><br><span class="line">demand_number_array = np.array([<span class="number">25</span>, <span class="number">20</span>, <span class="number">15</span>])</span><br><span class="line">initial_cut_pattern = np.diag(np.floor(roll_width / demand_width_array))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">flag_new_cut_pattern = <span class="literal">True</span></span><br><span class="line">new_cut_pattern = <span class="literal">None</span></span><br><span class="line">cut_pattern = initial_cut_pattern</span><br><span class="line"><span class="keyword">while</span> flag_new_cut_pattern:</span><br><span class="line"> <span class="keyword">if</span> new_cut_pattern:</span><br><span class="line"> cut_pattern = np.column_stack((cut_pattern, new_cut_pattern))</span><br><span class="line"> kk = restricted_lp_master_problem(cut_pattern)</span><br><span class="line"> flag_new_cut_pattern, new_cut_pattern = knapsack_subproblem(kk)</span><br><span class="line"></span><br><span class="line">minimal_stock, optimal_number = restricted_ip_master_problem(cut_pattern)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">'************************************************'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'parameter:'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'roll_width: <span class="subst">{roll_width}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'demand_width_array: <span class="subst">{demand_width_array}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'demand_number_array: <span class="subst">{demand_number_array}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'result:'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'minimal_stock: <span class="subst">{minimal_stock}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'cut_pattern: <span class="subst">{cut_pattern}</span>'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f'optimal_number: <span class="subst">{optimal_number}</span>'</span>)</span><br></pre></td></tr></table></figure>
<p>运行结果</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">************************************************</span><br><span class="line">roll_width:16</span><br><span class="line">demand_width_array:[3,6,7]</span><br><span class="line">demand_number_array:[25,20,15]</span><br><span class="line">minimal_stock:19.0</span><br><span class="line">cut_pattern:[[5,0,0,1,3,1]</span><br><span class="line">[0,2,0,2,0,1]</span><br><span class="line">[0,0,2,0,1,1]]</span><br><span class="line">optimal_number:[1,0,0,3,1,14]</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag>精确算法</tag>
</tags>
</entry>
<entry>
<title>无题</title>
<url>/2024/05/27/%E9%9B%A8%E5%A4%A9emo/</url>
<content><![CDATA[<p><img src="/../images/IMG_20240522_190921.jpg" alt="IMG_20240522_190921"></p>
]]></content>
<tags>
<tag>随便写写</tag>
</tags>
</entry>
<entry>
<title>灰靶决策</title>
<url>/2024/06/01/%E7%81%B0%E9%9D%B6%E5%86%B3%E7%AD%96/</url>
<content><![CDATA[<h1 id="多目标加权智能灰靶决策模型"><a href="#多目标加权智能灰靶决策模型" class="headerlink" title="多目标加权智能灰靶决策模型"></a>多目标加权智能灰靶决策模型</h1><h2 id="1-灰色决策模型"><a href="#1-灰色决策模型" class="headerlink" title="1. 灰色决策模型"></a>1. 灰色决策模型</h2><p><strong>定义1</strong> 事件、对策、目标、效果称为灰色决策四要素.</p>
<p><strong>定义2</strong> 设$A={a_1,a_2,\cdots,a_n}$为研究范围内事件的全体,称为该研究范围内的事件集,$a_i(i=1,2,\cdots,n)$为第$i$个事件,所有可能对策全体称为对策集,记作$B={b_1,b_2,\cdots,b_m}$,其中$b_j(j=1,2,\cdots,m)$为第$j$种对策.</p>
<p><strong>定义3</strong> 事件集A与对策集B的乘积$A\times B = {(a_i,b_j)|a_i\in A,b_j\in B}$称为决策方案集,记作$S= A\times B$.对于任意$a_i \in A, b_j \in B$,称$(a_i,b_j)$为一个决策方案,记作$s_{ij}=(a_i,b_j)$.</p>
<p><strong>定义4</strong> 设$$U^{(k)}=(u_{ij}^{(k)})=\begin{bmatrix}u_{11}^{(k)}&\dots&u_{1m}^{(k)}\\vdots&\ddots&\vdots\u_{1n}^{(k)}&\dots&u_{nm}^{(k)}\end{bmatrix}$$为决策方案集$S$在目标下的效果样本矩阵.</p>
<ol>
<li>设$k$为效益型目标,希望目标效果的样本值越大越优.$k$目标下的灰靶为$u_{ij}^{(k)}\in[u_{i_0j_0}^{(k)},\max_i\max_j{u_{ij}^{(k)}}]$即$u_{i_0j_0}^{(k)}$为k目标的效果临界值,称$r_{ij}^{(k)}=\frac{u_{ij}^{(k)}-u_{i_0j_0}^{(k)}}{\max_i\max_j{u_{ij}^{(k)}}-u_{i_0j_0}^{(k)}}$为效益型目标效果测度函数.</li>
<li>设$k$为成本型目标,希望目标效果的样本值越小越优.设$k$目标下的灰靶为$u_{ij}^{(k)}\in[u_{i_0j_0}^{(k)},\min_i\min_j{u_{ij}^{(k)}}]$即$u_{i_0j_0}^{(k)}$为k目标的效果临界值,称$r_{ij}^{(k)}=\frac{u_{i_0j_0}^{(k)}-u_{ij}^{(k)}}{u_{i_0j_0}^{(k)}-\min_i\min_j{u_{ij}^{(k)}}}$为成本型目标效果测度函数.</li>
<li>设$k$为适中型目标,希望目标效果的样本值越 接近一个适中值$A$越优.设$k$目标下的灰靶为$u_{ij}^{(k)}\in[A-u_{i_0j_0}^{(k)},A+u_{i_0j_0}^{(k)}]$即$A-u_{i_0j_0}^{(k)}$,$A+u_{i_0j_0}^{(k)}$,分别为k目标下的下限效果临界值和上限效果临界值.</li>
</ol>
<p> ① 当$u_{ij}^{(k)}\in[A-u_{i_0j_0}^{(k)},A]$时,称$r_{ij}^{(k)}=\frac{u_{ij}^{(k)}-A+u_{i_0j_0}^{(k)}}{u_{i_0j_0}^{(k)}}$为适中型目标下限效果测度函数;</p>
<p> ②当$u_{ij}^{(k)}\in[A,A+u_{i_0j_0}^{(k)}]$时,称$r_{ij}^{(k)}=\frac{A+u_{ij}^{(k)}-u_{i_0j_0}^{(k)}}{u_{i_0j_0}^{(k)}}$为适中型目标上限效果测度函数;</p>
<p><strong>定义5</strong> 当$k$目标效果值$r_{ij}^k\in[0,1]$时,称$k$目标中靶,$k$目标为加分因素;当$k$目标效果值$r_{ij}^k\in[-1,0]$时,称$k$目标脱靶,$k$目标为减分因素.</p>
<p><strong>定义6</strong> 设$\eta_k(k=1,2,\cdots,s)$为目标$k$的决策权,$\sum_{k=1}^s\eta_k=1$,称$R^{(k)}=(r_{ij}^{(k)})=\begin{bmatrix}r_{11}^{(k)}&\dots&r_{1m}^{(k)}\\vdots&\ddots&\vdots\r_{1n}^{(k)}&\dots&r_{nm}^{(k)}\end{bmatrix}$为决策方案集S在k目标下的一致效果测度矩阵.对于$s_{ij}\in S$,称$r_{ij}=\sum_{k=1}^s\eta_kr_{ij}^{(k)}$为决策方案的综合效果测度函数,同时也称$R=(r_{ij})=\begin{bmatrix}r_{11}&\dots&r_{1m}\\vdots&\ddots&\vdots\\r_{1n}&\dots&r_{nm}\end{bmatrix}$为综合效果测度矩阵.</p>
<p>**定义7 ** 若$\max_{1\leqslant j\leqslant m}{r_{ij}}=r_{ij_0}$则称$b_{j_0}$为事件$a_i$的最优对策;若$\max_{1\leqslant j\leqslant n}{r_{ij}}=r_{i_0j}$则称$a_{i_0}$为事件$b_j$的最优事件;若$\max_{1\leqslant i\leqslant n}\max_{1\leqslant j\leqslant m}{r_{ij}}=r_{i_0j_0}$则称$s_{i_0j_0}$为最优局势即方案.</p>
<h2 id="2-多目标加权智能灰靶决策模型的建模流程"><a href="#2-多目标加权智能灰靶决策模型的建模流程" class="headerlink" title="2. 多目标加权智能灰靶决策模型的建模流程"></a>2. 多目标加权智能灰靶决策模型的建模流程</h2><p>详细的多目标加权智能灰靶决策模型的建模算法流程如图所示.</p>
<img src="../images/image-20240601142847658.png" alt="image-20240601142847658" style="zoom: 67%;" />
]]></content>
<tags>
<tag>灰色系统</tag>
</tags>
</entry>
<entry>
<title>遗传算法求解带约束优化问题的处理办法</title>
<url>/2024/07/04/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95%E6%B1%82%E8%A7%A3%E5%B8%A6%E7%BA%A6%E6%9D%9F%E4%BC%98%E5%8C%96%E9%97%AE%E9%A2%98%E7%9A%84%E5%A4%84%E7%90%86%E5%8A%9E%E6%B3%95/</url>
<content><![CDATA[<h2 id="针对不满足约束染色体的处理对策"><a href="#针对不满足约束染色体的处理对策" class="headerlink" title="针对不满足约束染色体的处理对策"></a>针对不满足约束染色体的处理对策</h2><p>1、 直接标记为非法解,全部删去。相当于在种群中杀死所有的畸形个体。 问题:全部杀死,重新生成个体,直到满足约束,耗费时间很长。</p>
<p>2、 加高额的惩罚值。使得其在进化中快速淘汰。问题:耗时短,但是可能一直到迭代结束也无法找到合法解。</p>
<p>3、 加惩罚值的同时,不使用随机初始化,使用某种有策略的初始化。问题:需要知道问题的规则,并针对规则设计定制化的初始化算法。</p>
<h3 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h3><p>随机初始化:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">gen_chrom</span>(<span class="params">num_order, num_seru</span>):</span><br><span class="line"> sequence = np.random.permutation(<span class="built_in">list</span>(<span class="built_in">range</span>(<span class="number">1</span>,num_order+<span class="number">1</span>)))</span><br><span class="line"> assign = np.random.choice(<span class="built_in">range</span>(<span class="number">1</span>,num_seru+<span class="number">1</span>), num_order)</span><br><span class="line"> x = np.concatenate([sequence, assign],axis=<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure>
<p>定制化初始化:</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">gen_chrom</span>(<span class="params">num_order, num_seru, data_seru</span>):</span><br><span class="line"> sequence = np.random.permutation(<span class="built_in">list</span>(<span class="built_in">range</span>(<span class="number">1</span>,num_order+<span class="number">1</span>)))</span><br><span class="line"> process_able_matrix = np.zeros([num_seru,data_seru.shape[<span class="number">1</span>]-<span class="number">1</span>])</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(num_seru):</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(data_seru.shape[<span class="number">1</span>]-<span class="number">1</span>):</span><br><span class="line"> <span class="keyword">if</span> np.isnan(data_seru.iloc[i][j+<span class="number">1</span>][<span class="number">0</span>]):</span><br><span class="line"> <span class="keyword">pass</span></span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> process_able_matrix[i,j] = j+<span class="number">1</span></span><br><span class="line"> process_able_list = [[<span class="built_in">int</span>(value) <span class="keyword">for</span> value <span class="keyword">in</span> row <span class="keyword">if</span> value != <span class="number">0</span>] <span class="keyword">for</span> row <span class="keyword">in</span> process_able_matrix]</span><br><span class="line"> <span class="comment"># 找出所有的产品类型</span></span><br><span class="line"> product_types = <span class="built_in">set</span>()</span><br><span class="line"> <span class="keyword">for</span> machine <span class="keyword">in</span> process_able_list:</span><br><span class="line"> product_types.update(machine)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 创建一个包含每个产品类型可以在哪个机器加工的列表</span></span><br><span class="line"> product_to_machine = {product: [] <span class="keyword">for</span> product <span class="keyword">in</span> product_types}</span><br><span class="line"> <span class="keyword">for</span> machine_index, machine <span class="keyword">in</span> <span class="built_in">enumerate</span>(process_able_list):</span><br><span class="line"> <span class="keyword">for</span> product <span class="keyword">in</span> machine:</span><br><span class="line"> product_to_machine[product].append(machine_index+<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 按产品类型排序并转换为列表</span></span><br><span class="line"> result = [product_to_machine[product] <span class="keyword">for</span> product <span class="keyword">in</span> <span class="built_in">sorted</span>(product_to_machine)]</span><br><span class="line"> sequence = np.random.permutation(<span class="built_in">list</span>(<span class="built_in">range</span>(<span class="number">1</span>,num_order+<span class="number">1</span>)))</span><br><span class="line"> sequence_type = [data_order.iloc[i-<span class="number">1</span>][<span class="string">'product type'</span>] <span class="keyword">for</span> i <span class="keyword">in</span> sequence]</span><br><span class="line"> assign = [np.random.choice(result[sequence_type[i]-<span class="number">1</span>]) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(num_order)]</span><br><span class="line"> x = np.concatenate([sequence, assign],axis=<span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure>
<h3 id="效果比较"><a href="#效果比较" class="headerlink" title="效果比较"></a>效果比较</h3><p>使用对策2的效果</p>
<p><img src="/../images/image-20240705135906932.png" alt="图片未能加载!"></p>
<p>使用对策3的效果 </p>
<p><img src="/../images/image-20240704204703410.png" alt="image-20240704204703410"></p>
]]></content>
<tags>
<tag>启发算法</tag>
</tags>
</entry>
<entry>
<title>Docker初学者指南</title>
<url>/2024/07/06/Docker%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</url>
<content><![CDATA[<p>Docker 是一个开源的平台,用于开发、发布和运行应用程序。它通过使用容器技术,使应用程序可以在任何地方以一致的方式运行。Docker 的出现极大地简化了开发、测试和部署过程。本文将介绍 Docker 的基本使用方法,帮助你快速上手。</p>
<h1 id="Docker-介绍"><a href="#Docker-介绍" class="headerlink" title="Docker 介绍"></a>Docker 介绍</h1><p>什么是docker? </p>
<p><strong>官方回答:</strong> Docker 是一种虚拟化技术,它将应用程序及其依赖项打包到一个称为容器的标准化单元中。与传统的虚拟机不同,Docker 容器共享主机操作系统的内核,因此更轻量、启动更快、性能更高。</p>
<p><strong>通俗回答:</strong>开发了一个项目,可以在本机运行。比如这个项目需要依赖很多的库,如果别人的机器或者服务器想要运行这个项目就得一个个安装这些库并配置环境。工作量可能及其繁琐。但是有了docker就可以直接部署上线了。</p>
<p>Docker的历史?</p>
<p>诞生:2010年,一群热衷于 IT 技术的年轻人在美国成立了一家公司 dotCloud,专注于提供 PaaS(平台即服务)云计算服务。dotCloud 利用了 LXC(Linux Containers)相关的容器技术,并将其命名为 Docker。</p>
<p>困境:Docker 刚刚诞生时,并没有引起行业的广泛关注,dotCloud 面临着生存困难。然而,团队并没有放弃,他们决定将 Docker 开源。</p>
<p>崛起:2013年,Docker 开源。这一决定为 Docker 带来了巨大的转机。开源后,越来越多的人发现了 Docker 的优点,它逐渐在行业中火了起来。Docker 团队也开始每个月更新一个版本,以不断改进和增强这项技术。在 Docker 开源一年后,2014年4月9日,Docker 1.0 版本正式发布。这标志着 Docker 的技术达到了一个成熟的阶段,并准备好在生产环境中使用。</p>
<p>Docker的优点?</p>
<p>Docker 之所以如此受欢迎,主要原因在于其轻巧和高效。在容器技术出现之前,人们主要使用虚拟机技术。</p>
<p><strong>虚拟机技术</strong>:通过软件(如 VMware)在一个物理机器上虚拟出多台虚拟机。这种方法虽然实现了资源隔离和多环境共存,但虚拟机通常非常笨重,启动和运行都需要较高的资源开销。缺点:资源占用多、冗余步骤多、启动慢。</p>
<p><strong>容器技术</strong>:与虚拟机不同,Docker 容器更轻量级。它们共享主机的操作系统内核,而不是每个容器都有自己的操作系统。这使得 Docker 容器的启动速度极快,占用资源更少,管理更加方便。</p>
<p>Docker 从一个默默无闻的技术到如今的行业标准,经历了初期的困境和随后的迅速崛起。它的开源战略和轻量级、高效的特性,使其在短时间内得到了广泛的认可和应用。随着 Docker 的不断发展,它已经成为现代软件开发和部署过程中不可或缺的工具。</p>
<h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><ol>
<li><p>Dockerfile:dockerfile 就是用来构建 docker 镜像的构建文件。 命令脚本。</p>
</li>
<li><p>Image/镜像:docker镜像就好比一个模板,我们可以通过这个模板来创建容器服务。</p>
</li>
<li><p>Container/容器:可以把这个容器理解为就是一个简易的linux系统。</p>
</li>
<li><p>Volume/数据卷:Docker将运用与运行的环境打包形成容器运行, Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来, 那么当容器删除后,数据自然也就没有了。 为了能保存数据在Docker中我们使用卷。|</p>
<p>镜像(<code>Image</code>)和容器(<code>Container</code>)的关系,就像是面向对象程序设计中的 <code>类</code> 和 <code>实例</code> 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。</p>
</li>
</ol>
<h1 id="安装-Docker"><a href="#安装-Docker" class="headerlink" title="安装 Docker"></a>安装 Docker</h1><p>在开始使用 Docker 之前,你需要先安装它。以下是 Docker 在不同操作系统上的安装方法:</p>
<h2 id="在-Windows-上安装-Docker"><a href="#在-Windows-上安装-Docker" class="headerlink" title="在 Windows 上安装 Docker"></a>在 Windows 上安装 Docker</h2><ol>
<li>下载 Docker Desktop for Windows</li>
<li>双击下载的安装程序并按照提示完成安装</li>
<li>安装完成后,启动 Docker Desktop</li>
</ol>
<h2 id="在-macOS-上安装-Docker"><a href="#在-macOS-上安装-Docker" class="headerlink" title="在 macOS 上安装 Docker"></a>在 macOS 上安装 Docker</h2><ol>
<li>下载 Docker Desktop for Mac</li>
<li>双击下载的 DMG 文件并将 Docker 拖动到应用程序文件夹中</li>
<li>启动 Docker Desktop</li>
</ol>
<h2 id="在-Linux-上安装-Docker"><a href="#在-Linux-上安装-Docker" class="headerlink" title="在 Linux 上安装 Docker"></a>在 Linux 上安装 Docker</h2><p>对于大多数 Linux 发行版,可以使用以下命令安装 Docker:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">bash复制代码sudo apt-get update</span><br><span class="line">sudo apt-get install -y docker.io</span><br><span class="line">sudo systemctl start docker</span><br><span class="line">sudo systemctl enable docker</span><br></pre></td></tr></table></figure>
<h1 id="Dock-hub"><a href="#Dock-hub" class="headerlink" title="Dock hub"></a>Dock hub</h1><p>image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。</p>
<p>为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 <a href="https://hub.docker.com/">Docker Hub</a> 是最重要、最常用的 image 仓库。此外,出售自己制作的 image 文件也是可以的。</p>
]]></content>
<tags>
<tag>学习笔记</tag>
</tags>
</entry>
<entry>
<title>On comparing interval numbers 文章阅读笔记</title>
<url>/2024/07/10/On%20comparing%20interval%20numbers%20%E6%96%87%E7%AB%A0%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/</url>
<content><![CDATA[<h1 id="On-comparing-interval-numbers-文章阅读笔记"><a href="#On-comparing-interval-numbers-文章阅读笔记" class="headerlink" title="On comparing interval numbers 文章阅读笔记"></a>On comparing interval numbers 文章阅读笔记</h1><h3 id="一、文章概述"><a href="#一、文章概述" class="headerlink" title="一、文章概述"></a>一、文章概述</h3><p>这篇文章由Atanu Sengupta和Tapan Kumar Pal撰写,主要探讨了如何在实数线上比较和排序两个区间数。区间数作为实数的一种扩展,用于表示参数的不确定性或容忍范围。文章提出了两种比较区间数的方法:一种基于价值判断指数(乐观决策者的偏好),另一种定义了严格和模糊的偏好排序(悲观决策者的视角)。</p>
<h3 id="二、区间数的基本概念"><a href="#二、区间数的基本概念" class="headerlink" title="二、区间数的基本概念"></a>二、区间数的基本概念</h3><ol>
<li><p><strong>区间数的表示</strong>:</p>
<ul>
<li>区间数 $ A $ 可以表示为 $ A = [a_L, a_R] $,其中 $ a_L $ 和 $ a_R $ 分别是区间 $ A $ 的左极限和右极限。</li>
<li>中点 $ m(A) = \frac{a_L + a_R}{2} $ 和宽度 $ w(A) = \frac{a_R - a_L}{2} $。</li>
</ul>
</li>
<li><p><strong>区间数的运算</strong>:</p>
<ul>
<li>加法:$ A \oplus B = [a_L + b_L, a_R + b_R] $</li>
<li>减法:$ A \ominus B = [a_L - b_R, a_R - b_L] $</li>
</ul>
</li>
</ol>
<h3 id="三、现有方法的回顾与讨论"><a href="#三、现有方法的回顾与讨论" class="headerlink" title="三、现有方法的回顾与讨论"></a>三、现有方法的回顾与讨论</h3><ol>
<li><p><strong>Moore的方法</strong>:</p>
<ul>
<li>定义了两种传递性序关系,一种是实数线上“<”的扩展,另一种是集合包含关系的扩展。但这些方法无法处理重叠区间的排序。</li>
</ul>
</li>
<li><p><strong>Ishibuchi和Tanaka的方法</strong>:</p>
<ul>
<li>提出了两种序关系:$ \preceq_{LR} $ 和 $ \preceq_{mw} $。虽然这些方法定义了部分排序,但存在无法排序的区间对,且主要关注偏好排序而非价值排序。</li>
</ul>
</li>
<li><p><strong>Kundu的方法</strong>:</p>
<ul>
<li>基于模糊偏好关系定义了一个排序方法,但该方法在某些情况下与理性决策者的偏好不一致。</li>
</ul>
</li>
</ol>
<h3 id="四、本文主要工作"><a href="#四、本文主要工作" class="headerlink" title="四、本文主要工作"></a>四、本文主要工作</h3><ol>
<li><p><strong>价值判断指数(A-index)</strong>:(不是作者提出的方法)</p>
<ul>
<li><p>A-index是一个接受度函数,用于衡量一个区间数A在价值上是否劣于另一个区间数B。其公式为$ \mathcal{A} \ominus = \frac{m(B) - m(A)}{w(B) + w(A)}, $,其中m表示区间的中点,w表示区间的宽度。</p>
</li>
<li><p>如果A(A, B) > 0,则B在价值上优于A;如果0 < A(A, B) < 1,则表示部分接受;如果A(A, B) ≥ 1,则表示完全接受。</p>
</li>
<li><p>该方法既考虑了区间的中点也考虑了宽度,适用于多种决策场景,具有传递性和一致性。</p>
</li>
<li><p>这种方法的优点体现在<strong>example3.2.1、 example3.2.2</strong>等几个例子中。</p>
</li>
<li><p>对于这个指数的一个通俗理解: 一个区间的平均位置与另一个参考区间的平均位置相比,决定了前者优于后者还是劣于后者。</p>
</li>
<li><p>A-index可以应用于任意一对区间数的比较,而不像Ishibuchi和Tanaka的方法那样受限于$≤_{LR}\leq_{LR}≤LR$和≤mw\leq_{mw}≤mw条件的限制。</p>
</li>
<li><p>对于实数轴上的任意两个区间,Kundu提出的模糊左性关系在大多数情况下与A-index得出的结论相同,但存在一个例外情况:当两个区间的中点相同且宽度不同,Kundu的方法会得出A和B都是最优选择,这与直觉不符。</p>
<p>这一方法的缺点:相较之下,乐观的决策者更倾向于使用A-index,因为他们倾向于基于期望值和平均情况进行决策,这与A-index的设计初衷更加契合。因此,A-index更适合乐观决策者的使用,而无法完全满足悲观决策者的需求。</p>
</li>
</ul>
</li>
<li><p><strong>模糊偏好排序</strong>:(基于上述方法,加入本文的创新)</p>
<ul>
<li>从悲观决策者的角度出发,定义了模糊集 $ B^H $ 和 $ X^H $,分别表示对区间 $ B $ 和变量区间 $ X $ 的拒绝程度。</li>
<li>通过修改模糊集的成员函数,可以模拟不同程度悲观(或乐观)决策者的偏好模式。</li>
</ul>
</li>
</ol>
<h3 id="五、应用示例"><a href="#五、应用示例" class="headerlink" title="五、应用示例"></a>五、应用示例</h3><p>文章通过多个示例展示了如何应用这两种方法来比较和排序区间数。例如,在最大化利润的场景中,通过计算价值判断指数或模糊偏好程度,可以帮助决策者选择最优方案。</p>
<h3 id="六、如何应用这些方法"><a href="#六、如何应用这些方法" class="headerlink" title="六、如何应用这些方法"></a>六、如何应用这些方法</h3><ol>
<li><p><strong>理解基本概念</strong>:</p>
<ul>
<li>首先需要明确区间数的表示和运算规则。</li>
</ul>
</li>
<li><p><strong>选择适合的方法</strong>:</p>
<ul>
<li>根据决策者的偏好(乐观或悲观)和问题的具体需求,选择合适的方法进行比较和排序。</li>
</ul>
</li>
<li><p><strong>计算与解释</strong>:</p>
<ul>
<li>使用文章中的公式计算价值判断指数或模糊偏好程度。</li>
<li>解释结果,为决策者提供决策支持。</li>
</ul>
</li>
<li><p><strong>考虑实际应用场景</strong>:</p>
<ul>
<li>在实际应用中,可能需要根据具体的数据和需求调整参数和方法。</li>
</ul>
</li>
</ol>
<h3 id="七、结论"><a href="#七、结论" class="headerlink" title="七、结论"></a>七、结论</h3><p>这篇文章为比较和排序区间数提供了两种有效的方法:价值判断指数和模糊偏好排序。这两种方法各有特点,适用于不同的决策场景和决策者偏好。通过深入理解这些方法,你可以在处理含有不确定性或容忍范围的决策问题时更加得心应手。</p>
]]></content>
<tags>
<tag>论文阅读</tag>
</tags>
</entry>
<entry>
<title>Docker快速部署Graphhopper实现离线地图路径规划</title>
<url>/2024/07/11/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2Graphhopper%E5%AE%9E%E7%8E%B0%E7%A6%BB%E7%BA%BF%E5%9C%B0%E5%9B%BE%E8%B7%AF%E5%BE%84%E8%A7%84%E5%88%92%E5%8A%9F%E8%83%BD/</url>
<content><![CDATA[<p>前情提要:</p>
<p>去年的时候做了一个结合本地地图服务的CVRP项目。但是该服务需要配置本地环境,工作量极大,耗时很长。</p>
<p>今天带来的方法借助docker可以快速部署地图服务,节约90%的时间。</p>
<p>该方法需要借助Docker实现,所需需要提前安装好Docker。关于Docker的安装可以参考我的其他教程。</p>
<p>还需要提前下载好地图文件。可以去<a href="https://www.openstreetmap.org/%E4%B8%8B%E8%BD%BD%E3%80%82">https://www.openstreetmap.org/下载。</a></p>
<p>最终实现效果如下:</p>
<p><img src="/../images/TSP%E7%BB%93%E6%9E%9C%E5%B1%95%E7%A4%BA2.png"></p>
<p>#1. 通过Docker hub拉取镜像</p>
<p>打开命令行工具(例如,终端、命令提示符或PowerShell),然后运行以下命令来从Docker Hub拉取<code>israelhikingmap/graphhopper</code>镜像:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker pull israelhikingmap/graphhopper:latest</span><br></pre></td></tr></table></figure>
<h1 id="2-运行Docker"><a href="#2-运行Docker" class="headerlink" title="2. 运行Docker"></a>2. 运行Docker</h1><p>在下载好地图数据后可以进行该操作。例如,我的地图数据存储在”D:\open_street_map\china-latest.osm.pbf”</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">docker run -p 8989:8989 -v D:\/open_street_map:/graphhopper/mapdata israelhikingmap/graphhopper --input mapdata/china-latest.osm.pbf --host 0.0.0.0</span><br></pre></td></tr></table></figure>
<h1 id="3-内存溢出问题"><a href="#3-内存溢出问题" class="headerlink" title="3. 内存溢出问题"></a>3. 内存溢出问题</h1><p>因为地图数据很大,所以可能出现内存相关报错。这时可以多分配一些内存。加上-e JAVA_OPTS=”-Xmx4g -Xms4g”即可。</p>
<h1 id="使用本地地图服务"><a href="#使用本地地图服务" class="headerlink" title="使用本地地图服务"></a>使用本地地图服务</h1><p>经过上述步骤之后,本地服务即可成功运行。打开浏览器地址栏输入‘<a href="http://localhost:8989/maps/?profile=car)%E2%80%99%E5%90%8E%E5%8D%B3%E5%8F%AF%E4%BD%BF%E7%94%A8%E8%AF%A5%E6%9C%8D%E5%8A%A1%E3%80%82">http://localhost:8989/maps/?profile=car)’后即可使用该服务。</a></p>
<p>有了这样的一个本地服务之后,有哪些玩法呢?</p>
<h2 id="TSP项目"><a href="#TSP项目" class="headerlink" title="TSP项目"></a>TSP项目</h2><p>可以做一个本地的旅游路线规划求解器。通过这样一个函数即可获取两点之间的实际路径距离。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">lanlon_to_distance</span>(<span class="params">lat1,lon1,lat2,lon2</span>):</span><br><span class="line"> <span class="string">"""</span></span><br><span class="line"><span class="string"> 将经纬度传入本地服务器,根据路网数据,在本地进行路径规划,返回两点之间的路径距离以及时间</span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string"> Args:</span></span><br><span class="line"><span class="string"> lat1 (float): 地点1纬度</span></span><br><span class="line"><span class="string"> lon1 (float): 地点1经度</span></span><br><span class="line"><span class="string"> lat2 (float): 地点2纬度</span></span><br><span class="line"><span class="string"> lon2 (float): 地点2纬度</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> </span><br><span class="line"> url_head = <span class="string">'http://127.0.0.1:8989/route?point='</span></span><br><span class="line"> url_tail = <span class="string">'&profile=car&layer=OpenStreetMap'</span></span><br><span class="line"> url = url_head + <span class="built_in">str</span>(lat1) + <span class="string">','</span> + <span class="built_in">str</span>(lon1) + <span class="string">'&point='</span> + <span class="built_in">str</span>(lat2) + <span class="string">','</span> + <span class="built_in">str</span>(lon2) + url_tail</span><br><span class="line"> headers = {<span class="string">'Connection'</span>:<span class="string">'close'</span>}</span><br><span class="line"> response = requests.get(url,headers=headers)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> info = response.json()[<span class="string">'paths'</span>][<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> <span class="built_in">print</span>(response.json())</span><br><span class="line"> <span class="comment"># print(info) # 获取json</span></span><br><span class="line"> <span class="comment"># print(info['distance']) # 获取路径距离,单位为米</span></span><br><span class="line"> <span class="comment"># print(info['time']) # 获取路径时间,单位为毫秒</span></span><br><span class="line"> distance = info[<span class="string">'distance'</span>]/<span class="number">1000</span> <span class="comment"># 距离单位转为千米</span></span><br><span class="line"> <span class="keyword">return</span> distance</span><br></pre></td></tr></table></figure>
<p>有了路径距离之后,可以使用各种算法求解。</p>
<p>求解出最优路径之后,还可以通过该服务来展示路线。</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">generate_url</span>(<span class="params">route_lonlat</span>):</span><br><span class="line"> <span class="string">"""生成一条路径可视化的网页链接</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> Args:</span></span><br><span class="line"><span class="string"> route (_type_): 路径的经纬度坐标列表</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> Returns:</span></span><br><span class="line"><span class="string"> _type_: 网页链接,可视化展示每辆车的行驶路线</span></span><br><span class="line"><span class="string"> """</span></span><br><span class="line"> url = <span class="string">''</span></span><br><span class="line"> url_head = <span class="string">'http://127.0.0.1:8989/maps/?point='</span></span><br><span class="line"> url_tail = <span class="string">'&profile=car&layer=OpenStreetMap'</span></span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(route_lonlat) > <span class="number">2</span>:</span><br><span class="line"> url = url_head + <span class="built_in">str</span>(route_lonlat[<span class="number">0</span>][<span class="number">1</span>]) + <span class="string">','</span> + <span class="built_in">str</span>(route_lonlat[<span class="number">0</span>][<span class="number">0</span>])</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>,<span class="built_in">len</span>(route_lonlat)):</span><br><span class="line"> url = url + <span class="string">'&point='</span> + <span class="built_in">str</span>(route_lonlat[i][<span class="number">1</span>]) + <span class="string">','</span> + <span class="built_in">str</span>(route_lonlat[i][<span class="number">0</span>])</span><br><span class="line"> url += url_tail</span><br><span class="line"> <span class="keyword">return</span> url</span><br></pre></td></tr></table></figure>
<p>生成的链接点进去即可可视化展示路线。</p>
<p><img src="/../images/TSP%E7%BB%93%E6%9E%9C%E5%B1%95%E7%A4%BA-1720692249354.png"></p>
<h1 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h1><p><a href="https://john-start.github.io/2024/05/06/%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B2Graphhopper%E5%AE%9E%E7%8E%B0%E7%A6%BB%E7%BA%BF%E5%9C%B0%E5%9B%BE%E8%B7%AF%E5%BE%84%E8%A7%84%E5%88%92%E5%8A%9F%E8%83%BD%EF%BC%88%E5%B0%8F%E7%99%BD%E6%94%BE%E5%BF%83%E9%A3%9F%E7%94%A8%E7%89%88%EF%BC%89/">本地部署Graphhopper实现离线地图路径规划功能(小白放心食用版) | TUUG WORLD (john-start.github.io)</a></p>
<p><a href="https://blog.csdn.net/faithful1/article/details/132298190?spm=1001.2014.3001.5501">本地部署Graphhopper实现离线地图路径规划功能(小白放心食用版)_graphhopper 离线地图导航-CSDN博客</a></p>
]]></content>
<tags>
<tag>车辆路径规划</tag>
</tags>
</entry>
<entry>
<title>钢铁雄心4陆军装备与编制设计参考</title>
<url>/2024/07/12/%E9%92%A2%E9%93%81%E9%9B%84%E5%BF%834%E9%99%86%E5%86%9B%E6%AD%A6%E5%99%A8%E4%B8%8E%E7%BC%96%E5%88%B6%E8%AE%BE%E8%AE%A1/</url>
<content><![CDATA[<h1 id="陆军装备与编制设计参考"><a href="#陆军装备与编制设计参考" class="headerlink" title="陆军装备与编制设计参考"></a>陆军装备与编制设计参考</h1><h3 id="1-1-陆军装备设计"><a href="#1-1-陆军装备设计" class="headerlink" title="1.1 陆军装备设计"></a>1.1 陆军装备设计</h3><h4 id="1-1-1-中型主力坦克"><a href="#1-1-1-中型主力坦克" class="headerlink" title="1.1.1 中型主力坦克"></a>1.1.1 中型主力坦克</h4><ul>
<li>炮的类型取决于对人员或者装甲杀伤的需求,装甲设计商前期选择加数量的后期有条件就加质量,加几层装甲看产能和资源</li>
<li><img src="/../images/image-20240712110809613.png" alt="image-20240712110809613"></li>
<li>(中型主力坦克设计参考,图在备注上方)</li>
</ul>
<h4 id="1-1-2-中型喷火坦克"><a href="#1-1-2-中型喷火坦克" class="headerlink" title="1.1.2 中型喷火坦克"></a>1.1.2 中型喷火坦克</h4><ul>
<li>一般用于中型喷火坦克连。中型喷火坦克连为步兵及摩托化/机械化步兵(营级单位)提供一定的突破加成,且为师提供系列地形攻击加成。中型喷火坦克主要用于提供地形加成,可以牺牲数值以压低成本。</li>
<li><img src="/../images/image-20240712110829274.png" alt="image-20240712110829274"></li>
<li>(中型喷火坦克设计参考,图在备注上方)</li>
<li><img src="../images/image-20240712110840501.png" alt="image-20240712110840501" style="zoom:67%;" /></li>
<li>(中型喷火坦克支援连加成参考,图在备注上方)</li>
</ul>
<h4 id="1-1-3-轻型坦克"><a href="#1-1-3-轻型坦克" class="headerlink" title="1.1.3 轻型坦克"></a>1.1.3 轻型坦克</h4><ul>
<li>主要用于装甲支援连,装甲支援连为坦克及衍生装甲车辆(营级单位)提供对装甲杀伤加成,且为师提供系列地形移动加成。轻型坦克在用于装甲支援连时主要提供地形加成,可以牺牲数值以压低成本。</li>
<li><img src="/../images/image-20240712110858596.png" alt="image-20240712110858596"></li>
<li>(轻型坦克设计参考,图在备注上方)</li>
<li><img src="../images/image-20240712110909445.png" alt="image-20240712110909445" style="zoom:67%;" /></li>
<li>(装甲侦察连加成参考,图在备注上方)</li>
</ul>
<h3 id="1-2-陆军编制参考"><a href="#1-2-陆军编制参考" class="headerlink" title="1.2 陆军编制参考"></a>1.2 陆军编制参考</h3><ul>
<li>主力师战斗宽度达到 35 或 36 宽,HP300 左右,支援连通常带工兵连、后勤连、中型喷火坦克连、野战医院、装甲侦察连,对抗普通 AI 可用轻型装甲侦察连</li>
</ul>
<h4 id="1-2-1-有制空权陆军主力师"><a href="#1-2-1-有制空权陆军主力师" class="headerlink" title="1.2.1 有制空权陆军主力师"></a>1.2.1 有制空权陆军主力师</h4><ul>
<li><img src="/../images/image-20240712110930519.png" alt="image-20240712110930519"></li>
<li>优火 10 步兵 8 中坦克,图在备注上方</li>
<li><img src="/../images/image-20240712110940849.png" alt="image-20240712110940849"></li>
<li>美苏德高达师 9 坦 9 机或者 10 坦 8 机,图在备注上方</li>
<li><img src="/../images/image-20240712110953200.png" alt="image-20240712110953200"></li>
<li>人海左线 11 步 9 坦,图在备注上方</li>
<li><img src="/../images/image-20240712111001430.png" alt="image-20240712111001430"></li>
<li>人海左线 12 步 8 坦,图在备注上方</li>
</ul>
<h4 id="1-2-2-无制空权陆军主力师"><a href="#1-2-2-无制空权陆军主力师" class="headerlink" title="1.2.2 无制空权陆军主力师"></a>1.2.2 无制空权陆军主力师</h4><ul>
<li><img src="/../images/image-20240712111019958.png" alt="image-20240712111019958"></li>
<li>9 步 8 坦 2 防空,图在备注上方</li>
</ul>
<h4 id="1-2-3-小国主力师"><a href="#1-2-3-小国主力师" class="headerlink" title="1.2.3 小国主力师"></a>1.2.3 小国主力师</h4><ul>
<li>早战,工业能力不足,考虑人海左线,由步兵、常规炮兵、防空炮组成</li>
<li><img src="/../images/image-20240712111143501.png" alt="image-20240712111143501"></li>
<li>步、炮、防空,图在备注上方</li>
</ul>
<h4 id="1-2-4-天线宝宝(填线炮灰师)"><a href="#1-2-4-天线宝宝(填线炮灰师)" class="headerlink" title="1.2.4 天线宝宝(填线炮灰师)"></a>1.2.4 天线宝宝(填线炮灰师)</h4><ul>
<li>用于迟滞对方进攻,避免对方破坏我方战线,坚守至主力师抵达即可</li>
<li><img src="/../images/image-20240712111042165.png" alt="image-20240712111042165"></li>
<li>纯步兵师,图在备注上方</li>
</ul>
<h4 id="1-2-5-海军陆战部队(两栖部队)"><a href="#1-2-5-海军陆战部队(两栖部队)" class="headerlink" title="1.2.5 海军陆战部队(两栖部队)"></a>1.2.5 海军陆战部队(两栖部队)</h4><ul>
<li>用于跨河(或海峡)作战、登陆行动,由两栖特种部队、坦克组成(凑宽度可加常规步兵),坦克考虑常规坦克或者特种两栖坦克</li>
<li><img src="/../images/image-20240712111220099.png" alt="image-20240712111220099"></li>
<li>两栖师,图在备注上方</li>
<li><img src="/../images/image-20240712111233375.png" alt="image-20240712111233375"></li>
<li>两栖师,图在备注上方</li>
</ul>
<h4 id="1-2-6-山地部队(山地步兵线右左右)"><a href="#1-2-6-山地部队(山地步兵线右左右)" class="headerlink" title="1.2.6 山地部队(山地步兵线右左右)"></a>1.2.6 山地部队(山地步兵线右左右)</h4><ul>
<li>用于特殊地形(主要是山地、丘陵等)战斗,由山地步兵和坦克组成</li>
<li><img src="/../images/image-20240712111245346.png" alt="image-20240712111245346"></li>
<li>山地师,图在备注上方</li>
</ul>
]]></content>
<tags>
<tag>游戏</tag>
<tag>钢铁雄心IV</tag>
</tags>
</entry>
<entry>
<title>Logic-based Benders分解学习笔记(一)</title>
<url>/2024/10/28/Logic-based%20Benders%E5%88%86%E8%A7%A3%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</url>
<content><![CDATA[<p>[TOC]</p>
<h1 id="学习目标"><a href="#学习目标" class="headerlink" title="学习目标"></a>学习目标</h1><p>1.掌握Logic-based Benders分解的原理、学会如何应用</p>
<p>2.理解Logic-based Benders分解与Benders分解的区别</p>
<p>3.将Logic-based Benders分解应用到毕业论文的第五章</p>
<h1 id="理论介绍"><a href="#理论介绍" class="headerlink" title="理论介绍"></a>理论介绍</h1><p><strong>核心思想</strong>: 从错误中学习 (Learn from mistake)。</p>
<p><strong>Logic-based Benders分解与Benders分解的区别</strong>: 逻辑 Benders分解(Logic-based Benders decomposition)是一种基于经典 Benders 分解的扩展方法,通过逻辑推理代替传统的线性对偶来生成 Benders 切割,从而适用于更广泛的问题类型。这种方法的关键在于定义一种“推理对偶(inference duality)”而非线性对偶,通过逻辑推理在约束下生成最强的下界。这种方法不仅适用于线性优化,还可处理可满足性问题(satisfiability)、0-1 编程和机器调度问题等。</p>
<h2 id="推理对偶"><a href="#推理对偶" class="headerlink" title="推理对偶"></a>推理对偶</h2><p>推理对偶是逻辑benders分解的核心。为了学习推理对偶,需要引入语义蕴含(semantic implication)这个概念。</p>
<h3 id="语义蕴含"><a href="#语义蕴含" class="headerlink" title="语义蕴含"></a>语义蕴含</h3><p>这里还没太明白,下次再写</p>
<h2 id="logic-based-benders求解"><a href="#logic-based-benders求解" class="headerlink" title="logic-based benders求解"></a>logic-based benders求解</h2><p>针对参考文献中这篇文章的问题。</p>
<p>具体的benders cut可以设置为:$C_{\max} \geq C_{\max}^{hi’^*} - \sum_{j \in N_{i’}^h} (1 - x_{i’j}) \theta_{hi’j}$</p>
<p>为什么这么设置?因为其具有两大属性。</p>
<p>首先,这个cut必须从主问题的可行空间中移除当前的解;其次,这个cut不会将全局最优解从解空间中移除。</p>
<h2 id="并行机调度问题"><a href="#并行机调度问题" class="headerlink" title="并行机调度问题"></a>并行机调度问题</h2><p>2013年的state-of-the-art model</p>
<img src="../images/image-20241106161912566.png" alt="image-20241106161912566" style="zoom: 67%;" />
<p>为了适合LBBD的算法框架,我们建立的数学模型如下:</p>
<p><img src="/../images/image-20241106162000709.png" alt="image-20241106162000709"></p>
<p>先直接用求解器求解,不使用逻辑Benders分解</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">Description: 求解并行机调度问题</span></span><br><span class="line"><span class="string">Author: TUUG</span></span><br><span class="line"><span class="string">Date: 2024/11/04 16:48</span></span><br><span class="line"><span class="string">Version: V5.0</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> gurobipy <span class="keyword">as</span> gp</span><br><span class="line"><span class="keyword">from</span> gurobipy <span class="keyword">import</span> GRB</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"></span><br><span class="line">processing_time = pd.read_csv(<span class="string">'工件加工时间.csv'</span>,index_col=<span class="number">0</span>).T</span><br><span class="line">relation = pd.read_csv(<span class="string">'工件优先关系.csv'</span>,index_col=<span class="number">0</span>) <span class="comment"># 按列截取再转化就是前序加工集合,按行截取再转化就是后续加工集合</span></span><br><span class="line">set_up = pd.read_csv(<span class="string">'工件切换时间.csv'</span>,index_col=<span class="number">0</span>)</span><br><span class="line">jobs = [<span class="string">'job1'</span>,<span class="string">'job2'</span>,<span class="string">'job3'</span>,<span class="string">'job4'</span>,<span class="string">'job5'</span>]</span><br><span class="line">serus = [<span class="string">'seru1'</span>,<span class="string">'seru2'</span>,<span class="string">'seru3'</span>]</span><br><span class="line">num_serus = <span class="built_in">len</span>(serus)</span><br><span class="line">num_jobs = <span class="built_in">len</span>(jobs)</span><br><span class="line">batch_info = pd.read_csv(<span class="string">'批量大小.csv'</span>,index_col=<span class="number">0</span>)</span><br><span class="line">batch_info[<span class="string">'size'</span>] = np.random.normal(loc=batch_info[<span class="string">'mean'</span>],scale=batch_info[<span class="string">'std'</span>]).astype(<span class="built_in">int</span>)</span><br><span class="line">batch_size = batch_info[<span class="string">'size'</span>].to_list()</span><br><span class="line"></span><br><span class="line">relation = [(<span class="string">'job1'</span>,<span class="string">'job2'</span>)] <span class="comment"># 这里存储一些不能够先后加工的约束。</span></span><br><span class="line">dummy_job = [<span class="string">'job0'</span>] <span class="comment"># 表示两个虚拟工件</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_pre</span>(<span class="params">job</span>):</span><br><span class="line"> <span class="string">"""返回该工件最大的切换时间,benders cut需要用到"""</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">max</span>(set_up[job])</span><br><span class="line"></span><br><span class="line">max_pre_dict = <span class="built_in">dict</span>(<span class="built_in">zip</span>(jobs+dummy_job,[get_pre(job) <span class="keyword">for</span> job <span class="keyword">in</span> jobs+dummy_job]))</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_theta</span>(<span class="params">ind,job</span>):</span><br><span class="line"> <span class="string">"""返回theta值,benders cut需要用到"""</span></span><br><span class="line"> <span class="keyword">return</span> max_pre_dict[job]+processing_time.loc[ind,job]</span><br><span class="line"></span><br><span class="line">master_model = gp.Model(<span class="string">'master_problem'</span>)</span><br><span class="line">x = master_model.addVars(serus,jobs+dummy_job,vtype=GRB.BINARY,name=<span class="string">'x'</span>)</span><br><span class="line">y = master_model.addVars(serus,jobs+dummy_job,jobs+dummy_job,vtype=GRB.BINARY,name=<span class="string">'y'</span>)</span><br><span class="line">C_max = master_model.addVar(vtype=GRB.CONTINUOUS, name=<span class="string">"C_max"</span>)</span><br><span class="line">C = master_model.addVars(jobs+dummy_job,vtype=GRB.CONTINUOUS,name=<span class="string">'C'</span>)</span><br><span class="line">xi = master_model.addVars(serus,vtype=GRB.CONTINUOUS,name=<span class="string">'xi'</span>)</span><br><span class="line">master_model.setObjective(C_max, GRB.MINIMIZE)</span><br><span class="line">M = <span class="number">10086</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束22</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> master_model.addConstr(gp.quicksum(x[i,j]*processing_time.loc[i,j] <span class="keyword">for</span> j <span class="keyword">in</span> jobs)+xi[i] <= C_max)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束23</span></span><br><span class="line"><span class="keyword">for</span> j <span class="keyword">in</span> jobs:</span><br><span class="line"> master_model.addConstr(gp.quicksum(x[i,j] <span class="keyword">for</span> i <span class="keyword">in</span> serus) == <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束24</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> master_model.addConstr(x[i,<span class="string">'job0'</span>] == <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束25</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> master_model.addConstr(xi[i] == gp.quicksum(y[i,j,k]*set_up.loc[j,k] <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job <span class="keyword">for</span> k <span class="keyword">in</span> jobs+dummy_job))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束26</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> jobs+dummy_job:</span><br><span class="line"> master_model.addConstr(x[i,k] == gp.quicksum(y[i,j,k] <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束27</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job:</span><br><span class="line"> master_model.addConstr(x[i,j] == gp.quicksum(y[i,j,k] <span class="keyword">for</span> k <span class="keyword">in</span> jobs+dummy_job))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束28</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job:</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> jobs:</span><br><span class="line"> master_model.addConstr(C[k] -C[j] +M*(<span class="number">1</span>-y[i,j,k]) >= set_up.loc[j,k]+processing_time.loc[i,k])</span><br><span class="line"></span><br><span class="line"><span class="comment"># 约束29</span></span><br><span class="line">master_model.addConstr(C[<span class="string">'job0'</span>] == <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 先后关系约束</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> pair <span class="keyword">in</span> relation:</span><br><span class="line"> master_model.addConstr(y[i,pair[<span class="number">0</span>],pair[<span class="number">1</span>]] == <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">master_model.optimize()</span><br><span class="line">master_model.write(<span class="string">'right.lp'</span>)</span><br><span class="line"><span class="keyword">if</span> master_model.status == GRB.OPTIMAL:</span><br><span class="line"> assignment = np.array([[<span class="number">1</span> <span class="keyword">if</span> x[m, j].X > <span class="number">0.1</span> <span class="keyword">else</span> <span class="number">0</span> <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job] <span class="keyword">for</span> m <span class="keyword">in</span> serus])</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'----------'</span>,<span class="string">'x的取值情况'</span>,<span class="string">'--------------------'</span>)</span><br><span class="line"> <span class="keyword">for</span> row <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> col <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">if</span> x[row, col].X > <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(x[row, col])</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'----------'</span>,<span class="string">'y的取值情况'</span>,<span class="string">'----------'</span>)</span><br><span class="line"> <span class="keyword">for</span> row <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> col <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">if</span> y[row, col, k].X > <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(y[row,col,k])</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'----------'</span>,<span class="string">'C的取值情况'</span>,<span class="string">'--------------------'</span>)</span><br><span class="line"> <span class="keyword">for</span> col <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">if</span> C[col].X > <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(C[col])</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'最大完工时间为:'</span>,<span class="built_in">str</span>(C_max.X))</span><br></pre></td></tr></table></figure>
<p>求解结果如下:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Gurobi Optimizer version 10.0.3 build v10.0.3rc0 (win64)</span><br><span class="line"></span><br><span class="line">CPU model: AMD Ryzen 9 7945HX with Radeon Graphics, instruction set [SSE2|AVX|AVX2|AVX512]</span><br><span class="line">Thread count: 16 physical cores, 32 logical processors, using up to 32 threads</span><br><span class="line"></span><br><span class="line">Optimize a model with 144 rows, 136 columns and 613 nonzeros</span><br><span class="line">Model fingerprint: 0x5891c35e</span><br><span class="line">Variable types: 10 continuous, 126 integer (126 binary)</span><br><span class="line">Coefficient statistics:</span><br><span class="line"> Matrix range [1e+00, 1e+04]</span><br><span class="line"> Objective range [1e+00, 1e+00]</span><br><span class="line"> Bounds range [1e+00, 1e+00]</span><br><span class="line"> RHS range [1e+00, 1e+04]</span><br><span class="line">Presolve removed 32 rows and 30 columns</span><br><span class="line">Presolve time: 0.00s</span><br><span class="line">Presolved: 112 rows, 106 columns, 503 nonzeros</span><br><span class="line">Variable types: 5 continuous, 101 integer (100 binary)</span><br><span class="line">Found heuristic solution: objective 41.0000000</span><br><span class="line">Found heuristic solution: objective 35.0000000</span><br><span class="line">Found heuristic solution: objective 33.0000000</span><br><span class="line"></span><br><span class="line">Root relaxation: objective 1.378378e+01, 59 iterations, 0.00 seconds (0.00 work units)</span><br><span class="line"></span><br><span class="line"> Nodes | Current Node | Objective Bounds | Work</span><br><span class="line"> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time</span><br><span class="line"></span><br><span class="line"> 0 0 13.78378 0 25 33.00000 13.78378 58.2% - 0s</span><br><span class="line">H 0 0 25.0000000 13.78378 44.9% - 0s</span><br><span class="line">H 0 0 18.0000000 13.78378 23.4% - 0s</span><br><span class="line">H 0 0 17.0000000 14.20076 16.5% - 0s</span><br><span class="line"> 0 0 15.19231 0 30 17.00000 15.19231 10.6% - 0s</span><br><span class="line"> 0 0 15.19231 0 31 17.00000 15.19231 10.6% - 0s</span><br><span class="line"> 0 0 15.78689 0 25 17.00000 15.78689 7.14% - 0s</span><br><span class="line"></span><br><span class="line">Cutting planes:</span><br><span class="line"> Learned: 2</span><br><span class="line"> Gomory: 14</span><br><span class="line"> Cover: 1</span><br><span class="line"> Implied bound: 3</span><br><span class="line"> Clique: 6</span><br><span class="line"> MIR: 2</span><br><span class="line"> Zero half: 2</span><br><span class="line"> RLT: 4</span><br><span class="line"></span><br><span class="line">Explored 1 nodes (124 simplex iterations) in 0.03 seconds (0.01 work units)</span><br><span class="line">Thread count was 32 (of 32 available processors)</span><br><span class="line"></span><br><span class="line">Solution count 6: 17 18 25 ... 41</span><br><span class="line"></span><br><span class="line">Optimal solution found (tolerance 1.00e-04)</span><br><span class="line">Best objective 1.700000000000e+01, best bound 1.700000000000e+01, gap 0.0000%</span><br><span class="line">---------- x的取值情况 --------------------</span><br><span class="line"><gurobi.Var x[seru1,job3] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru2,job1] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru2,job5] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru3,job2] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru3,job4] (value 1.0)></span><br><span class="line">---------- y的取值情况 ----------</span><br><span class="line"><gurobi.Var y[seru2,job5,job1] (value 1.0)></span><br><span class="line"><gurobi.Var y[seru3,job4,job2] (value 1.0)></span><br><span class="line">---------- C的取值情况 --------------------</span><br><span class="line"><gurobi.Var C[job1] (value 14.0)></span><br><span class="line"><gurobi.Var C[job2] (value 17.0)></span><br><span class="line"><gurobi.Var C[job3] (value 16.0)></span><br><span class="line"><gurobi.Var C[job4] (value 8.0)></span><br><span class="line"><gurobi.Var C[job5] (value 10.0)></span><br><span class="line">最大完工时间为: 17.0</span><br></pre></td></tr></table></figure>
<p>采用逻辑benders分解后求解结果</p>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"><span class="string">Description: 复现Informs journal on computing上的论文。</span></span><br><span class="line"><span class="string">Author: TUUG</span></span><br><span class="line"><span class="string">Date: 2024/11/06 10:48</span></span><br><span class="line"><span class="string">Version: V6.0</span></span><br><span class="line"><span class="string">"""</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> gurobipy <span class="keyword">as</span> gp</span><br><span class="line"><span class="keyword">from</span> gurobipy <span class="keyword">import</span> GRB</span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</span><br><span class="line"><span class="keyword">import</span> pandas <span class="keyword">as</span> pd</span><br><span class="line"></span><br><span class="line">processing_time = pd.read_csv(<span class="string">'工件加工时间.csv'</span>,index_col=<span class="number">0</span>).T</span><br><span class="line">relation = pd.read_csv(<span class="string">'工件优先关系.csv'</span>,index_col=<span class="number">0</span>) <span class="comment"># 按列截取再转化就是前序加工集合,按行截取再转化就是后续加工集合</span></span><br><span class="line">set_up = pd.read_csv(<span class="string">'工件切换时间.csv'</span>,index_col=<span class="number">0</span>)</span><br><span class="line">jobs = [<span class="string">'job1'</span>,<span class="string">'job2'</span>,<span class="string">'job3'</span>,<span class="string">'job4'</span>,<span class="string">'job5'</span>]</span><br><span class="line">serus = [<span class="string">'seru1'</span>,<span class="string">'seru2'</span>,<span class="string">'seru3'</span>]</span><br><span class="line">num_serus = <span class="built_in">len</span>(serus)</span><br><span class="line">num_jobs = <span class="built_in">len</span>(jobs)</span><br><span class="line">batch_info = pd.read_csv(<span class="string">'批量大小.csv'</span>,index_col=<span class="number">0</span>)</span><br><span class="line">batch_info[<span class="string">'size'</span>] = np.random.normal(loc=batch_info[<span class="string">'mean'</span>],scale=batch_info[<span class="string">'std'</span>]).astype(<span class="built_in">int</span>)</span><br><span class="line">batch_size = batch_info[<span class="string">'size'</span>].to_list()</span><br><span class="line"></span><br><span class="line">relation = [(<span class="string">'job1'</span>,<span class="string">'job2'</span>)] <span class="comment"># 这里存储一些不能够先后加工的约束。</span></span><br><span class="line">dummy_job = [<span class="string">'job0'</span>] <span class="comment"># 表示两个虚拟工件</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_pre</span>(<span class="params">h,i,job,assign_jobs_list_record</span>):</span><br><span class="line"> ans_list = [set_up.loc[i,job] <span class="keyword">for</span> i <span class="keyword">in</span> assign_jobs_list_record[h][i]]</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">max</span>(ans_list)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_theta</span>(<span class="params">h,i,job,assign_jobs_list_record</span>):</span><br><span class="line"> <span class="keyword">return</span> get_pre(h,i,job,assign_jobs_list_record)+processing_time.loc[serus[i],job]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">create_master_model</span>(<span class="params">gen=<span class="literal">None</span>,C_max_current_record=<span class="literal">None</span>, assign_jobs_list_record=<span class="literal">None</span></span>):</span><br><span class="line"> master_model = gp.Model(<span class="string">'master problem'</span>)</span><br><span class="line"> x = master_model.addVars(serus,jobs+dummy_job,vtype=GRB.BINARY,name=<span class="string">'x'</span>)</span><br><span class="line"> C_max = master_model.addVar(vtype=GRB.CONTINUOUS, name=<span class="string">"C_max"</span>)</span><br><span class="line"> C = master_model.addVars(jobs+dummy_job,vtype=GRB.CONTINUOUS,name=<span class="string">'C'</span>)</span><br><span class="line"> xi = master_model.addVars(serus,vtype=GRB.CONTINUOUS,name=<span class="string">'xi'</span>)</span><br><span class="line"> master_model.setObjective(C_max, GRB.MINIMIZE)</span><br><span class="line"> master_model.setParam(<span class="string">'OutputFlag'</span>, <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 约束22</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> master_model.addConstr(gp.quicksum(x[i,j]*processing_time.loc[i,j] <span class="keyword">for</span> j <span class="keyword">in</span> jobs)+xi[i] <= C_max)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 约束23</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> jobs:</span><br><span class="line"> master_model.addConstr(gp.quicksum(x[i,j] <span class="keyword">for</span> i <span class="keyword">in</span> serus) == <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 约束24</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> serus:</span><br><span class="line"> master_model.addConstr(x[i,<span class="string">'job0'</span>] == <span class="number">1</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 约束29</span></span><br><span class="line"> master_model.addConstr(C[<span class="string">'job0'</span>] == <span class="number">0</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> gen:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'********'</span>,<span class="string">'增加了benders cut'</span>,<span class="string">'*********'</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> h <span class="keyword">in</span> <span class="built_in">range</span>(gen):</span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(serus)):</span><br><span class="line"> assign_jobs = assign_jobs_list_record[h][i]</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'job0'</span> <span class="keyword">in</span> assign_jobs:</span><br><span class="line"> assign_jobs.remove(<span class="string">'job0'</span>)</span><br><span class="line"> master_model.addConstr(C_max >= C_max_current_record[h][i] - gp.quicksum((<span class="number">1</span>-x[serus[i],j])*get_theta(h,i,j,assign_jobs_list_record) <span class="keyword">for</span> j <span class="keyword">in</span> assign_jobs),name=<span class="string">'cut'</span>)</span><br><span class="line"></span><br><span class="line"> master_model.optimize()</span><br><span class="line"> master_model.write(<span class="string">"master_model.lp"</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> master_model.status == GRB.OPTIMAL:</span><br><span class="line"> <span class="built_in">print</span>(master_model.objVal,<span class="string">'===主模型的解为====='</span>)</span><br><span class="line"> assignment = np.array([[<span class="number">1</span> <span class="keyword">if</span> x[m, j].X > <span class="number">0.1</span> <span class="keyword">else</span> <span class="number">0</span> <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job] <span class="keyword">for</span> m <span class="keyword">in</span> serus])</span><br><span class="line"> assignment = pd.DataFrame(assignment, columns=jobs+dummy_job, index=serus)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'----------'</span>,<span class="string">'x的取值情况'</span>,<span class="string">'--------------------'</span>)</span><br><span class="line"> <span class="keyword">for</span> row <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> col <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">if</span> x[row, col].X > <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(x[row, col])</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'----------'</span>,<span class="string">'C的取值情况'</span>,<span class="string">'--------------------'</span>)</span><br><span class="line"> <span class="keyword">for</span> col <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">if</span> C[col].X > <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(C[col])</span><br><span class="line"> <span class="keyword">return</span> assignment, master_model.objVal</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span>, <span class="literal">None</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_sub_job</span>(<span class="params">assignment,ind</span>):</span><br><span class="line"> row = assignment.loc[ind]</span><br><span class="line"> columns_with_1 = row[row == <span class="number">1</span>].index.tolist()</span><br><span class="line"> <span class="keyword">return</span> columns_with_1</span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">solve_subproblem</span>(<span class="params">ind,assignment</span>):</span><br><span class="line"> <span class="string">"""求解第ind个机器上的完工时间"""</span></span><br><span class="line"> i = ind</span><br><span class="line"> x = assignment</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'--------------求解第'</span> + <span class="built_in">str</span>(i) + <span class="string">'个机器上的完工时间--------------------'</span>)</span><br><span class="line"> <span class="comment"># assign_jobs = [i for i,j in enumerate(list(assignment.loc[ind])) if j==1] # 分配到这个seru的工件集合</span></span><br><span class="line"> assign_jobs = get_sub_job(assignment,ind)</span><br><span class="line"> sub_model = gp.Model(<span class="string">'sub_problem'</span>)</span><br><span class="line"> </span><br><span class="line"> C = sub_model.addVars(jobs+dummy_job,vtype=GRB.CONTINUOUS,name=<span class="string">'C'</span>)</span><br><span class="line"> y = sub_model.addVars(serus,jobs+dummy_job,jobs+dummy_job,vtype=GRB.BINARY,name=<span class="string">'y'</span>)</span><br><span class="line"> xi = sub_model.addVars(serus,vtype=GRB.CONTINUOUS,name=<span class="string">'xi'</span>) <span class="comment"># 该机器上的总切换时间</span></span><br><span class="line"> C_machine = sub_model.addVars(serus,vtype=GRB.CONTINUOUS,name=<span class="string">'C_machine'</span>) <span class="comment"># 该机器上的最大完工时间</span></span><br><span class="line"> sub_model.setObjective(C_machine[i],sense=GRB.MINIMIZE)</span><br><span class="line"> M = <span class="number">10086</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 自己的约束,子问题里添加的约束</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> jobs:</span><br><span class="line"> sub_model.addConstr(C_machine[i] >= C[j]*x.loc[i,j])</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 约束25</span></span><br><span class="line"> sub_model.addConstr(xi[i] == gp.quicksum(y[i,j,k]*set_up.loc[j,k] <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job <span class="keyword">for</span> k <span class="keyword">in</span> jobs+dummy_job))</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 约束26</span></span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> jobs+dummy_job:</span><br><span class="line"> sub_model.addConstr(gp.quicksum(y[i,j,k] <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job) == x.loc[i,k])</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 约束27</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job:</span><br><span class="line"> sub_model.addConstr(gp.quicksum(y[i,j,k] <span class="keyword">for</span> k <span class="keyword">in</span> jobs+dummy_job) == x.loc[i,j])</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 约束28</span></span><br><span class="line"> <span class="keyword">for</span> j <span class="keyword">in</span> jobs+dummy_job:</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> jobs:</span><br><span class="line"> sub_model.addConstr(C[k] -C[j] +M*(<span class="number">1</span>-y[i,j,k]) >= set_up.loc[j,k]+processing_time.loc[i,k])</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 自己的约束:不能违反的先后关系</span></span><br><span class="line"> <span class="keyword">for</span> pair <span class="keyword">in</span> relation:</span><br><span class="line"> sub_model.addConstr(y[i,pair[<span class="number">0</span>],pair[<span class="number">1</span>]] == <span class="number">0</span>)</span><br><span class="line"> </span><br><span class="line"> sub_model.setParam(<span class="string">'OutputFlag'</span>,<span class="number">0</span>)</span><br><span class="line"> </span><br><span class="line"> sub_model.optimize()</span><br><span class="line"> <span class="keyword">if</span> sub_model.status == GRB.OPTIMAL:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'----------'</span>,<span class="string">'y的取值情况'</span>,<span class="string">'----------'</span>)</span><br><span class="line"> <span class="keyword">for</span> row <span class="keyword">in</span> serus:</span><br><span class="line"> <span class="keyword">for</span> col <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">for</span> k <span class="keyword">in</span> jobs:</span><br><span class="line"> <span class="keyword">if</span> y[row, col, k].X > <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">print</span>(y[row,col,k])</span><br><span class="line"> result = np.array([[<span class="number">1</span> <span class="keyword">if</span> y[i,m,j].X > <span class="number">0</span> <span class="keyword">else</span> <span class="number">0</span> <span class="keyword">for</span> j <span class="keyword">in</span> jobs] <span class="keyword">for</span> m <span class="keyword">in</span> jobs])</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> result,sub_model.objVal,assign_jobs</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'未求得最优解'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">None</span>, <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line">assignment,obj = create_master_model()</span><br><span class="line">gen = <span class="number">1</span></span><br><span class="line">result_obj_list = [<span class="built_in">int</span>(obj*<span class="number">3</span>)]*num_serus <span class="comment"># 确保第一次循环能够进入</span></span><br><span class="line">C_max_list = [<span class="number">0</span>]*num_serus</span><br><span class="line">result_obj_list_record = []</span><br><span class="line">assign_jobs_list_record = []</span><br><span class="line">theta_record = []</span><br><span class="line">LB_record = []</span><br><span class="line">UB_record = []</span><br><span class="line">UB_min = result_obj_list[<span class="number">0</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="built_in">max</span>(result_obj_list)-obj >= <span class="number">1e-6</span>:</span><br><span class="line"> </span><br><span class="line"> LB_record.append(obj)</span><br><span class="line"> UB_record.append(<span class="built_in">max</span>(result_obj_list))</span><br><span class="line"></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'===============第'</span>+<span class="built_in">str</span>(gen)+<span class="string">'次循环====================='</span>)</span><br><span class="line"> result_list = [solve_subproblem(i,assignment=assignment) <span class="keyword">for</span> i <span class="keyword">in</span> serus]</span><br><span class="line"> result_assign_list = [i[<span class="number">0</span>] <span class="keyword">for</span> i <span class="keyword">in</span> result_list]</span><br><span class="line"> result_obj_list = [i[<span class="number">1</span>] <span class="keyword">for</span> i <span class="keyword">in</span> result_list]</span><br><span class="line"> assign_jobs_list = [i[<span class="number">2</span>] <span class="keyword">for</span> i <span class="keyword">in</span> result_list]</span><br><span class="line"> result_obj_list_record.append(result_obj_list)</span><br><span class="line"> assign_jobs_list_record.append(assign_jobs_list)</span><br><span class="line"></span><br><span class="line"> assignment,obj = create_master_model(gen=gen, C_max_current_record=result_obj_list_record,assign_jobs_list_record=assign_jobs_list_record)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'主问题的目标值'</span>,<span class="built_in">str</span>(obj))</span><br><span class="line"> gen += <span class="number">1</span></span><br><span class="line"> <span class="keyword">if</span> gen == <span class="number">100</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">'迭代次数超过100,退出循环'</span>)</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">'Logic-based benders求解结束'</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">'目标值为:'</span>,obj)</span><br><span class="line"></span><br><span class="line"><span class="comment"># %%</span></span><br><span class="line"><span class="keyword">from</span> matplotlib <span class="keyword">import</span> pyplot <span class="keyword">as</span> plt</span><br><span class="line"><span class="keyword">import</span> matplotlib.cm <span class="keyword">as</span> cm</span><br><span class="line"></span><br><span class="line">plt.rcParams[<span class="string">'font.sans-serif'</span>]=[<span class="string">'SimHei'</span>]</span><br><span class="line">plt.rcParams[<span class="string">'axes.unicode_minus'</span>]=<span class="literal">False</span></span><br><span class="line"></span><br><span class="line">UB_record.append(obj)</span><br><span class="line">LB_record.append(obj)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">update_to_historical_min</span>(<span class="params">UB_record</span>):</span><br><span class="line"> <span class="comment"># 初始化一个变量用于存储历史最小值</span></span><br><span class="line"> min_value = UB_record[<span class="number">0</span>]</span><br><span class="line"> <span class="comment"># 遍历数组并更新每个位置的值为历史最小值</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(UB_record)):</span><br><span class="line"> <span class="comment"># 更新当前位置的最小值</span></span><br><span class="line"> min_value = <span class="built_in">min</span>(min_value, UB_record[i])</span><br><span class="line"> <span class="comment"># 将当前位置的值改为历史最小值</span></span><br><span class="line"> UB_record[i] = min_value</span><br><span class="line"> <span class="keyword">return</span> UB_record</span><br><span class="line"><span class="comment"># UB_record = update_to_historical_min(UB_record)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建图表</span></span><br><span class="line">plt.figure(figsize=(<span class="number">10</span>, <span class="number">6</span>))</span><br><span class="line">colors = cm.viridis(np.linspace(<span class="number">0</span>, <span class="number">1</span>, <span class="number">7</span>))</span><br><span class="line">plt.plot(UB_record, label=<span class="string">"子问题"</span>, color=<span class="string">'purple'</span>,alpha=<span class="number">0.5</span>, marker=<span class="string">'s'</span>,linestyle=<span class="string">'--'</span>, linewidth=<span class="number">2</span>)</span><br><span class="line">plt.plot(LB_record, label=<span class="string">"主问题"</span>, color=<span class="string">'cornflowerblue'</span>,alpha=<span class="number">0.8</span>, marker=<span class="string">'x'</span>,linestyle=<span class="string">'-.'</span>, linewidth=<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加标题和标签</span></span><br><span class="line"><span class="comment"># plt.title("逻辑benders分解迭代过程中主问题与子问题解的变化情况")</span></span><br><span class="line">plt.xlabel(<span class="string">"迭代次数"</span>)</span><br><span class="line">plt.ylabel(<span class="string">"最大完工时间"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示图例和网格</span></span><br><span class="line">plt.legend()</span><br><span class="line">plt.grid(<span class="literal">True</span>,alpha=<span class="number">0.5</span>,linestyle=<span class="string">'--'</span>,color=<span class="string">'gray'</span>)</span><br><span class="line"><span class="comment"># 显示图表</span></span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">===============第17次循环=====================</span><br><span class="line">--------------求解第seru1个机器上的完工时间--------------------</span><br><span class="line">---------- y的取值情况 ----------</span><br><span class="line">--------------求解第seru2个机器上的完工时间--------------------</span><br><span class="line">---------- y的取值情况 ----------</span><br><span class="line"><gurobi.Var y[seru2,job5,job1] (value 1.0)></span><br><span class="line">--------------求解第seru3个机器上的完工时间--------------------</span><br><span class="line">---------- y的取值情况 ----------</span><br><span class="line"><gurobi.Var y[seru3,job4,job2] (value 1.0)></span><br><span class="line">******** 增加了benders cut *********</span><br><span class="line">17.0 ===主模型的解为=====</span><br><span class="line">---------- x的取值情况 --------------------</span><br><span class="line"><gurobi.Var x[seru1,job3] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru2,job1] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru2,job5] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru3,job2] (value 1.0)></span><br><span class="line"><gurobi.Var x[seru3,job4] (value 1.0)></span><br><span class="line">---------- C的取值情况 --------------------</span><br><span class="line">主问题的目标值 17.0</span><br><span class="line">Logic-based benders求解结束</span><br><span class="line">目标值为: 17.0</span><br></pre></td></tr></table></figure>
<p>求解过程图如下</p>
<p><img src="/../images/image-20241106152925359.png" alt="image-20241106152925359"></p>
<h1 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h1><p>Tran T T, Araujo A, Beck J C. Decomposition methods for the parallel machine scheduling problem with setups[J]. INFORMS Journal on Computing, 2016, 28(1): 83-95.</p>
]]></content>
<tags>
<tag>学习笔记</tag>
</tags>
</entry>
</search>