Un problema del millennio

La prova del nove

 

La nostra (lontana?) esperienza di studenti delle scuole medie ed elementari ha certamente incluso l'incontro con la famosa prova: il controllo, cioè, della correttezza della soluzione di un'operazione o di una equazione o comunque di un problema di Matematica. Semplici procedure, come la ben nota prova del nove, hanno verosimilmente allietato qualche nostro pomeriggio di giovani scolari. Converremo tutti che questo esercizio di verifica può essere talora noioso, arido e poco stimolante. Pur tuttavia, ha proprietà di sicurezza e meccanicità che non possono non essere apprezzate, almeno da uno studente alle prime armi, ancora inesperto di tutte le sottigliezze matematiche: pochi passaggi, automatici e ripetitivi, bastano per confermare che la risposta precedentemente acquisita è esatta oppure, malauguratamente, a contestarla e a costringerci a ricominciare. In effetti, risolvere un esercizio è pur sempre una scommessa, una sfida piena di incognite, di incertezze e di pericoli. Verificarne la soluzione – una volta che è stata acquisita – può essere talora un'antipatica appendice, ma ha il pregio di una placida procedura lontana da ogni rischio.
Anche per problemi più seri ed attuali, cercare una soluzione può essere esperienza delicata e impegnativa, mentre controllare la soluzione trovata richiede talvolta una semplice occhiata. Ad esempio, pensiamo alla decomposizione degli interi positivi N nei loro fattori primi. Recuperare i fattori primi di un assegnato numero composto N è, ancor oggi (almeno per N grande), esercizio complicato e difficile, privo di procedure adeguatamente veloci e soddisfacenti; invece, verificare la decomposizione di N, una volta che se ne conoscono i fattori, è impegno di poca spesa che si riduce ad una semplice moltiplicazione, gestibile in pochi attimi con un comune calcolatore, anche quando N ed i suoi fattori sono numeri di molte cifre. Fortunati sistemi di crittografia a chiave pubblica (come il famoso RSA) basano la loro sicurezza ed efficienza sul dislivello ancora esistente tra determinare e verificare la decomposizione di un intero N.

Nasce allora la curiosità generale di confrontare da un lato le risorse necessarie per risolvere un problema, dall'altro quelle richieste per controllarne le soluzione. In particolare, ci possiamo domandare: se la verifica può essere svolta in modo rapido (come nel caso della decomposizione), può dirsi lo stesso della soluzione? L'esempio degli interi ci mostra che la questione ha aspetti intriganti e fascinosi, ma in qualche caso attende ancora una risposta definitiva. L'articolo che segue vuole discutere in maggior dettaglio l'intera questione e sottolinearne sorprendenti venature, sottintesi e difficoltà.

 

P e NP

 

Come detto, il nostro intento è confrontare i tempi di soluzione e di verifica di un problema o, più esattamente, dei migliori algoritmi che gli si applicano. Naturalmente, un'analisi precisa e rigorosa della questione richiederebbe che prima si convenissero chiare definizioni teoriche di che cosa si intende per problema e per algoritmo e di come se ne misura l'efficienza temporale.

Alan Turing

