IBM ILOG Scheduler User's Manual > Getting Started with Scheduler > Using Discrete Resources > Managing Consumable Resources > Complete Program and Output--Example 4

You can see the entire program gsBudget.cpp here or online in the standard distribution.

#include <ilsched/iloscheduler.h>
 
ILOSTLBEGIN
 
#if defined(ILO_SDXLOUTPUT)
#include "sdxloutput.h"
#endif
 
///////////////////////////////////////////////////////////////////////////////
//
// PROBLEM DEFINITION
//
///////////////////////////////////////////////////////////////////////////////
IloNum dur [] = { 7, 3, 8, 3, 1, 2, 1, 2, 1, 1};
 
IloModel DefineModel(const IloEnv env,
                     IloNumVar& makespan,
                     IloDiscreteResource& budget,
                     IloSchedulerSolution& solution) 
{
  IloModel model(env);
  
  /* CREATE THE ACTIVITIES. */
  IloActivity masonry(env,   dur[0], "masonry   ");
  IloActivity carpentry(env, dur[1], "carpentry ");
  IloActivity plumbing(env,  dur[2], "plumbing  ");
  IloActivity ceiling(env,   dur[3], "ceiling   ");
  IloActivity roofing(env,   dur[4], "roofing   ");
  IloActivity painting(env,  dur[5], "painting  ");
  IloActivity windows(env,   dur[6], "windows   ");
  IloActivity facade(env,    dur[7], "facade    ");
  IloActivity garden(env,    dur[8], "garden    ");
  IloActivity moving(env,    dur[9], "moving    ");
  
  /* ADD THE TEMPORAL CONSTRAINTS. */
  model.add(carpentry.startsAfterEnd(masonry));
  model.add(plumbing.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));
  
  /* CREATE THE WORKER RESOURCE. */
  IloUnaryResource worker(env);
  
  /* ADD THE WORKER RESOURCE CONSTRAINTS. */
  model.add(masonry.requires(worker));
  model.add(carpentry.requires(worker));
  model.add(plumbing.requires(worker));
  model.add(ceiling.requires(worker));
  model.add(roofing.requires(worker));
  model.add(painting.requires(worker));
  model.add(windows.requires(worker));
  model.add(facade.requires(worker));
  model.add(garden.requires(worker));
  model.add(moving.requires(worker));
  /* SET THE MAKESPAN VARIABLE. */
  makespan = IloNumVar(env, 0, IloInfinity, ILOINT);
  model.add(moving.endsAt(makespan));
  /* CREATE THE CONSUMPTION RESOURCE. */
  budget = IloDiscreteResource(env, 29000, "Budget");
  budget.setCapacityMax(0, 15, 13000);
  /* ADD THE CONSUMPTION RESOURCE CONSTRAINTS. */
  model.add(masonry.consumes(budget,   1000*dur[0]));
  model.add(carpentry.consumes(budget, 1000*dur[1]));
  model.add(plumbing.consumes(budget,  1000*dur[2]));
  model.add(ceiling.consumes(budget,   1000*dur[3]));
  model.add(roofing.consumes(budget,   1000*dur[4]));
  model.add(painting.consumes(budget,  1000*dur[5]));
  model.add(windows.consumes(budget,   1000*dur[6]));
  model.add(facade.consumes(budget,    1000*dur[7]));
  model.add(garden.consumes(budget,    1000*dur[8]));
  model.add(moving.consumes(budget,    1000*dur[9]));
 
  /* SET THE OBJECTIVE */
  model.add(IloMinimize(env, makespan));
 
  /* REGISTER VARIABLES TO BE STORED IN THE SOLUTION */
  solution.getSolution().add(makespan);
  solution.add(budget);
 
  solution.add(masonry);
  solution.add(carpentry);
  solution.add(plumbing);
  solution.add(ceiling);
  solution.add(roofing);
  solution.add(painting);
  solution.add(windows);
  solution.add(facade);
  solution.add(garden);
  solution.add(moving);
 
  return model;
}
 
