You can see the entire program jobshopt.cpp
here or view it online in the standard distribution.
#include <ilsched/iloscheduler.h>
#include <ilsolver/iimls.h>
ILOSTLBEGIN
IloInt ResourceNumbers06 [] = {2, 0, 1, 3, 5, 4,
1, 2, 4, 5, 0, 3,
2, 3, 5, 0, 1, 4,
1, 0, 2, 3, 4, 5,
2, 1, 4, 5, 0, 3,
1, 3, 5, 0, 4, 2};
IloInt Durations06 [] = { 1, 3, 6, 7, 3, 6,
8, 5, 10, 10, 10, 4,
5, 4, 8, 9, 1, 7,
5, 5, 5, 3, 8, 9,
9, 3, 5, 4, 3, 1,
3, 3, 9, 10, 4, 1};
IloInt TransTimes06 [] = { 0, 2, 7, 3, 1, 3,
3, 0, 4, 7, 8, 8,
4, 2, 0, 5, 3, 6,
3, 6, 4, 0, 4, 7,
2, 1, 5, 5, 0, 1,
6, 4, 6, 9, 4, 0};
IloInt ResourceNumbers10 [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 2, 4, 9, 3, 1, 6, 5, 7, 8,
1, 0, 3, 2, 8, 5, 7, 6, 9, 4,
1, 2, 0, 4, 6, 8, 7, 3, 9, 5,
2, 0, 1, 5, 3, 4, 8, 7, 9, 6,
2, 1, 5, 3, 8, 9, 0, 6, 4, 7,
1, 0, 3, 2, 6, 5, 9, 8, 7, 4,
2, 0, 1, 5, 4, 6, 8, 9, 7, 3,
0, 1, 3, 5, 2, 9, 6, 7, 4, 8,
1, 0, 2, 6, 8, 9, 5, 3, 4, 7};
IloInt Durations10 [] = {29, 78, 9, 36, 49, 11, 62, 56, 44, 21,
43, 90, 75, 11, 69, 28, 46, 46, 72, 30,
91, 85, 39, 74, 90, 10, 12, 89, 45, 33,
81, 95, 71, 99, 9, 52, 85, 98, 22, 43,
14, 6, 22, 61, 26, 69, 21, 49, 72, 53,
84, 2, 52, 95, 48, 72, 47, 65, 6, 25,
46, 37, 61, 13, 32, 21, 32, 89, 30, 55,
31, 86, 46, 74, 32, 88, 19, 48, 36, 79,
76, 69, 76, 51, 85, 11, 40, 89, 26, 74,
85, 13, 61, 7, 64, 76, 47, 52, 90, 45};
IloInt TransTimes10 [] = {0, 9, 8, 1, 4, 3, 9, 2, 3, 7,
6, 0, 7, 5, 6, 1, 2, 1, 2, 3,
2, 3, 0, 3, 4, 3, 1, 9, 2, 2,
2, 7, 3, 0, 8, 7, 6, 4, 2, 1,
8, 3, 9, 8, 0, 5, 4, 9, 2, 3,
3, 2, 1, 3, 2, 0, 3, 2, 3, 9,
9, 8, 7, 4, 3, 8, 0, 6, 3, 4,
8, 7, 2, 1, 5, 3, 1, 0, 8, 2,
3, 9, 8, 5, 7, 1, 3, 2, 0, 9,
4, 8, 1, 2, 6, 4, 7, 2, 3, 0};
IloInt ResourceNumbers20 [] = {0, 1, 2, 3, 4,
0, 1, 3, 2, 4,
1, 0, 2, 4, 3,
1, 0, 4, 2, 3,
2, 1, 0, 3, 4,
2, 1, 4, 0, 3,
1, 0, 2, 3, 4,
2, 1, 0, 3, 4,
0, 3, 2, 1, 4,
1, 2, 0, 3, 4,
1, 3, 0, 4, 2,
2, 0, 1, 3, 4,
0, 2, 1, 3, 4,
2, 0, 1, 3, 4,
0, 1, 4, 2, 3,
1, 0, 3, 4, 2,
0, 2, 1, 3, 4,
0, 1, 4, 2, 3,
1, 2, 0, 3, 4,
0, 1, 2, 3, 4};
IloInt Durations20 [] = {29, 9, 49, 62, 44,
43, 75, 69, 46, 72,
91, 39, 90, 12, 45,
81, 71, 9, 85, 22,
14, 22, 26, 21, 72,
84, 52, 48, 47, 6,
46, 61, 32, 32, 30,
31, 46, 32, 19, 36,
76, 76, 85, 40, 26,
85, 61, 64, 47, 90,
78, 36, 11, 56, 21,
90, 11, 28, 46, 30,
85, 74, 10, 89, 33,
95, 99, 52, 98, 43,
6, 61, 69, 49, 53,
2, 95, 72, 65, 25,
37, 13, 21, 89, 55,
86, 74, 88, 48, 79,
69, 51, 11, 89, 74,
13, 7, 76, 52, 45};
IloInt TransTimes20 [] = {0, 3, 2, 9, 7,
3, 0, 2, 9, 5,
6, 4, 0, 5, 4,
1, 2, 3, 0, 7,
1, 9, 6, 4, 0};
///////////////////////////////////////////////////////////////////////////////
//
// PROBLEM DEFINITION
//
///////////////////////////////////////////////////////////////////////////////
class NbUnrankedExt {
private:
IlcInt _nbOfUnranked;
public:
NbUnrankedExt() :_nbOfUnranked(0) {};
~NbUnrankedExt(){};
void setValue(IlcInt nbOfUnranked) {
_nbOfUnranked = nbOfUnranked;
}
IlcInt getValue() const {
return _nbOfUnranked;
}
};
IloModel
DefineModel(IloEnv& env,
IloInt numberOfJobs,
IloInt numberOfResources,
IloInt* resourceNumbers,
IloInt* durations,
IloInt* transTimes,
IloNumVar& makespan)
{
IloModel model(env);
/* CREATE THE MAKESPAN VARIABLE. */
IloInt numberOfActivities = numberOfJobs * numberOfResources;
IloInt horizon = 0;
IloInt k;
IloInt maxTransTime = 0;
for (k = 0; k < numberOfResources*numberOfResources; k++)
if (maxTransTime < transTimes[k])
maxTransTime = transTimes[k];
for (k = 0; k < numberOfActivities; k++)
horizon += durations[k] + maxTransTime;
makespan = IloNumVar(env, 0, horizon, ILOINT);
/* CREATE THE TRANSITION TIMES */
IloTransitionParam ttParam(env, numberOfResources, IloFalse);
IloInt i, j;
for (i = 0; i < numberOfResources; i++)
for (j = 0; j < numberOfResources; j++)
ttParam.setValue(i, j, transTimes[j + (numberOfResources * i)]);
/* CREATE THE RESOURCES. */
IloSchedulerEnv schedEnv(env);
schedEnv.getResourceParam().setCapacityEnforcement(IloMediumHigh);
schedEnv.getResourceParam().setPrecedenceEnforcement(IloMediumHigh);
IloUnaryResource *resources =
new (env) IloUnaryResource[numberOfResources];
for (j = 0; j < numberOfResources; j++) {
IloUnaryResource res = IloUnaryResource(env);
IloTransitionTime( res, ttParam );
resources[j] = res;
}
/* CREATE THE ACTIVITIES. */
char buffer[128];
k = 0;
for (i = 0; i < numberOfJobs; i++) {
IloActivity previousActivity;
for (j = 0; j < numberOfResources; j++) {
IloActivity activity(env, durations[k]);
sprintf(buffer, "J%ldS%ldR%ld", i, j, resourceNumbers[k]);
activity.setName(buffer);
activity.setTransitionType(j);
IloResourceConstraint rct =
activity.requires(resources[resourceNumbers[k]]);
NbUnrankedExt* nbOfUnranked =
new (env) NbUnrankedExt();
rct.setObject(nbOfUnranked);
model.add(rct);
if (j != 0)
model.add(activity.startsAfterEnd(previousActivity));
previousActivity = activity;
k++;
}
model.add(previousActivity.endsBefore(makespan));
}
/* RETURN THE MODEL. */
return model;
}
///////////////////////////////////////////////////////////////////////////////
//
// PRINTING OF SOLUTIONS
//
///////////////////////////////////////////////////////////////////////////////
void
PrintSolution(IloSolver& solver)
{
IlcScheduler scheduler(solver);
IloEnv env = solver.getEnv();
for(IloIterator<IloActivity> ite(env); ite.ok(); ++ite)
solver.out() << scheduler.getActivity(*ite) << endl;
}
///////////////////////////////////////////////////////////////////////////////
//
// PROBLEM SOLVING
//
///////////////////////////////////////////////////////////////////////////////
IlcInt GetNumberOfUnranked(const IlcResourceConstraint& rct) {
/* RETURN NUMBER OF UNRANKED W.R.T. RCT */
IlcInt nb = 0;
for (IlcResourceConstraintIterator ite(rct, IlcUnranked);
ite.ok(); ++ite)
nb++;
return nb;
}
IlcInt GetOpportunity(
const IlcScheduler& scheduler,
const IlcResourceConstraint& srct1,
const IlcResourceConstraint& srct2) {
IlcActivity act1 = srct1.getActivity();
IlcActivity act2 = srct2.getActivity();
IlcInt smin1 = act1.getStartMin();
IlcInt smax1 = act1.getStartMax();
IlcInt emin1 = act1.getEndMin();
IlcInt emax1 = act1.getEndMax();
IlcInt smin2 = act2.getStartMin();
IlcInt smax2 = act2.getStartMax();
IlcInt emin2 = act2.getEndMin();
IlcInt emax2 = act2.getEndMax();
/* DOMAIN DELTA WHEN RCT1 RANKED BEFORE RCT2 */
IlcInt deltaEnd12 = ((emax1 < smax2) ? OL : emax1 - smax2);
IlcInt deltaStart12 = ((smin2 > emin1) ? OL : emin1 - smin2);
IlcInt delta12 = deltaEnd12 + deltaStart12;
/* DOMAIN DELTA WHEN RCT2 RANKED BEFORE RCT1 */
IlcInt deltaEnd21 = ((emax2 < smax1) ? OL : emax2 - smax1);
IlcInt deltaStart21 = ((smin1 > emin2) ? OL : emin2 - smin1);
IlcInt delta21 = deltaEnd21 + deltaStart21;
/* MINIMAL NUMBER OF UNRANKED RESOURCE CONSTRAINTS */
IlcInt nbUrkd1 = ((NbUnrankedExt*)(scheduler.getExtractable(srct1).getObject()))->getValue();
IlcInt nbUrkd2 = ((NbUnrankedExt*)(scheduler.getExtractable(srct2).getObject()))->getValue();
IlcInt minNbUrkd = (nbUrkd1 <= nbUrkd2) ? nbUrkd1 : nbUrkd2;
/* RETURN MEASURE OF OPPORTUNITY */
return (minNbUrkd * (delta12 - delta21));
}
IlcBool
SelectMostOpportunisticConflict(IlcScheduler& schedule,
IlcResourceConstraint& selectedRct1,
IlcResourceConstraint& selectedRct2) {
IlcBool existsConflict = IlcFalse;
IlcInt oppMaxAbs = -1;
IlcInt oppMax = 0;
IlcInt opp;
for (IlcUnaryResourceIterator ires(schedule); ires.ok(); ++ires) {
IlcUnaryResource resource = (*ires);
if (resource.hasPrecedenceGraphConstraint() &&
!resource.isRanked()) {
/* FOR EACH RESOURCE CONSTRAINT, COMPUTE AND STORE THE NUMBER OF
RESOURCE CONSTRAINTS UNRANKED W.R.T. IT */
for (IlcResourceConstraintIterator irct(resource);
irct.ok(); ++irct) {
IlcResourceConstraint rct = (*irct);
if (!rct.isRanked())
((NbUnrankedExt*)schedule.getExtractable(rct).getObject())->
setValue(GetNumberOfUnranked(rct));
}
/* SELECT MOST OPPORTUNISTIC PAIR OF RESOURCE CONSTRAINT */
for (IlcResourceConstraintIterator isrct1(resource);
isrct1.ok(); ++isrct1) {
IlcResourceConstraint srct1 = (*isrct1);
if (!srct1.isRanked()) {
for (IlcResourceConstraintIterator isrct2(srct1, IlcUnranked);
isrct2.ok(); ++isrct2) {
IlcResourceConstraint srct2 = (*isrct2);
opp = GetOpportunity(schedule, srct1, srct2);
if (oppMaxAbs < IloAbs(opp)) {
existsConflict = IlcTrue;
oppMaxAbs = IlcAbs(opp);
oppMax = opp;
selectedRct1 = srct1;
selectedRct2 = srct2;
}
}
}
}
}
}
/* SELECT WHICH BRANCH WILL BE CHOSEN FIRST AMONG RCT1 << RCT2 AND
RCT2 << RCT1 */
if (existsConflict && (0 < oppMax)) {
IlcResourceConstraint tmpRct = selectedRct1;
selectedRct1 = selectedRct2;
selectedRct2 = tmpRct;
}
return existsConflict;
}
ILCGOAL0(SolveConflictsIlc) {
IloSolver s = getSolver();
IlcScheduler scheduler = IlcScheduler(s);
IlcResourceConstraint srct1;
IlcResourceConstraint srct2;
if (SelectMostOpportunisticConflict(scheduler, srct1, srct2))
return IlcAnd(IlcTrySetSuccessor(srct1, srct2), this);
return 0;
}
ILOCPGOALWRAPPER0(SolveConflicts, solver) {
return SolveConflictsIlc(solver);
}
void
SetMakespanInitialBounds(IloSolver& solver,
IloNumVar& makespan)
{
/* SET MAKESPAN LOWER BOUND AND RESTART */
solver.solve(IloGoalTrue(solver.getEnv()));
makespan.setLB(solver.getMin(makespan));
/* SOLVE WITH GOAL SOLVECONFLICTS */
IloGoal solveConflicts = SolveConflicts(solver.getEnv());
solver.solve(solveConflicts);
/* SET MAKESPAN UPPER BOUND */
makespan.setUB(solver.getMin(makespan));
solver.out() << "Solution with makespan " << makespan.getUB() << endl;
}
void
Dichotomize(IloModel& model,
IloSolver& solver,
const IloNumVar& makespan)
{
/* GET MAKESPAN INITIAL BOUNDS */
IloNum min = makespan.getLB();
IloNum max = makespan.getUB();
/* OPTIMIZE. */
IloGoal goal = IloRankForward(solver.getEnv(),
makespan,
IloSelResMinLocalSlack,
IloSelFirstRCMinStartMax);
while(min < max) {
IloNum value = IloFloor((min + max) / 2);
IloConstraint ct = (makespan <= value);
model.add(ct);
if (solver.solve(goal)) {
max = solver.getMin(makespan);
solver.out() << "Solution with makespan " << max << endl;
}
else {
solver.out() << "Failure with makespan " << value << endl;
min = value + 1;
}
model.remove(ct);
}
/* RECOMPUTE THE OPTIMAL SOLUTION. THIS STEP COULD BE AVOIDED IF
SOLUTIONS WERE STORED AS PART OF THE OPTIMIZATION PROCESS. */
model.add(makespan == max);
solver.solve(goal);
}
///////////////////////////////////////////////////////////////////////////////
//
// MAIN FUNCTION
//
///////////////////////////////////////////////////////////////////////////////
void
InitParameters(int argc,
char** argv,
IloInt& numberOfJobs,
IloInt& numberOfResources,
IloInt*& resourceNumbers,
IloInt*& durations,
IloInt*& transTimes)
{
if (argc > 1) {
IloInt number = atol(argv[1]);
if (number == 10) {
numberOfJobs = 10;
numberOfResources = 10;
resourceNumbers = ResourceNumbers10;
durations = Durations10;
transTimes = TransTimes10;
}
else if (number == 20) {
numberOfJobs = 20;
numberOfResources = 5;
resourceNumbers = ResourceNumbers20;
durations = Durations20;
transTimes = TransTimes20;
}
}
}
int main(int argc, char** argv)
{
try {
IloEnv env;
IloInt numberOfJobs = 6;
IloInt numberOfResources = 6;
IloInt* resourceNumbers = ResourceNumbers06;
IloInt* durations = Durations06;
IloInt* transTimes = TransTimes06;
InitParameters(argc,
argv,
numberOfJobs,
numberOfResources,
resourceNumbers,
durations,
transTimes);
IloNumVar makespan;
IloModel model = DefineModel(env,
numberOfJobs,
numberOfResources,
resourceNumbers,
durations,
transTimes,
makespan);
IloSolver solver(model);
SetMakespanInitialBounds(solver, makespan);
Dichotomize(model, solver, makespan);
PrintSolution(solver);
solver.printInformation();
env.end();
}
catch (IloException& exc) {
cout << exc << endl;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
//
// RESULTS
//
///////////////////////////////////////////////////////////////////////////////
/* jobshopt 6
Solution with makespan 71
Failure with makespan 59
Solution with makespan 65
Failure with makespan 62
Failure with makespan 64
J0S0R2 [14..16 -- 1 --> 15..17]
J0S1R0 [15..17 -- 3 --> 18..20]
J0S2R1 [25..39 -- 6 --> 31..45]
J0S3R3 [34..45 -- 7 --> 41..52]
J0S4R5 [50..52 -- 3 --> 53..55]
J0S5R4 [59 -- 6 --> 65]
J1S0R1 [8 -- 8 --> 16]
J1S1R2 [17..21 -- 5 --> 22..26]
J1S2R4 [26 -- 10 --> 36]
J1S3R5 [36..38 -- 10 --> 46..48]
J1S4R0 [48..50 -- 10 --> 58..60]
J1S5R3 [58..60 -- 4 --> 62..64]
J2S0R2 [9..11 -- 5 --> 14..16]
J2S1R3 [14..17 -- 4 --> 18..21]
J2S2R5 [18..21 -- 8 --> 26..29]
J2S3R0 [35..37 -- 9 --> 44..46]
J2S4R1 [44..51 -- 1 --> 45..52]
J2S5R4 [52 -- 7 --> 59]
J3S0R1 [3 -- 5 --> 8]
J3S1R0 [8..12 -- 5 --> 13..17]
J3S2R2 [26..31 -- 5 --> 31..36]
J3S3R3 [31..36 -- 3 --> 34..39]
J3S4R4 [39 -- 8 --> 47]
J3S5R5 [54..56 -- 9 --> 63..65]
J4S0R2 [0..2 -- 9 --> 9..11]
J4S1R1 [18 -- 3 --> 21]
J4S2R4 [21 -- 5 --> 26]
J4S3R5 [31..34 -- 4 --> 35..38]
J4S4R0 [58..61 -- 3 --> 61..64]
J4S5R3 [62..64 -- 1 --> 63..65]
J5S0R1 [0 -- 3 --> 3]
J5S1R3 [3..9 -- 3 --> 6..12]
J5S2R5 [6..12 -- 9 --> 15..21]
J5S3R0 [25..27 -- 10 --> 35..37]
J5S4R4 [47 -- 4 --> 51]
J5S5R2 [51..64 -- 1 --> 52..65]
*/