Testing your installation with a scheduling problem

Before proceeding with the other tutorials in the Getting Started with CP Optimizer manual, you should test your environment by compiling and running a simple application. The log produced by the application provides useful information about the model and the solution search.

In this lesson, you are provided with a completed example code so that you can test your installation of CP Optimizer. In Using expressions on interval variables: house building with earliness and tardiness costs, you will learn about the classes and member functions used in this program.

The problem is a house building problem in which there are ten tasks of fixed size, each of which needs to be assigned a starting time. Using the C++ API, the code for creating the environment, model and interval variables that represent the tasks is:


#include <ilcp/cp.h>

int main(int argc, const char * argv[]) {
  IloEnv env;
  try {
    IloModel model(env);
    
    /* CREATE THE TIME-INTERVALS. */
    IloIntervalVar masonry  (env, 35, "masonry   ");
    IloIntervalVar carpentry(env, 15, "carpentry ");
    IloIntervalVar plumbing (env, 40, "plumbing  ");
    IloIntervalVar ceiling  (env, 15, "ceiling   ");
    IloIntervalVar roofing  (env, 5,  "roofing   ");
    IloIntervalVar painting (env, 10, "painting  ");
    IloIntervalVar windows  (env, 5,  "windows   ");
    IloIntervalVar facade   (env, 10, "facade    ");
    IloIntervalVar garden   (env, 5,  "garden    ");
    IloIntervalVar moving   (env, 5,  "moving    ");

The constraints in this problem are precedence constraints; some tasks cannot start until other tasks have ended. For example, the ceilings must be completed before painting can begin. The set of precedence constraints for this problem can be added to the model with the code:


    model.add(IloEndBeforeStart(env, masonry,   carpentry));
    model.add(IloEndBeforeStart(env, masonry,   plumbing));
    model.add(IloEndBeforeStart(env, masonry,   ceiling));
    model.add(IloEndBeforeStart(env, carpentry, roofing));
    model.add(IloEndBeforeStart(env, ceiling,   painting));
    model.add(IloEndBeforeStart(env, roofing,   windows));
    model.add(IloEndBeforeStart(env, roofing,   facade));
    model.add(IloEndBeforeStart(env, plumbing,  facade));
    model.add(IloEndBeforeStart(env, roofing,   garden));
    model.add(IloEndBeforeStart(env, plumbing,  garden));
    model.add(IloEndBeforeStart(env, windows,   moving));
    model.add(IloEndBeforeStart(env, facade,    moving));
    model.add(IloEndBeforeStart(env, garden,    moving));
    model.add(IloEndBeforeStart(env, painting,  moving));

Here there is a special constraint, IloEndBeforeStart, which ensures that one interval variable ends before the other starts. This constraint is handled specially by the engine. One reason is to correctly treat the presence of intervals so that if one of the interval variables is not present, the constraint is automatically satisfied, and another reason is for stronger inference in constraint propagation.

The interval variables and precedence constraints completely describe this simple problem. An optimizer object (an instance of the class IloCP) is used to find a solution to the model, assigning values to the start and end of each of the interval variables in the model. The last part of the code for this example is:


    IloCP cp(model);
    if (cp.solve()) {
      cp.out() << cp.domain(masonry)   << std::endl;
      cp.out() << cp.domain(carpentry) << std::endl;
      cp.out() << cp.domain(plumbing)  << std::endl;
      cp.out() << cp.domain(ceiling)   << std::endl;
      cp.out() << cp.domain(roofing)   << std::endl;
      cp.out() << cp.domain(painting)  << std::endl;
      cp.out() << cp.domain(windows)   << std::endl;
      cp.out() << cp.domain(facade)    << std::endl;
      cp.out() << cp.domain(garden)    << std::endl;
      cp.out() << cp.domain(moving)    << std::endl;
    } else {
      cp.out() << "No solution found. " << std::endl;
    }
    cp.printInformation();
  } catch (IloException& ex) {
    env.out() << "Error: " << ex << std::endl;
  }
  env.end();
  return 0;
}

Open the example file <Install_dir>/cpoptimizer/examples/src/cpp/sched_intro.cpp in your development environment. To test your installation of CP Optimizer, build and run the program. When you run the program, you should get results similar to this search log output:


 ! ----------------------------------------------------------------------------
 ! Satisfiability problem - 10 variables, 14 constraints
 ! Initial process time : 0.00s (0.00s extraction + 0.00s propagation)
 !  . Log search space  : 33.2 (before), 33.2 (after)
 !  . Memory usage      : 304.7 kB (before), 304.7 kB (after)
 ! Using parallel search with 8 workers.
 ! ----------------------------------------------------------------------------
 !               Branches  Non-fixed    W       Branch decision
 *                     11  0.00s        1            -
 ! ----------------------------------------------------------------------------
 ! Search completed, 1 solution found.
 ! Number of branches     : 11
 ! Number of fails        : 0
 ! Total memory usage     : 780.6 kB (735.1 kB CP Optimizer + 45.5 kB Concert)
 ! Time spent in solve    : 0.00s (0.00s engine + 0.00s extraction)
 ! Search speed (br. / s) : 1100.0
 ! ----------------------------------------------------------------------------
masonry   [1: 0 -- 35 --> 35]
carpentry [1: 35 -- 15 --> 50]
plumbing  [1: 35 -- 40 --> 75]
ceiling   [1: 35 -- 15 --> 50]
roofing   [1: 50 -- 5 --> 55]
painting  [1: 50 -- 10 --> 60]
windows   [1: 55 -- 5 --> 60]
facade    [1: 75 -- 10 --> 85]
garden    [1: 75 -- 5 --> 80]
moving    [1: 85 -- 5 --> 90]

To understand the solution found by CP Optimizer to this satisfiability scheduling problem, consider the line:


masonry [1: 0 -- 35 --> 35]

The interval variable representing the masonry task, which has size 35, has been assigned the interval [0,35). Masonry starts at time 0 and ends at the time point 35.

Note:

Displaying interval variables

After a time interval has been assigned a start value (say s) and an end value (say e), the interval is written as [s,e). The time interval does not include the endpoint e. If another interval variable is constrained to be placed after this interval, it can start at the time e.

In subsequent lessons in this manual, the log output is not included in the sections which report the results. You can view the log information when you build and run the completed programs.