Neon felirat: P=NP?

Episode I

Alice és Bob

7. fejezet

Alice és Bob egymillió dolláros kérdése

Az előző fejezetben megismerkedtünk a formális nyelvek és a Turing-gép fogalmával és láttuk, hogy a Turing-gépeket hogyan lehet optimalizálási vagy döntési problémák megoldására használni. A továbbiakban döntési problémákról, illetve azok "nehézségéről" lesz szó. Láttuk, hogy minden döntési problémának megfeleltethető egy valamilyen véges ábécé feletti formális nyelv. Amennyiben a probléma egyes példányait, azaz az eldöntendő kérdéseket ezen ábécé elemeiből alkotott jelsorozatokkal reprezentáljuk, úgy az algoritmikus feladat annak eldöntése, hogy egy adott jelsorozat mondata-e egy adott nyelvnek vagy sem. Azokat neveztük algoritmikusan eldönthető problémáknak, amelyek esetén a nyelvbe tartozás kérdése eldönthető Turing-géppel anélkül, hogy az végtelen ciklusba keveredne. A továbbiakban csak ilyen problémákkal foglalkozunk. De vajon mikor tekinthető egy döntési probléma "nehéznek" vagy "könnyűnek"? Mi számít vízválasztónak ilyen tekintetben? Valóban léteznek igazán "nehéz" problémák, vagy csupán ügyetlenek vagyunk? Mit mond erről a számítástudomány – és talán az egész matematika – egyik legfontosabb megoldatlan sejtése? Ebben a fejezetben erről lesz szó...

Figyelem! Ennek a fejezetnek a megértéséhez erősen ajánlott elolvasni az előző fejezetet is.

Egy adott feladat esetén nem egyszerűen az a cél, hogy találjunk rá egy algoritmust. Az is fontos, hogy az algoritmus bizonyos szempontból minél jobb legyen. Az algoritmust megvalósító Turing-gép szempontjából a "jóságot" kétféleképpen mérhetjük. Mérhetjük egyrészt, hogy a Turing-gép a végrehajtás során mennyi cellát használ fel a szalagjaiból, azaz hogy legalább mekkora tárolókapacitásra van szüksége ahhoz, hogy a döntést meghozza. Ezt a Turing-gép tárkomplexitásának nevezzük. Másrészt mérhetjük azt is, hogy a Turing-gépnek a döntésig hány elemi lépést kell megtennie. Ezt a Turing-gép időkomplexitásának nevezzük.

Igazából az érdekel minket, hogy a bemenet méretének függvényében e két mennyiség milyen gyorsan növekszik. Habár adott esetben mindkét érték fontos lehet, mi az egyszerűség kedvéért a továbbiakban elsősorban az időkomplexitást fogjuk vizsgálni. Nézzünk először egy példát, hogy lássuk, pontosan miről is van szó.

Gráfok színezése

A távoli Kompánia ország lakói között vannak, akik utálják egymást, és vannak, akik nem. Ez az állítás persze minden országra igaz, de mi most szorítkozzunk Kompániára. Feltételezzük, hogy két ember közötti utálat vagy nem utálat kölcsönös, azaz vagy mindkettő utálja a másikat, vagy egyik sem. Az algoritmikus döntési feladat annak eldöntése, hogy felosztható-e az egész ország két pártra úgy, hogy az azonos pártban lévők ne utálják egymást.

Ezt ábrázolhatjuk egy úgynevezett "utálatgráffal", amely csúcsokból és őket összekötő élekből áll. A gráfokról a 4.2. szakaszban a csatornamodellek kapcsán már volt szó. Ebben a példában a gráf minden csúcsa egy-egy embert jelképez, és két csúcs pontosan akkor van összekötve éllel, ha a nekik megfelelő két ember utálja egymást. Jelöljük az egyik pártot -val, a másikat pedig -gyel. Ekkor a feladat annak eldöntése, hogy az "utálatgráf" csúcsai megjelölhetők-e -gyel vagy -val úgy, hogy két szomszédos csúcs soha ne kapjon ugyanolyan jelölést. Ezt a gráfelméletben szemléletesen színezésnek nevezzük. A kérdés tehát így hangzik: kiszínezhetőek-e egy adott gráf csúcsai két színnel úgy, hogy a szomszédos csúcsok ne legyenek azonos színűek? Amennyiben ez megtehető egy adott gráfra, akkor azt mondjuk, hogy a gráf 2-színezhető.

A 7.1. ábrán látható gráf például nem 2-színezhető.

Nem 2-színezhető gráf (példa)
7.1. ábra: Nem 2-színezhető gráf (példa)

Ezzel szemben a 7.2. ábrán látható gráf 2-színezhető, a csúcsokhoz rendelt számok pedig egy helyes 2-színezést jelölnek.

2-színezhető gráf (példa)
7.2. ábra: 2-színezhető gráf (példa)

Most próbáljunk meg algoritmust adni a 2-színezhetőség eldöntésére. A könnyebb érthetőség miatt az algoritmust nem egy Turing-gép szabályrendszerének szintjén, hanem természetes nyelven fogjuk leírni. Elemi lépéseknek az alábbiakat fogjuk tekinteni:

  • Tetszőleges csúcs színének olvasása és írása.
  • Tetszőleges csúcs szomszédainak lekérdezése.