Noi qui ci accontentiamo di prendere atto che queste esigenze hanno adeguata risposta (si veda, ad esempio, [1] o [2]): un preciso formalismo matematico descrive che cosa è un problema e la classica tesi di Alan Turing degli anni Trenta del secolo scorso sembra suggerire ancora un buon modello teorico di quel che si deve intendere per algoritmo (o, meglio, per problema dotato di algoritmo). Quanto alla misurazione dell'efficienza di una procedura (di soluzione o di verifica), c'è una proposta in Informatica teorica, che è variamente attribuita (ad Edmonds, Cook, Karp) e risale ai tardi anni Sessanta. Sostiene che un algoritmo A è efficiente quando lavora in tempo al più polinomiale rispetto alla lunghezza dell' input: in dettaglio, ci deve essere un polinomio pA(x) – che ha coefficienti interi, assume valori positivi da un certo punto in poi e dipende solo da A – tale che la computazione di A su input di lunghezza al più n (a cui è possibile rispondere) si svolge entro pA(n) passi (almeno per n sufficientemente grande). Si propone così una stima asintotica del tempo di lavoro dell'algoritmo, tesa a valutarlo come funzione di n e a studiarne il comportamento per n che tende all'infinito: idea ragionevole, visto che quel che ci interessa per dichiarare A efficiente non è tanto il suo modo di trattare certi specifici particolarissimi input ma un quadro complessivo delle sue capacità di lavoro, al variare di tutti gli input e delle loro lunghezze. Da questo punto di vista, la tesi di Edmonds, Cook e Karp si può riassumere (in termini un po' rozzi e brutali) nello slogan “efficiente=polinomiale”.
Naturalmente, si tratta di proposta discutibile (e discussa). In effetti, se è facile ammettere che un algoritmo A sia efficiente quando lavora in tempo lineare oppure anche quadratico rispetto alla lunghezza dell' input (in altre parole, quando il corrispondente polinomio pA è di primo oppure di secondo grado), quando il grado del polinomio cresce e si vanno a scomodare situazioni quali , si può realmente dubitare che A lavori davvero in modo rapido. D'altra parte, sembra difficile individuare un miglior livello di separazione e cioè un grado d tale che gli algoritmi che lavorano in tempo asintotico limitato da xdsiano ritenuti veloci mentre quelli che impiegano xd+1 passi non lo siano più. Perché accettare d ed escludere d +1? Almeno a livello teorico, non ci sono argomentazioni sufficienti per motivare una simile opzione. Così, la tesi di Edmonds-Cook-Karp è comunemente accettata, sia pure con le riserve sopra accennate. Semmai, ne sottolineiamo un aspetto che ci pare indiscutibile: siccome la funzione esponenziale x→2x supera asintoticamente i polinomi di ogni possibile grado, un algoritmo che impiega tempo 2noppure superiore rispetto alla lunghezza n dei suoi input è da ritenersi lento e impraticabile (né ci pare che il senso comune possa qui smentire l'affermazione teorica).
Così, rassicurati dal rigore scientifico circa la definizione di problema, algoritmo ed efficienza, possiamo far libero riferimento ad un'idea intuitiva di questi tre concetti e procedere nel nostro scopo. Anzi definiamo, per fissare le idee, P come la classe dei problemi che ammettono un algoritmo efficiente di soluzione (P sta per polinomiale, ovviamente) e NP come la classe dei problemi che ammettono un algoritmo efficiente di verifica delle soluzioni.
È chiaro che P⊆NP. La nostra curiosità è se vale addirittura l'uguaglianza P=NP, se dunque un problema che ha procedura rapida di verifica ammette anche un algoritmo (magari più lento ma ancora efficiente, cioè polinomiale) per trovare le soluzioni. Questo è quanto vorremmo discutere qui. Ciò stabilito, vale comunque la pena di fermarsi un attimo e spendere qualche parola sui motivi per cui dovremmo appassionarci (o almeno qualcuno dovrebbe appassionarsi) a questa domanda.


Clay Mathematics Institute

Che si tratti di questione rilevante, si deduce facilmente vedendola inserita tra i sette Problemi del Millennio , quelli che il Clay Mathematics Institute di Cambridge, Massachussetts, ha segnalato come i più significativi e difficili nella ricerca matematica del 2000. Maggiori informazioni sull'argomento, e la lista completa dei sette problemi, possono trovarsi in [3] oppure direttamente nel sito del Clay Institute, www.claymath.org/millennium. Visitandolo, il lettore potrà osservare come un premio di un milione di dollari è promesso a chi risolverà una qualunque delle sette questioni, il che costituisce già da sé ottimo motivo per interessarsi anche di P=NP. C'è poi chi può essere attirato dalla questione a prescindere dal denaro, solo per la sua valenza teorica. Ma ciò che può accrescere la curiosità generale è lo spettro quasi illimitato delle sue applicazioni particolari, la quasi infinità dei problemi per i quali non è difficile intravedere un algoritmo di verifica efficiente, ma appare tragicamente complicato individuare una procedura rapida di soluzione.

Pensiamo, ad esempio, alla questione di riconoscere i numeri primi e a quella di decomporre i numeri naturali composti N, cui già abbiamo accennato nell'introduzione. Come già osservato, quando conosciamo i fattori primi di N, non è difficile né lento controllare la decomposizione (e cioè se N è davvero il risultato che si ottiene moltiplicandoli): anche se N ha 1000 cifre in base 10 ed i suoi singoli fattori sono “quasi altrettanto” lunghi, i moderni calcolatori impiegano tempi relativamente brevi per la verifica. Tuttavia, allo stato attuale delle conoscenze, non sono noti algoritmi capaci di decomporre N in tempo rapido (cioè al più polinomiale rispetto alla lunghezza di N, secondo i parametri sopra stabiliti). Il problema di riconoscere se N è primo (in genere chiamato problema di primalità) è lievemente diverso ed apparentemente più semplice. Non ci interessa infatti, per N composto, conoscere i suoi fattori ma soltanto dichiararlo tale. La relativa verifica è ovviamente rapida, almeno quando N è composto; controllare se N è primo (quando è primo) può invece riservare qualche maggior ostacolo, visto che non si tratta più di confermare una decomposizione che conosciamo ma di escludere ogni possibile fattorizzazione non banale di N. Esistono comunque algoritmi rapidi (di una qualche maggiore complicazione teorica) che sanno compiere rapidamente questa verifica. Del resto, nel 2002, tre ricercatori indiani (Agrawal, Kayal e Saxena) hanno finalmente proposto un procedimento capace di scoprire rapidamente se un fissato N è primo oppure no: l'algoritmo funziona infatti al più in tempo x11 rispetto alla lunghezza dell' input e recenti perfezionamenti di Lenstra e Pomerance hanno abbassato a x6 questa soglia (si veda [6]).
Tra le questioni che appartengono a NP, ce ne sono alcune che hanno un interesse particolare per un motivo che adesso cerchiamo di spiegare. Ammettiamo di trovare un problema che dichiaratamente sta in NP ma di cui riusciamo a provare per qualche via teorica che non può stare in P. Deduciamo ovviamente, e correttamente, che P≠NP. Ma supponiamo adesso di considerare un altro problema S in NP e di riuscire a dimostrare che S∈P. Commetteremmo un grosso errore matematico e logico a dedurre P=NP. Un esempio non può costituire una dimostrazione. Tuttavia, capita talora (anche nella vita di tutti i giorni) che esistano persone o riferimenti o valori così generali da rappresentare adeguatamente classi ampie ed articolate, coagulandone perfettamente le sensazioni e le aspettative. Come nel patto dei 3 (o 4) moschettieri di Dumas, vale il principio uno per tutti (e tutti per uno): il singolo rappresenta la totalità e la totalità si riconosce nel singolo. Lo stesso avviene nel caso di P e NP. Esistono davvero problemi S di NP capaci di rappresentare tutti gli altri loro confratelli, nel senso che – per dirla in modo rozzo e vagamente impreciso – se S appartiene a P, allora P=NP, ovvero, per usare termini più rigorosi e corretti, qualunque problema S' in NP si può tradurre in modo rapido in S, e quindi, se S ammette un algoritmo veloce di soluzione, anche S' lo eredita. Questi problemi S' si dicono NP-completi. Dunque, S è NP-completo se valgono due condizioni:

  • S ∈ NP;
  • per ogni problema S' ∈ NP , esiste un procedimento effettivo che traduce in tempo polinomiale ogni istanza di S' in una istanza di S (quest'ultima condizione si sintetizza dicendo che S è NP-arduo ).

Dunque, per provare che P=NP, basta dimostrare che uno tra i possibili problemi NP-completi ammette un algoritmo rapido di soluzione: si applica cioè il principio dei moschettieri ( uno per tutti ).
Il primo problema che fu provato NP-completo (da Cook, nel 1971) riguarda una questione di Logica elementare, che ha il nome di Problema della Soddisfacibilità della Logica Preposizionale ma che è anche conosciuto con la sigla (più immediata) SAT. Lo discuteremo nel prossimo paragrafo in modo che ci auguriamo accessibile anche ai non addetti ai lavori. Ma, come vedremo sempre nello stesso paragrafo, SAT è solo il capostipite di una dovizia di esempi NP-completi.
La situazione, che si viene così a configurare per ognuno di questi problemi S, è curiosa ed intrigante. Infatti, per ciascuno di essi, è facile verificare una soluzione (se la si conosce) ma è difficile trovarla, anzi è così impegnativo come risolvere l'intera questione P=NP. Non sorprenderà che una tale disparità di situazione sia ottima fonte di ispirazione per certe esigenze della moderna crittografia. La nostra epoca, infatti, va utilizzando sempre più intensamente le potenzialità dei calcolatori per eseguire pagamenti, certificazioni, firme, sottoscrizioni “virtuali”, cioè telematiche. Operazioni così delicate richiedono ovviamente strumenti capaci di garantire la privacy degli utenti e metterla al riparo da eventuali malintenzionati. In particolare, nasce l'esigenza di criptare i messaggi e i documenti trasmessi in rete in modo che la decodifica sia facile per l'interlocutore desiderato, ma complicata e difficile ai pirati di Internet. Le caratteristiche dei problemi NP-completi sembrano corrispondere perfettamente a questa situazione. L'analogia può dunque ispirare adeguati sistemi crittografici. Illustreremo nel sesto paragrafo un esempio di queste applicazioni, che del resto verranno ulteriormente discusse alla fine del lavoro.
Completiamo questa sezione dicendo che il problema della primalità ovviamente non è NP-completo, a meno che P=NP; sta infatti in P. Quanto alla fattorizzazione, la questione è aperta ma criptosistemi largamente diffusi come il famoso RSA (si veda ad esempio in [7]) si basano sulle difficoltà che ancora la riguardano e ne distinguono tempi minimi di soluzione e verifica.

 

Un problema di Logica elementare

 


Aristotele particolare - Raffaello Scuola di Atene
Il problema di cui si parla nel titolo è quello della Soddisfacibilità della Logica Proposizionale. A dispetto del nome vagamente altisonante, si tratta di questione relativamente semplice. Lo introduciamo come un gioco enigmistico, secondo l'approccio di [8]. Si tratta di considerare il nostro usuale alfabeto a, b, c ,…, o anche una sua estensione potenzialmente infinita, e di formarvi parole (dunque sequenze ordinate finite di lettere) nel rispetto delle seguenti regole:

 

  • ogni parola può accogliere lettere sia maiuscole che minuscole, A, a, B, b e così via (dunque SteLla , oppure sTELLa ,o StelA sono almeno inizialmente ammesse);
  • non sono comunque consentite ripetizioni della stessa lettera nella stessa parola (il che esclude, tra gli esempi appena proposti, sTELLa , che contiene L due volte);
  • neppure la presenza di una lettera sia maiuscola che minuscola nella stessa parola è permessa (e dunque anche SteLla va rifiutata).

Chiamiamo normali le parole che si ottengono in questo modo: così StelA , LEtra , mATeiC , PriSTeM sono parole normali. Il gioco consiste allora in quanto segue: dato un qualunque insieme finito di parole normali, vogliamo sapere se esiste una parola normale che interseca tutte quelle dell'insieme, nel senso che condivide con ciascuna di esse almeno un simbolo.
A scanso di equivoci, sottolineiamo che il problema non richiede espressamente di trovare una soluzione ma semplicemente di valutare se una soluzione è possibile oppure no. Adesso mescoliamo un po' le carte e vediamo come il nostro gioco di maiuscole e minuscole vada a nascondere qualcosa di teoricamente più rilevante. Interpretiamo ogni lettera minuscola come una affermazione, ad esempio:

a come “questo articolo mi piace”, s come “domani piove” e la corrispondente maiuscola come la negazione di quella affermazione, dunque:
A
come “questo articolo non mi piace” , S come “domani non piove”.

Immaginiamo poi che ogni parola normale vada a rappresentare la disgiunzione delle proposizioni (affermate o negate) associate alle sue lettere: così sA significa “domani piove” oppure “questo articolo non mi piace” (che può anche intendersi “se questo articolo mi piace, domani piove” ). Infine, interpretiamo un insieme finito di parole normali con la congiunzione delle disgiunzioni che le singole parole nascondono. Così, se t traduce l'affermazione “prendo l'ombrello”, l'insieme di sA e t rappresenta: “se questo articolo mi piace, domani piove” e “prendo l'ombrello”.
Non è difficile convincersi che, in questa ottica, il semplice esercizio di trovare una parola normale che condivide almeno un simbolo con ogni parola data va a nascondere qualcosa di apparentemente più impegnativo e cioè individuare un'opinione coerente che vada a trovare in ciascuna delle parole coinvolte almeno una proposizione (affermata o negata) con cui concorda. Il problema che ne risulta è, allora, quella questione classica di Logica elementare cui accennavamo all'inizio del paragrafo.
Che cosa ha di così nascosto e misterioso questo problema (e dunque, per dirla in modo meno ufficiale e impegnativo, la ricerca di parole normali capaci di intersecare un certo insieme dato)? Non è difficile convincersi che la nostra questione appartiene a NP : se conosciamo una soluzione adeguata ad un certo insieme, verificarla – controllare cioè che condivida almeno un simbolo con ciascuna delle parole dell'insieme– non è esercizio troppo lungo da svolgere. Non è invece evidente che il problema appartenga a P, ammetta cioè anche un algoritmo rapido di ricerca delle soluzioni. Ad esempio, se l'insieme di partenza ha parole che coinvolgono complessivamente n lettere (minuscole o maiuscole), le possibili soluzioni e dunque le parole che possono formarsi, anche a meno di permutazioni, con queste n lettere, sono 2n visto che ogni lettera può comparire (almeno a priori) maiuscola oppure minuscola. Dunque, il numero dei controlli richiesti da un esame pignolo di tutti i possibili candidati, al fine di valutare che almeno uno di essi funzioni, richiede 2n controlli: troppi, visto che n è indice della lunghezza dell'insieme input.


Kurt Gödel
Questo non esclude, in linea di principio, che altri procedimenti più profondi e brillanti possano ottenere esiti più veloci. Ma, nel 1971, Cook dimostrò un risultato fondamentale e, per certi versi, sorprendente, e cioè che trovare un algoritmo rapido (=polinomiale) per SAT equivale a risolvere positivamente il problema P=NP.

In dettaglio: per ogni problema S in NP, esiste un procedimento effettivo che traduce in tempo polinomiale ogni input relativo ad S in una istanza di SAT in modo tale che l'input originario appartiene a S se e solo se la corrispondente istanza di SAT ha soluzione positiva. Conseguentemente, se SAT ammette un algoritmo rapido di soluzione, lo stesso vale per ogni S in NP (tramite la precedente riduzione a SAT). L'idea della dimostrazione di Cook è semplice e brillante, tende infatti a codificare ed esprimere gli input del generico problema S tramite condizioni su lettere maiuscole e minuscole che formino istanze di SAT. Naturalmente, la sua realizzazione richiede l'uso di ingegnose tecniche combinatorie.
Dunque SAT, per quanto elementare possa sembrare il suo enunciato, accoglie in sé tutta la complessità della questione P=NP : è NP -completo, come preannunciato nel paragrafo precedente. Più precisamente, SAT è il primo caso storicamente provato di problema NP-completo. Tuttavia, non è l'unico. Anzi, SAT è il capostipite di una lunga progenie di esempi. Già nel 1972, dunque un anno dopo il Teorema di Cook, Karp propose una lista di 21 problemi NP-completi S. La strategia per riconoscerli tali è, tutto sommato, meccanica e ripetitiva. Si tratta di mostrare che SAT (oppure qualche altro esempio chiave già riconosciuto come NP-completo) si può ricondurre con una procedura polinomiale a S: tramite SAT, o comunque tramite l'altro esempio di riferimento, tutto NP si riduce di conseguenza in tempo polinomiale a S.
Si prova in questo modo che anche 3SAT – la versione di SAT che coinvolge soltanto parole normali che si compongono di esattamente 3 lettere– condivide la NP-completezza di SAT.
Dunque, il problema che si ricava riformulando la questione introdotta all'inizio del paragrafo con parole di sole 3 lettere include l'intera complessità di P=NP. In effetti, l'intero SAT può essere codificato con opportuni argomenti combinatori nel contesto di parole con 3 lettere. Lo stesso vale ovviamente quando le lettere coinvolte in ogni parola sono più di 3. Come detto, 3SAT compariva già nella lista di Karp del 1972.
Invece, 2SAT –la variante con parole di 2 lettere– appartiene a P. Vediamo perché. Abbiamo un insieme finito arbitrario di parole normali con 2 lettere (maiuscole o minuscole) e vogliamo sapere se c'è una parola normale che le interseca tutte. Anzi, cerchiamo un algoritmo che sappia risponderci in tempo rapido (in relazione alla grandezza dell'insieme finito a cui viene applicato) e non dipenda, ovviamente, dall'insieme particolare per cui lo si usa. Consideriamo la prima lettera in gioco: a, senza perdita di generalità. Possiamo crederla (ed accettare a nella possibile soluzione) oppure rifiutarla (ed accogliere allora A ). Scegliamo a, tanto per fissare le idee. A questo punto, tutte le parole che contengono a sono intersecate. Quelle che invece includono A (diciamo, Ab o AD ) non possono più condividere A; così la possibile soluzione deve accogliere b e D. Ma a questo punto il ragionamento appena condotto si può ripetere per b e D: si va a creare, per questa via, una specie di effetto domino al termine del quale si va in tempi brevi ad individuare, oppure escludere, l'esistenza di una soluzione.
La passione per i problemi NP -completi non si è certo arrestata con la lista di Karp. Negli anni successivi (e fino ad oggi), da un lato si sono approfonditi vari aspetti teorici della NP-completezza, senza riuscire tuttavia a risolvere la questione P=NP, cioè a trovare un algoritmo rapido per un problema NP-completo; dall'altro, si sono scoperti sempre nuovi esempi, tutti con un ovvio fondamento combinatorio, ma distribuiti in svariate aree della ricerca scientifica: in Matematica, in Informatica, in Biologia, in Chimica, in Enigmistica ed ancora in altri settori. Libri classici, come [5] trattano in dettaglio la NP-completezza e ne illustrano gli esempi chiave. La lista dei problemi NP -completi è costantemente aggiornata nel Journal of Algorithms, a cura di D. Johnson, ed anche da svariati siti Internet. Citiamo per tutti:

http://www.csc.liv.ac.uk/~ped/teachadmin/COMP202/annotated_np.html,

il quale propone e discute un centinaio di problemi. Noi ci limiteremo, nelle pagine che verranno, ad illustrarne alcuni che ci sembrano simpatici e rappresentativi.

 

Guerre stellari

 

Nelle nostre famiglie terrestri è già talora difficile andare d'accordo in due, marito e moglie. Figuriamoci allora quanti e quali contrasti, e forse guerre, potrebbero sorgere in qualche mondo lontano, nel quale i sessi ufficiali fossero 3 o più di 3 e dunque i matrimoni si combinassero in 3 o più di 3.
In effetti, la situazione è considerata e descritta con tocco crepuscolare e delicato nel libro Neanche gli Dei (The Gods Themselves) del maestro della fantascienza Isaac Asimov.


Isaac Asimov
A menti più superficiali e terrene (?!?) verrà comunque da pensare che anche le agenzie matrimoniali dovrebbero risentire di qualche maggiore difficoltà, di tipo sia combinatorio che caratteriale. In effetti, il Problema del Matrimonio nei comuni 2 sessi può formularsi come segue. Sono dati:
  • due insiemi finiti U e D di ugual cardinalità q (l'insieme degli uomini e quello delle donne );
  • una relazione S nel prodotto cartesiano U×D di tutte le possibili coppie (uomo, donna): la relazione di reciproca attrazione o simpatia .

Si tratta allora di combinare q matrimoni in modo da accontentare tutti gli uomini e le donne coinvolte e dunque determinare, se possibile, un sottoinsieme M di S (quello dei matrimoni, appunto), ancora di cardinalità q, in modo che ogni uomo ed ogni donna compaiano in una (ed una sola) coppia di M. A chi lavora nelle agenzie matrimoniali della nostra Terra, sarà consolante sapere che il Problema del Matrimonio a 2 Sessi, usualmente denotato 2DM (Two-dimensional matching), ha un procedimento veloce di soluzione: gli aspiranti sposi non dovranno aspettare troppo per coronare le loro aspirazioni (se mai è possibile coronarle). Ma, quando i sessi diventano 3, ad esempio nel mondo di Asimov, le cose si complicano. Infatti il Problema del Matrimonio a 3 Sessi (3DM, Three-dimensional matching) deve affrontare:

  • tre insiemi finiti A, B, C di ugual cardinalità q (corrispondente ai tre sessi possibili);
  • una relazione S nel prodotto cartesiano A×B×C di tutte le possibili terne (a, b, c): la relazione di reciproca attrazione o simpatia tra i 3 personaggi coinvolti.

Bisogna allora combinare q matrimoni in modo da accontentare tutti gli interessati e dunque determinare, se possibile, un sottoinsieme M di S (quello dei matrimoni, appunto), ancora di cardinalità q , in modo che ogni elemento di A, di B e di C compaia in una (ed una sola) terna di M. Ebbene, nessun algoritmo veloce di soluzione è conosciuto per 3DM (e per i problemi dei matrimoni in dimensioni superiori a 3). Anzi, se questo algoritmo ci fosse, potremmo dedurne P=NP nel senso illustrato nel precedente paragrafo: il Problema del Matrimonio a 3 Sessi è NP -completo (e dunque è forse bene che i sessi siano soltanto 2…).
Il riferimento ai numeri 2 e 3 non è una coincidenza casuale. Il lettore avrà già constatato, infatti, che la situazione che si va presentando per 2DM e 3DM corrisponde perfettamente a quella che distingue 2SAT da 3SAT. In effetti, ci sono opportune procedure che collegano in tempo polinomiale le istanze di nDM (per n=2, 3) a quelle per nSAT. Per tal via, 2DM preserva le prerogative di efficienza che ha 2SAT mentre 3DM si trova a condividere i limiti ed i dubbi degli algoritmi conosciuti per 3SAT. Del resto, 3DM compariva già nella lista di Karp del 1972.

 

Il commesso viaggiatore ed altre storie di grafi

 

Un concetto matematico facile da introdursi (ma non da studiarsi) e comunque utile nella formalizzazione di tanti problemi di carattere combinatorio, anche in Informatica e in altri settori scientifici diversi dalla Matematica, è quello di grafo. Nella versione più semplice, un grafo è un insieme G con una relazione binaria A (di adiacenza) simmetrica ed irriflessiva. Da un punto di vista intuitivo, possiamo immaginare gli elementi (o, come anche si dice, i vertici) a, b, … di G come possibili tappe di un itinerario stradale ed ogni coppia (a, b) ∈ A come una via diretta che collega a e b: strada a doppio senso, perché A è simmetrica, e con estremi tra loro diversi a≠b perché A è irriflessiva.
La nozione di grafo pare dunque molto facile ed accessibile. Si tratta comunque di impressione superficiale e menzognera. Infatti, proprio in ragione della loro semplicità, i grafi possono codificare qualunque struttura algebrica, anche apparentemente più complicata, quale potrebbe essere un gruppo, o un campo, ed addirittura accogliere per questa via l'intera complessità della Matematica. Non è allora stupefacente che, tra i problemi NP-completi, molti facciano riferimento proprio al concetto di grafo. Ci limitiamo qui a citarne quattro, fra quelli che compaiono nella lista di Karp, nell'ordine:

(a) Il Problema del Ricoprimento dei Vertici;

(b) il Problema del Clique;

(c) il Problema dell'Insieme Indipendente;

(d) il Problema del Commesso Viaggiatore (o del Circuito Hamiltoniano).

Vediamoli in dettaglio:

a), b), c) I dati di partenza dei tre problemi sono esattamente gli stessi: un grafo finito (G, A) ed un intero positivo k (minore o uguale del numero n dei vertici di G). In tutti e tre i casi, ci chiediamo se esiste un sottoinsieme di G di cardinalità al più k . Il criterio di ricerca di varia però a seconda del problema:

