You can see the entire program jobshopd.cpp
here or view it online in the standard distribution.
#include <ilsched/iloscheduler.h>
ILOSTLBEGIN
#if defined(ILO_SDXLOUTPUT)
#include "sdxloutput.h"
#endif
IloInt ResourceNumbers06 [] = {2, 0, 1, 3, 5, 4,
1, 2, 4, 5, 0, 3,
2, 3, 5, 0, 1, 4,
1, 0, 2, 3, 4, 5,
2, 1, 4, 5, 0, 3,
1, 3, 5, 0, 4, 2};
IloInt Durations06 [] = { 1, 3, 6, 7, 3, 6,
8, 5, 10, 10, 10, 4,
5, 4, 8, 9, 1, 7,
5, 5, 5, 3, 8, 9,
9, 3, 5, 4, 3, 1,
3, 3, 9, 10, 4, 1};
IloInt ResourceNumbers10 [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 2, 4, 9, 3, 1, 6, 5, 7, 8,
1, 0, 3, 2, 8, 5, 7, 6, 9, 4,
1, 2, 0, 4, 6, 8, 7, 3, 9, 5,
2, 0, 1, 5, 3, 4, 8, 7, 9, 6,
2, 1, 5, 3, 8, 9, 0, 6, 4, 7,
1, 0, 3, 2, 6, 5, 9, 8, 7, 4,
2, 0, 1, 5, 4, 6, 8, 9, 7, 3,
0, 1, 3, 5, 2, 9, 6, 7, 4, 8,
1, 0, 2, 6, 8, 9, 5, 3, 4, 7};
IloInt Durations10 [] = {29, 78, 9, 36, 49, 11, 62, 56, 44, 21,
43, 90, 75, 11, 69, 28, 46, 46, 72, 30,
91, 85, 39, 74, 90, 10, 12, 89, 45, 33,
81, 95, 71, 99, 9, 52, 85, 98, 22, 43,
14, 6, 22, 61, 26, 69, 21, 49, 72, 53,
84, 2, 52, 95, 48, 72, 47, 65, 6, 25,
46, 37, 61, 13, 32, 21, 32, 89, 30, 55,
31, 86, 46, 74, 32, 88, 19, 48, 36, 79,
76, 69, 76, 51, 85, 11, 40, 89, 26, 74,
85, 13, 61, 7, 64, 76, 47, 52, 90, 45};
IloInt ResourceNumbers20 [] = {0, 1, 2, 3, 4,
0, 1, 3, 2, 4,
1, 0, 2, 4, 3,
1, 0, 4, 2, 3,
2, 1, 0, 3, 4,
2, 1, 4, 0, 3,
1, 0, 2, 3, 4,
2, 1, 0, 3, 4,
0, 3, 2, 1, 4,
1, 2, 0, 3, 4,
1, 3, 0, 4, 2,
2, 0, 1, 3, 4,
0, 2, 1, 3, 4,
2, 0, 1, 3, 4,
0, 1, 4, 2, 3,
1, 0, 3, 4, 2,
0, 2, 1, 3, 4,
0, 1, 4, 2, 3,
1, 2, 0, 3, 4,
0, 1, 2, 3, 4};
IloInt Durations20 [] = {29, 9, 49, 62, 44,
43, 75, 69, 46, 72,
91, 39, 90, 12, 45,
81, 71, 9, 85, 22,
14, 22, 26, 21, 72,
84, 52, 48, 47, 6,
46, 61, 32, 32, 30,
31, 46, 32, 19, 36,
76, 76, 85, 40, 26,
85, 61, 64, 47, 90,
78, 36, 11, 56, 21,
90, 11, 28, 46, 30,
85, 74, 10, 89, 33,
95, 99, 52, 98, 43,
6, 61, 69, 49, 53,
2, 95, 72, 65, 25,
37, 13, 21, 89, 55,
86, 74, 88, 48, 79,
69, 51, 11, 89, 74,
13, 7, 76, 52, 45};
///////////////////////////////////////////////////////////////////////////////
//
// PROBLEM DEFINITION
//
///////////////////////////////////////////////////////////////////////////////
class NbUnrankedExt {
private:
IlcInt _nbOfUnranked;
public:
NbUnrankedExt() :_nbOfUnranked(0) {};
~NbUnrankedExt(){};
void setValue(IlcInt nbOfUnranked) {
_nbOfUnranked = nbOfUnranked;
}
IlcInt getValue() const {
return _nbOfUnranked;
}
};
IloModel
DefineModel(IloEnv& env,
IloInt numberOfJobs,
IloInt numberOfResources,
IloInt* resourceNumbers,
IloInt* durations,
IloNumVar& makespan)
{
IloModel model(env);
/* CREATE THE MAKESPAN VARIABLE. */
IloInt numberOfActivities = numberOfJobs * numberOfResources;
IloInt horizon = 0;
IloInt k;
for (k = 0; k < numberOfActivities; k++)
horizon += durations[k];
makespan = IloNumVar(env, 0, horizon, ILOINT);
/* CREATE THE RESOURCES. */
IloSchedulerEnv schedEnv(env);
schedEnv.getResourceParam().setCapacityEnforcement(IloMediumHigh);
schedEnv.getResourceParam().setPrecedenceEnforcement(IloMediumHigh);
IloInt j;
IloUnaryResource *resources =
new (env) IloUnaryResource[numberOfResources];
for (j = 0; j < numberOfResources; j++)
resources[j] = IloUnaryResource(env);
/* CREATE THE ACTIVITIES. */
char buffer[128];
k = 0;
IloInt i;
for (i = 0; i < numberOfJobs; i++) {
IloActivity previousActivity;
for (j = 0; j < numberOfResources; j++) {
IloActivity activity(env, durations[k]);
sprintf(buffer, "J%ldS%ldR%ld", i, j, resourceNumbers[k]);
activity.setName(buffer);
IloResourceConstraint rct =
activity.requires(resources[resourceNumbers[k]]);
NbUnrankedExt* nbOfUnranked =
new (env) NbUnrankedExt();
rct.setObject(nbOfUnranked);
model.add(rct);
if (j != 0)
model.add(activity.startsAfterEnd(previousActivity));
previousActivity = activity;
k++;
}
model.add(previousActivity.endsBefore(makespan));
}
/* RETURN THE MODEL. */
return model;
}
///////////////////////////////////////////////////////////////////////////////
//
// PRINTING OF SOLUTIONS
//
///////////////////////////////////////////////////////////////////////////////
void
PrintSolution(const IloSolver& solver)
{
IlcScheduler scheduler(solver);
IloEnv env = solver.getEnv();
for(IloIterator<IloActivity> ite(env); ite.ok(); ++ite)
solver.out() << scheduler.getActivity(*ite) << endl;
}
///////////////////////////////////////////////////////////////////////////////
//
// PROBLEM SOLVING
//
///////////////////////////////////////////////////////////////////////////////
IlcInt GetNumberOfUnranked(const IlcResourceConstraint& rct) {
/* RETURN NUMBER OF UNRANKED W.R.T. RCT */
IlcInt nb = 0;
for (IlcResourceConstraintIterator ite(rct, IlcUnranked);
ite.ok(); ++ite)
nb++;
return nb;
}
IlcInt GetOpportunity(const IlcScheduler& scheduler,
const IlcResourceConstraint& srct1,
const IlcResourceConstraint& srct2) {
IlcActivity act1 = srct1.getActivity();
IlcActivity act2 = srct2.getActivity();
IlcInt smin1 = act1.getStartMin();
IlcInt smax1 = act1.getStartMax();
IlcInt emin1 = act1.getEndMin();
IlcInt emax1 = act1.getEndMax();
IlcInt smin2 = act2.getStartMin();
IlcInt smax2 = act2.getStartMax();
IlcInt emin2 = act2.getEndMin();
IlcInt emax2 = act2.getEndMax();
/* DOMAIN DELTA WHEN RCT1 RANKED BEFORE RCT2 */
IlcInt deltaEnd12 = ((emax1 < smax2) ? OL : emax1 - smax2);
IlcInt deltaStart12 = ((smin2 > emin1) ? OL : emin1 - smin2);
IlcInt delta12 = deltaEnd12 + deltaStart12;
/* DOMAIN DELTA WHEN RCT2 RANKED BEFORE RCT1 */
IlcInt deltaEnd21 = ((emax2 < smax1) ? OL : emax2 - smax1);
IlcInt deltaStart21 = ((smin1 > emin2) ? OL : emin2 - smin1);
IlcInt delta21 = deltaEnd21 + deltaStart21;
/* MINIMAL NUMBER OF UNRANKED RESOURCE CONSTRAINTS */
IlcInt nbUrkd1 = ((NbUnrankedExt*)(scheduler.getExtractable(srct1).getObject()))->getValue();
IlcInt nbUrkd2 = ((NbUnrankedExt*)(scheduler.getExtractable(srct2).getObject()))->getValue();
IlcInt minNbUrkd = (nbUrkd1 <= nbUrkd2) ? nbUrkd1 : nbUrkd2;
/* RETURN MEASURE OF OPPORTUNITY */
return (minNbUrkd * (delta12 - delta21));
}
IlcBool
SelectMostOpportunisticConflict(IlcScheduler& schedule,
IlcResourceConstraint& selectedRct1,
IlcResourceConstraint& selectedRct2) {
IlcBool existsConflict = IlcFalse;
IlcInt oppMaxAbs = -1;
IlcInt oppMax = 0;
IlcInt opp;
for (IlcUnaryResourceIterator ires(schedule); ires.ok(); ++ires) {
IlcUnaryResource resource = (*ires);
if (resource.hasPrecedenceGraphConstraint() &&
!resource.isRanked()) {
/* FOR EACH RESOURCE CONSTRAINT, COMPUTE AND STORE THE NUMBER OF
RESOURCE CONSTRAINTS UNRANKED W.R.T. IT */
for (IlcResourceConstraintIterator irct(resource);
irct.ok(); ++irct) {
IlcResourceConstraint rct = (*irct);
if (!rct.isRanked())
((NbUnrankedExt*)schedule.getExtractable(rct).getObject())->
setValue(GetNumberOfUnranked(rct));
}
/* SELECT MOST OPPORTUNISTIC PAIR OF RESOURCE CONSTRAINT */
for (IlcResourceConstraintIterator isrct1(resource);
isrct1.ok(); ++isrct1) {
IlcResourceConstraint srct1 = (*isrct1);
if (!srct1.isRanked()) {
for (IlcResourceConstraintIterator isrct2(srct1, IlcUnranked);
isrct2.ok(); ++isrct2) {
IlcResourceConstraint srct2 = (*isrct2);
opp = GetOpportunity(schedule, srct1, srct2);
if (oppMaxAbs < IloAbs(opp)) {
existsConflict = IlcTrue;
oppMaxAbs = IlcAbs(opp);
oppMax = opp;
selectedRct1 = srct1;
selectedRct2 = srct2;
}
}
}
}
}
}
/* SELECT WHICH BRANCH WILL BE CHOSEN FIRST AMONG RCT1 << RCT2 AND
RCT2 << RCT1 */
if (existsConflict && (0 < oppMax)) {
IlcResourceConstraint tmpRct = selectedRct1;
selectedRct1 = selectedRct2;
selectedRct2 = tmpRct;
}
return existsConflict;
}
ILCGOAL0(SolveConflictsIlc) {
IloSolver s = getSolver();
IlcScheduler scheduler = IlcScheduler(s);
IlcResourceConstraint srct1;
IlcResourceConstraint srct2;
if (SelectMostOpportunisticConflict(scheduler, srct1, srct2))
return IlcAnd(IlcTrySetSuccessor(srct1, srct2), this);
return 0;
}
ILOCPGOALWRAPPER0(SolveConflicts, solver) {
return SolveConflictsIlc(solver);
}
void
SetMakespanInitialBounds(IloSolver& solver,
IloNumVar& makespan)
{
IloGoal goal;
/* SET MAKESPAN LOWER BOUND AND RESTART */
goal = IloGoalTrue(solver.getEnv());
solver.solve(goal);
makespan.setLB(solver.getMin(makespan));
/* SOLVE WITH GOAL SOLVECONFLICTS */
goal = SolveConflicts(solver.getEnv());
solver.solve(goal);
/* SET MAKESPAN UPPER BOUND */
makespan.setUB(solver.getMin(makespan));
solver.out() << "Solution with makespan " << makespan.getUB() << endl;
}
void
Dichotomize(IloModel& model,
IloSolver& solver,
const IloNumVar& makespan)
{
/* GET MAKESPAN INITIAL BOUNDS */
IloNum min = makespan.getLB();
IloNum max = makespan.getUB();
/* OPTIMIZE. */
IloGoal goal = IloRankForward(solver.getEnv(), makespan,
IloSelResMinLocalSlack,
IloSelFirstRCMinStartMax);
while (min < max) {
IloNum value = IloFloor((min + max) / 2);
IloConstraint ct = (makespan <= value);
model.add(ct);
if (solver.solve(goal)) {
max = solver.getMin(makespan);
solver.out() << "Solution with makespan " << max << endl;
}
else {
solver.out() << "Failure with makespan " << value << endl;
min = value + 1;
}
model.remove(ct);
}
/* RECOMPUTE THE OPTIMAL SOLUTION. THIS STEP COULD BE AVOIDED IF
SOLUTIONS WERE STORED AS PART OF THE OPTIMIZATION PROCESS. */
model.add(makespan == max);
solver.solve(goal);
}
///////////////////////////////////////////////////////////////////////////////
//
// MAIN FUNCTION
//
///////////////////////////////////////////////////////////////////////////////
void
InitParameters(int argc,
char** argv,
IloInt& numberOfJobs,
IloInt& numberOfResources,
IloInt*& resourceNumbers,
IloInt*& durations)
{
if (argc > 1) {
IloInt number = atol(argv[1]);
if (number == 10) {
numberOfJobs = 10;
numberOfResources = 10;
resourceNumbers = ResourceNumbers10;
durations = Durations10;
}
else if (number == 20) {
numberOfJobs = 20;
numberOfResources = 5;
resourceNumbers = ResourceNumbers20;
durations = Durations20;
}
}
}
int main(int argc, char** argv)
{
try {
IloEnv env;
IloInt numberOfJobs = 6;
IloInt numberOfResources = 6;
IloInt* resourceNumbers = ResourceNumbers06;
IloInt* durations = Durations06;
InitParameters(argc,
argv,
numberOfJobs,
numberOfResources,
resourceNumbers,
durations);
IloNumVar makespan;
IloModel model = DefineModel(env,
numberOfJobs,
numberOfResources,
resourceNumbers,
durations,
makespan);
IloSolver solver(model);
SetMakespanInitialBounds(solver, makespan);
Dichotomize(model, solver, makespan);
PrintSolution(solver);
#if defined(ILO_SDXLOUTPUT)
IloSDXLOutput output(env);
ofstream outFile("jobshopd.xml");
output.write(IlcScheduler(solver), outFile);
outFile.close();
#endif
solver.printInformation();
env.end();
}
catch (IloException& exc) {
cout << exc << endl;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
//
// RESULTS
//
///////////////////////////////////////////////////////////////////////////////
/* jobshopd 6
Solution with makespan 57
Failure with makespan 52
Solution with makespan 55
Failure with makespan 54
J0S0R2 [5..7 -- 1 --> 6..8]
J0S1R0 [6..11 -- 3 --> 9..14]
J0S2R1 [16 -- 6 --> 22]
J0S3R3 [30..36 -- 7 --> 37..43]
J0S4R5 [42..43 -- 3 --> 45..46]
J0S5R4 [49 -- 6 --> 55]
J1S0R1 [0 -- 8 --> 8]
J1S1R2 [8 -- 5 --> 13]
J1S2R4 [13..15 -- 10 --> 23..25]
J1S3R5 [28..29 -- 10 --> 38..39]
J1S4R0 [38..40 -- 10 --> 48..50]
J1S5R3 [48..50 -- 4 --> 52..54]
J2S0R2 [0..2 -- 5 --> 5..7]
J2S1R3 [5..7 -- 4 --> 9..11]
J2S2R5 [9..11 -- 8 --> 17..19]
J2S3R0 [18..19 -- 9 --> 27..28]
J2S4R1 [27..41 -- 1 --> 28..42]
J2S5R4 [42 -- 7 --> 49]
J3S0R1 [8 -- 5 --> 13]
J3S1R0 [13..14 -- 5 --> 18..19]
J3S2R2 [22 -- 5 --> 27]
J3S3R3 [27 -- 3 --> 30]
J3S4R4 [30 -- 8 --> 38]
J3S5R5 [45..46 -- 9 --> 54..55]
J4S0R2 [13 -- 9 --> 22]
J4S1R1 [22 -- 3 --> 25]
J4S2R4 [25 -- 5 --> 30]
J4S3R5 [38..39 -- 4 --> 42..43]
J4S4R0 [48..51 -- 3 --> 51..54]
J4S5R3 [52..54 -- 1 --> 53..55]
J5S0R1 [13 -- 3 --> 16]
J5S1R3 [16 -- 3 --> 19]
J5S2R5 [19 -- 9 --> 28]
J5S3R0 [28 -- 10 --> 38]
J5S4R4 [38 -- 4 --> 42]
J5S5R2 [42..54 -- 1 --> 43..55]
*/
/* jobshopd 10
Solution with makespan 1146
Failure with makespan 900
Solution with makespan 1023
Solution with makespan 961
Solution with makespan 930
Failure with makespan 915
Failure with makespan 923
Failure with makespan 927
Failure with makespan 929
J0S0R0 [119 -- 29 --> 148]
J0S1R1 [445..448 -- 78 --> 523..526]
J0S2R2 [523..526 -- 9 --> 532..535]
J0S3R3 [532..540 -- 36 --> 568..576]
J0S4R4 [568..595 -- 49 --> 617..644]
J0S5R5 [641..644 -- 11 --> 652..655]
J0S6R6 [652..655 -- 62 --> 714..717]
J0S7R7 [721 -- 56 --> 777]
J0S8R8 [777..782 -- 44 --> 821..826]
J0S9R9 [821..831 -- 21 --> 842..852]
J1S0R0 [76 -- 43 --> 119]
J1S1R2 [224..235 -- 90 --> 314..325]
J1S2R4 [355 -- 75 --> 430]
J1S3R9 [474..499 -- 11 --> 485..510]
J1S4R3 [568..576 -- 69 --> 637..645]
J1S5R1 [637..689 -- 28 --> 665..717]
J1S6R6 [714..717 -- 46 --> 760..763]
J1S7R5 [760..767 -- 46 --> 806..813]
J1S8R7 [813 -- 72 --> 885]
J1S9R8 [895..900 -- 30 --> 925..930]
J2S0R1 [308..311 -- 91 --> 399..402]
J2S1R0 [408..411 -- 85 --> 493..496]
J2S2R3 [493..496 -- 39 --> 532..535]
J2S3R2 [532..535 -- 74 --> 606..609]
J2S4R8 [609 -- 90 --> 699]
J2S5R5 [699 -- 10 --> 709]
J2S6R7 [709 -- 12 --> 721]
J2S7R6 [760..763 -- 89 --> 849..852]
J2S8R9 [849..852 -- 45 --> 894..897]
J2S9R4 [894..897 -- 33 --> 927..930]
J3S0R1 [0..6 -- 81 --> 81..87]
J3S1R2 [84..90 -- 95 --> 179..185]
J3S2R0 [185 -- 71 --> 256]
J3S3R4 [256 -- 99 --> 355]
J3S4R6 [359..370 -- 9 --> 368..379]
J3S5R8 [368..379 -- 52 --> 420..431]
J3S6R7 [420..431 -- 85 --> 505..516]
J3S7R3 [637..645 -- 98 --> 735..743]
J3S8R9 [766..809 -- 22 --> 788..831]
J3S9R5 [806..887 -- 43 --> 849..930]
J4S0R2 [210..221 -- 14 --> 224..235]
J4S1R0 [256..259 -- 6 --> 262..265]
J4S2R1 [286..289 -- 22 --> 308..311]
J4S3R5 [308..313 -- 61 --> 369..374]
J4S4R3 [370..404 -- 26 --> 396..430]
J4S5R4 [430 -- 69 --> 499]
J4S6R8 [499 -- 21 --> 520]
J4S7R7 [530..541 -- 49 --> 579..590]
J4S8R9 [594..657 -- 72 --> 666..729]
J4S9R6 [849..877 -- 53 --> 902..930]
J5S0R2 [0..3 -- 84 --> 84..87]
J5S1R1 [84..87 -- 2 --> 86..89]
J5S2R5 [86..90 -- 52 --> 138..142]
J5S3R3 [138..142 -- 95 --> 233..237]
J5S4R8 [233..244 -- 48 --> 281..292]
J5S5R9 [281..292 -- 72 --> 353..364]
J5S6R0 [361..364 -- 47 --> 408..411]
J5S7R6 [429..445 -- 65 --> 494..510]
J5S8R4 [499..510 -- 6 --> 505..516]
J5S9R7 [505..516 -- 25 --> 530..541]
J6S0R1 [86..89 -- 46 --> 132..135]
J6S1R0 [148 -- 37 --> 185]
J6S2R3 [233..237 -- 61 --> 294..298]
J6S3R2 [314..325 -- 13 --> 327..338]
J6S4R6 [327..338 -- 32 --> 359..370]
J6S5R5 [421..440 -- 21 --> 442..461]
J6S6R9 [442..467 -- 32 --> 474..499]
J6S7R8 [520 -- 89 --> 609]
J6S8R7 [668..679 -- 30 --> 698..709]
J6S9R4 [698..740 -- 55 --> 753..795]
J7S0R2 [179..190 -- 31 --> 210..221]
J7S1R0 [262..265 -- 86 --> 348..351]
J7S2R1 [399..402 -- 46 --> 445..448]
J7S3R5 [445..461 -- 74 --> 519..535]
J7S4R4 [519..535 -- 32 --> 551..567]
J7S5R6 [558..567 -- 88 --> 646..655]
J7S6R8 [699..710 -- 19 --> 718..729]
J7S7R9 [718..729 -- 48 --> 766..777]
J7S8R7 [777 -- 36 --> 813]
J7S9R3 [813..851 -- 79 --> 892..930]
J8S0R0 [0 -- 76 --> 76]
J8S1R1 [217..220 -- 69 --> 286..289]
J8S2R3 [294..298 -- 76 --> 370..374]
J8S3R5 [370..374 -- 51 --> 421..425]
J8S4R2 [422..425 -- 85 --> 507..510]
J8S5R9 [507..510 -- 11 --> 518..521]
J8S6R6 [518..527 -- 40 --> 558..567]
J8S7R7 [579..590 -- 89 --> 668..679]
J8S8R4 [668..714 -- 26 --> 694..740]
J8S9R8 [821..826 -- 74 --> 895..900]
J9S0R1 [132..135 -- 85 --> 217..220]
J9S1R0 [348..351 -- 13 --> 361..364]
J9S2R2 [361..364 -- 61 --> 422..425]
J9S3R6 [422..428 -- 7 --> 429..435]
J9S4R8 [429..435 -- 64 --> 493..499]
J9S5R9 [518..521 -- 76 --> 594..597]
J9S6R5 [594..597 -- 47 --> 641..644]
J9S7R3 [735..743 -- 52 --> 787..795]
J9S8R4 [787..795 -- 90 --> 877..885]
J9S9R7 [885 -- 45 --> 930]
*/
/* jobshopd 20
Solution with makespan 1405
Failure with makespan 896
Failure with makespan 1151
Solution with makespan 1275
Solution with makespan 1212
Solution with makespan 1178
Solution with makespan 1165
Failure with makespan 1158
Failure with makespan 1162
Failure with makespan 1164
J0S0R0 [188 -- 29 --> 217]
J0S1R1 [552..575 -- 9 --> 561..584]
J0S2R2 [581..598 -- 49 --> 630..647]
J0S3R3 [749 -- 62 --> 811]
J0S4R4 [954 -- 44 --> 998]
J1S0R0 [145 -- 43 --> 188]
J1S1R1 [209..215 -- 75 --> 284..290]
J1S2R3 [338 -- 69 --> 407]
J1S3R2 [439..440 -- 46 --> 485..486]
J1S4R4 [485..486 -- 72 --> 557..558]
J2S0R1 [830..832 -- 91 --> 921..923]
J2S1R0 [921..923 -- 39 --> 960..962]
J2S2R2 [960..962 -- 90 --> 1050..1052]
J2S3R4 [1061 -- 12 --> 1073]
J2S4R3 [1092 -- 45 --> 1137]
J3S0R1 [601 -- 81 --> 682]
J3S1R0 [692..726 -- 71 --> 763..797]
J3S2R4 [900 -- 9 --> 909]
J3S3R2 [1050..1052 -- 85 --> 1135..1137]
J3S4R3 [1137 -- 22 --> 1159]
J4S0R2 [0..1 -- 14 --> 14..15]
J4S1R1 [14..15 -- 22 --> 36..37]
J4S2R0 [37 -- 26 --> 63]
J4S3R3 [63 -- 21 --> 84]
J4S4R4 [84..168 -- 72 --> 156..240]
J5S0R2 [204..205 -- 84 --> 288..289]
J5S1R1 [369..375 -- 52 --> 421..427]
J5S2R4 [421..438 -- 48 --> 469..486]
J5S3R0 [763..797 -- 47 --> 810..844]
J5S4R3 [1159 -- 6 --> 1165]
J6S0R1 [756..758 -- 46 --> 802..804]
J6S1R0 [810..844 -- 61 --> 871..905]
J6S2R2 [892..905 -- 32 --> 924..937]
J6S3R3 [988 -- 32 --> 1020]
J6S4R4 [1109 -- 30 --> 1139]
J7S0R2 [14..15 -- 31 --> 45..46]
J7S1R1 [921..942 -- 46 --> 967..988]
J7S2R0 [967..988 -- 32 --> 999..1020]
J7S3R3 [1020 -- 19 --> 1039]
J7S4R4 [1073 -- 36 --> 1109]
J8S0R0 [63 -- 76 --> 139]
J8S1R3 [173 -- 76 --> 249]
J8S2R2 [706..723 -- 85 --> 791..808]
J8S3R1 [967..1099 -- 40 --> 1007..1139]
J8S4R4 [1139 -- 26 --> 1165]
J9S0R1 [284..290 -- 85 --> 369..375]
J9S1R2 [378..379 -- 61 --> 439..440]
J9S2R0 [507 -- 64 --> 571]
J9S3R3 [577 -- 47 --> 624]
J9S4R4 [665..666 -- 90 --> 755..756]
J10S0R1 [474..497 -- 78 --> 552..575]
J10S1R3 [624 -- 36 --> 660]
J10S2R0 [681..715 -- 11 --> 692..726]
J10S3R4 [844 -- 56 --> 900]
J10S4R2 [1135..1144 -- 21 --> 1156..1165]
J11S0R2 [288..289 -- 90 --> 378..379]
J11S1R0 [670..704 -- 11 --> 681..715]
J11S2R1 [802..804 -- 28 --> 830..832]
J11S3R3 [863 -- 46 --> 909]
J11S4R4 [1031 -- 30 --> 1061]
J12S0R0 [422 -- 85 --> 507]
J12S1R2 [507..517 -- 74 --> 581..591]
J12S2R1 [591 -- 10 --> 601]
J12S3R3 [660 -- 89 --> 749]
J12S4R4 [998 -- 33 --> 1031]
J13S0R2 [58..59 -- 95 --> 153..154]
J13S1R0 [323 -- 99 --> 422]
J13S2R1 [422..427 -- 52 --> 474..479]
J13S3R3 [479 -- 98 --> 577]
J13S4R4 [622..623 -- 43 --> 665..666]
J14S0R0 [139 -- 6 --> 145]
J14S1R1 [148..154 -- 61 --> 209..215]
J14S2R4 [228..295 -- 69 --> 297..364]
J14S3R2 [791..808 -- 49 --> 840..857]
J14S4R3 [1039 -- 53 --> 1092]
J15S0R1 [0..13 -- 2 --> 2..15]
J15S1R0 [228 -- 95 --> 323]
J15S2R3 [407 -- 72 --> 479]
J15S3R4 [557..558 -- 65 --> 622..623]
J15S4R2 [924..937 -- 25 --> 949..962]
J16S0R0 [0 -- 37 --> 37]
J16S1R2 [45..46 -- 13 --> 58..59]
J16S2R1 [58..63 -- 21 --> 79..84]
J16S3R3 [84 -- 89 --> 173]
J16S4R4 [173..240 -- 55 --> 228..295]
J17S0R0 [584..596 -- 86 --> 670..682]
J17S1R1 [682 -- 74 --> 756]
J17S2R4 [756 -- 88 --> 844]
J17S3R2 [844..857 -- 48 --> 892..905]
J17S4R3 [909 -- 79 --> 988]
J18S0R1 [79..85 -- 69 --> 148..154]
J18S1R2 [153..154 -- 51 --> 204..205]
J18S2R0 [217 -- 11 --> 228]
J18S3R3 [249 -- 89 --> 338]
J18S4R4 [338..364 -- 74 --> 412..438]
J19S0R0 [571 -- 13 --> 584]
J19S1R1 [584 -- 7 --> 591]
J19S2R2 [630..647 -- 76 --> 706..723]
J19S3R3 [811 -- 52 --> 863]
J19S4R4 [909 -- 45 --> 954]
*/