L'hardware / implementazione influenzerà la complessità tempo / spazio degli algoritmi?


32

Non sono nemmeno uno studente CS, quindi questa potrebbe essere una domanda stupida, ma per favore abbi pazienza con me ...

Nell'era pre-computer, possiamo implementare solo una struttura di dati array con qualcosa come una matrice di cassetti. Poiché è necessario individuare il cassetto con l'indice corrispondente prima di estrarre il valore da esso, la complessità temporale della ricerca di array è , presupponendo una ricerca binaria.O(log(n))

Tuttavia, l'invenzione dei computer ha fatto una grande differenza. I computer moderni possono leggere dalla loro RAM così velocemente che ora consideriamo la complessità temporale della ricerca di array come (anche tecnicamente non è il caso, perché ci vuole più tempo per spostare il registro su una distanza maggiore, ecc.)O(1)

Un altro esempio sono i dizionari Python. Mentre si potrebbe ottenere una complessità di accesso al dizionario di con un metodo magico sovraccarico scritto male (o ridicolmente sfortuna, cioè chiavi che hanno molte collisioni di hash), di solito si presume che sia . In questo caso, la complessità temporale dipende sia dall'implementazione della tabella hash dei dizionari Python, sia dall'implementazione delle chiavi delle funzioni hash.O ( 1 )O(n)__hash__O(1)

Ciò implica che l'hardware / l'implementazione possono influire sulla complessità temporale degli algoritmi? (Mentre entrambi gli esempi riguardano strutture di dati anziché algoritmi, i secondi sono basati sul primo e non ho mai sentito parlare della complessità temporale delle strutture di dati, quindi sto usando il termine "algoritmi" qui)

Per me, gli algoritmi sono astratti e concettuali, le cui proprietà come la complessità tempo / spazio non dovrebbero essere influenzate dal fatto che siano implementate in un modo specifico, ma lo sono?


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Gilles 'SO- smetti di essere malvagio' il

Risposte:


42

Sicuro. Certamente. Ecco come conciliare il tuo disagio.

O(logn)O(1)

Dopo aver scelto un modello di calcolo, l'analisi dell'algoritmo è un esercizio matematico, puramente astratto, concettuale, che non dipende più dall'hardware.

Tuttavia, in pratica di solito vogliamo scegliere un modello di calcolo che rifletta la realtà del nostro hardware, almeno in misura ragionevole. Quindi, se l'hardware cambia, potremmo decidere di analizzare i nostri algoritmi in base a un diverso modello di calcolo più appropriato per il nuovo hardware. Ecco come l'hardware può influire sul tempo di esecuzione.

Il motivo per cui questo non è ovvio è perché, nelle classi introduttive, spesso non parliamo del modello di calcolo. Facciamo implicitamente alcune ipotesi, senza mai renderle esplicite. È ragionevole, per scopi pedagogici, ma ha un costo: nasconde questo aspetto dell'analisi. Ora sapete.


Come hai detto, utilizziamo il modello di accesso casuale come modello di calcolo, ma quando utilizziamo la GPU per determinati calcoli, la complessità temporale di alcuni algoritmi cambia mentre utilizza le istruzioni SIMD.
Deep Joshi,

6
Si noti inoltre che la notazione O () è un limite superiore. Anche se usi l'analogia del cassetto trovando un cassetto di dimensioni limitate (la memoria reale ha dimensioni limitate) la costruzione impiega O (1) tempo. Anche se ci vogliono 20 minuti per raggiungere il cassetto più lontano (tutte le cache mancano e devi persino caricare i dati dallo swap) che è ancora O (1) tempo perché 20 minuti saranno la costante nascosta per accedere alla memoria.
Goswin von Brederlow,

2
O(1)O(n)

1
@CortAmmon: anche su un array di grandi dimensioni, l'utilizzo della ricerca lineare potrebbe essere più veloce dell'uso di una mappa hash se tutti gli elementi su cui stanno cercando sono molto vicini all'inizio. Ad esempio, se il 50% degli elementi corrisponde al primo elemento, il 25% corrisponde al secondo, il 12,5% corrisponde al terzo, ecc. Tranne per il fatto che un elemento dispari corrisponderà a qualcosa che potrebbe trovarsi ovunque nell'array, il numero previsto di confronti con eseguire ricerche M su un elenco di dimensioni N sarebbe 2M + N.
supercat,

5
@DeepJoshi Le istruzioni SIMD non cambiano la complessità degli algoritmi. Cambiano solo la costante moltiplicativa.
Gilles 'SO- smetti di essere malvagio' il

5

Penso che ci sia un malinteso fondamentale nella domanda. Si confronta una persona che trova un oggetto in un elenco ordinato (ad esempio, una pagina specifica in un libro, dato il suo numero) con un computer che cerca un oggetto da un array.