(a) chiede che sia quel che si dice un ricoprimento dei vertici di G e cioè che ogni percorso (a, b) in A ammetta almeno un estremo a o b in ;

( b ) invece domanda che ogni coppia di vertici distinti di sia congiunta da un percorso in A (si dice allora un clique);

(c) infine richiede che sia indipendente, in altre parole che nessuna coppia di vertici di sia congiunta da percorsi di A.

Non è difficile accorgersi che i tre problemi sono tra loro collegati. Infatti, un sottoinsieme di G è un ricoprimento dei vertici se e solo il suo complementare G–G´ è indipendente. Ambedue le condizioni, poi, equivalgono a chiedere che G–G´ sia un clique non in (G, A) ma nel grafo che se ne ottiene unendo proprio quelle coppie di vertici distinti che A lascia separati. In ciascuno dei tre casi, è facile convincersi che una eventuale soluzione , se conosciuta, può essere rapidamente controllata. Ma, quanto a decidere l'esistenza di , le cose si complicano: in linea di principio, i sottoinsiemi di G da coinvolgere nella ricerca sono tanti quanti il coefficiente binomiale

In effetti, i tre problemi sono –come detto– NP-completi. Ciascuno dei tre codifica in tempo polinomiale 3SAT (e trasmette ovviamente agli altri due questa proprietà).

