IBM ILOG Scheduler User's Manual > Getting Started with Scheduler > Using the Trace Facilities > Complete Program and Output--Example 10

You can see the entire program gsTrace.cpp here or view it online in the standard distribution.

#include <ilsched/iloscheduler.h>
 
ILOSTLBEGIN
 
#if defined(ILO_SDXLOUTPUT)
#include "sdxloutput.h"
#endif
 
/////////////////////////////////////////////////////////////////////////////
//
// PROBLEM DEFINITION
//
/////////////////////////////////////////////////////////////////////////////
 
IloActivity MakeActivity(IloEnv env, 
                         IloInt houseNumber,
                         IloNum duration,
                         const char* name) {
  char* s = new char[strlen(name)+3];
  sprintf(s, "%ld-%s", houseNumber, name);
  IloActivity act(env, duration, s);
  delete [] s;
  return act;
}
 
/* THREE DESIGNS OF HOUSES EACH HAVING DIFFERENT TASK DURATIONS */
 
IloNum durationsDesign1 [] = { 7, 3,  8, 3, 1, 2, 1, 2, 1, 1};
IloNum durationsDesign2 [] = {12, 5, 10, 5, 2, 5, 2, 3, 2, 1};
IloNum durationsDesign3 [] = {15, 3, 10, 6, 2, 3, 2, 3, 2, 1};
void MakeHouse(IloModel model,
               IloInt houseNumber,
               const IloNum* dur,
               const IloNum startMin,
               const IloNum endMax,
               const IloUnaryResourceArray workers,
               const IloReservoir budget,
               const IloNumVar makespan) 
{ 
  IloEnv env = model.getEnv();
  
  /* CREATE THE ACTIVITIES. */
  IloActivity masonry = 
    MakeActivity(env, houseNumber, dur[0], "masonry   ");
  IloActivity carpentry = 
    MakeActivity(env, houseNumber, dur[1], "carpentry ");
  IloActivity plumbing = 
    MakeActivity(env, houseNumber, dur[2], "plumbing  ");
 
  plumbing.setObject((IloAny)1);
 
  IloActivity ceiling = 
    MakeActivity(env, houseNumber, dur[3], "ceiling   ");
  IloActivity roofing = 
    MakeActivity(env, houseNumber, dur[4], "roofing   ");
  IloActivity painting = 
    MakeActivity(env, houseNumber, dur[5], "painting  ");
  IloActivity windows = 
    MakeActivity(env, houseNumber, dur[6], "windows   ");
  IloActivity facade = 
    MakeActivity(env, houseNumber, dur[7], "facade    ");
  IloActivity garden = 
    MakeActivity(env, houseNumber, dur[8], "garden    ");
  IloActivity moving = 
    MakeActivity(env, houseNumber, dur[9], "moving    ");
  
  /* SET STARTMIN AND ENDMAX. */
  model.add(masonry.startsAfter(startMin));
  model.add(moving.endsBefore(endMax));
  
  /* POST THE TEMPORAL CONSTRAINTS. */
  model.add(carpentry.startsAfterEnd(masonry));
  model.add(ceiling.startsAfterEnd(masonry));
  model.add(roofing.startsAfterEnd(carpentry));
  model.add(painting.startsAfterEnd(ceiling));
  model.add(windows.startsAfterEnd(roofing));
  model.add(facade.startsAfterEnd(roofing));
  model.add(facade.startsAfterEnd(plumbing));
  model.add(garden.startsAfterEnd(roofing));
  model.add(garden.startsAfterEnd(plumbing));
  model.add(moving.startsAfterEnd(windows));
  model.add(moving.startsAfterEnd(facade));
  model.add(moving.startsAfterEnd(garden));
  model.add(moving.startsAfterEnd(painting));
 
  IloPrecedenceConstraint p1(plumbing.startsAfterEnd(masonry));
  p1.setName("");
  model.add(p1);
 
  model.add(moving.endsBefore(makespan));
 
  /* POST THE RESOURCE CONSTRAINTS ON THE WORKERS. */ 
  model.add(carpentry.requires(workers[0]));
  model.add(ceiling.requires(workers[0]));
  model.add(roofing.requires(workers[0]));
  model.add(windows.requires(workers[0]));
  model.add(facade.requires(workers[0]));
 
  model.add(masonry.requires(workers[1]));
  
  model.add(plumbing.requires(workers[2]));
 
  model.add(garden.requires(workers[3]));
  model.add(painting.requires(workers[3]));
  model.add(moving.requires(workers[3]));
 
  /* POST THE RESOURCE CONSTRAINTS ON THE BUDGET. */ 
  model.add(masonry.consumes(budget, dur[0]));
  model.add(carpentry.consumes(budget, dur[1]));
  model.add(plumbing.consumes(budget, dur[2]));
  model.add(ceiling.consumes(budget, dur[3]));
  model.add(roofing.consumes(budget, dur[4]));
  model.add(painting.consumes(budget, dur[5]));
  model.add(windows.consumes(budget, dur[6]));
  model.add(facade.consumes(budget, dur[7]));
  model.add(garden.consumes(budget, dur[8]));
  model.add(moving.consumes(budget, dur[9]));
 
  model.add(masonry.produces(budget, (dur[0] + 1)));
  model.add(carpentry.produces(budget, (dur[1] + 1)));
  model.add(plumbing.produces(budget, (dur[2] + 1)));
  model.add(ceiling.produces(budget, (dur[3] + 1)));
  model.add(roofing.produces(budget, (dur[4] + 1)));
  model.add(painting.produces(budget, (dur[5] + 1)));
  model.add(windows.produces(budget, (dur[6] + 1)));
  model.add(facade.produces(budget, (dur[7] + 1)));
  model.add(garden.produces(budget, (dur[8] + 1)));
  model.add(moving.produces(budget, (dur[9] + 1)));
}
 
