Descent Solver: Completed - Taboo Solver: Completed

This commit is contained in:
AlexJavor 2020-05-10 21:07:42 +02:00
parent f306a8c7f6
commit 5fe1352f2d
20 changed files with 1824 additions and 1306 deletions

144
Solvers-Results.txt Normal file
View file

@ -0,0 +1,144 @@
basic random
instance size best runtime makespan ecart runtime makespan ecart
aaa1 2x3 11 1 12 9.1 999 11 0.0
ft06 6x6 55 0 60 9.1 999 55 0.0
ft10 10x10 930 0 1319 41.8 999 1209 30.0
ft20 20x5 1165 0 1672 43.5 999 1529 31.2
la01 10x5 666 0 858 28.8 999 701 5.3
la02 10x5 655 0 904 38.0 999 729 11.3
la03 10x5 597 0 775 29.8 999 673 12.7
la04 10x5 590 0 854 44.7 999 667 13.1
la05 10x5 593 0 629 6.1 999 593 0.0
la06 15x5 926 0 1015 9.6 999 943 1.8
la07 15x5 890 0 1096 23.1 999 981 10.2
la08 15x5 863 0 1102 27.7 999 944 9.4
la09 15x5 951 0 1024 7.7 999 964 1.4
AVG - - 0.1 - 24.5 999.0 - 9.7
Greedy-SPT Greedy-LRPT Greedy-EST_SPT Greedy-EST_LRPT
instance size best runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart
aaa1 2x3 11 6 16 45.5 0 11 0.0 0 11 0.0 1 11 0.0
ft06 6x6 55 2 108 96.4 2 74 34.5 1 88 60.0 1 61 10.9
ft10 10x10 930 3 2569 176.2 2 1289 38.6 2 1074 15.5 2 1108 19.1
ft20 20x5 1165 3 2765 137.3 3 1955 67.8 2 1267 8.8 1 1501 28.8
la01 10x5 666 1 1464 119.8 0 845 26.9 1 751 12.8 1 735 10.4
la02 10x5 655 1 1943 196.6 0 982 49.9 0 821 25.3 1 817 24.7
la03 10x5 597 1 1053 76.4 0 797 33.5 0 672 12.6 0 696 16.6
la04 10x5 590 1 1491 152.7 0 1000 69.5 1 711 20.5 0 758 28.5
la05 10x5 593 0 1521 156.5 0 666 12.3 0 610 2.9 0 593 0.0
la06 15x5 926 1 2372 156.2 1 1151 24.3 0 1200 29.6 0 926 0.0
la07 15x5 890 1 1823 104.8 1 1108 24.5 1 1034 16.2 1 970 9.0
la08 15x5 863 0 2309 167.6 0 1196 38.6 1 942 9.2 1 943 9.3
la09 15x5 951 0 2638 177.4 0 1233 29.7 0 1045 9.9 1 1015 6.7
AVG - - 1.5 - 135.6 0.7 - 34.6 0.7 - 17.2 0.8 - 12.6
Descent-SPT Descent-LRPT Descent-EST_SPT Descent-EST_LRPT
instance size best runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart
aaa1 2x3 11 14 11 0.0 1 11 0.0 1 11 0.0 1 11 0.0
ft06 6x6 55 21 65 18.2 4 58 5.5 5 72 30.9 3 55 0.0
ft10 10x10 930 66 1379 48.3 23 1073 15.4 5 1017 9.4 2 1108 19.1
ft20 20x5 1165 79 1574 35.1 31 1513 29.9 1 1267 8.8 1 1501 28.8
la01 10x5 666 11 907 36.2 4 666 0.0 2 686 3.0 4 695 4.4
la02 10x5 655 8 869 32.7 2 806 23.1 3 685 4.6 1 782 19.4
la03 10x5 597 2 877 46.9 1 725 21.4 0 666 11.6 1 696 16.6
la04 10x5 590 6 852 44.4 2 794 34.6 1 702 19.0 0 747 26.6
la05 10x5 593 12 742 25.1 2 621 4.7 0 610 2.9 0 593 0.0
la06 15x5 926 11 1348 45.6 3 952 2.8 2 963 4.0 0 926 0.0
la07 15x5 890 14 1087 22.1 3 965 8.4 0 1034 16.2 5 923 3.7
la08 15x5 863 20 1320 53.0 2 1082 25.4 0 933 8.1 0 909 5.3
la09 15x5 951 29 1433 50.7 3 1084 14.0 1 975 2.5 1 985 3.6
AVG - - 22.5 - 35.2 6.2 - 14.2 1.6 - 9.3 1.5 - 9.8
Taboo-EST_LRPT(1,1)
instance size best runtime makespan ecart
aaa1 2x3 11 17 11 0.0
ft06 6x6 55 20 57 3.6
ft10 10x10 930 13 1108 19.1
ft20 20x5 1165 9 1501 28.8
la01 10x5 666 4 695 4.4
la02 10x5 655 3 803 22.6
la03 10x5 597 2 696 16.6
la04 10x5 590 2 747 26.6
la05 10x5 593 1 593 0.0
la06 15x5 926 2 926 0.0
la07 15x5 890 3 951 6.9
la08 15x5 863 12 909 5.3
la09 15x5 951 2 985 3.6
AVG - - 6.9 - 10.6
Taboo-EST_LRPT(1,10) Taboo-EST_LRPT(2,10) Taboo-EST_LRPT(3,10) Taboo-EST_LRPT(4,10) Taboo-EST_LRPT(5,10) Taboo-EST_LRPT(6,10) Taboo-EST_LRPT(7,10) Taboo-EST_LRPT(8,10) Taboo-EST_LRPT(9,10) Taboo-EST_LRPT(10,10)
instance size best runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart
aaa1 2x3 11 25 11 0.0 4 11 0.0 4 11 0.0 2 11 0.0 2 11 0.0 2 11 0.0 2 11 0.0 1 11 0.0 2 11 0.0 3 11 0.0
ft06 6x6 55 14 55 0.0 11 55 0.0 11 55 0.0 7 55 0.0 8 55 0.0 7 55 0.0 6 55 0.0 16 55 0.0 4 55 0.0 4 55 0.0
ft10 10x10 930 21 1108 19.1 23 1108 19.1 19 1096 17.8 14 1108 19.1 19 1108 19.1 14 1108 19.1 12 1108 19.1 11 1108 19.1 11 1108 19.1 11 1108 19.1
ft20 20x5 1165 7 1501 28.8 7 1465 25.8 8 1465 25.8 15 1465 25.8 5 1465 25.8 4 1465 25.8 5 1465 25.8 5 1465 25.8 5 1465 25.8 5 1465 25.8
la01 10x5 666 4 695 4.4 2 692 3.9 3 692 3.9 2 692 3.9 3 692 3.9 2 692 3.9 2 692 3.9 2 692 3.9 2 692 3.9 2 692 3.9
la02 10x5 655 3 769 17.4 3 769 17.4 3 769 17.4 2 753 15.0 2 753 15.0 3 753 15.0 3 753 15.0 2 753 15.0 2 753 15.0 3 753 15.0
la03 10x5 597 2 692 15.9 2 692 15.9 6 689 15.4 2 689 15.4 2 692 15.9 4 692 15.9 3 692 15.9 2 692 15.9 3 692 15.9 2 692 15.9
la04 10x5 590 3 696 18.0 2 696 18.0 3 696 18.0 2 696 18.0 2 702 19.0 2 703 19.2 2 703 19.2 1 694 17.6 2 694 17.6 2 694 17.6
la05 10x5 593 3 593 0.0 2 593 0.0 1 593 0.0 1 593 0.0 1 593 0.0 1 593 0.0 1 593 0.0 1 593 0.0 1 593 0.0 1 593 0.0
la06 15x5 926 2 926 0.0 2 926 0.0 2 926 0.0 2 926 0.0 2 926 0.0 2 926 0.0 1 926 0.0 3 926 0.0 2 926 0.0 1 926 0.0
la07 15x5 890 7 912 2.5 5 912 2.5 4 912 2.5 8 912 2.5 4 912 2.5 4 912 2.5 5 912 2.5 4 912 2.5 4 912 2.5 4 912 2.5
la08 15x5 863 4 902 4.5 4 902 4.5 5 902 4.5 4 902 4.5 8 902 4.5 6 902 4.5 5 902 4.5 4 902 4.5 3 902 4.5 3 902 4.5
la09 15x5 951 3 951 0.0 2 951 0.0 3 951 0.0 15 985 3.6 6 985 3.6 5 951 0.0 4 951 0.0 4 951 0.0 4 951 0.0 6 951 0.0
AVG - - 7.5 - 8.5 5.3 - 8.2 5.5 - 8.1 5.8 - 8.3 4.9 - 8.4 4.3 - 8.1 3.9 - 8.1 4.3 - 8.0 3.5 - 8.0 3.6 - 8.0
Taboo-EST_LRPT(1,100) Taboo-EST_LRPT(6,100) Taboo-EST_LRPT(8,100) Taboo-EST_LRPT(10,100) Taboo-EST_LRPT(12,100) Taboo-EST_LRPT(14,100) Taboo-EST_LRPT(20,100) Taboo-EST_LRPT(50,100) Taboo-EST_LRPT(100,100)
instance size best runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart
aaa1 2x3 11 48 11 0.0 13 11 0.0 9 11 0.0 6 11 0.0 5 11 0.0 5 11 0.0 3 11 0.0 2 11 0.0 3 11 0.0
ft06 6x6 55 43 55 0.0 36 55 0.0 27 55 0.0 20 55 0.0 20 55 0.0 15 55 0.0 17 55 0.0 10 55 0.0 6 55 0.0
ft10 10x10 930 95 1108 19.1 63 1037 11.5 59 1041 11.9 52 1032 11.0 60 1048 12.7 82 1046 12.5 55 1054 13.3 48 1098 18.1 34 1098 18.1
ft20 20x5 1165 42 1501 28.8 40 1329 14.1 41 1329 14.1 46 1311 12.5 37 1325 13.7 43 1329 14.1 51 1352 16.1 23 1399 20.1 18 1400 20.2
la01 10x5 666 23 695 4.4 9 666 0.0 7 666 0.0 19 666 0.0 16 690 3.6 13 688 3.3 15 671 0.8 8 690 3.6 6 692 3.9
la02 10x5 655 34 737 12.5 17 722 10.2 22 694 6.0 15 706 7.8 16 732 11.8 13 736 12.4 11 736 12.4 9 736 12.4 11 745 13.7
la03 10x5 597 21 692 15.9 21 651 9.0 21 676 13.2 17 637 6.7 15 678 13.6 16 670 12.2 14 617 3.4 10 648 8.5 7 692 15.9
la04 10x5 590 21 696 18.0 22 638 8.1 26 646 9.5 23 648 9.8 14 639 8.3 14 651 10.3 12 647 9.7 9 674 14.2 5 674 14.2
la05 10x5 593 11 593 0.0 8 593 0.0 8 593 0.0 5 593 0.0 5 593 0.0 5 593 0.0 4 593 0.0 4 593 0.0 5 593 0.0
la06 15x5 926 31 926 0.0 11 926 0.0 8 926 0.0 8 926 0.0 8 926 0.0 8 926 0.0 11 926 0.0 7 926 0.0 7 926 0.0
la07 15x5 890 33 890 0.0 14 890 0.0 13 890 0.0 17 890 0.0 11 890 0.0 15 890 0.0 11 890 0.0 10 890 0.0 11 890 0.0
la08 15x5 863 30 902 4.5 22 863 0.0 25 866 0.3 23 863 0.0 24 863 0.0 21 863 0.0 14 863 0.0 13 878 1.7 8 902 4.5
la09 15x5 951 15 951 0.0 11 951 0.0 11 951 0.0 9 951 0.0 8 951 0.0 9 951 0.0 23 951 0.0 13 951 0.0 13 951 0.0
AVG - - 34.4 - 7.9 22.1 - 4.1 21.3 - 4.2 20.0 - 3.7 18.4 - 4.9 19.9 - 5.0 18.5 - 4.3 12.8 - 6.0 10.3 - 7.0
Taboo-EST_LRPT(1,1000) Taboo-EST_LRPT(6,1000) Taboo-EST_LRPT(8,1000) Taboo-EST_LRPT(10,1000) Taboo-EST_LRPT(12,1000) Taboo-EST_LRPT(14,1000) Taboo-EST_LRPT(20,1000) Taboo-EST_LRPT(50,1000) Taboo-EST_LRPT(100,1000)
instance size best runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart
aaa1 2x3 11 99 11 0.0 24 11 0.0 23 11 0.0 25 11 0.0 24 11 0.0 21 11 0.0 18 11 0.0 14 11 0.0 12 11 0.0
ft06 6x6 55 160 55 0.0 137 55 0.0 133 55 0.0 99 55 0.0 103 55 0.0 76 55 0.0 73 55 0.0 49 55 0.0 55 55 0.0
ft10 10x10 930 583 1108 19.1 622 1013 8.9 569 983 5.7 541 978 5.2 573 978 5.2 530 1007 8.3 535 1029 10.6 360 1045 12.4 251 1015 9.1
ft20 20x5 1165 383 1501 28.8 396 1217 4.5 438 1262 8.3 366 1243 6.7 294 1255 7.7 321 1218 4.5 302 1219 4.6 209 1246 7.0 168 1271 9.1
la01 10x5 666 196 695 4.4 61 666 0.0 52 666 0.0 64 666 0.0 65 666 0.0 76 666 0.0 68 666 0.0 52 666 0.0 54 666 0.0
la02 10x5 655 244 737 12.5 170 667 1.8 177 665 1.5 158 665 1.5 142 662 1.1 134 655 0.0 108 671 2.4 69 692 5.6 58 720 9.9
la03 10x5 597 165 692 15.9 133 628 5.2 152 620 3.9 143 603 1.0 140 603 1.0 130 603 1.0 108 603 1.0 76 615 3.0 56 615 3.0
la04 10x5 590 203 696 18.0 129 638 8.1 160 598 1.4 151 599 1.5 148 604 2.4 75 637 8.0 104 597 1.2 91 620 5.1 72 620 5.1
la05 10x5 593 93 593 0.0 56 593 0.0 59 593 0.0 49 593 0.0 49 593 0.0 45 593 0.0 45 593 0.0 45 593 0.0 40 593 0.0
la06 15x5 926 169 926 0.0 90 926 0.0 80 926 0.0 82 926 0.0 77 926 0.0 72 926 0.0 76 926 0.0 64 926 0.0 65 926 0.0
la07 15x5 890 164 890 0.0 92 890 0.0 94 890 0.0 84 890 0.0 82 890 0.0 79 890 0.0 81 890 0.0 69 890 0.0 72 890 0.0
la08 15x5 863 326 902 4.5 103 863 0.0 105 863 0.0 90 863 0.0 92 863 0.0 82 863 0.0 82 863 0.0 72 863 0.0 72 863 0.0
la09 15x5 951 151 951 0.0 85 951 0.0 81 951 0.0 80 951 0.0 79 951 0.0 78 951 0.0 78 951 0.0 78 951 0.0 62 951 0.0
AVG - - 225.8 - 7.9 161.4 - 2.2 163.3 - 1.6 148.6 - 1.2 143.7 - 1.3 132.2 - 1.7 129.1 - 1.5 96.0 - 2.5 79.8 - 2.8
Taboo-EST_LRPT(1,5000) Taboo-EST_LRPT(6,5000) Taboo-EST_LRPT(8,5000) Taboo-EST_LRPT(10,5000) Taboo-EST_LRPT(12,5000) Taboo-EST_LRPT(14,5000) Taboo-EST_LRPT(20,5000) Taboo-EST_LRPT(50,5000) Taboo-EST_LRPT(100,5000)
instance size best runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart runtime makespan ecart
aaa1 2x3 11 265 11 0.0 101 11 0.0 40 11 0.0 34 11 0.0 35 11 0.0 27 11 0.0 38 11 0.0 25 11 0.0 30 11 0.0
ft06 6x6 55 675 55 0.0 665 55 0.0 405 55 0.0 504 55 0.0 489 55 0.0 329 55 0.0 286 55 0.0 267 55 0.0 222 55 0.0
ft10 10x10 930 1000 1108 19.1 1000 1002 7.7 1000 954 2.6 1000 978 5.2 1000 976 4.9 1000 995 7.0 1000 1007 8.3 1000 1036 11.4 1000 1015 9.1
ft20 20x5 1165 1000 1501 28.8 1000 1217 4.5 1000 1262 8.3 1000 1193 2.4 1000 1255 7.7 1000 1192 2.3 1000 1187 1.9 1000 1189 2.1 699 1240 6.4
la01 10x5 666 999 695 4.4 320 666 0.0 278 666 0.0 273 666 0.0 274 666 0.0 280 666 0.0 255 666 0.0 240 666 0.0 242 666 0.0
la02 10x5 655 1000 737 12.5 959 667 1.8 722 660 0.8 612 655 0.0 604 658 0.5 620 655 0.0 473 655 0.0 420 660 0.8 329 669 2.1
la03 10x5 597 891 692 15.9 510 628 5.2 690 605 1.3 380 603 1.0 690 603 1.0 329 603 1.0 440 603 1.0 414 615 3.0 278 615 3.0
la04 10x5 590 1000 696 18.0 710 638 8.1 677 598 1.4 382 599 1.5 477 602 2.0 339 637 8.0 381 597 1.2 446 598 1.4 332 616 4.4
la05 10x5 593 504 593 0.0 302 593 0.0 278 593 0.0 271 593 0.0 250 593 0.0 249 593 0.0 252 593 0.0 214 593 0.0 223 593 0.0
la06 15x5 926 794 926 0.0 471 926 0.0 412 926 0.0 417 926 0.0 406 926 0.0 391 926 0.0 367 926 0.0 360 926 0.0 338 926 0.0
la07 15x5 890 787 890 0.0 462 890 0.0 477 890 0.0 474 890 0.0 474 890 0.0 421 890 0.0 395 890 0.0 373 890 0.0 381 890 0.0
la08 15x5 863 1000 902 4.5 473 863 0.0 455 863 0.0 445 863 0.0 421 863 0.0 411 863 0.0 387 863 0.0 372 863 0.0 351 863 0.0
la09 15x5 951 786 951 0.0 482 951 0.0 453 951 0.0 426 951 0.0 406 951 0.0 392 951 0.0 388 951 0.0 367 951 0.0 357 951 0.0
AVG - - 823.2 - 7.9 573.5 - 2.1 529.8 - 1.1 478.3 - 0.8 502.0 - 1.2 445.2 - 1.4 435.5 - 1.0 422.9 - 1.4 367.8 - 1.9