///////////////////////////////////////////////////////////////////////////////
//
// PRINTING OF SOLUTIONS
//
///////////////////////////////////////////////////////////////////////////////
 
void PrintSolution(const IloSolver& solver,
                   const IloSchedulerSolution solution,
                   const IloNumVar makespan,
                   const IloDiscreteResource budget)
{
  solver.out() << "Solution with makespan "
               << solution.getSolution().getMin(makespan) << endl << endl;
  
  for (IloSchedulerSolution::ActivityIterator iter(solution);
       iter.ok(); ++iter)
  {
    IloActivity act = *iter;
 
    solver.out() << act.getName();
 
    solver.out() << " [" << solution.getStartMin(act);
    if (solution.getStartMin(act) != solution.getStartMax(act))
      solver.out() << ".." << solution.getStartMax(act);
    solver.out() << " -- " 
                 << solution.getProcessingTimeMin(act);
 
    solver.out() << " --> " << solution.getEndMin(act);
    if (solution.getEndMin(act) != solution.getEndMax(act))
      solver.out() << ".." << solution.getEndMax(act);
    solver.out() << "]" << endl;
  }
  solver.out() << endl;
 
  solver.out() << budget << endl;
  solver.out() << endl;
 
  for (IloNumToNumStepFunctionCursor iter1(solution.getLevelMin(budget));
       iter1.ok(); ++iter1) {
    solver.out() << "date "
                 << iter1.getSegmentMin()
                 << " amount "
                 << iter1.getValue() << endl;
  }
}
 
///////////////////////////////////////////////////////////////////////////////
//
// MAIN FUNCTION
//
///////////////////////////////////////////////////////////////////////////////
 
int main()
{
  try {
    IloEnv env;
    IloNumVar makespan;
    IloDiscreteResource budget;
    IloSchedulerSolution solution(env);
    IloModel model = DefineModel(env, makespan, budget, solution);
    
    IloSolver solver(model);
    IloGoal goal = IloSetTimesForward(env, makespan);
    if (solver.solve(goal)) {
      solution.store( IlcScheduler(solver) );
      PrintSolution(solver,solution, makespan, budget);
#if defined(ILO_SDXLOUTPUT)
      IloSDXLOutput output(env);
      ofstream outFile("gsBudget.xml");
      output.write(IlcScheduler(solver), outFile, solver.getIntVar(makespan));
      outFile.close();
#endif
 
    }
    else
      solver.out() << "No Solution" << endl;
 
    solution.end();      
    env.end();
  
  } catch (IloException& exc) {
    cout << exc << endl;
  }
  return 0;
}
 
///////////////////////////////////////////////////////////////////////////////
//
// RESULTS
//
///////////////////////////////////////////////////////////////////////////////
 
/*
  Solution with makespan 31
 
  masonry    [0 -- 7 --> 7]
  carpentry  [7 -- 3 --> 10]
  plumbing   [16 -- 8 --> 24]
  ceiling    [10 -- 3 --> 13]
  roofing    [15 -- 1 --> 16]
  painting   [28 -- 2 --> 30]
  windows    [27 -- 1 --> 28]
  facade     [25 -- 2 --> 27]
  garden     [24 -- 1 --> 25]
  moving     [30 -- 1 --> 31]
 
  Budget [29000]
 
  date 0 amount 7000
  date 7 amount 10000
  date 10 amount 13000
  date 15 amount 14000
  date 16 amount 22000
  date 24 amount 23000
  date 25 amount 25000
  date 27 amount 26000
  date 28 amount 28000
  date 30 amount 29000
*/
 

The start and end times of all activities are fixed and the total time to complete the project is 31 days. Notice that there is no activity on days 14 and 15, because the original budget release has been used up and the additional budget has not yet become available. Figure 4.3 provides a graphic display of the solution to our problem.

discreteResourcesy3.gif

Figure 4.3 Solution with Consumable Resource

Figure 4.4 shows the amount of available and used budget capacity over the schedule.

discreteResourcesz4.gif

Figure 4.4 Budget Capacity Availability Over Time