Efficiente campionamento più brevi


14

Lasciate G un grafo, e lasciare s e t essere due vertici di G . È possibile campionare in modo efficiente un percorso s - più breve in tmodo uniforme e indipendente in modo casuale dall'insieme di tutti i percorsi più brevi tra s e t ? Per semplicità, possiamo presumere che G sia semplice, non orientato e non ponderato.

Anche in molti grafici ristrette il numero di cammini minimi tra s e t può essere esponenziale nella dimensione di G . Pertanto, saremmo naturalmente, come evitare di realtà calcolando tutte le più breve s - t percorsi. Non conosco il caso generale, ma mi sembra che possiamo raggiungere questo obiettivo per alcune classi di grafi speciali.

Sembra qualcosa che qualcuno deve aver considerato prima. C'è qualche ricerca esistente in questo, o è in realtà semplice da fare anche per i grafici generali?


Bella domanda Juho. Considerando una risposta, cosa capisci esattamente "campionando un percorso uniformemente a caso"? Se è sufficiente che s e t vengano rilevati casualmente, la domanda è banale, quindi immagino che intendi che tutti i nodi nel percorso più breve compaiano con una frequenza (cioè, probabilità) che segue una distribuzione uniforme. O c'è qualche altra definizione? In particolare, per i grafici bipartiti la tua domanda sembra essere molto semplice, vero?
Carlos Linares López,

1
@ CarlosLinaresLópez Considerare di dire il grafico a diamante e dire che è sul lato destro del "bordo verticale" e t è sul lato sinistro. Ora ci sono 2 percorsi più brevi tra s e t . L'algoritmo dovrebbe restituire con uguale probabilità uno di questi due percorsi. Quindi s e t non vengono "raccolti casualmente", ma vengono forniti come input. Questo lo chiarisce? In questo senso, non sono sicuro che il problema sia davvero semplice per i grafici bipartiti. ststst
Juho,

1
@ CarlosLinaresLópez In altre parole, ci viene dato un grafico e due vertici s , t V ( G ) . Sia S l'insieme di tutti i percorsi più brevi tra s e t . Emette un elemento di S uniformemente a caso. Gs,tV(G)SstS
Juho,

Risposte:


6

Non sono sicuro al 100% che questa risposta sia corretta, ma ecco qui:

Penso che puoi ridurlo a qualsiasi percorso uniformemente uniforme, da st , in un DAG con una sola sorgente e un singolo sink.

Dato un grafico G

  1. Crea un nuovo digrafo vuoto, .H
  2. Primo: esegui la parte BFS del percorso più breve di Dijkstra, partendo da , segna tutti i nodi con la loro distanza più breve da-s .s
  3. Sia la distanza minima da s - v ; che conosciamo dal passaggio BFS dell'algoritmo del percorso più breve di Dijkstra.d(s,v)sv
  4. Quindi fai il passo successivo dell'algoritmo del percorso più breve di Dijkstra, ottieni il percorso più breve, memorizzalo in (andando indietro da t a spts ).
  5. Ora avvia il seguente ciclo; spiegazione nei commenti e sotto:
    • q0={t}
    • Mentre q0
      • q1=
      • Per uq0
        • Quindi vogliamo trovare tutti i possibili nodi successivi per questo sottotraccia più breve da tu
        • Per tutti i tale che d ( s , v ) < d ( s , u )edge(u,v)Gd(s,v)<d(s,u)
          • è un nodo vicino, con meno d ( s , ) (sarà 1 in meno)vd(s,)1
          • Pertanto, è possibile sottotraccia in un percorso più breve.tuv
          • Inserisci vH,di-edge(u,v)H
          • Ora dobbiamo controllare i vicini di v minori il prossimo turno.v
          • Inserisci vq1
      • Impostare su q 1q0q1 :
        • q0q1

Essenzialmente, sto raccogliendo tutti i possibili nodi che possono essere utilizzati nel percorso più breve, e metterli in .H

Maggiori informazioni su come funziona:

L'algoritmo del percorso più breve di Dijkstra funziona eseguendo prima un BFS e contrassegnando tutti i nodi con i percorsi più brevi da s - v . Il prossimo passo è tornare indietro da t - s e seguire indietro i nodi meno vicini.vGsvts

Il fatto è che qui puoi scegliere uno dei nodi meno vicini. Quello che faccio qui è raccogliere tutti i nodi meno vicini ogni passaggio, il che significa che conto per tutti i percorsi più brevi.

Ora pensi rapidamente, ma hey, perché li sta enumerando in modo esponenziale, ma la mia strada non lo è?

La risposta è che, poiché utilizzo un set per evitare di aggiungere due volte gli stessi nodi, evito di ricalcolarlo per ogni possibile percorso.

Ora abbiamo un DAG che possiamo attraversare in qualsiasi modo da , e ottenere un percorso inverso più breve da s - t . Il grafico dovrebbe avere t come unica fonte e s come unico sink.tsstts


Se quanto sopra è corretto, penso che possiamo fare un ulteriore passo avanti e risolvere il problema come segue.

Assegna a ciascun nodo nel DAG un peso-nodo; il peso del nodo sarà il numero di percorsi da quel nodo a . Chiamiamolo w ( v ) .sw(v)

È possibile calcolare questi rapidamente, vedere Algoritmo che trova il numero di semplici percorsi da s a t in G .