Első ötletünk az lehet, hogy szisztematikusan végigpróbálgatjuk az összes lehetséges színezést. Ha egy színezéssel megvagyunk, akkor leellenőrizzük, hogy a kapott színezés helyes-e, vagy nem. Ezt úgy tudjuk megtenni, hogy minden csúcs színére megvizsgáljuk, hogy különbözik-e a szomszédos csúcsok színeitől. Amennyiben egy adott színezés esetén ez minden csúcsra teljesül, akkor nyilván találtunk egy helyes 2-színezést. Ekkor a döntési algoritmus kimenete "igen". Amennyiben ilyen színezést nem találtunk, úgy a kimenet "nem". Ez az algoritmus nyilvánvalóan tetszőleges bemeneti gráf esetén véges sok lépés alatt eldönti a kérdést. A gráf csúcsainak száma ugyanis véges, ezért a lehetséges színezések száma – amelyeket ugye egyenként ellenőrizni kell – is véges.

Ha most a 6.2. szakaszban ismertetett Turing-gép szintjén vizsgáljuk a kérdést, akkor a bemeneti gráfot egy valamilyen véges ábécé szimbólumaiból alkotott jelsorozat formájában kell a Turing-gép bemeneti szalagjára írni. Miután a Turing-gép végzett, a kimeneti szalagon ott lesz az "igen" vagy "nem" választ reprezentáló jelsorozat. Nyilvánvalóan szerkeszthető olyan Turing-gép erre a döntési feladatra, amely soha nem kerül végtelen ciklusba. Például a fenti, minden lehetséges színezést kipróbáló buta algoritmusunk "Turing-gépesített" változata. A 6.6. szakasz terminológiája alapján elmondhatjuk tehát, hogy a 2-színezhető gráfok leírásaiból alkotott formális nyelv rekurzív, vagy más néven algoritmikusan eldönthető.

Ez mind szép és jó, a gond csak az, hogy viszonylag sokáig tart. Ha például Kompánia lakosainak száma (ami azért nem túl sok), akkor lehetséges színezés van. Ha brutálisan gyors számítógépünk van, ami másodpercenként milliárd színezést tud megvizsgálni, akkor is több, mint milliárd évig tartana az algoritmus futása. Ennyi időt még akkor sem vagyunk hajlandók várni, ha nagyon nem szeretnénk egypártrendszert. Az algoritmusunk tehát hiába működik elméletben, a gyakorlatban használhatatlan.

Egy ennél némileg hatékonyabb eljárást ismertetünk az alábbiakban. Válasszunk ki egy tetszőleges csúcsot, és színezzük ki -val. Az már biztos, hogy a kiszínezett csúcs szomszédait -gyel kell színeznünk, ezért színezzük is ki őket. És így tovább, az eddig már kiszínezett csúcsok összes, eddig még ki nem színezett szomszédját színezzük mindig ellenkező színnel. Folytassuk ezt az eljárást addig, ameddig minden csúcsot ki nem színeztünk. Ekkor az algoritmus eredménye legyen "igen". Előfordulhat, hogy menet közben találunk egy olyan csúcsot, amelyet ha kiszíneznénk az épp soron következő színnel, akkor megsértenénk a színezési szabályt. Ekkor az algoritmus eredménye legyen "nem". Könnyen belátható, hogy ez az algoritmus is helyes eredményt fog adni. Vizsgáljuk meg az időkomplexitását, amely ugye a szükséges lépések számát jelenti.

Az eljárás lépésszáma arányos a gráfban lévő élek számával. A legrosszabb eset nyilván az, amikor minden csúcs minden más csúccsal össze van kötve, ekkor van ugyanis a gráfban a lehető legtöbb él.

Ebben a legrosszabb esetben egy csúcsú gráf éleinek számát az alábbi képlet adja meg:

Azaz az eljárásunk a lakosú Kompánia utálatgráfjára legfeljebb lépés alatt végez. Egy számítógéppel ez egy pillanat alatt elvégezhető, ezért ez már valóban egy használható algoritmus. Most hasonlítsuk össze az előbbi "buta" és az utóbbi "okos" algoritmus időkomplexitását általánosságban.

Az algoritmusok időkomplexitásának mérése

Vegyük észre, hogy gyakorlatilag lényegtelen, hogy a két algoritmust egy primitív Turing-gép leírásának szintjén, vagy a fenti magasabbszintű leírások alapján vizsgáljuk. A kettő között csak annyi a különbség, hogy mit tekintünk elemi lépésnek. Elképzelhető, hogy egy Turing-gép alacsonyszintű lépéseiben számolva az előző szakaszban kiszámolt lépésszámoknak a többszörösét kapnánk. Az azonban elmondható, hogy ez a szorzó tényező nem függ a bemeneti gráf méretétől. Feltéve persze, hogy értelmes formában írtuk le a Turing-gép bemeneti szalagján a gráfot a használt ábécé szimbólumaival.

Egy algoritmus időkomplexitásának mérésekor tehát elsősorban nem konkrét lépésszámokra vagyunk kíváncsiak. Ilyenkor alapvetően az a lényeges számunkra, hogy a bemenet méretének növelésével milyen gyorsan növekszik a végrehajtáshoz szükséges lépésszám. Ezt az algoritmus skálázódásának nevezzük. Egy olyan "vízválasztót" keresünk tehát, amely elválasztja egymástól a "gyors" és a "lassú" algoritmusokat.

Jelöljük a bemenet méretét -nel. Azt, hogy adott esetben pontosan mire vonatkozik az határozza meg, hogy milyen szinten vizsgáljuk az algoritmust. Egy Turing-gép primitív szintjén például jelölheti a bemeneti jelsorozat szimbólumainak számát. Mi most egy ennél absztraktabb szinten vizsgáljuk a fenti két algoritmust. Gráfalgoritmusokról lévén szó, célszerű az mennyiséget valamilyen módon a bemeneti gráf méretéhez kötni. Jelölje például a gráf csúcsainak számát.

