IBM ILOG Scheduler User's Manual > Advanced Concepts > Scheduling with Discrete Resources: the Ship-loading Problem > Solving the Problem:Minimizing Makespan

Once all the constraints are added, we can use the non-deterministic programming primitives of Solver to generate a solution with minimal makespan. The first thing to do is to define a constrained makespan variable and specify that its value is greater than the end time of each activity. For each activity activities[i], the statement model.add(activities[i].endsBefore(makespan)); constrains the makespan variable to be greater than or equal to the end time of activities[i].

The second thing to do is to write a function that (a) generates a solution to the problem and (b) sets the constrained makespan variable to the makespan of the solution we get. We'll adopt the following algorithm for that purpose.

  1. Consider all the activities to schedule as "selectable."
  2. If all the activities have fixed start and end times, set the constrained makespan variable to the makespan of the solution obtained this way and exit. Otherwise, consider as non-selectable those activities which have fixed start and end times.
  3. If the set of selectable activities is not empty, select an activity from the set, create a choice point for the selected activity (to allow backtracking), and schedule the selected activity from its earliest start time to its earliest end time. Then go to step 2.
  4. If the set of selectable activities is empty, backtrack to the most recent choice point. If there is no such choice point, report that there is no problem solution and exit.
  5. Upon backtracking, consider the activity that was scheduled at the choice point under consideration as "non-selectable" as long as its earliest start time has not changed. Then go to step 2.

The correctness of this algorithm is easy to demonstrate: The activity A chosen at step 3 must either start at its earliest start time or must be postponed to start later, but starting A later makes sense only if other activities prevent A from starting at its earliest start time. In that case, the scheduling of these other activities must eventually result in the update of the earliest start and end times of A. Hence, a backtrack from step 4 signifies that all the activities which do not have fixed start and end times have been postponed. Such a situation would be absurd, as in any solution the activity which will start the earliest among those which have been postponed could be set to start at its earliest start time. Consequently, it is correct to backtrack from step 4 up to the most recent choice point.

The search algorithm we will use is implemented by the predefined goal IloSetTimesForward. At each step, this goal selects a selectable activity and sets a choice point: either the chosen activity is scheduled to start at its earliest start time, or it is postponed.

To select the activities, the predefined activity selector IloSelFirstActMinEndMin is used. This selector considers the earliest start and end times among the activities that can still be selected. Then among the selectable activities having the minimal earliest start time, it chooses one having the minimal earliest end time.

IloMinimize sets the objective of minimizing makespan in the model.

    IloModel model(env);
    IloNumVar makespan;
    DefineProblem(model,
                  NumberOfActivities,
                  Durations,
                  Demands,
                  Capacity,
                  Precedences,
                  level,
                  makespan);
    
    model.add(IloMinimize(env, makespan));
    
    // Algorithm
    IloSolver solver(model);
    IloGoal goal = IloSetTimesForward(env, makespan, IloSelFirstActMinEndMin);
    
    if (solver.solve(goal)) {
      PrintSolution(IlcScheduler(solver));
      solver.printInformation();

#if defined(ILO_SDXLOUTPUT)
      IloSDXLOutput output(env);
      ofstream outFile("ship.xml");
      output.write(IlcScheduler(solver), outFile, solver.getIntVar(makespan));
      outFile.close();
#endif
    }
    else
      solver.out() << "No solution!" << endl;

    env.end();