// 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 util::graph::CostFunc& costFunc, const util::graph::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 util::graph::CostFunc& costFunc, const util::graph::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 util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, EList* resEdges, NList* resNodes) { std::set*> frEs; std::set*> toEs; for (auto n : from) { frEs.insert(n->getAdjListIn().begin(), n->getAdjListIn().end()); } 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 util::graph::CostFunc& costFunc, const util::graph::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.push(c + h, {e, (Edge*)0, (Node*)0, c}); } RouteEdge cur; while (!pq.empty()) { if (costFunc.inf() <= pq.topKey()) return costFunc.inf(); auto se = settled.find(pq.topVal().e); if (se != settled.end()) { // to allow non-consistent heuristics if (se->second.d <= pq.topVal().d) { pq.pop(); continue; } } EDijkstra::ITERS++; cur = pq.topVal(); 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 util::graph::CostFunc& costFunc, bool rev) { std::unordered_map*, C> costs; Settled settled; PQ pq; std::set*> to; for (auto e : from) { pq.push(C(), {e, (Edge*)0, (Node*)0, costFunc(0, 0, e)}); } RouteEdge cur; while (!pq.empty()) { auto se = settled.find(pq.topVal().e); if (se != settled.end()) { // to allow non-consistent heuristics if (se->second.d <= pq.topVal().d) { pq.pop(); continue; } } EDijkstra::ITERS++; cur = pq.topVal(); 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 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 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.push(c + h, {from, (Edge*)0, (Node*)0, c}); RouteEdge cur; while (!pq.empty()) { if (costFunc.inf() <= pq.topKey()) return costs; auto se = settled.find(pq.topVal().e); if (se != settled.end()) { // to allow non-consistent heuristics if (se->second.d <= pq.topVal().d) { pq.pop(); continue; } } EDijkstra::ITERS++; cur = pq.topVal(); 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 std::unordered_map*, C> EDijkstra::shortestPathImpl( const std::set*>& from, const std::set*>& to, const std::unordered_map*, C>& initCosts, C stall, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, std::unordered_map*, EList*> resEdges, std::unordered_map*, NList*> resNodes) { /** * Shortest paths from the set to ALL nodes in , but * init nodes with costs (this is equivalent to adding an auxiliary * node S, connecting it with directed edges to all , setting the * costs of these edges to the initial costs and run a 1->N Dijkstra from S **/ std::unordered_map*, C> costs; if (to.size() == 0) return costs; // init costs with inf for (auto e : to) costs[e] = costFunc.inf(); SettledInit settled; PQInit pq; size_t found = 0; // put all nodes in from onto the PQ with their initial costs, also set // the initial cost as a heuristic starting point! for (auto e : from) { C iCost = initCosts.find(e)->second; assert(iCost + heurFunc(e, to) >= iCost); pq.push(iCost + heurFunc(e, to), {e, (Edge*)0, (Node*)0, iCost}); } RouteEdgeInit cur; while (!pq.empty()) { if (costFunc.inf() <= pq.topKey()) return costs; if (stall <= pq.topVal().dwi) return costs; auto se = settled.find(pq.topVal().e); if (se != settled.end()) { // to allow non-consistent heuristics if (se->second.d <= pq.topVal().d) { pq.pop(); continue; } } EDijkstra::ITERS++; cur = pq.topVal(); pq.pop(); settled[cur.e] = cur; if (to.find(cur.e) != to.end()) { found++; costs[cur.e] = cur.d; buildPathInit(cur.e, settled, resNodes[cur.e], resEdges[cur.e]); if (found == to.size()) return costs; } relaxInit(cur, to, stall, costFunc, heurFunc, pq); } return costs; } // _____________________________________________________________________________ template std::unordered_map*, std::pair*, C>> EDijkstra::shortestPathImpl(const std::set*>& from, const std::set*>& to, const std::unordered_map*, C>& initCosts, C stall, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc) { /** * Shortest paths from the set to ALL nodes in , but * init nodes with costs (this is equivalent to adding an auxiliary * node S, connecting it with directed edges to all , setting the * costs of these edges to the initial costs and run a 1->N Dijkstra from S **/ std::unordered_map*, std::pair*, C>> costs; if (to.size() == 0) return costs; // init costs with inf for (auto e : to) costs[e] = {0, costFunc.inf()}; SettledInitNoRes settled; PQInitNoRes pq; size_t found = 0; // put all nodes in from onto the PQ with their initial costs, also set // the initial cost as a heuristic starting point! // set the parent to the edge itself - in this version, the parent is ALWAYS // the start edge, as we don't need the exact paths later on for (auto e : from) { C iCost = initCosts.find(e)->second; assert(iCost + heurFunc(e, to) >= iCost); pq.push(iCost + heurFunc(e, to), {e, e, iCost}); } RouteEdgeInitNoRes cur; while (!pq.empty()) { if (costFunc.inf() <= pq.topKey()) return costs; if (stall <= pq.topVal().dwi) return costs; auto se = settled.find(pq.topVal().e); if (se != settled.end()) { // to allow non-consistent heuristics if (se->second.d <= pq.topVal().d) { pq.pop(); continue; } } EDijkstra::ITERS++; cur = pq.topVal(); pq.pop(); settled[cur.e] = cur; if (to.find(cur.e) != to.end()) { found++; costs[cur.e] = {cur.parent, cur.d}; if (found == to.size()) return costs; } relaxInitNoResEdgs(cur, to, stall, costFunc, heurFunc, pq); } return costs; } // _____________________________________________________________________________ template void EDijkstra::relaxInv(RouteEdge& cur, const util::graph::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; if (newC < cur.d) continue; // cost overflow! pq.push(C(), {edge, cur.e, cur.e->getFrom(), newC}); } } // _____________________________________________________________________________ template void EDijkstra::relaxInitNoResEdgs( RouteEdgeInitNoRes& cur, const std::set*>& to, C stall, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, PQInitNoRes& pq) { if (cur.e->getFrom()->hasEdgeIn(cur.e) && cur.e->getFrom() != cur.e->getTo()) { // 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); C newDwi = cur.dwi + newC; if (stall <= newDwi) continue; if (costFunc.inf() <= newC) continue; newC = cur.d + newC; if (newC < cur.d) continue; // cost overflow! if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); if (costFunc.inf() <= h) continue; newC = cur.d + newC; const C& newH = newC + h; if (newH < newC) continue; // cost overflow! pq.push(newH, {edge, cur.parent, newC, newDwi}); } } for (const auto edge : cur.e->getTo()->getAdjListOut()) { if (edge == cur.e) continue; C newC = costFunc(cur.e, cur.e->getTo(), edge); C newDwi = cur.dwi + newC; if (stall <= newDwi) continue; if (costFunc.inf() <= newC) continue; newC = cur.d + newC; if (newC < cur.d) continue; // cost overflow! if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); if (costFunc.inf() <= h) continue; const C& newH = newC + h; if (newH < newC) continue; // cost overflow! pq.push(newH, {edge, cur.parent, newC, newDwi}); } } // _____________________________________________________________________________ template void EDijkstra::relaxInit(RouteEdgeInit& cur, const std::set*>& to, C stall, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, PQInit& pq) { if (cur.e->getFrom()->hasEdgeIn(cur.e) && cur.e->getFrom() != cur.e->getTo()) { // 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); C newDwi = cur.dwi + newC; if (stall <= newDwi) continue; if (costFunc.inf() <= newC) continue; newC = cur.d + newC; if (newC < cur.d) continue; // cost overflow! if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); if (costFunc.inf() <= h) continue; newC = cur.d + newC; const C& newH = newC + h; if (newH < newC) continue; // cost overflow! pq.push(newH, {edge, cur.e, cur.e->getFrom(), newC, newDwi}); } } for (const auto edge : cur.e->getTo()->getAdjListOut()) { if (edge == cur.e) continue; C newC = costFunc(cur.e, cur.e->getTo(), edge); C newDwi = cur.dwi + newC; if (stall <= newDwi) continue; if (costFunc.inf() <= newC) continue; newC = cur.d + newC; if (newC < cur.d) continue; // cost overflow! if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); if (costFunc.inf() <= h) continue; const C& newH = newC + h; if (newH < newC) continue; // cost overflow! pq.push(newH, {edge, cur.e, cur.e->getTo(), newC, newDwi}); } } // _____________________________________________________________________________ template void EDijkstra::relax(RouteEdge& cur, const std::set*>& to, const util::graph::CostFunc& costFunc, const util::graph::HeurFunc& heurFunc, PQ& pq) { if (cur.e->getFrom()->hasEdgeIn(cur.e) && cur.e->getFrom() != cur.e->getTo()) { // 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); if (costFunc.inf() <= newC) continue; newC = cur.d + newC; if (newC < cur.d) continue; // cost overflow! if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); if (costFunc.inf() <= h) continue; const C& newH = newC + h; if (newH < newC) continue; // cost overflow! pq.push(newH, {edge, cur.e, cur.e->getFrom(), newC}); } } for (const auto edge : cur.e->getTo()->getAdjListOut()) { if (edge == cur.e) continue; C newC = costFunc(cur.e, cur.e->getTo(), edge); if (costFunc.inf() <= newC) continue; newC = cur.d + newC; if (newC < cur.d) continue; // cost overflow! if (costFunc.inf() <= newC) continue; const C& h = heurFunc(edge, to); if (costFunc.inf() <= h) continue; const C& newH = newC + h; if (newH < newC) continue; // cost overflow! pq.push(newH, {edge, cur.e, cur.e->getTo(), newC}); } } // _____________________________________________________________________________ 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 (resNodes || resEdges) { 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; } } // _____________________________________________________________________________ template void EDijkstra::buildPathInit(Edge* curE, const SettledInit& settled, NList* resNodes, EList* resEdges) { const RouteEdgeInit* curEdge = &settled.find(curE)->second; if (resNodes) resNodes->push_back(curEdge->e->getOtherNd(curEdge->n)); while (resNodes || resEdges) { 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; } }