Célunk, hogy találjunk egy olyan -től függő mennyiséget, amelyet a tényleges lépésszám biztosan nem fog meghaladni "elegendően nagy" értékektől kezdve. Más szavakkal valamilyen módon felső becslést szeretnénk adni a szükséges lépésszámra a bemenet méretének függvényében.

Az első, "buta" algoritmusnál láttuk, hogy a lépésszám csúcsú gráf esetén egy olyan mennyiséggel becsülhető felülről, amely -nel arányos. Az olyan függvényeket, ahol a változó mennyiség (amely jelen esetben ) a kitevőben is előfordul, exponenciális függvényeknek nevezzük. Ezzel szemben a második, "okos" algoritmus esetén a lépésszám egy -tel arányos mennyiséggel becsülhető felülről. Az olyan függvényeket, ahol a változónak csak valamilyen rögzített kitevőjű hatványai fordulnak elő, polinomiális függvényeknek nevezzük. Mindkét függvénycsaládnak megvan az a tulajdonsága, hogy zárt a négy alapműveletre. Például két tetszőleges polinomiális függvény összege és szorzata is polinomiális, és ugyanez a zártság igaz az exponenciális függvényekre is.

Ezen kívül igaz az is, hogy bármilyen exponenciális függvény – feltéve, hogy az alapja -nél nagyobb – előbb-utóbb minden polinomiális függvénynél gyorsabban kezd el növekedni. Vegyük például az és az függvényeket. Az első egy -hez közeli alapú (tehát relatíve lassan növekvő) exponenciális függvény, a második pedig egy viszonylag magas kitevőjű (tehát relatíve gyorsan növekvő) polinomiális függvény. A 7.3. ábrán e két függvény grafikonja látható.

Exponenciális és polinomiális függvények összehasonlítása
7.3. ábra: Exponenciális és polinomiális függvények összehasonlítása

Látható, hogy kezdetben ugyan az exponenciális függvény a polinomiális függvény alatt marad, körül azonban végül "beelőzi" azt, és onnantól már sokkal nagyobb sebességgel növekszik. De választhattunk volna egy még lassabban növekvő exponenciális függvényt (például ) és egy még gyorsabban növekvő polinomiális függvényt (például ). Azokra ugyanúgy igaz lenne, hogy az előbbi "beelőzi" az utóbbit, maximum ez magasabb értékénél következik be.

Ezek után a Turing-gép fogalmára lefordítva meg tudjuk adni egy algoritmus "hatékonyságát". Tegyük fel, hogy egy probléma megoldására alkottunk egy Turing-gépet. Ha a probléma egy példányának reprezentációja (a fenti példában egy konkrét gráf leírása) a Turing-gép bemeneti szalagján "betűből" áll, és a Turing-gép legfeljebb lépésben be tudja fejezni a számolást tetszőleges bemenetre, de ennél gyorsabban nem, akkor azt mondjuk, hogy a Turing-gép időkomplexitása . Ha egy valamilyen polinomiális függvénnyel felülről becsülhető, akkor azt mondjuk, hogy a Turing-gép polinomiális időkomplexitású. Ha polinomiális függvénnyel nem, csak exponenciális függvénnyel becsülhető felülről, akkor azt mondjuk, hogy a Turing-gép exponenciális időkomplexitású. A továbbiakban a "probléma" és a "formális nyelv" szavakat, valamint az "algoritmus" és a "Turing-gép" szavakat szinonimaként fogjuk használni. Az előző fejezetben ugyanis láttuk, hogy ezek gyakorlatilag ugyanazt jelentik.

A gyakorlatban felmerülő problémák esetén egy algoritmus hatékonyságának általában egy jó vízválasztója az, hogy polinomiális vagy exponenciális időkomplexitású-e. Elképzelhető azonban, hogy a szóba jövő bemenet-méretek esetén jobb egy exponenciális időkomplexitású algoritmus, mint egy polinomiális. Az előző grafikonon például láthattuk, hogy egy relatíve lassan növő exponenciális függvény értéke egy ideig alatta maradhat egy relatíve gyorsan növő polinomiális függvény értékének. Amennyiben ez a két függvény két különböző algoritmus időkomplexitását jelöli, úgy elmondható, hogy az exponenciális algoritmus mindaddig hatékonyabb a polinomiálisnál, ameddig értéke alatt marad (bármit is jelentsen a bemenet méretére vonatkozóan).

Amennyiben tudható, hogy a bemenet mérete biztosan az értéktartomány alatt fog maradni az algoritmus használata során, úgy nyilvánvalóan ebben a konkrét esetben sokkal jobban megéri az exponenciális algoritmust alkalmazni. Ettől függetlenül nagy általánosságban elmondható, hogy a polinomiális algoritmusokat tekinthetjük "hatékony", míg az exponenciálisakat "rossz" algoritmusoknak.

A P problémaosztály

Most módosítsuk egy kicsit a Kompániára vonatkozó feladatunkat. Ezúttal ne kettő, hanem három pártra próbáljuk meg szétosztani a lakosságot úgy, hogy az egy pártba kerülők ne utálják egymást. Az ide tartozó döntési probléma: kiszínezhetők-e egy adott gráf csúcsai színnel úgy, hogy az azonos színű csúcsok között ne legyen él? Amennyiben ez megtehető egy adott gráfra, akkor azt mondjuk, hogy a gráf 3-színezhető.