(d) Il Problema del Commesso Viaggiatore si riferisce invece ad una questione più pratica, quella che può riguardare, appunto, un commesso viaggiatore che ogni mattina organizza l'itinerario giornaliero che lo porti da tutti i clienti previsti e poi lo riconduca a casa nel minor tempo possibile, evitando dunque di passare due volte dallo stesso punto e dalla stessa strada. In termini rigoro si, possiamo immaginare di avere un grafo G (in cui informalmente i vertici rappresentano l'abitazione del commesso viaggiatore e gli n distinti recapiti dei suoi clienti e i cui percorsi sono le strade che collegano tutte queste possibili tappe) e ci chiediamo se è possibile elencare gli elementi di G: g(0), g(1), …, g(n) in modo tale che (g(i), g(i +1))∈ A per ogni i < n e finalmente (g(n), g (0))∈A (in altre parole, assumendo che g(0) denoti la casa del commesso e g(i) quella del cliente i -mo per ogni i=1, …, n, devono esserci strade dirette che congiungono g(i) a g(i +1) per i<n e poi l'ultimo indirizzo g(n) a g (0), evitando così all'affaticato commesso di dover percorrere più volte parte del suo itinerario). Dispiace dover comunicare al nostro commesso viaggiatore, e a chiunque fosse interessato a situazioni analoghe, che la questione (ufficialmente denominata del Circuito Hamiltoniano ) è NP-completa perché ad essa si può ridurre in tempo polinomiale il Problema del Ricoprimento dei Vertici, sopra considerato.

 

