The complete program follows. You can also view it online in the file YourDispatcherHome/examples/src/technic2_complete.cpp
.
// -------------------------------------------------------------- -*- C++ -*-
// File: examples/src/technic2.cpp
//---------------------------------------------------------------------------
#include <ildispat/ilodispatcher.h>
ILOSTLBEGIN
///////////////////////////////////////////////////////////////////////////////
// Modeling
class RoutingModel {
IloEnv _env;
IloModel _mdl;
void createDimensions();
void createIloNodes(char* nodeFileName);
void createTechnicians(char* technicianFileName);
void createVisits(char* visitsFileName);
void setVisitsSkillPenalty(char * skillCostsFileName,
char * visitSkillsFileName,
char * techSkillsFileName);
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/technic2/nodes.csv";
else
nodeFileName = argv[3];
createIloNodes(nodeFileName);
char* technicianFileName;
if (argc < 2)
technicianFileName = (char *) "../../../examples/data/technic2/technicians.csv";
else
technicianFileName = argv[1];
createTechnicians(technicianFileName);
char* visitsFileName;
if (argc < 3)
visitsFileName =
(char*) "../../../examples/data/technic2/visits.csv";
else
visitsFileName = argv[2];
createVisits(visitsFileName);
//set the correct skillPenalty for visits
char * visitSkillsFileName = (char *) "../../../examples/data/technic2/visitSkills.csv";
char * techSkillsFileName = (char *) "../../../examples/data/technic2/techSkills.csv";
char * skillCostsFileName = (char *) "../../../examples/data/technic2/skillCosts.csv";
if(argc >= 4)
visitSkillsFileName = argv[4];
if(argc >= 5) {
visitSkillsFileName = argv[4];
techSkillsFileName = argv[5];
}
if(argc >= 6) {
visitSkillsFileName = argv[4];
techSkillsFileName = argv[5];
skillCostsFileName = argv[6];
}
setVisitsSkillPenalty(skillCostsFileName, visitSkillsFileName, techSkillsFileName);
}
// Add dimensions
void RoutingModel::createDimensions() {
IloDimension1 skillPenalty(_env, IloFalse, "SkillPenalty");
_mdl.add(skillPenalty);
skillPenalty.setKey("SkillPenalty");
IloDimension2 time(_env, IloEuclidean, "Time");
time.setKey("Time");
_mdl.add(time);
}
// 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 technicians
void RoutingModel::createTechnicians(char* techFileName) {
IloDimension2 time = IloDimension2::Find(_env, "Time");
IloDimension1 skillPenalty = IloDimension1::Find(_env, "SkillPenalty");
IloCsvReader csvTechReader(_env, techFileName);
IloCsvReader::LineIterator it(csvTechReader);
while(it.ok()) {
IloCsvLine line = *it;
char * namefirst = line.getStringByHeader("first");
char * namelast = line.getStringByHeader("last");
char * name = line.getStringByHeader("name");
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.getTransitVar(skillPenalty) == 0);
_mdl.add(first.getCumulVar(time) >= openTime);
IloVisit last(node2, "depot");
_mdl.add(last.getCumulVar(time) <= closeTime);
_mdl.add(last.getTransitVar(skillPenalty) == 0);
IloVehicle technician(first, last, name);
technician.setCost(time, 1.0);
technician.setCost(skillPenalty, 1.0);
technician.setKey(name);
_mdl.add(technician);
++it;
}
csvTechReader.end();
}
// Create visits
void RoutingModel::createVisits(char* visitsFileName) {
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 * visitName = line.getStringByHeader("name");
char * nodeName = line.getStringByHeader("node");
IloNum minTime = line.getFloatByHeader("minTime");
IloNum maxTime = line.getFloatByHeader("maxTime");
IloNum dropTime = line.getFloatByHeader("dropTime");
IloNode node = IloNode::Find(_env, nodeName);
IloVisit visit(node, visitName);
_mdl.add(visit.getDelayVar(time) == dropTime);
_mdl.add(minTime <= visit.getCumulVar(time) <= maxTime);
visit.setKey(visitName);
_mdl.add(visit);
++it;
}
csvVisitReader.end();
}
//set the correct skillPenalty for visits
void RoutingModel::setVisitsSkillPenalty(char * skillCostsFileName,
char * visitSkillsFileName,
char * techSkillsFileName) {
IloDimension1 skillPenalty = IloDimension1::Find(_env, "SkillPenalty");
IloCsvReader csvVisitSkillsReader(_env, visitSkillsFileName);
IloCsvReader csvTechSkillsReader(_env, techSkillsFileName);
IloCsvReader csvSkillCostsReader(_env, skillCostsFileName);
IloInt nbOfTech = csvTechSkillsReader.getNumberOfItems();
IloVehicleArray techs(_env, nbOfTech);
IloInt i = 0;
IloCsvReader::LineIterator it(csvTechSkillsReader);
while(it.ok()){
IloCsvLine line = *it;
char * techName = line.getStringByHeader("name");
IloVehicle technician = IloVehicle::Find(_env, techName);
techs[i] = technician;
i++;
++it;
}
IloCsvReader::LineIterator it2(csvVisitSkillsReader);
while(it2.ok()){
IloCsvLine line = *it2;
char * visitName = line.getStringByHeader("name");
IloVisit visit = IloVisit::Find(_env, visitName);
char * visitSkillName = line.getStringByHeader("VisitSkillName");
IloCsvLine costline = csvSkillCostsReader.getLineByKey(1, visitSkillName);
IloNumArray visitCost(_env, nbOfTech);
IloInt k = 0;
IloCsvReader::LineIterator it3(csvTechSkillsReader);
while(it3.ok()){
IloCsvLine line1 = *it3;
char * techSkillName = line1.getStringByHeader("TechSkillName");
visitCost[k] = costline.getFloatByHeader(techSkillName);
k++;
++it3;
}
IloVehicleToNumFunction function(_env, techs, visitCost);
IloNumVar skillCostVar (function(visit.getVehicleVar()));
_mdl.add(visit.getTransitVar(skillPenalty) == skillCostVar);
++it2;
}
csvVisitSkillsReader.end();
csvTechSkillsReader.end();
csvSkillCostsReader.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;
}
// 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 = IloInsertionGenerate(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;
}