A 7.4. ábrán látható gráf például nem 3-színezhető.

Nem 3-színezhető gráf (példa)
7.4. ábra: Nem 3-színezhető gráf (példa)

Ezzel szemben a 7.5. ábrán látható gráf 3-színezhető, a csúcsokhoz rendelt számok pedig egy helyes 3-színezést jelölnek.

3-színezhető gráf (példa)
7.5. ábra: 3-színezhető gráf (példa)

A 7.1. szakaszban bemutatott 2-színezhetőségre vonatkozó döntési problémára lehetett exponenciális és polinomiális időkomplexitású algoritmust is találni. A 3-színezhetőség eldöntésére azonban sajnos nem ismerünk exponenciálisnál gyorsabb algoritmust. Nem tudjuk, hogy létezik-e egyáltalán – csak esetleg még nem találta meg senki –, vagy pedig elméletileg sem létezhet ilyen algoritmus. Ha ez utóbbi a helyzet, akkor nem csak a jelenleg ismert algoritmusok "rosszak", hanem maga a probléma is "nehéz". Ezt jelenleg azonban csak sejtjük. Ezzel szemben a 2-színezhetőség eldöntése "könnyű", mert létezik rá polinomiális algoritmus.

Egy másik gráfelméletből ismert fontos probléma az úgynevezett független csúcsok problémája. Elhelyezhető-e a sakktáblán 8 vezér úgy, hogy ne üssék egymást? A 7.6. ábra mutatja, hogy ez lehetséges, de aki maga próbálta ezt a rejtvényt megfejteni, tudja, hogy nem olyan könnyű egy ilyen elhelyezést megtalálni.

Független csúcsok problémája a sakktáblán
7.6. ábra: Független csúcsok problémája a sakktáblán

Ez a feladat is megfogalmazható a gráfok nyelvén. A sakktábla mezői legyenek a gráf csúcsai, és két csúcsot akkor kössünk össze éllel, ha az egyik mezőről a vezér egy lépéssel el tud jutni a másikba, azaz a másik mezőt "ütni" tudja. Az általános, már gráfokra vonatkozó probléma így szól: adott egy gráf és egy egész szám, a kérdés pedig az, hogy ki lehet-e választani a gráfból darab csúcsot úgy, hogy ezek között a csúcsok között ne legyen él. Ezt úgy mondjuk, hogy található-e a gráfban darab független csúcs. Azokat a gráfokat, amelyekre ez teljesül, k-független gráfoknak nevezzük. A k-függetlenség eldöntésére sem ismert exponenciálisnál gyorsabb algoritmus, tehát ez is egy "nehéz" probléma, legalábbis annak tűnik.

Azokat a rekurzív nyelveket, amelyek eldöntésére létezik polinomiális időkomplexitású determinisztikus Turing-gép, egy osztályba soroljuk, amelyet -vel jelölünk, és a polinomiális időben eldönthető nyelvek osztályának nevezünk. Lényegében az összes hatékonyan kezelhető döntési problémához tartozó nyelv -beli. Ilyen volt például a 2-színezhetőségről szóló probléma. A 3-színezhetőség és a k-függetlenség problémájáról azonban nem tudjuk, hogy vajon -ben vannak-e.

Amit viszont tudunk róluk, hogy – sok más rendkívül fontos algoritmikus problémával együtt – egy -nél általánosabb problémaosztályba tartoznak. Ezért most ezzel a problémaosztállyal ismerkedünk meg. Ennek keretében felfrissítjük emlékeinket a 6.3. szakaszban már említett nemdeterminisztikus Turing-gépekkel kapcsolatban.

Az NP problémaosztály

A nemdeterminisztikus Turing-gépek mindössze abban különböznek a determinisztikus Turing-gépektől, hogy ezek kerülhetnek olyan helyzetbe, amikor egynél több állapotváltási szabály előfeltétele is teljesül. Így ezekben a helyzetekben a gépünk választhat, hogy melyik szabályt fogja alkalmazni. Innen ered a neve is, ugyanis a gép további sorsa ezekben a helyzetekben nem determinált (nem egyértelműen meghatározott).

A 7.7. ábrán egy olyan determinisztikus Turing-gép futása látható, amely egy tetszőleges bemeneti jelsorozat adott nyelvbe tartozását dönti el (azaz az eredménye egy "igen" vagy egy "nem" válasz).

Determinisztikus Turing-gép számítási útvonala
7.7. ábra: Determinisztikus Turing-gép számítási útvonala

A 7.8. ábrán ugyanez látható nemdeterminisztikus Turing-gép esetén.

Nemdeterminisztikus Turing-gép számítási útvonalai
7.8. ábra: Nemdeterminisztikus Turing-gép számítási útvonalai

Az egyes csúcsok az adott Turing-gép különböző helyzeteit jelölik, amelyekbe a döntés meghozatala során kerül. Látható, hogy a determinisztikus Turing-gép mindig csak egy szabályt alkalmazhat, ezért a döntéshez vezető út egyértelmű. A nemdeterminisztikus testvére azonban a fenti példában két helyen is kétféle számítási úton folytathatja a futását. Tekintve, hogy a kimeneti szalagon megjelenő "igen" vagy egy "nem" válasz függhet attól, hogy végül melyik útvonalat választotta, a nemdeterminisztikus Turing-gépeket látszólag nem igazán lehet nyelvek felismerésére használni. Legalábbis nem abban az értelemben, ahogyan a 6.6. szakaszban definiáltuk a Turing-gép által felismert nyelvet. Az ott szereplő definíció determinisztikus Turing-gépekre vonatkozott, ezért most általánosítjuk ezt a definíciót a nemdeterminisztikus esetre is.