Zaini, francobolli
e codici segreti

 

 

Il Problema dello Zaino è la questione che in genere ci affligge la notte prima della partenza per le vacanze: abbiamo uno zaino di volume V e vogliamo infilarci gli oggetti 0, 1, …, n-1, rispettivamente di volume v(0), …, v(n -1). Ognuno di essi ci pare, infatti, indispensabile per il buon esito delle nostre ferie. Ci chiediamo se è possibile sceglierne alcuni in modo da colmare esattamente lo zaino e dunque se esista un sottoinsieme I di {0, …, n -1} tale che

(intendiamo che V, v(0), …, v(n -1) ed ovviamente n siano interi positivi ed assumiamo poi che lo zaino non sia rigido e si presti ad essere deformato in ogni modo possibile, così che la soluzione dipenda solo dal volume degli oggetti coinvolti e non dalla loro figura).
L'esperienza comune ci insegna che la questione è tutto meno che semplice: in genere, la sera prima delle ferie, i tentativi si sprecano e le ore volano prima che gli oggetti siano finalmente sistemati, se mai lo sono, in modo soddisfacente. Spesso è il sonno, o la stanchezza, a dettare (o forse rinviare) la soluzione. Del resto, la difficoltà ha un suo logico fondamento visto che le possibili combinazioni di oggetti da infilare nello zaino sono tante quanti i sottoinsiemi di {0, 1, …, n -1 } , e cioè 2n.
Una versione più rassicurante e tranquilla del problema si riferisce ad una lettera da affrancare per un valore totale V e ad n francobolli 0, …, n -1 rispettivamente di costo v (0), …, v(n -1) tra i quali scegliere in modo tale da raggiungere esattamente il valore V. Stavolta la ricerca può apparire meno traumatica. Pur tuttavia, da un punto di vista matematico, la questione è esattamente la stessa e può prevedere un numero esponenziale di tentativi prima di ottenere, se possibile, la giusta soluzione.

Non v'è dubbio che il problema, comunque lo si voglia presentare, stia in NP : se conosciamo l'opportuno insieme I, verificare che (in relazione agli input V, n, v(0), …, v(n -1)) è controllo rapido di poca fatica. Ma il Problema dello Zaino (Knapsack secondo la terminologia ufficiale) è anche NP-completo: trovare una procedura efficiente di soluzione equivale a risolvere l'intera questione P=NP (e chi ci riuscisse potrebbe passare in vacanza tutto il resto della sua vita). In effetti, il Problema dello Zaino compare già (almeno implicitamente) nella lista di Karp; una tecnica per provarne la NP-completezza consiste nel riferirsi a 3DM e nel codificarlo in tempo polinomiale appunto in Knapsack. Il Problema dello Zaino ha, tra l'altro, dirette applicazioni alla moderna Crittografia. Le illustriamo brevemente, anche per riprendere ed approfondire con questo esempio il discorso già iniziato nel secondo paragrafo sui collegamenti tra P = NP e la Crittografia.

Osserviamo anzitutto che il Problema dello Zaino può avere talora rapida soluzione, ammesso che la sequenza v(0), …, v(n -1) sia opportunamente costruita. Ammettiamo, ad esempio, che v(0), …, v(n -1) sia supercrescente, cioè tale che, per ogni i<n, v(i) sia maggiore della somma dei volumi degli oggetti che lo precedono, . Così 2, 3, 7, 15, 31 è supercrescente perché 2<3, 2+3<7, 2+3+7<15 e 2+3+7+15<31 mentre la sequenza (crescente) 2, 5, 4 non lo è perché 2+4 non è minore di 5. È facile trovare algoritmi rapidi di soluzione per il Problema dello Zaino per sequenze supercrescenti. Infatti, supponiamo che v(0), …, v(n-1) formino una tale sequenza (e fissiamo anche V). Consideriamo, per cominciare, v(n-1). Se v(n-1)>V, dobbiamo evidentemente escluderlo dallo zaino ma, se v(n-1) è invece minore o uguale a V, dobbiamo obbligatoriamente inserirlo e coinvolgerlo nella eventuale soluzione: v(n-1) non può essere infatti sostituito dalla somma dei volumi restanti, che gli è minore per ipotesi, e dunque non riesce a raggiungere il valore V e riempire in tal modo lo zaino.
Dunque, se c'è soluzione, v(n-1) vi partecipa. A questo punto, consideriamo v(n -2) e confrontiamolo con il volume complessivo restante (ancora V se v(n-1) è stato escluso, Vv(n-1) altrimenti), ripetendo la procedura. Applicando questo metodo, recuperiamo alla fine una soluzione del problema, se esiste.
Anzi, si può osservare che la soluzione, se c'è, è anche unica. Ad esempio, consideriamo V=24 e la sequenza supercrescente di sopra 2<3<7<15<31. Siccome 31>24>15, si comincia con l'escludere v(4)=31 e coinvolgere v(3)=15. A questo punto, si calcola il volume residuo 24-15=9 e si nota che v(2)=7<9, ammettendo di conseguenza v(2) nell'eventuale soluzione. Da 9-7=2< 3, si deduce finalmente che v(1) va escluso e v(0) va coinvolto. Si conclude che il problema ha, in questo caso, soluzione 2, 7, 15.
In conclusione, il Problema Supercrescente dello Zaino ha un algoritmo rapido di soluzione mentre non si conosce nessuna procedura veloce per il Problema generale dello Zaino (ed anzi si paventa che non ci sia). La situazione si presta ad applicazioni crittografiche. Per introdurle, fissiamo anzitutto il nostro contesto. Abbiamo due interlocutori A e B che vogliono comunicare tra loro in modo sicuro, senza che i loro messaggi siano intercettati e soprattutto capiti da un qualche malintenzionato C. Conseguentemente A cerca di cifrare le sue comunicazioni a B in modo che B possa rapidamente decodificarle, ma C non sappia infrangerle in alcun modo. Possiamo anche immaginare che il messaggio di A a B si componga di sequenze di lunghezza n di bit 0 o 1.

