Ok,
ok, ok. Iniziamo un nuovo argomento.
Oggi e
vedremo altre classi di complessità.
Vedremo altre classi di complessità fino
a chiusura
e poi facciamo Mokizzam.
Ok. quello di cui ci siamo occupati
finora nella definizione
nella definizione di di classi
complessità,
quello che abbiamo visto finora sono
classi di complessità temporale,
cioè quanto tempo ci impiega un
algoritmo ad eseguire. Ok? Quello che
non ci siamo chiesti finora,
quanta memoria gli serve all'algoritmo,
ok? Perché sicuramente nel corso di
algoritmi e strutture dati avrete visto
la complessità spaziale, la complessità
temporale, eccetera. Oggi introduciamo,
ci concentreremo oggi e domani su classi
di complessità spaziale
e ok, non non scenderemo troppo nei
dettagli
e le collocheremo insieme insieme al
resto per vedere un po' come come si
si collocano. Ok?
Secondo voi
una macchina
che può usare,
ok? Abbiamo due macchine, una macchina M
e una macchina N. La macchina M
può usare tempo
polinomiale,
mentre l'altra macchina, la macchina N,
può usare spazio
polinomiale.
Intuitivamente ce n'è una più potente
dell'altra.
Sì.
Spazio polinomiale. Perché? La prima eh
per forza comunque come la prima per
forza come bo uno spazio policidiale,
quindi a tempo polinomiale, spazio
polinormi, la seconda ha solo spazio
polinormale, quindi può funzionare anche
esattamente. Ma queste cose le avate già
viste? No. Ok. Alr. Sì, l'ingip è
quello. Siccome noi abbiamo spazio
bounded e lo possiamo riutilizzare,
allora in principio possiamo rannare più
a lungo. Ok? Quindi sì, dato un certo
vincolo, quel vincolo se è dato sul
tempo o è dato sullo spazio fa fa la
differenza. Ok?
In realtà,
come vedremo
dopo,
noi abbiamo che P time intuitivamente,
adesso definiamo tutto più formalmente,
tempo polinomiale, P sta dentro P space,
che è la classe di spazio polinomiale.
Però, come tante di quelle cose
nell'area della complessità,
noi non sappiamo se sono distinte, cioè
noi sappiamo che P sta dentro P space,
ma non sappiamo se P space è
strettamente più grande di P. Ok? Qu è
un altro di quei risultati come P versus
NP. Sappiamo niente. Ok? Abbiamo questa
catena di contenimenti, come abbiamo già
visto l'altra volta, e ne vedremo altre
fra oggi e domani, tale per cui sappiamo
che, per esempio, fra Ptime ed exp time
sono due classi distinte, ma tutto in
mezzo c'è una marea di cose che da
qualche parte devono essere distinte se
tra Ptime ed exp time c'è un salto, però
noi non sappiamo dove e in particolare
crediamo che sia in tutti i passaggi,
che c'è un contenimento stretto, ma
nessun nessuno è mai riuscito a
dimostrare una cosa del genere. Forse
abbiamo tecniche di dimostrazione
sbagliata, forse stiamo guardando in
direzione sbagliata, non si sa. Sono
problemi aperti da 60-70 anni e nessuno
è mai riuscito ancora a chiudere le
questioni. Ok? Definiamo quindi in
maniera ehm
più formale le classi di complessità
spaziali, ok?
e
lo faremo assieme. Spero che vi
ricordiate un po' di definizioni di
classi di complessità temporali perché
ragioneremo assieme. Vi faccio vedere
come si fa a indurre, eh, perché alla
fine i ricercatori quando si inventavano
ste cose inducevano roba,
generalizzavano cose, quindi le vediamo
assieme per ragionare assieme e tireremo
fuori assieme le definizioni in maniera
tale che sia anche più semplice
ricordarcele perché ci siamo arrivati.
Ok? Allora, per prima cosa dobbiamo
introdurre un modello differente di
macchina di tuning,
altrimenti viene un po' complicato
definire la complessità spaziale. Si può
fare, però sulle classi di complessità
spaziali molto piccole che quelle che
vedremo oggi, domani ne vedremo di più
generiche, diviene difficile fare questo
genere di definizioni. Di conseguenza ci
serve un modello di macchine di Touring
leggermente diverso, ok? Che poi
generalmente se guardate la letteratura
moderna le macchine di Touring si
assumono in questo modo
perché poi per vari teoremi sono
equivalenti alle altre. Ok?
Allora, noi abbiamo una macchina di
Touring, si parla sempre di decisori,
quindi macchine di Touring che
rispondono sì, no? Poi più avanti nella
lezione ci servirà un trasduttore, però
è una facile generalizzazione.
Allora,
considereremo ora una macchina di
touring fatta in questo modo. Ha un
nastro di input
che è
un nastro di input
sulla quale la testina può andare avanti
e indietro, però è un nastro di sola
lettura. La macchina sul nostro input
non può fare niente, può solo leggere,
può spostare la testina dove vuole, può
spedirla a Milano se vuole, però non ci
può scrivere. La testina può andare
avanti e indietro, però il nastro di
input è un nastro di sola lettura.
Dopodiché c'è un nastro aggiuntivo
che è il nastro di lavoro. Nella
letteratura in inglese lo trovate
scritto workape.
Il nastro di lavoro è un nastro
infinito,
la testina del quale può andare avanti e
indietro come siamo abituati ed è un
nastro di lettura scrittura. Ok? Quindi
gli scarabocchi, la brutta copia, la
macchina di Touring la fa sul nastro di
lavoro, sul workpape. Ok? Questa è la
differenza rispetto alle macchine che
abbiamo visto finora. L'input non si può
scrivere, abbiamo un nastro, però lo
possiamo leggere, un nastro aggiuntivo
che è il nastro dei calcoli intermedi.
Si può leggere e scrivere e la testina
va avanti e indietro, quindi è standard.
Ok?
Machine, come si chiama?
Macchine di Touring. Sì. No, no, non
abbiamo un nome particolare. Le
assumiamo fatte così per vari risultati
che non andiamo a guardare. Siccome è
una macchina multinastro, questa alla
fine si si riduce a una macchina
mononastro. Perché facciamo questa
suddivisione?
Perché il vincolo dello spazio usato lo
metteremo solamente sul nastro di
lavoro. Ok? Ecco perché ci inventiamo
questa questa definizione
in maniera tale che il bound dello
spazio sia solo sul workape. Ok? Perché?
Perché andremo a vedere oggi tra un po'
una classe in cui una classe di
complessità in cui imporremo un
ridottissimo spazio. Gli algoritmi per
esempio che funzionano in spazio
logaritmico.
Però se noi andassimo a contare lo
spazio anche sul nastro di input e
l'input ce lo dobbiamo leggere tutto,
noi occuperemmo sempre spazio lineare
perché lo dobbiamo leggere tutto.
Allora, per poter
categorizzare questa classe piccolissima
che vedremo che è la classe dei problemi
in spazio logaritmico, allora ci serve
il nostro aggiuntivo in maniera tale che
il bound logaritmico viene dato sul
foglio di brutta. Ok? Puoi scrivere il
tema, ma sul foglio di brutta devi usare
poco spazio. Ok? Questa questa è la
cosa.
Allora,
definite queste macchine in questo modo,
introduciamo i concetti di computation
space, running space e via dicendo che
abbiamo fatto l'altra volta, ormai un
po' di settimane fa, per il tempo. Ok.
Definizione
computation
comp. Poi vedete un attimo
così vedo anch'io che vedete qua si è
spento. Vabboh.
computation
space
della
macchina
M su input
input W
è
il numero
di celle
distinte.
viste da M sul work tape,
mentre
processa
W. Ok?
Quindi il computation space
che è una cosa diversa dal running space
come il computation time è diverso dal
running time, quindi computation space,
come mi ricordo questi nomi? Computation
space. Siccome c'è computation fa
riferimento a una computazione
specifica, running space fa riferimento
alla funzione di bound. Ok? Quindi cos'è
il lo spazio di di computazione della
macchina M sulla stringa W?
È definito in maniera molto semplice.
Lanciamo la macchina M su W. Questa
macchina sposterà la testina sul nastro
di eh di lavoro. Il numero di celle
viste, nemmeno scritte, basta che la
testina ci arriva là. eh il numero di
celle viste su workta
dalla
macchina durante il processamento di W e
il suo computation space dm su W. Ok?
Molto semplice la definizione. Questa
definizione però assume che la macchina
M sia deterministica. Lo vedete da come
è stata scritta la definizione. Ok? ci
dobbiamo inventare una cosa per le
macchine non deterministiche. Secondo
voi così buttiamola là. Come potremmo
definire il computation space di una
macchina M non deterministica
su una particolare stringa W?
Dobbiamo generalizzare questa idea.
Prego. Eh, il massimo computation space.
[Musica]
Esattamente. Se M è non deterministica,
definiamo il computation space come il
massimo numero di celle visitate
dalla macchina su workta in qualsiasi
dei suoi branch di computazione. Ok?
Perché vi ricordo che una macchina non
deterministica ha vari branch di
computazione,
il suo computation space è il peggio che
fa, cioè quant'è lo spazio massimo che
la macchina usa in qualsiasi dei suoi
rami di computazione. Quello è in caso
di macchina M non deterministica, quindi
lo mettiamo fra parentesi, se non
deterministica
si prende
il massimo. Ok.
Alright. Altra definizione.
Una funzione
S che mappa
interi su interi
è una
space function.
Se S è strettamente positiva
è non decreasing.
Ok? Quindi abbiamo definito computation
space per U della computazione di una
macchina su una particolare string. Poi
abbiamo dato questo nome alle funzioni
intero verso interi. Noi diciamo che una
funzione S che mappa interi su interi è
una space function. Se S è strettamente
positiva è
ed è non decreasing è semplicemente un
nome. Vi faccio notare che la stessa
definizione era stata data per time
function, ok? Cioè, stiamo dando due
nomi alla stessa cosa, eh, giusto per
trovarci un po' con le cose. Ok,
definizione di running space, quindi
questa è una space function. Running
space
running
space
della macchina
M.
Ok, questa è una
un adattamento della definizione del
running time di una macchina di Turing.
Come lo possiamo definire?
Sì, prego.
Se è una funzione, è una function, se
per tutte le stringhe W parte qualcuno
il loro computation
space non eccede.
Esattamente. E quella è proprio la
generalizzazione di running space.
Allora, sia sn una space function,
il eh il running
space
di M è SDN
Se
per ogni
stringa
w
a parte
un numero
finito di s
che il computation
space
di M su w è bounded
da S
applicato sulla lunghezza di W. Ok?
Quindi è semplicemente un'estensione
del concetto di computation time, time
function, running time e speculare.
Semplicemente ci spostiamo sulla
definizione di spazio, ok? Quindi avremo
eh computation space, space functions,
running space, ok?
Esattamente come avevamo fatto per il
tempo che avevamo definito le classi
temporali, ok? Possiamo definire le
classi spaziali, le classi di
complessità spaziali. Sì, prego. Una
domanda. Decidendoation space abbiamo
come numero di celle dist.
Ma viste mi sembiamo le scritte o anche?
No, no, basta che ci ha spostato la
testina, perché la macchina potrebbe
fare questo giochino.
Sposto e torno indietro per contare.
Sposto, magari metto un marcatore su una
cella, sposto la testina per contare,
ok?
Non scrivo niente, quindi non uso
spazio, poi torno indietro fino a
trovare il marcatore. Eh, ok, in quel
modo ho imbrogliato, quindi basta che c
ci abbiamo spostato la testina. Ok.
Alright. Quindi, esattamente come
avevamo definito d time ed n time,
possiamo definire
D space ed n space. Ok, c'abbiamo
spazio. C'abbiamo spazio. Ok.
Secondo voi
Dpace
di SN
sia SN
una space function,
che cosa sarà mai di space?
L'insieme di cosa?
Ve lo ricordate cos'era? D time,
te lo dico io e poi generalizziamo. D
time per una certa funzione tdn
è l'insieme dei linguaggi
riconosciuti da macchine di touring
deterministiche in tempo big o di TDN.
Ok. Cosa potrà mai essere di Space?
insieme dei linguaggi riconosciuti da
una macchina diingerministica
con Running Space. Esattamente l'insieme
dei linguaggi tale per cui esiste una
macchina di Touring deterministica,
tale che il linguaggio di M e L è il
running
space
m e big o ds S di N.
Ok. Definizione abbastanza semplice.
S. Cos'è? N. N. Sì, è il mio modo
strambo di scrivere N.
C'ho una M e una N stranissimo. Vi ho
mai fatto vedere come scrivo minimum.
Eh, grandioso, eh. Ok,
ok.
Alri, next one.
Ah,
n space.
N space di s,
ok? Dove s n space function. Cosa mai
conterrà n space?
uguale macchine non determinisch
attentamente l'insieme dei linguaggi
tale per cui esiste
una macchina n non deterministica
tale che il linguaggio di N e L
è il running
Space
D n e big o di s n.
Ok,
quindi definita la complessità spaziale
delle macchine, abbiamo definito la
complessità
le classi di complessità spaziali.
Classi di complessità spaziale,
esattamente come le classi di
complessità temporale, sono insieme di
linguaggi. Insieme di linguaggi
caratterizzati dal fatto che possono
essere decisi da macchine di touring
all'interno di un certo un certo
quantitativo di risorse computazionali.
Nel caso delle classi temporali, la
risorsa computazionale è il tempo. Nel
caso della classi spaziali, la risorsa
computazionale è la memoria. Ok?
Ci concentreremo in questa lezione su
due classi, due classi spaziali, domani
ne vedremo un altro po', più un
risultato interessante
che le rende particolarmente differenti
dalle classi temporali. Allora, la prima
classe che definiamo è L,
a volte denotata come log space
e poi definiremo
NL
che è deterministic
log space.
Ok. Allora,
secondo voi L come la possiamo definire?
Usando D space ed n space. Quindi,
innanzitutto, L è deterministica o non
deterministica?
Deterministica. Deterministica. Quindi
facciamo di space. di space di quale
funzione? Logaritmo in base 2 di n
logaritmo in base 2 di n. Ok?
E invece nl
n space di logaritmo in base 2 n space
di logaritmo in base 2 di n. Ok?
Utilizziamo il logaritmo in base 2, ma
questo non non è una limitazione perché
se dovessimo usare un logaritmo in
un'altra base, fare il cambio di base di
logaritmo è una costante, quindi non ci
cambia niente. A livello asintotico è la
stessa cosa. Quindi da adesso in poi
quando scrivo logaritmo io intendo
logaritmo in base 2. Ok?
Secondo voi, qual è la relazione di
contenimento fra queste due classi?
L contenuto in NL. L è contenuto in ln
NL. Sì, L è contenuto in NL. Ok. E poi
relazioni con le altre classi le vediamo
domani.
Oggi ci focalizziamo su questo
problema, su queste due classi. Ok?
Allora, quello che noi ci poniamo come
obiettivo ora è andare a guardare un po'
di problemi che stanno in queste classi,
ok? cercare di capire se siano distinti
o meno, cosa la gente si è inventata per
stabilire se fossero distinti o meno. Ve
lo anticipo, tanto per cambiare. Noi
sappiamo che L sta dentro NL, ma non
sappiamo se le due classi sono distinte,
ok? È la solita storia di tante classi
di complessità.
Ok? Secondo voi?
Ok? No, ve lo dico io. All'inizio del
corso, mentre guardavamo macchine di
Touring eccetera,
abbiamo a un certo punto giocato con
questo linguaggio. Ok, qua uso
qua indico linguaggio. Ok. Alrght.
Allora, cercherò di questo linguaggio L
questo qua abbiamo questo linguaggio
qui. Eh, possiamo scrivere con L. Eh,
eh sì, alcune persone usano questo,
guarda, log space. Non non voglio scu,
scrivo log, ok? Log, però generalmente
sui testi troverete l oppure log space.
Ok?
Allora, abbiamo questo linguaggio 0n 1 n
con n strettamente maggiore di 0. Ok?
Avevamo visto questo linguaggio. Vi
ricordate come l'avevamo
come l'avevamo riconosciuto?
Noi vogliamo ci chiediamo se questo
linguaggio sta in lovead space o meno.
Ok? Questo è il nostro quesito di ora.
Vi ricordate la macchina che avevamo
usato?
Come riconosceva questo linguaggio?
[Musica]
Com'è?
No, era molto più semplice di quella.
Era una macchina deterministica.
Facevamo un giochino. La prima la prima
versione semplicemente leggeva il primo
carattere lo cancellava, poi a destra.
Sì, sì, esattamente. Facevamo questo
gioco, prendevamo con la testina,
andavamo sullo zero, lo marcavamo o lo
cancellavamo, andavamo in fondo,
eccetera, tornavamo indietro. Pam pam
pam.
Ok. Assumiamo di fare questo genere di
lavoro sulla macchina che abbiamo
definito oggi, quella con work tape.
Quello che dovremmo fare sostanzialmente
sarebbe prendere l'input, ricopiarlo su
Wordtech e iniziare a fare il gioco. Ok?
Perché noi questo gioco sul nassero di
input non lo possiamo fare. Ok? Quanto
spazio occupiamo a fare questo
lavoretto?
lineare. Ok? Quindi questa macchina usa
tanto spazio, non ci mostra che questo
linguaggio è in log space. Ok? Secondo
voi che ci possiamo inventare per
riconoscere decidere questo linguaggio
in spazio logaritmico?
Un attimo.
Chiaro l'obiettivo? Noi su nastro di
lavoro vogliamo usare solo spazio
logaritmico invece che spazio lineare.
Come si fa?
Pensateci un attimino.
Ok. Qualche voce nuova,
senò c'ho già la coda in testa delle
persone. Prenotate.
Ok, prego. Ci scriviamo in qualche modo
la quantità che a livello dizione
èamente
Esattamente. Noi su un nastro di lavoro
contiamo, cioè noi ci scriviamo in
binario quant'è questo n e questo n
quanto spazio occupa?
Logaritmico. Ok? Quindi la macchina
funziona così. Partiamo dagli zeri e
iniziamo a scrivere sul nastro questo
conteggio + 1 + 1 + 1 + 1 fin quando
arriviamo all'uno. Sul nastro avremo una
rappresentazione binaria di n
la cui taglia è logaritmica nella
quantità di zeri che apparivano sul
nastro in input.
Sì, prego. Per aumentare il conto non
bisogna andare a destra a sinistra con
la testina su work tape puoi fare quello
che vuoi, invece, ma puoi andare avanti
e indietro pure pure su input,
l'importante è che non ci scrivi. Ok?
Quindi andiamo avanti e li contiamo e
sommiamo uno e sommiamo uno e sommiamo
uno.
Prende un po' di tempo perché dobbiamo
fare queste somme binarie. Ok? Comunque
mi pare che la complessità ammortizzata
di contare è lineare. Non perdiamo così
tanto tempo. Scriviamo questa cosa su
worktape. Lasciamo uno spazietto.
Rifacciamo la stessa cosa con gli uni,
risommiamo tutto. Quando abbiamo finito
di fare i due conteggi, controlliamo le
due stringhe.
Se sono uguali rispondiamo di sì. Se
sono diverse rispondiamo di no. Quanto
spazio abbiamo occupato? logaritmico.
Ok? Quindi questo problema appartiene a
log space. Appartiene a log space.
Quello che vogliamo vedere adesso invece
è un interessante problema. Questo C
spazio. Ce ne abbiamo a non finire. Un
interessante problema che appartiene al
nondeterministicace.
Ok? È un problema che so per certo che
conosciate,
non sapete che è un problema di NL.
Quello è un problema famosissimo perché
l'avrete visto miliardi di volte in
10.000 Zs
e
però il nostro obiettivo sarà
mh
eh no,
sarà
definire un algoritmo non deterministic
long space perché di sicuro lo
conoscete, però avrete visto
ad altissima probabilità algoritmi
polinomiali deterministici. Invece
quello che noi vorremo vedere oggi è un
non deterministic lo space, cioè che nel
momento in cui abbiamo una macchina di
non deterministica possiamo risparmiare
un sacco di spazio. Ok?
Questo problema è l'astrusissimo
problema della raggiungibilità sul
grafo. Ok?
Quindi
com'è questo linguaggio
è il linguaggio delle triple GST
in cui G
è un grafo
diretto.
Importante che sia diretto, eh?
Sono
nodi di V.
ed esiste
in Gh
s
a t. Ok,
semplice il problema, lo conoscete,
abbiamo un grafo diretto.
Due nodi ci vengono dati in input. Non è
un problema di calcolo, è un problema di
decisione. Ci viene semplicemente
chiesto ma è vero o no che in G esiste
un percorso da S a T? Ok? Noi dobbiamo
rispondere sì o no.
Come
lo risolvete in genere questo problema?
BFS o BFS. Esattamente. Cioè, facciamo
un'esplorazione del grafo. Cosa possiamo
fare? Prendiamo S,
che è il nodo di partenza, è la
sorgente. T è il target. Analizziamo
prima questo algoritmo. Prendiamo S,
vediamo chi sono i successori di S.
Tutti loro li prendiamo e li infiliamo
in un sacco. Ok,
prendiamo,
no, facciamo così, vediamo i successori
di S, se tra loro c'è T, diciamo di sì,
sennò li prendiamo e li mettiamo in un
sacco. Tiriamo fuori dal sacco un uno di
questi vertici, vediamo chi sono i suoi
successori. Supponiamo che il grafo non
sia ciclico, sennò insomma vanno fatti
tutta una serie di controlli. Vediamo se
fra quelli c'è T. Se C è T, diciamo di
sì, senò prendiamo, li ributtiamo nel
sacco e continuiamo così. Ok, procedura
deterministica. Quanto tempo prende?
No, non mi interessa l'esponente
preciso. È polinomiale? Non è
polinomiale? È polinomiale. È
polinomiale. Sarà o quadratico o
pubblico, una cosa del genere. Ok.
deterministico polinomiale. Quanto
spazio usiamo?
Polinomiale. Usiamo spazio polinomiale.
Usiamo linear space più o meno perché
dobbiamo mettere nodi in questo sacco e
a un certo punto male che ci va
potrebbero comparire tutti. Ok? Quindi
lo spazio che usiamo in questo sacco è
bello grosso. Questo algoritmo non ci
mostra l'appartenenza
di reachability a non deterministic
space perché usiamo troppo spazio. ci
dobbiamo inventare
un
algoritmo non deterministico che usi
solamente, e questo è la parte
trucchettosa, che usi solamente spazio
logaritmico.
Prendetevi un paio di minuti per pensare
e poi iniziamo a ragionarci assieme.
Diretto vuol dire orientato. Orientato.
Sì, sorry
ho tradotto da directo.
Sì, orientato. Dove l'ho messo? Qua.
Cancelliamo.
Orientato.
Sì, alcune parole in italiano non mi
ricordo più come si dicono.
Che si può fare?
Per risparmiare spazio vi do questo
indizio, eh, per risparmiare spazio
dovete sfruttare il non determinismo,
senò non se ne esce.
Un attimo.
Secondo. Siamo a due. 3. Ok.
Siccome preferisco una lezione un po'
più collegiale, chiamerò prima quelli
che non ho sentito prima. Eh, ok.
Era
carino che quando ero a Oxford facevo
lezione a tre studenti ed era quasi una
lezione one to one, quindi si mette il
foglio in mezzo,
però è da lì che mi viene lo stile
interattivo, perché con loro ci
siedevamo e facevamo cose
Alri, prego.
Eh, io mi stavo immaginando di per un
guest se esiste una strada al massimo
lunga K, dove K è un numero di eh nodi.
Mh. Eh, altrimenti
Ma quindi lei deve gessare
K nodi,
lui deve gestare e scrivere sul nastro.
Sì, è quello che spazio lineare.
Troppo spazio.
Buon tentativo. Guess. Guess di cose.
Prego. Io farei un gest, però,
cioè, poi faccio il primo nodo, faccio
un guess, appunto, del primo passaggio
ecco
e a questo punto sovrassivo dal nuovo
nodo. In questo modo, cioè parole tipo
ogni singolo passaggio
Sì. Ok. Intanto possiamo fare un chest
dell'intero percorso. Posso fare un
chest? Il passaggio. Sì. E ok. Buono
l'impianto. Ok.
L'idea che ci dava il nostro collega
Gesso, il F è corretta. Il problema è
che dobbiamo risparmiare spazio. Come
risparmiamo in quel modo. Che cosa
facciamo noi? Gessiamo. È strano, eh,
perché adesso dobbiamo aggiungere un po'
di dettagli, poi scriverò uno
pseudocodice, così capiamo come
funziona.
La questione è che noi non possiamo
gessare tutto il patto assieme perché
occupa troppo spazio, quindi ne dobbiamo
gessare dei pezzi.
Che pezzo gessiamo? Noi gessiamo di
volta in volta solo il passo successivo,
quindi sono in s gesso il nodo di dopo.
Ok?
Come faccio a stabilire che non sto
gessando spazzatura? Verifico che il
gess
sia relativo a un arco presente nel
grafo. Ok? Quindi io gesso uno dei
successivi di S. Non è che gess una cosa
a caso. Gess uno dei successivi di ss.
Una volta che ho questo qua e sto usando
al momento poco spazio perché uso
l'identificativo del nodo. Oppure come
potrete leggere sugli appunti di Calutti
posso gessare il pointer alla posizione
nel nastro di input di dove compare il
nome del nodo. Ok? Cioè è una questione
per rappresentare compattamenti. Quindi
se abbiamo, che ne so,
16 nodi, per dire, numerati da 0 a 15, a
me servono 4 bit per dare nome a quei
nodi. Ok? Quindi cosa faccio? sono in s
gesso è il suo successivo. Sto solo
ghessando il nome identificativo di
questo nodo, quindi mi serve spazio
logaritmico per rappresentarlo.
Dopodiché quando devo gessare il passo
successivo, ok? Io prendo, a questo
punto sarà in un S prim', prendo un
successivo di S'ado in S2. Ok?
È chiaro?
E dove lo vado a scrivere? Sullo stesso
spazio, cioè io lo riuso. Io in memoria
mantengo costantemente nodo corrente,
nodo successivo, giusto per fare il
controllo che ci sia un arco. Dopodiché
cambio e vado a riscrivere di volta in
volta. Ok? Dobbiamo sfruttare il fatto
che riusiamo lo spazio. Questa è la
potenza delle classi spaziali. Un
secondo. Allora, che cosa succede? Se
esisterà,
no, un modo di arrivare a destinazione,
la macchina la macchina lo trova. Ok?
Però noi dobbiamo garantirci
che cosa? che questa macchina non
lucchi, perché io sto solo chiestando,
sto solo chiestando il successivo, eh,
io non ho una visione di insieme di dove
mi sto spostando nel grafo, sto
luppando. In genere negli algoritmi che
noi abbiamo visto al corso di algoritmi
e strutture dati, come fate ad evitare i
loop? Vi tenete una struttura dati che
dice io questo nodo l'ho già visto, ma
se noi abbiamo una lista del genere
nella macchina quanto spazio siiamo?
lineare lineare e quindi è una cosa che
non si può fare, cioè quindi noi
dobbiamo evitare il looping senza tenere
traccia di che cosa abbiamo visto. Ok,
chiaro? Quindi, che cosa abbiamo? Questa
macchina
gessa di volta in volta il next step e
in questo modo ci evitiamo di
di rappresentare tutto il patto in
memoria e risparmiamo spazio. Abbiamo un
problema però che se la se il grafo è
ciclico sta macchina inizia a ciclare
non si finisce più. Ok? Quindi dobbiamo
essere sicuri che noi andiamo a bloccare
i rami di computazione infiniti. Ok?
Non possiamo mantenere la lista delle
cose liste
come si fa generalmente
un attimo. Perché
non possiamo eh non possiamo occupare
tutto quello spazio per memorizzarlo. Ci
serve un'altra cosa. Allora, se mi
ricordo la sequenza c'era prima lei
nulla, poi lei
combinatoria. Ho visto un problema
simile col taglio del grafo. Mh. È
simile come problema, eh che intende per
taglio del grafo. Prendevo la spesa di
limite in area suppeva al grafo. Ci sono
forse si potrebbe fare in quel modo, ma
c'è un modo ancora più semplice. Prego.
E in questo caso mi sa che io mi
concentro solo sullo spazio, posso
contare, cioè io riciclo quest'anno
avanti all'infinito e mi accorgo che non
è corretto se ho ehm visitato tutti i
nodi del grafo, quindi se il mio
conteggio superato. Esattamente.
Mettiamo un bound sui nodi visti. Ok?
Quindi in memoria noi che cosa teniamo?
Nodo corrente, nodo successivo più un
contatore. Quanti ne ho visti finora?
Se mentre gesso i passi successivi il
contatore supera il numero dei nodi del
grafo, allora sto luppando e io quel
branch di computazione l'ammazzo
tutto. Quindi per accettare che devo
fare? Il branch accettante, la macchina
che fa? Gesso i passi successivi, conto
quanti passi faccio e accetto se arrivo
a Tliola.
Ok? Questo è il trucco. Prego. Due
domande. Allora, la prima è ma siccome
noi vogliamo mantenerci uno spazio
logaritmico, sì, tendenzialmente
eh gli algoritmi di ricerca del del B
ottimale sono molto più piccoli di una
BFS, una BFS. Non possiamo assumere che
il guessing eh della macchina in Cuding
segua appunto gli algoritmi primari di
ricerca del PUAP per avere Ma quegli
algoritmi
tipo la ricerca la ricerca in breath?
Allora, se io mi vado a guardare,
facciamo un esempio. Allora, io qui c'ho
S e devo arrivare a T che sta qua. Ok?
Supponiamo che S c'ha una marea di
successivi
e questo è attaccato a lui. Quando io
metto S
e faccio bread first, prendo i suoi
successivi e li infilo nel sacco. li ho
presi sostanzialmente tutti,
quindi ho usato spazio lineare e è
andata,
però vabbè, in questo esempio è eh ma io
devo avere la garanzia che la macchina
non usi mai più di più di spazio
cioè quindi su qualsiasi sia l' istanza
di input, qualsiasi forma abbia il
grafo, io devo essere certo di non usare
più di spazio logaritmico. Se mi arriva
una cosa strampa come quella,
al primo salto la macchina si mette nel
salto tutti i successivi DS che sono
quasi tutti noi. Da qui arriva anche la
seconda domanda, ovvero se noi conto che
letteralmente è un grafico unilaterale
dovè semplicemente una consecuzione di
nodi, no? Sì. Ok? Quindi noi lo
esploriamo tutto. Quindi noi
percorrorendo tutto il grado, cioè si
può dire ancora che è logaritmica la
questione.
La logaritmicità dell'algoritmo dipende
dalla quantità di informazione che va
scritta sul nastro, sulla quantità di
gelle che viene usato sul nastro di
lavoro.
Adesso descrivo lo pseudocodice di
questo algoritmo e vediamo che cosa ci
cosa intende per scrivere il nodo, cioè
scrivere il nominativo. Sì, quindi, cioè
quando lei in un algoritmo, non lo so,
programmato Python Java, C++ Sì. Ok. Nel
momento in cui abbiamo eh current vertex
equals S, ok? Quindi assegniamo S a
current vertex, che cosa sta succedendo
nella macchina? che c'è un blocco di
memoria
il cui contenuto binario prende
l'identificativo del modo S. Questa è la
stessa cosa, solo che invece di scrivere
un programma lo scriviamo su. Scusi, una
domanda stupida, ma allora seo
ha un nome lunghissimo, cioè si eh, però
il nome lunghissimo stava in integ
perché è tutto rispetto alla data e poi
li numeriamo anche Sì, sì.
Cioè, se io ho
i nomi che si chiamano Pipp, Giovanni,
Pluto e Topolino, no? E io mi devo
gessare di identificativi. Sto gessando
della delle cose che stavano nell'input
oppure io li posso semplicemente
numerare. Ok.
Ok. Grazie. Tutto qua. Allora, facciamo
questo e poi ci fermiamo.
Alri. Quindi abbiamo
rich
che prendiamo in input G, S.
Funziona così.
P è il nodo corrente e prende S.
Poi prendiamo il contatore N e gli
assegniamo uno che abbiamo visto un
nodo.
Dopodiché if P è uguale uguale a T, cioè
siamo arrivati, allora
accettiamo.
Dopodiché Pacciamo un guess.
di un vertice
di G. Ok? Poi facciamo un controllo. If
P'
appartiene
agli archi
del grafo,
eh no un attimo. Se non appartiene al
grafo agli archi, allora
rigettiamo.
[Musica]
Ok. Poi semplicemente mettiamo P' in P,
incrementiamo il contatore.
Se n è minore o è minore o uguale al
numero è minore
o uguale sì al alla al numero dei nodi,
then go
a e diamo la label a là.
Altrimenti
peggate.
Vedete tutto? Sì. Ok. Allora, questo è
un algoritmo molto semplice. Partiamo
dal nodo S. Inizializziamo il contatore.
Se P che il nodo corrente è uguale alla
destinazione, accettiamo perché ci siamo
arrivati. Altrimenti che siamo in primo
un qualsiasi vertice di C. Come vedete,
noi non ci curiamo di vedere se qualcosa
che è stato già visitato o meno. Se la
cosa che abbiamo cessato non fa parte
degli altri, rifiutiamo.
Dopodiché assegniamo P' a P e possiamo
continuare successivamente.
Incrementiamo il contatore. Se siamo
arrivati, se non stiamo eccedendo la
taglia dei nodi, ritorniamo qua e
continuiamo la procedura. altrimenti ci
fermiamo.
Ok? Allora, questo algoritmo è corretto
in quanto
in quanto nel momento in cui c'è un pat
da S a T dentro G, ci sarà una sequenza
di gess lunghezza al + n che mi
permetterà di arrivare lì e arrivare
alla parte in cui ci spostiamo nello
stato accettante. Se questo pat G non ci
sta, non ci sarà nessuna sequenza di gas
di alq n steps che ci permetterà di
arrivare t, quindi alla fine rigetteremo
su tutti i brgch. Ok?
È chiaro come funziona questo algoritmo?
Ok. Cosa ci serve da memorizzare? Cosa
abbiamo su workta tape? Abbiamo eh
abbiamo P che è il nodo corrente, P' che
è il nodo successivo e lì noi
memorizziamo due identificativi. Se se
li contiamo i nodi gli diamo
l'identificativo e quello là e prende
spazio lì spazio
logaritmico. Un altro modo, come
troverete sugli appunti di Calauti, è
che lì in Patore
a dove c'è la descrizione del nodo sul
nastro, c'è la 14 input. Quello lo si
rappresenta sicuramente in spazio
logaritmico. Io uso i nomi perché è più
intuitivo. Senò in linea di principio
uno lì ci mette il puntatore alla cella
sul nastro di input e quella ha sempre
taglia logaritmica. Quindi che cosa ho?
Devo memorizzare il nodo corrente,
il nodo successivo,
il contatore,
tutti questi. Quindi abbiamo tre
elementi, ognuno dei quali prende spazio
logaritmico. Quindi questa che cos'è? è
una procedura
log space da parte di una macchina non
deterministica che decide la
raggiungibilità in un grafo orientato da
cui richability è un problema in
nondeterministic
space. Chiaro? Ok. E possiamo fare un
po' di pausa, una decina di minuti, 10
minuti più o meno.
Eh, dov'è? Dov'è? Quand'è? Dove sta?
Un tempo ci stava il mouse. Dov'è?
Eccolo qua.
È a destra. A destra.
Spunta, spunta.
[Musica]
Alri. Right. Right. Ok. Allora,
prima quando ragionavamo sul problema
sul problema sul nostro fantastico
problema di receability vi ho detto se
volete risparmiare spazio logaritmico
dovete usare dovete usare il nond
determinismo perché se non volete usare
il non determinismo non ne usciamo.
Perché vi dicevo questo? Perché ho una
conoscenza che a voi ancora non avevo
comunicato che è questa. Non la gente si
è chiesta, ma il nondeterminismo per
risolvere richility è determinante?
Possiamo fare in log space
deterministico,
non si sa.
È una di quelle fantastiche questioni
della complessità nella quali algoritmi
deterministici log space per richability
non ce ne stanno, però nessuno ha mai
dimostrato che non sia possibile. Ok.
dopo tanti anni riteniamo che non sia
fattibile, ma non è che ne siamo certi,
lo assumiamo perché, insomma, ci abbiamo
sbattuto la testa così a lungo che ormai
riteniamo che non sia non sia fattibile.
La questione è che nessuno ha mai
mostrato formalmente che questa cosa non
si possa fare. Allora, il tutto proviene
e come si è studiata la gente questa
cosa qua?
Ha fatto dei ragionamenti simili alla
questione
P versus NP.
che nel momento in cui noi sappiamo che
log space sta dentro non deterministic
lo log space non sappiamo se queste due
classi c'è una relazione di contenimento
stretto o meno
e le persone se ne sono inventate delle
nozioni simili a quelle che furono
utilizzate per studiare la questione P
versus NP che si sono inventati si sono
inventati il concetto dei problemi più
difficili della classe NL. Vi ricorda
qualcosa?
Ok? Come c'abbiamo i problemi NP
completi, abbiamo i problemi NL completi
che sono i problemi più difficili della
classe NL e riceability è uno di quelli,
ok? È un problema tosto della classe non
deterministic lo space e per queste
ragioni riteniamo riteniamo che non
possa essere risolvibile il
deterministic
space. Ok? Allora, quello che noi
dobbiamo fare adesso, defini definiamo
cos'è un problema non deterministic log
space completo è una generalizzazione di
cose che abbiamo già visto per NP,
quindi lo facciamo assieme così ci
esercitiamo a ricordarci i concetti e a
estenderli.
Allora, ve la ricordate la definizione
di NP completezza?
un problema, un linguaggio di decisione
è sì, un linguaggio di decisione, un
linguaggio è NP completo. Se
appartiene ad NP e qualsiasi problema
appartenente ad NP è riducibile a quelli
quali. È riduci in quale modo? Eh,
polinomiale. Inopinomiale. Ok, questa
era la definizione di NP completezza.
Allora, non possiamo usare la
stessissima definizione, ne dobbiamo
usare una simile. In particolare il
problema si annila nella riduzione.
Ridurre polinomialmente
problemi
dentro NL
è troppo potente, cioè noi potremmo
ridurre problemi difficili a problemi
facili se avessimo possibilità di fare
riduzioni in tempo polinomiale perché
ok vabbò lo vedremo domani, ma vi do
l'anteprima. P sta qua, eh,
P sta qua sopra, eh,
lo vediamo domani sta cosa. Prendetemi
sulla parola. P sta lì sopra. Allora,
fare riduzioni polinomiali per problemi
che stanno qua dentro e sono riduzioni
un po' troppo forti. Allora, le persone
si sono inventate tutta una pletora di
riduzioni,
le le cui più semplici sono le riduzioni
log space, ok? Dice riduzione
polinomiale, riduzione spazio
logaritmico. Intuitivamente, secondo
voi, una riduzione log space che cosa
potrà mai essere? Un attimo, qualcuno di
nuovo? Voci nuove.
Facciamo il coro e poi andiamo a cantare
all'Antoniano, allo Zecchino d'oro.
Andiamo, guys. Cosa potrà mai essere una
riduzione? Lo space.
Io nel frattempo ho registrato i
prenotati. Vorrei sentire qualche voce
nuova.
Nuova. Sì, prego. La funzione
calcolabile in spazio logico. Ok. Ok.
Quindi ci dobbiamo inventare che cosa
significa che una funzione sia
calcolabile in spazio logaritmico prima,
ok? Perché ci serve una funzione di
trasformazione calcolabile in spazio
logaritmico. Vi ricordate come avevamo
definito le funzioni calcolabili in
tempo polinomiale?
Erano definite tramite il concetto di di
trasduttore. Cos'è un trasduttore? è una
macchina di Touring Stramb nastro di
output. Ok? Quindi le funzioni sono
calcolate da macchine di touring che
hanno un nastro particolare sola
scrittura
nel quale la macchina sputa fuori il
proprio output. Ok? Questa era la
nozione di trasduttore
perché adesso arriva la ragione del
perché il nastro di output sia di sola
scrittura. Ok? E in particolare ha pure
questa caratteristica. La testina va in
un solo verso. Perché mai ce la
inventiamo così? Perché nel momento in
cui sto andando troppo veloce, ok? Nel
momento in cui vogliamo imporre un
vincolo spaziale
a un trasduttore
e il trasduttore sul nastro di output
può fare quello che gli pare, potrebbe
iniziare a usare il nastro di output
come foglio di brutta e poi te lo
consegnano all'esame e sì, è un po'
mischiato, no? Sul sul nastro di output
ci va la bella, ci va il risultato. Ok?
Quindi un trasduttore
così definito in cui il nastro di input
lo possiamo solo leggere, il nastro di
output può essere solo scritto, diventa
sensato che cosa? Imporre il vincolo di
spazio sul nastro di lavoro. Ok? Questa
è la ragione per cui il nostro di output
è sola scrittura, in maniera tale che
diventi sensato imporre il vincolo
sullo spazio del del del nastro di
lavoro. Perché? Perché se dobbiamo
produrre un output grosso e noi andiamo
pure a contare lo spazio per scrivere,
eh ma noi quell'output dovevamo
generarlo, no? Quindi non potremmo mai
avere un trasduttore long space se
dobbiamo scrivere un un output lungo.
Quindi noi vogliamo imporre il vincolo
di spazio solamente sul nastro di lavoro
e per questa ragione noi imponiamo che
sul nastro di output possiamo solamente
scrivere. Quindi la macchina non può
processare, scrive e basta. Cioè, se non
è di lettura, vuol dire che il contenuto
del nastro di output non viene mai
considerato per valutare il next step.
Questa è la questione. Ok? Se io posso
solo scrivere su quel nastro, cosa ci
sta su quel nastro? Non entra mai nella
valutazione della funzione di
transizione. Quella è la ragione. Ok?
Quindi retap. Cos'è un trasduttore long
space? è un trasduttore
che ha quindi nastro di input di sola
lettura, nastro di lavoro work di
lettura scrittura, nastro di output di
sola scrittura.
Il trasuttore lavora in spazio
logaritmico se lo spazio utilizzato su
un nastro di lavoro è bound da un
logaritmo. Ok? e l' ottiene per ok?
Un tale trasduttore
calcola una certa funzione f
se per un qualsiasi input
eh che diamo a questo trasduttore su
quella stringa W il trasduttore lascerà
a fine calcolo sul nastro di output f.
Ok? Tutto qua. Possiamo quindi ora
definire, quindi è chiaro cos'è un
trasduttore in soldoni è un algoritmo
che produce un output e impiega spazio
algaritmico per farlo sul nastro di
lavoro. Ok? tutto qua, non è nulla di
particolare. Possiamo quindi definire
cos'è una riduzione log space,
quindi
siano
A e B due linguaggi.
Esiste
una riduzione
log space
da A
a b
denotato
con
A ug l b. Vedete, uso un simbolo
diverso. Quando è polinomial time la
mettiamo P. Quando è log space mettiamo
L. Completate voi la definizione. Quindi
A si riduce in log space a B.
Sì, per ogni stringa appartenente ad
manca un pezzo.
Lei sta dicendo per ogni stringa w vale
w appartiene ad a come tale w appartiene
ad asse solo se e f di w ed f chi è? F è
una funzione calcolabile che non abbiamo
ancora. Ok. Quindi esiste una funzione,
Esiste, bravissimo, esiste
una funzione
fpa cosa?
Stringa. String. String su string.
F caratteristiche deve avere?
Deve essere calcolabile da un
trasduttore calcolabile in spazio
logaritmico calcolabile
in log space.
Ed inoltre per ogni stringa w e se w
appartene ad a w appartina ad a se solo
se esattamente. Ok,
quindi la nozione di riduzione è
sostanzialmente mantenuta mantenuta.
L'unica cosa è che la funzione di
trasformazione che richiediamo è che
venga calcolato in log space, sottolineo
qua, log space deterministico, eh, cioè
non può fare cose strambe la riduzione,
deve è una cosa semplicissima. log space
deterministico.
In realtà non l'abbiamo mai
sottolineato, ma moltissime delle
riduzioni che abbiamo visto, tipo la
riduzione da indipendenzetta a vertex
cover, era una riduzione long space. Non
ve l'ho detto perché ancora non avevamo
il concetto. Quella sì traduce in
polinomial time, ma quella era una
riduzione che prendeva il grafo e lo
sputava in output, quindi spazio di
lavoro non ne usava proprio. Quella è
una riduzione log space, la prende, la
butta. Chiaro? L'unica cosa che faceva
calcolava la differenza. n - k faceva
era lunga trasformazione, si può
dimostrare che eh le sottrazioni, le
operazioni, le operazioni aritmetiche si
fanno in taglia log space degli
operandi, ok? Quindi quella era una
trasformazione log space, in realtà ne
abbiamo viste tante di trasformazioni
log space, ok? Logace deterministiche,
ok? E possiamo, una volta che abbiamo la
definizione
di
riduzione log space, possiamo definire
i linguaggi NL completi. Un linguaggio
L e NL complete.
Eh,
secondo voi
L appartiene a NL e per ogni L'O
appartenente a NL si ha una riduzione
da
N da L' a L.
Sì, esattamente.
Ok,
questo
l
Lness, sì, questa qui è membership.
Membership
in NL e questa è NL hardness.
Esattamente.
Quindi un problema è NL hard, se è
almeno difficile quando tutti i problemi
della classe NL ed è NL completo se sta
anche in NL, quindi è uno dei problemi
più complicati della classe NL. Un
risultato che si può dimostrare simile a
quello che abbiamo visto per P versus
NP. Si può mostrare che nel momento in
cui un linguaggio NL completo fosse in
logpace
e non deterministic log space sarebbero
la stessa classe. Ok?
Quello che dimostriamo ora è che
spazio ne abbiamo, ma più o meno.
Quello che dimostriamo ora è che tiriamo
una bella linea.
un problema che rich ability non solo è
un problema in NL, come abbiamo visto
prima, ma è anche un problema NL art,
cioè è un problema tosto per la classe
NL. Quindi quello che noi mostriamo ora
è che richility
è no appartiene, no? Eh,
NL complete.
Per le riduzioni per le riduzioni
log space valgono tutte le proprietà che
valevano per eh per le riduzioni
polinomiali, quindi la transitività
eccetera. E mi ricordo che noi quando
facevamo le riduzioni di NPR no
prendevamo un problema noto NP argo e lo
riducvamo al problema di interesse.
Abbiamo problemi noti NL hard? No.
Quindi dobbiamo far vedere che qualsiasi
linguaggio di NL si riduce a
ricciability. Quindi dobbiamo fare una
cosa che ha la valenza del teorema di
Cook però su NL. Ok? In realtà è più
semplice, non è così non è così
complicato,
però si può fa', dobbiamo un attimo
ragionare. Ok,
solite domande. Quindi, per mostrare che
richability è NL completo, noi dobbiamo
far vedere che preso un linguaggio L
generico, questo si riduce in log space
deterministico a reachability.
Ok? Qual è il problema di partenza?
qualsiasi L generico, ok? Si riduce log
space a reachability.
Cos'è un'istanza per L?
Stringa. Una stringa.
Cos'è un'istanza per richability?
Grafo sorgente. È una tripla. Grafo
sorgente target. Ok, quindi ci dobbiamo
inventare una funzione che mappi una
stringa W verso una tripla grafo
sorgente targets. Tempo ne abbiamo. Sì,
eh.
E a questo punto possiamo fare delle
considerazioni. Sono considerazioni che
avevamo già fatto per il teorema di
Cook, quindi vado un attimo più veloce
per poi focalizzarci su sulla riduzione
in sé, perché questa riduzione produce
grafi e non formule buule, quindi
dobbiamo un attimo capire dove si
colloca. Avevamo osservato che noi anche
perché il teorema di Cook, avevamo
osservato che L è un linguaggio
generico, un linguaggio che non sappiamo
che cosa sia. Quindi non sappiamo se
sono forme, non sappiamo se sono
grafiche, non sappiamo niente. Sappiamo
che le istanze di L sono stringhe
e noi queste stringhe vanno trasformate
in dei grafi tale per cui se W
appartiene a L nel grafo G c'è un pat da
S a T. Se W non appartiene a L nel grafo
G non ci deve stare un pat da S a T. Ok?
Bello rognoso sta cosa perché noi d L
non sappiamo niente. Come abbiamo
superato questa cosa per il teorema? Sul
teorema di Cook abbiamo detto di n
sappiamo niente. Sappiamo che cosa? Che
esiste una macchina non deterministica
che in tempo polinomiale
decide il linguaggio e quindi qui ci
siamo inventati tutto quel gran casino
per far vedere che il funzionamento di
quella macchina non deterministica
poteva essere codificato all'interno di
una formula bulearca. Qua dobbiamo fare
una cosa simile. Il funzionamento di una
macchina NL che decide
Linguaggio L va trasformato in un
grafico. Questa è una cosa. Ok? In
realtà è più semplice di quello che
abbiamo visto per il teorema di Cook,
infatti spero che in 20 minuti ce la
facciamo. Ok?
Allora, andiamo per intuizione.
Cosa facevamo sul teorema di Cook? Noi
avevamo che nella formula buleana
dovevamo codificare sostanzialmente le
configurazioni della macchina, i
passaggi, questo step, quest'altro step,
eccetera. Qui facciamo una cosa simile,
però dobbiamo sfruttare il fatto che
l'istanza di arrivo ha un grafo.
Che ci andiamo a ficcare in questo
grafo. Vi do l'intuizione prima e poi
vediamo come si fa.
I nodi
del grafo G
rappresenteranno,
cioè noi andremo a costruire un grafo G
i cui nodi saranno le configurazioni
della macchina M sulla stringa W.
Quindi i nodi di G ci diranno a che
punto della computazione
la macchina M che decide L è, mentre
esegue su B. Quindi i nodi sono le foto.
Nei nodi abbiamo le foto. A che punto è
la computazione. Quelli sono i nodi. I
nodi verranno collegati da archi
se uno stato è il legal successor del
precedente. Tutto qua. Dopodiché dentro
questo grafo avremo la foto dello stato
iniziale e la foto del target e potremo
andare dallo stato iniziale a quello
finale solamente se quello è accettante.
Tutto qua. Ok, questa è l'idea che ci
sta. Adesso però dobbiamo trovare il
modo di farlo. Ok? È chiaro qual è
l'obiettivo? Dovremmo generare un grafo
che ha tanti nodi quanti sono i
possibili stati di funzionamento della
macchina M su W. Quei nodi li andiamo a
collegare in base alla funzione di
transizione.
La parte trichi di tutto ciò è che
questo vada fatto in in spazio
logaritmico deterministico, quindi non è
che lo possiamo generare tutto quel
grafo e tenerlo su memoria di lavoro
perché occuperebbe troppo spazio. Quindi
noi tra virgolette dobbiamo generare su
un nastro di output, cioè questa
funzione futa
sul proprio nastro di output, la tripla
GST non può mantenere nella propria
memoria di lavoro pezzi di grafo intero,
occupa troppo spazio. Possiamo tenere
cose intermedie
e dobbiamo sputare in output qualcosa
che noi sappiamo essere corretto già nel
momento in cui lo stiamo scrivendo.
Questa è la cosa, ok? È la parte
difficile perché non possiamo tenere in
memoria il grafo, occupa troppo spazio.
Allora,
facciamo così.
Qua metto il coso e poi pagina no.
Vi dicevo che a noi servono tanti nodi
quanti sono i nodi, quanti sono le
possibili foto, abbiamo detto del
nastro,
eh
le foto della computazione, dello stato
di computazione della macchina M. Ok?
Allora, vi ricordo che questa macchina M
è una macchina particolare il cui nastro
di input non può essere scritto.
Ok?
Di conseguenza,
la caratterizzazione
delle possibili condizioni in cui si
trovi la computazione di M su W sono
caratterizzate da quali elementi?
La il nastro di input rimane sempre lo
stesso, quindi non è caratterizzante.
Quello che caratterizza è dove sta la
testina,
quindi la posizione della testina sul
nastro di input, ma non il suo
contenuto, perché quello rimarrebbe
costante in tutte tutte le ID. Quindi
non è necessario generare nodi in questo
grafo G che prendono in considerazione
il fatto che il contenuto del nostro
input cambi. No, quello non c'è bisogno.
Dobbiamo considerare che la testina sul
nastro di input può essere in posizioni
diverse, ma non che il contenuto cambi,
non è caratterizzante. Ok? Quindi,
quali informazioni ci servono per
stabilire a che punto del guado la
macchina M è?
Dove sta la testina sul nastro di input?
Il contenuto del nastro di lavoro,
perché quello può essere scritto, dove
sta la testina sul nastro di lavoro
e lo stato corrente di computazione, se
siamo in Q4, se siamo in Q11, eccetera.
Ok?
Quindi questa foto
del dello stato corrente della
computazione è caratterizzato potrebbe
essere scritta su una stringa di questo
tipo.
Quindi una stringa la cui parte iniziale
contiene il contiene il contenuto del
nastro di lavoro di M
H1 e H2 che sono le posizioni. Sono dei
numeri. Dice la testina sul primo nastro
alla cella 15, la testina sul secondo
nastro sta alla cella 170. Ok? e poi un
codice Q per dirci in quale stato siamo,
Q3, Q4, Q58,
eccetera. Ok? È chiaro? Quindi questa è
l'informazione.
Se in questa stringa noi scriviamo
queste informazioni così come ce le
siamo dette, noi siamo in grado di
stabilire a che punto del calcolo la
macchina M. È chiaro?
Questa stringa è una stringa di simboli
miei principi.
Gli possiamo dare il significato che
vogliamo.
Può essere il nome dei nodi in G.
Noi utilizziamo questa stringa come la
label dei nodi di G. Quindi la label dei
nodi in G ci dirà cosa c'è su workday,
dove sta la testina di primo nastro,
dove sta la sina di secondo nastro, in
quale stato la macchina.
È chiaro? Cioè, noi facciamo sto trucco,
questa cosa di Ma sai che sta
configurazione io la uso per dare il
nome ai nodi di G?
Adesso se io prendo inizio a dare
simboli a questa stringa, alcune saranno
sensate, altre saranno non sensate. Nel
momento in cui le generiamo, facciamo un
check per vedere se stiamo buttando
fuori spazzatura o meno. Sì, prego. Ti
scusi, ma la stringa che abbiamo
costruito è è la nostra assunzione? Al
momento stiamo solo facendo delle
considerazioni su quale informazione ci
serve per catturare lo stato di
avanzamento dei lavori di N. Dobbiamo
sapere cosa c'è sul nastro di lavoro,
dove stanno le due testine e in quale
stato si trovi la luce. Quindi per
adesso siamo ancora nella fase di idea.
Ideaidea. Fase diidea. Ok.
Allora, la macchina M che decide L,
la macchina M che decide L è una
macchina in quale classe di complessità?
NL. Quanto spazio usa?
Log space. Quindi questo quanto spazio
è?
Logaritmo di n
log n è la lunghezza di W. Ok.
Quanto occupa?
Scriviamo qua.
Quanto occupa l'indice sul primo nastro?
È un numero. Quindi la 18ª cella. Quanto
quanto bit ci servono?
logaritmo di sotto e quindi in generale
se la lunghezza del nostro input n
quanti bit ci servono per indicizzare le
celle su input logaritmo logaritmo di n
quindi qua abbiamo o di log n
questo qua h2 questo qua
quasi è log di log log di log perché
abbi dobbiamo indicizzare un nastro di
taglia logaritmica quindi qua Qua sotto
siamo o di log
n.
Ok. Numero di stati.
Quanto spazio ci serve per indigizzare
per nominare gli stati? Eh,
sicuri
logaritmico sul numero di stati, però
no. Attenzione, prego. Che sia relativo
all'ap, quindi direi No, no, no, sono
gli stati della macchina M che sono
numero. E questo numero com'è?
È fissato. Sì. Il numero di stati della
macchina non cambia rispetto all'input,
quindi il numero di bit che ci servono
per rappresentare Q è una costante.
Ok? Quindi, se prendiamo questa stringa
rappresentativa, quanto spazio ci serve
per scriverla?
Log log. Ok? Quindi noi siamo in grado
di scrivere questa stringa con l'ad n.
Ok?
Allora, la nostra idea era ora qual è? È
sputare perché noi stiamo definendo la
funzione di trasformazione fia b e tira
fuori gst.
Dobbiamo far vedere ora la funzione fare
fuori questa questo grafo. Ok? Allora,
il principio che usa è questo.
Ricordo che noi sostanzialmente dovremo
definire un grafo fatto così. I suoi
nodi sono tanti quanti le label, quelle
label.
Gli archi verranno messi fra nodi
che sono uno illegal successor
dell'altro secondo la funzione di
transizione.
Le configurazioni,
i nodi relativi a configurazioni
accettate verranno agganciate a un nodo
extra
che chiameremo T. Il nodo S è il nodo
relativo alla configurazione iniziale
della macchina. Tutto qua. Ok? Questa
cosa però va fatto in spazio
logaritmico, quindi dobbiamo riciclare
roba. Cosa fa questo trasduttore F? per
riuscire a generare, perché il grafo che
genera è bello grosso, eh, perché noi
abbiamo che questo qui
è il nome dei nodi,
quindi tutti i possibili nodi sono tutte
le possibili stringhe che hanno questa
forma, no? E quante sono?
Sì, noi dobbiamo generare
un grafo G i cui nodi hanno i nomi,
tutti i possibili nomi che si possono
costruire su una stringa che ha questa
forma. Quanti sono?
Attenzione, attenzione.
No,
abbiamo una stringa di 5 bit. Quante
sono le stringhe di 5 bit?
2^ qu. Abbiamo una stringa di 10 bit.
Quante sono le stringhe di 10 bit?
Abbiamo una stringa di 12
simboli ternari. Quante sono?
3^ 12 3^ 12 Quindi noi abbiamo Quante
sono le stringhe costruibili qua sopra?
2^ log n su n. Sì, sarebbe una costante
che è la taglia dell'alfabeto
eh per la taglia di questa stringa.
Quindi noi avremo che il numero totale
dei dei nomi che hanno questa forma,
cioè quindi il numero totale che dei
nodi che vanno a finire in G è un
esponenziale rispetto a questa taglia.
Ma questa taglia è logaritmica
nella taglia di w, perciò avremo un
polinomio nella taglia di W. Ma se
quello è un polinomio nella taglia di W,
mica può finire tutto nel work tape di
F, non abbiamo spazio, eh. Quindi noi
questo grafo non è che lo possiamo
piazzare tutto là, poi quando siamo
sicuri lo soriniamo, no? va costruito
pezzo a pezzo e buttato fuori. Allora,
facciamo in questo modo.
Praticamente la macchina, il trasduttore
che fa F, fa questa cosa qua. Si prende
quella stringa lì, no, con tutti i
campi, come abbiamo visto, eccetera.
Vi do l'intuizione di come si fa. Eh,
poi penso che sugli appunti di Calauti
sia più preciso, però visti le
tempistiche cerco di farvi capire.
Sostanzialmente la macchina F questo,
istanzia una di questa stringa
sul nastro di lavoro
e fa questo check.
Questa stringa è qualcosa di sensato
perché per esempio come posizione
delle testine e come nome dei stati
potrebbero comparire simboli che non
c'entrano assolutamente niente perché la
la stringa la macchina che fa? Devo
generare stringhe di 137 simboli e io ne
inizio a generare tutte, però alcune di
queste sono senza senso. Quindi parto
dalla stringa 00,
poi parto da 00 stella, 00
casetta. Ok. Cioè io mi faccio come
faccio il conto? Vado avanti. Come li
avete visti i contachilometri, quelli
quelli digitali, quelli di una volta che
giravano. Io li faccio gira tutti, me le
faccio tutte le rappresentazioni.
Allora, la macchina F che fa F che fa?
Si prende questa string, se la mette su
work daye, quanto spazio occupa?
Logaritmico.
Inizia a ciclarsene,
quindi guarda la corrente. Ha senso, sì,
sputata in output, quello è un nodo.
Vado alla successiva. Ha senso, no?
Andiamo alla prossima. Guardo la
successiva. Ha senso sì, sputate in
output e così a poco a poco genero tutti
i nodi di G. Not che i nodi di G vengono
sputati in output senza essere tutti
presenti allo stesso momento sul nastro
di lavoro. È questo il trucco, cioè che
io non li posso tenere tutti assieme.
Quindi io c'ho questa stringa e la
ciclo. Vado avanti avanti e sputo fuori.
Ta ta ta. Ok, è chiaro? Finito questo
giro,
prendo una stringa e aggiungo un
simbolo,
escludo quest'ultimo nodo che lo
chiamiamo VDAR.
Questo sarà T, che è un nodo differente
da tutti gli altri perché perché c'è un
simbolo in più. Ok? Quindi è un nodo
speciale.
Cancelliamo tutto, ripuliamo il
worktake, ripartiamo stavolta con due
stringhe
e io le conto entrambe e però stavolta
faccio lo stesso giochino per fare cosa?
Per considerare tutte le coppie.
Che ci faccio con queste coppie? Simile.
La prima è sensata. Sì. La seconda è
sensata. Sì, la seconda è un legal
successor della prima. Sì, sputo la
coppia in output. Quella è un'arma.
Quando non verifico questa condizione,
vado alla successiva. Vi faccio notare
che il grafo non è mai presente
completamente
su worktape. Cioè, noi stiamo avanzando
contatori. Prego. Ma possiamo fare
direttamente le coppie di fare prima i
figoli? Si potrebbe anche fare. Sì, sì,
sì. Si potrebbe anche fare magari. in
una rappresentazione nella quale non c'è
una rappresentazione esplicita dei nodi,
ma abbiamo direttamente gli archi.
Quello si può fare, è una scelta tipo
sugli appunti di Cala che credo sia
fatto così. Ok?
Sì, prego. Quindi, allora, prima i nodi.
Un secondo, un secondo. Finisco questo e
poi perché potremmo non aver tempo, poi
in caso mi fa la domanda. Ci siamo, che
facciamo? Usiamo cicliamo questa stringa
per sputare i nodi.
Cicliamo le e poi sputiamo VAR che è un
nodo con un nome speciale. Poi cicliamo
su tutte le coppie così su quelle
sensate mettiamo gli archi in output.
Ok? Cosa rimane da fare? Mentre cicliamo
queste, dopo che abbiamo fatto il ciclo
delle coppie, cancelliamo tutto,
rifacciamo il giochino dell'esplorazione
per andare a vedere quali sono le
configurazioni con uno stato accettante.
Quelle lì le agganciamo a Bostar,
ok? Perché dobbiamo fare tutto sto
gioco.
Abbiamo generato G,
vanno generate. È chiaro come G viene
generato?
Perché avremo dentro G ci sono tanti
nodi relativi a stati a configurazione
accettanti, ma noi il pat deve essere da
S verso un nodo specifico, quindi ne
mettiamo uno fettizio in maniera tale
che il pat è sempre verso il nodo
fittizio. Ok?
Generiamo il grafo. S è la è il nodo del
3G che è la configurazione iniziale
della partenza T e distante. Finito.
Per come è costruito questo grafo a un
pat da S a T? Se solo se m accetta w
e quindi siccome l era un linguaggio
generico che si riduce a ritability
allora avremo che richability è NL hard.
Chiaro? Sì. Prego. Ma dopo appena
analizzato le coppie non vado avanti per
analizzare 30. No, no, no. Le coppie ci
servono perché noi dobbiamo generare gli
archi del grafo e gli archi del grafo
sono coppie perché io devo devo poter
dire vado dal nodo 3 al modo 6, quindi
genero le coppie sono sensate. Uno è
successo l'altro sì. Allora lo
chiaro?
Prego. Star, cioè quindi lo star alla
fine viene messo in negli stati finali.
Star è un nodo specifico di G che riceve
come archi entranti
da tutti i nodi accettati.
E viene generato
generando un nodo aggiuntivo con una
stringa più lunga in maniera tale che
non sia nessuno degli altri che abbiamo
la certezza che non sia nessuno degli
altri. Ok?
Great guys.
Qua proprio eh.
Allora, fermato