// Copyright 2017, University of Freiburg, // Chair of Algorithms and Data Structures. // Authors: Patrick Brosi // _____________________________________________________________________________ template C Dijkstra::shortestPathImpl(Node* from, const std::set*>& to, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, EList* resEdges, NList* resNodes) { if (from->getOutDeg() == 0) return costFunc.inf(); Settled settled; PQ pq; bool found = false; pq.emplace(from); RouteNode cur; while (!pq.empty()) { if (costFunc.inf() <= pq.top().h) return costFunc.inf(); if (settled.find(pq.top().n) != settled.end()) { pq.pop(); continue; } Dijkstra::ITERS++; cur = pq.top(); pq.pop(); settled[cur.n] = cur; if (to.find(cur.n) != to.end()) { found = true; break; } relax(cur, to, costFunc, heurFunc, pq); } if (!found) return costFunc.inf(); buildPath(cur.n, settled, resNodes, resEdges); return cur.d; } // _____________________________________________________________________________ template C Dijkstra::shortestPathImpl(const std::set*> from, const std::set*>& to, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, EList* resEdges, NList* resNodes) { Settled settled; PQ pq; bool found = false; // put all nodes in from onto PQ for (auto n : from) pq.emplace(n); RouteNode cur; while (!pq.empty()) { if (costFunc.inf() <= pq.top().h) return costFunc.inf(); auto se = settled.find(pq.top().n); if (se != settled.end()) { // to allow non-consistent heuristics if (se->second.d <= pq.top().d) { pq.pop(); continue; } } Dijkstra::ITERS++; cur = pq.top(); pq.pop(); settled[cur.n] = cur; if (to.find(cur.n) != to.end()) { found = true; break; } relax(cur, to, costFunc, heurFunc, pq); } if (!found) return costFunc.inf(); buildPath(cur.n, settled, resNodes, resEdges); return cur.d; } // _____________________________________________________________________________ template std::unordered_map*, C> Dijkstra::shortestPathImpl( Node* from, const std::set*>& to, const util::graph::CostFunc& costFunc, const util::graph::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 n : to) costs[n] = costFunc.inf(); if (from->getOutDeg() == 0) return costs; Settled settled; PQ pq; size_t found = 0; pq.emplace(from); RouteNode cur; while (!pq.empty()) { if (costFunc.inf() <= pq.top().h) return costs; auto se = settled.find(pq.top().n); if (se != settled.end()) { // to allow non-consistent heuristics if (se->second.d <= pq.top().d) { pq.pop(); continue; } } Dijkstra::ITERS++; cur = pq.top(); pq.pop(); settled[cur.n] = cur; if (to.find(cur.n) != to.end()) { found++; } if (found == to.size()) break; relax(cur, to, costFunc, heurFunc, pq); } for (auto nto : to) { if (!settled.count(nto)) continue; Node* curN = nto; costs[nto] = settled[curN].d; buildPath(nto, settled, resNodes[nto], resEdges[nto]); } return costs; } // _____________________________________________________________________________ template void Dijkstra::relax(RouteNode& cur, const std::set*>& to, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, PQ& pq) { for (auto edge : cur.n->getAdjListOut()) { C newC = costFunc(cur.n, edge, edge->getOtherNd(cur.n)); newC = cur.d + newC; if (newC < cur.d) continue; // cost overflow! if (costFunc.inf() <= newC) continue; // addition done here to avoid it in the PQ auto h = heurFunc(edge->getOtherNd(cur.n), to); if (costFunc.inf() <= h) continue; const C& newH = newC + h; if (newH < newC) continue; // cost overflow! pq.emplace(edge->getOtherNd(cur.n), cur.n, newC, newH); } } // _____________________________________________________________________________ template void Dijkstra::buildPath(Node* curN, Settled& settled, NList* resNodes, EList* resEdges) { while (resNodes || resEdges) { const RouteNode& curNode = settled[curN]; if (resNodes) resNodes->push_back(curNode.n); if (!curNode.parent) break; if (resEdges) { for (auto e : curNode.n->getAdjListIn()) { if (e->getOtherNd(curNode.n) == curNode.parent) resEdges->push_back(e); } } curN = curNode.parent; } }