A questo proposito, notiamo che il Problema dello Zaino si può riformulare come segue: fissati V, n, v(0), …, v(n-1), possiamo cercare, anziché un sottoinsieme I di {0, …, n -1} tale che una sequenza ( e0, …, en-1) di bit 0 o 1 per cui (basta intendere che I è formato proprio dagli indici i<n per cui ei=1). Risolvere il problema per un dato input V, n, v(0),…, v(n -1) significa decidere l'esistenza di una tale sequenza ( e0, …, en-1).

Ritorniamo allora ai messaggi di B e A . Una possibile strategia, che A può seguire per organizzare il suo criptosistema, consiste nello scegliere anzitutto una sequenza supercrescente v(0),…, v(n-1). Ci sono semplici metodi per generarla. Ad esempio, A può prendere n +1 interi positivi arbitrari z(0),…, z(n -1), z(n) e calcolarsi: v(0)=z(0), v(1)=v(0)+z(1), per ogni i<n

(che formano ovviamente una sequenza supercrescente), anzi computare anche:

Ad esempio, gli interi positivi 2, 1, 2, 3, 4, 2 generano in questo modo la sequenza supercrescente 2, 3, 7, 15, 31 di cui sopra (ed inoltre m = 60). A questo punto, A maschera la sequenza prodotta v(0), …, v(n-1) moltiplicandone gli elementi modulo m per un qualche intero a primo con m e dunque invertibile modulo m. Nell'esempio, si può scegliere a=7 (infatti 7 è primo con 60 ed il suo inverso modulo 60 è 43) ed ottenere da 2, 3, 7, 15, 31 la nuova sequenza 14, 21, 49, 45, 37 (modulo 60) che non è più supercrescente, perché la moltiplicazione per 7 ha rimescolato (modulo 60) l'ordine degli elementi coinvolti: ad esempio 31 · 7 = 217 è congruo a 37 modulo 60. In generale, scelto a, A computa anzitutto l'inverso a' di a modulo m (operazione facile e veloce, grazie a metodi elementari di Teoria dei numeri) e poi soprattutto la sequenza w(0), …, w(n-1) definita ponendo, per ogni i<n, 0<w(i)<m e w(i) congruo ad a·v(i) modulo m (cioè v(i) congruo ad a ´· v (i) modulo m ). Ovviamente, la nuova sequenza w(0), …, w(n -1) può non essere supercrescente ed anzi A avrà comunque cura che non lo sia.
A questo punto, A comunica a B (ed anzi divulga a tutti gli interessati) w (0), …, w(n-1) (la chiave pubblica di codifica da utilizzare per scrivergli) e mantiene gelosamente segreti m, a e v(0), …, v(n-1) (che costituiscono la sua chiave privata di decriptazione).
La codifica, l'invio e la decodifica di un eventuale messaggio avvengono come segue. Come detto, l'interlocutore B lo scrive sotto forma di sequenze (e0, …, en-1) di lunghezza n di bit scelti tra 0 e 1. Per ogni sequenza, B calcola e lo trasmette ad A. Con le informazioni segrete in suo possesso, A può recuperare (e0, …, en-1) nel modo che adesso descriviamo. Dapprima, A moltiplica il messaggio cifrato ricevuto W per l'inverso a' di a modulo m e poi calcola il resto di questo prodotto nella divisione per m; poi osserva:

Siccome tanto V che sono interi positivi minori di m , A deduce =V. Allora A , ricavato , decodifica facilmente (e0, …, en-1) perché la sequenza v(0), …, v(n -1) è supercrescente.

Invece un pirata C, che pure riesca ad intercettare W ed intenda recuperare (e0, …, en-1), conoscendo soltanto la sequenza (non supercrescente) w (0), …, w(n -1), si trova di fronte ad una istanza del Problema generale dello Zaino con tutte le difficoltà che ne derivano.
In conclusione, Knapsack (ed altri problemi NP-completi) possono suggerire sistemi crittografici per lo scambio sicuro di messaggi. Quello appena descritto è un semplice esempio (ideato da Merkle ed Hellman alla fine degli anni Settanta).
Ad onor del vero, dobbiamo confessare che si tratta di un criptosistema troppo semplice, non affidabile né sicuro. In effetti, già nel 1982, pochi anni dopo la sua pubblicazione, ci fu chi osservò come le sequenze pubbliche w (0), …, w(n-1), pur non essendo supercrescenti come quelle private, hanno comunque una natura particolare (si ottengono da sequenze supercrescenti moltiplicando per un fattore costante modulo un intero m pure costante) ed ammettono conseguentemente un loro specifico algoritmo rapido di soluzione che, pur senza avere la pretesa di soddisfare il Problema generale dello Zaino, riesce comunque ad infrangerne con successo questo caso particolare. Va anche detto che, a seguito di questa osservazione, si studiarono perfezionamenti del criptosistema di Merkle ed Hellman capaci di restaurarne l'affidabilità.

 

L'orario delle lezioni

 

Il Problema dell'Orario è una di quelle antipatiche incombenze cui occorre far fronte all'inizio di ogni anno accademico o scolastico. Un disgraziato docente viene delegato a risolverlo e si trova così di fronte alla difficoltà di preparare un orario delle lezioni che concili le esigenze dei colleghi, quelle degli studenti e quelle ovvie di rispetto dei regolamenti didattici. L'impegno è ostico e quasi mai il risultato riesce ad accontentare tutti gli interessati, a prescindere dalla buona volontà e dalla capacità di chi si trova a svolgere la sfortunata incombenza. Del resto, che il problema non sia affatto semplice è anche testimoniato dal fatto che (allo stesso modo degli esempi elencati nei precedenti paragrafi) è NP-completo: non si conosce, in particolare, un algoritmo rapido che riesca a risolverlo in modo soddisfacente. Vediamo perché. Ovviamente, per apprezzare meglio il risultato di NP completezza, dobbiamo impostare in modo più preciso e matematico i termini della questione. Supponiamo allora che il Dipartimento (o l'Istituto) coinvolto ammettano n docenti e m classi di studenti ( n e m sono parte dell' input della questione). Sono inoltre fissati:

  • l'insieme finito O delle ore settimanali in cui è prevista l'attività didattica;
  • per ogni i=1, …, n, l'insieme P(i) delle ore in cui il professore i-mo è disponibile ad insegnare (così P(i) ⊆ O;
  • per ogni j =1, …, m, l'insieme C(j) delle ore in cui la classe j-ma è disponibile ad ascoltare la lezione (dunque anche C(j) è sottoinsieme di O);
  • per ogni i e j come sopra, il numero L(i, j) delle ore che il docente i è tenuto a svolgere alla classe j.

Tutti questi dati formano l'input del nostro problema. Ci chiediamo se sia possibile combinare un orario adeguato a queste premesse. In termini rigorosi, possiamo formalizzare questo obiettivo tramite una funzione:

f : {1, …, n}×{1, …, m} × O →{ 0, 1 }

(dove, per i=1, …, n , j=1, …, m ed o in O, f (i, j, o)=1 significa informalmente che l'insegnante i insegna alla classe j nell'ora o, e f (i, j, o)=0 l'esatto contrario) cui poniamo le seguenti richieste:

(a) per ogni scelta di i, j, o , se f(i, j, o)=1, allora o deve stare in P(i) e in C(j) (cioè deve appartenere all'insieme delle ore dichiarate disponibili dal professore i e dalla classe j);

(b) per ogni i e j, la somma dei valori f(i, j, o) al variare di o deve eguagliare L(i, j) (in altre parole, il numero complessivo delle ore di lezione che il professore i svolge alla classe j deve essere quello previsto dai regolamenti);

(c) per ogni j ed o, la somma dei valori f (i, j, o) al variare di i deve essere al massimo 1 (cioè non deve accadere che la stessa classe abbia alla stessa ora due docenti diversi);

(d) per ogni i ed o, la somma dei valori f (i, j, o) al variare di j deve essere al massimo 1 (cioè non deve accadere che lo stesso professore debba fare lezione alla stessa ora in due classi diverse).

Il Problema dell'Orario , usualmente denotato TT (dalle iniziali delle parole inglesi Time Table), chiede se esiste una tale funzione. È facile verificare che TT appartiene a NP: un algoritmo che ne verifica l'eventuale soluzione f si limita a controllarne le proprietà a), b), c) e d) e può svolgere in tempo rapido le relative computazioni. D'altra parte, esaminare tutte le possibili f richiede, almeno a priori, tempo esponenziale in n , m e nella cardinalità |O| di O, perché 2n·m·|O| è il numero delle funzioni coinvolte. Naturalmente, questo non esclude a priori che esistano algoritmi rapidi di soluzione.
Nel 1976, Even, Itai e Shamir provarono, nuovamente utilizzando un'ingegnosa riduzione a 3SAT, che TT è NP-completo: dunque, escogitare una procedura generale capace di determinare rapidamente in quali casi si può compilare un buon orario, soddisfacente per tutti gli interessati, è difficile come risolvere P=NP. Chi ci riuscisse risolverebbe la questione chiave dell'Informatica teorica e potrebbe così esimersi dal preparare orari per tutto il resto della propria vita. Dettagli della dimostrazione si trovano in [4].

 

