Penso che gli articoli di Wikipedia
P , N P e P vs. N P siano abbastanza buoni. Ecco ancora cosa direi: Parte I , Parte II
[Userò osservazioni tra parentesi per discutere alcuni dettagli tecnici che puoi saltare se vuoi.]
Parte I.
Problemi di decisione
Esistono vari tipi di problemi computazionali. Tuttavia, in un'introduzione al corso di teoria della complessità computazionale è più facile concentrarsi sul problema decisionale , vale a dire problemi in cui la risposta è SÌ o NO. Esistono altri tipi di problemi computazionali, ma il più delle volte le domande su di essi possono essere ridotte a domande simili sui problemi di decisione. Inoltre i problemi di decisione sono molto semplici. Pertanto in un'introduzione al corso di teoria della complessità computazionale focalizziamo la nostra attenzione sullo studio dei problemi di decisione.
Siamo in grado di identificare un problema decisionale con il sottoinsieme di input con risposta SÌ. Questo semplifica notazione e permette di scrivere
x ∈ Q in luogo di Q ( x ) = YES e
x ∉ Q in luogo di Q ( x ) = NO .
Un'altra prospettiva è che stiamo parlando di domande di appartenenza in un set. Ecco un esempio:
Problema decisionale:
Input: un numero naturale X ,
Domanda: X è un numero pari?
Problema di iscrizione:
Ingresso: Un numero naturale X ,
Domanda: X in Ev e n = { 0 , 2 , 4 , 6 , ⋯ } ?
Ci riferiamo alla risposta SÌ su un input come accettazione dell'input e alla risposta NO su un input come rifiuto dell'input.
Esamineremo gli algoritmi per i problemi decisionali e discuteremo dell'efficienza di tali algoritmi nell'uso delle risorse calcolabili . Farò affidamento sul tuo intuito dalla programmazione in un linguaggio come C al posto di definire formalmente cosa intendiamo per algoritmo e risorse computazionali.
[Osservazioni: 1. Se volessimo fare tutto in modo formale e preciso, avremmo bisogno di fissare un modello di calcolo come il modello standard della macchina di Turing per definire con precisione cosa intendiamo per algoritmo e il suo utilizzo delle risorse di calcolo. 2. Se vogliamo parlare del calcolo su oggetti che il modello non può gestire direttamente, dovremmo codificarli come oggetti che il modello di macchina può gestire, ad esempio se stiamo usando le macchine di Turing dobbiamo codificare oggetti come numeri e grafici naturali come stringhe binarie.]
P = Problemi con algoritmi efficienti per laricerca disoluzioni
Supponiamo che algoritmi efficienti significhino algoritmi che utilizzano al massimo quantità polinomiale di risorse computazionali. La principale risorsa a cui teniamo è il tempo di esecuzione nel peggiore dei casi degli algoritmi rispetto alla dimensione dell'input, ovvero il numero di passaggi di base che un algoritmo esegue su un input della dimensione n . La dimensione di un input X è n se sono necessarie n -bit di memoria del computer per memorizzare X , nel qual caso scriviamo | x | =n . Quindi per algoritmi efficienti intendiamo algoritmi che hanno un tempo di esecuzione polinomiale nel caso peggiore .
Il presupposto che gli algoritmi del tempo polinomiale catturino la nozione intuitiva di algoritmi efficienti è noto come tesi di Cobham . Non discuterò a questo punto se P sia il modello giusto per problemi risolvibili in modo efficiente e se P catturi o meno ciò che può essere calcolato in modo efficiente nella pratica e questioni correlate. Per ora ci sono buone ragioni per fare questo presupposto, quindi per il nostro scopo assumiamo che sia così. Se non accetti la tesi di Cobham, ciò non rende incorretto ciò che scrivo di seguito, l'unica cosa che perderemo è l' intuizione su un calcolo efficiente in pratica. Penso che sia un presupposto utile per qualcuno che sta iniziando a conoscere la teoria della complessità.
P è la classe di problemi di decisione che possono essere risolti in modo efficiente,
vale a dire problemi di decisione che hanno algoritmi a tempo polinomiale.
Più formalmente, diciamo che un problema di decisione Q è in P iff
esiste un algoritmo efficiente UN tale che
per tutti gli ingressi X ,
- se Q ( x ) = YES quindi A ( x ) = YES ,
- se Q ( x ) = NO allora A ( x ) = NO .
Posso semplicemente scrivere A ( x ) = Q ( x ) ma scrivere in questo modo in modo da poter confrontarlo con la definizione di N P .
N P = Problemi con algoritmi efficienti per laverifica diprove / certificati / testimoni
A volte non conosciamo alcun modo efficace per trovare la risposta a un problema decisionale, tuttavia se qualcuno ci dice la risposta e ci fornisce una prova
possiamo verificare efficacemente che la risposta sia corretta controllando la prova per vedere se è una prova valida . Questa è l'idea alla base della classe di complessità N P .
Se la prova è troppo lunga, non è davvero utile, può richiedere troppo tempo per leggere la prova e tanto meno verificare se è valida. Vogliamo che il tempo richiesto per la verifica sia ragionevole nella dimensione dell'input originale, non in quello della prova fornita! Ciò significa che ciò che vogliamo davvero non sono prove lunghe arbitrarie ma prove brevi . Si noti che se il tempo di esecuzione del verificatore è polinomiale nella dimensione dell'input originale, può solo leggere una parte polinomiale della prova. Quindi, in breve , intendiamo per dimensione polinomiale .
Formare questo punto ogni volta che uso la parola "prova" intendo "prova breve".
Ecco un esempio di un problema che non sappiamo risolvere in modo efficiente ma possiamo verificare in modo efficiente le prove:
Partition
Input: un insieme finito di numeri naturali S ,
Domanda: è possibile dividere S in due insiemi UN e B
( A ∪ B = S e A ∩ B = ∅ ) in modo
tale che la somma dei numeri in UN sia uguale a la somma del numero in B ( ∑x∈Ax=∑x∈Bx )?
Se ti do S e ti chiedo se possiamo dividerlo in due set in modo che le loro somme siano uguali, non conosci alcun algoritmo efficiente per risolverlo. Probabilmente proverai tutti i modi possibili di partizionare i numeri in due set finché non trovi una partizione in cui le somme sono uguali o fino a quando non hai provato tutte le possibili partizioni e nessuna ha funzionato. Se qualcuno di loro ha funzionato direi SÌ, altrimenti diresti NO.
Ma ci sono in modo esponenziale molte possibili partizioni, quindi ci vorrà molto tempo. Tuttavia, se ti do due insiemi A e B , si può facilmente verificare se le somme sono uguali e se A e B è una partizione di S . Si noti che possiamo calcolare le somme in modo efficiente.
Qui la coppia di A e B che ti do è una prova per una risposta SÌ. Puoi verificare in modo efficiente il mio reclamo esaminando la mia prova e controllando se si tratta di una prova valida . Se la risposta è SÌ, esiste una prova valida, che posso fornirti e che puoi verificarla in modo efficiente. Se la risposta è NO, allora non ci sono prove valide. Quindi, qualunque cosa ti dia, puoi controllare e vedere che non è una prova valida. Non posso ingannarti con una prova invalida che la risposta è SÌ. Ricordiamo che se la prova è troppo grande ci vorrà molto tempo per verificarla, non vogliamo che ciò accada, quindi ci preoccupiamo solo di prove efficienti , cioè prove che hanno dimensioni polinomiali.
A volte le persone usano " certificato " o " testimone " al posto di "prova".
Nota Ti sto dando abbastanza informazioni sulla risposta per un dato input x
modo che tu possa trovare e verificare la risposta in modo efficiente. Ad esempio, nel nostro esempio di partizione non ti dico la risposta, ti do solo una partizione e puoi verificare se è valida o meno. Nota che devi verificare tu stesso la risposta, non puoi fidarti di me per quello che dico. Inoltre puoi solo verificare la correttezza della mia prova. Se la mia prova è valida significa che la risposta è SÌ. Ma se la mia prova non è valida, ciò non significa che la risposta sia NO. Hai visto che una prova non era valida, non che non ci fossero prove valide. Stiamo parlando di prove per SI. Non stiamo parlando di prove per NO.
Vediamo un esempio:
A={2,4} e B={1,5} è una prova che
S={1,2,4,5} può essere suddiviso in due set con somme uguali. Abbiamo solo bisogno di riassumere i numeri in A ei numeri in B e vedere se i risultati sono uguali, e verificare se A , B è partizione di S .
Se ti ho dato A={2,5} e B={1,4} , controllerai e vedrai che la mia prova non è valida. Non significa che la risposta sia NO, significa solo che questa prova particolare non era valida. Il tuo compito qui non è trovare la risposta, ma solo verificare se la prova che ti è stata data è valida.
È come uno studente che risolve una domanda in un esame e un professore che verifica se la risposta è corretta. :) (sfortunatamente spesso gli studenti non danno abbastanza informazioni per verificare la correttezza della loro risposta e i professori devono indovinare il resto della loro risposta parziale e decidere quanto voto dovrebbero dare agli studenti per le loro risposte parziali, anzi è piuttosto difficile compito).
La cosa sorprendente è che la stessa situazione si applica a molti altri problemi naturali che vogliamo risolvere:
possiamo verificare in modo efficace se una determinata prova breve è valida, ma non conosciamo alcun modo efficace per trovare la risposta . Questa è la motivazione per cui la classe di complessità NP è estremamente interessante
(sebbene questa non fosse la motivazione originale per definirla). Qualunque cosa tu faccia (non solo in CS, ma anche in matematica, biologia, fisica, chimica, economia, gestione, sociologia, affari, ...) dovrai affrontare problemi computazionali che rientrano in questa classe. Per avere un'idea di quanti problemi si presentano in NP controlla
un compendio di problemi di ottimizzazione NP . Infatti si avrà difficoltà a trovare problemi naturali che non sono in NP . È semplicemente fantastico.
NP è la classe di problemi con verificatori efficienti, ovvero
esiste un algoritmo temporale polinomiale in grado di verificare se una determinata soluzione è corretta.
Più formalmente, diciamo che un problema di decisione Q è in NP iff
esiste un algoritmo efficiente V chiamato verificatore tale che
per tutti gli ingressi x ,
- se Q(x)=YES allora esiste una prova y tale che V(x,y)=YES ,
- se Q(x)=NO poi per tutte le prove y , V(x,y)=NO .
Diciamo che un verificatore è valido
se non accetta alcuna prova quando la risposta è NO. In altre parole, un verificatore di suoni non può essere ingannato per accettare una prova se la risposta è davvero NO. Nessun falso positivo.
Allo stesso modo, diciamo che un verificatore è completo
se accetta almeno una prova quando la risposta è SÌ. In altre parole, un verificatore completo può essere convinto che la risposta sia SÌ.
La terminologia deriva da sistemi logici e di prova . Non possiamo usare un sistema di insonorizzazione per provare dichiarazioni false. Possiamo usare un sistema di prova completo per provare tutte le affermazioni vere.
Il verificatore V ottiene due input,
- x : input originale perQ e
- y : una prova suggeritaQ(x)=YES .
Nota che vogliamo che V sia efficiente nella dimensione di x . Se y è una prova importante, il verificatore sarà in grado di leggere solo una parte polinomiale di y . Ecco perché richiediamo che le prove siano brevi. Se y è breve detto che V è efficace nel x
è uguale a dire che V è efficace nel x ed y
(perché la dimensione di y è delimitata da un polinomio fissato nella dimensione di x ).
In sintesi, per dimostrare che un problema decisionale Q trova in NP
dobbiamo fornire un algoritmo di verifica efficiente, solido e completo .
Nota storica: storicamente non è questa la definizione originale di NP . La definizione originale utilizza quelle che vengono chiamate macchine di Turing non deterministiche . Queste macchine non corrispondono a nessun modello di macchina reale e sono difficili da abituare (almeno quando si inizia a conoscere la teoria della complessità). Ho letto che molti esperti pensano che avrebbero usato la definizione di verificatore come definizione principale e avrebbero persino chiamato la classe VP
(per verificabile in tempo polinomiale) al posto di NP
se tornano agli albori della teoria della complessità computazionale. La definizione verificatore è più naturale, più facile capire concettualmente, e più facile da usare per mostrare problemi sono in NP .
P⊆NP
Pertanto abbiamo
P = efficiente risolvibile e NP = efficacemente verificabile . Quindi P=NP se i problemi che possono essere verificati in modo efficiente sono gli stessi dei problemi che possono essere risolti in modo efficiente.
Nota che qualsiasi problema in P è anche in NP , cioè se riesci a risolverlo puoi anche verificare se una data prova è corretta: il verificatore ignorerà semplicemente la prova!
Questo perché non ne abbiamo bisogno, il verificatore può calcolare la risposta da solo, può decidere se la risposta è SÌ o NO senza alcun aiuto. Se la risposta è NO, sappiamo che non dovrebbero esserci prove e il nostro verificatore rifiuterà semplicemente ogni prova suggerita. Se la risposta è SÌ, dovrebbe esserci una prova, e infatti accetteremo qualsiasi cosa come prova.
[Avremmo potuto fare in modo che il nostro verificatore accettasse solo alcuni di essi, va bene, purché il nostro verificatore accetti almeno una prova che il verificatore funzioni correttamente per il problema.]
Ecco un esempio:
n+1a1,⋯,ans
Σni=1ai=s
Ps
NPVP
NPPP⊆NP
NPNP⊆ExpTime
NPNP
Nel nostro esempio di partizione, proviamo tutte le possibili partizioni e controlliamo se le somme sono uguali in ognuna di esse.
m2m
NPNP⊆ExpTimeNP⊆PSpace
NPPNPNP
NP=PNP
NPNP
NPNPNPP⊆NP
NPNP
I limiti inferiori sembrano difficili da dimostrare
NP
Sfortunatamente il compito di dimostrare limiti inferiori è molto difficile. Non possiamo nemmeno dimostrare che questi problemi richiedono più di un tempo lineare ! Per non parlare del fatto che richiede tempo esponenziale.
Provare limiti inferiori a tempo lineare è piuttosto semplice: dopo tutto l'algoritmo deve leggere l'input. Dimostrare limiti inferiori super-lineari è una storia completamente diversa. Siamo in grado di dimostrare limiti inferiori superlineari con più restrizioni sul tipo di algoritmi che stiamo prendendo in considerazione, ad esempio ordinamento degli algoritmi mediante il confronto, ma non conosciamo limiti inferiori senza tali restrizioni.
Per dimostrare un limite superiore per un problema, dobbiamo solo progettare un algoritmo abbastanza buono. Spesso ha bisogno di conoscenza, pensiero creativo e persino ingegnosità per elaborare un tale algoritmo.
Tuttavia, l'attività è notevolmente più semplice rispetto alla dimostrazione di un limite inferiore. Dobbiamo dimostrare che non esistono buoni algoritmi . Non che non conosciamo algoritmi abbastanza validi in questo momento, ma che non esistono algoritmi validi , che nessuno riuscirà mai a trovare un buon algoritmo . Pensaci un minuto se non l'hai mai fatto prima, come possiamo mostrare un risultato così impossibile ?
1=0
Per dimostrare un limite inferiore, cioè a dimostrare che un problema richiede una certa quantità di tempo per risolvere, significa che dobbiamo dimostrare che qualsiasiNPproblemi, ad esempio avido e le sue estensioni non possono funzionare, e ci sono alcuni lavori relativi agli algoritmi di programmazione dinamica e ci sono alcuni lavori su modi particolari di usare la programmazione lineare. Ma questi non sono nemmeno vicini a escludere le idee intelligenti di cui siamo a conoscenza (cerca i limiti inferiori nei modelli di calcolo ristretti se sei interessato).
Barriere: i limiti inferiori sono difficili da dimostrare
D'altra parte abbiamo risultati matematici chiamati
barriere
che affermano che una prova con limite inferiore non può essere tale e tale, e tale e quasi copre quasi tutte le tecniche che abbiamo usato per dimostrare limiti inferiori! In effetti molti ricercatori hanno rinunciato a lavorare per dimostrare limiti inferiori dopo il risultato di barriera delle prove naturali di Alexander Razbarov e Steven Rudich
. Si scopre che l'esistenza di un particolare tipo di prove con limite inferiore implicherebbe l'insicurezza dei generatori di numeri pseudocasuali crittografici e di molti altri strumenti crittografici.
Dico quasi perché negli ultimi anni ci sono stati alcuni progressi principalmente da parte di Ryan Williams
che è stato in grado di aggirare in modo intelligente i risultati della barriera, ma i risultati finora sono per modelli di calcolo molto deboli e abbastanza lontani dall'escludere algoritmi generali del tempo polinomiale .
NP
[D'altra parte, il lavoro di Ryan Williams mostra che ci sono stretti legami tra la dimostrazione di limiti inferiori e la dimostrazione di limiti superiori. Guarda il suo discorso all'ICM 2014 se sei interessato.]
Riduzioni: risoluzione di un problema utilizzando un altro problema come subroutine / Oracle / scatola nera
L'idea di una riduzione è molto semplice: per risolvere un problema, utilizzare un algoritmo per un altro problema.
nSumSum
Problema:
nx1,…,xn
∑ni=1xi
Algoritmo di riduzione:
- s=0
- i1n
s=Sum(s,xi)
- s
SumSumSumSum
Questa è essenzialmente una riduzione: supponiamo che abbiamo un algoritmo per un problema e usalo come oracolo per risolvere un altro problema. Qui efficiente significa efficiente supponendo che l'oracolo risponda in un'unità di tempo, ovvero contiamo ogni esecuzione dell'oracolo in un unico passaggio.
Se l'oracolo restituisce una risposta di grandi dimensioni abbiamo bisogno di leggere e che può richiedere un certo tempo, quindi dovremmo contare il tempo necessario a noi per leggere la risposta che Oracle ha dato a noi. Allo stesso modo per scrivere / porre la domanda dall'oracolo. Ma l'oracolo funziona all'istante, cioè non appena facciamo la domanda dall'oracolo l'oracolo scrive la risposta per noi in una singola unità di tempo. Tutto il lavoro svolto dall'oracolo viene conteggiato in un solo passaggio, ma ciò esclude il tempo impiegato per scrivere la domanda e leggere la risposta.
Poiché non ci interessa il modo in cui funziona l'oracolo, ma solo le risposte che restituisce, possiamo semplificare e considerare l'oracolo come il problema stesso al posto di un algoritmo per esso. In altre parole, non ci importa se l'oracolo non è un algoritmo, non ci interessa come gli oracoli arrivano con le sue risposte.
Sum
Possiamo fare più domande da un oracolo e non è necessario che le domande siano predeterminate: possiamo fare una domanda e in base alla risposta che l'oracolo restituisce eseguiamo alcuni calcoli da soli e quindi facciamo un'altra domanda in base alla risposta che abbiamo ottenuto la domanda precedente.
Un altro modo di vedere questo è pensarlo come un calcolo interattivo . Il calcolo interattivo in sé è un argomento di grandi dimensioni, quindi non approfondirò qui, ma penso che menzionare questa prospettiva di riduzioni possa essere utile.
AOAO
La riduzione di cui abbiamo discusso in precedenza è la forma più generale di riduzione ed è nota come riduzione della scatola nera
(ovvero riduzione dell'oracolo , riduzione di Turing ).
Più formalmente:
QOQ≤TO
Ax
Q(x)=AO(x)
AOQ
AQ≤PTOT
Tuttavia, potremmo voler porre alcune restrizioni sul modo in cui l'algoritmo di riduzione interagisce con l'oracolo. Esistono diverse restrizioni studiate, ma la restrizione più utile è quella denominata riduzioni
multiple (ovvero riduzioni della mappatura ).
xy
Più formalmente,
QOQ≤mO
Ax
Q(x)=O(A(x))
Q≤PmO
NPANPBANP
PNPNP
Il post è diventato troppo lungo e supera il limite di una risposta (30000 caratteri). Continuerò la risposta nella parte II .