Trovare programmaticamente la notazione Landau (notazione Big O o Theta) di un algoritmo?


11

Sono abituato a cercare manualmente la notazione Landau (Big O, Theta ...) dei miei algoritmi per assicurarmi che siano ottimizzati il ​​più possibile, ma quando le funzioni stanno diventando davvero grandi e complesse, sta prendendo piede troppo tempo per farlo a mano. è anche soggetto a errori umani.

Ho trascorso un po 'di tempo su Codility (esercizi di codifica / algo) e ho notato che ti daranno la notazione Landau per la tua soluzione inviata (sia nell'utilizzo del tempo che della memoria).

Mi chiedevo come lo facessero ... Come lo faresti?

Esiste un altro modo oltre all'analisi lessicale o all'analisi del codice?

Questa domanda riguarda principalmente PHP e o JavaScript, ma sono aperto a qualsiasi linguaggio e teoria.


4
Controlla questa risposta da SO. Sembra quello che stai cercando.
Deco,

2
Se riesci a creare un programma che risolve questo problema per ogni singolo algoritmo, diventerai famoso come "l'uomo che ha smentito Turing".
user281377

1
Per prove che la decisione sui tempi di esecuzione è in generale impossibile, vedi qui e qui : le risposte lì dimostrano persino più di quanto chiedi, in realtà.
Alex ten Brink,

Risposte:


13

Mi chiedevo come lo facessero ... Come lo faresti?

Immagino che stiano effettivamente stimando le misure di Big O ... eseguendo il programma per diverse dimensioni del problema, misurando il tempo e l'utilizzo dello spazio e adattando le curve ai risultati.

Il problema con questo approccio è che può sbagliare se le funzioni di costo cambiano forma man mano che N diventa grande; es 1000 N + N^1.5.

Esiste un altro modo oltre all'analisi lessicale o all'analisi del codice?

L'analisi lessicale e l'analisi non sono sufficienti. Devi anche fare alcuni ragionamenti sul comportamento dell'algoritmo. E farlo automaticamente per un algoritmo precedentemente sconosciuto è difficile.


6
"Farlo automaticamente per un algoritmo precedentemente sconosciuto è difficile" - Più precisamente: equivale a risolvere il problema di Halting.
Jörg W Mittag,

Ehm ... non esattamente. Risolvere il problema di Halting equivarrebbe a poterlo fare per tutti gli algoritmi precedentemente sconosciuti.
Stephen C,

2
Sì scusa. Farlo per un algoritmo equivale a (o piuttosto implica) provare la terminazione.
Jörg W Mittag,

1
Gli aspetti pratici di questo sono che 1) è impossibile provare o confutare la terminazione per alcuni algoritmi, ma 2) la maggior parte degli algoritmi non ha questo impedimento teorico, ma 3) lo stato dell'arte nel teorema che dimostra non è abbastanza avanzato per essere in grado di farlo comunque ... tranne in casi relativamente semplici. Da qui la mia affermazione che immagino che lo stiano facendo in un modo diverso. Ma ovviamente, non possiamo essere sicuri di come lo stiano facendo senza guardare il loro codice.
Stephen C,

3

Non possono senza analizzare il codice.

Gli esempi seguenti con "inflazione / deflazione" artificiale della complessità dimostrano che la semplice misurazione della durata del programma non è sufficiente per stimare in modo affidabile Big-O

void lets_trick_runtime(int n) {
   if (n == 10 || n == 25 || n == 118) {
      // unfair speed-up
      do_precalculated_solution_in_constant_time(n);
      return;
   }
   if (n == 11 || n == 26 || n == 119) {
      // unfair slow-down
      do_some_fake_processing_in_n_cube_time(n);
      return;
   }
   // fair solution
   do_general_solution_in_quadratic_time(n);
}

La stima del tempo di esecuzione di cui sopra sarebbe suscettibile di fornire stime false - tempo costante per i valori in ncui esiste una soluzione precalcolata e tempo cubico per i valori in cui unfair slow-downentra in azione - invece del tempo quadratico "equo".


Tuttavia, se per caso controllano i casi "ingiusti", possono ancora supporre che il caso peggiore stia effettivamente valutando la complessità del Big-O.
Yam Marcovic,

1

Penso che questo non sia possibile.

Se si eseguono alcuni test con un numero fisso di dimensioni di input diverse, è possibile calcolare facilmente un polinomio, che approssimerà i tempi di esecuzione misurati molto bene. Quindi finisci con un polinomio per ogni possibile programma, il che significherebbe P = NP(sì!;)).

Se provi a farlo con manipolazione simbolica, finisci per halting problem. Dal momento che non puoi decidere se il tuo programma si fermerà mai, non puoi decidere quale complessità di runtime avrà.

Potrebbero tuttavia esserci casi molto speciali, in cui è possibile il metodo successivo. Ma questi casi forse sono così piccoli, che è discutibile se lo sforzo viene mai pagato.


1
+1, anche se penso che il problema dell'arresto possa essere considerato una rarità.
Yam Marcovic,

0

Come lo farei? Il modo in cui risolvo quasi tutti i problemi che non voglio sedermi e risolvere . Io simulo.

Per molti problemi, può essere sufficiente eseguire l'algoritmo più volte utilizzando una varietà di dimensioni e quindi adattare una curva di regressione a tali risultati. Ciò identificherebbe rapidamente alcuni costi generali "fissi" del tuo algoritmo (l'intercettazione della curva) e come si ridimensiona all'aumentare della dimensione del problema.

Saranno necessari alcuni aggiustamenti per acquisire soluzioni particolarmente complicate, ma soprattutto se stai solo cercando una stima del parco palla, dovresti essere in grado di ottenerla in questo modo e vedere come la tua stima differisce dai risultati effettivi e decidere se è un'approssimazione accettabile.

La più grande debolezza nella mia mente con questo metodo è che se il tuo algoritmo si ridimensiona davvero male, quel passo iniziale "eseguilo un sacco di volte" diventerà brutto. Ma francamente, è così, che da solo dovrebbe essere un indicatore del fatto che potresti voler fare un passo indietro e riconsiderare le cose.


0

La mia intuizione è che una soluzione generale a questo problema sia impossibile; affermando, a tal proposito, fatti a priori sul runtime degli algoritmi senza eseguirli (si allude all'analisi lessicale). Detto questo, è possibile per alcuni algoritmi euristici per una classe (probabilmente di grandi dimensioni) di algoritmi (dal momento che lo facciamo sempre), ma un algoritmo generale per fare ciò equivarrebbe a risolvere il problema di Entscheidungs che è noto per non essere possibile (cfr. Church, Turing, et al.). Sono ~ 99,9% sicuro di questo ora che ci penso ...

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.