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 # Example instance
3 3 # num-jobs num-tasks 3 3 # num-jobs num-tasks
2 3 0 3 1 2 2 4 0 3 1 2
1 7 0 6 2 5 1 7 0 6 2 5
0 2 1 10 2 4 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

@ -1,180 +1,189 @@
package jobshop; package jobshop;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
public class BestKnownResult { import java.util.stream.Collectors;
public static boolean isKnown(String instanceName) { public class BestKnownResult {
return bests.containsKey(instanceName);
} public static boolean isKnown(String instanceName) {
return bests.containsKey(instanceName);
public static int of(String instanceName) { }
if(!bests.containsKey(instanceName)) {
throw new RuntimeException("Unknown best result for "+instanceName); public static List<String> instancesMatching(String namePrefix) {
} return Arrays.stream(instances)
return bests.get(instanceName); .filter(i -> i.startsWith(namePrefix))
} .sorted()
.collect(Collectors.toList());
static private HashMap<String, Integer> bests; }
static String[] instances;
static { public static int of(String instanceName) {
bests = new HashMap<>(); if(!bests.containsKey(instanceName)) {
bests.put("aaa1", 11); throw new RuntimeException("Unknown best result for "+instanceName);
bests.put("abz5", 1234); }
bests.put("abz6", 943); return bests.get(instanceName);
bests.put("abz7", 656); }
bests.put("abz8", 665);
bests.put("abz9", 679); static private HashMap<String, Integer> bests;
bests.put("ft06", 55); static String[] instances;
bests.put("ft10", 930); static {
bests.put("ft20", 1165); bests = new HashMap<>();
bests.put("la01", 666); bests.put("aaa1", 11);
bests.put("la02", 655); bests.put("abz5", 1234);
bests.put("la03", 597); bests.put("abz6", 943);
bests.put("la04", 590); bests.put("abz7", 656);
bests.put("la05", 593); bests.put("abz8", 665);
bests.put("la06", 926); bests.put("abz9", 679);
bests.put("la07", 890); bests.put("ft06", 55);
bests.put("la08", 863); bests.put("ft10", 930);
bests.put("la09", 951); bests.put("ft20", 1165);
bests.put("la10", 958); bests.put("la01", 666);
bests.put("la11", 1222); bests.put("la02", 655);
bests.put("la12", 1039); bests.put("la03", 597);
bests.put("la13", 1150); bests.put("la04", 590);
bests.put("la14", 1292); bests.put("la05", 593);
bests.put("la15", 1207); bests.put("la06", 926);
bests.put("la16", 945); bests.put("la07", 890);
bests.put("la17", 784); bests.put("la08", 863);
bests.put("la18", 848); bests.put("la09", 951);
bests.put("la19", 842); bests.put("la10", 958);
bests.put("la20", 902); bests.put("la11", 1222);
bests.put("la21", 1046); bests.put("la12", 1039);
bests.put("la22", 927); bests.put("la13", 1150);
bests.put("la23", 1032); bests.put("la14", 1292);
bests.put("la24", 935); bests.put("la15", 1207);
bests.put("la25", 977); bests.put("la16", 945);
bests.put("la26", 1218); bests.put("la17", 784);
bests.put("la27", 1235); bests.put("la18", 848);
bests.put("la28", 1216); bests.put("la19", 842);
bests.put("la29", 1152); bests.put("la20", 902);
bests.put("la30", 1355); bests.put("la21", 1046);
bests.put("la31", 1784); bests.put("la22", 927);
bests.put("la32", 1850); bests.put("la23", 1032);
bests.put("la33", 1719); bests.put("la24", 935);
bests.put("la34", 1721); bests.put("la25", 977);
bests.put("la35", 1888); bests.put("la26", 1218);
bests.put("la36", 1268); bests.put("la27", 1235);
bests.put("la37", 1397); bests.put("la28", 1216);
bests.put("la38", 1196); bests.put("la29", 1152);
bests.put("la39", 1233); bests.put("la30", 1355);
bests.put("la40", 1222); bests.put("la31", 1784);
bests.put("orb01", 1059); bests.put("la32", 1850);
bests.put("orb02", 888); bests.put("la33", 1719);
bests.put("orb03", 1005); bests.put("la34", 1721);
bests.put("orb04", 1005); bests.put("la35", 1888);
bests.put("orb05", 887); bests.put("la36", 1268);
bests.put("orb06", 1010); bests.put("la37", 1397);
bests.put("orb07", 397); bests.put("la38", 1196);
bests.put("orb08", 899); bests.put("la39", 1233);
bests.put("orb09", 934); bests.put("la40", 1222);
bests.put("orb10", 944); bests.put("orb01", 1059);
bests.put("swv01", 1407); bests.put("orb02", 888);
bests.put("swv02", 1475); bests.put("orb03", 1005);
bests.put("swv03", 1398); bests.put("orb04", 1005);
bests.put("swv04", 1474); bests.put("orb05", 887);
bests.put("swv05", 1424); bests.put("orb06", 1010);
bests.put("swv06", 1678); bests.put("orb07", 397);
bests.put("swv07", 1600); bests.put("orb08", 899);
bests.put("swv08", 1763); bests.put("orb09", 934);
bests.put("swv09", 1661); bests.put("orb10", 944);
bests.put("swv10", 1767); bests.put("swv01", 1407);
bests.put("swv11", 2991); bests.put("swv02", 1475);
bests.put("swv12", 3003); bests.put("swv03", 1398);
bests.put("swv13", 3104); bests.put("swv04", 1474);
bests.put("swv14", 2968); bests.put("swv05", 1424);
bests.put("swv15", 2904); bests.put("swv06", 1678);
bests.put("swv16", 2924); bests.put("swv07", 1600);
bests.put("swv17", 2794); bests.put("swv08", 1763);
bests.put("swv18", 2852); bests.put("swv09", 1661);
bests.put("swv19", 2843); bests.put("swv10", 1767);
bests.put("swv20", 2823); bests.put("swv11", 2991);
bests.put("yn1", 885); bests.put("swv12", 3003);
bests.put("yn2", 909); bests.put("swv13", 3104);
bests.put("yn3", 892); bests.put("swv14", 2968);
bests.put("yn4", 968); bests.put("swv15", 2904);
bests.put("ta01", 1231); bests.put("swv16", 2924);
bests.put("ta02", 1244); bests.put("swv17", 2794);
bests.put("ta03", 1218); bests.put("swv18", 2852);
bests.put("ta04", 1175); bests.put("swv19", 2843);
bests.put("ta05", 1224); bests.put("swv20", 2823);
bests.put("ta06", 1238); bests.put("yn1", 885);
bests.put("ta07", 1227); bests.put("yn2", 909);
bests.put("ta08", 1217); bests.put("yn3", 892);
bests.put("ta09", 1274); bests.put("yn4", 968);
bests.put("ta10", 1241); bests.put("ta01", 1231);
bests.put("ta11", 1361); bests.put("ta02", 1244);
bests.put("ta12", 1367); bests.put("ta03", 1218);
bests.put("ta13", 1342); bests.put("ta04", 1175);
bests.put("ta14", 1345); bests.put("ta05", 1224);
bests.put("ta15", 1340); bests.put("ta06", 1238);
bests.put("ta16", 1360); bests.put("ta07", 1227);
bests.put("ta17", 1462); bests.put("ta08", 1217);
bests.put("ta18", 1396); bests.put("ta09", 1274);
bests.put("ta19", 1335); bests.put("ta10", 1241);
bests.put("ta20", 1351); bests.put("ta11", 1361);
bests.put("ta21", 1644); bests.put("ta12", 1367);
bests.put("ta22", 1600); bests.put("ta13", 1342);
bests.put("ta23", 1557); bests.put("ta14", 1345);
bests.put("ta24", 1647); bests.put("ta15", 1340);
bests.put("ta25", 1595); bests.put("ta16", 1360);
bests.put("ta26", 1645); bests.put("ta17", 1462);
bests.put("ta27", 1680); bests.put("ta18", 1396);
bests.put("ta28", 1614); bests.put("ta19", 1335);
bests.put("ta29", 1635); bests.put("ta20", 1351);
bests.put("ta30", 1584); bests.put("ta21", 1644);
bests.put("ta31", 1764); bests.put("ta22", 1600);
bests.put("ta32", 1796); bests.put("ta23", 1557);
bests.put("ta33", 1793); bests.put("ta24", 1647);
bests.put("ta34", 1829); bests.put("ta25", 1595);
bests.put("ta35", 2007); bests.put("ta26", 1645);
bests.put("ta36", 1819); bests.put("ta27", 1680);
bests.put("ta37", 1778); bests.put("ta28", 1614);
bests.put("ta38", 1673); bests.put("ta29", 1635);
bests.put("ta39", 1795); bests.put("ta30", 1584);
bests.put("ta40", 1674); bests.put("ta31", 1764);
bests.put("ta41", 2018); bests.put("ta32", 1796);
bests.put("ta42", 1956); bests.put("ta33", 1793);
bests.put("ta43", 1859); bests.put("ta34", 1829);
bests.put("ta44", 1984); bests.put("ta35", 2007);
bests.put("ta45", 2000); bests.put("ta36", 1819);
bests.put("ta46", 2021); bests.put("ta37", 1778);
bests.put("ta47", 1903); bests.put("ta38", 1673);
bests.put("ta48", 1952); bests.put("ta39", 1795);
bests.put("ta49", 1968); bests.put("ta40", 1674);
bests.put("ta50", 1926); bests.put("ta41", 2018);
bests.put("ta51", 2760); bests.put("ta42", 1956);
bests.put("ta52", 2756); bests.put("ta43", 1859);
bests.put("ta53", 2717); bests.put("ta44", 1984);
bests.put("ta54", 2839); bests.put("ta45", 2000);
bests.put("ta55", 2679); bests.put("ta46", 2021);
bests.put("ta56", 2781); bests.put("ta47", 1903);
bests.put("ta57", 2943); bests.put("ta48", 1952);
bests.put("ta58", 2885); bests.put("ta49", 1968);
bests.put("ta59", 2655); bests.put("ta50", 1926);
bests.put("ta60", 2723); bests.put("ta51", 2760);
bests.put("ta61", 2868); bests.put("ta52", 2756);
bests.put("ta62", 2869); bests.put("ta53", 2717);
bests.put("ta63", 2755); bests.put("ta54", 2839);
bests.put("ta64", 2702); bests.put("ta55", 2679);
bests.put("ta65", 2725); bests.put("ta56", 2781);
bests.put("ta66", 2845); bests.put("ta57", 2943);
bests.put("ta67", 2825); bests.put("ta58", 2885);
bests.put("ta68", 2784); bests.put("ta59", 2655);
bests.put("ta69", 3071); bests.put("ta60", 2723);
bests.put("ta70", 2995); bests.put("ta61", 2868);
instances = bests.keySet().toArray(new String[0]); bests.put("ta62", 2869);
Arrays.sort(instances); bests.put("ta63", 2755);
} bests.put("ta64", 2702);
bests.put("ta65", 2725);
} bests.put("ta66", 2845);
bests.put("ta67", 2825);
bests.put("ta68", 2784);
bests.put("ta69", 3071);
bests.put("ta70", 2995);
instances = bests.keySet().toArray(new String[0]);
Arrays.sort(instances);
}
}