O(logn)O(1)

Quindi, sì, l'hardware (ovvero il modello di calcolo) influisce sul tempo di esecuzione degli algoritmi, come spiega DW , ma non è su questo che si basa l'esempio di accesso all'array.


2
Per essere onesti, hai saltato tutti i pezzi tra "il controller di memoria imposta le tensioni sui fili dell'indirizzo alla rappresentazione binaria di diciassette anni" e "i dati ritornano". Uno di quei pezzi quasi certamente è un albero binario di ricerca del tipo descritto dal PO; ma viene comunque eseguito a tempo costante perché il log n è approssimativamente 64, per tutti n .
Quuxplusone,

@Quuxplusone Quale parte della memoria utilizza la ricerca binaria? Le righe dell'indirizzo selezionano direttamente le celle di memoria.
David Richerby,

Operiamo molto al di fuori della mia area di competenza, ma quello che stavo cercando di suggerire è che un decodificatore di indirizzo sarà implementato in termini di un albero di demuxer . (Supponendo che stiamo colpendo direttamente la memoria fisica, ignorando qualsiasi ulteriore complicazione derivante dalla memorizzazione nella cache .) Ancora una volta, tutta questa complicazione aggiuntiva aggiunge solo O(lg size-of-memory), cioè, trascurabile - ma questo è esattamente il pezzo di cui stava chiedendo OP!
Quuxplusone,

2

No, l'hardware non influisce sulla complessità degli algoritmi.

Tuttavia , influisce sulla scelta dell'algoritmo e può influire sull'utilità dell'analisi della complessità a un punto in cui l'analisi diventa praticamente insignificante (o semplicemente di interesse accademico).

Trovare il cassetto giusto (come accedere a un elemento array) usa l'algoritmo "apri l'ennesimo elemento direttamente dall'indice", non l'algoritmo "cerca linearmente" o "esegui ricerca binaria". Gli algoritmi non sono cambiati, ma la scelta.

D'altra parte, l'analisi della complessità stessa, o meglio la sua significatività, è fortemente influenzata dall'hardware.

Molti algoritmi che sono stellari per la loro analisi della complessità sono scarsi o addirittura inutili nella pratica perché il fattore costante insignificante non è affatto insignificante, ma dominante .

Oppure, perché i presupposti che una volta erano veri (o per lo più veri) non valgono più. Come, ad esempio, ogni operazione è per lo più la stessa (solo piccole differenze costanti che non contano), o non fa differenza a quali posizioni di memoria si accede in quale ordine. Tramite l'analisi della complessità, è possibile concludere che alcuni algoritmi sono di gran lunga superiori perché richiedono solo così tante operazioni. In pratica, potresti scoprire che ogni operazione causa un mancato cache garantito (o peggio ancora, un errore di pagina), che introduce un k così grande che non è più insignificante, ma domina tutto.
Se l'algoritmo A impiega 500 operazioni per elaborare un set di dati di una determinata dimensione e l'algoritmo B ne richiede solo 5, ma B causa 5 guasti che bruciano venti milioni di cicli ciascuno, nonostante ciò che l'anaylsis o il buonsenso possono dirti, A è migliore.

Ciò ha portato a sorprese divertenti come ad esempio Cuckoo Hashing qualche anno fa. Che era di gran lunga superiore perché [lunga lista di benefici]. Dopo che l'hype si è raffreddato, si è scoperto che era notevolmente inferiore perché garantiva due errori di cache (errori, per set di dati più grandi) ad ogni accesso.

Simile è successo all'identificazione e all'elaborazione di sottoinsiemi di dati. Spesso la soluzione corretta al giorno d'oggi è: "fai tutto" , cioè invece di capire cosa devi provare e farlo, elabora il set di dati completo in modo lineare anche se forse ne hai bisogno solo per metà. Perché, che ci crediate o no, è più veloce a causa di errori di previsione del ramo, mancati errori nella cache, errori di pagina.
Devi leggere i primi 8 KB e gli ultimi 3 KB di un file da 3 MB? Bene, leggi il file completo e getta via ciò che non vuoi, perché cercare tra sarà dieci volte più lento della semplice lettura.

Utilizzare una mappa perché presenta complessità logaritmica? O una tabella hash, che ha tempi di accesso costanti? Constant sembra fantastico. Bene, per qualsiasi cosa con meno di un migliaio di cose (a seconda dell'hardware, delle dimensioni dei dati e del modello di accesso), una ricerca lineare può essere altrettanto buona o migliore. Sorpresa.

Quindi, non sono gli algoritmi in sé che ne sono interessati, ma la loro utilità e scelta.

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.