IloModel DefineModel(const IloEnv env, IloNumVar& makespan)
{
  IloModel model(env);
  
  /* CREATE THE MAKESPAN VARIABLE. */
  IloNum horizon = 150;
  makespan = IloNumVar(env, 0, horizon, IloNumVar::Int); 
 
  /* CREATE THE WORKERS. */
  IloInt nrOfWorkers = 4;
  IloUnaryResourceArray workers(env,nrOfWorkers);
  for (IloInt k = 0; k < nrOfWorkers; k++) {
    workers[k] = IloUnaryResource(env);
    workers[k].setCapacityEnforcement(IloMediumHigh);
  }
 
  workers[3].setObject((IloAny)1);
 
  /* CREATE THE BUDGET RESOURCE. */
  IloReservoir budget(env, 100, 11);
 
  /* CREATE THE ACTIVITIES AND CONSTRAINTS FOR THE HOUSES. */
  MakeHouse(model, 0, durationsDesign1, 
            0, horizon, workers, budget, makespan);
  MakeHouse(model, 1, durationsDesign2, 
            0, horizon, workers, budget, makespan);
  MakeHouse(model, 2, durationsDesign3, 
            0, horizon, workers, budget, makespan);
 
  return model;
}
 
/////////////////////////////////////////////////////////////////////////////
//
// PRINTING OF SOLUTIONS
//
/////////////////////////////////////////////////////////////////////////////
 
void PrintSolution(const IloSolver solver, const IloNumVar makespan)
{
  IlcScheduler scheduler(solver);
  IloEnv env = solver.getEnv();
  env.out() << "Solution with makespan " 
            << solver.getIntVar(makespan).getMin() << endl;
  for(IloIterator<IloActivity> act(env);
      act.ok();
      ++act)
    env.out() << scheduler.getActivity(*act) << endl;
  solver.printInformation();
}
 
/////////////////////////////////////////////////////////////////////////////
//
// GOAL TO SET THE TRACE
//
/////////////////////////////////////////////////////////////////////////////
 
