L'algoritmo di Dijkstra su enormi grafici


15

Conosco molto bene Dijkstra e ho una domanda specifica sull'algoritmo. Se avessi un grafico enorme, ad esempio 3,5 miliardi di nodi (tutti i dati OpenStreetMap), allora chiaramente non sarei in grado di avere il grafico in memoria, quindi il grafico viene archiviato su disco in un database.

Ci sono librerie disponibili per calcolare i percorsi più brevi su tali grafici. Come lo fanno? Più specificamente, come caricano la parte richiesta del grafico per eseguire l'algoritmo di Dijkstra?

Il recupero dell'elenco di adiacenza di ciascun vertice visitato richiederebbe circa 1.500 query di database per 10.000 nodi secondo i miei dati statistici, quindi chiaramente non è così che lo fanno. Sarebbe troppo lento.

Come lo fanno? Sto cercando di implementarlo da solo.


2
Sei sicuro che usano Dijkstra? Esistono molti altri algoritmi del percorso più breve che potrebbero essere più adatti alla situazione che descrivi.
David Richerby,

1
Hai esaminato il codice? Come dovremmo saperlo? "query di database" - spero che tu non usi un DBMS per archiviare i grafici?
Raffaello

@DavidRicherby sì, ne sono sicuro, guarda questo link
dimitris93,

2
"[I] t sarebbe un processo estremamente noioso per esaminare il codice C puro." Ma questo è l'unico modo per sapere cosa fa il codice. Quindi ci stai solo chiedendo di fare il tuo noioso compito per te, che non è la
migliore

1
@Shiro Chiedete esplicitamente: "Come fanno a farlo?" Se questa non è davvero la domanda che vuoi porre, devi riformularla.
Raffaello

Risposte:


6

Ci sono librerie disponibili per calcolare i percorsi più brevi su tali grafici. Come lo fanno? Più specificamente, come caricano la parte richiesta del grafico per eseguire l'algoritmo di Dijkstra?

È possibile utilizzare un DB, un formato file personalizzato da leggere dal disco e un'impostazione in memoria.

Ma dalla mia esperienza nell'uso di un DB è circa 5-10 volte più lento e molta più memoria rispetto alla scrittura del proprio formato di file basato su un "semplice" formato di elenco collegato.

La cosa buona è che ci sono diversi framework software che utilizzano OSM che sono open source in modo da poter guardare nel codice ad es. Vedere qui . Nel motore di routing open source GraphHopper è molto semplice passare da un'impostazione mappata in memoria (basata su disco) a un'impostazione in memoria, entrambi utilizzando lo stesso formato. L'impostazione "mmap" consente persino l'utilizzo su dispositivi mobili con limitazioni di memoria e quest'ultimo funziona molto più velocemente se si dispone della RAM necessaria, ad esempio su un server. Ad esempio, per un grafico mondiale (> 100 milioni di nodi) sono necessari circa 8-10 GB di RAM, oltre a molta più RAM se si desidera accelerare ulteriormente, ad esempio con Gerarchie di contrazioni - circa 5-8 GB in più per ogni veicolo desiderato.

Il formato è molto semplicistico e fondamentalmente memorizza solo i dati necessari con alcuni accorgimenti per renderlo compatto. Leggi di più qui . Disclaimer: sono l'autore di GraphHopper.

Per quanto riguarda le altre risposte:

L'algoritmo di Dijkstras mentre applicabile non è considerato ottimale per questo problema

