Lyhyt MathCheck-ohje (uuteen välilehteen)
Datan määrää mitataan yleensä sillä, montako tavua tarvitaan tallettamaan se. Tavumäärä riippuu kuitenkin esitystavasta. On olemassa häviöttömiä pakkausmenetelmiä, joilla tiedostoa voi pienentää toisinaan merkittävästi, mutta alkuperäinen tiedosto pystytään palauttamaan pakatusta tiedostosta. Tämä herättää kysymyksen, voiko informaation määrää mitata toisella tavalla, niin että tulokseksi tulee pienimmän sellaisen tiedoston koko, johon informaatio saadaan mahtumaan niin että se voidaan sieltä palauttaa.
Tässä tehtävässä käydään tämän kysymyksen kimppuun, mutta sitä ennen käsitellään datan pakkaamiseen liittyviä perusasioita. Paljastuu, että pienimmän pakatun tiedoston koolla mittaaminen ei toimi sellaisenaan, koska niin saatavaa tulosta voi keinotekoisesti manipuloida pakkausmenetelmän yksityiskohtia valitsemalla. Pakatun tiedoston purkava ohjelmakin sisältää informaatiota, ja se on otettava oikealla tavalla huomioon.
Nämä pohdinnat johtavat Kolmogorov-kompleksisuutena tunnettuun käsitteeseen, joka on osa algoritmista informaatioteoriaa. Kolmogorov-kompleksisuus vastaa varsin hyvin monien ihmisten intuitiivisia odotuksia siitä, miten informaation tulisi käyttäytyä. Valitettavasti siihen liittyy myös rankka ratkeamattomuustulos, joka tekee sen käyttämisestä mittarina käytännössä mahdotonta.
Aakkosto on mikä tahansa äärellinen joukko. Sen alkioita kutsutaan merkeiksi. Tässä tehtävässä oletetaan, että on valittu jokin aakkosto Σ, joka sisältää ainakin esimerkeissä käytettävät merkit. Merkitsemme merkkijonoja eli Σ*:n alkioita pienillä kreikkalaisilla kirjaimilla σ, ρ ja niin edelleen. Merkkijonovakiot esitetään ”lainausmerkeissä” ja merkkivakiot näin: ’0’.
Merkkijonon pituus on sen merkkien määrä. Sitä merkitään |σ|. Esimerkiksi |”pituus”| = …6. Jos σ ja ρ ovat merkkijonoja, niin σρ tarkoittaa sitä merkkijonoa, jossa on ensin σ:n sisältö ja heti perään ρ:n sisältö. Jos esimerkiksi σ = ”yli”, niin σ”opisto” = …”yliopisto”.
On tärkeää, että aakkoston koko on vähintään 2. Tyhjällä aakkostolla ei synny mielenkiintoista informaation teoriaa tästä syystäSilloin erilaisia merkkijonoja on vain yksi, nimittäin tyhjä merkkijono ε.. Jos Σ = {’0’}, niin Σ* = tämä{ε, ”0”, ”00”, ”000”, ”0000”, …}. Siksi jos |Σ| = 1, niin merkkijonossa on olennaista vain sen pituus, jolloin teoria käsittelee itse asiassa luonnollisia lukuja. Se on omalla tavallaan mielenkiintoinen asia, mutta ei tämän tehtävän aihe.
Monissa käytännön sovelluksissa merkit ovat tavuja. Data on siis esitetty tavujen jonona. Tavu koostuu 8 bitistä. Silloin |Σ| = näin paljon28 = 256.
Informaatioteoriassa ajatellaan, että on jokin joukko lähdesanoja, joille valitaan esitystavat koodisanoina. Koodisanat ovat Σ*:n alkioita. Tässä tehtävässä (ja usein muuallakin) oletetaan, että lähdesanojen joukko on äärellinen. Lähdesanojen esitystapa ei ole olennainen. Lähdesanojen ja koodisanojen muodostama kokonaisuus on koodi. Kahdella eri lähdesanalla ei saa olla sama koodisana tästä syystäMuuten koodisanan muuntaminen takaisin lähdesanaksi ei aina onnistu. Jos esimerkiksi sekä ”spruce”:n että ”six”:n koodisana on ”kuusi”, niin takaisin käännettäessä ei tiedetä, pitäisikö ”kuusi” kääntää ”spruce” vai ”six”.. Funktion, joka kuvaa lähdesanat koodisanoiksi on siis oltava …injektio. ”Injektio” tarkoittaa funktiota, joka ei kuvaa lähtöjoukon mitään kahta eri alkiota samaksi maalijoukon alkioksi..
On tavallista, että viestissä on useita lähdesanoja peräkkäin. Tällöin koodisanat pitää valita siten, että kukin niiden jono voidaan purkaa niiksi vain yhdellä tavalla. Jollei näin tehdä, niin voi käydä esimerkiksi siten, että lähdekielen ilmaus ”result evening” kääntyy koodisanaksi ”tulosilta”, joka kääntyy takaisin ilmaukseksi ”income bridge” (”tulo silta”). (Televisiossa esitettiin 14.4.2019 Eduskuntavaalit 2019: Tulosilta.)
Yleisin tapa varmistaa tämä on valita koodisanat siten, että mikään niistä ei ole toisen aito alkuosa. Sana etuliitekoodi (prefix code) tarkoittaa mitä tahansa tällaista koodia. Siis esimerkiksi ei voi olla niin, että sekä ”maa” että ”maali” ovat koodisanoja. Matemaattisesti sanottuna ei ole olemassa sellaisia merkkijonoja σ ja ρ, että ρ ≠ ε ja sekä σ että σρ on koodisana. Äskeisessä ”maali”-esimerkissä σ = …”maa”, ρ = …”li”, ja σρ = …”maali”.
Jos kaikki koodisanat ovat yhtä pitkiä, niin mikään niistä ei ole toisen aito alkuosa. Tietotekniikan maailmanlaajuinen standardimerkistö Unicode sisälsi 137 994 merkkiä (joista varsinaisia näkyviä merkkejä 137 766) toukokuussa 2019, ja siinä on laajennusvaraa suunnilleen miljoonaan merkkiin saakka. UTF-32 esittää ne kaikki käyttäen täsmälleen neljä tavua merkkiä kohden.
Kaikkien koodisanojen tekeminen yhtä pitkiksi johtaa helposti muistin ja tietoliikennekapasiteetin tuhlaamiseen. Tästä syystä UTF-32:sta käytetään vähän. Esimerkiksi suomenkielelle riittäisi mainiosti yksi tavu merkkiä kohden. (Aikoinaan suosittu merkistö ISO/IEC 8859-1 olikin sellainen.) Syyskuussa 2019 ylivoimaisesti suosituin esitystapa (94 % maailman veppisivuista) oli UTF-8. Se käyttää yhdestä neljään tavua merkkiä kohden. UTF-8-koodatun merkin ensimmäinen tavu sisältää tiedon, montako tavua merkin koodisana sisältää. Siksi mikään UTF-8-koodattu merkki ei voi olla toisen UTF-8-koodatun merkin aito alkuosa.
Usein esiintyville lähdesanoille kannattaa antaa lyhyet koodisanat ja harvoin esiintyville pitemmät koodisanat. Tätä ei kuitenkaan voi tehdä siten, että 256 useimmin esiintyvää lähdesanaa saa yhden tavun pituisen koodisanan, seuraavat 2562 = 65 536 kahden tavun pituisen ja niin edelleen, koska …Silloin esimerkiksi koodisanojen jonosta ”aa” ei tiedettäisi, esittääkö se sitä lähdesanaa, jonka koodisana on ”aa”, vai kahta peräkkäistä esiintymää siitä lähdesanasta, jonka koodisana on ”a”.
Olettakaamme havainnollisuuden vuoksi, että Σ = {’0’, ’1’, …, ’9’} ja haluamme koodata sata erilaista lähdesanaa etuliitekoodilla. Yksi mahdollisuus on käyttää kullekin koodisanalle kaksi merkkiä, eli koodisanat ovat ”00”, ”01”, …, ”09”, ”10”, …, ”99”. Jos jollekin lähdesanalle annetaankin koodisanaksi ”0”, niin kuinka monelle lähdesanalle joudutaan antamaan vähintään kolmen merkin pituinen koodisana? vihje 1Muodosta ehdot täyttävä koodi. Ensimmäinen koodisana on ”0” ja mikään muu ei ala ’0’:lla. Kolmen merkin pituisia on niin paljon, että koodisanoja on kaikkiaan sata. Mikään kolmen merkin pituinen ei ole minkään kahden merkin pituisen jatke. Sellaisesta koodista on esimerkki vihje 2:ssa. vihje 2”0”, ”10”, ”11”, …, ”19”, ”20”, …, ”98”, ”990”, ”991”, …, ”999”. vastaus10 Kaikkein useimmin esiintyvän lähdesanan esittäminen yhdellä merkillä kannattaa tässä esimerkissä siis vain, jos se esiintyy vähintään yhtä useasti kuin näin monta10 harvinaisinta lähdesanaa yhteensä.
Merkitsemme eri lähdesanojen todennäköisyyksiä p1, …, pn ja vastaavien koodisanojen pituuksia l1, …, ln. Koodatun viestin pituus on keskimäärin p1l1 + p2l2 + … + pnln. Esimerkiksi jos koodisanat ja niiden osuudet ovat oheisen taulukon mukaiset, niin koodattu viesti on keskimäärin näin pitkä0,60 ⋅ 1 + 0,25 ⋅ 3 + 0,10 ⋅ 3 + 0,05 ⋅ 3 = 1,8. Onko taulukon koodi etuliitekoodi? vastausOn.
”0” ”100” ”101” ”111” 60 % 25 % 10 % 5 %
Tätä koodia on helppo muuntaa siten, että muunnettukin koodi on etuliitekoodi mutta koodattujen viestien keskimääräinen pituus vähenee. Näin se käy!Koodisanan ”111” tilalla voi olla ”11”. Sen jälkeen keskipituus on 1,75. Vielä parempi tulos 1,55 saadaan varaamalla ”11” sille lähdesanalle, jonka todennäköisyys on 25 % (jolloin se lähdesana, jonka todennäköisyys on 5 %, saa koodisanan ”100”).
Kun sanomme, että etuliitekoodi on optimaalinen, niin oletamme, että eri lähdesanojen esiintymistodennäköisyydet on kiinnitetty ja tarkoitamme, että koodi tuottaa keskimäärin niin lyhyet koodatut viestit kuin mahdollista. Tarkoitamme siis, että p1l1 + p2l2 + … + pnln on mahdollisimman pieni. Jos Σ = {’0’, ’1’} ja lähdesanojen todennäköisyydet ovat 60 %, 25 %, 10 % ja 5 %, niin onko koodi {”00”, ”01”, ”10”, ”11”} optimaalinen? vastausEi ole. Sen tuottama keskipituus on 2. Edellä näytetty koodi tuotti 1,8 ja sen parannettu versio 1,55.
Näillä todennäköisyyksillä siis kannattaa antaa eri lähdesanoille eripituisia koodisanoja. Osoitamme seuraavaksi tuloksen, joka tuskin yllättää.
Lause 1 Jos kaikki lähdesanat ovat yhtä todennäköisiä, niin optimaalisessa etuliitekoodissa koodisanojen pituudet poikkeavat toisistaan enintään yhdellä.
Todistus. Osoitamme, että jos etuliitekoodissa on kaksi koodisanaa, joiden pituusero on ainakin 2, niin sitä voi muuttaa tiiviimmäksi siten, että se säilyy etuliitekoodina. Annamme lyhyemmälle niistä nimen σ ja sitä vastaavalle lähdesanalle s. Pidemmälle annamme nimen ρa1, missä ρ on merkkijono ja a1 on merkki. Annamme tällaisen nimen, koska se tulee olemaan kätevä jatkossa. Lupa antaa tällainen nimi tulee siitä, että pidemmässä koodisanassa on varmasti ainakin yksi merkki, koska se on ainakin 2 merkkiä pitempi kuin σ.
Oletetun pituuseron vuoksi pätee |ρa1| ≥ |σ| + 2. Siitä seuraa |ρ| ≥ |σ| + 1 eli |ρ| > |σ|.
Jos koodissa ei ole muita ρ-alkuisia koodisanoja kuin ρa1, niin sitä voi tiivistää tällä tavallaVaihdetaan ρa1:n tilalle ρ..
Muussa tapauksessa olkoot ρ-alkuiset koodisanat ρa1, …, ρan, missä n ≥ …2 tästä syystäTodistuksen alun perusteella ρ-alkuisia koodisanoja on ainakin yksi, ja olemme muussa tapauksessa kuin siinä, jossa niitä on vain yksi.. Olkoot s1, …, sn niitä vastaavat lähdesanat. Vaihdetaan niiden koodisanoiksi σa1, …, σan ja s:n koodisanaksi ρ. Mikään minkään σai:n aito alkuosa ei ole syntyvän koodin koodisana tästä syystäMikään minkään σai:n aito alkuosa ei ole ρ, koska |ρ| > |σ|. σ lakkaa olemasta koodisana. Mikään σ:n aito alkuosa ei ole koodisana, koska se ei ollut koodisana alkuperäisessä koodissa, koska σ oli siinä koodisana ja se oli etuliitekoodi.. Mikään ρ:n aito alkuosa ei ole syntyvän koodin koodisana tästä syystäσ ei voi olla ρ:n alkuosa, koska alkuperäinen koodi oli etuliitekoodi ja siinä σ ja ρa1 olivat koodisanoja. Siksi myöskään mikään σai ei voi olla ρ:n alkuosa. Mikään ρ:n aito alkuosa ei ole koodisana, koska se ei ollut koodisana alkuperäisessä koodissa, koska ρa1 oli siinä koodisana ja se oli etuliitekoodi.. Siksi koodi säilyy etuliitekoodina.
Tämä muuttuu selvemmäksi, kun piirrät kuvan. Valitse kuvaan koodisanoiksi ”tali”, ”talk”, ”talo” ja ”te”. Nyt σ = …”te”, ρ = …”tal”, n = …3, ja a1, …, an ovat …’i’, ’k’ ja ’o’. Piirrä deterministisen äärellisen automaatin näköinen kuva jossa haarat eivät yhdisty, ja muunna se kuvaksi, jossa koodisanat ovat σa1 ja niin edelleen.
s:n koodisana pitenee näin monen|ρ| − |σ| merkin verran ja jokaisen si:n koodisana lyhenee näin monen|ρai| − |σai| = |ρ| − |σ| merkin verran. Nämä lyhenemät ja pitenemät ovat positiivisia tästä syystäEdellä todettiin, että |ρ| > |σ|.. Koska n ≥ 2, lyhenemistä on enemmän kuin pitenemistä. □
Jos kaikki lähdesanat eivät olekaan yhtä todennäköisiä, niin optimaalisen koodin muodostaminen on mielenkiintoinen tehtävä. MIT:n professori Robert Fano oli sitä turhaan yrittänyt. Hän antoi vuonna 1951 opiskelijaryhmälle tehtäväksi kirjoittaa ongelmaa käsittelevä essee. David Huffman onnistui ratkaisemaan ongelman. Huffmanin koodi on tietokoneille helppo laatia ja käyttää, ja sen optimaalisuuden todistus on kiehtova. Jos haluat tutustua niihin perusteellisemmin, niin suorita tehtävä Shannonin alaraja.
Huffmanin koodi ei kuitenkaan ole koko totuus, koska lähdesanojen todennäköisyydet voivat riippua edeltävistä lähdesanoista. Havainnollistamme tätä esimerkillä, joka on käytännön kannalta typerä, mutta siitä huolimatta osoittaa, että toisinaan informaatiota voi tiivistää paljon enemmän kuin mihin Huffmanin koodi pystyy.
Esimerkissä viesti muodostuu merkkipareista, joissa sama merkki esiintyy kahdesti tähän tyyliin: ”eessiimmeerrkkkkii”. Jos a ja b ovat kaksi eri merkkiä, niin merkkiparit aa ja bb ovat yhtä todennäköiset, ja merkkiparin ab todennäköisyys on tämä0, koska juuri sanoimme, että merkkiparin merkit ovat sama merkki.. (ab voi kuitenkin esiintyä siten, että ensin on merkkipari aa ja heti sen perässä merkkipari bb.) Optimaalinen etuliitekoodi esittää jokaisen merkin yhdellä merkillä, mutta puolet parempaan tulokseen päästään ottamalla kunkin merkkiparin jälkimmäinen merkki pois. Esimerkiksi ”eessiimmeerrkkkkii”:stä tulee tämä”esimerkki”.
Realistisempi esimerkki saadaan suomenkielestä. Kirjaimen ’a’ yleisyys on yli 11 %, mutta jos kaksi viimeksi luettua merkkiä olivat ’a’ ja ’a’, niin todennäköisyys sille, että seuraavakin merkki on ’a’, on likimain nolla.
Tämä ilmiö voidaan ottaa Huffmanin koodissa huomioon koodaamalla merkkipareja, merkkikolmikoita tai niin edelleen. Tällöin kuitenkin lähde- ja koodisanojen määrä kasvaa nopeasti hallitsemattomaksi ja lähdesanojen todennäköisyysjakauma muuttuu tapauskohtaiseksi. Esimerkiksi viiden merkin jono ”koodi” esiintyy joissakin suomenkielisissä teksteissä paljon useammin kuin joissakin toisissa. Siksi on kehitetty muita koodeja, kuten Lempel–Ziv–Welch.
Informaation pakkaamisessa myös lähdesanat ovat Σ*:n alkioita. Tavoitteena on koodata lähdeviestinä oleva merkkijono siten, että koodattu merkkijono olisi mahdollisimman lyhyt.
Jokainen pakkausmenetelmä voidaan helposti muuntaa sellaiseksi, että se ei pidennä mitään merkkijonoa enemmän kuin yhden merkin. Näin se käy!Oletimme, että aakkostossa on ainakin kaksi merkkiä. Olkoot ne ’0’ ja ’1’. Olkoon σ alkuperäinen merkkijono ja ρ sen koodattu versio. Jos |ρ| ≥ |σ|, niin palautetaan ”0”σ, muutoin palautetaan ”1”ρ. Toisin sanoen, koetetaan josko koodaaminen lyhentäisi merkkijonoa. Jos kyllä, palautetaan koodattu merkkijono ja jos ei, niin palautetaan alkuperäinen merkkijono. Eteen lisätään ’1’ tai ’0’ kertomaan, kummalla tavalla palautettu merkkijono pitää tulkita. Jos ihan tarkkoja ollaan, niin tällaisissa pohdinnoissa täytyy ottaa huomioon eräs asia. En uskalla jättää sitä kokonaan mainitsematta, koska yksi tapa tuottaa huuhaatuloksia on unohtaa se. Se on kuitenkin niin vähämerkityksellinen ja toisaalta konstikas, että mainitsen sen vain tässäAlkuperäinenkin merkkijono täytyy esittää siten, että sen loppukohta voidaan tunnistaa. Käytännössä tähänkin käytetään etuliitekoodia. Esimerkiksi C:ssä merkkijonon sisäinen esitystapa päättyy aina merkkiin, jonka bittikuvio on 00000000, eikä se merkki voi esiintyä merkkijonon merkkinä. C++:ssa merkkijonon sisäisen esitystavan voi tämän ongelman näkökulmasta ajatella alkavan tiedolla, kuinka pitkä merkkijono on (vaikka todellisuudessa nämä tiedot eivät ole muistissa peräkkäin).. Tästä näkökulmasta on tärkeää, että jos alkuperäiset merkkijonot on esitetty etuliitekoodilla ja alkuperäinen pakkausmenetelmä on etuliitekoodi, niin myös äskeinen enintään yhdellä pidentävä koodi …on etuliitekoodi. Mikään alkuperäisenä palautettu ei voi olla koodattuna palautetun aito alkuosa eikä päinvastoin, koska toiset alkavat ’0’:lla ja toiset ’1’:llä. Mikään alkuperäisenä palautettu ei voi olla toisen alkuperäisenä palautetun aito alkuosa, koska alkuperäinen esitystapa oli etuliitekoodi, ja saman yhden merkin (tässä tapauksessa ’0’) lisääminen eteen ei tuhoa etuliitekoodiominaisuutta. Samankaltainen peruste pätee koodattuna palautettuihin.
Satunnaisissa merkkijonoissa jokainen merkki on yhtä todennäköinen riippumatta siitä, mitä merkkejä on tullut sitä ennen. Siksi lausetta 1 voi käyttää. Se kertoo, että mikään koodi ei voi keskimäärin lyhentää satunnaisia merkkijonoja. Edellä näimme, että voimme kuitenkin yrittää jotain koodia niin että onnistuneesta yrityksestä saamme yhtä merkkiä vaille täyden hyödyn, ja epäonnistuneesta yrityksestä maksamme vain yhden merkin verran. Se on hyvin monia käytännön tarpeita ajatellen mitätön lisähinta, joten tutkimme hetken, olisiko tämä hyödyllinen keino toisinaan lyhentää satunnaisia merkkijonoja.
Tältä kannalta on tärkeää ymmärtää kaksi asiaa, jotka koskevat kaikkia koodeja, siis ei pelkästään etuliitekoodeja. Niistä ensimmäinen on jo mainittu ja jälkimmäistä käsittelemme seuraavaksi:
Jälkimmäisen havainnollistamiseksi oletamme, että haluamme lyhentää joitakin merkkijonoja 10 % ja hyväksymme sen, että koodimme ei kykene esittämään muita merkkijonoja lainkaan. Etuliitekoodien tapauksessa, jotta lyhennettyjä merkkijonoja olisi käytettävissä mahdollisimman paljon, niiden on oltava samanpituiset. Laskujen helpottamiseksi oletamme ensin, että Σ = {’0’, ’1’, …, ’9’}. Silloin erilaisia 10 merkkiä pitkiä merkkijonoja on näin monta1010 = 10 000 000 000 kappaletta ja 10 % lyhyempiä eli 9 merkkiä pitkiä näin monta109 = 1 000 000 000 kappaletta. Jälkimmäinen luku on näin monta10 % edellisestä. Teemme saman laskelman muutamalle muulle merkkijonojen pituudelle.
pituus kappaletta pituus kappaletta osuus 20 näin monta1020 18 näin monta1018 %1 30 näin monta1030 27 näin monta1027 %0,1 100 näin monta10100 90 näin monta1090 %0,000 000 01 10n näin monta1010n 9n näin monta109n %100 ⋅= 100 ⋅ 10−n = 102−n
109n 1010n
Oletamme sitten, että merkit ovat tavuja. Jos alkuperäisten merkkijonojen pituus on 10, niin niistä noin 0,4 % voidaan esittää koodilla, jossa jokaisen koodisanan pituus on 9. Taulukossa on tämä ja muutama muu tulos. Älä laske miinusta itsellesi, vaikka yleisen kaavan johtaminen ei onnistuisikaan.
pituus pituus osuus 10 9 0,4 % 20 18 0,0015 % 100 90 0,000 000 000 000 000 000 000 1 % 10n 9n näin monta %100 ⋅= 100 ⋅ |Σ|−n = 100 ⋅ 256−n
|Σ|9n |Σ|10n
Siis lyhentäminen c merkillä vähentää merkkijonojen määrää niin paljon, että vähennetty määrä saadaan kertomalla alkuperäinen määrä luvulla |Σ|−c. Lyhentäminen 10 prosentilla tarkoittaa, että c = …0,1n, missä n on alkuperäinen pituus.. Jos |Σ| = 256, niin 10 % lyhyempiä merkkijonoja riittää suunnilleen 0,574n osalle alkuperäisiä merkkijonoja. Tämä luku pienenee hyvin nopeasti, kun n kasvaa.
Samankaltainen tulos voidaan johtaa myös sillä oletuksella, että kaikki tiettyä rajaa lyhyemmät merkkijonot ovat käytettävissä. Tarkka kaava on hankala, mutta jos Σ on iso (ja varsinkin jos myös n on iso), niin merkkijonoja, joiden pituus on korkeintaan n − c, on suunnilleen |Σ|−c kertaa niiden merkkijonojen määrä, joiden pituus on täsmälleen n. Kerroin on siis sama kuin äsken, mutta nyt se on vain likimääräisesti pätevä. Tämä arvio heittää enintään 10 % kun |Σ| > 10.
Olkoon valittu mikä tahansa häviötön pakkausmenetelmä. Edellä olleista luvuista voi arvata ja kaavoista voi laskea täsmällisesti, että todennäköisyys sille, että se pystyy lyhentämään satunnaisesti valittua vaikkapa 1000 merkkiä pitkää tavujonoa edes 10 % on kertakaikkisen mitättömän pieni, ja todennäköisyys pienenee vielä siitäkin sitä mukaa kuin tavujonon pituus kasvaa. Pitkän satunnaisen merkkijonon olennainen lyheneminen ei siis ole täysin mahdotonta, mutta on niin harvinaista, että sillä ei ole käytännössä mitään merkitystä. Toisinaan tämä ilmaistaan lyhyenä väitteenä, joka ei ole matemaattisen tarkka, mutta on käytännön tarpeita ajatellen totta:
Satunnaista dataa ei voi pakata häviöttömästi.
Kuitenkin monenlaista dataa pystytään käytännössä pakkaamaan tuntuvasti. Se perustuu kolmeen asiaan.
Seuraavassa luvussa viemme tiedostossa sijaitsevaan säännönmukaisuuteen perustuvan pakkaamisen ajatuksen äärimmilleen. Sitä ennen: olet suunnittelemassa hyvisten valtion puolustusvoimille viestintäjärjestelmää. Tiedot pitää salata, jotta vihollinen ei voisi niitä lukea, ja pakata, koska tiedonsiirtokapasiteetti on sotatilanteessa niukka. Ensin kannattaa tehdä tämäpakata ja vasta sitten tehdä se toinen tästä syystäSalaamisen jälkeen viesti näyttää satunnaiselta, joten pakkaaminen ei pysty sitä lyhentämään..
Toivottavasti hoksasit, että
w&6.$e!'*<&1jd5ä&>5ä}ä`'n1!,72-e,
+%+e*(+&b+>&+st5~4,%9t;m
Viestissä voi toki oikeastikin olla merkityksetöntä sisältöä. Esimerkiksi tästä löytyy historiallisesti merkittävä julkaisu skannattuna. Sen etusivulla olevat tahrat eivät ole julkaisun kirjoittajan tarkoittamaa informaatiota, mutta ovat silti tiedostoa käsittelevien tietokoneohjelmien näkökulmasta informaatiota. Tällaista häiriöinformaatiota sanotaan kohinaksi. Palaamme kohinaan myöhemmin. Tämän luvun ajan oletamme, että tarkasteltavissa merkkijonoissa ei ole kohinaa.
Merkkijono ”+++++++++” ei sisällä kohinaa ja on yhtä pitkä kuin ”lentokone”, mutta intuitio sanoo, että siinä on vähemmän informaatiota kuin merkkijonossa ”lentokone”. Samoin intuitio sanoo, että kirjat ”Asterix Hispaniassa” ja ”Asterix Britanniassa” sisältävät yhteensä enemmän informaatiota kuin kaksi kappaletta kirjaa ”Asterix Hispaniassa” sisältää yhteensä.
Intuitiolle sopisi informaatiokäsite, jonka mukaan merkkijonon sisältämän informaation määrä voi olla paljon merkkijonon pituutta pienempi. Kutsumme tätä hypoteettista informaatiokäsitettä i-informaatioksi. Merkkijonon lyheneminen häviöttömässä pakkaamisessa olisi mahdollista vain silloin, kun …merkkijono sisältää pituuttaan vähemmän i-informaatiota. Pakatun merkkijonon pituus olisi aina vähintään …alkuperäisen merkkijonon i-informaation määrä. I-informaation tarkka määrä olisi lyhyimmän sellaisen merkkijonon pituus, joksi alkuperäinen merkkijono voidaan pakata kun pakkausmenetelmän saa valita vapaasti.
Ihan tällaisenaan tätä ajatusta ei voi toteuttaa siksi, että mikä tahansa merkkijono saadaan pakattua yhteen merkkiin valitsemalla sopiva pakkausmenetelmä. Johdannoksi siihen näytän esimerkin toisesta, samankaltaisesta ilmiöstä. Jollet vielä kokeillut, mitä edellä ollut salauskone tekee merkkijonolle ”+++++++++”, niin kokeile nyt! vihje 1Älä syötä salauskoneelle ”-merkkejä, koska ne eivät ole osa merkkijonoa vaan vain osoittavat sen alku- ja loppukohdan. Syötä pelkästään +-merkkejä. vihje 2Kokeile myös suurempia määriä +-merkkejä.
Ongelma on siis se, että jokaisen merkkijonon i-informaation määräksi tulee yksi merkki, koska jokaiselle merkkijonolle voidaan keksiä pakkausmenetelmä, jolla juuri se merkkijono pakkautuu yhteen merkkiin. Muuta ei tarvita kuin sopia, että ”\\” tarkoittaa tätä’\’ merkkiä , ”\”” tarkoittaa tätä’”’ merkkiä, ”\!” tarkoittaa tätä’!’ merkkiä, ja ”!” tarkoittaa esimerkiksi jonkin tuhatsivuisen kirjan koko sisältöä. Tämä voidaan välttää sopimalla, että i-informaation määrään tulee laskea paitsi pakattu merkkijono, myös se menetelmä, jolla pakattu merkkijono puretaan.
Miten purkumenetelmän i-informaation määrä mitataan? Purkamisen toteuttavan aliohjelman pituudella! Jos järkevä tuhatsivuinen kirja on pakattu yhdeksi merkiksi ’!’ edellä kuvatulla tavalla, niin kirjan sisältö joudutaan jokseenkin varmasti kirjoittamaan purkualiohjelmaan. Tällöin tuntuisi epäreilulta laskea kirjan i-informaation määräksi yksi merkki, mutta ottamalla purkualiohjelman pituus mukaan laskelmaan tulee siihen kirjoitettu kirjan sisältö otettua asianmukaisesti huomioon.
Pakattua merkkijonoa ei enää tarvita erillisenä käsitteenä tästä syystäSe voidaan sisällyttää aliohjelmaan merkkijonovakiona.. Silloin syntyy aliohjelma, joka ei ota mitään syötteekseen ja joka palauttaa sen merkkijonon, jonka i-informaation määrästä on kyse. Kuten kaikki aliohjelmat, palautettuaan tuotoksensa tämäkin aliohjelma pysähtyy.
Tämä lähestymistapa kattaa paitsi kaikki tunnetut ja tuntemattomat pakkaus- ja purkualiohjelmina toteutettavissa olevat pakkausmenetelmät, myös kaikki muutkin tavat tuottaa kyseessä oleva merkkijono aliohjelmalla. Olemme motivoineet seuraavan käsitteen.
Määritelmä Merkkijonon σ Kolmogorov-kompleksisuus K(σ) on lyhyimmän sellaisen aliohjelman pituus, joka tyhjällä syötteellä palauttaa σ:n.
Tämä määritelmä ei poista täysin sitä ongelmaa, että jonkin pitkän merkkijonon kompleksisuudesta tehdään keinotekoisesti pieni, sillä ohjelmointikielessä voi olla valmiiksi määritelty merkkijonovakio paksu_kirja, joka sisältää jonkin tuhatsivuisen kirjan sisällön. Tällaisia ei kuitenkaan voi olla miten paljon tahansa, sillä vakioilla täytyy olla nimet ja lyhyet nimet loppuvat jossain vaiheessa kesken. Tärkeämpää on, että kuten kohta havainnollistetaan esimerkeillä, tämä käsite tuottaa pienen kompleksisuuden kaikissa niissä tapauksissa, joissa merkkijonon voi ”rehellisin keinoin” tiivistää lyhyeksi.
Kolmogorov-kompleksisuus siis riippuu valitun ohjelmointikielen yksityiskohdista. Alla olevissa konkreettisissa luvuissa mittayksikkönä on tavu, ja tavujen määrä on laskettu UTF-8-koodatusta esityksestä. Jotta ei lipsahdettaisi edellä mainitun huuhaan puolelle, merkkijonon pituus oletetaan tulkittavan jonkin etuliitekoodiesityksen mukaan. Merkitsemme sellaisenaan aliohjelmaan kirjoitettua merkkijonoa ”…σ…” ja numeromerkeillä kirjoitettua luonnollista lukua ”…n…”. Jos n = 314 ja σ = ”314”, niin sekä return ”…σ…” että return ”…n…” tarkoittaa return ”314”.
|κ| |
2 |
|κ| |
2 |
K ∈ Σ*
ρ := ”…σ…”
return ρρ
Kuinka olennainen edellä saatu konkreettinen lukuarvo 35 on? vastausEi yhtään olennainen. Se riippuu valitusta ohjelmointikielestä. Esitän konkreettisia lukuarvoja vain selventääkseni sitä, että joissakin kohdissa jokin arvo todella on konkreettinen arvo, eikä esimerkiksi jonkin b-nimisen, aliohjelmassa sijaitsevan muuttujan sisältö.
Merkkijonon lisääminen itsensä perään siis lisää sen Kolmogorov-kompleksisuutta vain hieman, sen sijaan että kaksinkertaistaisi sen. Tämä täsmää siihen intuitioon, että kaksi kappaletta samaa kirjaa ei sisällä enempää tietoa kuin yksi kappale. Tarvitaan kuitenkin kirjan paksuudesta riippumaton määrä lisäinformaatiota sanomaan ”ja sama kirja toiseen kertaan”.
Edellä piilevästi oletin, että merkkijonon Kolmogorov-kompleksisuus on enintään suunnilleen sen pituus. Valitettavasti unohdin todistaa sen, kun laadin tämän tehtävän. Siksi sinä joudut paikkaamaan huolimattomuuteni ja todistamaan sen itse.
Lause 2 On olemassa sellainen vakio b, että jokaisella σ ∈ Σ* pätee K(σ) ≤ |σ| + b.
Todistus.
Oheinen aliohjelma palauttaa σ:n.
Sen pituus on |σ| + 24 tavua.
K ∈ Σ*
return ”…σ…”
□
Seuraava aliohjelma palauttaa √2:n desimaaliesityksestä alun ja n desimaalia. Sen pituus on n:n esittämiseen tarvittavien numeromerkkien määrä + 227 tavua. Niinpä on olemassa sellainen vakio b, että √2:n desimaaliesityksen n + 2 merkkiä pitkän alkuosan Kolmogorov-kompleksisuus on enintään log n + b, missä logaritmi on 10-kantainen.
K ∈ Σ*
m := 2
k := 1
σ := ”1,”
for i := 1 to ”…n…” do
m := 100 ⋅ m
k := 10 ⋅ k + 9
c := ’9’
while k ⋅ k > m do
k := k − 1
c := c − 1
σ := σc
return σ
Osoita, että kun n > 0, niin merkkijonon, jossa on
n ’a’:ta peräkkäin eikä muuta, Kolmogorov-kompleksisuus on enintään
log n + b, missä logaritmi on 10-kantainen ja b on jokin
vakio.
vastausAlla oleva aliohjelma palauttaa
kyseessä olevan merkkijonon.
Sen pituus on 76 + ⌊log n⌋ + 1 ≤ log n + 77 tavua, missä
⌊x⌋ tarkoittaa suurinta kokonaislukua, joka on enintään x, ja
⌊log n⌋ + 1 on n:n esittämisessä tarvittavien numeromerkkien
määrä.
K ∈ Σ*
σ := ””
for i := 1 to ”…n…” do
σ := σ”a”
return σ
Osoita, että joillakin n:n arvoilla merkkijonon, jossa
on n ’a’:ta peräkkäin eikä muuta, Kolmogorov-kompleksisuudelle voidaan
antaa paljon pienempi yläraja kuin edellä.
vastausTälle on loputtomasti toinen
toistaan dramaattisempia ratkaisuja.
Esimerkiksi alla olevan aliohjelman pituus on enintään log n + b,
missä logaritmi on 10-kantainen ja b on jokin vakio.
(Edellä käytetyllä laskutavalla b = 124.)
Se palauttaa 10n ’a’:ta peräkkäin.
Jos syntyvän merkkijonon pituutta merkitään m:llä, niin alla olevan
aliohjelman pituus on log log m + b.
K ∈ Σ*
σ := ””
m := 1
for i := 1 to ”…n…” do
m := 10 ⋅ m
for i := 1 to m do
σ := σ”a”
return σ
Edellä näimme, että K(σ):n voidaan todistaa olevan enintään annetun luvun n suuruinen antamalla syötteetön aliohjelma, jonka pituus on n ja joka palauttaa σ:n. Kuinka voidaan todistaa, että merkkijonon Kolmogorov-kompleksisuus on vähintään jonkin luvun suuruinen? Hankimme seuraavaksi hieman tuntumaa tähän kysymykseen.
Kun edellä olleessa esimerkissä valitaan n = 99, niin saadaan 126 merkkiä pitkä aliohjelma, joka palauttaa merkkijonon, jossa on 1 000 000 ⋯ 000 (99 nollaa) ’a’-kirjainta peräkkäin. Siis hyvinkin pitkän merkkijonon Kolmogorov-kompleksisuus voi olla pieni.
Toisaalta näimme aiemmin, että annettua pituutta olennaisesti
lyhyempiä merkkijonoja on hyvin paljon vähemmän kuin sen pituisia
merkkijonoja.
Esimerkiksi enintään 126 merkkiä pitkiä merkkijonoja on hyvin paljon vähemmän
kuin esimerkiksi 1099 merkkiä pitkiä tai edes 150 merkkiä pitkiä
merkkijonoja.
Siitä voidaan tällä tavallaMerkkijonoja, joiden pituus on olennaisesti pienempi kuin |σ|,
on hyvin paljon vähemmän kuin merkkijonoja, joiden pituus on |σ|.
Aliohjelmat ovat merkkijonoja.
Annetun pituisia aliohjelmia on korkeintaan saman verran kuin sen pituisia
merkkijonoja.
Siksi vain hyvin pienelle osalle |σ|:n pituisia merkkijonoja riittää sen
palauttava aliohjelma, joka on olennaisesti σ:aa lyhyempi.
Toisaalta Lauseen 2 mukaan K(σ) ei voi olla olennaisesti suurempi kuin
|σ|. päätellä, että melkein jokaisen merkkijonon σ
Kolmogorov-kompleksisuus on suunnilleen |σ|.
Samaan tyyliin Enintään 100 merkkiä pitkiä merkkijonoja on äärellinen määrä, joten enintään 100 merkkiä pitkiä aliohjelmia on äärellinen määrä. voidaan päätellä, että melkein jokaisen merkkijonon Kolmogorov-kompleksisuus on suurempi kuin 100. Mutta miten voidaan todistaa jostain nimenomaisesta merkkijonosta, että juuri sen Kolmogorov-kompleksisuus on suurempi kuin 100?
Voidaanko Kolmogorov-kompleksisuudeksi todistaa vähintään n ajamalla kaikki sitä lyhyemmät syötteettömät aliohjelmat ja toteamalla, että mikään niistä ei palauta kyseessä olevaa merkkijonoa? vastausJos n on jotain rajaa isompi, niin ei voida. Osa aliohjelmista ei pysähdy ja pysähtymisen testaaminen on ratkeamatonta, joten tarpeeksi isolla n joudutaan loputtomasti odottamaan jonkin aliohjelman valmistumista ilman että voidaan saada selville, että se ei valmistu koskaan.
Jälleen kerran tulosta voidaan manipuloida ohjelmointikielen valinnalla. Jos aliohjelmasta paluun avainsanaksi vaihdetaan return:n sijaan ”nyt on aika tulla ulos tästä aliohjelmasta, sillä laskut on saatu valmiiksi, ja tässäpä onkin nätti merkkijono, joka täten palautetaan aliohjelman tuloksena”, niin jokainen aliohjelma on yli 100 merkkiä pitkä, joten jokaisen merkkijonon Kolmogorov-kompleksisuus on yli 100. Siksi emme johda tulosta, jossa on konkreettinen lukuarvo, vaan ainoastaan tuloksen, jossa sanotaan, että jokin lukuarvo on olemassa.
Muissa suhteissa tuloksemme onkin hyvin vahva. Se kattaa kaikki realistiset keinot yrittää osoittaa, että annetun merkkijonon Kolmogorov-kompleksisuus on vähintään annetun suuruinen. Se kattaa matemaattisen todistamisen, syötteettömien aliohjelmien koeajamisen ja niin edelleen. Se kattaa myös keinot, jotka eivät vastaa ”kyllä” tai ”ei”, vaan ”kyllä” tai ”en tiedä”.
Määritelmä Ainakin-todistaja on aliohjelma, joka ottaa syötteeksi merkkijonon σ ja luonnollisen luvun n, ja pysähtyy palauttaen T tai F. Jos se palauttaa T, niin K(σ) ≥ n.
Ainakin-todistaja pysähtyy kaikilla syötteillä. Jos se palauttaa F, niin K(σ) saa olla mitä tahansa.
Kuten tehtävässä Lisää pysähtymisen testaamisesta todettiin, alla olevaa aliohjelmaa toistuvasti kutsumalla saadaan kaikki merkkijonot lyhimmästä alkaen. Havainnollisuuden vuoksi aliohjelma käyttää merkkejä ’0’ ja ’9’, mutta ne edustavat aakkoston pienintä ja suurinta merkkiä. Ykkösen lisääminen merkkiin tuottaa aakkosjärjestyksen mukaan seuraavan merkin.
seuraava(σ ∈ Σ*) ∈ Σ*
i := 1
while i ≤ σ.pituus ∧ σ[i] = ’9’ do
σ[i] := ’0’
i := i + 1
if i ≤ σ.pituus then
σ[i] := σ[i] + 1
else
lisää σ:n loppuun '0'
Olkoon ainakin ainakin-todistaja. Tarkastelemme alla olevan mallin mukaista aliohjelmaa κn, jossa while-silmukan ehdossa esiintyvä luku on n > 0. Havainnollisuuden vuoksi n on kirjoitettu myös aliohjelman nimeen, mutta oletamme, että todellisesta aliohjelmasta se puuttuu. Pätee |κn| = |κ1| + ⌊log n⌋.
κ23 ∈ Σ*
σ := ””
while ¬ ainakin(σ, 23) do
σ := seuraava(σ)
return σ
Jos n on tarpeeksi iso, niin n > |κ1| + log n. Oletetaan, että ainakin(σ, n) palauttaa T sellaisella n ainakin yhdellä σ. Silloin κn palauttaa merkkijonon σ, jolle K(σ) ≥ n while-silmukan ehdon vuoksi. Toisaalta K(σ) ≤ |κn| = |κ1| + ⌊log n⌋, koska κn palauttaa σ:n. Siis K(σ) ≥ n > |κ1| + log n ≥ |κn| ≥ K(σ), joten K(σ) > K(σ), mikä on mahdotonta. Tämä ristiriita osoittaa, että jos n on tarpeeksi iso, niin ainakin(σ, n) ei voi millekään merkkijonolle σ palauttaa tietoa, että K(σ) ≥ n.
Olemme todistaneet seuraavan.
Lause 3 Jokaiselle ainakin-todistajalle ainakin on olemassa sellainen vakio c, että jokaiselle σ ∈ Σ* ja jokaiselle n ≥ c ainakin(σ, n) palauttaa F.
Tästä voidaan johtaa tuloksia, jotka kertovat, että vaikka melkein jokaisen merkkijonon Kolmogorov-kompleksisuus on suunnilleen sama kuin merkkijonon pituus, mikään keino ei pysty todistamaan kuin poikkeustapauksissa, että jonkin nimenomaisen merkkijonon Kolmogorov-kompleksisuus on suunnilleen sama kuin merkkijonon pituus. Alla on muotoiltu täsmällisesti yksi tällainen väite.
Lause 4 Jokainen ainakin-todistaja palauttaa T vain äärelliselle määrälle syötteitä, joissa n ≥ 0,9|σ|.
Todistus.Jos |σ| ≥ 0,111… ⋅ c ja n ≥ 0,9|σ|, niin n ≥ 0,9 ⋅ 0,111… ⋅ c = c. Silloin lauseen 3 mukaan ainakin-todistaja palauttaa F. Siksi n ≥ 0,9|σ| ja tulos T ovat yhtäaikaa mahdolliset vain, jos |σ| < 0,111… ⋅ c. Sellaisia σ on äärellinen määrä, koska jokaiselle luonnolliselle luvulle k pätee, että enintään k:n pituisia merkkijonoja on äärellinen määrä. □
Puhumisen helpottamiseksi sanomme epätäsmällisesti, että merkkijonon Kolmogorov-kompleksisuus on suuri, jos ja vain jos se on ainakin suunnilleen sama kuin merkkijonon pituus, ja pieni muutoin. Tapaukset, joissa merkkijonon Kolmogorov-kompleksisuus on paljon suurempi kuin merkkijonon pituus, eivät ole kiinnostavia, koska …Lause 2 kertoo, että niitä ei ole.
Tälla puhetavalla ilmaistuna tämäMelkein jokaisen merkkijonon σ Kolmogorov-kompleksisuus on suunnilleen |σ|. aikaisemmin kerrottu tosiasia ja Lause 4 kertovat, että melkein kaikkien merkkijonojen Kolmogorov-kompleksisuus on suuri, mutta mikä tahansa tapa yrittää todistaa merkkijonon Kolmogorov-kompleksisuus suureksi epäonnistuu melkein kaikissa tapauksissa (onnistuu vain äärellisessä määrässä tapauksia). Meillä on siis väite, joka on melkein kaikille merkkijonoille totta, mutta on melkein kaikille merkkijonoille mahdoton todistaa todeksi!
Vielä pahempaa:
Lause 5 Olkoon c kuten Lauseessa 3. Melkein jokaisen merkkijonon Kolmogorov-kompleksisuus on vähintään c, mutta mistään merkkijonosta ei voi todistaa, että sen Kolmogorov-kompleksisuus on vähintään c.
Todistus.Koska alle c:n pituisia merkkijonoja on vain äärellinen määrä, on alle c:n pituisia aliohjelmia vain äärellinen määrä, joten vain äärellisen määrän merkkijonoja Kolmogorov-kompleksisuus on alle c. Tämä on mitätön osuus kaikista merkkijonoista, koska kaikkiaan niitä on äärettömästi. Lause 3 sanoo, että mistään merkkijonosta ei voi todistaa, että sen Kolmogorov-kompleksisuus on vähintään c. □
Edellisen luvun tulos tarkoittaa, että pääsääntöisesti ei ole mitään keinoa olla varma, että merkkijonon Kolmogorov-kompleksisuus ei ole pienempi kuin pienin sille jo tunnettu alaraja. Jos tiedetään keino tuottaa σ lyhyellä aliohjelmalla, niin tiedetään, että σ:n Kolmogorov-kompleksisuus on enintään aliohjelman pituinen. Jos myöhemmin löytyy lyhyempi aliohjelma, niin arvio paranee. Jollei löydy, niin yleensä jää avoimeksi, onko arvio jo paras mahdollinen. Annetun merkkijonon Kolmogorov-kompleksisuudesta ei siis pääsääntöisesti voida tietää mitään muuta kuin että se on korkeintaan jokin tunnettu luku.
Vielä on käsittelemättä se mahdollisuus, että merkkijonossa on mukana kohinaa. Kohinaisen merkkijonon Kolmogorov-kompleksisuus koostuu hyötyinformaation Kolmogorov-kompleksisuudesta ja kohinan Kolmogorov-kompleksisuudesta. Koska kohina on usein täysin tai melko satunnaista ja …satunnaista dataa ei voi pakata häviöttömästi, pääsääntö on, että kohinaisen merkkijonon Kolmogorov-kompleksisuus määräytyy kohinan eikä hyötyinformaation Kolmogorov-kompleksisuuden mukaan.
Siksi kohinainen data pakkautuu yleensä huonosti häviöttömillä pakkausmenetelmillä. Häviölliset pakkausmenetelmät poistavat kohinaa tehokkaasti, ja siten mahdollistavat esimerkiksi valokuvien pakkaamisen huomattavasti pienempään tilaan kuin kamerakennolta tuleva raakadata vie. Valitettavasti ne samalla poistavat myös hyötyinformaatiota.
Kuten monesta muustakin aiheesta, tästäkin aiheesta tiedetään paljon enemmän kuin tällainen lyhyt veppisivu voi kertoa. Lisätietoa voi metsästää vaikka avainsanoilla ”algorithmic information theory”.