The intention of this page is to build a set of example code over time.
All code and other information was provided by Mike Pegman of Vine Solutions Ltd unless otherwise noted.
The mechanism built into Solver (IlcActive & IlcNextSolution) works only at the top level, i.e. not inside the scope of an IlcSolve, code like this:
IlcActive( myGoal() );
while (IlcNextSolution()) procToPrintSolution();
More interesting is the general form of non-deterministic loop which can be used anywhere you need this facility, thus:
ILCGOAL0(printSolution) {&ldots;}
IlcSolve( IlcAnd( myGoal(), printSolution(), IlcGoalFail() ) );
The simplest case is the delay between two adjacent jobs, allocated to a machine. In Scheduler, to model the set up time between any pair of jobs (activities) on a machine (resource), you derive a sub-class of the resource implementation class, overloading the getTransitionTime member function:
class myMachineI : public IlcUnaryResourceI {
public:
myMachineI::myMachineI(IlcSchedule schedule)
:IlcUnaryResourceI( schedule.getImpl(), IlcRequiredResource )
{}
IlcInt getTransitionTime(
const IlcResourceConstraintI* rc1st, const IlcResourceConstraintI* rc2nd){
switch ( ((Job *)rc1st->getActivity()->getObject())->getJobType() ) {
case type1: return 5;
case type2: return 12;
case &ldots; }
}
‘Job’ is an application specific class which ‘owns’ the activity and which has knowledge about its characteristics, such as the type of the job to be scheduled on the resource, which here determines the set-up time.
I note that the versions of the makeTimeTableConstraint member functions of resources which take a time range are now 'undocumented' (Schedule 2.1).
The Schedule development team have confirmed that they are considering moving away from multiple time tables. If you have views on this, especially if you use them, why not contact solver-support@ilog.fr ? (and please copy mp@vinesolutions.co.uk ).
This code will step through a time table and dump the variables to the C++ output stream cout.
IlcIntVarTable tab = money.getTimeTable();
IlcIntVarTableIterator iter(tab);
IlcIntVar iv;
IlcInt oldMin = 0;
while(iter.next(iv)) {
cout << iter.getIndexMin() << "\t" << iter.getIndexMax() << "\t";
cout << iv.getMin() << "\t" << iv.getMin()-oldMin <<
"\t" << iv.getMax() << endl;
oldMin = iv.getMin();
}
See the Scheduler White paper available from ILOG or email mp@vinesolutions.co.uk
// M Pegman (c) Vine Solutions Ltd 1996
// The Brick Kiln Example from the Schedule White Paper
#include <ilsched/intact.h>
ILCGOAL1( ScheduleActivity, IlcIntervalActivity, x ) {
return( IlcOr( x.getStartVariable() == x.getStartMin(),
And( x.getStartVariable() != x.getStartMin(), this) ) );
}
// Select unscheduled activities in aplha order
IlcActivitySelector1(ChooseActivity, !activity.getStartVariable().isBound(), activity.getName()[0], IlcIntervalActivity)
ILCGOAL1( ScheduleAll, IlcSchedule, x ) {
IlcIntervalActivity ChosenActivity;
if( ChooseActivity ( ChosenActivity, x ))
return IlcAnd( ScheduleActivity(ChosenActivity), this );
else
return 0;
}
IlcIntervalActivity MakeActivity(IlcSchedule schedule,IlcDiscreteResource resource, IlcInt duration, IlcInt requires, char* name) {
IlcIntervalActivity activity(schedule, duration);
activity.setName(name);
IlcPost(activity.requires(resource, requires));
return activity;
}
IlcSchedule DefineProblem(void)
{
IlcInt horizon = 11; // problem specification
IlcSchedule schedule(0, horizon);
IlcDiscreteResource kiln( schedule, IlcRequiredResource , 3);
IlcPost( kiln.makeTimeTableConstraint());
// IlcPost( kiln.makeDisjunctiveConstraint());
// kiln.setEdgeFinder(IlcTrue);
kiln.setCapacityMax( 0, 1, 2); kiln.setCapacityMax( 1, 2, 1); kiln.setCapacityMax( 2, 3, 0);
kiln.setCapacityMax( 3, 5, 1); kiln.setCapacityMax( 10,11, 1);
IlcIntervalActivity A = MakeActivity(schedule, kiln, 1, 2, "A ");
IlcIntervalActivity B = MakeActivity(schedule, kiln, 4, 1, "B ");
IlcIntervalActivity C = MakeActivity(schedule, kiln, 4, 1, "C ");
IlcIntervalActivity D = MakeActivity(schedule, kiln, 2, 1, "D ");
IlcIntervalActivity E = MakeActivity(schedule, kiln, 4, 2, "E ");
// Manual Method
// A.setStartTime(0);
// B.setStartTime(B.getStartMin());
// IlcPost( B.getStartVariable() != B.getStartMin() );
// IlcPost( A.getStartVariable() != 0 );
// A.setStartTime(5);
// B.setStartTime(3);
return schedule;
}
void PrintSolution(IlcSchedule schedule) {
IlcActivityIterator iterator(schedule);
IlcActivity activity;
while (iterator.next(activity))
IlcOut << activity << endl;
}
int main(void) {
IlcInit();
IlcSchedule schedule = DefineProblem();
if (IlcSolve(ScheduleAll(schedule))) {
PrintSolution(schedule);
}
else
cout << "Failed to schedule";
IlcPrintInformation();
IlcEnd();
return 0;
}
// (c) 1996 Vine Solutions Ltd
// Mike Pegman's extended frequency allocation example
// shows:
// more appropriate use of OO & locus of instantiation - see Node::generate
// minimisation by goal in STEP 1
//STEP 2 and by constraint
// custom constraint - cost increment
// this code is developed from the 'node' example in the Solver material in
// stages to teach the concepts of incremental back propagating cost functions and
// then to ilustrate a binary constraint.
// STEP 3 should be to make the cost csts to be generic
#include <ilsolver/ilcint.h>
class Node {
const IlcInt _id;
IlcIntVar_channels;
public:
Node(IlcInt id, IlcInt numberOfChannels);
~Node() {};
IlcIntVar getChannel() {return _channels;}
IlcBool isBound() const {return _channels.isBound();}
void display(ostream& str=cout) ;
IlcGoal generate(IlcIntVar costVar);
};
ILCGOAL3(Generate, IlcInt, size, Node**, node, IlcIntVar, costVar) {
if (size==0) return 0;
return IlcAnd( node[0]->generate(costVar),
Generate(size-1, &node[1], costVar)); }
// step 1
// 'bump' cost with a goal, called at the right time
ILCGOAL2(IncrCost, IlcIntVar, costVar, IlcIntVar, chan) {
costVar.setMin(chan.getValue());
return 0; }
ILCGOAL1(InstCost, IlcIntVar, cost) {
cost.setValue(cost.getMin());
cout << " cost set to " << cost << endl;
return 0;}
Node::Node(IlcInt id, IlcInt numberOfChannels)
:_channels(0, numberOfChannels), _id(id)
{};
void Node::display(ostream& str) {
str << getChannel() << endl; };
IlcGoal Node::generate(IlcIntVar costVar) {
// step 1 use of goal
//return IlcAnd(IlcInstantiate(_channels), IncrCost(costVar,_channels));
// step 2 - back to the base case!
return IlcInstantiate(_channels);}
ostream & operator<< (ostream & str, Node &node) { node.display(str); return str; }
void offset(Node &nodea, Node &nodeb, IlcInt off) {
IlcPost(IlcAbs(nodea.getChannel() - nodeb.getChannel()) >= off); }
// step 2 binary incremental cost constraint
class costCstI : public IlcConstraintI{
IlcIntVar _cost;
Node* _node;
public:
costCstI(IlcIntVar var, Node* n): _cost(var), _node(n) {}
~costCstI() {}
void post();
void propagate();
void varValue(); };
ILCDEMON1(CostCstIValueDemon, costCstI*, ct) { ct->varValue(); }
void costCstI::post() { _node->getChannel().whenValue(CostCstIValueDemon(this)); }
void costCstI::propagate() {
if (_node->getChannel().isBound())
varValue(); }
void costCstI::varValue() {
_cost.setMin(_node->getChannel().getValue());
cout << " in value " << _cost << " channel " << _node->getChannel().getValue()<< endl; }
IlcConstraint updateCost(IlcIntExp cost, Node* n) {
IlcConstraintI* ct = new (IlcHeap())costCstI(cost,n);
return ct;}
main () {
IlcInit();
Node node0(0,10); Node node1(0,10); Node node2(0,10); Node node3(0,10); Node node4(0,10);
IlcIntVar costVar(0,10);
offset(node0,node1,2); offset(node0,node2,2); offset(node1,node4,1); offset(node2,node3,3); offset(node2,node4,1);
Node *arrayOfNode[5];// = {&node0, &node1, &node2, &node3, &node4};
arrayOfNode[0]=&node0; arrayOfNode[1]=&node1; arrayOfNode[2]=&node2; arrayOfNode[3]=&node3; arrayOfNode[4]=&node4;
for (IlcInt i = 0; i<5; i++) IlcPost(updateCost(costVar,arrayOfNode[i]));
// showing alternative high level goal management
//IlcActive(IlcAnd( Generate(5, arrayOfNode, costVar), intCost(costVar) ) );
//while (IlcNextSolution())
if (IlcMinimize( IlcAnd( Generate(5,arrayOfNode,costVar), InstCost(costVar) ) , costVar)) {
IlcOut << node0 << node1 << node2 << node3 << node4;
}
IlcEnd();
return 0; }
© Copyright Vine Solutions Ltd 1997 Email to: mp@vinesolutions.co.uk