Il Dijkstra "normale" può funzionare in modo molto ragionevole (<1s per query a livello nazionale come nell'esempio dei nodi 3mio) ed è ottimale in senso teorico, ma necessita di un po 'di ottimizzazione per ottenere velocemente scenari di produzione. E tecniche come la Contraction Hierachies ne usano una modifica bidirezionale e si comportano molto bene.

le reti stradali sono gerarchiche e planari.

le reti stradali sono gerarchiche solo per auto e non planari (ponti, tunnel, ...)


Ho un'altra domanda. Come si trova il NodeIDnodo più vicino dal latitude/longitude? Ciò è necessario per calcolare il percorso più breve A-> B. Inoltre, dobbiamo tenere presente che A e B potrebbero non esistere come nodi, poiché non tutti i metri quadrati contengono un nodo. Quindi dobbiamo trovare i 2 NodeID più vicini di A e B.
dimitris93

Questo viene fatto in LocationIndexTree, che è una specie di quadrifoglio che memorizza in modo efficiente i NodeID in una cella che ha ad esempio per GraphHopper un raggio di ~ 500m. Se non viene trovato nulla, il raggio si espande fino a un certo grado. Sembra semplice in teoria, ma è molto complesso poiché potresti avere bordi che attraversano l'area, devi essere efficiente quando lo crei e interroghi e molto altro.
Karussell,

Gli alberi KD non sono più efficienti quando si cerca il vicino più vicino? Perché hai scelto QuadTrees su KD-Trees? In questo momento sto implementando KD-Trees per il mio motore di routing. Ho iniziato a implementare QuadTrees ma mi sono fermato perché immaginavo che KD-Trees fosse la stessa cosa, ma più facile da programmare e più veloce per interrogare il vicino più vicino. Ho sbagliato ?
dimitris93,

Quando si usano i quadrifici non è necessario archiviare esplicitamente il rettangolo di selezione, dandogli un vantaggio in termini di archiviazione, il che è stato più critico per il mio caso d'uso (anche io trovo i quadrifici più facili;)). La velocità della query non è un problema. In effetti qualcuno ha studiato questi tentativi e ha superato qualsiasi altra implementazione incl. Alberi KD, ma suppongo che tutto dipenda dall'attuazione specifica ...
Karussell,

Se guardi la pagina 9 di questo pdf da Stanford, la ricerca del vicino più vicino in KD-Trees non richiede di conoscere le caselle di delimitazione. E un'altra cosa è che, poiché conosciamo in anticipo tutti i punti, possiamo creare un albero bilanciato di altezza logn. Sei ancora sicuro che i quadrifici abbiano qualche vantaggio rispetto ai kd-tree?
dimitris93,

2

Non è necessario inserire tutti i bordi adiacenti nella coda di priorità. "Lie" all'algoritmo di Dijkstra e dagli solo il vertice più corto, v, incidente al vertice, diciamo w, tirato fuori dallo stack. Quindi, quando v viene estratto dalla coda, dici "oops", ho fatto un errore e avrei dovuto darti anche questo vertice, che è il prossimo più vicino al vertice w. Si vede facilmente che in questo modo si avrà una soluzione corretta e la dimensione della coda si riduce drasticamente a un vertice incidente invece che a molti. Devi comunque tenere traccia degli incidenti per dare sempre il prossimo vertice più vicino - quando richiesto. Uno dei commenti ha affermato che le reti stradali sono planari errate. In effetti, uno studio ha dimostrato che sono altamente non planari. Pensa a tutte le autostrade che attraversano i ponti attraverso una città che induce molte non planarità.


0

L'algoritmo di Dijkstras, sebbene applicabile, è considerato non ottimale per questo problema, sebbene le varianti più efficienti possano essere considerate "simili". ci sono varie semplificazioni. le reti stradali sono gerarchiche e planari . ecco gli approcci di base. la zona è generalmente nota come "pianificazione del percorso nelle reti stradali".

  • una struttura grafica può essere "compilata" dai dati dell'elenco di adiacenza. questo è l'approccio nella biblioteca che citi , SpatiaLite. queste strutture grafiche sono archiviate in un formato binario compresso in cui le posizioni dei grafici sono rappresentate da numeri interi con codifica binaria ecc., quindi la rappresentazione e la manipolazione dei grafici occupano molto meno spazio rispetto alla memorizzazione di tutti i nomi delle strade ecc .; sembra che l'algoritmo SpatiaLite non sia "online" e funzioni interamente in memoria.

  • ci sono algoritmi paralleli / distribuiti. vedi ad esempio Grafico GPU scalabile Traversal / Merrill, Garland, Grimshaw.

  • la domanda utilizza la terminologia client-server, ad esempio "query". gli algoritmi non vengono eseguiti "interrogando" il database nel senso client-server. linguaggi di query di livello superiore come SQL sono un'interfaccia per il database e possono essere utilizzati per trasmettere la richiesta per calcolare i percorsi minimi ma non sono utilizzati internamente dall'algoritmo. generalmente l'algoritmo viene eseguito "all'interno del database", cioè interamente "lato server". quindi è quindi possibile scrivere un algoritmo di percorso più breve nelle query del database per reti di piccole dimensioni ma non per medie / grandi dimensioni.

  • esiste un altro approccio in cui le stime entro piccole percentuali possono essere accettabili. l'idea di base è quella di mantenere un indice delle distanze tra i nodi. vedere ad es. Stima rapida e accurata dei percorsi più brevi nei grafici di grandi dimensioni / Gubichev, Bedathur, Seufert, Weikum

  • questa tesi di dottorato (235p!) è particolarmente applicabile. Pianificazione del percorso in reti stradali / Schultes

  • alcuni algoritmi utilizzano molte di queste idee e altri, sono altamente sintonizzati e proprietari e sfiorano segreti commerciali competitivi. ad es. di Google. potrebbero esserci dei media fuorvianti su questo argomento. ad es. l'algoritmo semplice ed elegante che rende possibile Google Maps che sostiene / implica che Google utilizza l'algoritmo Dijkstras senza alcuna citazione.


1
Google Maps ha sicuramente aggiornato a qualcosa di meglio di Dijskstra. Ogni sviluppatore competente a metà utilizzerebbe A * per le mappe stradali, ma nel mio lavoro precedente abbiamo scoperto che il motore di Google poteva sostituire 2500 chilometri di rotte attraverso un waypoint in <100 ms. È troppo veloce per A *, quindi è probabile che usino qualcosa come ArcFlags.
Salterio il

La risposta di Karussell contesta questa frase di apertura "L'algoritmo di Dijkstras mentre applicabile è considerato non ottimale per questo problema" che non si aspettava sarebbe controverso. c'è un supporto molto forte per l'affermazione nella tesi di Schultes (all'inizio) che è anche un'indagine molto completa / recente dell'area, e spiega anche le "approssimazioni" gerarchiche e planari. sfortunatamente non sembra esserci alcuna indicazione degli attuali algoritmi di google nella letteratura aperta sulla ricerca rapida.
vzn,

-2

Su set di dati estremamente grandi come quello, per ottenere risultati così veloci, trovo che sia meglio usare una struttura di dati di unione-find con compressione del percorso. Tuttavia, se stai cercando di utilizzare solo l'algoritmo di Djikstra e ottimizzarlo, si riduce a quali informazioni ha ciascun nodo nel grafico. Molto probabilmente non è necessario eseguire tutte le 1.500 query.

Ad esempio, considera il seguente esempio. Diciamo che sto cercando di trovare i gradi di separazione tra 2 attori (il numero di Bacon) e voglio trovare il percorso meno ponderato (percorso usando i film più recenti possibili). Ora, diciamo che ho una funzione chiamata shortestPath(actor A, actor B);. Considera il seguente scenario.

Se l'attore A ha recitato dal 1970 e l'attore B ha recitato dal 2000, quindi fornite tali informazioni, sarebbe molto più logico trovare un percorso che inizi dal primo film dell'attore B e che poi passi per l'attore A. al contrario dell'iterazione in ogni film in cui ha recitato l'attore A.

Pertanto, il punto principale è che l'ottimizzazione dell'algoritmo di Djikstra dipende in realtà dal set di dati. Dovresti fornire ulteriori informazioni su ciò che il tuo set di dati comporta per noi per aiutarti a ottimizzare il tuo algoritmo.

EDIT: Diciamo che stai cercando di trovare il percorso più breve tra 2 città nello stesso paese e se questo paese è più lungo di quanto sia più ampio, ad esempio l'Argentina, puoi fare le tue domande in base alla longitudine e alla latitudine dei paesi confini. Quindi puoi iniziare a percorrere in verticale (usando la longitudine) anziché in orizzontale. Ovviamente, dovrebbe esserci una gestione delle eccezioni, ma ottieni l'idea generale.


1
Come si usa Union-Find in Dijkstra?
Raffaello

I dati sono dati spaziali, latitudine e longitudine. Ho pensato che fosse chiaro.
dimitris93,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.