it works?

This commit is contained in:
Ross
2020-05-14 23:40:48 +01:00
parent 0ac1990cfd
commit 12f7b5270c
13 changed files with 1657 additions and 289 deletions
+15
View File
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Test",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/test.py",
"console": "integratedTerminal"
}
]
}
+1
View File
@@ -0,0 +1 @@
,ross,maverick.fritz.box,14.05.2020 23:29,file:///home/ross/.config/libreoffice/4;
+140
View File
@@ -0,0 +1,140 @@
Solver command line: ['/usr/bin/cbc', '-seconds', '3200', '-allow', '2200', '-printingOptions', 'all', '-import', '/tmp/tmpgzf8zbpg.pyomo.lp', '-stat=1', '-solve', '-solu', '/tmp/tmpgzf8zbpg.pyomo.soln']
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 7 2019
command line - /usr/bin/cbc -seconds 3200 -allow 2200 -printingOptions all -import /tmp/tmpgzf8zbpg.pyomo.lp -stat=1 -solve -solu /tmp/tmpgzf8zbpg.pyomo.soln (default strategy 1)
seconds was changed from 1e+100 to 3200
allowableGap was changed from 1e-10 to 2200
Option for printingOptions changed from normal to all
Presolve 63617 (-74184) rows, 25986 (-83735) columns and 256502 (-851515) elements
Statistics for presolved model
Original problem has 109096 integers (108160 of which binary)
Presolved problem has 25896 integers (25688 of which binary)
==== 21788 zero objective 4 different
21788 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
2638 variables have objective of 1000
==== absolute objective values 4 different
21788 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
2638 variables have objective of 1000
==== for integers 21788 zero objective 4 different
21788 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
2548 variables have objective of 1000
==== for integers absolute objective values 4 different
21788 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
2548 variables have objective of 1000
===== end objective counts
Problem has 63617 rows, 25986 columns (4198 with objective) and 256502 elements
There are 1650 singletons with objective
Column breakdown:
298 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf,
0 of type lo->up, 0 of type free, 0 of type fixed,
0 of type -inf->0.0, 0 of type -inf->up, 25688 of type 0.0->1.0
Row breakdown:
2704 of type E 0.0, 676 of type E 1.0, 0 of type E -1.0,
279 of type E other, 0 of type G 0.0, 0 of type G 1.0,
418 of type G other, 5408 of type L 0.0, 49868 of type L 1.0,
1560 of type L other, 0 of type Range 0.0->1.0, 2704 of type Range other,
0 of type Free
Continuous objective value is 178488 - 30.16 seconds
Cgl0002I 75712 variables fixed
Cgl0003I 0 fixed, 208 tightened bounds, 37490 strengthened rows, 47518 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1438 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 5 strengthened rows, 0 substitutions
Cgl0004I processed model has 24041 rows, 16522 columns (16432 integer (16224 of which binary)) and 124218 elements
Cbc0038I Initial state - 1405 integers unsatisfied sum - 471.24
Cbc0038I Pass 1: (45.34 seconds) suminf. 304.35185 (762) obj. 223295 iterations 6320
Cbc0038I Pass 2: (45.54 seconds) suminf. 259.90250 (677) obj. 229665 iterations 1456
Cbc0038I Pass 3: (45.71 seconds) suminf. 237.42785 (612) obj. 231568 iterations 757
Cbc0038I Pass 4: (45.76 seconds) suminf. 234.36193 (605) obj. 231838 iterations 256
Cbc0038I Pass 5: (45.80 seconds) suminf. 233.19893 (597) obj. 232546 iterations 202
Cbc0038I Pass 6: (45.83 seconds) suminf. 232.04656 (590) obj. 233310 iterations 71
Cbc0038I Pass 7: (45.86 seconds) suminf. 231.54656 (589) obj. 233360 iterations 8
Cbc0038I Pass 8: (45.89 seconds) suminf. 231.31610 (590) obj. 233360 iterations 40
Cbc0038I Pass 9: (45.92 seconds) suminf. 229.14180 (587) obj. 233352 iterations 22
Cbc0038I Pass 10: (45.94 seconds) suminf. 229.14180 (587) obj. 233352 iterations 1
Cbc0038I Pass 11: (45.98 seconds) suminf. 219.44422 (557) obj. 231301 iterations 113
Cbc0038I Pass 12: (46.02 seconds) suminf. 212.43029 (535) obj. 229437 iterations 116
Cbc0038I Pass 13: (46.03 seconds) suminf. 212.43029 (535) obj. 229437 iterations 0
Cbc0038I Pass 14: (46.06 seconds) suminf. 208.43029 (527) obj. 229837 iterations 31
Cbc0038I Pass 15: (46.08 seconds) suminf. 208.43029 (527) obj. 229837 iterations 1
Cbc0038I Pass 16: (46.11 seconds) suminf. 204.43029 (519) obj. 230237 iterations 18
Cbc0038I Pass 17: (46.14 seconds) suminf. 204.43029 (519) obj. 230237 iterations 3
Cbc0038I Pass 18: (46.17 seconds) suminf. 196.93029 (504) obj. 230987 iterations 35
Cbc0038I Pass 19: (46.19 seconds) suminf. 196.93029 (504) obj. 230987 iterations 2
Cbc0038I Pass 20: (46.22 seconds) suminf. 189.43029 (489) obj. 231737 iterations 25
Cbc0038I Pass 21: (46.25 seconds) suminf. 189.43029 (489) obj. 231737 iterations 6
Cbc0038I Pass 22: (46.27 seconds) suminf. 184.43029 (479) obj. 232237 iterations 25
Cbc0038I Pass 23: (46.30 seconds) suminf. 184.43029 (479) obj. 232237 iterations 4
Cbc0038I Pass 24: (46.33 seconds) suminf. 178.43029 (467) obj. 232837 iterations 25
Cbc0038I Pass 25: (46.36 seconds) suminf. 178.43029 (467) obj. 232837 iterations 3
Cbc0038I Pass 26: (46.38 seconds) suminf. 175.93029 (462) obj. 233087 iterations 16
Cbc0038I Pass 27: (46.41 seconds) suminf. 175.93029 (462) obj. 233087 iterations 5
Cbc0038I Pass 28: (46.44 seconds) suminf. 174.93029 (460) obj. 233187 iterations 7
Cbc0038I Pass 29: (46.46 seconds) suminf. 174.93029 (460) obj. 233187 iterations 1
Cbc0038I Pass 30: (46.49 seconds) suminf. 173.43029 (457) obj. 233337 iterations 6
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 14611 integers at bound fixed and 43 continuous
Cbc0038I Mini branch and bound did not improve solution (46.52 seconds)
Cbc0038I After 46.52 seconds - Feasibility pump exiting - took 3.36 seconds
Cbc0031I 552 added rows had average density of 29.197464
Cbc0013I At root node, 552 cuts changed objective from 188237.94 to 222332.75 in 10 passes
Cbc0014I Cut generator 0 (Probing) - 3440 row cuts average 3.4 elements, 0 column cuts (0 active) in 3.913 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 2373 row cuts average 245.7 elements, 0 column cuts (0 active) in 7.187 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 1879 row cuts average 2.3 elements, 0 column cuts (0 active) in 0.268 seconds - new frequency is 1
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.095 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 1177 row cuts average 13.5 elements, 0 column cuts (0 active) in 0.242 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.039 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 3221 row cuts average 43.5 elements, 0 column cuts (0 active) in 4.283 seconds - new frequency is 1
Cbc0010I After 0 nodes, 1 on tree, 1e+50 best solution, best possible 222332.75 (95.56 seconds)
Cbc0010I After 100 nodes, 58 on tree, 1e+50 best solution, best possible 222332.75 (140.65 seconds)
Cbc0010I After 200 nodes, 109 on tree, 1e+50 best solution, best possible 222332.75 (153.72 seconds)
Cbc0010I After 300 nodes, 159 on tree, 1e+50 best solution, best possible 222332.75 (166.84 seconds)
Cbc0010I After 400 nodes, 211 on tree, 1e+50 best solution, best possible 222332.75 (180.19 seconds)
Cbc0010I After 500 nodes, 260 on tree, 1e+50 best solution, best possible 222332.75 (194.37 seconds)
Cbc0010I After 600 nodes, 312 on tree, 1e+50 best solution, best possible 222332.75 (208.13 seconds)
Cbc0010I After 700 nodes, 363 on tree, 1e+50 best solution, best possible 222332.75 (223.59 seconds)
Cbc0010I After 800 nodes, 412 on tree, 1e+50 best solution, best possible 222332.75 (239.21 seconds)
Cbc0012I Integer solution of 225548.92 found by rounding after 83817 iterations and 877 nodes (249.96 seconds)
Cbc0038I Full problem 24041 rows 16522 columns, reduced to 0 rows 0 columns
Cbc0038I Full problem 24041 rows 16522 columns, reduced to 716 rows 543 columns
Cbc0012I Integer solution of 224493.06 found by RINS after 85051 iterations and 900 nodes (257.47 seconds)
Cbc0010I After 900 nodes, 38 on tree, 224493.06 best solution, best possible 222332.75 (257.55 seconds)
Cbc0011I Exiting as integer gap of 2160.3118 less than 2200 or 0%%
Cbc0001I Search completed - best objective 224493.0622792392, took 85147 iterations and 901 nodes (257.69 seconds)
Cbc0032I Strong branching done 3076 times (85272 iterations), fathomed 0 nodes and fixed 0 variables
Cbc0035I Maximum depth 178, 1114 variables fixed on reduced cost
Cuts at root node changed objective from 188238 to 222333
Probing was tried 920 times and created 13923 cuts of which 0 were active after adding rounds of cuts (10.780 seconds)
Gomory was tried 920 times and created 4524 cuts of which 0 were active after adding rounds of cuts (24.789 seconds)
Knapsack was tried 920 times and created 9817 cuts of which 0 were active after adding rounds of cuts (12.716 seconds)
Clique was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.095 seconds)
MixedIntegerRounding2 was tried 920 times and created 5513 cuts of which 0 were active after adding rounds of cuts (16.556 seconds)
FlowCover was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.039 seconds)
TwoMirCuts was tried 920 times and created 9162 cuts of which 0 were active after adding rounds of cuts (11.763 seconds)
ImplicationCuts was tried 20 times and created 2198 cuts of which 0 were active after adding rounds of cuts (0.049 seconds)
Result - Optimal solution found (within gap tolerance)
Objective value: 224493.06227924
Lower bound: 222332.750
Gap: 0.01
Enumerated nodes: 901
Total iterations: 85147
Time (CPU seconds): 258.90
Time (Wallclock seconds): 259.64
Total time (CPU seconds): 261.09 (Wallclock seconds): 262.01
+133
View File
@@ -0,0 +1,133 @@
Solver command line: ['/usr/bin/cbc', '-seconds', '3200', '-allow', '2200', '-printingOptions', 'all', '-import', '/tmp/tmpm0xkmuez.pyomo.lp', '-stat=1', '-solve', '-solu', '/tmp/tmpm0xkmuez.pyomo.soln']
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 7 2019
command line - /usr/bin/cbc -seconds 3200 -allow 2200 -printingOptions all -import /tmp/tmpm0xkmuez.pyomo.lp -stat=1 -solve -solu /tmp/tmpm0xkmuez.pyomo.soln (default strategy 1)
seconds was changed from 1e+100 to 3200
allowableGap was changed from 1e-10 to 2200
Option for printingOptions changed from normal to all
Presolve 19601 (-110296) rows, 15178 (-12903) columns and 97892 (-209117) elements
Statistics for presolved model
Original problem has 27872 integers (27040 of which binary)
Presolved problem has 15088 integers (14872 of which binary)
==== 13606 zero objective 3 different
13606 variables have objective of 0
208 variables have objective of 20
1364 variables have objective of 1000
==== absolute objective values 3 different
13606 variables have objective of 0
208 variables have objective of 20
1364 variables have objective of 1000
==== for integers 13606 zero objective 3 different
13606 variables have objective of 0
208 variables have objective of 20
1274 variables have objective of 1000
==== for integers absolute objective values 3 different
13606 variables have objective of 0
208 variables have objective of 20
1274 variables have objective of 1000
===== end objective counts
Problem has 19601 rows, 15178 columns (1572 with objective) and 97892 elements
There are 298 singletons with objective
Column breakdown:
306 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf,
0 of type lo->up, 0 of type free, 0 of type fixed,
0 of type -inf->0.0, 0 of type -inf->up, 14872 of type 0.0->1.0
Row breakdown:
2712 of type E 0.0, 0 of type E 1.0, 0 of type E -1.0,
227 of type E other, 0 of type G 0.0, 0 of type G 1.0,
334 of type G other, 4056 of type L 0.0, 10816 of type L 1.0,
1456 of type L other, 0 of type Range 0.0->1.0, 0 of type Range other,
0 of type Free
Continuous objective value is 307977 - 1.79 seconds
Cgl0002I 9464 variables fixed
Cgl0003I 0 fixed, 208 tightened bounds, 12068 strengthened rows, 72112 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 3874 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 2414 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 913 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 472 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 426 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 419 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 416 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 394 strengthened rows, 0 substitutions
Cgl0004I processed model has 3557 rows, 3002 columns (2912 integer (2704 of which binary)) and 27294 elements
Cbc0038I Initial state - 203 integers unsatisfied sum - 48.1942
Cbc0038I Pass 1: (4.31 seconds) suminf. 25.79319 (98) obj. 308847 iterations 1030
Cbc0038I Pass 2: (4.31 seconds) suminf. 20.95041 (81) obj. 308850 iterations 75
Cbc0038I Pass 3: (4.32 seconds) suminf. 19.51710 (76) obj. 308846 iterations 18
Cbc0038I Pass 4: (4.32 seconds) suminf. 16.38158 (66) obj. 309105 iterations 146
Cbc0038I Pass 5: (4.33 seconds) suminf. 15.78139 (64) obj. 309104 iterations 56
Cbc0038I Pass 6: (4.34 seconds) suminf. 17.82947 (66) obj. 309861 iterations 149
Cbc0038I Pass 7: (4.34 seconds) suminf. 16.87253 (64) obj. 309853 iterations 56
Cbc0038I Pass 8: (4.35 seconds) suminf. 16.34740 (64) obj. 309851 iterations 17
Cbc0038I Pass 9: (4.36 seconds) suminf. 17.31553 (66) obj. 311385 iterations 128
Cbc0038I Pass 10: (4.36 seconds) suminf. 16.18974 (65) obj. 311381 iterations 52
Cbc0038I Pass 11: (4.37 seconds) suminf. 16.66807 (65) obj. 309850 iterations 85
Cbc0038I Pass 12: (4.37 seconds) suminf. 16.39342 (65) obj. 309855 iterations 36
Cbc0038I Pass 13: (4.38 seconds) suminf. 19.03518 (68) obj. 311416 iterations 132
Cbc0038I Pass 14: (4.39 seconds) suminf. 15.97431 (63) obj. 311425 iterations 75
Cbc0038I Pass 15: (4.39 seconds) suminf. 15.48765 (62) obj. 311431 iterations 18
Cbc0038I Pass 16: (4.40 seconds) suminf. 17.17728 (68) obj. 309925 iterations 172
Cbc0038I Pass 17: (4.41 seconds) suminf. 15.30830 (62) obj. 309922 iterations 83
Cbc0038I Pass 18: (4.42 seconds) suminf. 19.16642 (70) obj. 309215 iterations 152
Cbc0038I Pass 19: (4.42 seconds) suminf. 17.03452 (65) obj. 309214 iterations 68
Cbc0038I Pass 20: (4.43 seconds) suminf. 15.92705 (65) obj. 309214 iterations 29
Cbc0038I Pass 21: (4.43 seconds) suminf. 14.93939 (66) obj. 309217 iterations 15
Cbc0038I Pass 22: (4.44 seconds) suminf. 17.10473 (66) obj. 309204 iterations 185
Cbc0038I Pass 23: (4.45 seconds) suminf. 16.32949 (63) obj. 309208 iterations 28
Cbc0038I Pass 24: (4.46 seconds) suminf. 14.92720 (62) obj. 309202 iterations 70
Cbc0038I Pass 25: (4.46 seconds) suminf. 14.92720 (62) obj. 309202 iterations 12
Cbc0038I Pass 26: (4.47 seconds) suminf. 16.38608 (65) obj. 309206 iterations 77
Cbc0038I Pass 27: (4.47 seconds) suminf. 15.38263 (62) obj. 309211 iterations 26
Cbc0038I Pass 28: (4.48 seconds) suminf. 15.54781 (63) obj. 309199 iterations 61
Cbc0038I Pass 29: (4.51 seconds) suminf. 42.72391 (154) obj. 344500 iterations 566
Cbc0038I Pass 30: (4.52 seconds) suminf. 25.91427 (90) obj. 331553 iterations 359
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 2368 integers at bound fixed and 42 continuous
Cbc0038I Full problem 3557 rows 3002 columns, reduced to 819 rows 561 columns
Cbc0038I Mini branch and bound did not improve solution (5.26 seconds)
Cbc0038I After 5.26 seconds - Feasibility pump exiting - took 1.06 seconds
Cbc0031I 66 added rows had average density of 160.28788
Cbc0013I At root node, 66 cuts changed objective from 307976.81 to 308016.81 in 10 passes
Cbc0014I Cut generator 0 (Probing) - 274 row cuts average 19.0 elements, 0 column cuts (0 active) in 0.293 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 144 row cuts average 720.2 elements, 0 column cuts (0 active) in 0.649 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 35 row cuts average 8.6 elements, 0 column cuts (0 active) in 0.023 seconds - new frequency is 1
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.005 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 81 row cuts average 42.5 elements, 0 column cuts (0 active) in 0.060 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.008 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 148 row cuts average 62.1 elements, 0 column cuts (0 active) in 0.153 seconds - new frequency is -100
Cbc0010I After 0 nodes, 1 on tree, 1e+50 best solution, best possible 308016.81 (7.77 seconds)
Cbc0012I Integer solution of 308036.81 found by DiveCoefficient after 2997 iterations and 2 nodes (8.23 seconds)
Cbc0038I Full problem 3557 rows 3002 columns, reduced to 89 rows 63 columns
Cbc0004I Integer solution of 308016.81 found after 3022 iterations and 3 nodes (8.83 seconds)
Cbc0011I Exiting as integer gap of -5.8207661e-11 less than 2200 or 0%%
Cbc0001I Search completed - best objective 308016.8141544065, took 3022 iterations and 3 nodes (8.83 seconds)
Cbc0032I Strong branching done 66 times (4711 iterations), fathomed 0 nodes and fixed 0 variables
Cbc0035I Maximum depth 2, 364 variables fixed on reduced cost
Cuts at root node changed objective from 307977 to 308017
Probing was tried 16 times and created 281 cuts of which 0 were active after adding rounds of cuts (0.305 seconds)
Gomory was tried 16 times and created 145 cuts of which 0 were active after adding rounds of cuts (0.669 seconds)
Knapsack was tried 16 times and created 35 cuts of which 0 were active after adding rounds of cuts (0.034 seconds)
Clique was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.005 seconds)
MixedIntegerRounding2 was tried 16 times and created 87 cuts of which 0 were active after adding rounds of cuts (0.089 seconds)
FlowCover was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.008 seconds)
TwoMirCuts was tried 10 times and created 148 cuts of which 0 were active after adding rounds of cuts (0.153 seconds)
ImplicationCuts was tried 6 times and created 2 cuts of which 0 were active after adding rounds of cuts (0.001 seconds)
Result - Optimal solution found (within gap tolerance)
Objective value: 308016.81415441
Lower bound: 308016.814
Gap: 0.00
Enumerated nodes: 3
Total iterations: 3022
Time (CPU seconds): 9.17
Time (Wallclock seconds): 9.37
Total time (CPU seconds): 9.97 (Wallclock seconds): 10.23
@@ -0,0 +1,121 @@
Solver command line: ['/usr/bin/cbc', '-seconds', '3200', '-allow', '2200', '-printingOptions', 'all', '-import', '/tmp/tmpvgmu8xky.pyomo.lp', '-stat=1', '-solve', '-solu', '/tmp/tmpvgmu8xky.pyomo.soln']
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 7 2019
command line - /usr/bin/cbc -seconds 3200 -allow 2200 -printingOptions all -import /tmp/tmpvgmu8xky.pyomo.lp -stat=1 -solve -solu /tmp/tmpvgmu8xky.pyomo.soln (default strategy 1)
seconds was changed from 1e+100 to 3200
allowableGap was changed from 1e-10 to 2200
Option for printingOptions changed from normal to all
Presolve 61633 (-68602) rows, 24642 (-12955) columns and 252462 (-219179) elements
Statistics for presolved model
Original problem has 37336 integers (36504 of which binary)
Presolved problem has 24552 integers (24336 of which binary)
==== 21796 zero objective 3 different
21796 variables have objective of 0
208 variables have objective of 20
2638 variables have objective of 1000
==== absolute objective values 3 different
21796 variables have objective of 0
208 variables have objective of 20
2638 variables have objective of 1000
==== for integers 21796 zero objective 3 different
21796 variables have objective of 0
208 variables have objective of 20
2548 variables have objective of 1000
==== for integers absolute objective values 3 different
21796 variables have objective of 0
208 variables have objective of 20
2548 variables have objective of 1000
===== end objective counts
Problem has 61633 rows, 24642 columns (2846 with objective) and 252462 elements
There are 298 singletons with objective
Column breakdown:
306 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf,
0 of type lo->up, 0 of type free, 0 of type fixed,
0 of type -inf->0.0, 0 of type -inf->up, 24336 of type 0.0->1.0
Row breakdown:
2712 of type E 0.0, 0 of type E 1.0, 0 of type E -1.0,
409 of type E other, 0 of type G 0.0, 0 of type G 1.0,
376 of type G other, 4056 of type L 0.0, 49868 of type L 1.0,
1508 of type L other, 0 of type Range 0.0->1.0, 2704 of type Range other,
0 of type Free
Continuous objective value is 235275 - 18.65 seconds
Cgl0002I 9464 variables fixed
Cgl0003I 0 fixed, 208 tightened bounds, 37440 strengthened rows, 48132 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 830 strengthened rows, 0 substitutions
Cgl0004I processed model has 22157 rows, 15170 columns (15080 integer (14872 of which binary)) and 119840 elements
Cbc0038I Initial state - 627 integers unsatisfied sum - 209.255
Cbc0038I Pass 1: (27.97 seconds) suminf. 106.07246 (326) obj. 252225 iterations 3662
Cbc0038I Pass 2: (28.07 seconds) suminf. 95.72743 (291) obj. 251499 iterations 716
Cbc0038I Pass 3: (28.09 seconds) suminf. 93.33763 (280) obj. 251505 iterations 57
Cbc0038I Pass 4: (28.12 seconds) suminf. 92.83763 (279) obj. 251505 iterations 6
Cbc0038I Pass 5: (28.14 seconds) suminf. 92.83763 (279) obj. 251505 iterations 7
Cbc0038I Pass 6: (28.35 seconds) suminf. 88.07561 (260) obj. 271289 iterations 1630
Cbc0038I Pass 7: (28.57 seconds) suminf. 54.65876 (187) obj. 266649 iterations 1549
Cbc0038I Pass 8: (28.60 seconds) suminf. 51.21935 (179) obj. 267604 iterations 132
Cbc0038I Pass 9: (28.62 seconds) suminf. 51.21935 (179) obj. 267604 iterations 5
Cbc0038I Pass 10: (28.66 seconds) suminf. 45.87751 (162) obj. 267375 iterations 232
Cbc0038I Pass 11: (28.69 seconds) suminf. 41.50434 (150) obj. 267395 iterations 268
Cbc0038I Pass 12: (28.72 seconds) suminf. 38.95309 (137) obj. 267389 iterations 46
Cbc0038I Pass 13: (28.74 seconds) suminf. 37.01190 (134) obj. 267389 iterations 54
Cbc0038I Pass 14: (28.79 seconds) suminf. 32.20802 (125) obj. 267386 iterations 470
Cbc0038I Pass 15: (28.84 seconds) suminf. 31.56175 (131) obj. 267386 iterations 344
Cbc0038I Pass 16: (28.86 seconds) suminf. 31.56175 (131) obj. 267386 iterations 28
Cbc0038I Pass 17: (28.92 seconds) suminf. 29.43450 (121) obj. 268378 iterations 460
Cbc0038I Pass 18: (28.95 seconds) suminf. 29.26964 (118) obj. 268294 iterations 102
Cbc0038I Pass 19: (29.01 seconds) suminf. 29.44524 (120) obj. 268264 iterations 492
Cbc0038I Pass 20: (29.03 seconds) suminf. 29.44678 (122) obj. 268264 iterations 83
Cbc0038I Pass 21: (29.06 seconds) suminf. 29.36685 (125) obj. 267950 iterations 156
Cbc0038I Pass 22: (29.09 seconds) suminf. 29.34914 (124) obj. 267950 iterations 71
Cbc0038I Pass 23: (29.14 seconds) suminf. 29.92259 (124) obj. 267721 iterations 406
Cbc0038I Pass 24: (29.17 seconds) suminf. 29.77899 (123) obj. 267720 iterations 60
Cbc0038I Pass 25: (29.19 seconds) suminf. 29.77899 (123) obj. 267720 iterations 15
Cbc0038I Pass 26: (29.21 seconds) suminf. 29.77899 (123) obj. 267720 iterations 3
Cbc0038I Pass 27: (29.23 seconds) suminf. 29.77899 (123) obj. 267720 iterations 6
Cbc0038I Pass 28: (29.37 seconds) suminf. 42.90902 (137) obj. 287514 iterations 1303
Cbc0038I Pass 29: (29.51 seconds) suminf. 31.28342 (118) obj. 286853 iterations 1012
Cbc0038I Pass 30: (29.55 seconds) suminf. 30.17992 (120) obj. 287303 iterations 229
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 13786 integers at bound fixed and 43 continuous
Cbc0038I Mini branch and bound did not improve solution (29.58 seconds)
Cbc0038I After 29.58 seconds - Feasibility pump exiting - took 2.51 seconds
Cbc0031I 264 added rows had average density of 41.094697
Cbc0013I At root node, 264 cuts changed objective from 235274.72 to 247993.63 in 10 passes
Cbc0014I Cut generator 0 (Probing) - 729 row cuts average 6.8 elements, 0 column cuts (135 active) in 2.312 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 911 row cuts average 479.7 elements, 0 column cuts (0 active) in 2.646 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 231 row cuts average 2.6 elements, 0 column cuts (0 active) in 0.145 seconds - new frequency is 1
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.034 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 186 row cuts average 57.1 elements, 0 column cuts (0 active) in 0.196 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.033 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 758 row cuts average 87.3 elements, 0 column cuts (0 active) in 1.797 seconds - new frequency is 1
Cbc0010I After 0 nodes, 1 on tree, 1e+50 best solution, best possible 247993.63 (51.80 seconds)
Cbc0012I Integer solution of 247993.63 found by rounding after 23120 iterations and 84 nodes (90.51 seconds)
Cbc0038I Full problem 22157 rows 15170 columns, reduced to 0 rows 0 columns
Cbc0001I Search completed - best objective 247993.6283088135, took 23120 iterations and 84 nodes (91.04 seconds)
Cbc0032I Strong branching done 1752 times (40035 iterations), fathomed 0 nodes and fixed 0 variables
Cbc0035I Maximum depth 50, 0 variables fixed on reduced cost
Cuts at root node changed objective from 235275 to 247994
Probing was tried 36 times and created 874 cuts of which 135 were active after adding rounds of cuts (2.553 seconds)
Gomory was tried 36 times and created 923 cuts of which 0 were active after adding rounds of cuts (3.186 seconds)
Knapsack was tried 36 times and created 280 cuts of which 0 were active after adding rounds of cuts (0.413 seconds)
Clique was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.034 seconds)
MixedIntegerRounding2 was tried 36 times and created 245 cuts of which 0 were active after adding rounds of cuts (0.652 seconds)
FlowCover was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.033 seconds)
TwoMirCuts was tried 36 times and created 821 cuts of which 0 were active after adding rounds of cuts (2.415 seconds)
ImplicationCuts was tried 16 times and created 90 cuts of which 0 were active after adding rounds of cuts (0.022 seconds)
Result - Optimal solution found
Objective value: 247993.62830881
Enumerated nodes: 84
Total iterations: 23120
Time (CPU seconds): 91.58
Time (Wallclock seconds): 91.98
Total time (CPU seconds): 92.49 (Wallclock seconds): 92.98
+167
View File
@@ -0,0 +1,167 @@
Solver command line: ['/usr/bin/cbc', '-seconds', '3200', '-allow', '2200', '-printingOptions', 'all', '-import', '/tmp/tmp5_964_on.pyomo.lp', '-stat=1', '-solve', '-solu', '/tmp/tmp5_964_on.pyomo.soln']
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 7 2019
command line - /usr/bin/cbc -seconds 3200 -allow 2200 -printingOptions all -import /tmp/tmp5_964_on.pyomo.lp -stat=1 -solve -solu /tmp/tmp5_964_on.pyomo.soln (default strategy 1)
seconds was changed from 1e+100 to 3200
allowableGap was changed from 1e-10 to 2200
Option for printingOptions changed from normal to all
Presolve 9073 (-28732) rows, 13610 (-73595) columns and 64596 (-446201) elements
Statistics for presolved model
Original problem has 86684 integers (86528 of which binary)
Presolved problem has 13520 integers (13520 of which binary)
==== 10894 zero objective 3 different
10894 variables have objective of 0
1352 variables have objective of 100
1364 variables have objective of 1000
==== absolute objective values 3 different
10894 variables have objective of 0
1352 variables have objective of 100
1364 variables have objective of 1000
==== for integers 10894 zero objective 3 different
10894 variables have objective of 0
1352 variables have objective of 100
1274 variables have objective of 1000
==== for integers absolute objective values 3 different
10894 variables have objective of 0
1352 variables have objective of 100
1274 variables have objective of 1000
===== end objective counts
Problem has 9073 rows, 13610 columns (2716 with objective) and 64596 elements
There are 1442 singletons with objective
Column breakdown:
90 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf,
0 of type lo->up, 0 of type free, 0 of type fixed,
0 of type -inf->0.0, 0 of type -inf->up, 13520 of type 0.0->1.0
Row breakdown:
0 of type E 0.0, 676 of type E 1.0, 0 of type E -1.0,
97 of type E other, 0 of type G 0.0, 0 of type G 1.0,
84 of type G other, 5408 of type L 0.0, 1352 of type L 1.0,
1456 of type L other, 0 of type Range 0.0->1.0, 0 of type Range other,
0 of type Free
Continuous objective value is 5579.29 - 0.25 seconds
Cgl0002I 66248 variables fixed
Cgl0003I 52 fixed, 0 tightened bounds, 4004 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 196 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1533 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1527 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1527 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1524 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1522 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1520 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1520 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1410 strengthened rows, 0 substitutions
Cgl0004I processed model has 8929 rows, 13558 columns (13468 integer (13468 of which binary)) and 72963 elements
Cbc0038I Initial state - 757 integers unsatisfied sum - 322.142
Cbc0038I Pass 1: (2.10 seconds) suminf. 231.92695 (505) obj. 30728.2 iterations 1751
Cbc0038I Pass 2: (2.12 seconds) suminf. 206.58889 (444) obj. 31931.6 iterations 194
Cbc0038I Pass 3: (2.14 seconds) suminf. 196.54920 (421) obj. 32116 iterations 204
Cbc0038I Pass 4: (2.16 seconds) suminf. 196.54920 (421) obj. 32116 iterations 37
Cbc0038I Pass 5: (2.18 seconds) suminf. 195.04920 (418) obj. 32166 iterations 17
Cbc0038I Pass 6: (2.20 seconds) suminf. 195.04920 (418) obj. 32166 iterations 24
Cbc0038I Pass 7: (2.22 seconds) suminf. 195.04920 (418) obj. 32166 iterations 18
Cbc0038I Pass 8: (2.25 seconds) suminf. 72.58889 (171) obj. 37485.9 iterations 561
Cbc0038I Pass 9: (2.27 seconds) suminf. 70.08889 (166) obj. 37485.9 iterations 32
Cbc0038I Pass 10: (2.29 seconds) suminf. 69.08889 (164) obj. 37485.9 iterations 6
Cbc0038I Pass 11: (2.31 seconds) suminf. 69.08889 (164) obj. 37485.9 iterations 4
Cbc0038I Pass 12: (2.35 seconds) suminf. 32.58141 (84) obj. 60503.3 iterations 914
Cbc0038I Pass 13: (2.39 seconds) suminf. 27.88537 (75) obj. 61927.9 iterations 484
Cbc0038I Pass 14: (2.41 seconds) suminf. 27.50124 (75) obj. 62180.1 iterations 58
Cbc0038I Pass 15: (2.43 seconds) suminf. 27.00124 (74) obj. 62180.1 iterations 1
Cbc0038I Pass 16: (2.45 seconds) suminf. 16.00124 (52) obj. 62980.1 iterations 32
Cbc0038I Pass 17: (2.47 seconds) suminf. 7.10271 (34) obj. 62816.5 iterations 296
Cbc0038I Pass 18: (2.49 seconds) suminf. 6.79422 (33) obj. 62168.7 iterations 55
Cbc0038I Pass 19: (2.53 seconds) suminf. 3.14487 (17) obj. 64662.8 iterations 509
Cbc0038I Pass 20: (2.55 seconds) suminf. 3.14487 (17) obj. 64662.8 iterations 192
Cbc0038I Pass 21: (2.59 seconds) suminf. 1.23209 (8) obj. 65540 iterations 475
Cbc0038I Pass 22: (2.61 seconds) suminf. 1.23209 (8) obj. 65540 iterations 82
Cbc0038I Pass 23: (2.63 seconds) suminf. 0.79917 (6) obj. 66277.4 iterations 327
Cbc0038I Pass 24: (2.66 seconds) suminf. 1.01893 (6) obj. 65540 iterations 189
Cbc0038I Pass 25: (2.69 seconds) suminf. 14.01747 (45) obj. 83423 iterations 774
Cbc0038I Pass 26: (2.73 seconds) suminf. 10.55675 (34) obj. 83054.5 iterations 517
Cbc0038I Pass 27: (2.75 seconds) suminf. 9.55675 (32) obj. 83054.5 iterations 5
Cbc0038I Pass 28: (2.77 seconds) suminf. 9.55675 (32) obj. 83054.5 iterations 6
Cbc0038I Pass 29: (2.79 seconds) suminf. 2.31454 (11) obj. 81144.3 iterations 317
Cbc0038I Pass 30: (2.81 seconds) suminf. 2.27485 (10) obj. 81546.8 iterations 84
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 12405 integers at bound fixed and 20 continuous
Cbc0038I Full problem 8929 rows 13558 columns, reduced to 355 rows 402 columns
Cbc0038I Mini branch and bound improved solution from 1.79769e+308 to 44152.7 (3.07 seconds)
Cbc0038I Freeing continuous variables gives a solution of 44152.7
Cbc0038I Round again with cutoff of 41270.3
Cbc0038I Pass 30: (3.10 seconds) suminf. 231.92695 (505) obj. 30728.2 iterations 0
Cbc0038I Pass 31: (3.13 seconds) suminf. 186.69839 (405) obj. 34976.8 iterations 320
Cbc0038I Pass 32: (3.15 seconds) suminf. 175.89364 (383) obj. 35626.8 iterations 89
Cbc0038I Pass 33: (3.17 seconds) suminf. 174.39364 (380) obj. 35676.8 iterations 10
Cbc0038I Pass 34: (3.18 seconds) suminf. 174.39364 (380) obj. 35676.8 iterations 3
Cbc0038I Pass 35: (3.20 seconds) suminf. 165.39364 (362) obj. 36526.8 iterations 35
Cbc0038I Pass 36: (3.22 seconds) suminf. 152.89364 (337) obj. 37726.8 iterations 41
Cbc0038I Pass 37: (3.24 seconds) suminf. 137.89364 (307) obj. 39126.8 iterations 44
Cbc0038I Pass 38: (3.27 seconds) suminf. 132.89364 (297) obj. 39626.8 iterations 15
Cbc0038I Pass 39: (3.29 seconds) suminf. 117.39364 (266) obj. 40976.8 iterations 44
Cbc0038I Pass 40: (3.33 seconds) suminf. 106.89364 (251) obj. 41270.3 iterations 184
Cbc0038I Pass 41: (3.36 seconds) suminf. 99.39364 (236) obj. 41270.3 iterations 71
Cbc0038I Pass 42: (3.40 seconds) suminf. 93.04601 (226) obj. 41270.3 iterations 176
Cbc0038I Pass 43: (3.43 seconds) suminf. 92.89364 (223) obj. 41270.3 iterations 135
Cbc0038I Pass 44: (3.46 seconds) suminf. 92.39364 (222) obj. 41270.3 iterations 3
Cbc0038I Pass 45: (3.49 seconds) suminf. 83.89364 (208) obj. 41270.3 iterations 74
Cbc0038I Pass 46: (3.51 seconds) suminf. 70.89364 (182) obj. 41270.3 iterations 44
Cbc0038I Pass 47: (3.53 seconds) suminf. 63.89364 (168) obj. 41270.3 iterations 26
Cbc0038I Pass 48: (3.55 seconds) suminf. 63.89364 (168) obj. 41270.3 iterations 4
Cbc0038I Pass 49: (3.58 seconds) suminf. 57.89364 (156) obj. 41270.3 iterations 28
Cbc0038I Pass 50: (3.60 seconds) suminf. 57.89364 (156) obj. 41270.3 iterations 2
Cbc0038I Pass 51: (3.62 seconds) suminf. 45.39364 (131) obj. 41270.3 iterations 33
Cbc0038I Pass 52: (3.64 seconds) suminf. 32.89364 (106) obj. 41270.3 iterations 42
Cbc0038I Pass 53: (3.66 seconds) suminf. 25.39364 (91) obj. 41270.3 iterations 34
Cbc0038I Pass 54: (3.68 seconds) suminf. 14.89364 (70) obj. 41270.3 iterations 35
Cbc0038I Pass 55: (3.73 seconds) suminf. 9.96998 (47) obj. 41270.3 iterations 460
Cbc0038I Pass 56: (3.77 seconds) suminf. 8.19475 (45) obj. 41270.3 iterations 185
Cbc0038I Pass 57: (3.84 seconds) suminf. 6.00263 (32) obj. 41270.3 iterations 797
Cbc0038I Pass 58: (3.87 seconds) suminf. 5.48991 (33) obj. 41270.3 iterations 238
Cbc0038I Pass 59: (3.93 seconds) suminf. 4.62934 (19) obj. 40801.3 iterations 623
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 12628 integers at bound fixed and 39 continuous
Cbc0038I Mini branch and bound did not improve solution (3.98 seconds)
Cbc0038I After 3.98 seconds - Feasibility pump exiting with objective of 44152.7 - took 1.99 seconds
Cbc0012I Integer solution of 44152.66 found by feasibility pump after 0 iterations and 0 nodes (3.99 seconds)
Cbc0038I Full problem 8929 rows 13558 columns, reduced to 228 rows 243 columns
Cbc0012I Integer solution of 40453.232 found by RINS after 0 iterations and 0 nodes (4.21 seconds)
Cbc0012I Integer solution of 29020.952 found by DiveCoefficient after 8819 iterations and 0 nodes (11.10 seconds)
Cbc0031I 340 added rows had average density of 48.729412
Cbc0013I At root node, 340 cuts changed objective from 15329.289 to 27320.952 in 10 passes
Cbc0014I Cut generator 0 (Probing) - 2358 row cuts average 2.0 elements, 0 column cuts (0 active) in 1.816 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 2006 row cuts average 335.9 elements, 0 column cuts (0 active) in 1.068 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 1313 row cuts average 2.1 elements, 0 column cuts (0 active) in 0.138 seconds - new frequency is 1
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.011 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 1050 row cuts average 17.3 elements, 0 column cuts (0 active) in 0.129 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.029 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 2500 row cuts average 26.5 elements, 0 column cuts (0 active) in 1.001 seconds - new frequency is 1
Cbc0011I Exiting as integer gap of 1700 less than 2200 or 0%%
Cbc0001I Search completed - best objective 29020.95202118316, took 8819 iterations and 0 nodes (11.12 seconds)
Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost
Cuts at root node changed objective from 15329.3 to 27321
Probing was tried 10 times and created 2358 cuts of which 0 were active after adding rounds of cuts (1.816 seconds)
Gomory was tried 10 times and created 2006 cuts of which 0 were active after adding rounds of cuts (1.068 seconds)
Knapsack was tried 10 times and created 1313 cuts of which 0 were active after adding rounds of cuts (0.138 seconds)
Clique was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.011 seconds)
MixedIntegerRounding2 was tried 10 times and created 1050 cuts of which 0 were active after adding rounds of cuts (0.129 seconds)
FlowCover was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.029 seconds)
TwoMirCuts was tried 10 times and created 2500 cuts of which 0 were active after adding rounds of cuts (1.001 seconds)
Result - Optimal solution found (within gap tolerance)
Objective value: 29020.95202118
Lower bound: 27320.952
Gap: 0.06
Enumerated nodes: 0
Total iterations: 8819
Time (CPU seconds): 11.49
Time (Wallclock seconds): 11.67
Total time (CPU seconds): 12.70 (Wallclock seconds): 12.97
+149
View File
@@ -0,0 +1,149 @@
Solver command line: ['/usr/bin/cbc', '-seconds', '3200', '-allow', '2200', '-printingOptions', 'all', '-import', '/tmp/tmpkl4fr1k_.pyomo.lp', '-stat=1', '-solve', '-solu', '/tmp/tmpkl4fr1k_.pyomo.soln']
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 7 2019
command line - /usr/bin/cbc -seconds 3200 -allow 2200 -printingOptions all -import /tmp/tmpkl4fr1k_.pyomo.lp -stat=1 -solve -solu /tmp/tmpkl4fr1k_.pyomo.soln (default strategy 1)
seconds was changed from 1e+100 to 3200
allowableGap was changed from 1e-10 to 2200
Option for printingOptions changed from normal to all
Presolve 37323 (-99282) rows, 19234 (-52423) columns and 162892 (-464645) elements
Statistics for presolved model
Original problem has 71240 integers (70304 of which binary)
Presolved problem has 19144 integers (18928 of which binary)
==== 15946 zero objective 4 different
15946 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
1728 variables have objective of 1000
==== absolute objective values 4 different
15946 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
1728 variables have objective of 1000
==== for integers 15946 zero objective 4 different
15946 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
1638 variables have objective of 1000
==== for integers absolute objective values 4 different
15946 variables have objective of 0
208 variables have objective of 20
1352 variables have objective of 100
1638 variables have objective of 1000
===== end objective counts
Problem has 37323 rows, 19234 columns (3288 with objective) and 162892 elements
There are 1650 singletons with objective
Column breakdown:
306 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf,
0 of type lo->up, 0 of type free, 0 of type fixed,
0 of type -inf->0.0, 0 of type -inf->up, 18928 of type 0.0->1.0
Row breakdown:
2712 of type E 0.0, 156 of type E 1.0, 0 of type E -1.0,
279 of type E other, 0 of type G 0.0, 0 of type G 1.0,
376 of type G other, 5408 of type L 0.0, 24180 of type L 1.0,
1508 of type L other, 0 of type Range 0.0->1.0, 2704 of type Range other,
0 of type Free
Continuous objective value is 243935 - 12.03 seconds
Cgl0002I 44616 variables fixed
Cgl0003I 0 fixed, 208 tightened bounds, 22826 strengthened rows, 47235 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 3826 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 2221 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1079 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 490 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 255 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 229 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 214 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 197 strengthened rows, 0 substitutions
Cgl0004I processed model has 16387 rows, 9762 columns (9672 integer (9464 of which binary)) and 80599 elements
Cbc0038I Initial state - 1275 integers unsatisfied sum - 411.736
Cbc0038I Pass 1: (22.09 seconds) suminf. 275.36033 (699) obj. 275508 iterations 6394
Cbc0038I Pass 2: (22.31 seconds) suminf. 251.50450 (630) obj. 278893 iterations 1211
Cbc0038I Pass 3: (22.42 seconds) suminf. 237.26278 (596) obj. 280250 iterations 470
Cbc0038I Pass 4: (22.50 seconds) suminf. 231.25228 (584) obj. 281559 iterations 306
Cbc0038I Pass 5: (22.56 seconds) suminf. 228.30447 (580) obj. 283466 iterations 239
Cbc0038I Pass 6: (22.60 seconds) suminf. 224.54385 (568) obj. 283611 iterations 52
Cbc0038I Pass 7: (22.64 seconds) suminf. 220.41141 (557) obj. 281841 iterations 75
Cbc0038I Pass 8: (22.67 seconds) suminf. 219.91141 (556) obj. 281891 iterations 18
Cbc0038I Pass 9: (22.70 seconds) suminf. 216.62887 (548) obj. 278935 iterations 28
Cbc0038I Pass 10: (22.74 seconds) suminf. 216.62887 (548) obj. 278935 iterations 11
Cbc0038I Pass 11: (22.77 seconds) suminf. 216.62887 (548) obj. 278935 iterations 1
Cbc0038I Pass 12: (22.96 seconds) suminf. 104.93793 (325) obj. 277541 iterations 1105
Cbc0038I Pass 13: (23.22 seconds) suminf. 89.97792 (266) obj. 277060 iterations 1082
Cbc0038I Pass 14: (23.40 seconds) suminf. 87.18147 (261) obj. 276745 iterations 761
Cbc0038I Pass 15: (23.44 seconds) suminf. 83.46793 (252) obj. 276810 iterations 30
Cbc0038I Pass 16: (23.47 seconds) suminf. 82.96793 (251) obj. 276860 iterations 19
Cbc0038I Pass 17: (23.54 seconds) suminf. 78.18433 (247) obj. 277277 iterations 204
Cbc0038I Pass 18: (23.58 seconds) suminf. 77.57806 (243) obj. 277327 iterations 100
Cbc0038I Pass 19: (23.62 seconds) suminf. 67.34112 (222) obj. 278330 iterations 84
Cbc0038I Pass 20: (23.68 seconds) suminf. 65.92745 (219) obj. 278478 iterations 148
Cbc0038I Pass 21: (23.72 seconds) suminf. 65.98731 (206) obj. 278632 iterations 50
Cbc0038I Pass 22: (23.75 seconds) suminf. 65.48731 (205) obj. 278632 iterations 2
Cbc0038I Pass 23: (23.79 seconds) suminf. 50.98731 (175) obj. 279728 iterations 96
Cbc0038I Pass 24: (23.82 seconds) suminf. 50.98731 (175) obj. 279728 iterations 1
Cbc0038I Pass 25: (23.86 seconds) suminf. 38.98731 (148) obj. 279915 iterations 83
Cbc0038I Pass 26: (24.08 seconds) suminf. 35.45286 (143) obj. 281045 iterations 828
Cbc0038I Pass 27: (24.14 seconds) suminf. 35.45286 (145) obj. 281045 iterations 136
Cbc0038I Pass 28: (24.22 seconds) suminf. 33.71076 (144) obj. 281155 iterations 337
Cbc0038I Pass 29: (24.26 seconds) suminf. 33.71076 (144) obj. 281155 iterations 47
Cbc0038I Pass 30: (24.45 seconds) suminf. 33.05241 (137) obj. 281075 iterations 685
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 7967 integers at bound fixed and 43 continuous
Cbc0038I Mini branch and bound did not improve solution (24.48 seconds)
Cbc0038I After 24.48 seconds - Feasibility pump exiting - took 4.32 seconds
Cbc0031I 631 added rows had average density of 14.393027
Cbc0013I At root node, 631 cuts changed objective from 253685.18 to 271905.7 in 10 passes
Cbc0014I Cut generator 0 (Probing) - 3898 row cuts average 3.2 elements, 0 column cuts (245 active) in 1.358 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 2171 row cuts average 144.4 elements, 0 column cuts (0 active) in 3.571 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 2247 row cuts average 2.3 elements, 0 column cuts (0 active) in 0.210 seconds - new frequency is 1
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.071 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 1162 row cuts average 6.3 elements, 0 column cuts (0 active) in 0.142 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.022 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 3316 row cuts average 32.5 elements, 0 column cuts (0 active) in 2.821 seconds - new frequency is 1
Cbc0010I After 0 nodes, 1 on tree, 1e+50 best solution, best possible 271905.7 (55.94 seconds)
Cbc0010I After 100 nodes, 57 on tree, 1e+50 best solution, best possible 271905.7 (157.36 seconds)
Cbc0010I After 200 nodes, 109 on tree, 1e+50 best solution, best possible 271905.7 (202.91 seconds)
Cbc0010I After 300 nodes, 159 on tree, 1e+50 best solution, best possible 271905.7 (246.36 seconds)
Cbc0010I After 400 nodes, 209 on tree, 1e+50 best solution, best possible 271905.7 (282.02 seconds)
Cbc0010I After 500 nodes, 261 on tree, 1e+50 best solution, best possible 271905.7 (316.04 seconds)
Cbc0010I After 600 nodes, 310 on tree, 1e+50 best solution, best possible 271905.7 (349.89 seconds)
Cbc0010I After 700 nodes, 359 on tree, 1e+50 best solution, best possible 271905.7 (379.69 seconds)
Cbc0010I After 800 nodes, 409 on tree, 1e+50 best solution, best possible 271905.7 (411.29 seconds)
Cbc0010I After 900 nodes, 459 on tree, 1e+50 best solution, best possible 271905.7 (445.93 seconds)
Cbc0010I After 1000 nodes, 509 on tree, 1e+50 best solution, best possible 271905.7 (480.64 seconds)
Cbc0010I After 1100 nodes, 608 on tree, 1e+50 best solution, best possible 271905.7 (499.37 seconds)
Cbc0010I After 1200 nodes, 708 on tree, 1e+50 best solution, best possible 271905.7 (520.89 seconds)
Cbc0010I After 1300 nodes, 808 on tree, 1e+50 best solution, best possible 271905.7 (537.68 seconds)
Cbc0010I After 1400 nodes, 908 on tree, 1e+50 best solution, best possible 271905.7 (552.14 seconds)
Cbc0012I Integer solution of 272705.7 found by rounding after 448734 iterations and 1452 nodes (559.78 seconds)
Cbc0038I Full problem 16387 rows 9762 columns, reduced to 0 rows 0 columns
Cbc0011I Exiting as integer gap of 800 less than 2200 or 0%%
Cbc0001I Search completed - best objective 272705.7047293056, took 448997 iterations and 1453 nodes (561.24 seconds)
Cbc0032I Strong branching done 6808 times (449919 iterations), fathomed 0 nodes and fixed 2 variables
Cbc0035I Maximum depth 523, 518 variables fixed on reduced cost
Cuts at root node changed objective from 253685 to 271906
Probing was tried 449 times and created 36967 cuts of which 245 were active after adding rounds of cuts (4.132 seconds)
Gomory was tried 449 times and created 14449 cuts of which 0 were active after adding rounds of cuts (17.213 seconds)
Knapsack was tried 449 times and created 26037 cuts of which 0 were active after adding rounds of cuts (5.361 seconds)
Clique was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.071 seconds)
MixedIntegerRounding2 was tried 449 times and created 15587 cuts of which 0 were active after adding rounds of cuts (5.479 seconds)
FlowCover was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.022 seconds)
TwoMirCuts was tried 449 times and created 21730 cuts of which 0 were active after adding rounds of cuts (6.315 seconds)
ImplicationCuts was tried 19 times and created 3254 cuts of which 0 were active after adding rounds of cuts (0.035 seconds)
Result - Optimal solution found (within gap tolerance)
Objective value: 272705.70472931
Lower bound: 271905.705
Gap: 0.00
Enumerated nodes: 1453
Total iterations: 448997
Time (CPU seconds): 562.33
Time (Wallclock seconds): 563.34
Total time (CPU seconds): 563.79 (Wallclock seconds): 564.95
+125
View File
@@ -0,0 +1,125 @@
Solver command line: ['/usr/bin/cbc', '-seconds', '3200', '-allow', '2200', '-printingOptions', 'all', '-import', '/tmp/tmpkhpv9a3u.pyomo.lp', '-stat=1', '-solve', '-solu', '/tmp/tmpkhpv9a3u.pyomo.soln']
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 7 2019
command line - /usr/bin/cbc -seconds 3200 -allow 2200 -printingOptions all -import /tmp/tmpkhpv9a3u.pyomo.lp -stat=1 -solve -solu /tmp/tmpkhpv9a3u.pyomo.soln (default strategy 1)
seconds was changed from 1e+100 to 3200
allowableGap was changed from 1e-10 to 2200
Option for printingOptions changed from normal to all
Presolve 51155 (-79938) rows, 21938 (-44207) columns and 202022 (-585467) elements
Statistics for presolved model
Original problem has 65728 integers (64896 of which binary)
Presolved problem has 21848 integers (21632 of which binary)
==== 19456 zero objective 3 different
19456 variables have objective of 0
208 variables have objective of 20
2274 variables have objective of 1000
==== absolute objective values 3 different
19456 variables have objective of 0
208 variables have objective of 20
2274 variables have objective of 1000
==== for integers 19456 zero objective 3 different
19456 variables have objective of 0
208 variables have objective of 20
2184 variables have objective of 1000
==== for integers absolute objective values 3 different
19456 variables have objective of 0
208 variables have objective of 20
2184 variables have objective of 1000
===== end objective counts
Problem has 51155 rows, 21938 columns (2482 with objective) and 202022 elements
There are 298 singletons with objective
Column breakdown:
306 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf,
0 of type lo->up, 0 of type free, 0 of type fixed,
0 of type -inf->0.0, 0 of type -inf->up, 21632 of type 0.0->1.0
Row breakdown:
2712 of type E 0.0, 520 of type E 1.0, 0 of type E -1.0,
227 of type E other, 0 of type G 0.0, 0 of type G 1.0,
376 of type G other, 4056 of type L 0.0, 41756 of type L 1.0,
1508 of type L other, 0 of type Range 0.0->1.0, 0 of type Range other,
0 of type Free
Continuous objective value is 239817 - 9.92 seconds
Cgl0002I 40560 variables fixed
Cgl0003I 0 fixed, 208 tightened bounds, 31984 strengthened rows, 69557 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 4437 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 2091 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 1067 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 143 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 135 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 126 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 120 strengthened rows, 0 substitutions
Cgl0003I 0 fixed, 0 tightened bounds, 113 strengthened rows, 0 substitutions
Cgl0004I processed model has 10896 rows, 9762 columns (9672 integer (9464 of which binary)) and 72490 elements
Cbc0038I Initial state - 346 integers unsatisfied sum - 76.2913
Cbc0038I Pass 1: (15.76 seconds) suminf. 33.26604 (123) obj. 249238 iterations 1545
Cbc0038I Pass 2: (15.78 seconds) suminf. 25.78093 (112) obj. 251318 iterations 269
Cbc0038I Pass 3: (15.80 seconds) suminf. 25.79137 (111) obj. 251456 iterations 69
Cbc0038I Pass 4: (15.82 seconds) suminf. 21.19438 (98) obj. 249900 iterations 423
Cbc0038I Pass 5: (15.84 seconds) suminf. 21.83309 (100) obj. 250336 iterations 56
Cbc0038I Pass 6: (15.86 seconds) suminf. 20.71492 (94) obj. 249739 iterations 149
Cbc0038I Pass 7: (15.88 seconds) suminf. 20.09167 (98) obj. 252364 iterations 33
Cbc0038I Pass 8: (15.91 seconds) suminf. 19.76241 (84) obj. 250731 iterations 323
Cbc0038I Pass 9: (15.93 seconds) suminf. 19.49844 (84) obj. 251114 iterations 93
Cbc0038I Pass 10: (15.95 seconds) suminf. 21.05958 (87) obj. 250700 iterations 261
Cbc0038I Pass 11: (15.96 seconds) suminf. 19.48336 (84) obj. 253142 iterations 83
Cbc0038I Pass 12: (15.98 seconds) suminf. 18.90177 (82) obj. 253142 iterations 11
Cbc0038I Pass 13: (16.00 seconds) suminf. 19.56423 (80) obj. 250761 iterations 260
Cbc0038I Pass 14: (16.02 seconds) suminf. 19.58715 (83) obj. 251156 iterations 97
Cbc0038I Pass 15: (16.04 seconds) suminf. 20.75833 (83) obj. 250573 iterations 263
Cbc0038I Pass 16: (16.06 seconds) suminf. 20.45839 (85) obj. 250971 iterations 81
Cbc0038I Pass 17: (16.08 seconds) suminf. 19.69155 (83) obj. 250561 iterations 141
Cbc0038I Pass 18: (16.09 seconds) suminf. 19.43441 (86) obj. 250946 iterations 40
Cbc0038I Pass 19: (16.11 seconds) suminf. 21.02156 (80) obj. 250564 iterations 260
Cbc0038I Pass 20: (16.13 seconds) suminf. 17.85922 (77) obj. 250965 iterations 106
Cbc0038I Pass 21: (16.15 seconds) suminf. 17.45928 (78) obj. 250601 iterations 200
Cbc0038I Pass 22: (16.17 seconds) suminf. 17.92720 (78) obj. 250994 iterations 212
Cbc0038I Pass 23: (16.19 seconds) suminf. 21.11487 (78) obj. 250598 iterations 209
Cbc0038I Pass 24: (16.21 seconds) suminf. 19.59336 (79) obj. 250987 iterations 67
Cbc0038I Pass 25: (16.23 seconds) suminf. 18.27678 (74) obj. 250985 iterations 255
Cbc0038I Pass 26: (16.24 seconds) suminf. 18.38292 (78) obj. 251377 iterations 30
Cbc0038I Pass 27: (16.26 seconds) suminf. 17.97511 (82) obj. 251341 iterations 129
Cbc0038I Pass 28: (16.28 seconds) suminf. 17.97511 (81) obj. 251174 iterations 8
Cbc0038I Pass 29: (16.30 seconds) suminf. 17.12085 (75) obj. 250970 iterations 164
Cbc0038I Pass 30: (16.31 seconds) suminf. 16.96998 (77) obj. 251356 iterations 34
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 9127 integers at bound fixed and 42 continuous
Cbc0038I Full problem 10896 rows 9762 columns, reduced to 514 rows 451 columns
Cbc0038I Mini branch and bound did not improve solution (16.47 seconds)
Cbc0038I After 16.47 seconds - Feasibility pump exiting - took 0.94 seconds
Cbc0012I Integer solution of 258618.43 found by DiveCoefficient after 3400 iterations and 0 nodes (23.00 seconds)
Cbc0031I 95 added rows had average density of 558.45263
Cbc0013I At root node, 95 cuts changed objective from 239816.84 to 258618.43 in 10 passes
Cbc0014I Cut generator 0 (Probing) - 181 row cuts average 21.4 elements, 0 column cuts (0 active) in 2.128 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 301 row cuts average 1018.4 elements, 0 column cuts (0 active) in 1.454 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.057 seconds - new frequency is -100
Cbc0014I Cut generator 3 (Clique) - 1 row cuts average 5.0 elements, 0 column cuts (0 active) in 0.017 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 122 row cuts average 82.9 elements, 0 column cuts (0 active) in 0.155 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.024 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 171 row cuts average 135.5 elements, 0 column cuts (0 active) in 0.580 seconds - new frequency is 1
Cbc0001I Search completed - best objective 258618.4298960748, took 3400 iterations and 0 nodes (23.02 seconds)
Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost
Cuts at root node changed objective from 239817 to 258618
Probing was tried 10 times and created 181 cuts of which 0 were active after adding rounds of cuts (2.128 seconds)
Gomory was tried 10 times and created 301 cuts of which 0 were active after adding rounds of cuts (1.454 seconds)
Knapsack was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.057 seconds)
Clique was tried 10 times and created 1 cuts of which 0 were active after adding rounds of cuts (0.017 seconds)
MixedIntegerRounding2 was tried 10 times and created 122 cuts of which 0 were active after adding rounds of cuts (0.155 seconds)
FlowCover was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.024 seconds)
TwoMirCuts was tried 10 times and created 171 cuts of which 0 were active after adding rounds of cuts (0.580 seconds)
Result - Optimal solution found
Objective value: 258618.42989607
Enumerated nodes: 0
Total iterations: 3400
Time (CPU seconds): 23.58
Time (Wallclock seconds): 23.80
Total time (CPU seconds): 25.14 (Wallclock seconds): 25.45
+123 -33
View File
@@ -15,13 +15,17 @@ import datetime
import itertools
import operator
use_neos = False
weeks_to_rota = 26
sites = ("truro", "exeter", "torquay", "barnstaple", "plymouth")
Rota = RotaBuilder(datetime.date(2020, 9, 7),
weeks_to_rota=weeks_to_rota,
balance_offset_modifier=1)
balance_offset_modifier=1,
max_weekend_frequency=1,
max_night_frequency=2)
rota_collections = {
"current": deepcopy(Rota),
@@ -59,27 +63,51 @@ rota_collections['current'].add_shifts(
days[5:],
workers_required=2,
assign_as_block=True),
#SingleShift((sites), "night", 12.5, days, balance_weighting=1, workers_required=3, rota_on_nwds=True),
SingleShift((sites),
"night",
"night_weekday",
12.25,
days,
balance_offset=2,
days[:4],
balance_offset=5,
balance_weighting=1,
workers_required=3,
rota_on_nwds=True),
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
SingleShift((sites),
"night_weekend",
12.25,
days[4:],
balance_offset=4,
balance_weighting=1,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
)
rota_collections['extended proc nights only'].add_shifts(
#SingleShift((sites), "night", 12.5, days, balance_weighting=1, workers_required=3, rota_on_nwds=True),
SingleShift((sites),
"night",
"night_weekday",
13,
days,
balance_offset=2,
days[:4],
balance_offset=5,
balance_weighting=1,
workers_required=3,
rota_on_nwds=True), )
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
SingleShift((sites),
"night_weekend",
13,
days[4:],
balance_offset=4,
balance_weighting=1,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
)
rota_collections['no weekends'].add_shifts(
SingleShift(("exeter", ), "exeter_twilight", 12.5, days[:5]),
@@ -88,13 +116,25 @@ rota_collections['no weekends'].add_shifts(
SingleShift(("plymouth", ), "plymouth_twilight", 12.5, days[:5]),
#SingleShift((sites), "night", 12.5, days, balance_weighting=1, workers_required=3, rota_on_nwds=True),
SingleShift((sites),
"night",
"night_weekday",
13,
days,
balance_offset=2,
days[:4],
balance_offset=5,
balance_weighting=1,
workers_required=3,
rota_on_nwds=True),
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
SingleShift((sites),
"night_weekend",
13,
days[4:],
balance_offset=4,
balance_weighting=1,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
)
rota_collections['no twighlights'].add_shifts(
@@ -121,13 +161,25 @@ rota_collections['no twighlights'].add_shifts(
assign_as_block=True),
#SingleShift((sites), "night", 12.5, days, balance_weighting=1, workers_required=3, rota_on_nwds=True),
SingleShift((sites),
"night",
"night_weekday",
13,
days,
balance_offset=2,
days[:4],
balance_offset=5,
balance_weighting=1,
workers_required=3,
rota_on_nwds=True),
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
SingleShift((sites),
"night_weekend",
13,
days[4:],
balance_offset=4,
balance_weighting=1,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
)
rota_collections['no nights'].add_shifts(
@@ -184,13 +236,25 @@ rota_collections['nights + proc twighlights + normal weekends'].add_shifts(
assign_as_block=True),
#SingleShift((sites), "night", 12.5, days, balance_weighting=1, workers_required=3, rota_on_nwds=True),
SingleShift((sites),
"night",
"night_weekday",
12.25,
days,
balance_offset=2,
days[:4],
balance_offset=5,
balance_weighting=1,
workers_required=3,
rota_on_nwds=True),
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
SingleShift((sites),
"night_weekend",
12.25,
days[4:],
balance_offset=4,
balance_weighting=1,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
)
rota_collections['nights + proc twighlights + proc weekends'].add_shifts(
@@ -201,13 +265,25 @@ rota_collections['nights + proc twighlights + proc weekends'].add_shifts(
workers_required=3),
#SingleShift((sites), "night", 12.5, days, balance_weighting=1, workers_required=3, rota_on_nwds=True),
SingleShift((sites),
"night",
"night_weekday",
12.25,
days,
balance_offset=2,
days[:4],
balance_offset=5,
balance_weighting=1,
workers_required=3,
rota_on_nwds=True),
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
SingleShift((sites),
"night_weekend",
12.25,
days[4:],
balance_offset=4,
balance_weighting=1,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
)
# Import trainee data
@@ -245,16 +321,30 @@ for rot in rota_collections:
Rota.build_shifts_and_workers()
print("-Building model")
Rota.build_model()
print("-Building model: complete")
opt = SolverFactory('cbc') # choose a solver
#opt = SolverFactory('ipopt') # choose a solver
results = opt.solve(
Rota.model, tee=True, options={
"seconds": 1200,
"allow": 3500
}) # solve the model with the, options="seconds=60" selected solver
if use_neos:
print("-Solving with neos")
solver_manager = SolverManagerFactory('neos') # Solve in neos server
results = solver_manager.solve(Rota.model,
opt=opt,
logfile="{}.log".format(rot))
else:
print("-Solving with local cbc")
results = opt.solve(
Rota.model,
tee=True,
options={
"seconds": 3200,
"allow": 2200,
},
logfile="{}.log".format(rot)
) # solve the model with the, options="seconds=60" selected solver
results.solver.status
@@ -285,8 +375,8 @@ for rot in rota_collections:
f.write("<pre>{}</pre>".format(worker_shift_summary))
f.write("\n\n\n")
#workers_no_pref = ResultsHolder.get_no_preference(Rota.model.no_pref) # list with the non-satisfied workers (work on Sat but not on Sun)
worker_night_block = ResultsHolder.get_night_blocks()
multi = ResultsHolder.get_multinight()
#worker_night_block = ResultsHolder.get_night_blocks()
#multi = ResultsHolder.get_multinight()
#break
+418 -198
View File
@@ -37,6 +37,7 @@ class SingleShift(object):
rota_on_nwds=False,
assign_as_block=False,
force_as_block=False,
hard_constrain_shift=True,
constraints=[],
):
self.site = sites
@@ -51,6 +52,7 @@ class SingleShift(object):
# weight the shift for balancing, default is 1
self.balance_weighting = balance_weighting
self.hard_constrain_shift = hard_constrain_shift
self.workers_required = workers_required
self.rota_on_nwds = rota_on_nwds
@@ -75,7 +77,10 @@ class RotaBuilder(object):
def __init__(self,
start_date,
weeks_to_rota=26,
balance_offset_modifier=1):
balance_offset_modifier=1,
ltft_balance_offset=4,
max_night_frequency=2,
max_weekend_frequency=2):
self.shifts = [] # type List[SingleShift]
self.days = days
@@ -99,6 +104,22 @@ class RotaBuilder(object):
self.sites = None
self.balance_offset_modifier = balance_offset_modifier
self.ltft_balance_offset = ltft_balance_offset
# Don't assign multiple shifts every (n) weeks
self.max_night_frequency = max_night_frequency
self.max_weekend_frequency = max_weekend_frequency
self.constraint_options = {
"limit_to_1_st1_on_nights": True,
"ensure_1_st4_plus_on_nights": True,
"balance_nights": True,
"constrain_time_off_after_nights": True,
"balance_nights_across_sites": True,
"balance_blocks": True,
"balance_shifts": True,
"balance_weekends": True,
}
def build_model(self):
# Initialize model
@@ -115,12 +136,12 @@ class RotaBuilder(object):
)
# The nights self.model is used to ensure nights are assigned as a block (and limit the number of workers required)
self.model.nights = Var(
((worker.id, week, block) for worker in self.workers
for week in self.weeks for block in self.night_blocks),
within=Binary,
initialize=0,
)
# self.model.nights = Var(
# ((worker.id, week, block) for worker in self.workers
# for week in self.weeks for block in self.night_blocks),
# within=Binary,
# initialize=0,
# )
# The nights self.model is used to ensure nights are assigned as a block (and limit the number of workers required)
self.model.shift_week_worker_assigned = Var(
@@ -156,26 +177,30 @@ class RotaBuilder(object):
# Used to limit number of workers on night shift per site
# if we force a binary it will in effect hard constrain to < 2
# from a single site
self.model.night_per_site = Var(
((week, block, site) for site in self.sites for week in self.weeks
for block in ["weekday", "weekend"]),
#within=Binary,
within=NonNegativeIntegers,
initialize=0,
)
if self.constraint_options["balance_nights_across_sites"]:
self.model.night_per_site = Var(
((week, shift.name, site) for site in self.sites
for week in self.weeks
for shift in self.get_shifts_with_constraint("night")),
#within=Binary,
within=NonNegativeIntegers,
initialize=0,
)
self.model.night_per_site_t1 = Var(
((week, block, site) for site in self.sites for week in self.weeks
for block in ["weekday", "weekend"]),
domain=NonNegativeIntegers,
initialize=0,
)
self.model.night_per_site_t2 = Var(
((week, block, site) for site in self.sites for week in self.weeks
for block in ["weekday", "weekend"]),
domain=NonNegativeIntegers,
initialize=0,
)
self.model.night_per_site_t1 = Var(
((week, shift.name, site) for site in self.sites
for week in self.weeks
for shift in self.get_shifts_with_constraint("night")),
domain=NonNegativeIntegers,
initialize=0,
)
self.model.night_per_site_t2 = Var(
((week, shift.name, site) for site in self.sites
for week in self.weeks
for shift in self.get_shifts_with_constraint("night")),
domain=NonNegativeIntegers,
initialize=0,
)
self.model.shift_count = Var(
((worker.id, shift) for worker in self.workers
@@ -196,6 +221,84 @@ class RotaBuilder(object):
initialize=0,
)
if self.constraint_options["balance_nights"]:
# We also try to even out the night shifts seperately
self.model.night_shift_count = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeReals,
initialize=0,
)
self.model.night_shift_count_t1 = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeReals,
initialize=0,
)
self.model.night_shift_count_t2 = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeReals,
initialize=0,
)
self.model.worker_weekend_assigned = Var(
((worker.id, week) for worker in self.workers
for week in self.weeks),
domain=NonNegativeReals,
initialize=0,
)
self.model.works_weekend_count = Var(
((worker.id, week) for worker in self.workers
for week in self.weeks),
domain=NonNegativeIntegers,
initialize=0,
)
# self.model.works_saturday = Var(
# ((worker.id, week) for worker in self.workers
# for week in self.weeks),
# domain=Binary,
# initialize=0,
# )
# self.model.works_sunday = Var(
# ((worker.id, week) for worker in self.workers
# for week in self.weeks),
# domain=Binary,
# initialize=0,
# )
# self.model.works_whole_weekend = Var(
# ((worker.id, week) for worker in self.workers
# for week in self.weeks),
# domain=Binary,
# initialize=0,
# )
self.model.works_weekend = Var(
((worker.id, week) for worker in self.workers
for week in self.weeks),
domain=Binary,
initialize=0,
)
self.model.worker_weekend_count = Var(
((worker.id) for worker in self.workers),
domain=NonNegativeIntegers,
initialize=0,
)
# self.model.weekend_count_t1 = Var(
# ((worker.id) for worker in self.workers),
# domain=NonNegativeReals,
# initialize=0,
# )
# self.model.weekend_count_t2 = Var(
# ((worker.id) for worker in self.workers),
# domain=NonNegativeReals,
# initialize=0,
# )
# self.model.unavailable = Var(((worker, week, day) for worker in self.workers for week in weeks for day in days),
# within=Binary, initialize=0)
@@ -295,86 +398,62 @@ class RotaBuilder(object):
self.model.max_hours_constraint = Constraint(
[worker.id for worker in self.workers], rule=maxHoursRule)
# # Limit to 1 ST2 (or below) on a night shift
# def nightShiftMaxSTRule(model, week, block):
# """Limits to 1 ST2 (or below) per night"""
# single_workers = [w for w in self.workers if w.grade < 3]
# if not single_workers:
# return Constraint.Skip
# return sum(model.nights[w.id, week, block]
# for w in single_workers) <= 1
# # self.model.night_shifts_max_st_constraint = Constraint(
# # [week for week in self.weeks],
# # [block for block in ["weekday", "weekend"]],
# # rule=nightShiftMaxSTRule,
# # )
# Limit to 1 ST2 (or below) on a night shift
def nightShiftMaxSTRule_new(model, week, day, shift):
def nightShiftMaxSTRule(model, week, shift):
"""Limits to 1 ST2 (or below) per night"""
single_workers = [w for w in self.workers if w.grade < 3]
if not single_workers:
return Constraint.Skip
return sum(model.works[w.id, week, day, shift]
return sum(model.shift_week_worker_assigned[shift, week, w.id]
for w in single_workers) <= 1
self.model.night_shifts_max_st_constraint = Constraint(
[week for week in self.weeks],
[day for day in self.days],
[shift.name for shift in self.get_shifts_with_constraint("night")],
rule=nightShiftMaxSTRule_new,
)
if self.constraint_options["limit_to_1_st1_on_nights"]:
self.model.night_shifts_max_st_constraint = Constraint(
[week for week in self.weeks],
[
shift.name
for shift in self.get_shifts_with_constraint("night")
],
rule=nightShiftMaxSTRule,
)
# Enusre at least 1 ST4+ on a night shift
def nightShiftMinST4Rule(model, week, block):
def nightShiftMinST4Rule(model, week, shift):
single_workers = [w for w in self.workers if w.grade > 3]
if not single_workers:
print(single_workers)
return Constraint.Skip
return sum(model.nights[w.id, week, block]
for w in single_workers) >= 1
return sum(model.shift_week_worker_assigned[shift, week, w.id]
for w in single_workers) >= 2
self.model.night_shifts_min_st4_constraint = Constraint(
[week for week in self.weeks],
[block for block in ["weekday", "weekend"]],
rule=nightShiftMinST4Rule,
)
if self.constraint_options["ensure_1_st4_plus_on_nights"]:
self.model.night_shifts_min_st4_constraint = Constraint(
[week for week in self.weeks],
[
shift.name
for shift in self.get_shifts_with_constraint("night")
],
rule=nightShiftMinST4Rule,
)
# #Constraint (def of self.model.needed)
# for worker in self.workers:
# self.model.constraints.add(
# 10000 * self.model.needed[worker.id] >= sum(
# self.model.works[worker.id, week, day, shift] for week,
# day, shift in self.get_all_shiftname_combinations())
# ) # if any self.model.works[worker, ·, ·] non-zero, self.model.needed[worker] must be one; else is zero to reduce the obj function
# #10000 is to remark, but 5 was enough since max of 40 hours yields max of 5 shifts, the maximum possible sum
# #Constraint (def of self.model.no_pref)
# for worker in self.workers:
# for week in weeks:
# self.model.constraints.add(
# self.model.no_pref[worker.id] >=
# sum(self.model.works[worker.id, week, 'Sat', shift]
# for shift in self.get_shift_names_by_day("Sat")) -
# sum(self.model.works[worker.id, week, 'Sun', shift]
# for shift in self.get_shift_names_by_day("Sun"))
# ) # if not working on sunday but working saturday self.model.needed must be 1; else will be zero to reduce the obj function
# Count the number of workers from each site on each night shift
# As 1 or 0 is optimum we can simply subtract 1 from the number
for site in self.sites:
for block in ("weekend", "weekday"):
for week in self.weeks:
self.model.constraints.add(
self.model.night_per_site[week, block, site] == sum(
self.model.nights[worker.id, week, block]
for worker in self.workers if worker.site == site)
#1 >= sum(self.model.nights[worker.id, week, block] for worker in self.workers if worker.site == site)
)
self.model.constraints.add(
self.model.night_per_site_t1[week, block, site] -
self.model.night_per_site_t2[week, block, site] ==
self.model.night_per_site[week, block, site] - 1)
# # Count the number of workers from each site on each night shift
# # As 1 or 0 is optimum we can simply subtract 1 from the number
if self.constraint_options["balance_nights_across_sites"]:
for site in self.sites:
for shift in self.get_shifts_with_constraint("night"):
block = shift.name
for week in self.weeks:
self.model.constraints.add(
self.model.night_per_site[week, block, site] ==
sum(self.model.shift_week_worker_assigned[
block, week, worker.id]
for worker in self.workers
if worker.site == site)
#1 >= sum(self.model.shift_week_worker_assigned[shift.name, week, worker.id] for worker in self.workers if worker.site == site)
)
self.model.constraints.add(
self.model.night_per_site_t1[week, block, site] -
self.model.night_per_site_t2[week, block, site] ==
self.model.night_per_site[week, block, site] - 1)
weeks_days = self.get_week_day_combinations()
@@ -396,7 +475,6 @@ class RotaBuilder(object):
for worker in self.workers))
if shift.force_as_block:
# Force nights to be assigned in blocks
self.model.constraints.add(
self.model.worker_block_shift_counts[worker.id, week,
shift.name] ==
@@ -412,6 +490,13 @@ class RotaBuilder(object):
# Most of our constraints apply per worker
for worker in self.workers:
# Count number of weekends an worker works
if self.constraint_options["balance_weekends"]:
self.model.constraints.add(
self.model.worker_weekend_count[worker.id] == sum(
self.model.works_weekend[worker.id, week]
for week in self.weeks))
# Balance shifts within required limits (set by balance_offset)
# If balance_offset is too restrictive (for the rota length)
# no solution will be possible
@@ -433,18 +518,26 @@ class RotaBuilder(object):
worker.fte_adj)
worker.shift_target_number[shift.name] = target_shifts
if worker.name == "Jean Sukumar":
print(worker.name, shift.name, target_shifts,
total_shifts, worker.fte_adj)
max_shifts = target_shifts + shift.balance_offset * self.balance_offset_modifier
min_shifts = target_shifts - shift.balance_offset * self.balance_offset_modifier
if shift.hard_constrain_shift:
adjusted_balance_offset = shift.balance_offset
if worker.fte_adj < 100:
adjusted_balance_offset = adjusted_balance_offset * self.ltft_balance_offset
self.model.constraints.add(
inequality(
min_shifts,
sum(self.model.works[worker.id, week, day,
shift.name] for week, day in
self.get_week_day_combinations()),
max_shifts,
))
max_shifts = target_shifts + adjusted_balance_offset * self.balance_offset_modifier
min_shifts = target_shifts - adjusted_balance_offset * self.balance_offset_modifier
self.model.constraints.add(
inequality(
min_shifts,
sum(self.model.works[worker.id, week, day,
shift.name] for week, day
in self.get_week_day_combinations()),
max_shifts,
))
else:
# Make sure shifts aren't assigned to those from other sites
self.model.constraints.add(0 == sum(
@@ -458,6 +551,13 @@ class RotaBuilder(object):
self.model.works[worker.id, week, day, shift.name]
for week, day in self.get_week_day_combinations()))
if self.constraint_options["balance_nights"]:
self.model.constraints.add(
self.model.night_shift_count[worker.id] == sum(
self.model.works[worker.id, week, day, shift.name]
for week, day in self.get_week_day_combinations()
for shift in self.get_shifts_with_constraint("night")))
# Define shift_count_t1 and shift_count_t2 constraints for the object
# Thus bypassing the need for a quadratic solver
# t1-t2 is the target
@@ -469,6 +569,28 @@ class RotaBuilder(object):
(self.model.shift_count[worker.id, shift.name] -
worker.shift_target_number[shift.name]) *
shift.balance_weighting for shift in self.get_shifts()))
#if "night" not in shift.constraints))
if self.constraint_options["balance_nights"]:
night_shift_target_number = sum(
worker.shift_target_number[shift.name]
for shift in self.get_shifts_with_constraint("night"))
min_shifts = night_shift_target_number - 20
max_shifts = night_shift_target_number + 20
self.model.constraints.add(
inequality(
min_shifts,
self.model.night_shift_count[worker.id],
max_shifts,
))
self.model.constraints.add(
self.model.night_shift_count_t1[worker.id] -
self.model.night_shift_count_t2[worker.id] ==
self.model.night_shift_count[worker.id] -
night_shift_target_number)
# Ensure worker is not allocated shifts on non working days
if worker.nwd:
@@ -478,37 +600,74 @@ class RotaBuilder(object):
0 == self.model.works[worker.id, week, day,
shift.name])
if "night" in self.get_shift_names():
for week_blocks in self.get_week_block_iterator(2):
# Prevent nights more than once every n weeks
self.model.constraints.add(
1 >= sum(self.model.nights[worker.id, week, block]
for week in week_blocks
for block in ["weekday", "weekend"]))
# for week_blocks in self.get_week_block_iterator(
# self.max_night_frequency):
# if self.get_shifts_with_constraint("night"):
# # Prevent nights more than once every n weeks
# self.model.constraints.add(1 >= sum(
# self.model.shift_week_worker_assigned[shift.name, week,
# worker.id]
# for week in week_blocks
# for shift in self.get_shifts_with_constraint("night")))
# for week_blocks in self.get_week_block_iterator(
# self.max_weekend_frequency):
# # Prevent weekend shifts more than once every n weeks
# self.model.constraints.add(
# 1 >= sum(self.model.works_weekend[worker.id, week]
# for week in week_blocks))
for week in self.weeks:
# # model.weekend_count stores the number of weekend shifts that a worker is assigned to wor
# # this is used (by the objective) to balance the total number of weekend shifts worked
# self.model.constraints.add(
# # We could use a helper to get required shifts to check
# self.model.works_whole_weekend[worker.id, week] >= sum(
# self.model.works[worker.id, week, day, shift.name]
# for day in self.days[5:]
# for shift in self.get_shifts()) - 1)
# self.model.constraints.add(
# self.model.works_whole_weekend[worker.id, week] <= sum(
# self.model.works[worker.id, week, day, shift.name]
# for day in self.days[5:]
# for shift in self.get_shifts()) / 2)
if self.constraint_options["balance_weekends"]:
self.model.constraints.add(
self.model.works_weekend[worker.id, week] >= sum(
self.model.works[worker.id, week, day, shift.name]
for day in self.days[5:]
for shift in self.get_shifts()) / 2)
self.model.constraints.add(
self.model.works_weekend[worker.id, week] <= sum(
self.model.works[worker.id, week, day, shift.name]
for day in self.days[5:]
for shift in self.get_shifts()))
# self.model.constraints.add(
# self.model.works_saturday[worker.id, week] == sum(
# self.model.works[worker.id, week, "Sat", shift.name]
# for shift in self.get_shifts()))
# self.model.constraints.add(
# self.model.works_sunday[worker.id, week] == sum(
# self.model.works[worker.id, week, "Sun", shift.name]
# for shift in self.get_shifts()))
# self.model.constraints.add(1 == sum(
# self.model.shift_week_worker_assigned[s.name, week, worker.id]
# for s in self.get_shifts_with_constraint("night")))
if "night" in self.get_shift_names():
for shift in self.get_shifts_with_constraint("night"):
# Force nights to be assigned in blocks
self.model.constraints.add(1 == sum(
self.model.nights[worker.id, week, block]
for block in self.night_blocks))
# self.model.constraints.add(8* self.model.shift_week_worker_assigned[shift.name, week, worker.id] >= sum(self.model.works[worker.id, week, day, shift.name] for day in self.days)
# )
# if night block is weekday make sure Mon - Thurs is assigned as nights
# Force night shifts to be assigned in blocks
self.model.constraints.add(
self.model.nights[worker.id, week, "weekday"] *
4 == sum(self.model.works[worker.id, week, day,
"night"]
for day in days[:4]))
self.model.constraints.add(
self.model.nights[worker.id, week, "weekend"] *
3 == sum(self.model.works[worker.id, week, day,
"night"]
for day in days[4:]))
self.model.shift_week_worker_assigned[shift.name, week,
worker.id] *
len(shift.shift_days) == sum(
self.model.works[worker.id, week, day, shift.name]
for day in shift.shift_days))
#
@@ -528,7 +687,7 @@ class RotaBuilder(object):
p2week, p2day = weeks_days[n - 2]
except IndexError:
p2week, p2day = weeks_days[n]
n2 = 0
p2 = 0
n1 = 1
n2 = 1
@@ -544,50 +703,58 @@ class RotaBuilder(object):
n2week, n2day = weeks_days[n]
n2 = 0
# Unable to work (hard constraint not preference)
self.model.constraints.add(
self.model.available[worker.id, week, day] >= sum(
if self.get_shift_names_by_day(day):
# Unable to work (hard constraint not preference)
self.model.constraints.add(
self.model.available[worker.id, week, day] >= sum(
self.model.works[worker.id, week, day, shift]
for shift in self.get_shift_names_by_day(day)))
# single shift per day
self.model.constraints.add(1 >= sum(
self.model.works[worker.id, week, day, shift]
for shift in self.get_shift_names_by_day(day)))
# single shift per day
self.model.constraints.add(
1 >= sum(self.model.works[worker.id, week, day, shift]
for shift in self.get_shift_names_by_day(day)))
# if working a night ensure preceeding (1) or subsequent (2) shifts can only be nights
if "night" in self.get_shift_names():
# Ensure night prior to unavalibity is not assigned
self.model.constraints.add(
self.model.available[worker.id, week, day] >=
self.model.works[worker.id, pweek, pday, "night"])
if self.constraint_options["constrain_time_off_after_nights"]:
for constraint_shift in self.get_shifts_with_constraint(
"night"):
# Ensure night prior to unavalibity is not assigned
self.model.constraints.add(
self.model.available[worker.id, week, day] >=
self.model.works[worker.id, pweek, pday,
constraint_shift.name])
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day, "night"] +
sum(n1 *
self.model.works[worker.id, nweek, nday, shift]
for shift in self.get_shift_names_by_day(nday)
if shift != "night"))
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day,
constraint_shift.name] +
sum(n1 *
self.model.works[worker.id, nweek, nday, shift]
for shift in self.get_shift_names_by_day(nday)
if shift != constraint_shift.name))
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day, "night"] +
sum(n2 *
self.model.works[worker.id, n2week, n2day, shift]
for shift in self.get_shift_names_by_day(n2day)
if shift != "night"))
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day, "night"] +
sum(p1 *
self.model.works[worker.id, pweek, pday, shift]
for shift in self.get_shift_names_by_day(pday)
if shift != "night"))
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day, "night"] +
sum(p2 *
self.model.works[worker.id, p2week, p2day, shift]
for shift in self.get_shift_names_by_day(p2day)
if shift != "night"))
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day,
constraint_shift.name] +
sum(n2 * self.model.works[worker.id, n2week, n2day,
shift]
for shift in self.get_shift_names_by_day(n2day)
if shift != constraint_shift.name))
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day,
constraint_shift.name] +
sum(p1 *
self.model.works[worker.id, pweek, pday, shift]
for shift in self.get_shift_names_by_day(pday)
if shift != constraint_shift.name))
self.model.constraints.add(
1 >= self.model.works[worker.id, week, day,
constraint_shift.name] +
sum(p2 * self.model.works[worker.id, p2week, p2day,
shift]
for shift in self.get_shift_names_by_day(p2day)
if shift != constraint_shift.name))
self.define_objectives()
@@ -597,12 +764,25 @@ class RotaBuilder(object):
# c = len(workers)
balance_modifier_constant = 1000
balance_modifier_constant = 500
shift_balancing = sum(balance_modifier_constant *
(self.model.shift_count_t1[(worker.id)] +
self.model.shift_count_t2[(worker.id)])
for worker in self.workers)
if self.constraint_options["balance_shifts"]:
shift_balancing = sum(balance_modifier_constant *
(self.model.shift_count_t1[(worker.id)] +
self.model.shift_count_t2[(worker.id)])
for worker in self.workers)
else:
shift_balancing = 0
if self.constraint_options["balance_nights"]:
night_balance_modifier_constant = 2000
night_shift_balancing = sum(
night_balance_modifier_constant *
(self.model.night_shift_count_t1[(worker.id)] +
self.model.night_shift_count_t2[(worker.id)])
for worker in self.workers)
else:
night_shift_balancing = 0
preference_constant = 10
# Preferences
@@ -614,19 +794,29 @@ class RotaBuilder(object):
# # Spread nights
nights_balancing = sum(
self.model.night_per_site_t1[week, block, site] * 20
#self.model.night_per_site2[week, block, site]
for week in self.weeks for block in ("weekday", "weekend")
for site in self.sites)
#nights_balancing = 0
if self.constraint_options["balance_nights_across_sites"]:
nights_site_balancing = sum(
(self.model.night_per_site_t1[week, shift.name, site] +
self.model.night_per_site_t2[week, shift.name, site]) * 20
#self.model.night_per_site2[week, block, site]
for week in self.weeks
for shift in self.get_shifts_with_constraint("night")
for site in self.sites)
else:
nights_site_balancing = 0
blocks_balancing = sum(
100 * self.model.blocks_assigned[week, shift]
for week in self.weeks
for shift in self.shifts_to_assign_as_blocks())
if self.constraint_options["balance_blocks"]:
blocks_balancing = sum(
100 * self.model.blocks_assigned[week, shift]
for week in self.weeks
for shift in self.shifts_to_assign_as_blocks())
else:
blocks_balancing = 0
return shift_balancing + preferences + nights_balancing + blocks_balancing
return night_shift_balancing
#return shift_balancing + preferences + blocks_balancing
#return shift_balancing + preferences + nights_site_balancing + blocks_balancing
return shift_balancing + night_shift_balancing + preferences + nights_site_balancing + blocks_balancing
# add objective function to the model. rule (pass function) or expr (pass expression directly)
self.model.obj = Objective(rule=obj_rule, sense=minimize)
@@ -874,6 +1064,9 @@ class RotaBuilder(object):
s.extend(self.shifts_to_force_as_blocks())
return s
def get_workers_total_fte(self):
return self.full_time_equivalent
class RotaResults(object):
def __init__(self, rota, results):
@@ -946,7 +1139,10 @@ class RotaResults(object):
timetable[worker.name][week][day] = shift
return timetable
def get_worker_timetable_brief(self, show_prefs=True, marker_every=19):
def get_worker_timetable_brief(self,
show_prefs=True,
marker_every=19,
show_unavailable=True):
model = self.rota.model
week_string = "{:20}".format("-Week-") + "".join(
[7 * str("{}".format(w))[-1:] for w in self.rota.weeks])
@@ -966,8 +1162,11 @@ class RotaResults(object):
shift_count = ""
for s in set(shifts):
shift_count = shift_count + "{}: {},".format(
shift_count = shift_count + "{}: {}, ".format(
s, shifts.count(s))
shift_count = shift_count + "#weekends_worked: {}\\#".format(
model.worker_weekend_count[worker.id].value)
timetable.append("{} {}".format("".join(w), shift_count))
if show_prefs:
@@ -980,6 +1179,16 @@ class RotaResults(object):
w.append("N")
timetable.append("".join(w))
if show_unavailable:
# prefs
w = ["{:20}".format("Unavailable")]
for week, day in self.rota.get_week_day_combinations():
if model.available[worker.id, week, day] > 0:
w.append("A")
else:
w.append("U")
timetable.append("".join(w))
i = marker_every
while i < len(timetable):
timetable.insert(i, week_string)
@@ -1024,26 +1233,27 @@ class RotaResults(object):
# """Extract to a list the workers not satisfied with their weekend preference."""
# return [worker.id for worker in workers if no_pref[worker.id].value == 1]
def get_night_blocks(self):
nights = self.rota.model.nights
timetable = {
worker.name: {
week: {block: ""
for block in self.rota.night_blocks}
for week in self.rota.weeks
}
for worker in self.rota.workers
}
for worker in self.rota.workers:
for week in self.rota.weeks:
for block in self.rota.night_blocks:
if nights[worker.id, week, block].value == 1:
timetable[worker.name][week][block] = "true"
return timetable
# def get_night_blocks(self):
# nights = self.rota.model.nights
# timetable = {
# worker.name: {
# week: {block: ""
# for block in self.rota.night_blocks}
# for week in self.rota.weeks
# }
# for worker in self.rota.workers
# }
# for worker in self.rota.workers:
# for week in self.rota.weeks:
# for block in self.rota.night_blocks:
# if nights[worker.id, week, block].value == 1:
# timetable[worker.name][week][block] = "true"
# return timetable
def get_multinight(self):
for site in self.rota.sites:
for block in ("weekend", "weekday"):
for shift in self.get_shifts_with_constraint("night"):
block = shift.name
for week in self.rota.weeks:
print(
site, week, block,
@@ -1053,3 +1263,13 @@ class RotaResults(object):
site].value,
self.rota.model.night_per_site_t2[week, block,
site].value)
def get_night_details(self):
for worker in self.rota.workers:
print(
worker.name,
self.rota.model.night_shift_count[(worker.id)].value,
self.rota.model.night_shift_count_t1[(worker.id)].value,
self.rota.model.night_shift_count_t2[(worker.id)].value,
worker.shift_target_number["night_weekday"] +
worker.shift_target_number["night_weekend"])
+118
View File
@@ -0,0 +1,118 @@
Solver command line: ['/usr/bin/cbc', '-seconds', '1200', '-allow', '4000', '-printingOptions', 'all', '-import', '/tmp/tmpeun6jpa7.pyomo.lp', '-stat=1', '-solve', '-solu', '/tmp/tmpeun6jpa7.pyomo.soln']
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 7 2019
command line - /usr/bin/cbc -seconds 1200 -allow 4000 -printingOptions all -import /tmp/tmpeun6jpa7.pyomo.lp -stat=1 -solve -solu /tmp/tmpeun6jpa7.pyomo.soln (default strategy 1)
seconds was changed from 1e+100 to 1200
allowableGap was changed from 1e-10 to 4000
Option for printingOptions changed from normal to all
Presolve 57035 (-82138) rows, 23862 (-89251) columns and 226642 (-883011) elements
Statistics for presolved model
Original problem has 112272 integers (112112 of which binary)
Presolved problem has 23696 integers (23696 of which binary)
==== 23751 zero objective 2 different
23751 variables have objective of 0
111 variables have objective of 2000
==== absolute objective values 2 different
23751 variables have objective of 0
111 variables have objective of 2000
==== for integers 23696 zero objective 1 different
23696 variables have objective of 0
==== for integers absolute objective values 1 different
23696 variables have objective of 0
===== end objective counts
Problem has 57035 rows, 23862 columns (111 with objective) and 226642 elements
There are 111 singletons with objective 988 singletons with no objective
Column breakdown:
110 of type 0.0->inf, 56 of type 0.0->up, 0 of type lo->inf,
0 of type lo->up, 0 of type free, 0 of type fixed,
0 of type -inf->0.0, 0 of type -inf->up, 23696 of type 0.0->1.0
Row breakdown:
2843 of type E 0.0, 676 of type E 1.0, 0 of type E -1.0,
289 of type E other, 0 of type G 0.0, 0 of type G 1.0,
231 of type G other, 2788 of type L 0.0, 48596 of type L 1.0,
1612 of type L other, 0 of type Range 0.0->1.0, 0 of type Range other,
0 of type Free
Continuous objective value is 497995 - 22.34 seconds
Cgl0002I 82402 variables fixed
Cgl0003I 0 fixed, 55 tightened bounds, 34225 strengthened rows, 50251 substitutions
Cgl0004I processed model has 17402 rows, 14104 columns (13939 integer (13939 of which binary)) and 89454 elements
Cbc0038I Initial state - 511 integers unsatisfied sum - 146.075
Cbc0038I Pass 1: (33.84 seconds) suminf. 63.26415 (238) obj. 530335 iterations 2863
Cbc0038I Pass 2: (33.87 seconds) suminf. 52.41969 (214) obj. 526335 iterations 226
Cbc0038I Pass 3: (33.90 seconds) suminf. 51.56248 (211) obj. 526335 iterations 61
Cbc0038I Pass 4: (33.93 seconds) suminf. 51.15178 (211) obj. 526335 iterations 79
Cbc0038I Pass 5: (33.96 seconds) suminf. 45.85375 (210) obj. 529354 iterations 94
Cbc0038I Pass 6: (33.99 seconds) suminf. 45.71180 (212) obj. 529354 iterations 41
Cbc0038I Pass 7: (34.04 seconds) suminf. 35.87037 (187) obj. 529354 iterations 322
Cbc0038I Pass 8: (34.08 seconds) suminf. 33.85554 (195) obj. 526761 iterations 264
Cbc0038I Pass 9: (34.11 seconds) suminf. 33.14549 (176) obj. 526830 iterations 105
Cbc0038I Pass 10: (34.14 seconds) suminf. 31.13224 (172) obj. 526830 iterations 115
Cbc0038I Pass 11: (34.21 seconds) suminf. 30.55620 (160) obj. 529691 iterations 562
Cbc0038I Pass 12: (34.25 seconds) suminf. 28.64178 (153) obj. 534012 iterations 205
Cbc0038I Pass 13: (34.29 seconds) suminf. 29.16979 (146) obj. 527774 iterations 240
Cbc0038I Pass 14: (34.31 seconds) suminf. 28.35432 (144) obj. 523774 iterations 4
Cbc0038I Pass 15: (34.37 seconds) suminf. 25.43149 (140) obj. 525658 iterations 341
Cbc0038I Pass 16: (34.39 seconds) suminf. 25.05606 (138) obj. 525658 iterations 13
Cbc0038I Pass 17: (34.42 seconds) suminf. 25.05606 (133) obj. 525988 iterations 132
Cbc0038I Pass 18: (34.45 seconds) suminf. 25.05606 (133) obj. 525988 iterations 6
Cbc0038I Pass 19: (34.52 seconds) suminf. 25.01303 (143) obj. 526804 iterations 492
Cbc0038I Pass 20: (34.55 seconds) suminf. 24.96852 (141) obj. 526288 iterations 33
Cbc0038I Pass 21: (34.63 seconds) suminf. 22.73642 (133) obj. 527464 iterations 691
Cbc0038I Pass 22: (34.64 seconds) suminf. 22.73642 (133) obj. 527464 iterations 0
Cbc0038I Pass 23: (34.69 seconds) suminf. 22.27803 (129) obj. 527464 iterations 346
Cbc0038I Pass 24: (34.72 seconds) suminf. 22.01961 (123) obj. 527464 iterations 76
Cbc0038I Pass 25: (34.79 seconds) suminf. 22.04026 (123) obj. 526572 iterations 541
Cbc0038I Pass 26: (34.82 seconds) suminf. 22.04026 (121) obj. 526572 iterations 47
Cbc0038I Pass 27: (34.86 seconds) suminf. 22.15035 (111) obj. 527464 iterations 339
Cbc0038I Pass 28: (34.89 seconds) suminf. 22.04689 (111) obj. 527464 iterations 91
Cbc0038I Pass 29: (34.95 seconds) suminf. 22.01936 (123) obj. 526475 iterations 455
Cbc0038I Pass 30: (34.98 seconds) suminf. 21.93681 (123) obj. 526475 iterations 40
Cbc0038I No solution found this major pass
Cbc0038I Before mini branch and bound, 13026 integers at bound fixed and 50 continuous
Cbc0038I Full problem 17402 rows 14104 columns, reduced to 796 rows 583 columns
Cbc0038I Mini branch and bound did not improve solution (35.07 seconds)
Cbc0038I After 37.37 seconds - Feasibility pump exiting - took 3.92 seconds
Cbc0031I 166 added rows had average density of 73.783133
Cbc0013I At root node, 166 cuts changed objective from 497995.24 to 497995.24 in 10 passes
Cbc0014I Cut generator 0 (Probing) - 298 row cuts average 8.2 elements, 0 column cuts (123 active) in 1.134 seconds - new frequency is 1
Cbc0014I Cut generator 1 (Gomory) - 985 row cuts average 585.6 elements, 0 column cuts (0 active) in 0.785 seconds - new frequency is 1
Cbc0014I Cut generator 2 (Knapsack) - 170 row cuts average 2.9 elements, 0 column cuts (0 active) in 0.100 seconds - new frequency is 1
Cbc0014I Cut generator 3 (Clique) - 0 row cuts average 0.0 elements, 0 column cuts (0 active) in 0.012 seconds - new frequency is -100
Cbc0014I Cut generator 4 (MixedIntegerRounding2) - 285 row cuts average 68.8 elements, 0 column cuts (0 active) in 0.137 seconds - new frequency is 1
Cbc0014I Cut generator 5 (FlowCover) - 26 row cuts average 28.7 elements, 0 column cuts (0 active) in 0.019 seconds - new frequency is -100
Cbc0014I Cut generator 6 (TwoMirCuts) - 723 row cuts average 138.8 elements, 0 column cuts (0 active) in 0.677 seconds - new frequency is -100
Cbc0010I After 0 nodes, 1 on tree, 1e+50 best solution, best possible 497995.24 (43.62 seconds)
Cbc0010I After 100 nodes, 57 on tree, 1e+50 best solution, best possible 497995.24 (59.88 seconds)
Cbc0010I After 200 nodes, 109 on tree, 1e+50 best solution, best possible 497995.24 (64.07 seconds)
Cbc0010I After 300 nodes, 161 on tree, 1e+50 best solution, best possible 497995.24 (68.27 seconds)
Cbc0012I Integer solution of 497995.24 found by rounding after 15921 iterations and 379 nodes (71.58 seconds)
Cbc0038I Full problem 17402 rows 14104 columns, reduced to 0 rows 0 columns
Cbc0001I Search completed - best objective 497995.2442909057, took 15921 iterations and 379 nodes (71.87 seconds)
Cbc0032I Strong branching done 2148 times (28125 iterations), fathomed 0 nodes and fixed 0 variables
Cbc0035I Maximum depth 100, 0 variables fixed on reduced cost
Cuts at root node changed objective from 497995 to 497995
Probing was tried 119 times and created 537 cuts of which 123 were active after adding rounds of cuts (1.734 seconds)
Gomory was tried 119 times and created 1156 cuts of which 0 were active after adding rounds of cuts (1.679 seconds)
Knapsack was tried 119 times and created 219 cuts of which 0 were active after adding rounds of cuts (1.038 seconds)
Clique was tried 10 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.012 seconds)
MixedIntegerRounding2 was tried 119 times and created 374 cuts of which 0 were active after adding rounds of cuts (1.404 seconds)
FlowCover was tried 10 times and created 26 cuts of which 0 were active after adding rounds of cuts (0.019 seconds)
TwoMirCuts was tried 10 times and created 723 cuts of which 0 were active after adding rounds of cuts (0.677 seconds)
ImplicationCuts was tried 15 times and created 16 cuts of which 0 were active after adding rounds of cuts (0.023 seconds)
Result - Optimal solution found
Objective value: 497995.24429091
Enumerated nodes: 379
Total iterations: 15921
Time (CPU seconds): 72.51
Time (Wallclock seconds): 72.80
Total time (CPU seconds): 74.98 (Wallclock seconds): 75.41
+146 -58
View File
@@ -15,56 +15,120 @@ import datetime
import itertools
import operator
weeks_to_rota = 16
use_neos = False
weeks_to_rota = 26
sites = ("truro", "exeter", "torquay", "barnstaple", "plymouth")
Rota = RotaBuilder(datetime.date(2020, 9, 7),
weeks_to_rota=weeks_to_rota,
balance_offset_modifier=1)
balance_offset_modifier=1,
max_weekend_frequency=1,
max_night_frequency=1)
Rota.add_shifts(
# SingleShift(("exeter", ), "exeter_twilight", 12.5, days[:5]),
# # SingleShift(("truro", ),
# # "truro_twilight",
# # 12.5,
# # days[:5],
# # assign_as_block=False),
# #SingleShift(("torquay", ), "torquay_twilight", 12.5, days[:5]),
# #SingleShift(("plymouth", ), "plymouth_twilight", 12.5, days[:5]),
# SingleShift(("exeter", ),
# "weekend_exeter",
# 12.5,
# days[5:],
# assign_as_block=False),
# SingleShift(("truro", ),
# "weekend_truro",
# 12.5,
# days[5:],
# force_as_block=True),
# # SingleShift(("torquay", ),
# # "weekend_torquay",
# # 12.5,
# # days[5:],
# # assign_as_block=True),
# # SingleShift(("plymouth", ),
# # "weekend_plymouth",
# # 8,
# # days[5:],
# # workers_required=2,
# # assign_as_block=True),
# SingleShift((sites),
# "night_weekday",
# 12.25,
# days[:4],
# balance_offset=2,
# balance_weighting=1,
# workers_required=3,
# force_as_block=False,
# rota_on_nwds=True,
# constraints=["night"]),
# SingleShift((sites),
# "night_weekend",
# 12.25,
# days[4:],
# balance_offset=2,
# balance_weighting=1,
# workers_required=3,
# force_as_block=False,
# rota_on_nwds=True,
# constraints=["night"]),
SingleShift(("exeter", ), "exeter_twilight", 12.5, days[:5]),
SingleShift(("truro", ),
"truro_twilight",
12.5,
days[:5],
assign_as_block=False),
#SingleShift(("torquay", ), "torquay_twilight", 12.5, days[:5]),
#SingleShift(("plymouth", ), "plymouth_twilight", 12.5, days[:5]),
SingleShift(("truro", ), "truro_twilight", 12.5, days[:5]),
SingleShift(("torquay", ), "torquay_twilight", 12.5, days[:5]),
SingleShift(("plymouth", ), "plymouth_twilight", 12.5, days[:5]),
SingleShift(("exeter", ),
"weekend_exeter",
12.5,
days[5:],
force_as_block=True),
assign_as_block=True),
SingleShift(("truro", ),
"weekend_truro",
12.5,
days[5:],
assign_as_block=True),
# SingleShift(("torquay", ),
# "weekend_torquay",
# 12.5,
# days[5:],
# assign_as_block=True),
# SingleShift(("plymouth", ),
# "weekend_plymouth",
# 8,
# days[5:],
# workers_required=2,
# assign_as_block=True),
SingleShift((sites),
"night",
12.25,
days,
balance_offset=2,
balance_weighting=1,
workers_required=3,
rota_on_nwds=True,
constraints=["night"]),
SingleShift(("torquay", ),
"weekend_torquay",
12.5,
days[5:],
assign_as_block=True),
SingleShift(("plymouth", ),
"weekend_plymouth",
8,
days[5:],
workers_required=2,
assign_as_block=True),
SingleShift(
(sites),
"night_weekday",
12.25,
days[:4],
balance_offset=4,
balance_weighting=1,
#hard_constrain_shift=False,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
SingleShift(
(sites),
"night_weekend",
12.25,
days[4:],
balance_offset=3,
balance_weighting=1,
#hard_constrain_shift=False,
workers_required=3,
force_as_block=False,
rota_on_nwds=True,
constraints=["night"]),
)
use_test_workers = True
use_test_workers = False
# Import trainee data
if use_test_workers:
@@ -83,29 +147,35 @@ if use_test_workers:
"Truro {}".format(i),
"truro",
4,
) for i in range(2, 14)
) for i in range(1, 9)
])
Rota.add_workers([
Worker(Rota, i, "Plym {}".format(i), "plymouth", 4, 50)
for i in range(9, 17)
])
Rota.add_workers([
Worker(Rota, i, "Plym {}".format(i), "plymouth", 4, 80)
for i in range(17, 19)
])
# Rota.add_workers([
# Worker(Rota, i, "Plym {}".format(i), "plymouth", 4)
# for i in range(16, 30)
# Worker(
# Rota,
# i,
# "Exe {}".format(i),
# "exeter",
# 4,
# ) for i in range(20, 25)
# ])
# Rota.add_workers([
# Worker(
# Rota,
# i,
# "Torq {}".format(i),
# "torquay",
# 2,
# 50,
# ) for i in range(25, 29)
# ])
Rota.add_workers([
Worker(
Rota,
i,
"Exe {}".format(i),
"exeter",
4,
) for i in range(30, 40)
])
Rota.add_workers([
Worker(Rota,
i,
"Torq {}".format(i),
"torquay",
2,
pref_not_to_work=(("2020/09/07"), )) for i in range(50, 60)
])
else:
import csv
with open('trainees.csv', newline='') as f:
@@ -119,7 +189,7 @@ else:
name, site, grade, fte, nwd, end_date, oop, extra = row
# Ignore trainees if fte == 0 (what are they doing here anyway)
if fte == 0:
if int(fte) < 1:
continue
nwds = nwd.split(",").title() if nwd else None
@@ -130,6 +200,13 @@ else:
Worker(Rota, n, name, site.lower(), int(grade[2]), int(fte),
nwds, end_date, oop))
Rota.constraint_options["limit_to_1_st1_on_nights"] = True
Rota.constraint_options["balance_nights"] = True
Rota.constraint_options["constrain_time_off_after_nights"] = True
Rota.constraint_options["balance_nights_across_sites"] = False
Rota.constraint_options["balance_blocks"] = False
Rota.constraint_options["balance_weekends"] = True
print(0)
Rota.build_shifts_and_workers()
@@ -140,11 +217,19 @@ opt = SolverFactory('cbc') # choose a solver
#opt = SolverFactory('ipopt') # choose a solver
print(2)
results = opt.solve(
Rota.model, tee=True, options={
"seconds": 1200,
"allow": 70000
}) # solve the model with the, options="seconds=60" selected solver
if use_neos:
solver_manager = SolverManagerFactory('neos') # Solve in neos server
results = solver_manager.solve(Rota.model, opt=opt, logfile="test.log")
else:
results = opt.solve(
Rota.model,
tee=True,
options={
"seconds": 1200,
"allow": 4000,
},
logfile="test.log"
) # solve the model with the, options="seconds=60" selected solver
print(results)
results.solver.status
@@ -156,9 +241,12 @@ ResultsHolder = RotaResults(Rota, results)
week_table = ResultsHolder.get_work_table() # list with the required workers
worker_timetable = ResultsHolder.get_worker_timetable()
worker_timetable_brief = ResultsHolder.get_worker_timetable_brief(
show_prefs=False)
show_prefs=False, show_unavailable=False)
print(worker_timetable_brief)
print(Rota.get_workers_total_fte())
ResultsHolder.get_night_details()
# for i in ResultsHolder.rota.model.blocks_worker_shift_count:
# n = ResultsHolder.rota.model.blocks_worker_shift_count[i].value
+1
View File
@@ -53,6 +53,7 @@ class Worker:
end_oop_date = datetime.datetime.strptime(end_oop,
"%Y/%m/%d").date()
print(start_oop_date, end_oop_date)
if end_oop_date > Rota.rota_end_date:
end_oop_date = Rota.rota_end_date