View file

@ -1,5 +1,5 @@
# Example instance
3 3 # num-jobs num-tasks
2 3 0 3 1 2
2 4 0 3 1 2
1 7 0 6 2 5
0 2 1 10 2 4

5
instances/aaa3 Normal file
View file

@ -0,0 +1,5 @@
# Example instance
3 3 # num-jobs num-tasks
1 4 2 3 0 2
1 7 0 6 2 5
0 2 1 10 2 4

View file

@ -2,6 +2,8 @@ package jobshop;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class BestKnownResult {
@ -9,6 +11,13 @@ public class BestKnownResult {
return bests.containsKey(instanceName);
}
public static List<String> instancesMatching(String namePrefix) {
return Arrays.stream(instances)
.filter(i -> i.startsWith(namePrefix))
.sorted()
.collect(Collectors.toList());
}
public static int of(String instanceName) {
if(!bests.containsKey(instanceName)) {
throw new RuntimeException("Unknown best result for "+instanceName);

View file

@ -4,10 +4,12 @@ import jobshop.encodings.JobNumbers;
import jobshop.encodings.ResourceOrder;
import jobshop.encodings.Task;
import jobshop.solvers.DescentSolver;
import jobshop.solvers.GreedySolver;
import jobshop.solvers.DescentSolver.Block;
import jobshop.solvers.DescentSolver.Swap;
import jobshop.solvers.GreedySolver;
import jobshop.solvers.GreedySolver.PriorityESTRule;
import jobshop.solvers.GreedySolver.PriorityRule;
import jobshop.solvers.TabooSolver;
import java.io.IOException;
import java.nio.file.Paths;
@ -26,19 +28,20 @@ public class DebuggingMain {
// mais on commençait à compter à 1 ce qui donnait [1 2 2 1 1 2]
JobNumbers enc = new JobNumbers(instance);
enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 1;
System.out.println("\nJOB NUMBER ENCODING: " + enc + "\n");
System.out.println("\nENCODING: " + enc);
Schedule sched = enc.toSchedule();
System.out.println("SCHEDULE:\n" + sched);
System.out.println("VALID: " + sched.isValid() + "\n");
System.out.println("MAKESPAN: " + sched.makespan() + "\n");
// TODO: make it print something meaningful
// by implementing the toString() method
System.out.println("SCHEDULE: " + sched);
System.out.println("VALID: " + sched.isValid());
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("---------------------------------------------\n");
@ -81,8 +84,8 @@ public class DebuggingMain {
System.out.println("---------------------------------------------\n");
JobNumbers jo = JobNumbers.fromSchedule(sched);
System.out.println("JOB NUMBER ENCODING (FROM_SCHEDULE): " + jo + "\n");
/*JobNumbers jo = JobNumbers.fromSchedule(sched);
System.out.println("JOB NUMBER ENCODING (FROM_SCHEDULE): " + jo + "\n");*/
System.out.println("---------------------------------------------\n");
System.out.println("Greedy Solver: STP");
@ -118,10 +121,9 @@ public class DebuggingMain {
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("---------------------------------------------\n");
System.out.println("Greedy Solver: ic void applyOn(ResourceOrder order) {\r\n" +
" throw new UnsupportedOperationException();EST_SPT\n");
System.out.println("Greedy Solver: EST_LRPT\n");
PriorityESTRule EST_LRPT = PriorityESTRule.EST_LRPT;
Solver solverEST_LRPT = new GreedySolver(EST_SPT);
Solver solverEST_LRPT = new GreedySolver(EST_LRPT);
Result resultEST_LRPT = solverEST_LRPT.solve(instance, System.currentTimeMillis() + 10);
sched = resultEST_LRPT.schedule;
@ -130,19 +132,53 @@ public class DebuggingMain {
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("---------------------------------------------\n");
System.out.println("Descent Solver: \n");
DescentSolver solverDescent = new DescentSolver();
System.out.println("Descent Solver: [Executed with EST_LRPT]\n");
DescentSolver solverDescent = new DescentSolver(EST_LRPT);
System.out.print("****** TEST: blocksOfCriticalPath() ******\n");
System.out.print("Number of Jobs : " + instance2.numJobs + "\n");
System.out.print("Number of Tasks : " + instance2.numTasks + "\n");
System.out.print("Number of Machines : " + instance2.numMachines + "\n\n");
List<Block> criticalBlockList = solverDescent.blocksOfCriticalPath(ro2);
for(Block b : criticalBlockList) {
System.out.println(b);
//System.out.println(solverDescent.neighbors(b));
for(Swap s : solverDescent.neighbors(b)) {
System.out.println(s);
}
}
/*
sched = ro2.toSchedule();
System.out.print("******************************************\n");
Result resultDescent = solverDescent.solve(instance2, System.currentTimeMillis() + 10);
sched = resultDescent.schedule;
System.out.println("SCHEDULE:\n" + sched);
System.out.println("VALID: " + sched.isValid());
System.out.println("MAKESPAN: " + sched.makespan());*/
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("---------------------------------------------\n");
System.out.println("Taboo Solver: [Executed with EST_LRPT]\n");
TabooSolver solverTaboo = new TabooSolver(EST_LRPT, 50, 1000);
Result resultTaboo = solverTaboo.solve(instance2, System.currentTimeMillis() + 10);
sched = resultTaboo.schedule;
/*
List<Block>criticalBlockList2 = solverTaboo.blocksOfCriticalPath(ro2);
for(Block b : criticalBlockList2) {
System.out.println(b);
for(Swap s : solverTaboo.neighbors(b)) {
System.out.println(s);
}
}
*/
System.out.println("SCHEDULE:\n" + sched);
System.out.println("VALID: " + sched.isValid());
System.out.println("MAKESPAN: " + sched.makespan());
} catch (IOException e) {
e.printStackTrace();

View file

@ -1,5 +1,7 @@
package jobshop;
import jobshop.encodings.Task;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -24,9 +26,15 @@ public class Instance {
public int duration(int job, int task) {
return durations[job][task];
}
public int duration(Task t) {
return duration(t.job, t.task);
}
public int machine(int job, int task) {
return machines[job][task];
}
public int machine(Task t) {
return this.machine(t.job, t.task);
}
/** among the tasks of the given job, returns the task index that uses the given machine. */
public int task_with_machine(int job, int wanted_machine) {
@ -46,6 +54,7 @@ public class Instance {
machines = new int[numJobs][numTasks];
}
/** Parses a instance from a file. */
public static Instance fromFile(Path path) throws IOException {
Iterator<String> lines = Files.readAllLines(path).stream()
.filter(l -> !l.startsWith("#"))
@ -63,11 +72,8 @@ public class Instance {
pb.machines[job][task] = line.nextInt();
pb.durations[job][task] = line.nextInt();
}
line.close();
}
header.close();
return pb;
}
}

View file

@ -3,16 +3,15 @@ package jobshop;
import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import jobshop.solvers.BasicSolver;
import jobshop.solvers.RandomSolver;
import jobshop.solvers.*;
import jobshop.solvers.GreedySolver.PriorityESTRule;
import jobshop.solvers.GreedySolver.PriorityRule;
import jobshop.solvers.GreedySolver;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
@ -20,26 +19,93 @@ import net.sourceforge.argparse4j.inf.Namespace;
public class Main {
// ******************************************** Main - Arguments ************************************************ //
// *** Basic + Random *** //
// --solver basic random --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
/** All solvers available in this program */
// *** Greedy Solvers *** //
// --solver Greedy-SPT Greedy-LRPT Greedy-EST_SPT Greedy-EST_LRPT --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
// *** Descent Solvers *** //
// --solver Descent-SPT Descent-LRPT Descent-EST_SPT Descent-EST_LRPT --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
// *** Taboo Solvers *** //
// --solver Taboo-EST_LRPT(1,1) --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
// --solver Taboo-EST_LRPT(1,10) Taboo-EST_LRPT(2,10) Taboo-EST_LRPT(3,10) Taboo-EST_LRPT(4,10) Taboo-EST_LRPT(5,10) Taboo-EST_LRPT(6,10) Taboo-EST_LRPT(7,10) Taboo-EST_LRPT(8,10) Taboo-EST_LRPT(9,10) Taboo-EST_LRPT(10,10) --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
// --solver Taboo-EST_LRPT(1,100) Taboo-EST_LRPT(6,100) Taboo-EST_LRPT(8,100) Taboo-EST_LRPT(10,100) Taboo-EST_LRPT(12,100) Taboo-EST_LRPT(14,100) Taboo-EST_LRPT(20,100) Taboo-EST_LRPT(50,100) Taboo-EST_LRPT(100,100) --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
// --solver Taboo-EST_LRPT(1,1000) Taboo-EST_LRPT(6,1000) Taboo-EST_LRPT(8,1000) Taboo-EST_LRPT(10,1000) Taboo-EST_LRPT(12,1000) Taboo-EST_LRPT(14,1000) Taboo-EST_LRPT(20,1000) Taboo-EST_LRPT(50,1000) Taboo-EST_LRPT(100,1000) --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
// --solver Taboo-EST_LRPT(1,5000) Taboo-EST_LRPT(6,5000) Taboo-EST_LRPT(8,5000) Taboo-EST_LRPT(10,5000) Taboo-EST_LRPT(12,5000) Taboo-EST_LRPT(14,5000) Taboo-EST_LRPT(20,5000) Taboo-EST_LRPT(50,5000) Taboo-EST_LRPT(100,5000) --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
/** All solvers available in this program */
private static HashMap<String, Solver> solvers;
static {
solvers = new HashMap<>();
solvers.put("basic", new BasicSolver());
solvers.put("random", new RandomSolver());
// add new solvers here
// Add new solvers here
// ******************** Greedy Solver ******************** //
PriorityRule SPT = PriorityRule.SPT;
solvers.put("greedySPT", new GreedySolver(SPT));
solvers.put("Greedy-SPT", new GreedySolver(SPT));
PriorityRule LRPT = PriorityRule.LRPT;
solvers.put("greedyLRPT", new GreedySolver(LRPT));
solvers.put("Greedy-LRPT", new GreedySolver(LRPT));
PriorityESTRule EST_SPT = PriorityESTRule.EST_SPT;
solvers.put("greedyEST_SPT", new GreedySolver(EST_SPT));
solvers.put("Greedy-EST_SPT", new GreedySolver(EST_SPT));
PriorityESTRule EST_LRPT = PriorityESTRule.EST_LRPT;
solvers.put("greedyEST_LRPT", new GreedySolver(EST_LRPT));
solvers.put("Greedy-EST_LRPT", new GreedySolver(EST_LRPT));
// ******************* Descent Solver ******************** //
solvers.put("Descent-SPT", new DescentSolver(SPT));
solvers.put("Descent-LRPT", new DescentSolver(LRPT));
solvers.put("Descent-EST_SPT", new DescentSolver(EST_SPT));
solvers.put("Descent-EST_LRPT", new DescentSolver(EST_LRPT));
// ******************** Taboo Solver ********************* //
solvers.put("Taboo-EST_LRPT(1,1)", new TabooSolver(EST_LRPT, 1, 1));
solvers.put("Taboo-EST_LRPT(1,10)", new TabooSolver(EST_LRPT, 1, 10));
solvers.put("Taboo-EST_LRPT(2,10)", new TabooSolver(EST_LRPT, 2, 10));
solvers.put("Taboo-EST_LRPT(3,10)", new TabooSolver(EST_LRPT, 3, 10));
solvers.put("Taboo-EST_LRPT(4,10)", new TabooSolver(EST_LRPT, 4, 10));
solvers.put("Taboo-EST_LRPT(5,10)", new TabooSolver(EST_LRPT, 5, 10));
solvers.put("Taboo-EST_LRPT(6,10)", new TabooSolver(EST_LRPT, 6, 10));
solvers.put("Taboo-EST_LRPT(7,10)", new TabooSolver(EST_LRPT, 7, 10));
solvers.put("Taboo-EST_LRPT(8,10)", new TabooSolver(EST_LRPT, 8, 10));
solvers.put("Taboo-EST_LRPT(9,10)", new TabooSolver(EST_LRPT, 9, 10));
solvers.put("Taboo-EST_LRPT(10,10)", new TabooSolver(EST_LRPT, 10, 10));
solvers.put("Taboo-EST_LRPT(1,100)", new TabooSolver(EST_LRPT, 1, 100));
solvers.put("Taboo-EST_LRPT(6,100)", new TabooSolver(EST_LRPT, 6, 100));
solvers.put("Taboo-EST_LRPT(8,100)", new TabooSolver(EST_LRPT, 8, 100));
solvers.put("Taboo-EST_LRPT(10,100)", new TabooSolver(EST_LRPT, 10, 100));
solvers.put("Taboo-EST_LRPT(12,100)", new TabooSolver(EST_LRPT, 12, 100));
solvers.put("Taboo-EST_LRPT(14,100)", new TabooSolver(EST_LRPT, 14, 100));
solvers.put("Taboo-EST_LRPT(20,100)", new TabooSolver(EST_LRPT, 20, 100));
solvers.put("Taboo-EST_LRPT(50,100)", new TabooSolver(EST_LRPT, 50, 100));
solvers.put("Taboo-EST_LRPT(100,100)", new TabooSolver(EST_LRPT, 100, 100));
solvers.put("Taboo-EST_LRPT(1,1000)", new TabooSolver(EST_LRPT, 1, 1000));
solvers.put("Taboo-EST_LRPT(6,1000)", new TabooSolver(EST_LRPT, 6, 1000));
solvers.put("Taboo-EST_LRPT(8,1000)", new TabooSolver(EST_LRPT, 8, 1000));
solvers.put("Taboo-EST_LRPT(10,1000)", new TabooSolver(EST_LRPT, 10, 1000));
solvers.put("Taboo-EST_LRPT(12,1000)", new TabooSolver(EST_LRPT, 12, 1000));
solvers.put("Taboo-EST_LRPT(14,1000)", new TabooSolver(EST_LRPT, 14, 1000));
solvers.put("Taboo-EST_LRPT(20,1000)", new TabooSolver(EST_LRPT, 20, 1000));
solvers.put("Taboo-EST_LRPT(50,1000)", new TabooSolver(EST_LRPT, 50, 1000));
solvers.put("Taboo-EST_LRPT(100,1000)", new TabooSolver(EST_LRPT, 100, 1000));
solvers.put("Taboo-EST_LRPT(1,5000)", new TabooSolver(EST_LRPT, 1, 5000));
solvers.put("Taboo-EST_LRPT(6,5000)", new TabooSolver(EST_LRPT, 6, 5000));
solvers.put("Taboo-EST_LRPT(8,5000)", new TabooSolver(EST_LRPT, 8, 5000));
solvers.put("Taboo-EST_LRPT(10,5000)", new TabooSolver(EST_LRPT, 10, 5000));
solvers.put("Taboo-EST_LRPT(12,5000)", new TabooSolver(EST_LRPT, 12, 5000));
solvers.put("Taboo-EST_LRPT(14,5000)", new TabooSolver(EST_LRPT, 14, 5000));
solvers.put("Taboo-EST_LRPT(20,5000)", new TabooSolver(EST_LRPT, 20, 5000));
solvers.put("Taboo-EST_LRPT(50,5000)", new TabooSolver(EST_LRPT, 50, 5000));
solvers.put("Taboo-EST_LRPT(100,5000)", new TabooSolver(EST_LRPT, 100, 5000));
}
@SuppressWarnings("unused")
public static void main(String[] args) {
public static void main(String[] args) {
ArgumentParser parser = ArgumentParsers.newFor("jsp-solver").build()
.defaultHelp(true)
.description("Solves jobshop problems.");
@ -79,20 +145,23 @@ public class Main {
System.exit(1);
}
}
List<String> instances = ns.<String>getList("instance");
for(String instanceName : instances) {
if(!BestKnownResult.isKnown(instanceName)) {
System.err.println("ERROR: instance \"" + instanceName + "\" is not avalaible.");
List<String> instancePrefixes = ns.getList("instance");
List<String> instances = new ArrayList<>();
for(String instancePrefix : instancePrefixes) {
List<String> matches = BestKnownResult.instancesMatching(instancePrefix);
if(matches.isEmpty()) {
System.err.println("ERROR: instance prefix \"" + instancePrefix + "\" does not match any instance.");
System.err.println(" available instances: " + Arrays.toString(BestKnownResult.instances));
System.exit(1);
}
instances.addAll(matches);
}
float[] runtimes = new float[solversToTest.size()];
float[] distances = new float[solversToTest.size()];
try {
output.print( " ");;
output.print( " ");
for(String s : solversToTest)
output.printf("%-30s", s);
output.println();
@ -103,46 +172,46 @@ public class Main {
output.println();
for(String instanceName : instances) {
int bestKnown = BestKnownResult.of(instanceName);
for(String instanceName : instances) {
int bestKnown = BestKnownResult.of(instanceName);
Path path = Paths.get("instances/", instanceName);
Instance instance = Instance.fromFile(path);
Path path = Paths.get("instances/", instanceName);
Instance instance = Instance.fromFile(path);
output.printf("%-8s %-5s %4d ",instanceName, instance.numJobs +"x"+instance.numTasks, bestKnown);
output.printf("%-8s %-5s %4d ",instanceName, instance.numJobs +"x"+instance.numTasks, bestKnown);
for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) {
String solverName = solversToTest.get(solverId);
Solver solver = solvers.get(solverName);
long start = System.currentTimeMillis();
long deadline = System.currentTimeMillis() + solveTimeMs;
Result result = solver.solve(instance, deadline);
long runtime = System.currentTimeMillis() - start;
for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) {
String solverName = solversToTest.get(solverId);
Solver solver = solvers.get(solverName);
long start = System.currentTimeMillis();
long deadline = System.currentTimeMillis() + solveTimeMs;
Result result = solver.solve(instance, deadline);
long runtime = System.currentTimeMillis() - start;
if(!result.schedule.isValid()) {
System.err.println("ERROR: solver returned an invalid schedule");
System.exit(1);
if(!result.schedule.isValid()) {
System.err.println("ERROR: solver returned an invalid schedule");
System.exit(1);
}
assert result.schedule.isValid();
int makespan = result.schedule.makespan();
float dist = 100f * (makespan - bestKnown) / (float) bestKnown;
runtimes[solverId] += (float) runtime / (float) instances.size();
distances[solverId] += dist / (float) instances.size();
output.printf("%7d %8s %5.1f ", runtime, makespan, dist);
output.flush();
}
output.println();
assert result.schedule.isValid();
int makespan = result.schedule.makespan();
float dist = 100f * (makespan - bestKnown) / (float) bestKnown;
runtimes[solverId] += (float) runtime / (float) instances.size();
distances[solverId] += dist / (float) instances.size();
output.printf("%7d %8s %5.1f ", runtime, makespan, dist);
output.flush();
}
output.println();
}
output.printf("%-8s %-5s %4s ", "AVG", "-", "-");
for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) {
output.printf("%7.1f %8s %5.1f ", runtimes[solverId], "-", distances[solverId]);
}
output.printf("%-8s %-5s %4s ", "AVG", "-", "-");
for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) {
output.printf("%7.1f %8s %5.1f ", runtimes[solverId], "-", distances[solverId]);
}

View file

@ -1,8 +1,5 @@
package jobshop;
import java.util.Optional;
@SuppressWarnings("unused")
public class Result {
public Result(Instance instance, Schedule schedule, ExitCause cause) {

View file

@ -1,15 +1,11 @@
package jobshop;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
import jobshop.encodings.Task;
import java.util.*;
import java.util.stream.IntStream;
public class Schedule {
public final Instance pb;
// start times of each job and task

View file

@ -14,7 +14,7 @@ public class JobNumbers extends Encoding {
/** A numJobs * numTasks array containing the representation by job numbers. */
public final int[] jobs;
/** In case the encoding is only partially filled, indicates the index of first
/** In case the encoding is only partially filled, indicates the index of the first
* element of `jobs` that has not been set yet. */
public int nextToSet = 0;
@ -77,38 +77,6 @@ public class JobNumbers extends Encoding {
return new Schedule(instance, startTimes);
}
public static JobNumbers fromSchedule(Schedule sched) {
JobNumbers jo = new JobNumbers(sched.pb);
int current_time = 0;
Task current_task = new Task(-1,-1);
Task [] done_tasks = new Task[sched.pb.numJobs*sched.pb.numTasks];
Arrays.fill(done_tasks, current_task);
int min;
for (int i = 0; i < sched.pb.numJobs*sched.pb.numTasks; i++) {
// Il faut faire le code ci-dessous autant de fois que l'on a de taches
// On trouve le minimum parmis les restants
min = Integer.MAX_VALUE;
for (int job = 0; job < sched.pb.numJobs; job++) {
for (int task = 0; task < sched.pb.numTasks; task++) {
int task_start_time = sched.startTime(job, task);
Task this_task = new Task(job, task);
if (task_start_time < min && task_start_time >= current_time && !(Arrays.asList(done_tasks).contains(this_task))) {
min = task_start_time;
current_task = this_task;
}
}
}
// Une fois on a trouvé la suivante tache a realiser on introduit le numero du job dans jobs
jo.jobs[jo.nextToSet++] = current_task.job;
done_tasks[i] = current_task;
}
return jo;
}
@Override
public String toString() {
return Arrays.toString(Arrays.copyOfRange(jobs,0, nextToSet));

View file

@ -1,35 +1,37 @@
package jobshop.encodings;
import java.util.Comparator;
import java.util.Optional;
import java.util.stream.IntStream;
import jobshop.Encoding;
import jobshop.Instance;
import jobshop.Schedule;
import java.util.Comparator;
import java.util.Optional;
import java.util.stream.IntStream;
public class ResourceOrder extends Encoding {
public final Task[][] tasksByMachine;
// for each machine m, taskByMachine[m] is an array of tasks to be
// executed on this machine in the same order
public final Task[][] tasksByMachine;
public final int[] nextFreeSlot;
// for each machine, indicate on many tasks have been initialized
public final int[] nextFreeSlot;
public ResourceOrder(Instance instance) {
super(instance);
/** Creates a new empty resource order. */
public ResourceOrder(Instance instance)
{
super(instance);
this.tasksByMachine = new Task[instance.numMachines][instance.numJobs];
for (int i = 0; i < instance.numMachines; i++) {
for (int j = 0; j < instance.numJobs; j++) {
this.tasksByMachine[i][j] = new Task(-1,-1);
}
}
// matrix of null elements (null is the default value of objects)
tasksByMachine = new Task[instance.numMachines][instance.numJobs];
// no task scheduled on any machine (0 is the default value)
// no task scheduled on any machine (0 is the default value)
nextFreeSlot = new int[instance.numMachines];
}
}
public ResourceOrder(Schedule schedule) {
/** Creates a resource order from a schedule. */
public ResourceOrder(Schedule schedule)
{
super(schedule.pb);
Instance pb = schedule.pb;
@ -49,10 +51,9 @@ public class ResourceOrder extends Encoding {
// indicate that all tasks have been initialized for machine m
nextFreeSlot[m] = instance.numJobs;
}
}
}
@Override
@Override
public Schedule toSchedule() {
// indicate for each task that have been scheduled, its start time
int [][] startTimes = new int [instance.numJobs][instance.numTasks];
@ -88,7 +89,7 @@ public class ResourceOrder extends Encoding {
// compute the earliest start time (est) of the task
int est = t.task == 0 ? 0 : startTimes[t.job][t.task-1] + instance.duration(t.job, t.task-1);
est = Math.max(est, releaseTimeOfMachine[instance.machine(t.job, t.task)]);
est = Math.max(est, releaseTimeOfMachine[instance.machine(t)]);
startTimes[t.job][t.task] = est;
// mark the task as scheduled
@ -105,6 +106,11 @@ public class ResourceOrder extends Encoding {
return new Schedule(instance, startTimes);
}
/** Creates an exact copy of this resource order. */
public ResourceOrder copy() {
return new ResourceOrder(this.toSchedule());
}
@Override
public String toString() {
String res = "";

View file

@ -36,7 +36,7 @@ public final class Task {
@Override
public String toString() {
return "Job " + this.job + " Task " + this.task;
return "(" + job +", " + task + '}';
}
public Task add_one() {

View file

@ -2,16 +2,35 @@ package jobshop.solvers;
import jobshop.Instance;
import jobshop.Result;
import jobshop.Result.ExitCause;
import jobshop.Schedule;
import jobshop.Solver;
import jobshop.encodings.ResourceOrder;
import jobshop.encodings.Task;
import jobshop.solvers.GreedySolver.PriorityESTRule;
import jobshop.solvers.GreedySolver.PriorityRule;
import java.util.ArrayList;
import java.util.List;
public class DescentSolver implements Solver {
private PriorityRule priorityRule;
private PriorityESTRule priorityESTRule;
// 2 constructors: the default and one with the EST restriction
public DescentSolver(PriorityRule rule) {
super();
this.priorityRule = rule;
this.priorityESTRule = null;
}
public DescentSolver(PriorityESTRule ruleEST) {
super();
this.priorityESTRule = ruleEST;
this.priorityRule = null;
}
/** A block represents a subsequence of the critical path such that all tasks in it execute on the same machine.
* This class identifies a block in a ResourceOrder representation.
*
@ -24,7 +43,7 @@ public class DescentSolver implements Solver {
* Represent the task sequence : [(0,2) (2,1)]
*
* */
public static class Block {
public static class Block {
/** machine on which the block is identified */
final int machine;
/** index of the first task of the block */
@ -78,7 +97,7 @@ public class DescentSolver implements Solver {
// Retrieve the tasks to be swap
Task task1 = order.tasksByMachine[this.machine][this.t1];
Task task2 = order.tasksByMachine[this.machine][this.t2];
// Make the swap
// Make the swap (default in/out)
order.tasksByMachine[this.machine][this.t1] = task2;
order.tasksByMachine[this.machine][this.t2] = task1;
}
@ -87,90 +106,142 @@ public class DescentSolver implements Solver {
return "Swap: {M" + this.machine + " | t1 = " + this.t1 + " | t2 = " + this.t2 + "}";
}
}
// ************************************************************************************************************* //
// *************************************** DescentSolver: solve Method ***************************************** //
// ************************************************************************************************************* //
@Override
public Result solve(Instance instance, long deadline) {
throw new UnsupportedOperationException();
// Choosing rule (SPT / LRPT / EST_SPT / EST_LRPT)
GreedySolver greedy = null;
if(priorityESTRule == null) {
PriorityRule currentRule = this.priorityRule;
greedy = new GreedySolver(currentRule);
} else if(priorityRule == null) {
PriorityESTRule currentESTRule = this.priorityESTRule;
greedy = new GreedySolver(currentESTRule);
} else {
System.out.printf("Error priorityRule and priorityRuleEST are null. You must give a value to one of them.");
}
// Start: Sinit <- GreedySolver(instance)
Result resultLRPT = greedy.solve(instance, deadline);
Schedule initialSolution = resultLRPT.schedule;
// Record the best solution
Schedule bestSolution = initialSolution;
ResourceOrder bestResourceOrder = new ResourceOrder(bestSolution);
// Repeat: Explore the concurrent neighbors
Boolean optimizable = true;
Schedule currentSolution;
ResourceOrder currentResourceOrder;
List<Block> criticalBlockList;
while(optimizable && deadline > System.currentTimeMillis()) {
// We first take the critical path from the bestSolution
bestResourceOrder = new ResourceOrder(bestSolution);
criticalBlockList = this.blocksOfCriticalPath(bestResourceOrder);
// By default we suppose there will be no optimization possible. If there is, this value will be later changed
optimizable = false;
// We search for the best solution by checking all neighbors
for(Block b : criticalBlockList) {
for(Swap s : this.neighbors(b)) {
// We copy to a variable the bestResourceOrder in order to modified freely while searching for the best solution
currentResourceOrder = bestResourceOrder.copy();
// We apply the swap on the current Resource Order and we schedule it
s.applyOn(currentResourceOrder);
currentSolution = currentResourceOrder.toSchedule();
// If the currentSolution duration is smaller than the bestSolution one, save the currentSolution
if(currentSolution != null) {
if(currentSolution.makespan() < bestSolution.makespan()) {
bestSolution = currentSolution;
// While we find better solutions keep running the solve method
optimizable = true;
}
}
}
}
}
// We find the exit cause in order to create the result we will return
ExitCause exitCause = null;
if(deadline <= System.currentTimeMillis()) {
exitCause = ExitCause.Timeout;
} else {
exitCause = ExitCause.ProvedOptimal;
}
return new Result(instance, bestSolution, exitCause);
}
// ************************************************************************************************************* //
// ************************************************************************************************************* //
// ***************************** blocksOfCriticalPath and neighbors Methods ************************************ //
// ************************************************************************************************************* //
/** Returns a list of all blocks of the critical path. */
public List<Block> blocksOfCriticalPath(ResourceOrder order) {
List<Block> criticalBlockList = new ArrayList<>();
List<Integer> checkedMachines = new ArrayList<>();
Block currentBlock;
// Obtain the critical task list from the resource order instance
Schedule criticalSchedule = order.toSchedule();
List<Task> criticalTaskList = criticalSchedule.criticalPath();
Block currentBlock;
int currentMachine, m;
int firstTask = 0, lastTask = 0;
Task currentTask;
int totalNumMachines = criticalSchedule.pb.numMachines;
int totalNumJobs = criticalSchedule.pb.numJobs;
System.out.print("Number of Jobs : " + order.instance.numJobs + "\n");
System.out.print("Number of Tasks : " + order.instance.numTasks + "\n");
System.out.print("Number of Machines : " + order.instance.numMachines + "\n");
System.out.print("Critical path : " + criticalTaskList + "\n");
Task currentTaskRO;
int currentTaskIndexRO, currentCriticalTaskIndex, firstTask, lastTask;
// Initialize the block list
for(int i = 0; i < order.instance.numMachines; i++) {
currentBlock = new Block(i, -1, -1);
criticalBlockList.add(i, currentBlock);
}
for(int i = 0; i < criticalTaskList.size(); i++) {
currentTask = criticalTaskList.get(i);
currentMachine = order.instance.machine(currentTask.job, currentTask.task);
// When we find a machine we have not explored, we start searching for all its appearances in the critical path
// and we safe the first and last occurrence of the machine.
if(!checkedMachines.contains(currentMachine)) {
firstTask = 0;
lastTask = 0;
for(int index = i; index < criticalTaskList.size(); index++) {
m = order.instance.machine(criticalTaskList.get(index).job, criticalTaskList.get(index).task);
// If we find a task running in the same machine and it is not the first task, add 1 to the last task
if(currentMachine == m && index > i){
lastTask++;
}
}
// Add the machine to the checked machines list
checkedMachines.add(currentMachine);
// Create and add the new block to the list
currentBlock = new Block(currentMachine, firstTask, lastTask);
criticalBlockList.set(currentMachine, currentBlock);
}
// We check for all machines
for(int currentMachine = 0; currentMachine < totalNumMachines; currentMachine++) {
currentTaskIndexRO = 0;
while(currentTaskIndexRO < (totalNumJobs-1)){
currentTaskRO = order.tasksByMachine[currentMachine][currentTaskIndexRO];
if (criticalTaskList.contains(currentTaskRO)) {
currentCriticalTaskIndex = criticalTaskList.indexOf(currentTaskRO);
//If the next task in the critical path is running in the same machine try find the last task index
if(currentMachine == criticalSchedule.pb.machine(criticalTaskList.get(currentCriticalTaskIndex+1))) {
firstTask = currentTaskIndexRO;
while(currentCriticalTaskIndex < (criticalTaskList.size()-1) && currentMachine == criticalSchedule.pb.machine(criticalTaskList.get(currentCriticalTaskIndex+1))){
// We advance in the list
currentCriticalTaskIndex++;
// We have to also advance in the resource order
currentTaskIndexRO++;
}
// Create and add the new block to the list
lastTask = currentTaskIndexRO;
currentBlock = new Block(currentMachine, firstTask, lastTask);
criticalBlockList.add(currentBlock);
}
}
// We move on to the next task in the resource order
currentTaskIndexRO++;
}
}
return criticalBlockList;
}
}
/** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */
public List<Swap> neighbors(Block block) {
/** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */
public List<Swap> neighbors(Block block) {
List<Swap> swapList = new ArrayList<>();
Swap currentSwap;
Swap swap1, swap2;
int machine = block.machine;
int firstTask = block.firstTask;
int lastTask = block.lastTask;
// Case when there is just one element in the block
if(firstTask == lastTask) {
swapList = null;
}
for(int i = firstTask; i < lastTask; i++) {
if(i == firstTask + 1) {
currentSwap = new Swap(machine, firstTask, i);
swapList.add(currentSwap);
}
if (i == lastTask - 1) {
currentSwap = new Swap(machine, i, lastTask);
swapList.add(currentSwap);
}
}
// One single swap if there are just 2 elements in the block, two swaps if there are more than 2.
if(firstTask + 1 == lastTask) {
swap1 = new Swap(machine, firstTask, lastTask);
swapList.add(swap1);
} else {
swap1 = new Swap(machine, firstTask, firstTask+1);
swap2 = new Swap(machine, lastTask-1 , lastTask);
swapList.add(swap1);
swapList.add(swap2);
}
return swapList;
}
}
// ************************************************************************************************************* //
}

View file

@ -3,9 +3,9 @@ package jobshop.solvers;
import java.util.ArrayList;
import jobshop.*;
import jobshop.Result.ExitCause;
import jobshop.encodings.ResourceOrder;
import jobshop.encodings.Task;
import jobshop.solvers.GreedySolver.PriorityESTRule;
public class GreedySolver implements Solver {
@ -100,12 +100,12 @@ public class GreedySolver implements Solver {
// Search for the date or dates which start sooner
ArrayList<Task> priorityTasks = new ArrayList<>();
int minStartDate = Integer.MAX_VALUE;
Task currentTask;
int currentMachine, currentStartDate;
for(int i = 0; i < achievableTasks.size(); i++) {
Task currentTask = achievableTasks.get(i);
int currentMachine = instance.machine(currentTask.job, currentTask.task);
int currentStartDate = Integer.max(nextStartDateJobs[currentTask.job], nextStartDateMachines[currentMachine]);
currentTask = achievableTasks.get(i);
currentMachine = instance.machine(currentTask);
currentStartDate = Integer.max(nextStartDateJobs[currentTask.job], nextStartDateMachines[currentMachine]);
if(currentStartDate < minStartDate) {
minStartDate = currentStartDate;
@ -124,16 +124,18 @@ public class GreedySolver implements Solver {
/********************** Greedy Solver: Constructors + Solve function *************************/
/*********************************************************************************************/
public PriorityRule priorityRule;
public PriorityESTRule priorityESTRule;
private PriorityRule priorityRule;
private PriorityESTRule priorityESTRule;
// 2 constructors: the default and one with the EST restriction
public GreedySolver(PriorityRule rule) {
super();
this.priorityRule = rule;
this.priorityESTRule = null;
}
public GreedySolver(PriorityESTRule ruleEST) {
super();
this.priorityESTRule = ruleEST;
this.priorityRule = null;
}
@ -143,7 +145,7 @@ public class GreedySolver implements Solver {
@Override
public Result solve(Instance instance, long deadline) {
int currentMachine, currentDuration;
int currentMachine, currentDuration, currentStartDate, nextFreeSlot;
// We declare 2 arrays containing the updated moment the next task will start in a job and a machine respectively
int[] nextStartDateJobs = new int[instance.numJobs];
int[] nextStartDateMachines = new int[instance.numMachines];
@ -155,11 +157,10 @@ public class GreedySolver implements Solver {
// Initialize the array list with all the first task achievable
for(int i = 0 ; i < instance.numJobs ; i++) {
Task currentTask = new Task(i, 0);
achievableTasks.add(currentTask);
achievableTasks.add(new Task(i, 0));
}
while(!achievableTasks.isEmpty()) {
while(!achievableTasks.isEmpty() && deadline > System.currentTimeMillis()) {
// We take the task we should do now in function of the priority rule used
Task currentTask = null;
if(priorityESTRule == null) {
@ -170,25 +171,33 @@ public class GreedySolver implements Solver {
System.out.printf("Error priorityRule and priorityRuleEST are null. You must give a value to one of them.");
}
// Updating starting dates
currentMachine = instance.machine(currentTask.job, currentTask.task);
currentDuration = instance.duration(currentTask.job, currentTask.task);
nextStartDateJobs[currentTask.job] += currentDuration;
nextStartDateMachines[currentMachine] += currentDuration;
// We remove the current task from the achievable tasks list
achievableTasks.remove(currentTask);
// Updating starting dates
currentMachine = instance.machine(currentTask);
currentDuration = instance.duration(currentTask);
currentStartDate = Integer.max(nextStartDateJobs[currentTask.job], nextStartDateMachines[currentMachine]);
nextStartDateJobs[currentTask.job] = currentStartDate + currentDuration;
nextStartDateMachines[currentMachine] = currentStartDate + currentDuration;
// If it's not the last task of the job, we update the array list with the new task
if (currentTask.task < (instance.numTasks - 1)) {
achievableTasks.add(new Task(currentTask.job, currentTask.task + 1));
}
// We add the current task to the solution
int nextFreeSlot = solution.nextFreeSlot[currentMachine]++;
nextFreeSlot = solution.nextFreeSlot[currentMachine]++;
solution.tasksByMachine[currentMachine][nextFreeSlot] = currentTask;
}
return new Result(instance, solution.toSchedule(), Result.ExitCause.Blocked);
// We find the exit cause in order to create the result we will return
ExitCause exitCause = null;
if(deadline <= System.currentTimeMillis()) {
exitCause = ExitCause.Timeout;
} else {
exitCause = ExitCause.ProvedOptimal;
}
return new Result(instance, solution.toSchedule(), exitCause);
}
}

View file

@ -6,7 +6,6 @@ import jobshop.encodings.JobNumbers;
import java.util.Optional;
import java.util.Random;
@SuppressWarnings("unused")
public class RandomSolver implements Solver {
@Override

View file

@ -0,0 +1,231 @@
package jobshop.solvers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jobshop.Instance;
import jobshop.Result;
import jobshop.Schedule;
import jobshop.Solver;
import jobshop.Result.ExitCause;
import jobshop.encodings.ResourceOrder;
import jobshop.encodings.Task;
import jobshop.solvers.GreedySolver.PriorityESTRule;
import jobshop.solvers.GreedySolver.PriorityRule;
import jobshop.solvers.DescentSolver.*;
public class TabooSolver implements Solver {
private PriorityRule priorityRule;
private PriorityESTRule priorityESTRule;
private int dureeTaboo;
private int maxIter;
// 2 constructors: the default and one with the EST restriction
public TabooSolver(PriorityRule rule, int dureeTaboo, int maxIter) {
super();
this.priorityRule = rule;
this.priorityESTRule = null;
this.dureeTaboo = dureeTaboo;
this.maxIter = maxIter;
}
public TabooSolver(PriorityESTRule ruleEST, int dureeTaboo, int maxIter) {
super();
this.priorityESTRule = ruleEST;
this.priorityRule = null;
this.dureeTaboo = dureeTaboo;
this.maxIter = maxIter;
}
// ************************************************************************************************************* //
// *************************************** TabooSolver: solve Method ******************************************* //
// ************************************************************************************************************* //
@Override
public Result solve(Instance instance, long deadline) {
// Choosing rule (SPT / LRPT / EST_SPT / EST_LRPT)
GreedySolver greedy = null;
if(priorityESTRule == null) {
PriorityRule currentRule = this.priorityRule;
greedy = new GreedySolver(currentRule);
} else if(priorityRule == null) {
PriorityESTRule currentESTRule = this.priorityESTRule;
greedy = new GreedySolver(currentESTRule);
} else {
System.out.printf("Error priorityRule and priorityRuleEST are null. You must give a value to one of them.");
}
// Generating a viable solution
Result result = greedy.solve(instance, deadline);
Schedule initialSolution = result.schedule;
ResourceOrder initialResourceOrder = new ResourceOrder(initialSolution);
// Declaring all solution types
ResourceOrder bestRO = initialResourceOrder; // s*
ResourceOrder currentRO = bestRO.copy(); // s
ResourceOrder bestNeighborRO = bestRO.copy(); // s'
ResourceOrder neighborRO; // s''
// Defining the sTaboo variables
int totalTasks = instance.numJobs * instance.numTasks;
int[][] sTaboo = new int[totalTasks][totalTasks];
// Initializing sTaboo with all 0
for (int[] row : sTaboo) {
Arrays.fill(row, 0);
}
// Declaring other variables
List<Block> criticalBlockList;
int TASK_PER_JOB, j1, i1, j2, i2, taskID1, taskID2, forbiddenTaskID1, forbiddenTaskID2;
int bestMakespan = initialSolution.makespan();
int bestNeighborMakespan, neighborMakespan;
boolean updated;
// Iteration Counter
int k = 0;
while (deadline > System.currentTimeMillis() && k <= this.maxIter) {
// ***************** 1. k <- k + 1 ******************************************************** //
k++;
// ***************** 2. Choose the best neighbor s' that is not in sTaboo ***************** //
bestNeighborMakespan = Integer.MAX_VALUE;
forbiddenTaskID1 = -1;
forbiddenTaskID2 = -1;
updated = false;
// We first take the critical path from the currentRO (s)
currentRO = bestNeighborRO.copy(); // (s <- s')
criticalBlockList = this.blocksOfCriticalPath(currentRO);
for(Block b : criticalBlockList) {
for(Swap s : neighbors(b)) {
// Extract the current index values for sTaboo
TASK_PER_JOB = currentRO.instance.numTasks;
j1 = currentRO.tasksByMachine[s.machine][s.t1].job;
j2 = currentRO.tasksByMachine[s.machine][s.t2].job;
i1 = currentRO.tasksByMachine[s.machine][s.t1].task;
i2 = currentRO.tasksByMachine[s.machine][s.t2].task;
taskID1 = j1 * TASK_PER_JOB + i1;
taskID2 = j2 * TASK_PER_JOB + i2;
// Check if it is a forbidden swap
if(sTaboo[taskID1][taskID2] < k) {
updated= true;
neighborRO = currentRO.copy();
// We apply the swap on the current Resource Order and we schedule it to find its makespan
s.applyOn(neighborRO);
neighborMakespan = neighborRO.toSchedule().makespan();
if(neighborMakespan < bestNeighborMakespan) {
// We forbid the opposite permutation of the given tasks (in index taskID1 and taskID2)
forbiddenTaskID1 = taskID1;
forbiddenTaskID2 = taskID2;
// We have checked all neighbors and we have chosen the best one: bestNeighborRO
bestNeighborMakespan = neighborMakespan;
bestNeighborRO = neighborRO.copy();
}
}
}
}
// ************************ 3. Add bestNeighborSolution (s') to sTaboo *************************** //
// If it is not updated it means all solutions are forbidden
if(updated) {
sTaboo[forbiddenTaskID2][forbiddenTaskID1] = this.dureeTaboo + k;
// ******************** 4. If s' is better than s* then s* <- s' ************************** //
if(bestNeighborMakespan < bestMakespan) {
bestMakespan = bestNeighborMakespan;
bestRO = bestNeighborRO.copy();
}
}
}
// We find the exit cause in order to create the result we will return
ExitCause exitCause = null;
if(deadline <= System.currentTimeMillis()) {
exitCause = ExitCause.Timeout;
} else if(k >= this.maxIter) {
exitCause = ExitCause.Blocked;
} else {
exitCause = ExitCause.ProvedOptimal;
}
return new Result(instance, bestRO.toSchedule(), exitCause);
}
// ************************************************************************************************************* //
// ************************************************************************************************************* //
// ********************************** Copied functions from DescentSolver ************************************** //
// ************************************************************************************************************* //
/** Returns a list of all blocks of the critical path. */
private List<Block> blocksOfCriticalPath(ResourceOrder order) {
List<Block> criticalBlockList = new ArrayList<>();
Block currentBlock;
// Obtain the critical task list from the resource order instance
Schedule criticalSchedule = order.toSchedule();
List<Task> criticalTaskList = criticalSchedule.criticalPath();
int totalNumMachines = criticalSchedule.pb.numMachines;
int totalNumJobs = criticalSchedule.pb.numJobs;
Task currentTaskRO;
int currentTaskIndexRO, currentCriticalTaskIndex, firstTask, lastTask;
// We check for all machines
for(int currentMachine = 0; currentMachine < totalNumMachines; currentMachine++) {
currentTaskIndexRO = 0;
while(currentTaskIndexRO < (totalNumJobs-1)){
currentTaskRO = order.tasksByMachine[currentMachine][currentTaskIndexRO];
if (criticalTaskList.contains(currentTaskRO)) {
currentCriticalTaskIndex = criticalTaskList.indexOf(currentTaskRO);
//If the next task in the critical path is running in the same machine try find the last task index
if(currentMachine == criticalSchedule.pb.machine(criticalTaskList.get(currentCriticalTaskIndex+1))) {
firstTask = currentTaskIndexRO;
while(currentCriticalTaskIndex < (criticalTaskList.size()-1) && currentMachine == criticalSchedule.pb.machine(criticalTaskList.get(currentCriticalTaskIndex+1))){
// We advance in the list
currentCriticalTaskIndex++;
// We have to also advance in the resource order
currentTaskIndexRO++;
}
// Create and add the new block to the list
lastTask = currentTaskIndexRO;
currentBlock = new Block(currentMachine, firstTask, lastTask);
criticalBlockList.add(currentBlock);
}
}
// We move on to the next task in the resource order
currentTaskIndexRO++;
}
}
return criticalBlockList;
}
/** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */
private List<Swap> neighbors(Block block) {
List<Swap> swapList = new ArrayList<>();
Swap swap1;
Swap swap2;
int machine = block.machine;
int firstTask = block.firstTask;
int lastTask = block.lastTask;
// One single swap if there are just 2 elements in the block, two swaps if there are more than 2.
if(firstTask + 1 == lastTask) {
swap1 = new Swap(machine, firstTask, lastTask);
swapList.add(swap1);
} else {
swap1 = new Swap(machine, firstTask, firstTask+1);
swap2 = new Swap(machine, lastTask-1 , lastTask);
swapList.add(swap1);
swapList.add(swap2);
}
return swapList;
}
// ************************************************************************************************************* //
}

View file

@ -5,9 +5,6 @@ import jobshop.Result;
import jobshop.Schedule;
import jobshop.Solver;
import jobshop.solvers.BasicSolver;
import jobshop.solvers.GreedySolver;
import jobshop.solvers.GreedySolver.PriorityRule;
import org.junit.Test;
import java.io.IOException;
@ -75,29 +72,4 @@ public class EncodingTests {
assert result.schedule.makespan() == sched.makespan(); // should have the same makespan
}
@Test
public void testGreedySolver() throws IOException {
Instance instance = Instance.fromFile(Paths.get("instances/aaa1"));
// build a solution that should be equal to the result of BasicSolver
JobNumbers enc = new JobNumbers(instance);
enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 1;
Schedule sched = enc.toSchedule();
assert sched.isValid();
assert sched.makespan() == 12;
PriorityRule priorityRule = PriorityRule.SPT;
Solver solver = new GreedySolver(priorityRule);
Result result = solver.solve(instance, System.currentTimeMillis() + 10);
assert result.schedule.isValid();
assert result.schedule.makespan() == sched.makespan(); // should have the same makespan
}
}