The complete program and output for cost2.cpp
follows. You can also view it online in the file YourDispatcherHome/examples/src/cost2.cpp.
// -------------------------------------------------------------- -*- C++ -*-
// File: examples/src/cost2.cpp
//---------------------------------------------------------------------------
#include <ildispat/ilodispatcher.h>
ILOSTLBEGIN
///////////////////////////////////////////////////////////////////////////////
// Modeling
class RoutingModel {
IloEnv _env;
IloModel _mdl;
void createDimensions();
void createIloNodes(char* nodeFileName);
void createVehicles(char* vehicleFileName);
void createVisits(char* visitsFileName);
public:
RoutingModel(IloEnv env,
int argc,
char* argv[]);
~RoutingModel() {}
IloEnv getEnv() const { return _env; }
IloModel getModel() const { return _mdl; }
};
RoutingModel::RoutingModel(IloEnv env,
int argc,
char * argv[])
: _env(env), _mdl(env){
createDimensions();
char* nodeFileName;
if(argc < 4)
nodeFileName = (char *) "../../../examples/data/pdp/nodes.csv";
else
nodeFileName = argv[3];
createIloNodes(nodeFileName);
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/visits.csv";
else
visitsFileName = argv[2];
createVisits(visitsFileName);
}
// 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 IloNodes
void RoutingModel::createIloNodes(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);
IloNumToNumSegmentFunction costFunction(_env);
costFunction.setSlope(75, 100, 37.5, 0.5);
costFunction.setSlope(100, IloInfinity, 100, 1);
vehicle.setCost(distance, costFunction);
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));
++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
<< IloVerbose(dispatcher) << endl;
}
// Solving
void RoutingSolver::solve() {
IloDispatcher dispatcher(_solver);
IloEnv env = _solver.getEnv();
// Subgoal
IloGoal instantiateCost = IloDichotomize(env,
dispatcher.getCostVar(),
IloFalse);
IloGoal restoreSolution = IloRestoreSolution(env, _solution);
IloGoal goal = IloSavingsGenerate(env) && instantiateCost;
// Solving
if (findFirstSolution(goal)) {
improve(instantiateCost);
_solver.solve(restoreSolution);
}
}
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char * argv[]) {
IloEnv env;
try {
RoutingModel mdl(env, argc, argv);
RoutingSolver solver(mdl);
solver.solve();
solver.printInformation();
} catch(IloException& ex) {
cerr << "Error: " << ex << endl;
}
env.end();
return 0;
}