Una volta che abbiamo il peso del nodo, possiamo scegliere uniformemente un percorso per:

  • Layout del DAG come struttura di livello (per visualizzazione)
  • Ad ogni livello, scegliere un ordinamento arbitrario tra i nodi, ad es. una nozione di "da sinistra a destra".
  • Attraversare il DAG: ad ogni passo , i [ 1 , | p | ] (dove ||ii[1,|p|]|| indica la dimensione di, in questo caso, la lunghezza del percorso più breve):
    • Let tramite il nodo corrente (a partire da tuit )
    • Sommate tutti i pesi dei figli di , e l'utilizzo di un RNG, scegliere uno nodo figlio, v iuivi , in modo uniforme tra i bambini ponderati.
    • Imposta e vai al passaggio successivoui+1=vi

La struttura dei livelli e la nozione di sinistra-destra facevano parte del mio tentativo iniziale di generare semplicemente e scegliere un percorso in quel modo, ma non l'ho capito, quindi puoi tranquillamente ignorarli. r[0,w(t))
Realz Slaw,

1
Questa risposta è fantastica! Adoro le idee! Ho provato a scriverlo in un modo leggermente diverso (nella mia risposta), come prova della mia comprensione. In ogni caso, volevo solo condividere il mio apprezzamento per questa bella risposta!
DW

5

Ecco una soluzione basata sulle idee nella risposta di Realz Slaw. Fondamentalmente è una riesposizione delle sue idee che potrebbe essere più chiara o più facile da seguire. Il piano è che procederemo in due fasi:

  1. In primo luogo, si costruirà un grafico con la seguente struttura: qualsiasi percorso da s a t in S è un cammino minimo da s a t in G , ed ogni cammino minimo da s a t in G è presente anche in S . Pertanto, S contiene esattamente i percorsi più brevi in G : tutti i percorsi più brevi e niente di più. Come succede, S sarà un DAG.SstSstGstGSSGS

  2. Successivamente, si campionare uniformemente a caso da tutti i percorsi da a t in S .stS

Questo approccio si generalizza a un grafico diretto arbitrario , purché tutti i bordi abbiano un peso positivo, quindi spiegherò il mio algoritmo in questi termini. Lascia che w ( u , v ) indichi il peso sul bordo u v . (Questo generalizza l'affermazione del problema che hai dato. Se hai un grafico non ponderato, supponi solo che ogni bordo abbia peso 1. Se hai un grafico non orientato, tratta ogni bordo non orientato ( u , v ) come i due bordi diretti u v e v u .)Gw(u,v)uv(u,v)uvvu


Fase 1: estratto di . S Esegui un algoritmo di percorsi più brevi a sorgente singola (ad esempio, l'algoritmo di Dijkstra) su , a partire dalla sorgente s . Per ogni vertice v in G , d ( s , v ) denota la distanza da s a v .GsvGd(s,v)sv

Ora definisci il grafico come segue. È costituito da ogni bordo u v tale che (1) u v sia un bordo in G e (2) d ( s , v ) = d ( s , u ) + w ( u , v ) .SuvuvGd(s,v)=d(s,u)+w(u,v)

Il grafico ha alcune proprietà convenienti:S

  • Ogni percorso più breve da a t in G esiste come percorso in S : un percorso più breve s = v 0 , v 1 , v 2 , , v k = t in G ha la proprietà che d ( s , v i + 1 ) = d ( s , v i ) + w ( v i , v istGSs=v0,v1,v2,,vk=tGd(s,vi+1)=d(s,vi)+w(vi,vi+1), so the edge vivi+1 is present in S.

  • Every path in S from s to t is a shortest path in G. In particular, consider any path in S from s to t, say s=v0,v1,v2,,vk=t. Its length is given by the sum of the weights of its edges, namely i=1kw(vi1,vi)Si=1k(d(s,vi)d(s,vi1)d(s,t)d(s,s)=d(s,t). Therefore, this path is a shortest path from s to t in G.

  • Finally, the absence of zero-weight edges in G implies that S is a dag.

Step 2: sample a random path. Now we can throw away the weights on the edges in S, and sample a random path from s to t in S.

To help with this, we will do a precomputation to compute n(v) for each vertex v in S, where n(v) counts the number of distinct paths from v to t. This precomputation can be done in linear time by scanning the vertices of S in topologically sorted order, using the following recurrence relation:

n(v)=wsucc(v)n(w)

where succ(v) denotes the successors of v, i.e., succ(v)={w:vw is an edge in S}, and where we have the base case n(t)=1.

Next, we use the n() annotation to sample a random path. We first visit node s. Then, we randomly choose one of the successors of s, with successor w weighted by n(w). In other words:

choosesuccessor(v):
    n = 0
    for each w in succ(w):
        n = n + n(w)
    r = a random integer between 0 and n-1
    n = 0
    for each w in succ(w):
        n = n + n(w)
        if r < n:
            return w

To choose a random path, we repeatedly iterate this process: i.e., v0=s, and vi+1= choosesuccessor(vi). The resulting path is the desired path, and it will be sampled uniformly at random from all shortest paths from s to t.

Hopefully this helps you understand Realz Slaw's solution more easily. All credit to Realz Slaw for the beautiful and clean solution to this problem!


The one case this doesn't handle is the case where some edges have weight 0 or negative weight. However, the problem is potentially not well-defined in that case, as you can have infinitely many shortest paths.


Glad you took the time to fully get my answer; I wasn't sure it is correct. Now I am vindicated :D.
Realz Slaw
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.