View file

@ -1,153 +1,189 @@
package jobshop; package jobshop;
import jobshop.encodings.JobNumbers; import jobshop.encodings.JobNumbers;
import jobshop.encodings.ResourceOrder; import jobshop.encodings.ResourceOrder;
import jobshop.encodings.Task; import jobshop.encodings.Task;
import jobshop.solvers.DescentSolver; import jobshop.solvers.DescentSolver;
import jobshop.solvers.GreedySolver; import jobshop.solvers.DescentSolver.Block;
import jobshop.solvers.DescentSolver.Block; import jobshop.solvers.DescentSolver.Swap;
import jobshop.solvers.GreedySolver.PriorityESTRule; import jobshop.solvers.GreedySolver;
import jobshop.solvers.GreedySolver.PriorityRule; import jobshop.solvers.GreedySolver.PriorityESTRule;
import jobshop.solvers.GreedySolver.PriorityRule;
import java.io.IOException; import jobshop.solvers.TabooSolver;
import java.nio.file.Paths;
import java.util.List; import java.io.IOException;
import java.nio.file.Paths;
public class DebuggingMain { import java.util.List;
public static void main(String[] args) { public class DebuggingMain {
try {
// load the aaa1 instance public static void main(String[] args) {
Instance instance = Instance.fromFile(Paths.get("instances/aaa1")); try {
// load the aaa1 instance
// construit une solution dans la représentation par Instance instance = Instance.fromFile(Paths.get("instances/aaa1"));
// numéro de jobs : [0 1 1 0 0 1]
// Note : cette solution a aussi été vue dans les exercices (section 3.3) // construit une solution dans la représentation par
// mais on commençait à compter à 1 ce qui donnait [1 2 2 1 1 2] // numéro de jobs : [0 1 1 0 0 1]
JobNumbers enc = new JobNumbers(instance); // Note : cette solution a aussi été vue dans les exercices (section 3.3)
enc.jobs[enc.nextToSet++] = 0; // mais on commençait à compter à 1 ce qui donnait [1 2 2 1 1 2]
enc.jobs[enc.nextToSet++] = 0; JobNumbers enc = new JobNumbers(instance);
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;
enc.jobs[enc.nextToSet++] = 1; enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 0;
System.out.println("\nJOB NUMBER ENCODING: " + enc + "\n"); enc.jobs[enc.nextToSet++] = 1;
Schedule sched = enc.toSchedule(); System.out.println("\nENCODING: " + enc);
System.out.println("SCHEDULE:\n" + sched); Schedule sched = enc.toSchedule();
System.out.println("VALID: " + sched.isValid() + "\n"); // TODO: make it print something meaningful
System.out.println("MAKESPAN: " + sched.makespan() + "\n"); // by implementing the toString() method
System.out.println("SCHEDULE: " + sched);
System.out.println("---------------------------------------------\n"); System.out.println("VALID: " + sched.isValid());
System.out.println("MAKESPAN: " + sched.makespan());
ResourceOrder ro = new ResourceOrder(instance);
ro.tasksByMachine[0][0] = new Task(0,0); System.out.println("---------------------------------------------\n");
ro.tasksByMachine[0][1] = new Task(1,1);
ro.tasksByMachine[1][0] = new Task(1,0); ResourceOrder ro = new ResourceOrder(instance);
ro.tasksByMachine[1][1] = new Task(0,1); ro.tasksByMachine[0][0] = new Task(0,0);
ro.tasksByMachine[2][0] = new Task(0,2); ro.tasksByMachine[0][1] = new Task(1,1);
ro.tasksByMachine[2][1] = new Task(1,2); ro.tasksByMachine[1][0] = new Task(1,0);
ro.tasksByMachine[1][1] = new Task(0,1);
System.out.println("RESOURCE ORDER ENCODING:\n" + ro + "\n"); ro.tasksByMachine[2][0] = new Task(0,2);
ro.tasksByMachine[2][1] = new Task(1,2);
System.out.println("---------------------------------------------\n");
System.out.println("RESOURCE ORDER ENCODING:\n" + ro + "\n");
// load the aaa2 instance
Instance instance2 = Instance.fromFile(Paths.get("instances/aaa2")); System.out.println("---------------------------------------------\n");
ResourceOrder ro2 = new ResourceOrder(instance2); // load the aaa2 instance
ro2.tasksByMachine[0][0] = new Task(2,0); //O7: Job 2, Task 0 (Machine 0) Instance instance2 = Instance.fromFile(Paths.get("instances/aaa2"));
ro2.tasksByMachine[0][1] = new Task(1,1); //O5: Job 1, Task 1 (Machine 0)
ro2.tasksByMachine[0][2] = new Task(0,1); //O2: Job 0, Task 1 (Machine 0) ResourceOrder ro2 = new ResourceOrder(instance2);
ro2.tasksByMachine[1][0] = new Task(1,0); //O4: Job 1, Task 0 (Machine 1) ro2.tasksByMachine[0][0] = new Task(2,0); //O7: Job 2, Task 0 (Machine 0)
ro2.tasksByMachine[1][1] = new Task(2,1); //O8: Job 2, Task 1 (Machine 1) ro2.tasksByMachine[0][1] = new Task(1,1); //O5: Job 1, Task 1 (Machine 0)
ro2.tasksByMachine[1][2] = new Task(0,2); //O3: Job 0, Task 2 (Machine 1) ro2.tasksByMachine[0][2] = new Task(0,1); //O2: Job 0, Task 1 (Machine 0)
ro2.tasksByMachine[2][0] = new Task(2,2); //O9: Job 2, Task 2 (Machine 2) ro2.tasksByMachine[1][0] = new Task(1,0); //O4: Job 1, Task 0 (Machine 1)
ro2.tasksByMachine[2][1] = new Task(0,0); //O1: Job 0, Task 0 (Machine 2) ro2.tasksByMachine[1][1] = new Task(2,1); //O8: Job 2, Task 1 (Machine 1)
ro2.tasksByMachine[2][2] = new Task(1,2); //O6: Job 1, Task 2 (Machine 2) ro2.tasksByMachine[1][2] = new Task(0,2); //O3: Job 0, Task 2 (Machine 1)
ro2.tasksByMachine[2][0] = new Task(2,2); //O9: Job 2, Task 2 (Machine 2)
System.out.println("RESOURCE ORDER ENCODING:\n" + ro2 + "\n"); ro2.tasksByMachine[2][1] = new Task(0,0); //O1: Job 0, Task 0 (Machine 2)
ro2.tasksByMachine[2][2] = new Task(1,2); //O6: Job 1, Task 2 (Machine 2)
System.out.println("---------------------------------------------\n");
System.out.println("RESOURCE ORDER ENCODING:\n" + ro2 + "\n");
System.out.println("Default Solver\n");
sched = ro.toSchedule(); System.out.println("---------------------------------------------\n");
System.out.println("SCHEDULE:\n" + sched); System.out.println("Default Solver\n");
System.out.println("VALID: " + sched.isValid()); sched = ro.toSchedule();
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("SCHEDULE:\n" + sched);
System.out.println("---------------------------------------------\n"); System.out.println("VALID: " + sched.isValid());
System.out.println("MAKESPAN: " + sched.makespan());
JobNumbers jo = JobNumbers.fromSchedule(sched);
System.out.println("JOB NUMBER ENCODING (FROM_SCHEDULE): " + jo + "\n"); System.out.println("---------------------------------------------\n");
System.out.println("---------------------------------------------\n"); /*JobNumbers jo = JobNumbers.fromSchedule(sched);
System.out.println("Greedy Solver: STP"); System.out.println("JOB NUMBER ENCODING (FROM_SCHEDULE): " + jo + "\n");*/
PriorityRule SPT = PriorityRule.SPT;
Solver solverSPT = new GreedySolver(SPT); System.out.println("---------------------------------------------\n");
Result resultSPT = solverSPT.solve(instance, System.currentTimeMillis() + 10); System.out.println("Greedy Solver: STP");
sched = resultSPT.schedule; PriorityRule SPT = PriorityRule.SPT;
Solver solverSPT = new GreedySolver(SPT);
System.out.println("SCHEDULE:\n" + sched); Result resultSPT = solverSPT.solve(instance, System.currentTimeMillis() + 10);
System.out.println("VALID: " + sched.isValid()); sched = resultSPT.schedule;
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("SCHEDULE:\n" + sched);
System.out.println("---------------------------------------------\n"); System.out.println("VALID: " + sched.isValid());
System.out.println("Greedy Solver: LRPT\n"); System.out.println("MAKESPAN: " + sched.makespan());
PriorityRule LRPT = PriorityRule.LRPT;
Solver solverLRPT = new GreedySolver(LRPT); System.out.println("---------------------------------------------\n");
Result resultLRPT = solverLRPT.solve(instance, System.currentTimeMillis() + 10); System.out.println("Greedy Solver: LRPT\n");
sched = resultLRPT.schedule; PriorityRule LRPT = PriorityRule.LRPT;
Solver solverLRPT = new GreedySolver(LRPT);
System.out.println("SCHEDULE:\n" + sched); Result resultLRPT = solverLRPT.solve(instance, System.currentTimeMillis() + 10);
System.out.println("VALID: " + sched.isValid()); sched = resultLRPT.schedule;
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("SCHEDULE:\n" + sched);
System.out.println("---------------------------------------------\n"); System.out.println("VALID: " + sched.isValid());
System.out.println("Greedy Solver: EST_SPT\n"); System.out.println("MAKESPAN: " + sched.makespan());
PriorityESTRule EST_SPT = PriorityESTRule.EST_SPT;
Solver solverEST_SPT = new GreedySolver(EST_SPT); System.out.println("---------------------------------------------\n");
Result resultEST_SPT = solverEST_SPT.solve(instance, System.currentTimeMillis() + 10); System.out.println("Greedy Solver: EST_SPT\n");
sched = resultEST_SPT.schedule; PriorityESTRule EST_SPT = PriorityESTRule.EST_SPT;
Solver solverEST_SPT = new GreedySolver(EST_SPT);
System.out.println("SCHEDULE:\n" + sched); Result resultEST_SPT = solverEST_SPT.solve(instance, System.currentTimeMillis() + 10);
System.out.println("VALID: " + sched.isValid()); sched = resultEST_SPT.schedule;
System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("SCHEDULE:\n" + sched);
System.out.println("---------------------------------------------\n"); System.out.println("VALID: " + sched.isValid());
System.out.println("Greedy Solver: ic void applyOn(ResourceOrder order) {\r\n" + System.out.println("MAKESPAN: " + sched.makespan());
" throw new UnsupportedOperationException();EST_SPT\n");
PriorityESTRule EST_LRPT = PriorityESTRule.EST_LRPT; System.out.println("---------------------------------------------\n");
Solver solverEST_LRPT = new GreedySolver(EST_SPT); System.out.println("Greedy Solver: EST_LRPT\n");
Result resultEST_LRPT = solverEST_LRPT.solve(instance, System.currentTimeMillis() + 10); PriorityESTRule EST_LRPT = PriorityESTRule.EST_LRPT;
sched = resultEST_LRPT.schedule; Solver solverEST_LRPT = new GreedySolver(EST_LRPT);
Result resultEST_LRPT = solverEST_LRPT.solve(instance, System.currentTimeMillis() + 10);
System.out.println("SCHEDULE:\n" + sched); sched = resultEST_LRPT.schedule;
System.out.println("VALID: " + sched.isValid());
System.out.println("MAKESPAN: " + sched.makespan()); System.out.println("SCHEDULE:\n" + sched);
System.out.println("VALID: " + sched.isValid());
System.out.println("---------------------------------------------\n"); System.out.println("MAKESPAN: " + sched.makespan());
System.out.println("Descent Solver: \n");
DescentSolver solverDescent = new DescentSolver(); System.out.println("---------------------------------------------\n");
List<Block> criticalBlockList = solverDescent.blocksOfCriticalPath(ro2); System.out.println("Descent Solver: [Executed with EST_LRPT]\n");
for(Block b : criticalBlockList) {
System.out.println(b); DescentSolver solverDescent = new DescentSolver(EST_LRPT);
//System.out.println(solverDescent.neighbors(b));
}
/* System.out.print("****** TEST: blocksOfCriticalPath() ******\n");
sched = ro2.toSchedule(); System.out.print("Number of Jobs : " + instance2.numJobs + "\n");
System.out.print("Number of Tasks : " + instance2.numTasks + "\n");
System.out.println("SCHEDULE:\n" + sched); System.out.print("Number of Machines : " + instance2.numMachines + "\n\n");
System.out.println("VALID: " + sched.isValid());
System.out.println("MAKESPAN: " + sched.makespan());*/
} catch (IOException e) { List<Block> criticalBlockList = solverDescent.blocksOfCriticalPath(ro2);
e.printStackTrace(); for(Block b : criticalBlockList) {
System.exit(1); System.out.println(b);
} for(Swap s : solverDescent.neighbors(b)) {
System.out.println(s);
} }
} }
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("---------------------------------------------\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();
System.exit(1);
}
}
}

