IBM ILOG Scheduler User's Manual > Advanced Concepts > A Dichotomizing Binary-Search Algorithm: the Job-Shop Problem > Setting Initial Interval Values for the Makespan Variable > Developing the Problem-Solving Algorithm

A simple way to reduce the number of optimizing iterations is to replace the minimization loop by a binary search that dichotomizes the interval where the possible values of the constrained makespan variable occur.

When the domain of the makespan variable is [min max], we try to solve the problem with a new constraint stating that the makespan variable must be less than or equal to (min+max)/2. If this trial succeeds, max becomes the makespan of the solution that was found; if the trial fails, min becomes 1+((min+max)/2). The optimal solution is found when min and max are equal.

 
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);
}
    

Using this dichotomizing binary search reduces the number of iterations needed to solve the problem, but it means harder iterations. The iterations are harder because we have to prove quasi-optimality of a solution prior to proving its optimality. To simplify those hard iterations, we use the predefined resource selector IloSelResMinLocalSlack. This resource selector uses the member function getLocalSlack to calculate the slack of a resource more carefully. It considers all time periods [T1 T2) for which T1 is the earliest start time of an activity and T2 is the latest end time of any other activity.

Let's consider an example to clarify this idea. Let's say there are three activities, A, B, and C. Activity A has a duration of two days and can take place anytime in the next twenty days; activity B lasts 5 days, cannot start before day 1, and must be finished by day 12; and activity C will last 4 days, can start on day 2, and must be finished by day 13.

Table 16.1 Scheduling Activities
Activity 
Earliest Start Time 
Latest End Time 
Duration 
A  
0  
20  
B  
1  
12  
C  
2  
13  

Considering the problem globally, we can take the minimal earliest start time. That is, we take the soonest of the earliest start times (day 0 for activity A) and the last of the latest end times (day 20 for activity A), so there are twenty days available. The activities take only 11 days total (2+5+4), so there are 9 days slack globally.

However, if we refine our idea of slack by considering the earliest start time of any activity and the latest end time of any other activity, we get much tighter slack times. By considering the earliest start time of activity B and the latest end time of activity C, we get an overall span of 12 days. The total duration of the activities that must absolutely execute during this period is 9 days (5 days for B and 4 days for C), so we now have only 3 days of slack.

This more refined idea of slack is used in the program.