// Copyright 2017, University of Freiburg, // Chair of Algorithms and Data Structures. // Authors: Patrick Brosi // _____________________________________________________________________________ template C EDijkstra::shortestPathImpl(Node* from, const std::set*>& to, const ShortestPath::CostFunc& costFunc, const ShortestPath::HeurFunc& heurFunc, EList* resEdges, NList* resNodes) { std::set*> frEs; std::set*> toEs; frEs.insert(from->getAdjListOut().begin(), from->getAdjListOut().end()); for (auto n : to) { toEs.insert(n->getAdjListIn().begin(), n->getAdjListIn().end()); } C cost = shortestPathImpl(frEs, toEs, costFunc, heurFunc, resEdges, resNodes); // the beginning node is not included in our edge based dijkstra if (resNodes) resNodes->push_back(from); return cost; } // _____________________________________________________________________________ template C EDijkstra::shortestPathImpl(Edge* from, const std::set*>& to, const ShortestPath::CostFunc& costFunc, const ShortestPath::HeurFunc& heurFunc, EList* resEdges, NList* resNodes) { std::set*> frEs; std::set*> toEs; frEs.insert(from); for (auto n : to) { toEs.insert(n->getAdjListIn().begin(), n->getAdjListIn().end()); } C cost = shortestPathImpl(frEs, toEs, costFunc, heurFunc, resEdges, resNodes); return cost; } // _____________________________________________________________________________ template C EDijkstra::shortestPathImpl(const std::set*> from, const std::set*>& to, const ShortestPath::CostFunc& costFunc, const ShortestPath::HeurFunc& heurFunc, EList* resEdges, NList* resNodes) { if (from.size() == 0 || to.size() == 0) return costFunc.inf(); Settled settled; PQ pq; bool found = false; // at the beginning, put all edges on the priority queue, // init them with their own cost for (auto e : from) { C c = costFunc(0, 0, e); C h = heurFunc(e, to); pq.emplace(e, (Edge*)0, (Node*)0, c, c + h); } RouteEdge cur; while (!pq.empty()) { EDijkstra::ITERS++; if (settled.find(pq.top().e) != settled.end()) { pq.pop(); continue; } cur = pq.top(); pq.pop(); settled[cur.e] = cur; if (to.find(cur.e) != to.end()) { found = true; break; } relax(cur, to, costFunc, heurFunc, pq); } if (!found) return costFunc.inf(); buildPath(cur.e, settled, resNodes, resEdges); return cur.d; } // _____________________________________________________________________________ template std::unordered_map*, C> EDijkstra::shortestPathImpl( const std::set*>& from, const ShortestPath::CostFunc& costFunc, bool rev) { std::unordered_map*, C> costs; Settled settled; PQ pq; std::set*> to; for (auto e : from) { pq.emplace(e, (Edge*)0, (Node*)0, costFunc(0, 0, e), C()); } RouteEdge cur; while (!pq.empty()) { EDijkstra::ITERS++; if (settled.find(pq.top().e) != settled.end()) { pq.pop(); continue; } cur = pq.top(); pq.pop(); settled[cur.e] = cur; costs[cur.e] = cur.d; buildPath(cur.e, settled, (NList*)0, (EList*)0); if (rev) relaxInv(cur, costFunc, pq); else relax(cur, to, costFunc, ZeroHeurFunc(), pq); } return costs; } // _____________________________________________________________________________ template std::unordered_map*, C> EDijkstra::shortestPathImpl( Edge* from, const std::set*>& to, const ShortestPath::CostFunc& costFunc, const ShortestPath::HeurFunc& heurFunc, std::unordered_map*, EList*> resEdges, std::unordered_map*, NList*> resNodes) { std::unordered_map*, C> costs; if (to.size() == 0) return costs; // init costs with inf for (auto e : to) costs[e] = costFunc.inf(); Settled settled; PQ pq; size_t found = 0; C c = costFunc(0, 0, from); C h = heurFunc(from, to); pq.emplace(from, (Edge*)0, (Node*)0, c, c + h); RouteEdge cur; while (!pq.empty()) { EDijkstra::ITERS++; if (settled.find(pq.top().e) != settled.end()) { pq.pop(); continue; } cur = pq.top(); pq.pop(); settled[cur.e] = cur; if (to.find(cur.e) != to.end()) { found++; costs[cur.e] = cur.d; buildPath(cur.e, settled, resNodes[cur.e], resEdges[cur.e]); } if (found == to.size()) return costs; relax(cur, to, costFunc, heurFunc, pq); } return costs; } // _____________________________________________________________________________ template void EDijkstra::relaxInv(RouteEdge& cur, const ShortestPath::CostFunc& costFunc, PQ& pq) { // handling undirected graph makes no sense here for (const auto edge : cur.e->getFrom()->getAdjListIn()) { if (edge == cur.e) continue; C newC = costFunc(edge, cur.e->getFrom(), cur.e); newC = cur.d + newC; if (costFunc.inf() <= newC) continue; pq.emplace(edge, cur.e, cur.e->getFrom(), newC, C()); } } // _____________________________________________________________________________ template void EDijkstra::relax(RouteEdge& cur, const std::set*>& to, const ShortestPath::CostFunc& costFunc, const ShortestPath::HeurFunc& heurFunc, PQ& pq) { if (cur.e->getFrom()->hasEdgeIn(cur.e)) { // for undirected graphs for (const auto edge : cur.e->getFrom()->getAdjListOut()) { if (edge == cur.e) continue; C newC = costFunc(cur.e, cur.e->getFrom(), edge); newC = cur.d + newC; if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); const C& newH = newC + h; pq.emplace(edge, cur.e, cur.e->getFrom(), newC, newH); } } for (const auto edge : cur.e->getTo()->getAdjListOut()) { if (edge == cur.e) continue; C newC = costFunc(cur.e, cur.e->getTo(), edge); newC = cur.d + newC; if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); const C& newH = newC + h; pq.emplace(edge, cur.e, cur.e->getTo(), newC, newH); } } // _____________________________________________________________________________ template void EDijkstra::buildPath(Edge* curE, const Settled& settled, NList* resNodes, EList* resEdges) { const RouteEdge* curEdge = &settled.find(curE)->second; if (resNodes) resNodes->push_back(curEdge->e->getOtherNd(curEdge->n)); while (true) { if (resNodes && curEdge->n) resNodes->push_back(curEdge->n); if (resEdges) resEdges->push_back(curEdge->e); if (!curEdge->parent) break; curEdge = &settled.find(curEdge->parent)->second; } }