#pragma once
#include <config.h>
#include <string>
#include <functional>
#include <vector>
#include <set>
#include <limits>
#include <algorithm>
#include <iterator>
#include <utils/common/MsgHandler.h>
#include <utils/common/StdDefs.h>
template<class E, class C>
class SPTree {
public:
typedef std::vector<C> CHConnections;
typedef std::pair<const C*, const C*> CHConnectionPair;
typedef std::vector<CHConnectionPair> CHConnectionPairs;
class EdgeByTTComparator {
public:
bool operator()(const E* a, const E* b) const {
if (a->traveltime == b->traveltime) {
return a->edge->getNumericalID() > b->edge->getNumericalID();
}
return a->traveltime > b->traveltime;
}
};
SPTree(int maxDepth, bool validatePermissions) :
myMaxDepth(maxDepth),
myValidatePermissions(validatePermissions) {
}
void init() {
for (typename std::vector<E*>::iterator i = myFrontier.begin(); i != myFrontier.end(); i++) {
(*i)->reset();
}
myFrontier.clear();
for (typename std::vector<E*>::iterator i = myFound.begin(); i != myFound.end(); i++) {
(*i)->reset();
}
myFound.clear();
}
void rebuildFrom(E* start, const E* excluded) {
init();
start->traveltime = 0;
start->depth = 0;
start->permissions = start->edge->getPermissions();
myFrontier.push_back(start);
while (!myFrontier.empty()) {
E* min = myFrontier.front();
std::pop_heap(myFrontier.begin(), myFrontier.end(), myCmp);
myFrontier.pop_back();
myFound.push_back(min);
min->visited = true;
if (min->depth < myMaxDepth) {
for (typename CHConnections::iterator it = min->followers.begin(); it != min->followers.end(); it++) {
C& con = *it;
E* follower = con.target;
if (follower == excluded) {
continue;
}
const double traveltime = min->traveltime + con.cost;
const double oldTraveltime = follower->traveltime;
if (!follower->visited && traveltime < oldTraveltime) {
follower->traveltime = traveltime;
follower->depth = min->depth + 1;
follower->permissions = (min->permissions & con.permissions);
if (oldTraveltime == std::numeric_limits<double>::max()) {
myFrontier.push_back(follower);
std::push_heap(myFrontier.begin(), myFrontier.end(), myCmp);
} else {
std::push_heap(myFrontier.begin(),
std::find(myFrontier.begin(), myFrontier.end(), follower) + 1,
myCmp);
}
}
}
}
}
}
inline bool validatePermissions() {
return myValidatePermissions;
}
void registerForValidation(const C* aInfo, const C* fInfo) {
assert(myValidatePermissions);
myShortcutsToValidate.push_back(CHConnectionPair(aInfo, fInfo));
}
const CHConnectionPairs& getNeededShortcuts(const E* excluded) {
assert(myValidatePermissions);
myNeededShortcuts.clear();
for (typename CHConnectionPairs::iterator it = myShortcutsToValidate.begin(); it != myShortcutsToValidate.end(); ++it) {
const C* const aInfo = it->first;
const C* const fInfo = it->second;
const double bestWitness = dijkstraTT(
aInfo->target, fInfo->target, excluded, (aInfo->permissions & fInfo->permissions));
const double viaCost = aInfo->cost + fInfo->cost;
if (viaCost < bestWitness) {
myNeededShortcuts.push_back(*it);
}
}
myShortcutsToValidate.clear();
return myNeededShortcuts;
}
private:
double dijkstraTT(E* start, E* dest, const E* excluded, SVCPermissions permissions) {
init();
start->traveltime = 0;
start->depth = 0;
myFrontier.push_back(start);
while (!myFrontier.empty()) {
E* min = myFrontier.front();
if (min == dest) {
return dest->traveltime;
}
std::pop_heap(myFrontier.begin(), myFrontier.end(), myCmp);
myFrontier.pop_back();
myFound.push_back(min);
min->visited = true;
if (min->depth < myMaxDepth) {
for (typename CHConnections::iterator it = min->followers.begin(); it != min->followers.end(); it++) {
C& con = *it;
E* follower = con.target;
if (follower == excluded) {
continue;
}
if ((con.permissions & permissions) != permissions) {
continue;
}
const double traveltime = min->traveltime + con.cost;
const double oldTraveltime = follower->traveltime;
if (!follower->visited && traveltime < oldTraveltime) {
follower->traveltime = traveltime;
follower->depth = min->depth + 1;
follower->permissions = (min->permissions & con.permissions);
if (oldTraveltime == std::numeric_limits<double>::max()) {
myFrontier.push_back(follower);
std::push_heap(myFrontier.begin(), myFrontier.end(), myCmp);
} else {
std::push_heap(myFrontier.begin(),
std::find(myFrontier.begin(), myFrontier.end(), follower) + 1,
myCmp);
}
}
}
}
}
return dest->traveltime;
}
void debugPrintVector(std::vector<E*>& vec, E* start, const E* excluded) {
std::cout << "computed SPT from '" << start->edge->getID() << "' (excluding " << excluded->edge->getID() << ") with " << myFound.size() << " edges\n";
for (typename std::vector<E*>::iterator it = vec.begin(); it != vec.end(); it++) {
E* e = *it;
std::cout << "(" << e->edge->getID() << "," << e->traveltime << ") ";
}
std::cout << "\n";
}
std::vector<E*> myFrontier;
std::vector<E*> myFound;
EdgeByTTComparator myCmp;
int myMaxDepth;
bool myValidatePermissions;
CHConnectionPairs myShortcutsToValidate;
CHConnectionPairs myNeededShortcuts;
};