Enigmistica

 

Gli appassionati di enigmistica saranno contenti di sapere che anche il gioco del sudoku, così di moda negli ultimi tempi, è NP-completo: dunque non dovranno vergognarsi troppo quando la soluzione tarda ad arrivare.

Sono stati due ricercatori giapponesi, Yato e Seta, a dimostrare questa sorprendente proprietà nell'articolo [9]. Ecco qualche maggior dettaglio a questo proposito. Come tutti sanno, il problema del Sudoku si può formalizzare nei termini che seguono:

  • sono dati un intero positivo n e una griglia di n2×n2 caselle, suddivisa in n2 quadrati di lato n, ciascuno composto da n×n caselle;
  • alcune delle caselle sono riempite da un numero intero tra 1 e n2;
  • si devono riempire le caselle bianche in modo tale che ogni riga, ogni colonna e ogni quadrato di lato n contenga esattamente tutti gli interi da 1 a n2.

Ebbene, Yato e Seta hanno mostrato come tradurre SAT, e cioè il capostipite dei problemi NP-completi, nei termini di questo gioco combinatorio; ne hanno dedotto che anche il sudoku viene a ereditare da SAT la proprietà di NP-completezza.
Del resto, molte altre questioni di enigmistica condividono col Sudoku questa imbarazzante proprietà.

 

La Matematica
non guasta mai

 

Ci sono poi problemi NP-completi legati alla Matematica. In realtà, tutte le questioni elencate nei precedenti paragrafi riguardano sostanzialmente la Matematica, se non altro perché in linguaggio matematico possono essere formalizzate. Ma, in genere, quando si parla di Matematica (almeno nella accezione popolare del termine), si intendono numeri ed equazioni. Consideriamo allora un classicissimo sistema di equazioni, magari a coefficienti interi, e chiediamoci se ammette o no soluzioni. Ovviamente, dobbiamo preliminarmente specificare dove cerchiamo queste radici, se nello stesso anello Z degli interi o tra i razionali, i reali o addirittura i complessi. La risposta naturalmente può variare a seconda dell'ambiente in cui la cerchiamo.
Ciò premesso, lasciamo al sistema la più ampia libertà circa il numero delle equazioni e delle incognite o il grado dei polinomi coinvolti. Dunque, il problema ammette come input un sistema arbitrario di equazioni a coefficienti interi e tende a stabilire se esistono o no soluzioni reali, o complesse, o anche soltanto intere.

È facile notare che la questione che ne risulta è almeno NP ardua (a prescindere dal contesto in cui cerchiamo le radici). Infatti, il Problema dello Zaino vi può essere comunque codificato in modo rapido come segue. Consideriamo gli input (interi) V, v(0), …, v(n-1) di un'istanza di Knapsack. Vogliamo scegliere alcuni tra v(0), …, v(n-1) in modo tale che la loro somma sia proprio V; in altre parole, cerchiamo valori x0, …, xn-1 tra 0 e 1 per i quali valga l'equazione a coefficienti interi:

v(0)·x0+ … +v(n- 1)·xn -1= V

(per i < n , l'opzione xi=1 corrisponde ad includere v(i) tra gli oggetti selezionati per formare V; l'alternativa xi=0 significa escluderlo). La restrizione di xi ai valori 0,1 si traduce, per ogni i<n , nell'altra equazione xi·(xi–1)=0. Così, l'esistenza di una soluzione per il Problema dello Zaino si traduce nell'esistenza di una soluzione (intera, e dunque anche reale e complessa) al sistema formato in questo modo.
Siccome Knapsack è NP-completo, la questione che ne risulta è almeno NP-ardua, come già detto. Non è però chiaro se sia anche NP-completa, cioè se stia in NP. Il motivo del dubbio è chiaro. Consideriamo, infatti, il caso dei reali. Dobbiamo verificare l'esistenza di soluzioni reali del sistema. La prima idea che viene in mente è ovviamente quella di prendere una possibile soluzione e, appunto, controllare che funzioni. Ma c'è un guaio: i valori coinvolti sono, appunto, reali ed è oggettivamente difficile proporre un numero reale (con la sua infinita rappresentazione decimale) ad un computer. Il contesto continuo dei reali lega male con l'ambiente discreto che i calcolatori usualmente trattano. In verità, un computer non sa neppure controllare se un reale è uguale o no a zero. Ne scorre infatti le cifre intere o decimali ma, quand'anche giunga a leggerne migliaia, o milioni, ed a verificare che sono tutte uguali a 0, non può prevedere se le successive continuino ad annullarsi, oppure no. Il controllo dell'esistenza di soluzioni ha, quindi, inaspettate complicazioni e deve percorrere altre strade. Allo stato attuale delle conoscenze, si può solo dire che il problema dell'esistenza di soluzioni reali per sistemi a coefficienti interi è nella classe che in Teoria della Complessità si denota PSPACE e corrisponde ai problemi che si risolvono in spazio al più polinomiale, che cioè un calcolatore è capace di risolvere utilizzando un numero di locazioni di memoria limitato polinomialmente rispetto alla lunghezza dell' input. Della classe PSPACE, è noto che include NP ma non si sa se propriamente.
Se poi ci interessano soluzioni complesse, la questione ha risvolti ancora più intriganti. Il relativo problema (esistenza di soluzioni complesse per sistemi a coefficienti interi) è, ovviamente, NP-arduo ma, di nuovo, non si sa se sta in NP. È, invece, certamente collocato nella classe dei problemi AM, quelli che hanno procedure rapide capaci, se non di risolvere, almeno di convincere con piccola probabilità di errore dell'esistenza di soluzioni. A e M stanno qui a rappresentare le iniziali di Artù e di Merlino. Si immagina, infatti, che Merlino, da bravo mago, sappia tutto e che la sua autorità sia sufficiente (senza bisogno di troppe spiegazioni) a persuadere il giovane e fiducioso Artù. La classe AM è un'altra estensione (non si sa se propria) di NP , a sua volta inclusa in PSPACE .