View file

@ -1,12 +1,12 @@
package jobshop; package jobshop;
public abstract class Encoding { public abstract class Encoding {
public final Instance instance; public final Instance instance;
public Encoding(Instance instance) { public Encoding(Instance instance) {
this.instance = instance; this.instance = instance;
} }
public abstract Schedule toSchedule(); public abstract Schedule toSchedule();
} }

View file

@ -1,73 +1,79 @@
package jobshop; package jobshop;
import java.io.IOException; import jobshop.encodings.Task;
import java.nio.file.Files;
import java.nio.file.Path; import java.io.IOException;
import java.util.Iterator; import java.nio.file.Files;
import java.util.Scanner; import java.nio.file.Path;
import java.util.stream.Collectors; import java.util.Iterator;
import java.util.Scanner;
public class Instance { import java.util.stream.Collectors;
/** Number of jobs in the instance */ public class Instance {
public final int numJobs;
/** Number of jobs in the instance */
/** Number of tasks per job */ public final int numJobs;
public final int numTasks;
/** Number of tasks per job */
/** Number of machines, assumed to be same as number of tasks. */ public final int numTasks;
public final int numMachines;
/** Number of machines, assumed to be same as number of tasks. */
final int[][] durations; public final int numMachines;
final int[][] machines;
final int[][] durations;
public int duration(int job, int task) { final int[][] machines;
return durations[job][task];
} public int duration(int job, int task) {
public int machine(int job, int task) { return durations[job][task];
return machines[job][task]; }
} public int duration(Task t) {
return duration(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) { public int machine(int job, int task) {
for(int task = 0 ; task < numTasks ; task++) { return machines[job][task];
if(machine(job, task) == wanted_machine) }
return task; public int machine(Task t) {
} return this.machine(t.job, t.task);
throw new RuntimeException("No task targeting machine "+wanted_machine+" on job "+job); }
}
/** among the tasks of the given job, returns the task index that uses the given machine. */
Instance(int numJobs, int numTasks) { public int task_with_machine(int job, int wanted_machine) {
this.numJobs = numJobs; for(int task = 0 ; task < numTasks ; task++) {
this.numTasks = numTasks; if(machine(job, task) == wanted_machine)
this.numMachines = numTasks; return task;
}
durations = new int[numJobs][numTasks]; throw new RuntimeException("No task targeting machine "+wanted_machine+" on job "+job);
machines = new int[numJobs][numTasks]; }
}
Instance(int numJobs, int numTasks) {
public static Instance fromFile(Path path) throws IOException { this.numJobs = numJobs;
Iterator<String> lines = Files.readAllLines(path).stream() this.numTasks = numTasks;
.filter(l -> !l.startsWith("#")) this.numMachines = numTasks;
.collect(Collectors.toList())
.iterator(); durations = new int[numJobs][numTasks];
machines = new int[numJobs][numTasks];
Scanner header = new Scanner(lines.next()); }
int num_jobs = header.nextInt();
int num_tasks = header.nextInt(); /** Parses a instance from a file. */
Instance pb = new Instance(num_jobs, num_tasks); public static Instance fromFile(Path path) throws IOException {
Iterator<String> lines = Files.readAllLines(path).stream()
for(int job = 0 ; job<num_jobs ; job++) { .filter(l -> !l.startsWith("#"))
Scanner line = new Scanner(lines.next()); .collect(Collectors.toList())
for(int task = 0 ; task < num_tasks ; task++) { .iterator();
pb.machines[job][task] = line.nextInt();
pb.durations[job][task] = line.nextInt(); Scanner header = new Scanner(lines.next());
} int num_jobs = header.nextInt();
line.close(); int num_tasks = header.nextInt();
} Instance pb = new Instance(num_jobs, num_tasks);
header.close(); for(int job = 0 ; job<num_jobs ; job++) {
Scanner line = new Scanner(lines.next());
return pb; for(int task = 0 ; task < num_tasks ; task++) {
} pb.machines[job][task] = line.nextInt();
} pb.durations[job][task] = line.nextInt();
}
}
return pb;
}
}

View file

@ -1,154 +1,223 @@
package jobshop; package jobshop;
import java.io.PrintStream; import java.io.PrintStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays; import java.util.ArrayList;
import java.util.HashMap; import java.util.Arrays;
import java.util.List; 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.PriorityESTRule;
import jobshop.solvers.GreedySolver.PriorityRule; import jobshop.solvers.GreedySolver.PriorityRule;
import jobshop.solvers.GreedySolver; import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParser; import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.ArgumentParserException; import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Namespace;
public class Main {
public class Main { // ******************************************** Main - Arguments ************************************************ //
// *** Basic + Random *** //
/** All solvers available in this program */ // --solver basic random --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
private static HashMap<String, Solver> solvers;
static { // *** Greedy Solvers *** //
solvers = new HashMap<>(); // --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
solvers.put("basic", new BasicSolver());
solvers.put("random", new RandomSolver()); // *** Descent Solvers *** //
// add new solvers here // --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
PriorityRule SPT = PriorityRule.SPT;
solvers.put("greedySPT", new GreedySolver(SPT)); // *** Taboo Solvers *** //
PriorityRule LRPT = PriorityRule.LRPT; // --solver Taboo-EST_LRPT(1,1) --instance aaa1 ft06 ft10 ft20 la01 la02 la03 la04 la05 la06 la07 la08 la09
solvers.put("greedyLRPT", new GreedySolver(LRPT)); // --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
PriorityESTRule EST_SPT = PriorityESTRule.EST_SPT; // --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
solvers.put("greedyEST_SPT", new GreedySolver(EST_SPT)); // --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
PriorityESTRule EST_LRPT = PriorityESTRule.EST_LRPT; // --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
solvers.put("greedyEST_LRPT", new GreedySolver(EST_LRPT));
} /** All solvers available in this program */
private static HashMap<String, Solver> solvers;
@SuppressWarnings("unused") static {
public static void main(String[] args) { solvers = new HashMap<>();
ArgumentParser parser = ArgumentParsers.newFor("jsp-solver").build() solvers.put("basic", new BasicSolver());
.defaultHelp(true) solvers.put("random", new RandomSolver());
.description("Solves jobshop problems."); // Add new solvers here
// ******************** Greedy Solver ******************** //
parser.addArgument("-t", "--timeout") PriorityRule SPT = PriorityRule.SPT;
.setDefault(1L) solvers.put("Greedy-SPT", new GreedySolver(SPT));
.type(Long.class) PriorityRule LRPT = PriorityRule.LRPT;
.help("Solver timeout in seconds for each instance"); solvers.put("Greedy-LRPT", new GreedySolver(LRPT));
parser.addArgument("--solver") PriorityESTRule EST_SPT = PriorityESTRule.EST_SPT;
.nargs("+") solvers.put("Greedy-EST_SPT", new GreedySolver(EST_SPT));
.required(true) PriorityESTRule EST_LRPT = PriorityESTRule.EST_LRPT;
.help("Solver(s) to use (space separated if more than one)"); solvers.put("Greedy-EST_LRPT", new GreedySolver(EST_LRPT));
parser.addArgument("--instance") // ******************* Descent Solver ******************** //
.nargs("+") solvers.put("Descent-SPT", new DescentSolver(SPT));
.required(true) solvers.put("Descent-LRPT", new DescentSolver(LRPT));
.help("Instance(s) to solve (space separated if more than one)"); solvers.put("Descent-EST_SPT", new DescentSolver(EST_SPT));
solvers.put("Descent-EST_LRPT", new DescentSolver(EST_LRPT));
Namespace ns = null;
try { // ******************** Taboo Solver ********************* //
ns = parser.parseArgs(args); solvers.put("Taboo-EST_LRPT(1,1)", new TabooSolver(EST_LRPT, 1, 1));
} catch (ArgumentParserException e) {
parser.handleError(e); solvers.put("Taboo-EST_LRPT(1,10)", new TabooSolver(EST_LRPT, 1, 10));
System.exit(1); 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));
PrintStream output = System.out; 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));
long solveTimeMs = ns.getLong("timeout") * 1000; 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));
List<String> solversToTest = ns.getList("solver"); solvers.put("Taboo-EST_LRPT(9,10)", new TabooSolver(EST_LRPT, 9, 10));
for(String solverName : solversToTest) { solvers.put("Taboo-EST_LRPT(10,10)", new TabooSolver(EST_LRPT, 10, 10));
if(!solvers.containsKey(solverName)) {
System.err.println("ERROR: Solver \"" + solverName + "\" is not avalaible."); solvers.put("Taboo-EST_LRPT(1,100)", new TabooSolver(EST_LRPT, 1, 100));
System.err.println(" Available solvers: " + solvers.keySet().toString()); solvers.put("Taboo-EST_LRPT(6,100)", new TabooSolver(EST_LRPT, 6, 100));
System.err.println(" You can provide your own solvers by adding them to the `Main.solvers` HashMap."); solvers.put("Taboo-EST_LRPT(8,100)", new TabooSolver(EST_LRPT, 8, 100));
System.exit(1); 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));
List<String> instances = ns.<String>getList("instance"); solvers.put("Taboo-EST_LRPT(20,100)", new TabooSolver(EST_LRPT, 20, 100));
for(String instanceName : instances) { solvers.put("Taboo-EST_LRPT(50,100)", new TabooSolver(EST_LRPT, 50, 100));
if(!BestKnownResult.isKnown(instanceName)) { solvers.put("Taboo-EST_LRPT(100,100)", new TabooSolver(EST_LRPT, 100, 100));
System.err.println("ERROR: instance \"" + instanceName + "\" is not avalaible.");
System.err.println(" available instances: " + Arrays.toString(BestKnownResult.instances)); solvers.put("Taboo-EST_LRPT(1,1000)", new TabooSolver(EST_LRPT, 1, 1000));
System.exit(1); 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));
float[] runtimes = new float[solversToTest.size()]; solvers.put("Taboo-EST_LRPT(14,1000)", new TabooSolver(EST_LRPT, 14, 1000));
float[] distances = new float[solversToTest.size()]; 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));
try { solvers.put("Taboo-EST_LRPT(100,1000)", new TabooSolver(EST_LRPT, 100, 1000));
output.print( " ");;
for(String s : solversToTest) solvers.put("Taboo-EST_LRPT(1,5000)", new TabooSolver(EST_LRPT, 1, 5000));
output.printf("%-30s", s); solvers.put("Taboo-EST_LRPT(6,5000)", new TabooSolver(EST_LRPT, 6, 5000));
output.println(); solvers.put("Taboo-EST_LRPT(8,5000)", new TabooSolver(EST_LRPT, 8, 5000));
output.print("instance size best "); solvers.put("Taboo-EST_LRPT(10,5000)", new TabooSolver(EST_LRPT, 10, 5000));
for(String s : solversToTest) { solvers.put("Taboo-EST_LRPT(12,5000)", new TabooSolver(EST_LRPT, 12, 5000));
output.print("runtime makespan ecart "); 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));
output.println(); 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));
}
for(String instanceName : instances) {
int bestKnown = BestKnownResult.of(instanceName);
public static void main(String[] args) {
ArgumentParser parser = ArgumentParsers.newFor("jsp-solver").build()
Path path = Paths.get("instances/", instanceName); .defaultHelp(true)
Instance instance = Instance.fromFile(path); .description("Solves jobshop problems.");
output.printf("%-8s %-5s %4d ",instanceName, instance.numJobs +"x"+instance.numTasks, bestKnown); parser.addArgument("-t", "--timeout")
.setDefault(1L)
for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) { .type(Long.class)
String solverName = solversToTest.get(solverId); .help("Solver timeout in seconds for each instance");
Solver solver = solvers.get(solverName); parser.addArgument("--solver")
long start = System.currentTimeMillis(); .nargs("+")
long deadline = System.currentTimeMillis() + solveTimeMs; .required(true)
Result result = solver.solve(instance, deadline); .help("Solver(s) to use (space separated if more than one)");
long runtime = System.currentTimeMillis() - start;
parser.addArgument("--instance")
if(!result.schedule.isValid()) { .nargs("+")
System.err.println("ERROR: solver returned an invalid schedule"); .required(true)
System.exit(1); .help("Instance(s) to solve (space separated if more than one)");
}
Namespace ns = null;
assert result.schedule.isValid(); try {
int makespan = result.schedule.makespan(); ns = parser.parseArgs(args);
float dist = 100f * (makespan - bestKnown) / (float) bestKnown; } catch (ArgumentParserException e) {
runtimes[solverId] += (float) runtime / (float) instances.size(); parser.handleError(e);
distances[solverId] += dist / (float) instances.size(); System.exit(1);
}
output.printf("%7d %8s %5.1f ", runtime, makespan, dist);
output.flush(); PrintStream output = System.out;
}
output.println(); long solveTimeMs = ns.getLong("timeout") * 1000;
} List<String> solversToTest = ns.getList("solver");
for(String solverName : solversToTest) {
if(!solvers.containsKey(solverName)) {
output.printf("%-8s %-5s %4s ", "AVG", "-", "-"); System.err.println("ERROR: Solver \"" + solverName + "\" is not avalaible.");
for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) { System.err.println(" Available solvers: " + solvers.keySet().toString());
output.printf("%7.1f %8s %5.1f ", runtimes[solverId], "-", distances[solverId]); System.err.println(" You can provide your own solvers by adding them to the `Main.solvers` HashMap.");
} System.exit(1);
}
}
List<String> instancePrefixes = ns.getList("instance");
} catch (Exception e) { List<String> instances = new ArrayList<>();
e.printStackTrace(); for(String instancePrefix : instancePrefixes) {
System.exit(1); 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( " ");
for(String s : solversToTest)
output.printf("%-30s", s);
output.println();
output.print("instance size best ");
for(String s : solversToTest) {
output.print("runtime makespan ecart ");
}
output.println();
for(String instanceName : instances) {
int bestKnown = BestKnownResult.of(instanceName);
Path path = Paths.get("instances/", instanceName);
Instance instance = Instance.fromFile(path);
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;
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();
}
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]);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}

