The complete program follows. You can also view it online in the file YourDispatcherHome/examples/src/bays.cpp
.
// -------------------------------------------------------------- -*- C++ -*-
// File: examples/src/bays.cpp
//---------------------------------------------------------------------------
#include <ildispat/ilodispatcher.h>
#include <ilsched/iloscheduler.h>
ILOSTLBEGIN
///////////////////////////////////////////////////////////////////////////////
// Modeling
class RoutingModel {
IloEnv _env;
IloModel _mdl;
IloDiscreteResource _bays;
IloInt _schedGranularity;
void createDepotDockingBays(char* baysFileName);
void createDimensions();
void createNodes(char* nodeFileName);
void createVehicles(char* vehicleFileName);
void createVisits(char* visitsFileName);
public:
RoutingModel(IloEnv env,
int argc,
char* argv[],
IloInt schedGranularity = 100);
~RoutingModel() {}
IloDiscreteResource getBays() const { return _bays; }
IloEnv getEnv() const { return _env; }
IloModel getModel() const { return _mdl; }
};
RoutingModel::RoutingModel(IloEnv env,
int argc,
char * argv[],
IloInt schedGranularity)
: _env(env), _mdl(env), _schedGranularity(schedGranularity) {
createDimensions();
char* nodeFileName;
if(argc < 4)
nodeFileName = (char *) "../../../examples/data/pdp/nodes.csv";
else
nodeFileName = argv[3];
createNodes(nodeFileName);
char* baysFileName;
if (argc < 5)
baysFileName = (char*) "../../../examples/data/bays.csv";
else
baysFileName = argv[4];
createDepotDockingBays(baysFileName);
char* vehiclesFileName;
if (argc < 2)
vehiclesFileName = (char *) "../../../examples/data/pdp/vehicles.csv";
else
vehiclesFileName = argv[1];
createVehicles(vehiclesFileName);
char* visitsFileName;
if (argc < 3)
visitsFileName =
(char*) "../../../examples/data/pdp/visitsWithPickupInDepot.csv";
else
visitsFileName = argv[2];
createVisits(visitsFileName);
}
// Create docking bays
void RoutingModel::createDepotDockingBays(char* baysFileName) {
// Scheduler environment settings
IloCsvReader csvBaysReader(_env, baysFileName);
IloCsvReader::LineIterator it(csvBaysReader);
while (it.ok()) {
IloCsvLine line = *it;
IloSchedulerEnv schedEnv(_env);
IloInt horizon = line.getIntByHeader("horizon");
IloInt nbOfBays = line.getIntByHeader("bays");
IloInt breakStart = line.getIntByHeader("breakStart");
IloInt breakEnd = line.getIntByHeader("breakEnd");
schedEnv.setHorizon(horizon * _schedGranularity);
_bays = IloDiscreteResource(_env, nbOfBays);
_bays.addBreak(breakStart * _schedGranularity,
breakEnd * _schedGranularity);
++it;
}
csvBaysReader.end();
}
// Create dimensions
void RoutingModel::createDimensions() {
IloDimension1 weight(_env, "Weight");
weight.setKey("Weight");
_mdl.add(weight);
IloDimension2 time(_env, IloEuclidean, "Time");
time.setKey("Time");
_mdl.add(time);
IloDimension2 distance(_env, IloEuclidean, IloFalse, "Distance");
distance.setKey("Distance");
_mdl.add(distance);
}
// Create nodes
void RoutingModel::createNodes(char* nodeFileName) {
IloCsvReader csvNodeReader(_env, nodeFileName);
IloCsvReader::LineIterator it(csvNodeReader);
while(it.ok()) {
IloCsvLine line = *it;
char* name = line.getStringByHeader("name");
IloNode node(_env,
line.getFloatByHeader("x"),
line.getFloatByHeader("y"),
0,
name);
node.setKey(name);
++it;
}
csvNodeReader.end();
}
// Create vehicles
void RoutingModel::createVehicles(char* vehicleFileName) {
IloDimension1 weight = IloDimension1::Find(_env, "Weight");
IloDimension2 time = IloDimension2::Find(_env, "Time");
IloDimension2 distance = IloDimension2::Find(_env, "Distance");
IloCsvReader csvVehicleReader(_env, vehicleFileName);
IloCsvReader::LineIterator it(csvVehicleReader);
while(it.ok()) {
IloCsvLine line = *it;
char * namefirst = line.getStringByHeader("first");
char * namelast = line.getStringByHeader("last");
char * name = line.getStringByHeader("name");
IloNum capacity = line.getFloatByHeader("capacity");
IloNum openTime = line.getFloatByHeader("open");
IloNum closeTime = line.getFloatByHeader("close");
IloNode node1 = IloNode::Find(_env, namefirst);
IloNode node2 = IloNode::Find(_env, namelast);
IloVisit first(node1, "depot");
_mdl.add(first.getCumulVar(weight) == 0);
_mdl.add(first.getCumulVar(time) >= openTime);
IloVisit last(node2, "depot");
_mdl.add(last.getCumulVar(time) <= closeTime);
IloVehicle vehicle(first, last, name);
vehicle.setCost(distance, 1.0);
vehicle.setCost(time, 1.0);
vehicle.setCapacity(weight, capacity);
_mdl.add(vehicle);
++it;
}
csvVehicleReader.end();
}
// Create visits
void RoutingModel::createVisits(char* visitsFileName) {
IloDimension1 weight = IloDimension1::Find(_env, "Weight");
IloDimension2 time = IloDimension2::Find(_env, "Time");
IloCsvReader csvVisitReader(_env, visitsFileName);
IloCsvReader::LineIterator it(csvVisitReader);
while(it.ok()){
IloCsvLine line = *it;
//read visit data from files
char * pickupVisitName = line.getStringByHeader("pickup");
char * pickupNodeName = line.getStringByHeader("pickupNode");
char * deliveryVisitName = line.getStringByHeader("delivery");
char * deliveryNodeName = line.getStringByHeader("deliveryNode");
IloNum quantity = line.getFloatByHeader("quantity");
IloNum pickupMinTime = line.getFloatByHeader("pickupMinTime");
IloNum pickupMaxTime = line.getFloatByHeader("pickupMaxTime");
IloNum deliveryMinTime = line.getFloatByHeader("deliveryMinTime");
IloNum deliveryMaxTime = line.getFloatByHeader("deliveryMaxTime");
IloNum dropTime = line.getFloatByHeader("dropTime");
IloNum pickupTime = line.getFloatByHeader("pickupTime");
// read data nodes from the file nodes.csv
// and create pickup and delivery nodes
IloNode pickupNode = IloNode::Find(_env, pickupNodeName);
IloNode deliveryNode = IloNode::Find(_env, deliveryNodeName);
//create and add pickup and delivery visits
IloVisit pickup(pickupNode, pickupVisitName);
_mdl.add(pickup.getDelayVar(time) >= pickupTime);
_mdl.add(pickup.getTransitVar(weight) == quantity);
_mdl.add(pickupMinTime <= pickup.getCumulVar(time) <= pickupMaxTime);
_mdl.add(pickup);
IloVisit delivery(deliveryNode, deliveryVisitName);
_mdl.add(delivery.getDelayVar(time) == dropTime);
_mdl.add(delivery.getTransitVar(weight) == -quantity);
_mdl.add(deliveryMinTime <= delivery.getCumulVar(time) <= deliveryMaxTime);
_mdl.add(delivery);
//add pickup and delivery order constraint
_mdl.add(IloOrderedVisitPair(_env, pickup, delivery));
// Pickup requiring docking bay
IloNumVar process(_env, 0, pickupMaxTime * _schedGranularity, ILOINT);
IloActivity vehicleLoad(_env, process);
IloNumVar start(_env, 0, pickupMaxTime * _schedGranularity, ILOINT);
IloNumVar end(_env, 0, pickupMaxTime * _schedGranularity, ILOINT);
_mdl.add(start == vehicleLoad.getStartExpr());
_mdl.add(end == vehicleLoad.getEndExpr());
vehicleLoad.setName(pickupVisitName);
vehicleLoad.setBreakable();
_mdl.add(vehicleLoad.requires(_bays, 1));
_mdl.add(start == pickup.getCumulVar(time) * _schedGranularity);
_mdl.add(end <= (pickup.getCumulVar(time) + pickup.getDelayVar(time))
* _schedGranularity);
_mdl.add(process >= pickupTime * _schedGranularity);
++it;
}
csvVisitReader.end();
}
///////////////////////////////////////////////////////////////////////////////
// Solving
class RoutingSolver {
IloModel _mdl;
IloSolver _solver;
IloRoutingSolution _solution;
IloBool findFirstSolution(IloGoal goal);
void greedyImprove(IloNHood nhood, IloGoal subGoal);
void improve(IloGoal subgoal);
public:
RoutingSolver(RoutingModel mdl);
~RoutingSolver() {}
IloRoutingSolution getSolution() const { return _solution; }
void printInformation() const;
void solve();
};
RoutingSolver::RoutingSolver(RoutingModel mdl)
: _mdl(mdl.getModel()), _solver(mdl.getModel()), _solution(mdl.getModel()) {}
// Solving : find first solution
IloBool RoutingSolver::findFirstSolution(IloGoal goal) {
if (!_solver.solve(goal)) {
_solver.error() << "Infeasible Routing Plan" << endl;
return IloFalse;
}
IloDispatcher dispatcher(_solver);
_solver.out() << dispatcher.getTotalCost() << endl;
_solution.store(_solver);
return IloTrue;
}
// Improve solution using nhood
void RoutingSolver::greedyImprove(IloNHood nhood, IloGoal subGoal) {
_solver.out() << "Improving solution" << endl;
IloEnv env = _solver.getEnv();
nhood.reset();
IloGoal improve = IloSingleMove(env,
_solution,
nhood,
IloImprove(env),
subGoal);
while (_solver.solve(improve)) {}
}
// Improve solution
void RoutingSolver::improve(IloGoal subGoal) {
IloEnv env = _solver.getEnv();
IloNHood nhood = IloTwoOpt(env)
+ IloOrOpt(env)
+ IloRelocate(env)
+ IloCross(env)
+ IloExchange(env);
greedyImprove(nhood, subGoal);
}
// Display Dispatcher information
void RoutingSolver::printInformation() const {
IloDispatcher dispatcher(_solver);
_solver.printInformation();
dispatcher.printInformation();
_solver.out() << "===============" << endl
<< "Cost : " << dispatcher.getTotalCost() << endl
<< "Number of vehicles used : "
<< dispatcher.getNumberOfVehiclesUsed() << endl
<< "Solution : " << endl
<< dispatcher << endl;
IlcScheduler sched(_solver);
for (IlcActivityIterator iter(sched); iter.ok(); ++iter) {
_solver.out() << *iter << endl;
}
}
// Solving
void RoutingSolver::solve() {
IloDispatcher dispatcher(_solver);
IloEnv env = _solver.getEnv();
// Subgoals
IloGoal instantiateCost = IloDichotomize(env,
dispatcher.getCostVar(),
IloFalse);
IloGoal schedGoal = IloSetTimesForward(env);
IloGoal subGoal = schedGoal && instantiateCost;
IloGoal restoreSolution = IloRestoreSolution(env, _solution) && subGoal;
IloGoal goal = IloSavingsGenerate(env, schedGoal) && instantiateCost;
// Solving
if (findFirstSolution(goal)) {
improve(subGoal);
_solver.solve(restoreSolution);
}
}
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char * argv[]) {
IloEnv env;
try {
IloInt schedGranularity = 100;
RoutingModel mdl(env, argc, argv, schedGranularity);
RoutingSolver solver(mdl);
solver.solve();
solver.printInformation();
} catch(IloException& ex) {
cerr << "Error: " << ex << endl;
}
env.end();
return 0;
}