Se dunque la classica esigenza di risolvere equazioni non corrisponde a problemi dichiaratamente NP-completi (almeno allo stato attuale delle conoscenze), c'è comunque ampio spazio per esempi di NP-completezza tra questioni che emergono in modo naturale nell'ambito matematico. Ne proponiamo alcuni.

(a) (Equazioni quadratiche diofantine) Consideriamo il caso particolare di un'unica equazione ax2+by+c=0 con a, b, c interi positivi; cerchiamo soluzioni x, y ancora intere positive. Il nome del problema fa riferimento al grado 2 dell'equazione e al matematico alessandrino Diofanto. In generale, la questione generale di individuare radici intere per sistemi a coefficienti interi (che ha appassionato molti, a cominciare da Diofanto nell'antichità) è tutto meno che banale: l'abbiamo evitata nelle considerazioni precedenti, ma le dedicheremo il prossimo paragrafo. Nel nostro caso particolare, se conosciamo x e y, è facile controllare che funzionano; ma stabilirne l'esistenza è un altro discorso e sconfina, appunto, nella NP-completezza.

(b) (Congruenze quadratiche) Consideriamo ancora, come nel caso precedente, tre interi positivi a, b e c. Ci chiediamo stavolta se è possibile trovare un intero positivo x < c tale che a sia il quadrato di x modulo b , cioè valga la congruenza x2≡ a (mod b). Come si vede, siamo nel regno dell'Aritmetica e dell'Algebra classica. Ma la questione è, nuovamente, NP-completa.

(c) (Incongruenze simultanee) Stavolta abbiamo n coppie ordinate di naturali (a(i), b(i)) per i=1, …, n (anche n è un intero positivo arbitrario). Fissiamo a(i)<b(i) per ogni indice i; pensiamo dunque ad a(i) come ad un possibile resto della divisione per b(i). Un classico teorema di Aritmetica (il Teorema del Resto Cinese ) stabilisce condizioni sotto le quali possiamo trovare una comune soluzione intera x alle congruenze x ≡ a(i) (mod b(i)) per i=1, …, n. Afferma, in particolare, che x può trovarsi se b (1), …, b (n) sono a 2 a 2 primi tra loro. Ma a noi interessa qui, in un qualche senso, la situazione opposta, cioè se esiste un intero positivo x che non soddisfi nessuna delle precedenti congruenze x ≡ a(i) (mod b(i)). Potrà interessare sapere che il problema è NP-completo: facile da verificare, non si sa quanto rapido (o lento) da risolvere.

 

 

Un'attesa troppo lunga ed un'antipatica impossibilità

 

Se i problemi NP-completi condividono la fatalità di essere facili da controllare ma (almeno momentaneamente) lunghi da risolvere, ci sono questioni (matematiche e non) che trovano sorte anche peggiore. Ad esempio, ci sono problemi che certamente non hanno algoritmi rapidi né di soluzione né di verifica. Certe questioni algebrico-logiche sui reali e sui complessi (che estendono e complicano quella sulle radici reali, o complesse, dei sistemi di equazioni a coefficienti interi) richiedono tempo almeno esponenziale sia di soluzione che di verifica delle soluzioni. Una risposta può richiedere un'attesa proibitivamente lunga.

Ma c'è di peggio. Torniamo infatti al nostro sistema a coefficienti interi e chiediamoci se ammette o no soluzioni intere. Il problema è famoso. Interessò Hilbert, che lo pose al decimo posto nella lista di questioni rilevanti da lui proposte al Congresso internazionale di Parigi del 1900. Ebbene, un teorema di Matijasevic (cui contribuirono anche Davis, Putnam, Julia Robinson e altri) provò nel 1970 che la questione non ha algoritmo possibile (almeno se ci rifacciamo alla tesi di Turing e alla relativa definizione del concetto di algoritmo, cui abbiamo accennato nel secondo paragrafo). Non basta più avere la pazienza di aspettare un tempo esponenzialmente lungo o anche più esteso. L'attesa può essere infinita, perché la risposta non arriverà mai.

 

Che cosa ci riserva il futuro

 

Dopo aver proposto tanti curiosi esempi NP-completi, ci pare giusto accennare almeno un attimo alla possibile soluzione del problema P=NP. Come già insinuato nei paragrafi precedenti, la questione pare enormemente complicata e lontana dal chiarimento. I manuali di Informatica teorica e di Complessità (come [1] o [2], ad esempio) mostrano in abbondanza quale minuziosa analisi si è sviluppata per affrontarla e risponderle, quante e quali ulteriori classi di complessità (come PSPACE o AM ) sono state considerate per approssimare NP e possibilmente comprenderne la natura. Va poi aggiunto che certi sviluppi della Fisica, in particolare la nascita e la crescita di metodi e tecniche di Informazione quantistica, possono comunque alterare sostanzialmente il quadro del problema. Dal 1985 sono stati infatti introdotti a livello teorico i calcolatori quantistici, potenzialmente capaci di sviluppare in parallelo una quantità anche esponenziale di computazioni contemporanee e dunque di estendere la potenza del calcolo e di accelerarne le conclusioni. Ad esempio, esiste un recente (1994) ma già famoso procedimento quantistico di Peter Shor che, in teoria, sa decomporre in tempo rapido un numero composto N nei suoi fattori primi. È evidente che simili progressi possono diminuire sostanzialmente i tempi di computazione e dunque indurre a rivedere in modo sostanziale la questione P=NP ed anche le sue applicazioni a Crittografia ed informazione. Tuttavia l'ovvia premessa a tutti questi sviluppi è la possibilità pratica di costruire e far funzionare i calcolatori quantistici. Una loro realizzazione effettiva pare ancora ostacolata da serie difficoltà, sostanzialmente legate all'influsso che l'ambiente esterno può avere sul calcolatore e alla possibilità che ne alteri le computazioni. L'avvento effettivo dei metodi quantistici può quindi cambiare radicalmente il quadro di P e NP ma non sembra ancora prossimo ad attuarsi.

 

Bibliografia

 

 

[1] D. P. Bovet e P. Crescenzi, Teoria della Complessità Computazionale , Franco Angeli, 1991.

[2] F. Corradini, S. Leonesi, S. Mancini, C. Toffalori , Teoria della Computabilità e della Complessità , McGraw-Hill, 2005.

 

[3] K. Devlin , I Problemi del Millennio, Longanesi, 2004.

 

[4] S. Even, A. Itai, A. Shamir, “ On the Complexity of Timetable and Multicommodity Flow Problems” , SiamJ. Comp. 5, 1976, pp.691-698.

 

[5] M. Garey, D. Johnson , Computer and Intractability: A Guide to the Theory of Completeness, Freeman, 1979.

 

[6] A. Granville, “It is Easy to determine wheter a given Integer is Prime”, Bulletin American Mathematical Society , 42 (2005), pp. 3-38.

 

[7] S. Leonesi, S. L'Innocente, M. Marconi, C. Toffalori, “Primi e Segreti”, Lettera Matematica Pristem, 52, 2004 .

 

[8] D. Mundici , “ Algoritmi e Calcolabilità, Tesi di Church, Applicazioni della Logica all'Informatica”, L'Insegnamento della Logica , MPI-AILA, pp. 265-309.

 

[9] T. Yato, T. Seta, “Complexity and completeness of finding another solution and its application to puzzles”,IPSJ SIG Notes 2002-AL-87-2, IPSJ, 2002..