Tekintsünk most egy nemdeterminisztikus Turing-gépet. Ha összes lehetséges számítási útvonalát egyszerre vizsgáljuk, akkor kétféle eset lehetséges:

  • Van legalább egy olyan számítási útvonal, amely mentén a Turing-gép nem kerül végtelen ciklusba, és az eredmény "igen".
  • Ilyen számítási útvonal nincs, azaz a Turing-gép minden számítási útvonala vagy a "nem" válasszal végződik, vagy végtelen ciklusba kerül.

Az első esetben azt mondjuk, hogy a nemdeterminisztikus Turing-gép elfogadta az jelsorozatot, míg a második esetben elutasította azt. Hasonlóan a determinisztikus Turing-gépek esetéhez, azok a bemeneti jelsorozatok, amelyeket a nemdeterminisztikus Turing-gép a fenti értelemben elfogad, egy részhalmazt alkotnak az összes bemeneti jelsorozat között. Ezt a részhalmazt a nemdeterminisztikus Turing-gép által felismert nyelvnek nevezzük és -mel jelöljük.

Nyilván a nemdeterminisztikus esetben is csak azokkal a Turing-gépekkel érdemes foglalkoznunk, amelyek nem keverednek végtelen ciklusba egyetlen lehetséges számítási útvonalon sem. Másként fogalmazva ez azt jelenti, hogy a leghosszabb számítási útvonal hossza is felülről becsülhető valamilyen, a bemenet hosszától függő véges mennyiséggel. Amennyiben ilyen felső becslésnek megadható egy polinomiális függvény, akkor azt mondjuk, hogy a nemdeterminisztikus Turing-gép polinomiális időkomplexitású.

Azokat a rekurzív nyelveket, amelyek eldöntésére létezik polinomiális időkomplexitású nemdeterminisztikus Turing-gép, egy osztályba soroljuk, amelyet -vel jelölünk, és a nemdeterminisztikusan polinomiális időben eldönthető nyelvek osztályának nevezzük (innen ered tehát az rövidítés). A nyelvosztály nyilván része -nek, ha ugyanis egy nyelv determinisztikus Turing-géppel eldönthető polinomiális időben, akkor nemdeterminisztikus Turing-géppel "méginkább" eldönthető.

Jogosan vetődhet fel az Olvasóban a kérdés, hogy mi értelme nemdeterminisztikus döntési algoritmusokkal foglalkozni, amikor ez nem egy realisztikus számítási modell. Hiszen a számítási útvonalakat úgyis csak egyenként tudnánk "bejárni" egy valódi számítógéppel?

Emlékezzünk azonban, hogy a 6.5. szakaszban a Church-Turing tézis kapcsán már megemlítettük a kvantumszámítógépeket. Ezek egy olyan – most még többnyire csak elméletben létező – számítási modellt valósítanak meg, amely kihasználja az elemi részecskék szintjén jelentkező nagyon furcsa jelenségeket. Ezeket a kvantumfizika írja le, és nagyjából arról van szó, hogy egy elemi részecske nem feltétlenül van mindig egy adott állapotban, hanem bizonyos körülmények között egy úgynevezett szuperpozíciós állapotba kerülhet. Tegyük fel például, hogy egy ilyen részecske valamilyen irányú "pörgése" a bináris 1, a fordított irányú "pörgése" pedig a bináris 0 szimbólumot jelenti. Ezeket a "kvantumbit" kifejezés alapján qubit-eknek nevezzük. Amennyiben több qubit-et is sikerül szuperpozíciós állapotba hozni, úgy egy ilyen rendszer párhuzamosan tud számításokat végezni a qubit-állapotok összes lehetséges kombinációján.

Egy ilyen gép tehát nagyon hasonló számítási modellt valósítana meg, mint a nemdeterminisztikus Turing-gép, amelynek rengeteg párhuzamos számítási útvonalat kell egyszerre vizsgálnia. A fő technikai problémát az okozza, hogy a szuperpozíció egy nagyon érzékeny állapot, és a rendszer a legapróbb külső behatásra egy konkrét állapotba "zuhanhat", véget vetve a kvantumszámításnak. Vannak egészen ígéretes eredmények, azonban ez a technológia még igencsak gyerekcipőben jár.

A problémaosztályról szóló 7.3. szakaszban megemlítettük, hogy a 3-színezhetőség és a k-függetlenség problémájáról – sok egyéb más, a gyakorlatban rendkívül fontos probléma mellett – nem tudjuk, hogy vajon -beliek-e. Azt viszont nemsokára látni fogjuk, hogy ha -be nem is tartoznak bele feltétlenül, az problémaosztályba azonban igen. Kérdés, hogy hogyan tudjuk bizonyítani egy döntési problémáról – pontosabban az őt reprezentáló formális nyelvről –, hogy -beli. Ez ugyanis igen nehézkesnek tűnik a fenti, nemdeterminisztikus számítási modellre építő definíció alapján. Ezért most megismerkedünk az nyelvosztály egy másik definíciójával, amely a sokkal könnyebben kezelhető determinisztikus Turing-gépekre épít.

A tanú-tétel

