The complete program follows. You can also view it online in the file YourDispatcherHome/examples/src/carp.cpp
.
// -------------------------------------------------------------- -*- C++ -*-
// File: examples/src/carp.cpp
//---------------------------------------------------------------------------
#include <ildispat/ilodispatcher.h>
ILOSTLBEGIN
///////////////////////////////////////////////////////////////////////////////
// Modeling
class RoutingModel {
IloEnv _env;
IloModel _mdl;
IloDispatcherGraph _graph;
IloDimension2 _time;
IloDimension2 _distance;
IloDimension1 _weight;
void addDimensions();
void loadGraphInformation (char* arcFileName);
void CreateIloNodes(char* nodeFileName, char* coordFileName);
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; }
void modifyGraphArcCost();
IloDispatcherGraph getGraph() const { return _graph; }
};
RoutingModel::RoutingModel( IloEnv env,
int argc,
char* argv[]):
_env(env), _mdl(env), _graph(env) {
addDimensions();
// load dispatcher graph information from file and add instance-specific features
char * arcFileName;
if(argc < 5) arcFileName = (char *) "../../../examples/data/dispatcherGraphData/gridNetwork.csv";
else arcFileName = argv[4];
loadGraphInformation (arcFileName);
//create IloNodes
char * nodeFileName;
if(argc < 4) nodeFileName = (char *) "../../../examples/data/carp/nodes.csv";
else nodeFileName = argv[3];
char * nodeCoordsFile;
if(argc < 6) nodeCoordsFile = (char *) "../../../examples/data/carp/coordTable.csv";
else nodeCoordsFile = argv[5];
CreateIloNodes(nodeFileName, nodeCoordsFile);
//create vehicles
char * vehiclesFileName;
if(argc < 2) vehiclesFileName = (char *) "../../../examples/data/carp/vehicles.csv";
else vehiclesFileName = argv[1];
CreateVehicles(vehiclesFileName);
//create visits
char * visitsFileName;
if(argc < 3) visitsFileName = (char *) "../../../examples/data/carp/visits.csv";
else visitsFileName = argv[2];
CreateVisits(visitsFileName);
}
// Create distance functions for dimensions, add dimensions to model
void RoutingModel::addDimensions() {
_weight =IloDimension1 (_env, "weight");
_mdl.add(_weight);
IloDistance SP_time = IloGraphDistance (_graph);
_time =IloDimension2 (_env, SP_time, "time");
_mdl.add(_time);
IloDistance SP_distance = IloGraphDistance (_graph);
_distance =IloDimension2 (_env, SP_distance, "distance");
_mdl.add(_distance);
}
// load network topology and travel costs from files.
void RoutingModel::loadGraphInformation (char* arcFileName) {
_graph.createArcsFromFile (arcFileName);
_graph.loadArcDimensionDataFromFile (arcFileName, _time);
_graph.loadArcDimensionDataFromFile (arcFileName, _distance);
}
//create IloNodes
void RoutingModel::CreateIloNodes(char* nodeFileName, char* coordFileName) {
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);
_graph.associateByCoordsInFile (node, coordFileName);
++it;
}
csvNodeReader.end();
}
//create vehicles
void RoutingModel::CreateVehicles(char* vehicleFileName) {
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 costRatio = line.getFloatByHeader("costRatio");
IloNode node1 = IloNode::Find(_env, namefirst);
IloNode node2 = IloNode::Find(_env, namelast);
IloVisit first(node1, "depot");
_mdl.add(first.getCumulVar(_distance) == 0);
_mdl.add(first.getCumulVar(_time) == 0);
IloVisit last(node2, "depot");
IloVehicle vehicle(first, last, name);
vehicle.setCost(_time, 100 * costRatio);
vehicle.setCost(_distance, 100 * (1- costRatio));
vehicle.setCapacity(_weight, capacity);
_mdl.add(vehicle);
++it;
}
csvVehicleReader.end();
}
//create visits
void RoutingModel::CreateVisits(char* visitsFileName) {
IloCsvReader csvVisitReader(_env, visitsFileName);
IloCsvReader::LineIterator it(csvVisitReader);
char c = 's';
while(it.ok()){
IloCsvLine line = *it;
//read visit data from files
char * visitName = line.getStringByHeader("name");
char * nodeName1 = line.getStringByHeader("nodeName1");
char * nodeName2 = line.getStringByHeader("nodeName2");
IloInt symmetric = line.getIntByHeader("symmetric");
IloNum quantity = line.getFloatByHeader("quantity");
IloNum timeValue = line.getFloatByHeader("time");
IloNum distanceValue = line.getFloatByHeader("distance");
IloNode node1 = IloNode::Find(_env, nodeName1);
IloNode node2 = IloNode::Find(_env, nodeName2);
IloVisit visit1(node1, node2, visitName);
_mdl.add(visit1.getTransitVar(_weight) == quantity);
_mdl.add(visit1.getDelayVar(_time) == timeValue );
_mdl.add(visit1.getDelayVar(_distance) == distanceValue );
_mdl.add(visit1);
if(symmetric) {
visit1.setPenaltyCost(0);
char visitName2[16];
sprintf(visitName2, "%s%c", visitName, c);
IloVisit visit2(node2, node1, visitName2);
_mdl.add(visit2.getTransitVar(_weight) == quantity);
_mdl.add(visit2.getDelayVar(_time) == timeValue );
_mdl.add(visit2.getDelayVar(_distance) == distanceValue );
visit2.setPenaltyCost(0);
_mdl.add(visit2);
_mdl.add(visit1.performed() + visit2.performed() == 1);
}
++it;
}
csvVisitReader.end();
}
// Modify problem set-up by modifying the cost of un arc in the graph
void RoutingModel::modifyGraphArcCost() {
IloDispatcherGraph::Arc arc1 = _graph.getArc(3916); //Arc from 1043 to 987
IloDispatcherGraph::Arc arc2 = _graph.getArc(4134); //Arc from 1043 to 1042
IloDispatcherGraph::Arc arc3 = _graph.getArc(4136); //Arc from 1043 to 1044
IloDispatcherGraph::Arc arc4 = _graph.getArc(4137); //Arc from 1043 to 1099
_graph.setArcCost(arc1, _time, 10);
_graph.setArcCost(arc2, _time, 10);
_graph.setArcCost(arc3, _time, 10);
_graph.setArcCost(arc4, _time, 10);
}
///////////////////////////////////////////////////////////////////////////////
// Solving
class RoutingSolver {
IloModel _mdl;
IloSolver _solver;
IloRoutingSolution _solution;
IloEnv _env;
IloDispatcher _dispatcher;
IloGoal _instantiateCost;
IloGoal _restoreSolution;
IloGoal _goal;
void greedyImprove(IloNHood nhood, IloGoal subGoal);
void improve(IloGoal subgoal);
void improveWithFastGLS(IloNHood nhood, IloInt nbOfIter, IloGoal subgoal);
public:
RoutingSolver(RoutingModel mdl);
~RoutingSolver() {}
IloRoutingSolution getSolution() const { return _solution; }
void printInformation() const;
IloBool findFirstSolution();
void improveWithNHood(IloInt nbIter);
void modifyFilterLevelAndRestore();
void restoreSolution();
void displayPaths(IloDispatcherGraph graph);
};
RoutingSolver::RoutingSolver(RoutingModel mdl):
_mdl(mdl.getModel()),
_solver(mdl.getModel()),
_solution(mdl.getModel()),
_env(mdl.getEnv()),
_dispatcher(_solver) {
_instantiateCost = IloGoal (IloDichotomize(_env, _dispatcher.getCostVar(), IloFalse));
_restoreSolution = IloGoal(IloRestoreSolution(_env, _solution));
_goal = IloGoal(IloSavingsGenerate(_env) && _instantiateCost);
}
// Solving : find first solution
IloBool RoutingSolver::findFirstSolution() {
if (!_solver.solve(_goal)) {
_solver.error() << "Infeasible Routing Plan" << endl;
return IloFalse;
}
_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;
nhood.reset();
IloGoal improve = IloSingleMove(_env,
_solution,
nhood,
IloImprove(_env),
subGoal);
while (_solver.solve(improve)) {}
}
// Modify dispatcher filter level and resolve
void RoutingSolver::modifyFilterLevelAndRestore() {
_dispatcher.setFilterLevel(IlcMedium);
IloNum cost = _solution.getObjectiveValue();
_solver.solve(_restoreSolution
&& IloSetMax(_env, _dispatcher.getCostVar(), cost));
_dispatcher.setFilterLevel(IlcLow);
}
// Modify graph arc cost and resolve
void RoutingSolver::restoreSolution() {
_solver.solve(_restoreSolution && _instantiateCost);
_solution.store(_solver);
_solver.out() << "Modified cost: " << _dispatcher.getTotalCost() << endl;
}
void RoutingSolver::improveWithFastGLS(IloNHood nhood,
IloInt nbOfIter,
IloGoal instantiateCost) {
nhood.reset();
_solver.out() << "Improving with first-accept GLS" << endl;
IloRoutingSolution rsol = _solution.makeClone(_env);
IloRoutingSolution best = _solution.makeClone(_env);
IloDispatcherGLS dgls(_env, 0.2);
IloGoal move = IloSingleMove(_env, rsol, nhood, dgls, instantiateCost);
move = move && IloStoreBestSolution(_env, best);
IloNumVar costVar = _dispatcher.getCostVar();
IloCouple(nhood, dgls);
for (IloInt i = 0; i < nbOfIter; i++) {
if (_solver.solve(move)) {
_solver.out() << "Cost = " << _solver.getMax(costVar) << endl;
} else {
_solver.out() << "---" << endl;
if (dgls.complete()) break;
}
}
_solver.out() << endl;
IloDecouple(nhood, dgls);
IloGoal restoreSolution = IloRestoreSolution(_env, best) && instantiateCost;
_solver.solve(restoreSolution);
_solution.store(_solver);
rsol.end();
best.end();
dgls.end();
}
// Display Dispatcher information
void RoutingSolver::printInformation() const {
_solver.printInformation();
_dispatcher.printInformation();
_solver.out() << "===============" << endl
<< "Cost : " << _dispatcher.getTotalCost() << endl
<< "Number of vehicles used : "
<< _dispatcher.getNumberOfVehiclesUsed() << endl
<< "Solution : " << endl
<< _dispatcher << endl;
}
// Solving
void RoutingSolver::improveWithNHood(IloInt nbIter) {
IloNHood nhood = IloTwoOpt(_env)
+ IloOrOpt(_env)
+ IloRelocate(_env)
+ IloExchange(_env)
+ IloCross(_env)
+ IloSwapPerform(_env);
greedyImprove(nhood, _instantiateCost);
improveWithFastGLS(nhood, nbIter, _instantiateCost);
}
void RoutingSolver::displayPaths(IloDispatcherGraph graph) {
_env.out() << "Paths" << endl;
for (IloIterator<IloVehicle> iter1(_env); iter1.ok(); ++iter1) {
IloVehicle vehicle = *iter1;
IloVisit visit1 = vehicle.getFirstVisit();
for (IloDispatcher::RouteIterator iter2(_dispatcher, vehicle);
iter2.ok();
++iter2) {
IloVisit visit2 = *iter2;
if (visit1 != visit2) {
_env.out() << visit1.getName() << " {"
<< graph.getLocation(visit1.getStartNode())
.getIndex();
for (IloDispatcherGraph::PathIterator iter3(graph,
visit1.getEndNode(),
visit2.getStartNode(),
vehicle);
iter3.ok();
++iter3) {
_env.out() << " -> " << (*iter3).getIndex();
}
_env.out() << "} -> ";
visit1 = visit2;
}
}
_env.out() << vehicle.getLastVisit().getName() << endl;
}
_env.out() << endl;
}
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char * argv[]) {
IloEnv env;
try {
RoutingModel mdl(env, argc, argv);
RoutingSolver solver(mdl);
if (solver.findFirstSolution()) {
solver.printInformation();
solver.improveWithNHood(250);
solver.modifyFilterLevelAndRestore();
solver.printInformation();
solver.displayPaths(mdl.getGraph());
mdl.modifyGraphArcCost();
solver.restoreSolution();
solver.improveWithNHood(50);
solver.modifyFilterLevelAndRestore();
solver.printInformation();
solver.displayPaths(mdl.getGraph());
}
} catch(IloException& ex) {
cerr << "Error: " << ex << endl;
}
env.end();
return 0;
}