IBM ILOG Scheduler User's Manual > Advanced Concepts > A Dichotomizing Binary-Search Algorithm: the Job-Shop Problem > Complete Program and Output

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]
*/