Kortste Paden Algoritmiek
Toepassingen Kevin Bacon getal Six degrees of separation Heeft een netwerk de small-world eigenschap? TomTom / Google Maps Algoritmiek
Kortste paden Gerichte graaf G=(N,A), en een lengte L(v,w) voor elke pijl (v,w) in A. Knopen x, y in N. Probleem: gegeven G, L, x, y, wat is de afstand van x naar y? Wat is het kortste pad? Afstand: som van pijl-lengtes d(x,y) 4 c x 3 3 5 a d 3 2 1 b 1 y Algoritmiek
Over de definitie Ongerichte grafen Vervang elke kant door twee pijlen en los probleem op gerichte graaf op Negatieve pijl-lengtes vaak nuttig Sommige algoritmes werken alleen als alle lengtes niet-negatief zijn Bij negatieve lengtes kunnen er negatieve cycles zijn: kortste pad hoeft niet goed gedefinieerd te zijn dan… Algoritmiek
Versies All pairs shortest paths Bereken voor alle paren knopen v, w de kortste afstand van v naar w Single source shortest paths Gegeven knoop v, bereken voor elke knoop w de kortste afstand van v naar w Single target shortest paths Gegeven knoop w, bereken voor elke knoop v de kortste afstand van v naar w Single pair shortest path Gegeven knopen v en w, bereken de kortste afstand van v naar w. Algoritmiek
Vandaag Single Source Shortest Path Dijkstra’s algoritme Bellman-Ford All-Pairs Shortest Path Floyd-Warshall Dinsdag: verder met APSP Johnson’s algoritme Algoritmiek
Single source algoritmen Een startknoop s: wat is de afstand van s naar v, voor elke andere knoop v? Twee algoritmes: Dijkstra: sneller, alleen bij niet-negatieve pijl-lengtes Bellman-Ford: trager, werkt ook bij negatieve pijl-lengtes Maar niet bij negatieve cycles Beide gebruiken zelfde principe Algoritmiek
Algemeen principe: relaxatie Elke knoop heeft een waarde D[v]: een schatting van de afstand d(s,v): Initieel: D[s]= 0; voor alle andere v: D[v] = ¥ Invariant van het algoritme: D[v] >= d(s,v) Idee: Relaxatie verlaagt de schattingen terwijl we wel de invariant in stand houden Algoritmiek
Relaxatie We bekijken de mogelijkheid dat het kortste pad van s naar w via v en de pijl (v,w) gaat Relax (v,w) { (v,w) is een pijl in G} If D[w] > D[v] + L(v,w) Then D[w] = D[v]+ L(v,w) Behoudt invariant pad via v is maar 1 van de mogelijke paden, dus kortste pad is korter v w s Algoritmiek
Algemeen principe: subpad optimaliteit Stel v0, v1, ..., vk is een kortste pad van v0 naar vk Dan voor iedere i < j, vi ... vj is een kortste pad van vi naar vj Als dit een kortste pad is, dan kan ik nergens afsnijden v0 v1 vi vj vk-1 vk Algoritmiek
Dijkstra’s algoritme Algoritmiek
Dijkstra’s algoritme: De Wolk Bouw langzaam een verzameling knopen u waarvoor we zeker weten dat D[u] = d(s,u) De Wolk W Greedy algoritme voegt in iedere stap knoop toe aan De Wolk Maar welke knoop? s W Algoritmiek
Initialisatie D[s] = 0; W = {s}; For alle knopen w do D[w] = ¥ For alle pijlen (s,u) do D[u] = L(s,u); Algoritmiek
Greedy Loop While W ≠ N do Kies een element v uit N-W waarvoor D[v] minimaal is t.o.v. de andere elementen uit N-W Stop v in W For alle pijlen (v,u) met u in N-W do If D[u] > D[v] + L(v,u) then D[u] = D[v] + L(v,u) We gaan bewijzen dat voor deze v D[v] = d(s,v) Let op: we nemen v als minimum D, daarom werkt het algoritme Relax: we moeten kijken of het kortste pad van s naar u via v loopt Relax(v,u) Algoritmiek
Voorbeeld Algoritmiek
Waarom werkt Dijkstra? Invarianten Voor elke knoop u: D[u] ³ d(s,u) Voor elke knoop u in W: D[u] = d(s,u). Algoritmiek
Invarianten zijn initieel geldig Voor elke knoop u: D[u] ³ d(s,u) Voor elke knoop u in W: D[u] = d(s,u). D[s] = 0; W = {s}; For alle knopen w do D[w] = ¥ For alle pijlen (s,u) do D[u] = L(s,u); Algoritmiek
Invarianten blijven geldig Voor elke knoop u: D[u] ³ d(s,u) Relaxatie werkt Voor elke knoop u in W: D[u] = d(s,u) Voor elke knoop u die al in W zat: D[u] wordt nooit meer gewijzigd, dus D[u] = d(s,u) Dus te bewijzen dat D[v] = d(s,v) voor knoop v gekozen in algoritme Algoritmiek
De Wolk werkt (1) Te bewijzen dat D[v] = d(s,v) voor knoop v gekozen in algoritme Uit invariant weten we dat D[v] ³ d(s,v) Stel dat D[v] > d(s,v) Wat hebben we fout gedaan? Hoe loopt dat kortste pad dus echt? Algoritmiek
De Wolk werkt (2) Bekijk kortste pad P van s naar v P gaat van knoop in wolk (s) naar knoop buiten de wolk (v) Bekijk eerste knoop w op P buiten de wolk Mogelijk: w = v Bewering: D[w] < D[v] En dus hadden we w moeten kiezen in het algoritme w s v W Algoritmiek
De Wolk werkt (3): D[w] < D[v] u is voorganger van w op P Dan D[w] ≤ D[u] + L(u,w) = d(s,u) + L(u,w) u zit al in wolk W = d(s,w) sub-pad optimaliteit ≤ d(s,v) w ligt ‘onderweg’ naar v, sub-pad optimaliteit en pijl-lengtes niet-negatief w u s v W Relax(u,w) al gedaan
De Wolk werkt (4) Bewering was: D[w] < D[v] Net bewezen: D[w] ≤ d(s,v) Aanname was: D[v] > d(s,v) Dus D[w] < D[v] Daarom hadden we w moeten kiezen ipv v Contradictie! Dus D[v] = d(s,v) Algoritmiek
Dijkstra: Correctheid Invarianten zijn correct Voor elke knoop u: D[u] ³ d(s,u) Voor elke knoop u in W: D[u] = d(s,u). Algoritme is klaar als N=W Dus voor alle u: D[u] = d(s,u) While W ≠ N do … Algoritmiek
Greedy Loop While W ≠ N do Kies een element v uit N-W waarvoor D[v] minimaal is t.o.v. de andere elementen uit N-W Stop v in W For alle pijlen (v,u) met u in N-W do If D[u] > D[v] + L(v,u) then D[u] = D[v] + L(v,u) Relax: we moeten kijken of het kortste pad van s naar u via v loopt, omdat we de afstand tot v nu zeker weten Als de wolk in grootte toeneemt, krijg je steeds betere schattingen Relax(v,w) Algoritmiek
Implementatie Simpel, behalve hoe we v kiezen en D updaten Welke datastructuur? Priority queue! Extract-min: 1 keer per knoop: n keer Update: hooguit 1 keer per pijl (bij relaxatie): £ a keer Algoritmiek
Verschillende priority queues Binaire zoekboom Goede keuze: min-heap Minimum zoeken en update: O(log n) per keer O((n+a) log n) tijd totaal Fibonnaci (of hollow) heap O(a + n log n) tijd Algoritmiek
Inzichten (1): hoe hangen schattingen af van de wolk? uitgaande buren x van W alleen schatting van d(s,x) bekend Wolk D[u]=d(s,u) rest van G niets over bekend Algoritmiek
Inzichten (1): hoe hangen schattingen af van de wolk? Voor iedere u in W: D[u] = d(s,u), en het kortste pad dat Dijkstra’s algoritme vindt gebruikt alleen knopen die in W liggen op het moment dat u werd toegevoegd Voor elke knoop u in N-W: D[u] is de lengte van het kortste pad P(W,u) van s naar u dat alleen s, u, en knopen in W gebruikt Gevolg: knopen u niet in W en zonder uitgaande pijl vanuit W hebben D[u] = ¥ Dat is de crux van het correctheidsbewijs: we moeten alleen naar de eerste knoop buiten de wolk kijken Algoritmiek
Inzichten (2): waarom alleen updates in N-W? While W ≠ N do Kies een element v uit N-W waarvoor D[v] minimaal is t.o.v. de andere elementen uit N-W Stop v in W For alle pijlen (v,u) met u in N-W do If D[u] > D[v] + L(v,u) then D[u] = D[v] + L(v,u) Relax(v,w) Algoritmiek
Inzichten (2): waarom alleen updates in N-W? While W ≠ N do Kies een element v uit N-W waarvoor D[v] minimaal is t.o.v. de andere elementen uit N-W Stop v in W For alle pijlen (v,u) do If D[u] > D[v] + L(v,u) then D[u] = D[v] + L(v,u) Relax(v,w) Algoritmiek
Inzichten (3): Prim-Jarnik? Ook een ‘wolk’: de deelboom B die we telkens uitbouwen Voeg kant toe die B verlaat met minimum lengte Kant naar knoop dichtste bij B Dijkstra Wolk W Voeg knoop v toe buiten W met kleinste waarde van D Knoop die geschat dichtste bij s ligt Algoritmiek
Inzichten (3): Prim-Jarnik? Prim-Jarnik doet net iets anders Prim-Jarnik zou kortste pad van lengte 10 van s naar t ontdekken v 5 5 s t 8 Algoritmiek
Inzichten (4): negatieve lengtes? Waarom werkt Dijkstra niet? Volgorde hoe we aan wolk toevoegen is s, t, x, v We moeten alle afstanden weer opnieuw berekenen nadat we v zien Ihb D[t], D[x] Dat kost te veel tijd v 5 -20 s t x 1 2 Algoritmiek
Inzichten (4): negatieve lengtes? Wat nou als we gewoon een grote constante optellen bij alle lengtes? Lengte van het pad (onder L) is iets anders dan aantal pijlen op pad! v v 1 1 -1 -1 Wel een truuk om hier mee om te gaan: later s t s t 1 -1 Algoritmiek
Negatieve lengtes: Bellman-Ford Negatieve cycles nog steeds niet toegestaan! Negatieve lengtes: Bellman-Ford Algoritmiek
Bellman-Ford: Algoritme Initieel: D[s] = 0; voor alle andere u: D[u] = ¥ Herhaal n-1 keer: Voor alle pijlen (v,w): Relax(v,w) Als er dan nog een pijl (v,w) is waarvoor Relax mogelijk is, dwz D[v]+L(v,w) > D[w], dan is er een negatieve cycle bereikbaar uit s Tijd: O(na) Algoritmiek
Voorbeeld Algoritmiek
Bellman-Ford: Correctheid (1) Stelling: Als er een pad van s naar u is met k pijlen en lengte x, dan is na k iteraties van de hoofdloop van het algoritme D[u] <= x. Bewijs: met inductie naar k Initieel waar Een kortste pad s = v0 … vk = u met k pijlen is een kortste pad s = v0 .. vk-1 met k-1 pijlen plus pijl (vk-1,vk) Sub-pad optimaliteit Algoritmiek
Bellman-Ford: Correctheid (2) Stelling: Als er een pad van s naar u is met k pijlen en lengte x, dan is na k iteraties van de hoofdloop van het algoritme D[u] <= x. Uit stelling volgt correctheid: Negatieve cycle bereikbaar uit s: relaxaties blijven altijd mogelijk Geen negatieve cycle: elk kortste pad heeft hooguit n-1 pijlen Algoritmiek
Single source algoritmen Een startknoop s: wat is de afstand van s naar v, voor elke andere knoop v? Twee algoritmes: Dijkstra: O(a + n log n), alleen bij niet-negatieve pijl-lengtes Bellman-Ford: O(na), werkt ook bij negatieve pijl-lengtes Maar niet bij negatieve cycles Algoritmiek
Reflectie op kortste Paden (1) Algoritmiek
Reflectie (1): praktijk Kijk eens naar routebepaling op wegennetwerk Europa O(n+a) is al te veel… Technieken: Bidirectional search A* of goal-oriented search Gebruik van hierarchie en preprocessing Algoritmiek
Reflectie (1): praktijk Highway node routing Univ. Karlsruhe Gelaagde structuur van netwerken: optimale route gebruikt lagen 1, 2, 3, … r-1, r, r-1, … 3, 2, 1 Partitioning using natural cuts Microsoft research Gebruikt dat er natuurlijke snedes in een wegenwerk zijn en partitioneert netwerk daarmee Snedes worden met stromingstechnieken gevonden Algoritmiek