Képzeljük el, hogy a 3-színezhetőség eldöntését próbáljuk megoldani egy konkrét, viszonylag nagy gráfra. Hatékony algoritmus hiányában helyzetünk reménytelennek tűnik. Tegyük fel azonban, hogy valahonnan hozzájutunk egy olyan plusz információhoz, amelynek helyességét már hatékonyan le tudjuk ellenőrizni. Például támad egy sejtésünk, vagy valaki megsúg nekünk bizonyos információkat a megoldásról. Ezt a plusz információt tanúnak (vagy súgásnak) nevezzük.

A tanúval szemben két fontos követelményünk van:

  • Ne legyen túl hosszú az eredeti bemenet méretéhez képest. Ez pontosabban fogalmazva azt jelenti, hogy ha az eredeti bemeneti jelsorozat , a tanút leíró jelsorozat pedig , akkor megköveteljük, hogy hossza hosszának legfeljebb polinomiális függvénye legyen.
  • Megköveteljük továbbá, hogy a tanú helyessége legyen leellenőrizhető polinomiális időkomplexitású determinisztikus Turing-géppel.

A "súgás" elnevezés arra utal, hogy e plusz információnak csak a létezése a feltétel. Annak eredetével kapcsolatosan azonban nincs semmilyen kiszámíthatósági feltételezésünk. Az olyan döntési problémák osztályát szintén -vel jelöljük, amelyek esetén az "igen" válasznak létezik hatékonyan ellenőrizhető tanúja.

A tanú-tétel azt állítja, hogy a nemdeterminisztikusan polinomiális eldönthetőségre, és a determinisztikusan polinomiális ellenőrizhetőségre épülő két látszólag teljesen különböző definíció ugyanazt a nyelvosztályt határozza meg, így mindegy, hogy melyiket nevezzük -nek. Mielőtt a bizonyítás vázlatára rátérnénk, nézzük meg egy konkrét példán, hogy hogyan kell értelmezni a tanú fogalmára épülő definíciót.

A már említett 3-színezhetőség eldöntése reménytelenül nehéz feladatnak tűnik, ha csak a bemeneti gráf áll rendelkezésre. Ha azonban kapunk hozzá egy konkrét színezést, mint tanút (vagy más néven súgást), annak helyessége már könnyen leellenőrizhető. Továbbá az is nyilvánvaló, hogy csak a 3-színezhető gráfokhoz létezik helyes színezés, azaz tanú. Végezetül, egy színezés leírható a bemeneti gráf méretéhez képest "nem túl hosszan", hiszen csak az egyes csúcsokhoz rendelt színeket kell felsorolni. Ehhez hasonlóan a k-függetlenség problémája esetén k darab független csúcs felsorolása szintén megfelelő tanú, hiszen könnyen leellenőrizhető, hogy azok valóban függetlenek-e. A 3-színezhetőség és a k-függetlenség problémája tehát a második definíció alapján mindketten az problémaosztályba tartoznak.

Egy -beli nyelv esetén egy adott bemeneti jelsorozat -be tartozásának eldöntése felfogható egy bírósági analógiával is. Képzeljünk el egy bírót, aki elé oda kerül az jelsorozat, mint vádlott. A vád az, hogy mondata az nyelvnek. A kérdés eldöntésére a bírónak polinomiális időkorlátja van, azaz kissé türelmetlen, és segítségre van szüksége, hogy időben meg tudja hozni az ítéletet. Ekkor jelentkezik egy rejtélyes tanú, aki terhelő vallomást tesz az vádlottra. A bírónak így csak ellenőriznie kell, hogy a vallomás tényleg bizonyítja-e a vádat. Nem kell azonban foglalkoznia a tanú megkeresésével, amely mai tudásunk szerint sok fontos esetben nem is tehető meg polinomiális időben.

Látható, hogy ez a tanú fogalmára építő második definíció igen hasznos, hiszen segítségével lényegesen könnyebben tudjuk bizonyítani adott nyelvekre, hogy -beliek, mintha a nemdeterminisztikus Turing-gépekkel kellene szórakoznunk. Ahhoz azonban, hogy ezt a piszkos kis trükköt legálisan használhassuk, még bizonyítanunk kell a tanú-tételt.

Először azonban fogalmazzuk meg újra a tanú-tétel állítását, de ezúttal a matematika nyelvén. Bonyolultnak fog tűnni, de valójában ugyanarról van szó, mint amiről eddig beszéltünk. Érdemes végigkövetni, hogy szokjuk egy kicsit ezt a szigorú nyelvezetet.

Tegyük fel, hogy adva van egy nyelv, és azt szeretnénk bizonyítani, hogy ez a nyelv -ben van-e vagy nem. Az nyelvosztály első definíciója alapján tehát keresnünk kellene egy olyan polinomiális időkomplexitású nemdeterminisztikus Turing-gépet, amely eldönti az -be tartozást, vagy pedig bizonyítani, hogy ilyen Turing-gép nem létezik. Mi nem ezt az utat fogjuk választani az -beliség eldöntésére, ugyanis nem szeretnénk nemdeterminisztikus Turing-gépekkel bajlódni.

Ehelyett -ből konstruálni fogunk egy másik nyelvet, és azt fogjuk vizsgálni, hogy ez a nyelv eldönthető-e polinomiális időkomplexitású determinisztikus Turing-géppel (azaz, hogy -beli-e). Most nézzük meg, hogy milyen jelsorozatokat tartalmazzon ez a nyelv.

