2. Laskettavuusteoriaa Käymme läpi ratkeamattomuuteen liittyviä ja perustuloksia ja -tekniikoita [HMU luku 9]. Tämän luvun jälkeen opiskelija tuntee joukon keskeisiä ratkeamattomuustuloksia osaa esittää tyypillisiä Turingin koneisiin liittyviä ongelmia formaalisti ja tarkastella niiden ratkeavuutta tunnettujen tulosten valosssa osaa yhdistää käytännön algoritmiongelmia tunnettuihin formaaleihin ratkeamattomuustuloksiin osaa tehdä yksinkertaisia ratkeamattomuustodistuksia 80
Palautetaan mieliin terminologiaa: Kieli L Σ on rekursiivisesti lueteltava jos A = L(M) jollain Turingin koneella M. Turingin kone on totaalinen jos se pysähtyy kaikilla syötteillä. (Joissain lähteissä käytetään termiä algoritmi spesifisti tällaisista koneista.) Kieli L Σ on rekursiivinen jos A = L(M) jollain totaalisella Turingin koneella M. Vastaavasti Päätösongelma π: Σ { 0, 1 } on osittain ratkeava jos vastaava kieli on rekursiivisesti lueteltava. A π = { x Σ π(x) = 1 } Päätösongelma π on ratkeava jos A π on rekursiivinen. 81
Termien selityksiä rekursiivinen tulee siitä että tämä kieliluokka historiallisesti vakiintui Kleenen ja Gödelin rekursiokonstruktion kautta lueteltava tulee siitä että A on rekursiivisesti lueteltava jos ja vain jos on olemassa algoritmi joka luettelee joukon A alkiot (ja vain ne) jos x A niin x esiintyy luettelossa jonkin äärellisen ajan kuluttua ja asia on selvä jos x A niin x ei tule koskaan esiintymään luettelossa, mutta tätähän ei voi tietää pelkästään katsomalla jotain luettelon äärellistä alkuosaa Luetteloimisidea esitetään myöhemmin yksityiskohtaisemmin. Huom. kaikista laskennallisista ongelmista vain häviävän pieni osa on edes osittain ratkeavia, mutta tietojenkäsittelytieteessä tietysti yleensä keskitytään ratkeaviin ongelmiin. 82
Churchin-Turingin teesin mukaan ratkeavuus tarkoittaa samaa, kuin että ongelma voidaan ratkaista jollain algoritmisella menettelyllä. Esitämme jatkossa joukon Turingin koneita koskevia eksakteja matemaattisia tuloksia, mutta jos uskomme C-T:n teesin, näillä on siis yleisempiä seurauksia. C-T:n teesi oikeastaan motivoi koko tämän tutkimusohjelman, koska muuten Turingin koneet eivät välttämättä olisi kovin kiinnostava tutkimuskohde. (Tosin voidaan kumminkin argumentoida, että Turingin kone on oikea malli sille mitä ihminen voi mekaanisesti laskea, ja mitä nykyiset tietokoneet voivat laskea.) Joka tapauksessa on kuitenkin selvää, että jos ongelma osataan ratkaista esim. Java-kielellä, se voidaan ratkaista myös Turingin koneella (vrt. RAM-malli luvussa 1). Samoin joka tapauksessa jonkin ongelman ratkeamattomuuden osoittaminen on aina ei-triviaalia, koska pitää osoittaa että mikään Turingin kone ei ratkaise sitä. 83
Formaalin logiikan todistuvuusongelma (Motivoiva esimerkki yleisellä tasolla; yksityiskohdat ks. esim. Matemaattinen logiikka) Annettu: ensimmäisen kertaluvun predikaattilogiikan kaava φ Kysymys: onko kaavalle φ olemassa todistus predikaattilogiikan aksioomista Voidaan helposti luetella ensin kaavat joilla on yhden askelen mittainen todistus, sitten ne joilla on kahden askelen mittainen todistus jne. Siis todistuksen omaavien kaavojen joukko on rekursiivisesti lueteltava, ja todistuvuusongelma osittain ratkeava. Kuitenkin osoittautuu, että todistuvuusongelma ei ole ratkeava. 84
Pysähtymisongelma (johdanto) [HMU 9.1] Intuitiivisesti on kysymys seuraavasta ongelmasta: Annettu: Turingin kone M, merkkijono x Kysymys: pysähtyykö kone M syötteellä x Tavoitteena on osoittaa tämä ongelma ratkeamattomaksi. Ensimmäinen osatavoite, puhtaasti tekninen ja käsitteellisesti yksinkertainen, on esittää Turingin koneet merkkijonoina. Muutenhan niistä ei olisi formaalisti mielekästä edes puhua algoritmin syötteenä tms. Esitämme siis seuraavaksi yksinkertaisen koodauksen, joka liittää jokaiseen Turingin koneeseen M = (Q,..., F ) merkkijonon w { 0, 1 } ja kääntäen. 85
Turingin koneiden koodaus Rajoittaudutaan yksinauhaisiin koneisiin ja syöteaakkostoon Σ = { 0, 1 }. Lisäksi oletetaan että hyväksyviä tiloja on tasan yksi ja se ei ole alkutila. Numeroidaan aakkoston { 0, 1 } merkkijonot siten, että merkkijonon w numero on 1w binääriluvuksi tulkittuna. Olkoon w i merkkijono numero i; siis w 1 = ε, w 2 = 0, w 3 = 1, w 4 = 00, w 5 = 01 jne. Oletetaan nyt M = (Q, { 0, 1 }, Γ, δ, q 1, #, F ) missä Q = k, Q = { q 1,..., q k } ja F = { q 2 } Γ = m 3, Γ = { X 1,..., X m }, X 1 = 0, X 2 = 1, X 3 = # suunnat on numeroitu L = D 1 ja R = D 2 86
Nyt kaikki muu paitsi δ on numeroitu. koodataan yksittäinen siirtymä δ(q i, X j ) = (q k, X l, D m ) jonoksi 0 i 10 j 10 k 10 l 10 m huom. i, j, k, l, m 1 joten tässä ei koskaan tule kahta ykköstä peräkkäin merkkijono C 1 11C 2 11... C n 1 11C n on koodi koneelle jossa on n siirtymää joiden koodit ovat C 1,..., C n Huomaa että samalla koneella on tyypillisesti useita eri koodeja yksi merkkijono ei kuitenkaan voi koodata useita eri koneita jotkin merkkijonot eivät ole minkään koneen koodeja 87
Olkoon M triv jokin kiinteä Turingin kone joka hylkää kaikki syötteet. Määritellään kaikille w { 0, 1 } Turingin kone M w seuraavasti: jos w on jonkin koneen M koodi, niin M w on tämä M muuten M w = M triv Aputuloksena pysähtymisongelman ratkeamattomuustodistuksessa osoitetaan, että diagonaalikieli ei ole edes rekursiivisesti lueteltava. L d = { w { 0, 1 } w L(M w ) } Kieli L d on hieman keinotekoinen. Sen merkitys on lähinnä, että sen avulla voidaan osoittaa muita kiinnostavampia ongelmia ratkeamattomaksi. 88
Analogia: Koodit ja ohjelmointikielet Eräs mahdollinen analogia on seuraava: Tulkitaan, että ohjelma hyväksyy syötteen, jos sen suoritus päättyy normaalisti, ja hylkää jos suoritus päättyy virheeseen. Lisäksi ohjelma voi jäädä silmukkaan. Nyt Turingin kone M konekieliohjelma merkkijono w { 0, 1 } ASCII-merkkijono (esim. C-ohjelma) M w ohjelma w käännettynä M triv konekieliohjelma joka aina jää silmukkaan Lisäksi sovimme, että M w = M triv jos w ei ole syntaktisesti korrekti C-ohjelma. Nyt C-ohjelma kuuluu joukkoon L d, jos se ei pysähdy normaalisti, kun (se käännetään ja) siille annetaan syötteenä oma lähdekoodinsa. Huom. C-kieli ja konekieli ovat yhtä laskentavoimaisia, joten analogia voitaisiin ajatella toisinkin päin: konekieliohjelmasta voidaan kääntää C-ohjelma. 89
Lause 2.1: [HMU Thm. 9.2] Kieli L d = { w { 0, 1 } w L(M w ) } ei ole rekursiivisesti lueteltava. Todistus: Tehdään vastaoletus että L d = L(M) jollain M. Olkoon w jokin koneen M koodi; siis L d = L(M w ). Nyt w L d w L(M w ) w L d missä on ensin käytetty kielen L d määritelmää ja sitten koodin w valintaperustetta; ristiriita. Nyt olemme saaneet ensimmäisen konkreettisen ratkeamattomuustuloksen. Jatkossa osoitamme suurelle joukolle ongelmia X, että jos X osattaisiin ratkaista, niin L d voitaisiin tunnistaa. Tästä seuraa ongelman X ratkeamattomuus yo. lauseen nojalla. 90
Rekursiivisuuden perusominaisuuksia [HMU 9.2.1-9.2.2] Ennen kuin ruvetaan tarkastelemaan varsinaisen pysähtymisongelman ratkeamattomuutta, on hyödyllistä tarkastella rekursiivisten kielten luokan joitain perusominaisuuksia. Oletetaan jatkossa että Turingin koneissa on tasan yksi hyväksyvä tila, ja tästä ei mitään siirtymiä tasan yksi sellainen ei-hyväksyvä tila, josta ei ole mitään siirtymiä (hylkäävä lopputila) muuten kaikki siirtymät määriteltyjä On helppo muuntaa mikä tahansa Turingin kone tällaiseen muotoon. 91
Lause 2.2: Olkoot A, B Σ rekursiivisia. Nyt myös A = Σ A, A B ja A B ovat rekursiivisia. Todistus: Olkoon A = L(M A ) ja B = L(M B ) missä M A ja M B ovat totaalisia. Esitetään Turingin koneet kaavamaisesti: alkutila M hyväksyvä hylkäävä 92
Kielen A hyväksyvä kone saadaan vaihtamalla koneen M A hyväksyvä ja hylkäävä lopputila keskenään Kielen A B hyväksymiseksi simuloidaan ensin konetta M A. jos M A hyväksyy, niin hyväksytään jos M A hylkää, niin simuloidaan konetta M B jonka ratkaisu jää voimaan (kuva seuraavalla sivulla) Tapaus A B seuraa koska A B = A B 93
M A M B Kielen A B tunnistaminen koneiden M A ja M B avulla 94
Lause 2.3: Olkoot A, B Σ rekursiivisesti lueteltavia. Nyt myös A B ja A B ovat rekursiivisesti lueteltavia. Todistus: Harjoitustehtävä. Sen sijaan yleisesti ei päde että rekursiivisesti lueteltavan kielen A komplementti A olisi rekursiivisesti lueteltava. Sen sijaan pätee Lause 2.4: Kieli A on rekursiivinen jos ja vain jos sekä A että A ovat rekursiivisesti lueteltavia. 95
Todistus: Jos A rekursiivinen, niin A on rekursiivinen, joten suunta vasemmalta oikealle on selvä. Olkoot toisaalta M A ja M A koneet jotka tunnistavat kielet A ja A. Muodostetaan kaksinauhainen kone M, joka on totaalinen ja tunnistaa kielen A. Kone M simuloi konetta M A käyttäen ykkösnauhaansa ja konetta M A käyttäen kakkosnauhaansa. Simulaatiot suoritetaan lomittain, aina yksi askel kerrallaan kumpaakin. Jos simuloitava M A hyväksyy, M hyväksyy. Jos simuloitava M A hyväksyy, M hylkää. Koska jokaisella x joko x L(M A ) tai x L(M A ), aina tasan yksi simulaatioista hyväksyy. (kuva seuraavalla sivulla) 96
M A M A Kielen A tunnistaminen totaalisella koneella jos A ja A ovat rekursiivisesti lueteltavia 97
Formalistisemmin tulos voidaan esittää seuraavasti: Olkoon RE rekursiivisesti lueteltavien kielten joukko: RE = { L(M) M mielivaltainen Turingin kone }. Olkoon co-re rekursiivisesti lueteltavien kielten komplemettien joukko: co-re = { A A RE }. Olkoon REC rekursiivisten kielten joukko: Edellä esitetyn mukaan REC = { L(M) M totaalinen }. REC = RE co-re. 98
Huomaa yhteys rekursiivisen luettelemisen ajatukseen: Oletetaan, että jokin algoritmi M A osaa luetella kielen A; samoin M A kielelle A. Kun halutaan tietää päteekö x A, listataan rinnakkain joukkoja A ja A. Koska joko x A tai x A, niin jonkin äärellisen ajan kuluttua x esiintyy jommassa kummassa listassa ja vastaus tiedetään. Myös A-lista tarvitaan jotta voidaan taata pysähtyminen myös kielteisessä tapauksessa. 99
Universaalikieli [HMU 9.2.3-9.2.4] Seuraava askel kohti pysähtymisongelman ratkeamattomuutta on universaalikieli L u joka on muutenkin hyvin tärkeä: Huom. L u = { w111x { 0, 1 } x L(M w ) }. mikään Turingin koneen koodi ei sisällä merkkijonoa 111 siis merkkijono z { 0, 1 } voidaan esittää korkeintaan yhdellä tavalla muodossa z = w111x siten, että w on validi Turingin koneen koodi jos w ei ole validi koodi, edellä sovitun mukaan x L(M w ) kaikilla x Osoitamme nyt että universaalikieli on rekursiivisesti lueteltava, mutta ei rekursiivinen. Kielen L u tunnistavaa Turingin konetta U sanotaan universaaliksi Turingin koneeksi. (Universaalikone ei tietenkään ole yksikäsitteinen.) 100
Lause 2.5: [HMU Thm. 9.6(a)] Universaalikieli L u on rekursiivisesti lueteltava. Todistus: Muodostetaan nelinauhainen U jolle L u = L(U). Nauhojen käyttö syötteellä z = w111x missä w on koneen M koodi: Nauha 1 sisältää syötteen z ja siis erityisesti koneen M siirtymäfunktion koodin w Nauha 2 simuloi koneen M nauhan sisältöä käyttäen samaa koodausta kuin siirtymäfunktiossa; siis esim. pätkää... X 3 X 1 X 4... esittäisi... 100010100001... Nauha 3 simuloi koneen M tilaa; tila q i koodataan 0 i Nauha 4 on työtilaa 101
Koneen U laskenta: Aluksi tarkista onko syöte muotoa w111x jollain validilla koodilla w. Jos ei ole, niin hylkää. Muuten rupea simuloimaan koneta M = M w syötteellä x. Kussakin askelessa 1. Olkoon nauhalla 3 jono... #0 i #... ja nauhalla 2 nauhapäästä alkaen jono 0 j 1. 2. Etsi koneen M kuvauksesta nauhalla 1 kohta... 110 i 10 j 1...; jos ei löydy, niin hylkää. 3. Olkoon nauhalta 1 löytynyt jono... 110 i 10 j 10 k 10 l 10 m 11.... 4. Vaihda nauhan 3 sisällöksi 0 k ja nauhalle 2 nauhapäästä alkaen 0 l ; siirrä nauhan 2 loppuosuutta tarpeen mukaan. 5. Siirrä nauhan 2 nauhapää seuraavaan ykköseen vasemmalla (jos m = 1) tai oikealla (jos m = 2). 6. Jos q k on hyväksyvä tila (siis k = 2), hyväksy. 102
Lause 2.6: [HMU Thm. 9.6(b)] Universaalikieli L u ei ole rekursiivinen. Todistus: Tehdään vastaoletus että L u = L(M) jollain totaalisella M. Muodostetaan totaalinen M jolle L(M ) = L d, missä L d on aiemmin ei-rekursiiviseksi osoitettu diagonaalikieli; ristiriita. Kone M toimii syötteellä w seuraavasti: 1. Jos w ei ole validi koodi, hyväksy. 2. Muuten muunna nauhan sisällöksi w111w. 3. Simuloi koneen M laskentaa; oletuksen mukaan tämä johtaa joko hylkäävään tai hyväksyvään lopputilaan. 4. Jos M hyväksyy, niin hylkää; jos M hylkää, niin hyväksy. Nyt w L(M ) (w ei validi koodi tai w111w L u ) w L(M w ) w L d. 103
Pysähtymisongelma Voimme nyt formuloida pysähtymisongelman kieleksi H = { w111x { 0, 1 } w validi koodi ja M w pysähtyy syötteellä x }. Lause 2.7: Kieli H on rekursiivisesti lueteltava. Todistus: Universaalikoneen U konstruktiota on helppo muuttaa siten että se hyväksyy jos ja vain jos simuloitavan koneen laskenta pysähtyy. Lause 2.8: Kieli H ei ole rekursiivinen. Todistus: Tehdään vastaoletus että H = L(M) jollain totaalilla M. Tästä saadaan helposti sellainen totaali M, että L(M ) = H ja hyväksyessään syötteen x kone M jättää laskennan lopuksi nauhalle alkuperäisen syötteen tyhjämerkkien ympäröimänä. 104
Tästä saadaan totaalinen kone M joka tunnistaa universaalikielen L u seuraavasti: 1. Tarkista että syöte on muotoa w111x missä w on validi koodi; jos ei ole, niin hylkää. 2. Simuloi sitten konetta M ; jos hylkäsi niin hylkää. 3. Jos M hyväksyi, käsittele sama syöte universaalikoneella U jonka hyväksyminen tai hylkääminen jää voimaan. Universaalikoneen konstruktiosta nähdään, että U pysähtyy syötteellä w111x jos ja vain jos M w pysähtyy syötteellä x. Siis M on totaali ja tunnistaa saman kielen kuin U; ristiriita 105
Seuraava ongelma on oleellisesti pysähtymisongelman komplementti eikä siis edes osittain ratkeava. Lause 2.9: Pysähtymättömyysongelma H missä H = { w111x w validi koodi, M w ei pysähdy syötteellä x } ei ole rekursiivisesti lueteltava. Todistus: Pysähtymisongelman komplementti H voidaan esittää muodossa H = H E missä E = { z { 0, 1 } n z ei ole w111x millään validilla koodilla w }. Selvästi E on rekursiivinen Siis jos H olisi rekursiivisesti lueteltava, myös H = H E olisi (Lause 2.3). Kieli H on rekursiivisesti lueteltava, joten jos H myös olisi, niin H olisi rekursiivinen (Lause 2.4); ristiriita. Siis H ei voi olle rekursiivisesti lueteltava 106
Ohjelmointikielen pysähtymisongelma Turingin koneet ovat analogisia jollain ohjelmointikielellä kirjoitettujen ohjelmien kanssa: Turingin kone -formalismi jonkin ohjelmointikieli Turingin kone tällä kielellä kirjoitettu ohjelma Turingin koneen koodi ohjelma käännettynä konekielelle universaali Turingin kone konekielen tulkki joitain ohjelmointikielten ratkeamattomuustuloksia voidaan kätevästi osoittaa suoraan (kuten johdannossa C-kielen pysähtymisongelma) voidaan myös käyttää hyväksi Turingin koneiden ja minkä tahansa yleisohjelmointikielen samaa ilmaisuvoimaa ja siirtää tulokset Turingin koneista ohjelmointikieliin sama ilmaisuvoima tarkoittaa tässä, että mikä tahansa ongelma voida ratkaista Turingin koneella jos ja vain jos se voidaan ratkaista kyseisellä ohjelmointikielellä 107
Esimerkki 2.10: C-kielen pysähtymisongelma Rajoitutaan tarkastelemaan C-kielen funktioita jotka saavat parametrina yhden merkkijonon ja palauttavat 0 tai 1 tai jäävät silmukkaan. Sanotaan että tällainen funktio f hyväksyy merkkijonon x jos f(x) palauttaa 1, ja on totaalinen jos f(x) pysähtyy kaikilla x. Ollaan valmiit uskomaan, että kieli A voidaan tunnistaa (totaalisella) Turingin koneella jos ja vain jos se voidaan tunnistaa tällaisella (totaalisella) C-funktiolla. Tämän uskomuksen tarkka perusteleminen vaatisi tietysti C-kielen semantiikan tarkkaa läpikäymistä, mutta intuitiivisesti se on selvästi totta (vrt. RAM-malli). Halutaan osoittaa Turingin koneiden pysähtymisongelmalle analoginen tulos: mikään totaalinen C-funktio ei tunnista kieltä H C = { w x w on C-funktio joka syötteellä x pysähtyy } 108
Argumentti menee pääpiirtessään seuraavasti: koska C on yhtä ilmaisuvoimainen kuin Turingin koneet, voidaan Turingin koneiden universaalikieli L u tunnistaa jollain (ei-totaalisella) C-funktiolla univt siis kysymykset Turingin koneen M w toiminnasta syötteellä x palautuvat kysymyksiksi C-funktion univt toiminnasta syötteellä w111x. erityisesti jos jokin C-funktio halts ratkaisisi C-funktioiden pysähtymisongelman, niin tätä kautta se ratkaisisi myös Turingin koneiden pysähtymisongelman koska toisaalta Turingin koneet ovat yhtä ilmaisuvoimaisia kuin C-funktiot, funktiota halts voitaisiin simuloida Turingin koneella näin saataisiin ratkaistuksi Turingin koneiden pysähtymisongelma; ristiriita 109
Esitetään sama hieman yksityiskohtaisemmin. Vastaoletus siis on, että jokin totaalinen C-funktio haltsc ratkaisee C-kielen pysähtymisongelman. Tunnetusti on olemassa C-funktio f u joka simuloi universaalia Turingin konetta U. Siis erityisesti f u syötteellä w111x pysähtyy, jos ja vain jos M w syötteellä x pysähtyy. Olkoon haltst C-funktio, joka syötteellä z tekee kutsun haltsc(p*z) missä p on funktion f u teksti. Tämä on helppo konstruoida, kun haltsc oletetaan annetuksi. Siis haltst on totaalinen, ja funktiota haltsc koskevan oletuksen mukaan haltst(w111x) = 1 haltsc(p w111x) = 1 f u (w111x) pysähtyy w111x H. Toisaalta on selvästi olemassa totaalinen Turingin kone M H joka simuloi C-funktiota haltst. Siis M H ratkaisee Turingin koneiden pysähtymisongelman; ristiriita. 110