View file

@ -1,23 +1,20 @@
package jobshop; package jobshop;
import java.util.Optional; public class Result {
@SuppressWarnings("unused") public Result(Instance instance, Schedule schedule, ExitCause cause) {
public class Result { this.instance = instance;
this.schedule = schedule;
public Result(Instance instance, Schedule schedule, ExitCause cause) { this.cause = cause;
this.instance = instance; }
this.schedule = schedule;
this.cause = cause; public enum ExitCause {
} Timeout, ProvedOptimal, Blocked
}
public enum ExitCause {
Timeout, ProvedOptimal, Blocked public final Instance instance;
} public final Schedule schedule;
public final ExitCause cause;
public final Instance instance;
public final Schedule schedule;
public final ExitCause cause; }
}

View file

@ -1,157 +1,153 @@
package jobshop; package jobshop;
import java.util.Arrays; import jobshop.encodings.Task;
import java.util.Comparator;
import java.util.LinkedList; import java.util.*;
import java.util.List; import java.util.stream.IntStream;
import java.util.Optional;
import java.util.stream.IntStream; public class Schedule {
public final Instance pb;
import jobshop.encodings.Task; // start times of each job and task
// times[j][i] is the start time of task (j,i) : i^th task of the j^th job
public class Schedule { final int[][] times;
public final Instance pb;
// start times of each job and task public Schedule(Instance pb, int[][] times) {
// times[j][i] is the start time of task (j,i) : i^th task of the j^th job this.pb = pb;
final int[][] times; this.times = new int[pb.numJobs][];
for(int j = 0 ; j < pb.numJobs ; j++) {
public Schedule(Instance pb, int[][] times) { this.times[j] = Arrays.copyOf(times[j], pb.numTasks);
this.pb = pb; }
this.times = new int[pb.numJobs][]; }
for(int j = 0 ; j < pb.numJobs ; j++) {
this.times[j] = Arrays.copyOf(times[j], pb.numTasks); public int startTime(int job, int task) {
} return times[job][task];
} }
public int startTime(int job, int task) { /** Returns true if this schedule is valid (no constraint is violated) */
return times[job][task]; public boolean isValid() {
} for(int j = 0 ; j<pb.numJobs ; j++) {
for(int t = 1 ; t<pb.numTasks ; t++) {
/** Returns true if this schedule is valid (no constraint is violated) */ if(startTime(j, t-1) + pb.duration(j, t-1) > startTime(j, t))
public boolean isValid() { return false;
for(int j = 0 ; j<pb.numJobs ; j++) { }
for(int t = 1 ; t<pb.numTasks ; t++) { for(int t = 0 ; t<pb.numTasks ; t++) {
if(startTime(j, t-1) + pb.duration(j, t-1) > startTime(j, t)) if(startTime(j, t) < 0)
return false; return false;
} }
for(int t = 0 ; t<pb.numTasks ; t++) { }
if(startTime(j, t) < 0)
return false; for (int machine = 0 ; machine < pb.numMachines ; machine++) {
} for(int j1=0 ; j1<pb.numJobs ; j1++) {
} int t1 = pb.task_with_machine(j1, machine);
for(int j2=j1+1 ; j2<pb.numJobs ; j2++) {
for (int machine = 0 ; machine < pb.numMachines ; machine++) { int t2 = pb.task_with_machine(j2, machine);
for(int j1=0 ; j1<pb.numJobs ; j1++) {
int t1 = pb.task_with_machine(j1, machine); boolean t1_first = startTime(j1, t1) + pb.duration(j1, t1) <= startTime(j2, t2);
for(int j2=j1+1 ; j2<pb.numJobs ; j2++) { boolean t2_first = startTime(j2, t2) + pb.duration(j2, t2) <= startTime(j1, t1);
int t2 = pb.task_with_machine(j2, machine);
if(!t1_first && !t2_first)
boolean t1_first = startTime(j1, t1) + pb.duration(j1, t1) <= startTime(j2, t2); return false;
boolean t2_first = startTime(j2, t2) + pb.duration(j2, t2) <= startTime(j1, t1); }
}
if(!t1_first && !t2_first) }
return false;
} return true;
} }
}
public int makespan() {
return true; int max = -1;
} for(int j = 0 ; j<pb.numJobs ; j++) {
max = Math.max(max, startTime(j, pb.numTasks-1) + pb.duration(j, pb.numTasks -1));
public int makespan() { }
int max = -1; return max;
for(int j = 0 ; j<pb.numJobs ; j++) { }
max = Math.max(max, startTime(j, pb.numTasks-1) + pb.duration(j, pb.numTasks -1));
} public int startTime(Task task) {
return max; return startTime(task.job, task.task);
} }
public int startTime(Task task) { public int endTime(Task task) {
return startTime(task.job, task.task); return startTime(task) + pb.duration(task.job, task.task);
} }
public int endTime(Task task) { public boolean isCriticalPath(List<Task> path) {
return startTime(task) + pb.duration(task.job, task.task); if(startTime(path.get(0)) != 0) {
} return false;
}
public boolean isCriticalPath(List<Task> path) { if(endTime(path.get(path.size()-1)) != makespan()) {
if(startTime(path.get(0)) != 0) { return false;
return false; }
} for(int i=0 ; i<path.size()-1 ; i++) {
if(endTime(path.get(path.size()-1)) != makespan()) { if(endTime(path.get(i)) != startTime(path.get(i+1)))
return false; return false;
} }
for(int i=0 ; i<path.size()-1 ; i++) { return true;
if(endTime(path.get(i)) != startTime(path.get(i+1))) }
return false;
} public List<Task> criticalPath() {
return true; // select task with greatest end time
} Task ldd = IntStream.range(0, pb.numJobs)
.mapToObj(j -> new Task(j, pb.numTasks-1))
public List<Task> criticalPath() { .max(Comparator.comparing(this::endTime))
// select task with greatest end time .get();
Task ldd = IntStream.range(0, pb.numJobs) assert endTime(ldd) == makespan();
.mapToObj(j -> new Task(j, pb.numTasks-1))
.max(Comparator.comparing(this::endTime)) // list that will contain the critical path.
.get(); // we construct it from the end, starting with the
assert endTime(ldd) == makespan(); // task that finishes last
LinkedList<Task> path = new LinkedList<>();
// list that will contain the critical path. path.add(0,ldd);
// we construct it from the end, starting with the
// task that finishes last // keep adding tasks to the path until the first task in the path
LinkedList<Task> path = new LinkedList<>(); // starts a time 0
path.add(0,ldd); while(startTime(path.getFirst()) != 0) {
Task cur = path.getFirst();
// keep adding tasks to the path until the first task in the path int machine = pb.machine(cur.job, cur.task);
// starts a time 0
while(startTime(path.getFirst()) != 0) { // will contain the task that was delaying the start
Task cur = path.getFirst(); // of our current task
int machine = pb.machine(cur.job, cur.task); Optional<Task> latestPredecessor = Optional.empty();
// will contain the task that was delaying the start if(cur.task > 0) {
// of our current task // our current task has a predecessor on the job
Optional<Task> latestPredecessor = Optional.empty(); Task predOnJob = new Task(cur.job, cur.task -1);
if(cur.task > 0) { // if it was the delaying task, save it to predecessor
// our current task has a predecessor on the job if(endTime(predOnJob) == startTime(cur))
Task predOnJob = new Task(cur.job, cur.task -1); latestPredecessor = Optional.of(predOnJob);
}
// if it was the delaying task, save it to predecessor if(!latestPredecessor.isPresent()) {
if(endTime(predOnJob) == startTime(cur)) // no latest predecessor found yet, look among tasks executing on the same machine
latestPredecessor = Optional.of(predOnJob); latestPredecessor = IntStream.range(0, pb.numJobs)
} .mapToObj(j -> new Task(j, pb.task_with_machine(j, machine)))
if(!latestPredecessor.isPresent()) { .filter(t -> endTime(t) == startTime(cur))
// no latest predecessor found yet, look among tasks executing on the same machine .findFirst();
latestPredecessor = IntStream.range(0, pb.numJobs) }
.mapToObj(j -> new Task(j, pb.task_with_machine(j, machine))) // at this point we should have identified a latest predecessor, either on the job or on the machine
.filter(t -> endTime(t) == startTime(cur)) assert latestPredecessor.isPresent() && endTime(latestPredecessor.get()) == startTime(cur);
.findFirst(); // insert predecessor at the beginning of the path
} path.add(0, latestPredecessor.get());
// at this point we should have identified a latest predecessor, either on the job or on the machine }
assert latestPredecessor.isPresent() && endTime(latestPredecessor.get()) == startTime(cur); assert isCriticalPath(path);
// insert predecessor at the beginning of the path return path;
path.add(0, latestPredecessor.get()); }
}
assert isCriticalPath(path); public Schedule copy() {
return path; return new Schedule(this.pb, this.times);
} }
public Schedule copy() { /****************************************************************/
return new Schedule(this.pb, this.times); /* Implémentation de la méthode toString() de la classe Schedule*/
} /****************************************************************/
public String toString() {
/****************************************************************/ String res = "";
/* Implémentation de la méthode toString() de la classe Schedule*/ for (int i = 0; i < this.times.length; i++) {
/****************************************************************/ res += "Job " + Integer.toString(i + 1) + " starting times : \n";
public String toString() { for (int j = 0; j < this.times[i].length; j++) {
String res = ""; res += "\tTask " + Integer.toString(j + 1) + " starts at time : " + Integer.toString(this.times[i][j]) + "\n";
for (int i = 0; i < this.times.length; i++) { }
res += "Job " + Integer.toString(i + 1) + " starting times : \n"; }
for (int j = 0; j < this.times[i].length; j++) { return res;
res += "\tTask " + Integer.toString(j + 1) + " starts at time : " + Integer.toString(this.times[i][j]) + "\n"; }
} }
}
return res;
}
}