Tartalmazzon olyan és jelsorozatokból álló párokat, amelyeknél hossza az hosszának legfeljebb polinomiális függvénye, azaz ne legyen "túl hosszú" -hez képest. Hogy az éppen használt ábécé segítségével hogyan lehet ilyen párokat leírni, az most részletkérdés. A lényeg, hogy a pár összetevőit (tehát az és jelsorozatokat) egyértelműen be lehessen azonosítani a -beli szavakban. Mi a továbbiakban az jelölést fogjuk használni ezekre a párokra, függetlenül attól, hogy ez konkrétan hogyan néz ki a nyelv ábécéjével leírva. A jelsorozatot az jelsorozat tanújának fogjuk nevezni.

Teljesüljön ezen kívül a és nyelvekre a következő: egy tetszőleges jelsorozat akkor és csak akkor tartozzon -be, ha létezik olyan tanú, amely esetén az jelsorozat -ba tartozik. Amennyiben ilyen tanú nem létezik egy adott -hez, akkor ne tartozzon -be. Mégegyszer hangsúlyozzuk, hogy a tanúnak csak a létezése a feltétel. A megtalálásának mikéntjéről nem feltételezünk semmit, de azt gondoljuk, hogy az "nehéz".

A tanú-tétel ezek után a következőt állítja: az nyelv akkor és csak akkor van -ben, ha a nyelv -ben van. Vegyük észre, hogy ha ez igaz, akkor egy nemdeterminisztikus Turing-gép létezésének bizonyítása helyett egy determinisztikus Turing-gép létezését kell bizonyítanunk egy nyelv -beliségének eldöntéséhez, ami sok esetben jóval egyszerűbb. Most vizsgáljuk meg, hogy miért igaz ez a tétel.

A tanú-tétel bizonyításának vázlata

Itt csak a tanú-tétel bizonyításának alapötletét ismertetjük, a részletek ugyanis főként technikai jellegűek, és csak elterelnék a figyelmet a gondolatmenetről.

Tekintve, hogy ez egy "akkor és csak akkor" típusú állítás, ezért a bizonyítás két részből fog állni. Egyrész bizonyítani kell, hogy ha a nyelv -ben van, akkor az nyelv -beli. Másrészt azt is bizonyítani kell, hogy az nyelv -belisége semmilyen más esetben nem fordulhat elő, csak akkor, ha a nyelv -beli. Másként fogalmazva bizonyítani kell a másik irányú következtetést is, azaz azt, hogy ha az nyelv -ben van, akkor a nyelv -beli.

Kezdjük ez utóbbival, azaz tegyük fel az nyelvről, hogy -ben van. Ez azt jelenti, hogy polinomiális időkomplexitású nemdeterminisztikus Turing-géppel eldönthető, ezért bármely, a nyelvbe tartozó jelsorozathoz (de csak azokhoz) létezik legalább 1 olyan számítási útvonal, amelyet követve a számolás végeredménye az "igen" válasz. A 7.9. ábrán egy ilyen útvonal látható.

Nyelv felismerése nemdeterminisztikus Turing-géppel
7.9. ábra: Nyelv felismerése nemdeterminisztikus Turing-géppel

Építsünk most egy olyan determinisztikus Turing-gépet, amely az bemeneten kívül megkapja még ennek az útvonalnak a leírását is valamilyen formában. Jelöljük ezt a gépet -mel. Az gép legyen olyan, hogy szimulálja a nemdeterminisztikus testvérének működését, de minden olyan szituációban, ahol a nemdeterminisztikus gép számítási útvonala elágazik, a kapott útvonal-leírás szerinti úton haladjon tovább a számítással. A technikai részleteket az Olvasóra bízom, de viszonylag könnyen belátható, hogy egyrészt az útvonal leírható "nem túl hosszan", azaz úgy, hogy hossza az bemenet hosszának polinomiális függvénye legyen. Másrészt szintén viszonylag könnyen belátható, hogy az determinisztikus Turing-gép időkomplexitása szintén polinomiális, tekintve hogy az eredeti nemdeterminisztikus gép időkomplexitása is polinomiális volt.

Ez azt jelenti, hogy az útvonal leírása megfelel a tanúval szemben támasztott követelményeknek. Ezen kívül az is igaz, hogy csak azokra az jelsorozatokhoz van ilyen tanú, amelyek -ben vannak. Az eredeti nemdeterminisztikus Turing-gép ugyanis az egyéb jelsorozatokat nem fogadja el, így az ilyen jelsorozatokra nincs "igen" végződésű számítási útvonal, következésképp az azt leíró tanú sem létezhet.

A tanú tétel másik felének bizonyításához azt kell belátni, hogy ha az nyelvhez tartozó jelsorozatokhoz (de csak azokhoz) létezik tanú a fenti értelemben, akkor az nyelv polinomiális időkomplexitású nemdeterminisztikus Turing-géppel eldönthető. Vegyünk tehát egy tetszőleges bemeneti jelsorozatot, és építsünk egy olyan nemdeterminisztikus gépet, amely -et elfogadja, ha az nyelvhez tartozik, és elutasítja, ha nem.

Azt mondtuk, hogy az jelsorozat akkor és csak akkor tartozik -hez, ha létezik hozzá egy ezt bizonyító tanú. Ha tehát a készülő gépünk végig tudná vizsgálni az összes olyan jelsorozatot, amely tanúként szóba jöhet, akkor el tudná dönteni az jelsorozat -be tartozását is. Szerencsére az ilyen lehetséges tanúkból véges sok van, mivel azt mondtuk, hogy a tanú "nem túl hosszú" -hez képest. Ha például az jelsorozat hossza szimbólum, akkor a keresett tanú – ha egyáltalán létezik – maximum darab szimbólummal leírható, ahol egy valamilyen rögzített polinomiális függvény.