IlcBool MyPrintTraceFilter(IlcBool isBeginEvent,
                           IlcSchedulerChange change, 
                           IlcSolverChange solverChange) {
  // We are only interested in events that occur just
  // before a modification
  if (!isBeginEvent) {
    return IlcFalse;
  }
  switch (change) {
    // If the start variable of an activity is modified,
    // we only care if it becomes bound, or its min is
    // modified. 
    //I.e. we do not care about the Latest Start Time
    case IlcActivityStart:
      return ((solverChange == IlcIntExpSetMin) ||
              (solverChange == IlcIntExpSetValue));
    // All other modifications of activities are skipped
    case IlcActivityEnd:
    case IlcActivityProcessingTime:
    case IlcActivityDuration:
    case IlcActivityDurationOfBreaks:
    case IlcActivityStartOverlap:
    case IlcActivityEndOverlap:
      return IlcFalse;
    // Other events are traced
    default:
      return IlcTrue;
  }
}
 
 
ILCGOAL1(SetTraceIlc, IlcInt, traceLevel) {
  IloSolver solver = getSolver();
  IlcScheduler scheduler(solver);
  IlcSchedulerPrintTrace trace(scheduler);
  solver.setTraceMode(IlcTrue);
  if (traceLevel == 0) {
    // Trace only some specific activities
    for (IlcActivityIterator it(scheduler); it.ok(); ++it) {
      IlcActivity act = *it;
      if (act.getObject() == (IloAny)1) {
        trace.trace(act);
      }
    }
  } else if (traceLevel == 1) {
    // We trace only the activities that require a specific resource
    for (IlcResourceIterator it(scheduler); it.ok(); ++it) {
      IlcResource res = *it;
      if (res.getObject() == (IloAny)1) {
        trace.trace(res);
      }
    }
  } else {
    // Tracing all activities in the problem
    trace.traceAllActivities();
  }
  if (traceLevel > 0) {
    // Setting a filter to get only some specified events
    trace.setFilter(MyPrintTraceFilter);
  }
  return 0;
}
 
ILOCPGOALWRAPPER1(SetTrace, solver, IloInt, traceLevel) {
  return SetTraceIlc(solver, traceLevel);
}
 
/////////////////////////////////////////////////////////////////////////////
//
// MAIN FUNCTION
//
/////////////////////////////////////////////////////////////////////////////
 
int main(int argc, char** argv)
{
  try {
    IloEnv env;
    IloNumVar makespan; 
    IloModel model = DefineModel(env, makespan);
 
    IloSolver solver(model);
 
    IloInt traceLevel = 0;
    if (argc == 2) {
      traceLevel = atol(argv[1]);
    }
 
    IloGoal goal = SetTrace(env, traceLevel) &&
                   IloSetTimesForward(env, makespan);
    if (solver.solve(goal)) {
      PrintSolution(solver,makespan);
#if defined(ILO_SDXLOUTPUT)
      IloSDXLOutput output(env);
      ofstream outFile("gsTrace.xml");
      output.write(IlcScheduler(solver), outFile, solver.getIntVar(makespan));
      outFile.close();
#endif
 
    }
    else
      solver.out() << "No Solution" << endl;
 
    env.end();
    
  } catch (IloException& exc) {
    cout << exc << endl;
  }
 
  return 0;
}
 
 

The whole output is not printed here, but with traceLevel equal to 0, it will begin with:

IlcOr   : 1
 >> begin IlcActivityStart(IlcIntExpSetMin) 2-plumbing   
                                   [22..136 -- 10 --> 32..146] val: 25
    goal:IlcGoalScheduleActivity
    the active demon is the constraint: IlcPrecedenceConstraint(0x010A01C8)
                                   [2-plumbing   starts after end 2-masonry   ]
 << end   IlcActivityStart(IlcIntExpSetMin) 2-plumbing   
                                   [25..136 -- 10 --> 32..146] val: 25
 >> begin IlcActivityEnd(IlcIntExpSetMin) 2-plumbing   
                                   [25..136 -- 10 --> 32..146] val: 35
    goal:IlcGoalScheduleActivity
    propagation of demon, the constraint associated with the demon is: 
                                   2-plumbing   [25..136 -- 10 --> 32..146]
 << end   IlcActivityEnd(IlcIntExpSetMin) 2-plumbing   
                                   [25..136 -- 10 --> 35..146] val: 35
IlcOr   : 2
 >> begin IlcActivityStart(IlcIntExpSetMin) 2-plumbing   [
                                   25..136 -- 10 --> 35..146] val: 34
    goal:IlcGoalScheduleActivity
    the active demon is the constraint: IlcPrecedenceConstraint(0x010A01C8) 
                                   [2-plumbing   starts after end 2-masonry   ]

We learn here that during the first choice point, the plumbing activity for the third house (numbered 2) has its earliest start time shifted from 22 to 25 due to a precedence constraint, and then its earliest end time shifted from 32 to 35 due to the internal constraint between all the variables of the activity. The choice made next (second choice point) leads to a shift of this same activity from 25 to 34 as earliest start time.