#pragma once
#include <config.h>
#include <cassert>
#include <string>
#include <functional>
#include <vector>
#include <set>
#include <limits>
#include <algorithm>
#include <iterator>
#include <map>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <cstddef>
#include <utils/common/MsgHandler.h>
#include <utils/common/StringTokenizer.h>
#include <utils/common/StringUtils.h>
#include <utils/common/StdDefs.h>
#include <utils/common/ToString.h>
#include <utils/iodevices/OutputDevice.h>
#include <utils/common/SUMOTime.h>
#include "SUMOAbstractRouter.h"
#include "KDTreePartition.h"
#include "AFInfo.h"
template<class E, class N, class V>
class AFCentralizedSPTree {
public:
typedef typename KDTreePartition<E, N, V>::Cell Cell;
typedef typename AFInfo<E>::ArcInfo ArcInfo;
class EdgeInfoComparator {
public:
EdgeInfoComparator(std::vector<ArcInfo*>& arcInfos) : myArcInfos(arcInfos) {
}
bool operator()(const typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo1,
const typename SUMOAbstractRouter<E, V>::EdgeInfo* edgeInfo2) const {
int index1 = edgeInfo1->edge->getNumericalID();
int index2 = edgeInfo2->edge->getNumericalID();
ArcInfo* arcInfo1 = myArcInfos[index1];
ArcInfo* arcInfo2 = myArcInfos[index2];
double key1 = arcInfo1->key;
double key2 = arcInfo2->key;
if (key1 == key2) {
return index1 > index2;
}
return key1 > key2;
}
private:
std::vector<ArcInfo*>& myArcInfos;
};
AFCentralizedSPTree(const std::vector<E*>& edges, std::vector<ArcInfo*>& arcInfos, bool unbuildIsWarning,
SUMOAbstractRouter<E, V>* effortProvider,
const bool havePermissions = false, const bool haveRestrictions = false) :
myArcInfos(arcInfos),
myHavePermissions(havePermissions),
myHaveRestrictions(haveRestrictions),
myErrorMsgHandler(unbuildIsWarning ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
myEffortProvider(effortProvider),
myMaxSpeed(NUMERICAL_EPS) {
for (const E* const edge : edges) {
myEdgeInfos.push_back(typename SUMOAbstractRouter<E, V>::EdgeInfo(edge));
myMaxSpeed = MAX2(myMaxSpeed, edge->getSpeedLimit() * MAX2(1.0, edge->getLengthGeometryFactor()));
}
myComparator = new EdgeInfoComparator(myArcInfos);
}
~AFCentralizedSPTree() {
delete myComparator;
}
bool isProhibited(const E* const edge, const V* const vehicle) const {
return (myHavePermissions && edge->prohibits(vehicle)) || (myHaveRestrictions && edge->restricts(vehicle));
}
bool computeCentralizedSPTree(SUMOTime msTime, const Cell* cell, const V* const vehicle,
const std::map<const E*, std::vector<const E*>>& incomingEdgesOfOutgoingBoundaryEdges,
bool silent = false) {
assert(cell != nullptr);
const std::unordered_set<const E*>& fromEdges = cell->getOutgoingBoundaryEdges();
if (fromEdges.empty()) {
return false;
}
double length = 0.;
const SUMOVehicleClass vClass = vehicle == 0 ? SVC_IGNORING : vehicle->getVClass();
std::vector<const E*> fromEdgesAsVector(fromEdges.begin(), fromEdges.end());
init(fromEdgesAsVector, vehicle, msTime);
size_t numberOfVisitedFromEdges = 0;
bool minIsFromEdge = false;
#ifdef CSPT_DEBUG_LEVEL_0
size_t numberOfTouchedSupercellEdges = 0;
int num_visited = 0;
#endif
#ifdef _DEBUG
const Cell* supercell = cell->getSupercell();
#endif
const bool mayRevisit = true;
while (!myFrontierList.empty()) {
#ifdef CSPT_DEBUG_LEVEL_0
num_visited += 1;
#endif
typename SUMOAbstractRouter<E, V>::EdgeInfo* minimumInfo = myFrontierList.front();
const E* const minEdge = minimumInfo->edge;
assert(!minEdge->isInternal());
ArcInfo* minimumArcInfo = myArcInfos[minEdge->getNumericalID()];
if (minimumInfo->visited || numberOfVisitedFromEdges < fromEdges.size()) {
minIsFromEdge = incomingEdgesOfOutgoingBoundaryEdges.find(minEdge) != incomingEdgesOfOutgoingBoundaryEdges.end();
} else {
minIsFromEdge = false;
}
if (minIsFromEdge) {
if (numberOfVisitedFromEdges < fromEdges.size()) {
numberOfVisitedFromEdges++;
}
}
assert(incomingEdgesOfOutgoingBoundaryEdges.size() == fromEdges.size());
assert(minimumArcInfo->key != std::numeric_limits<double>::max() && minimumArcInfo->key != UNREACHABLE);
size_t index;
#ifdef CSPT_DEBUG_LEVEL_0
if (supercell->contains(minEdge->getToJunction())) {
if (!minimumArcInfo->touched) {
numberOfTouchedSupercellEdges++;
minimumArcInfo->touched = true;
}
}
#endif
#ifdef CSPT_DEBUG_LEVEL_0
if (num_visited % 500 == 0) {
std::cout << "num_visited: " << num_visited << ", numberOfTouchedSupercellEdges: " << numberOfTouchedSupercellEdges
<< ", minimumArcInfo->key: " << minimumArcInfo->key << std::endl;
}
#endif
std::pop_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
myFrontierList.pop_back();
myFound.push_back(minimumInfo);
minimumInfo->visited = true;
const double effortDelta = myEffortProvider->getEffort(minEdge, vehicle, minimumInfo->leaveTime);
const double leaveTime = minimumInfo->leaveTime + myEffortProvider->getTravelTime(minEdge, vehicle, minimumInfo->leaveTime, effortDelta);
for (const std::pair<const E*, const E*>& follower : minEdge->getViaSuccessors(vClass)) {
assert(!follower.first->isInternal());
bool wasPushedToHeap = false;
auto& followerInfo = myEdgeInfos[follower.first->getNumericalID()];
ArcInfo* followerArcInfo = myArcInfos[follower.first->getNumericalID()];
if (followerInfo.prohibited || isProhibited(follower.first, vehicle)) {
if (!silent) {
myErrorMsgHandler->inform("Vehicle '" + Named::getIDSecure(vehicle) + "' is not allowed on source edge '" + followerInfo.edge->getID() + "'.");
}
continue;
}
if (followerArcInfo->effortsToBoundaryNodes.empty()) {
assert(!supercell->contains(follower.first->getToJunction()));
std::fill_n(std::back_inserter(followerArcInfo->effortsToBoundaryNodes),
minimumArcInfo->effortsToBoundaryNodes.size(), std::numeric_limits<double>::max());
}
double key = std::numeric_limits<double>::max();
assert(followerArcInfo->effortsToBoundaryNodes.size() == minimumArcInfo->effortsToBoundaryNodes.size());
bool hasImproved = false;
for (index = 0; index < followerArcInfo->effortsToBoundaryNodes.size(); index++) {
if (minIsFromEdge && (incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index]) {
assert((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge)).size()
== followerArcInfo->effortsToBoundaryNodes.size());
const std::vector<std::pair<const E*, const E*>>& followersOfIncomingEdge
= ((incomingEdgesOfOutgoingBoundaryEdges.at(minEdge))[index])->getViaSuccessors(vClass);
bool turningAllowed = false;
for (std::pair<const E*, const E*> followerOfIncomingEdge : followersOfIncomingEdge) {
if (follower.first == followerOfIncomingEdge.first) {
turningAllowed = true;
break;
}
}
if (!turningAllowed) {
continue;
}
}
double effortToFollower = minimumArcInfo->effortsToBoundaryNodes[index] == UNREACHABLE ?
UNREACHABLE : minimumArcInfo->effortsToBoundaryNodes[index] + effortDelta;
if (effortToFollower == UNREACHABLE) {
continue;
}
double time = leaveTime;
myEffortProvider->updateViaEdgeCost(follower.second, vehicle, time, effortToFollower, length);
if (effortToFollower < key) {
key = effortToFollower;
}
const double oldEffort = followerArcInfo->effortsToBoundaryNodes[index];
if (oldEffort != std::numeric_limits<double>::max()) {
wasPushedToHeap = true;
}
if ((!followerInfo.visited || mayRevisit)
&& effortToFollower < oldEffort) {
hasImproved = true;
followerArcInfo->effortsToBoundaryNodes[index] = effortToFollower;
}
}
if (!hasImproved) {
continue;
}
followerArcInfo->key = key;
if (!wasPushedToHeap) {
myFrontierList.push_back(&followerInfo);
std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
} else {
auto fi = std::find(myFrontierList.begin(), myFrontierList.end(), &followerInfo);
if (fi == myFrontierList.end()) {
assert(mayRevisit);
myFrontierList.push_back(&followerInfo);
std::push_heap(myFrontierList.begin(), myFrontierList.end(), *myComparator);
} else {
std::push_heap(myFrontierList.begin(), fi + 1, *myComparator);
}
}
}
}
#ifdef CSPT_DEBUG_LEVEL_0
std::cout << "centralizedSPTree finished (queue empty)." << std::endl;
#endif
return true;
}
protected:
void init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime);
std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFrontierList;
std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo*> myFound;
std::vector<typename SUMOAbstractRouter<E, V>::EdgeInfo> myEdgeInfos;
std::vector<ArcInfo*>& myArcInfos;
const bool myHavePermissions;
const bool myHaveRestrictions;
MsgHandler* const myErrorMsgHandler;
SUMOAbstractRouter<E, V>* myEffortProvider;
EdgeInfoComparator* myComparator;
double myMaxSpeed;
};
template<class E, class N, class V>
void AFCentralizedSPTree<E, N, V>::init(std::vector<const E*> fromEdges, const V* const vehicle, SUMOTime msTime) {
for (auto& edgeInfo : myFrontierList) {
edgeInfo->reset();
}
myFrontierList.clear();
for (auto& edgeInfo : myFound) {
edgeInfo->reset();
}
for (auto& arcInfo : myArcInfos) {
arcInfo->reset();
}
myFound.clear();
for (const E* from : fromEdges) {
if (from->isInternal()) {
continue;
}
int edgeID = from->getNumericalID();
auto& fromInfo = myEdgeInfos[edgeID];
if (fromInfo.prohibited || isProhibited(from, vehicle)) {
continue;
}
fromInfo.heuristicEffort = 0.;
fromInfo.prev = nullptr;
fromInfo.leaveTime = STEPS2TIME(msTime);
myFrontierList.push_back(&fromInfo);
ArcInfo* fromArcInfo = myArcInfos[edgeID];
fromArcInfo->key = 0;
}
}