Overview | Group | Tree | Graph | Index | Concepts |
A resource precedence graph is a directed graph that can be associated with a resource and whose nodes are the resource constraints posted on the resource.
On a resource precedence graph, an edge between two resource constraints (rct1, rct2) means that the activity of rct1 is constrained to execute before the activity of rct2, provided that both resource constraints rct1 and rct2 definitely affect the availability of the resource (processing time and required capacity strictly greater than zero).
A resource precedence graph constraint is a constraint that creates a precedence graph structure for the resource with which it is associated and allows propagation of the precedence information contained in this graph on the variables of the resource constraints (start and end time, processing time, required capacity).
A
resource precedence graph constraint can be created on a resource with the member function IlcResource::makePrecedenceGraphConstraint
.
A resource precedence graph constraint is automatically created for each unary resource with a sequence constraint.
When a resource is associated with a precedence graph constraint, new precedence relations between resource constraints are automatically discovered and added to the graph by the disjunctive constraint, the edge finder, and the sequence constraint. New edges on the resource precedence graph are also discovered when the following precedence constraints are posted on the solver between two activities that require the resource:
IlcPrecedenceConstraintType::IlcStartsAfterEnd
with positive or null delayIlcPrecedenceConstraintType::IlcStartsAtEnd
with positive or null delayIlcPrecedenceConstraintType::IlcEndsAtStart
with negative or null delaySome member functions of the class IlcResourceConstraint
allow direct addition of new relations on the graph (IlcResourceConstraint::setNext
, IlcResourceConstraint::setSetup
, IlcResourceConstraint::setSuccessor
, IlcResourceConstraint::setTeardown
). Before entering the search,
it is also possible to remove relations already added on the graph (IlcResourceConstraint::unsetNext
, IlcResourceConstraint::unsetSetup
, IlcResourceConstraint::unsetSuccessor
, IlcResourceConstraint::unsetTeardown
).
Transitive closure of the graph is automatically computed and maintained during the search.
The information stored in the precedence graph can be accessed with
member functions of the class IlcResourceConstraint
--such as IlcResourceConstraint::hasAsNext
, IlcResourceConstraint::isDirectlySucceededBy
, IlcResourceConstraint::isSucceededBy
--and with the resource constraint iterator IlcResourceConstraintIterator
. The
availability of these accessors and iterators is restricted before entering the search,
as the transitive closure of the graph has not been computed.
Status of Resource Constraints in a Precedence Graph
In a resource precedence graph, a resource constraint rct is said to surely contribute if and only if:
IlcNever
, and IlcTimeExtent::IlcFromStartToEnd
, andIn a resource precedence graph, a resource constraint rct is said to not possibly contribute if and only if it is sure that rct will not affect the availability of the resource. That is:
IlcNever
, orIlcTimeExtent::IlcFromStartToEnd
, orRelative Positions of Resource Constraints in a Precedence Graph
Let rct1 and rct2 be two resource constraints on the same resource precedence graph.
Example
Consider a closed resource with five resource constraints rct1, rct2, rct3, rct4, and rct5 that definitely affect the availability of the resource. Suppose that the following relations have been added:
After the transitive closure of the graph has been computed during search, we find that:
This list is not exhaustive and, of course, the initial relations are still valid in the transitive closure.
Precedence Graph Events and Delta Sets of Resource Constraints
Several events can be defined on a resource constraint with a precedence graph (IlcResource::whenDirectPredecessors, IlcResource::whenDirectSuccessors, IlcResource::whenPredecessors, IlcResource::whenSuccessors, IlcResource::whenNext, IlcResource::whenPrevious). These events are triggered as soon as the corresponding set of resource constraints is modified because the structure of the precedence graph has changed.
The modifications of these sets of resource constraints are stored in special sets called delta sets. These delta sets can be accessed during the execution of the goals
associated with the event (see IlcResourceConstraintDeltaIterator
). When all the graph events
associated with a resource constraint have been processed, these delta sets are cleared.
For example, the following code displays the set of new direct successor links in the graph as soon as they are discovered.
class PrintCtI :public IlcConstraintI { public: PrintCtI(IloSolver solver) :IlcConstraintI(solver) {} void printNewDirectSuccessors(IlcResourceConstraint rct) { getSolver().out() << "New direct successors of " << rct << ":" << endl; for (IlcResourceConstraintDeltaIterator ite(rct, IlcDirectSuccessors); ite.ok(); ++ite) getSolver().out() << "\t" << *ite << endl; } }; ILCRESOURCEDEMON(PrintDirectSucc, PrintCtI, printNewDirectSuccessors); PrintCtI* printer = new PrintCtI(solver); IlcResource resource ...; resource.whenDirectSuccessors(PrintDirectSucc(printer));
The light precedence graph is a light version of the precedence graph constraint on unary resources. It is a global constraint that maintains the sequence of activities that have been ranked first, the sequence of activities that have been ranked last and a partition of the other (unranked) activities according to their status (Not)PossibleFirst/Last. The light precedence graph constraint is sufficient to enforce the unit capacity of the resource and the successor links between resource constraints. The main interest of the light precedence graph relies on the fact that its average complexity is linear with the number of activities.
The functionality consists of two member functions:
IlcResource::makeLightPrecedenceGraphConstraint
allows the creation and return of a light precedence graph constraint.IlcResource::hasLightPrecedenceGraphConstraint
returns IlcTrue
if and only if a light precedence graph constraint
has been created on the resource.When the light precedence graph is created and posted on a unary
resource, the member function
IlcResource::hasRankInfo
returns
IlcTrue
, and
it allows the use of the rank functionalities listed below:
IlcResourceConstraint::rankFirst
,
IlcResourceConstraint::rankNotFirst
,
IlcResourceConstraint::rankLast
,
IlcResourceConstraint::rankNotLast
,
IlcResourceConstraint::setSuccessor
,
IlcResourceConstraint::isPossibleFirst
,
IlcResourceConstraint::isPossibleLast
,
IlcResourceConstraint::isRanked
,
IlcResourceConstraint::isRankedFirst
, and
IlcResourceConstraint::isRankedLast
.
IlcUnaryResource::isRanked
,
IlcResource::whenRankedFirstRC
,
IlcResource::whenRankedLastRC
,
IlcResource::getLastRankedFirstRC
,
IlcResource::getLastRankedLastRC
,
IlcResource::getOldLastRankedFirstRC
, and
IlcResource::getOldLastRankedLastRC
.
IlcResource::ResourceConstraintIterator
and
IlcResource::ResourceConstraintDeltaIterator
.
IlcRank
and
IlcRankBackward
.
Note that both the disjunctive constraint (makeDisjunctiveConstraint
)
and the (classical) precedence graph constraint
(makePrecedenceGraphConstraint
) automatically create a light
precedence graph constraint. The light precedence graph constraint
should be used on unary resources with a large number of activities
when the quadratic complexity of the disjunctive constraint is too
expensive.
Whereas the nodes of a resource precedence graph represent resource constraints (see above), we describe in this section the concept of schedule precedence graph whose nodes are the activities created on a schedule.
On a schedule precedence graph, an edge between two activities ( act1, act2) means that activity act1 is constrained to execute before activity act2.
A schedule precedence graph constraint is a constraint that creates a precedence graph structure for the schedule with which it is associated and allows propagation of the precedence information contained in this graph on the variables of the activities (start and end time).
Creating a Schedule Precedence Graph Constraint
A schedule precedence graph constraint can be created on a schedule with the member function IlcSchedule::makePrecedenceGraphConstraint
.
Overview of Functions Related to Schedule Precedence Graphs
When a schedule is associated a precedence graph constraint, the coherence between this global graph and the resource precedence graphs is ensured: when new precedence relations are discovered on a resource with a precedence graph, these relations are also added on the schedule precedence graph and, reciprocally, when new precedence relations are added on the schedule precedence graph, the resource precedence graphs are updated accordingly.
New edges on the schedule precedence graph are automatically discovered when the following precedence constraints are posted on the solver:
IlcPrecedenceConstraintType::IlcStartsAfterEnd
with positive or null delayIlcPrecedenceConstraintType::IlcStartsAtEnd
with positive or null delayIlcPrecedenceConstraintType::IlcEndsAtStart
with negative or null delaySome member functions of the class IlcActivity
allow direct addition of new precedence relations on the graph (IlcActivity::setSuccessor
).
Before entering the search, it is also possible to remove relations already added on the graph (IlcActivity::unsetSuccessor
).
Note that adding a new precedence relation on the graph leads exactly to the same propagation as
posting a IlcPrecedenceConstraintType::IlcStartsAfterEnd
constraint with null delay.
Transitive closure of the graph is automatically computed and maintained during the search.
The information stored in the precedence graph can be accessed with member
functions of the class IlcActivity
(such as IlcActivity::isDirectlySucceededBy
, and IlcActivity::isSucceededBy
), and with the activity iterator IlcActivityIterator
. The
availability of these accessors and iterators is limited before entering the search,
as the transitive closure of the graph has not been computed.
Relative Positions of Activities in a Precedence Graph
Let act1 and act2 be two activities of a schedule with precedence graph.
Precedence Graph Events and Delta Sets of Activities
Several events can be defined on an activity with precedence graph (IlcSchedule::whenDirectPredecessors
, IlcSchedule::whenDirectSuccessors
, IlcSchedule::whenPredecessors
, IlcSchedule::whenSuccessors
.)
These events are triggered as soon as the corresponding set of activities is modified because
the structure of the precedence graph has changed.
The modifications of these sets of activities are stored in special sets called delta sets. These
delta sets can be accessed during the execution of the goals associated with the event (see IlcActivityDeltaIterator
). When all the
graph events associated with an activity have been processed, then these delta sets are cleared.
Example
For example, the following code displays the set of new direct successors of the activity
act
as soon as new direct successors of
act
are discovered on the precedence graph.
class PrintCtI :public IlcConstraintI { public: PrintCtI(IloSolver solver) :IlcConstraintI(solver) {} void printNewDirectSuccessors(IlcActivity act) { getSolver().out() << "New direct successors of " << act << ":" << endl; for (IlcActivityDeltaIterator ite(act, IlcDirectSuccessors); ite.ok(); ++ite) getSolver().out() << "\t" << *ite << endl; } }; ILCRESOURCEDEMON(PrintDirectSucc, PrintCtI, printNewDirectSuccessors); PrintCtI* printer = new PrintCtI(solver); IlcSchedule sched ...; sched.whenDirectSuccessors(PrintDirectSucc(printer));
See Also
IlcActivity, IlcActivityIterator, IlcActivityIteratorFilter, IlcActivityDeltaIterator, IlcResource, IlcResourceConstraint, IlcResourceConstraintIterator, IlcResourceConstraintDeltaIterator, IlcResourceConstraintIteratorFilter