FRAMES NO FRAMES

Durability
PREVIOUS NEXT
Description
Writing Multi-Threaded Applications
Limitations
Managing the Initial Requirement Amount on a Durable Resource
Description

Scheduler Engine offers an easy way to build applications where the same resources are used successively in different scheduling problems and information about resource availability is kept from one problem to another. Such resources are called durable resources. The information about resource availability that is kept from one problem to another is stored in the timetable constraints of the resources.

The typical steps that may be encountered by an application using durability are:

  • Create durable resources in a model.
  • Extract these resources on a durable scheduler that is an instance of IlcSchedule. The durable scheduler can be seen as an object that stores the information that is kept from one problem to another (timetables of durable resources).
  • Different schedules (instances of IlcSchedule), called computation schedules, declare an interest in using some durable resources.
  • Once a computation schedule has access to the resources it needs (we say that the resources are locked by the computation schedule), a complete scheduling problem can be defined and solved.
  • At any point, the computation schedule can unlock any of the locked resources; the unlocked resources keep their timetable information.
  • After a resource is unlocked, further computation done on the computation schedule does not interfere with the unlocked resource, except the backtracking: that is, backtracking a decision that modified the timetable of a resource will undo the modification, even if the resource has been unlocked.

Example

The main elements of the API that allow the use of durable resources across different scheduling problems are illustrated in the following example.

The following code creates a durable schedule that gets its durable resources extracted from a Scheduler model.

IloEnv env0;              // Allocation environment
IloModel model0(env0);
IloUnaryResource resource(env0);
model0.add(resource);
IloSolver solver0(env0);
IlcScheduler durSched(solver0);
durSched.setDurable();   // A durable schedule is created
solver0.extract(model0); // Extract durable resources
durSched.close();        // All durable resources were defined

Now we define a goal SolveSubProblem, which is in charge of scheduling one activity on the durable unary resource. In the goal “wrapper,” the computation resource is obtained from the durable scheduler.

ILCGOAL1(SolveSubProblemIlc,
         IlcUnaryResource, compResource) {
  IloSolver solver = getSolver();
  IlcSchedule compSched(solver, 0, 24); // computation schedule
  IlcActivity act(compSched, 8);
  compSched.lock(1, compResource);   // Locking before using
  solver.add(act.requires(compResource));
  solver.startsNewSearch(IlcSetTimes(compSched));
  solver.next();
  compSched.unlock(1, compResource); // Resource no longer needed
  solver.out() << act << endl;      // Display scheduled activity
  solver.endSearch();
  return 0;
}
ILOCPGOALWRAPPER2(SolveSubProblem, solver,
                  IlcScheduler, durSched,
                  IloUnaryResource, resource) {
  return SolveSubProblem(solver, durSched.getUnaryResource(resource));
}

The following code creates a computation solver to solve a first instance of sub-problem on the durable resource.

IloEnv env1; // Computation environment
IloSolver solver1(env1);
solver1.solve
       (SolveSubProblem(env1, solver1, compResource));
env1.end();

It outputs: [0 -- 8 --> 8]. The activity of this first sub-problem is scheduled to start at time 0. From now on, the durable resource remains occupied on the time interval [0, 8). Thus a second computation solver trying to place another activity on the resource will be aware of the resource availability:

IloEnv env2; // Computation environment
IloSolver solver2(env2);
solver2.solve
       (SolveSubProblem(env2, solver2, compResource));
env2.end();

It outputs: [8 -- 8 --> 16]. The activity of the second sub-problem is scheduled to start at time 8.

Writing Multi-Threaded Applications

It is possible to use durable resources in multi-threaded applications. Scheduler is multi-thread safe if each thread uses a different solver for creating scheduler objects and those objects are not accessed across different threads.

Durable resources may be concurrently used by different threads through the methods lock and unlock.

  • The lock method may block while waiting for all arguments to be unlocked by other threads.
  • The unlock ethod allows other threads to gain access to its arguments.
Limitations

Currently, the only resources that can be managed as durable resources are discrete and unary resources, and energy resources.

The durable resources are shared by several independent computational solvers. The whole set of requirements on a durable resource is not known. Also, the following limitations exist:

  • The minimal capacity/energy of a durable resource is undefined: setCapacityMin, getCapacityMin, setEnergyMin, getEnergyMin will not work reliably.
  • The maximal capacity/energy of a durable resource should only be changed on the durable environment and protected with a lock. It is not reversible.
  • A durable resource cannot be closed.
Managing the Initial Requirement Amount on a Durable Resource

When entering a new session using durable resources, or when a commitment from a previous search phase must be removed (to figure out a rollback on a database), one needs specific functions for having non-monotonic, non- reversible behavior. Those functions are:

void IlcCapResource::incrDurableRequirement
                    (IlcInt t1, IlcInt t2, IlcInt capacity,
IlcInt outward = IlcTrue, IlcInt breaksDuration = 0);
void IlcCapResource::incrDurableRequirement
                    (IlcIntToIntStepFunction func);

These functions modify the requirement amount that corresponds to an activity starting a t1, ending at t2 and requiring the capacity of the argument capacity. The signature of this function, using an instance of IlcIntToIntStepFunction, nearly behaves like the iteration of the basic signature on each step of the function.

If the argument capacity is greater than 0, the effect of the function is to add capacity to the requirement amount to the resource; that is, to actually decrease the available capacity in the resource.

If the argument capacity is less than 0, the effect of the function is to remove capacity from the requirement amount of the resource; that is, to increase the available capacity in the resource.

The coherency of the requirement amount with respect to the resource capacity is under the responsibility of the user. For example, one should be cautious that the requirements that are undone do not exceed the activity requirements that are committed on the resource when a search using the durable resource is launched.

For a multi-threaded durable resource, these functions are enclosed in a critical section. That is, these functions are MT-hot.

In addition to the limitations described in the previous paragraph, the durable schedule be must closed and the resource must not be involved in a computational solver.

See Also

IlcResource, IlcSchedule, IlcWorkServer, IlcCapResource.

PREVIOUS NEXT