A készülő nemdeterminisztikus gépünknek tehát nincs más dolga, mint különböző számítási útvonalakon előállítani az összes lehetséges tanújelöltet, és mindegyik számítási útvonalon leellenőrizni, hogy az adott tanújelölt bizonyítja-e az jelsorozat -be tartozását. Ehhez az ellenőrzéshez pedig használhatja a feltételünk szerint létező polinomiális időkomplexitású determinisztikus Turing-gépet. Tegyük fel például, hogy a bináris ábécét használjuk, és az jelsorozat hosszúsága alapján maximum szimbólum hosszú tanújelöltek jöhetnek szóba.

Ekkor a nemdeterminisztikus gépünk számítási útvonalai a 7.10. ábrán látható módon alakulnak.

Tanújelöltek tesztelése nemdeterminisztikus Turing-géppel
7.10. ábra: Tanújelöltek tesztelése nemdeterminisztikus Turing-géppel

A működés első felében annyiszor ágazik el minden útvonal, ahány szimbólumból a lehetséges tanújelöltek állnak. Erről ugye tudjuk, hogy az bemenet hosszának polinomiális függvénye. A működés második felében – miután minden lehetséges tanújelölt előállt valamelyik útvonalon – le kell futtatni mindegyik számítási ágon az adott tanút ellenőrző polinomiális időkomplexitású determinisztikus Turing-gépet, azaz innentől kezdve már nem fognak tovább ágazni az útvonalak. Ennek a szakasznak a hossza ugye az összetett jelsorozat hosszának polinomiális függvénye.

Az így megkonstruált nemdeterminisztikus Turing-gépnek az összlépésszáma tehát végsősoron szintén az eredeti bemenet hosszának polinomiális függvénye az összes lehetséges számítási útvonalon. Az is igaz továbbá, hogy ez a gép akkor és csak akkor fogja elfogadni az bemenetet, ha van "igen" végződésű számítási útvonala. Ez viszont akkor és csak akkor lehetséges, ha az jelsorozathoz létezik az ő -be tartozását bizonyító tanú.

Ezzel bizonyítottuk az nyelvosztály kétféle definíciójának ekvivalenciáját. A továbbiakban tehát nyugodtan használhatjuk a tanú létezését megkövetelő definíciót, amikor egy adott nyelv -be tartozását akarjuk igazolni.

Most pedig rátérhetünk a számítástudomány egyik legfontosabb megoldatlan problémájára.

Az egymillió dolláros megoldatlan probléma

Az nyilvánvaló, hogy a problémaosztály mind az első, mind pedig a második definíció alapján is része az problémaosztálynak. Ha ugyanis a bíró maga is meg tudja oldani a feladatot polinomiális időben, akkor nincs más dolga, mint a kapott megoldást összehasonlítani a tanú "vallomásával", és "igen"-t ítélni egyezés esetén.

Érdekes kérdés viszont, hogy vajon valódi tartalmazásról van-e szó, vagy a két problémaosztály valójában egy és ugyanaz lenne? Vajon ha egy feladat megoldásának az ellenőrzésére van hatékony eljárás, akkor szükségképpen létezik-e hatékony eljárás magának a megoldásnak a megtalálására is? Amennyiben ez igaz lenne, annak rendkívül messzemenő következményei lennének nemcsak a matematika számos területén, hanem más tudományokban is.

A választ nem tudjuk, de alapos okunk van feltételezni, hogy , azaz vannak nemcsak nehéznek tűnő, hanem valóban nehezen megoldható, viszont hatékonyan ellenőrizhető feladatok. Ez jelenleg a számítástudomány, de talán az egész matematika egyik legfontosabb megválaszolatlan kérdése. A -sejtés egyike az úgynevezett Millenniumi Problémáknak is. Ez hét olyan matematikai problémát takar, amelyek megoldására 2000-ben magas pénzjutalommal járó díjat alapított az amerikai Clay Matematikai Intézet. Ezek közül hat még mindig megfejtésre vár – köztük a -sejtés is –, amelyekért a dicsőségen túl egyenként egymillió amerikai dollár is jár.

A 7.11. ábrán az eddig megismert "bonyolultságtérképünk", valamint az ebben a fejezetben bemutatott 2-színezhetőség, 3-színezhetőség és k-függetlenség problémájának elhelyezkedése látható ezen a térképen abban az esetben, ha a . Az ábrán látható és problémaosztályokat a 6.6. szakaszban ismertettük.

Bonyolultságtérkép P nem egyenlő NP esetén
7.11. ábra: Bonyolultságtérkép esetén

Amennyiben a sejtés valamilyen csoda folytán mégis hamisnak bizonyul, akkor a "bonyolultságtérkép" a 7.12. ábrán látható módon alakulna.

Bonyolultságtérkép P egyenlő NP esetén
7.12. ábra: Bonyolultságtérkép esetén

A következő fejezetben megismerkedünk egy fontos fogalommal, amelynek a segítségével az algoritmikus problémákat össze tudjuk majd hasonlítani "nehézség" szempontjából. Ennek kapcsán megismerkedünk az problémaosztály "krémjével", azokkal a problémákkal, amelyek bizonyos tekintetben a legnehezebb -beli feladatoknak tűnnek. Ekkor fog világossá válni, hogy miért valószínűsítjük annyira, hogy nem azonos -vel, még ha egzakt bizonyításunk nincs is erre. A kérdés többek között azért is rendkívül fontos, mivel a modern információbiztonsági és rejtjelezési eljárások 5. fejezetben említett algoritmikus biztonsága alapvetően ezen áll vagy bukik.