View file

@ -1,7 +1,7 @@
package jobshop; package jobshop;
public interface Solver { public interface Solver {
Result solve(Instance instance, long deadline); Result solve(Instance instance, long deadline);
} }

View file

@ -1,116 +1,84 @@
package jobshop.encodings; package jobshop.encodings;
import jobshop.Encoding; import jobshop.Encoding;
import jobshop.Instance; import jobshop.Instance;
import jobshop.Schedule; import jobshop.Schedule;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.stream.IntStream; import java.util.stream.IntStream;
/** Représentation par numéro de job. */ /** Représentation par numéro de job. */
public class JobNumbers extends Encoding { public class JobNumbers extends Encoding {
/** A numJobs * numTasks array containing the representation by job numbers. */ /** A numJobs * numTasks array containing the representation by job numbers. */
public final int[] jobs; 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. */ * element of `jobs` that has not been set yet. */
public int nextToSet = 0; public int nextToSet = 0;
public JobNumbers(Instance instance) { public JobNumbers(Instance instance) {
super(instance); super(instance);
jobs = new int[instance.numJobs * instance.numMachines]; jobs = new int[instance.numJobs * instance.numMachines];
Arrays.fill(jobs, -1); Arrays.fill(jobs, -1);
} }
public JobNumbers(Schedule schedule) { public JobNumbers(Schedule schedule) {
super(schedule.pb); super(schedule.pb);
this.jobs = new int[instance.numJobs * instance.numTasks]; this.jobs = new int[instance.numJobs * instance.numTasks];
// for each job indicates which is the next task to be scheduled // for each job indicates which is the next task to be scheduled
int[] nextOnJob = new int[instance.numJobs]; int[] nextOnJob = new int[instance.numJobs];
while(Arrays.stream(nextOnJob).anyMatch(t -> t < instance.numTasks)) { while(Arrays.stream(nextOnJob).anyMatch(t -> t < instance.numTasks)) {
Task next = IntStream Task next = IntStream
// for all jobs numbers // for all jobs numbers
.range(0, instance.numJobs) .range(0, instance.numJobs)
// build the next task for this job // build the next task for this job
.mapToObj(j -> new Task(j, nextOnJob[j])) .mapToObj(j -> new Task(j, nextOnJob[j]))
// only keep valid tasks (some jobs have no task left to be executed) // only keep valid tasks (some jobs have no task left to be executed)
.filter(t -> t.task < instance.numTasks) .filter(t -> t.task < instance.numTasks)
// select the task with the earliest execution time // select the task with the earliest execution time
.min(Comparator.comparing(t -> schedule.startTime(t.job, t.task))) .min(Comparator.comparing(t -> schedule.startTime(t.job, t.task)))
.get(); .get();
this.jobs[nextToSet++] = next.job; this.jobs[nextToSet++] = next.job;
nextOnJob[next.job] += 1; nextOnJob[next.job] += 1;
} }
} }
@Override @Override
public Schedule toSchedule() { public Schedule toSchedule() {
// time at which each machine is going to be freed // time at which each machine is going to be freed
int[] nextFreeTimeResource = new int[instance.numMachines]; int[] nextFreeTimeResource = new int[instance.numMachines];
// for each job, the first task that has not yet been scheduled // for each job, the first task that has not yet been scheduled
int[] nextTask = new int[instance.numJobs]; int[] nextTask = new int[instance.numJobs];
// for each task, its start time // for each task, its start time
int[][] startTimes = new int[instance.numJobs][instance.numTasks]; int[][] startTimes = new int[instance.numJobs][instance.numTasks];
// compute the earliest start time for every task of every job // compute the earliest start time for every task of every job
for(int job : jobs) { for(int job : jobs) {
int task = nextTask[job]; int task = nextTask[job];
int machine = instance.machine(job, task); int machine = instance.machine(job, task);
// earliest start time for this task // earliest start time for this task
int est = task == 0 ? 0 : startTimes[job][task-1] + instance.duration(job, task-1); int est = task == 0 ? 0 : startTimes[job][task-1] + instance.duration(job, task-1);
est = Math.max(est, nextFreeTimeResource[machine]); est = Math.max(est, nextFreeTimeResource[machine]);
startTimes[job][task] = est; startTimes[job][task] = est;
nextFreeTimeResource[machine] = est + instance.duration(job, task); nextFreeTimeResource[machine] = est + instance.duration(job, task);
nextTask[job] = task + 1; nextTask[job] = task + 1;
} }
return new Schedule(instance, startTimes); return new Schedule(instance, startTimes);
} }
public static JobNumbers fromSchedule(Schedule sched) { @Override
JobNumbers jo = new JobNumbers(sched.pb); public String toString() {
return Arrays.toString(Arrays.copyOfRange(jobs,0, nextToSet));
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,120 +1,126 @@
package jobshop.encodings; package jobshop.encodings;
import java.util.Comparator; import jobshop.Encoding;
import java.util.Optional; import jobshop.Instance;
import java.util.stream.IntStream; import jobshop.Schedule;
import jobshop.Encoding; import java.util.Comparator;
import jobshop.Instance; import java.util.Optional;
import jobshop.Schedule; import java.util.stream.IntStream;
public class ResourceOrder extends Encoding {
public class ResourceOrder extends Encoding {
// for each machine m, taskByMachine[m] is an array of tasks to be
public final Task[][] tasksByMachine; // 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 ResourceOrder(Instance instance) { public final int[] nextFreeSlot;
super(instance);
/** Creates a new empty resource order. */
this.tasksByMachine = new Task[instance.numMachines][instance.numJobs]; public ResourceOrder(Instance instance)
for (int i = 0; i < instance.numMachines; i++) { {
for (int j = 0; j < instance.numJobs; j++) { super(instance);
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]; nextFreeSlot = new int[instance.numMachines];
} }
public ResourceOrder(Schedule schedule) { /** Creates a resource order from a schedule. */
super(schedule.pb); public ResourceOrder(Schedule schedule)
Instance pb = schedule.pb; {
super(schedule.pb);
this.tasksByMachine = new Task[pb.numMachines][]; Instance pb = schedule.pb;
this.nextFreeSlot = new int[instance.numMachines];
this.tasksByMachine = new Task[pb.numMachines][];
for(int m = 0 ; m<schedule.pb.numMachines ; m++) { this.nextFreeSlot = new int[instance.numMachines];
final int machine = m;
for(int m = 0 ; m<schedule.pb.numMachines ; m++) {
// for thi machine, find all tasks that are executed on it and sort them by their start time final int machine = m;
tasksByMachine[m] =
IntStream.range(0, pb.numJobs) // all job numbers // for thi machine, find all tasks that are executed on it and sort them by their start time
.mapToObj(j -> new Task(j, pb.task_with_machine(j, machine))) // all tasks on this machine (one per job) tasksByMachine[m] =
.sorted(Comparator.comparing(t -> schedule.startTime(t.job, t.task))) // sorted by start time IntStream.range(0, pb.numJobs) // all job numbers
.toArray(Task[]::new); // as new array and store in tasksByMachine .mapToObj(j -> new Task(j, pb.task_with_machine(j, machine))) // all tasks on this machine (one per job)
.sorted(Comparator.comparing(t -> schedule.startTime(t.job, t.task))) // sorted by start time
// indicate that all tasks have been initialized for machine m .toArray(Task[]::new); // as new array and store in tasksByMachine
nextFreeSlot[m] = instance.numJobs;
} // indicate that all tasks have been initialized for machine m
} nextFreeSlot[m] = instance.numJobs;
}
}
@Override
public Schedule toSchedule() { @Override
// indicate for each task that have been scheduled, its start time public Schedule toSchedule() {
int [][] startTimes = new int [instance.numJobs][instance.numTasks]; // indicate for each task that have been scheduled, its start time
int [][] startTimes = new int [instance.numJobs][instance.numTasks];
// for each job, how many tasks have been scheduled (0 initially)
int[] nextToScheduleByJob = new int[instance.numJobs]; // for each job, how many tasks have been scheduled (0 initially)
int[] nextToScheduleByJob = new int[instance.numJobs];
// for each machine, how many tasks have been scheduled (0 initially)
int[] nextToScheduleByMachine = new int[instance.numMachines]; // for each machine, how many tasks have been scheduled (0 initially)
int[] nextToScheduleByMachine = new int[instance.numMachines];
// for each machine, earliest time at which the machine can be used
int[] releaseTimeOfMachine = new int[instance.numMachines]; // for each machine, earliest time at which the machine can be used
int[] releaseTimeOfMachine = new int[instance.numMachines];
// loop while there remains a job that has unscheduled tasks
while(IntStream.range(0, instance.numJobs).anyMatch(m -> nextToScheduleByJob[m] < instance.numTasks)) { // loop while there remains a job that has unscheduled tasks
while(IntStream.range(0, instance.numJobs).anyMatch(m -> nextToScheduleByJob[m] < instance.numTasks)) {
// selects a task that has noun scheduled predecessor on its job and machine :
// - it is the next to be schedule on a machine // selects a task that has noun scheduled predecessor on its job and machine :
// - it is the next to be scheduled on its job // - it is the next to be schedule on a machine
// if there is no such task, we have cyclic dependency and the solution is invalid // - it is the next to be scheduled on its job
Optional<Task> schedulable = // if there is no such task, we have cyclic dependency and the solution is invalid
IntStream.range(0, instance.numMachines) // all machines ... Optional<Task> schedulable =
.filter(m -> nextToScheduleByMachine[m] < instance.numJobs) // ... with unscheduled jobs IntStream.range(0, instance.numMachines) // all machines ...
.mapToObj(m -> this.tasksByMachine[m][nextToScheduleByMachine[m]]) // tasks that are next to schedule on a machine ... .filter(m -> nextToScheduleByMachine[m] < instance.numJobs) // ... with unscheduled jobs
.filter(task -> task.task == nextToScheduleByJob[task.job]) // ... and on their job .mapToObj(m -> this.tasksByMachine[m][nextToScheduleByMachine[m]]) // tasks that are next to schedule on a machine ...
.findFirst(); // select the first one if any .filter(task -> task.task == nextToScheduleByJob[task.job]) // ... and on their job
.findFirst(); // select the first one if any
if(schedulable.isPresent()) {
// we found a schedulable task, lets call it t if(schedulable.isPresent()) {
Task t = schedulable.get(); // we found a schedulable task, lets call it t
int machine = instance.machine(t.job, t.task); Task t = schedulable.get();
int machine = instance.machine(t.job, t.task);
// 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); // compute the earliest start time (est) of the task
est = Math.max(est, releaseTimeOfMachine[instance.machine(t.job, t.task)]); int est = t.task == 0 ? 0 : startTimes[t.job][t.task-1] + instance.duration(t.job, t.task-1);
startTimes[t.job][t.task] = est; est = Math.max(est, releaseTimeOfMachine[instance.machine(t)]);
startTimes[t.job][t.task] = est;
// mark the task as scheduled
nextToScheduleByJob[t.job]++; // mark the task as scheduled
nextToScheduleByMachine[machine]++; nextToScheduleByJob[t.job]++;
// increase the release time of the machine nextToScheduleByMachine[machine]++;
releaseTimeOfMachine[machine] = est + instance.duration(t.job, t.task); // increase the release time of the machine
} else { releaseTimeOfMachine[machine] = est + instance.duration(t.job, t.task);
// no tasks are schedulable, there is no solution for this resource ordering } else {
return null; // no tasks are schedulable, there is no solution for this resource ordering
} return null;
} }
// we exited the loop : all tasks have been scheduled successfully }
return new Schedule(instance, startTimes); // we exited the loop : all tasks have been scheduled successfully
} return new Schedule(instance, startTimes);
}
@Override
public String toString() { /** Creates an exact copy of this resource order. */
String res = ""; public ResourceOrder copy() {
for (int i = 0; i < this.tasksByMachine.length; i++) { return new ResourceOrder(this.toSchedule());
res += "Machine number : " + Integer.toString(i+1) + "\n"; }
for (int j = 0; j < this.tasksByMachine[i].length; j++) {
res += "\tUse number " + Integer.toString(j+1) + " : " + this.tasksByMachine[i][j].add_one() + "\n"; @Override
} public String toString() {
} String res = "";
return res; for (int i = 0; i < this.tasksByMachine.length; i++) {
} res += "Machine number : " + Integer.toString(i+1) + "\n";
for (int j = 0; j < this.tasksByMachine[i].length; j++) {
} res += "\tUse number " + Integer.toString(j+1) + " : " + this.tasksByMachine[i][j].add_one() + "\n";
}
}
return res;
}
}

View file

@ -1,45 +1,45 @@
package jobshop.encodings; package jobshop.encodings;
import java.util.Objects; import java.util.Objects;
/** Represents a task (job,task) of an jobshop problem. /** Represents a task (job,task) of an jobshop problem.
* *
* Example : (2, 3) repesents the fourth task of the third job. (remeber that we tart counting at 0) * Example : (2, 3) repesents the fourth task of the third job. (remeber that we tart counting at 0)
* */ * */
public final class Task { public final class Task {
/** Identifier of the job */ /** Identifier of the job */
public final int job; public final int job;
/** Index of the task inside the job. */ /** Index of the task inside the job. */
public final int task; public final int task;
public Task(int job, int task) { public Task(int job, int task) {
this.job = job; this.job = job;
this.task = task; this.task = task;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Task task1 = (Task) o; Task task1 = (Task) o;
return job == task1.job && return job == task1.job &&
task == task1.task; task == task1.task;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(job, task); return Objects.hash(job, task);
} }
@Override @Override
public String toString() { public String toString() {
return "Job " + this.job + " Task " + this.task; return "(" + job +", " + task + '}';
} }
public Task add_one() { public Task add_one() {
return new Task(this.job + 1, this.task + 1); return new Task(this.job + 1, this.task + 1);
} }
} }

View file

@ -1,21 +1,21 @@
package jobshop.solvers; package jobshop.solvers;
import jobshop.Instance; import jobshop.Instance;
import jobshop.Result; import jobshop.Result;
import jobshop.Solver; import jobshop.Solver;
import jobshop.encodings.JobNumbers; import jobshop.encodings.JobNumbers;
public class BasicSolver implements Solver { public class BasicSolver implements Solver {
@Override @Override
public Result solve(Instance instance, long deadline) { public Result solve(Instance instance, long deadline) {
JobNumbers sol = new JobNumbers(instance); JobNumbers sol = new JobNumbers(instance);
for(int t = 0 ; t<instance.numTasks ; t++) { for(int t = 0 ; t<instance.numTasks ; t++) {
for(int j = 0 ; j<instance.numJobs ; j++) { for(int j = 0 ; j<instance.numJobs ; j++) {
sol.jobs[sol.nextToSet++] = j; sol.jobs[sol.nextToSet++] = j;
} }
} }
return new Result(instance, sol.toSchedule(), Result.ExitCause.Blocked); return new Result(instance, sol.toSchedule(), Result.ExitCause.Blocked);
} }
} }

View file

@ -2,15 +2,34 @@ package jobshop.solvers;
import jobshop.Instance; import jobshop.Instance;
import jobshop.Result; import jobshop.Result;
import jobshop.Result.ExitCause;
import jobshop.Schedule; import jobshop.Schedule;
import jobshop.Solver; import jobshop.Solver;
import jobshop.encodings.ResourceOrder; import jobshop.encodings.ResourceOrder;
import jobshop.encodings.Task; import jobshop.encodings.Task;
import jobshop.solvers.GreedySolver.PriorityESTRule;
import jobshop.solvers.GreedySolver.PriorityRule;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DescentSolver implements Solver { 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. /** 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. * 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)] * Represent the task sequence : [(0,2) (2,1)]
* *
* */ * */
public static class Block { public static class Block {
/** machine on which the block is identified */ /** machine on which the block is identified */
final int machine; final int machine;
/** index of the first task of the block */ /** index of the first task of the block */
@ -78,7 +97,7 @@ public class DescentSolver implements Solver {
// Retrieve the tasks to be swap // Retrieve the tasks to be swap
Task task1 = order.tasksByMachine[this.machine][this.t1]; Task task1 = order.tasksByMachine[this.machine][this.t1];
Task task2 = order.tasksByMachine[this.machine][this.t2]; 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.t1] = task2;
order.tasksByMachine[this.machine][this.t2] = task1; 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 + "}"; return "Swap: {M" + this.machine + " | t1 = " + this.t1 + " | t2 = " + this.t2 + "}";
} }
} }
// ************************************************************************************************************* //
// *************************************** DescentSolver: solve Method ***************************************** //
// ************************************************************************************************************* //
@Override @Override
public Result solve(Instance instance, long deadline) { 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. */ /** Returns a list of all blocks of the critical path. */
public List<Block> blocksOfCriticalPath(ResourceOrder order) { public List<Block> blocksOfCriticalPath(ResourceOrder order) {
List<Block> criticalBlockList = new ArrayList<>(); List<Block> criticalBlockList = new ArrayList<>();
List<Integer> checkedMachines = new ArrayList<>(); Block currentBlock;
// Obtain the critical task list from the resource order instance // Obtain the critical task list from the resource order instance
Schedule criticalSchedule = order.toSchedule(); Schedule criticalSchedule = order.toSchedule();
List<Task> criticalTaskList = criticalSchedule.criticalPath(); List<Task> criticalTaskList = criticalSchedule.criticalPath();
Block currentBlock; int totalNumMachines = criticalSchedule.pb.numMachines;
int currentMachine, m; int totalNumJobs = criticalSchedule.pb.numJobs;
int firstTask = 0, lastTask = 0;
Task currentTask;
System.out.print("Number of Jobs : " + order.instance.numJobs + "\n"); Task currentTaskRO;
System.out.print("Number of Tasks : " + order.instance.numTasks + "\n"); int currentTaskIndexRO, currentCriticalTaskIndex, firstTask, lastTask;
System.out.print("Number of Machines : " + order.instance.numMachines + "\n");
System.out.print("Critical path : " + criticalTaskList + "\n");
// Initialize the block list // We check for all machines
for(int i = 0; i < order.instance.numMachines; i++) { for(int currentMachine = 0; currentMachine < totalNumMachines; currentMachine++) {
currentBlock = new Block(i, -1, -1); currentTaskIndexRO = 0;
criticalBlockList.add(i, currentBlock); while(currentTaskIndexRO < (totalNumJobs-1)){
} currentTaskRO = order.tasksByMachine[currentMachine][currentTaskIndexRO];
if (criticalTaskList.contains(currentTaskRO)) {
for(int i = 0; i < criticalTaskList.size(); i++) { currentCriticalTaskIndex = criticalTaskList.indexOf(currentTaskRO);
currentTask = criticalTaskList.get(i); //If the next task in the critical path is running in the same machine try find the last task index
currentMachine = order.instance.machine(currentTask.job, currentTask.task); if(currentMachine == criticalSchedule.pb.machine(criticalTaskList.get(currentCriticalTaskIndex+1))) {
firstTask = currentTaskIndexRO;
// When we find a machine we have not explored, we start searching for all its appearances in the critical path while(currentCriticalTaskIndex < (criticalTaskList.size()-1) && currentMachine == criticalSchedule.pb.machine(criticalTaskList.get(currentCriticalTaskIndex+1))){
// and we safe the first and last occurrence of the machine. // We advance in the list
if(!checkedMachines.contains(currentMachine)) { currentCriticalTaskIndex++;
firstTask = 0; // We have to also advance in the resource order
lastTask = 0; currentTaskIndexRO++;
for(int index = i; index < criticalTaskList.size(); index++) { }
m = order.instance.machine(criticalTaskList.get(index).job, criticalTaskList.get(index).task); // Create and add the new block to the list
// If we find a task running in the same machine and it is not the first task, add 1 to the last task lastTask = currentTaskIndexRO;
if(currentMachine == m && index > i){ currentBlock = new Block(currentMachine, firstTask, lastTask);
lastTask++; criticalBlockList.add(currentBlock);
} }
} }
// Add the machine to the checked machines list // We move on to the next task in the resource order
checkedMachines.add(currentMachine); currentTaskIndexRO++;
// Create and add the new block to the list }
currentBlock = new Block(currentMachine, firstTask, lastTask);
criticalBlockList.set(currentMachine, currentBlock);
}
} }
return criticalBlockList; return criticalBlockList;
} }
/** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */ /** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */
public List<Swap> neighbors(Block block) { public List<Swap> neighbors(Block block) {
List<Swap> swapList = new ArrayList<>(); List<Swap> swapList = new ArrayList<>();
Swap currentSwap; Swap swap1, swap2;
int machine = block.machine; int machine = block.machine;
int firstTask = block.firstTask; int firstTask = block.firstTask;
int lastTask = block.lastTask; int lastTask = block.lastTask;
// Case when there is just one element in the block // One single swap if there are just 2 elements in the block, two swaps if there are more than 2.
if(firstTask == lastTask) { if(firstTask + 1 == lastTask) {
swapList = null; swap1 = new Swap(machine, firstTask, lastTask);
} swapList.add(swap1);
} else {
for(int i = firstTask; i < lastTask; i++) { swap1 = new Swap(machine, firstTask, firstTask+1);
if(i == firstTask + 1) { swap2 = new Swap(machine, lastTask-1 , lastTask);
currentSwap = new Swap(machine, firstTask, i); swapList.add(swap1);
swapList.add(currentSwap); swapList.add(swap2);
} }
if (i == lastTask - 1) {
currentSwap = new Swap(machine, i, lastTask);
swapList.add(currentSwap);
}
}
return swapList; return swapList;
} }
// ************************************************************************************************************* //
} }

View file

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

View file

@ -1,53 +1,52 @@
package jobshop.solvers; package jobshop.solvers;
import jobshop.*; import jobshop.*;
import jobshop.encodings.JobNumbers; import jobshop.encodings.JobNumbers;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
@SuppressWarnings("unused") public class RandomSolver implements Solver {
public class RandomSolver implements Solver {
@Override
@Override public Result solve(Instance instance, long deadline) {
public Result solve(Instance instance, long deadline) { Random generator = new Random(0);
Random generator = new Random(0);
JobNumbers sol = new JobNumbers(instance);
JobNumbers sol = new JobNumbers(instance);
for(int j = 0 ; j<instance.numJobs ; j++) {
for(int j = 0 ; j<instance.numJobs ; j++) { for(int t = 0 ; t<instance.numTasks ; t++) {
for(int t = 0 ; t<instance.numTasks ; t++) { sol.jobs[sol.nextToSet++] = j;
sol.jobs[sol.nextToSet++] = j; }
} }
} Schedule best = sol.toSchedule();
Schedule best = sol.toSchedule(); while(deadline - System.currentTimeMillis() > 1) {
while(deadline - System.currentTimeMillis() > 1) { shuffleArray(sol.jobs, generator);
shuffleArray(sol.jobs, generator); Schedule s = sol.toSchedule();
Schedule s = sol.toSchedule(); if(s.makespan() < best.makespan()) {
if(s.makespan() < best.makespan()) { best = s;
best = s; }
} }
}
return new Result(instance, best, Result.ExitCause.Timeout);
return new Result(instance, best, Result.ExitCause.Timeout); }
}
/** Simple FisherYates array shuffling */
/** Simple FisherYates array shuffling */ private static void shuffleArray(int[] array, Random random)
private static void shuffleArray(int[] array, Random random) {
{ int index;
int index; for (int i = array.length - 1; i > 0; i--)
for (int i = array.length - 1; i > 0; i--) {
{ index = random.nextInt(i + 1);
index = random.nextInt(i + 1); if (index != i)
if (index != i) {
{ array[index] ^= array[i];
array[index] ^= array[i]; array[i] ^= array[index];
array[i] ^= array[index]; array[index] ^= array[i];
array[index] ^= array[i]; }
} }
} }
} }
}

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

@ -1,103 +1,75 @@
package jobshop.encodings; package jobshop.encodings;
import jobshop.Instance; import jobshop.Instance;
import jobshop.Result; import jobshop.Result;
import jobshop.Schedule; import jobshop.Schedule;
import jobshop.Solver; import jobshop.Solver;
import jobshop.solvers.BasicSolver; import jobshop.solvers.BasicSolver;
import jobshop.solvers.GreedySolver; import org.junit.Test;
import jobshop.solvers.GreedySolver.PriorityRule;
import java.io.IOException;
import org.junit.Test; import java.nio.file.Paths;
import java.io.IOException; public class EncodingTests {
import java.nio.file.Paths;
@Test
public class EncodingTests { public void testJobNumbers() throws IOException {
Instance instance = Instance.fromFile(Paths.get("instances/aaa1"));
@Test
public void testJobNumbers() throws IOException { // numéro de jobs : 1 2 2 1 1 2 (cf exercices)
Instance instance = Instance.fromFile(Paths.get("instances/aaa1")); JobNumbers enc = new JobNumbers(instance);
enc.jobs[enc.nextToSet++] = 0;
// numéro de jobs : 1 2 2 1 1 2 (cf exercices) enc.jobs[enc.nextToSet++] = 1;
JobNumbers enc = new JobNumbers(instance); enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0; enc.jobs[enc.nextToSet++] = 0;
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++] = 0; Schedule sched = enc.toSchedule();
enc.jobs[enc.nextToSet++] = 1; // TODO: make it print something meaningful
// by implementing the toString() method
Schedule sched = enc.toSchedule(); System.out.println(sched);
// TODO: make it print something meaningful assert sched.isValid();
// by implementing the toString() method assert sched.makespan() == 12;
System.out.println(sched);
assert sched.isValid();
assert sched.makespan() == 12;
// numéro de jobs : 1 1 2 2 1 2
enc = new JobNumbers(instance);
enc.jobs[enc.nextToSet++] = 0;
// numéro de jobs : 1 1 2 2 1 2 enc.jobs[enc.nextToSet++] = 0;
enc = new JobNumbers(instance); enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0; enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0; enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 1; enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0; sched = enc.toSchedule();
enc.jobs[enc.nextToSet++] = 1; assert sched.isValid();
assert sched.makespan() == 14;
sched = enc.toSchedule(); }
assert sched.isValid();
assert sched.makespan() == 14; @Test
} public void testBasicSolver() throws IOException {
Instance instance = Instance.fromFile(Paths.get("instances/aaa1"));
@Test
public void testBasicSolver() throws IOException { // build a solution that should be equal to the result of BasicSolver
Instance instance = Instance.fromFile(Paths.get("instances/aaa1")); JobNumbers enc = new JobNumbers(instance);
enc.jobs[enc.nextToSet++] = 0;
// build a solution that should be equal to the result of BasicSolver enc.jobs[enc.nextToSet++] = 1;
JobNumbers enc = new JobNumbers(instance); enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 0; enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 1; enc.jobs[enc.nextToSet++] = 0;
enc.jobs[enc.nextToSet++] = 0; enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 1;
enc.jobs[enc.nextToSet++] = 0; Schedule sched = enc.toSchedule();
enc.jobs[enc.nextToSet++] = 1; assert sched.isValid();
assert sched.makespan() == 12;
Schedule sched = enc.toSchedule();
assert sched.isValid(); Solver solver = new BasicSolver();
assert sched.makespan() == 12; Result result = solver.solve(instance, System.currentTimeMillis() + 10);
Solver solver = new BasicSolver(); assert result.schedule.isValid();
Result result = solver.solve(instance, System.currentTimeMillis() + 10); assert result.schedule.makespan() == sched.makespan(); // should have the same makespan
}
assert result.schedule.isValid();
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
}
}