• Tidak ada hasil yang ditemukan

Konputagarritasunerako oinarrizko teknikak

N/A
N/A
Protected

Academic year: 2021

Membagikan "Konputagarritasunerako oinarrizko teknikak"

Copied!
114
0
0

Teks penuh

(1)

Konputagarritasunerako

Oinarrizko Teknikak

Arantza Irastorza, Ana Sánchez, Jesús Ibáñez

(2)

KONPUTAGARRITASUNERAKO OINARRIZKO

TEKNIKAK

Arantza Irastorza

Ana Sánchez

Jesús Ibáñez

(3)
(4)

Aurkibidea

Aurkibidea ... 1

 

1.

 

Sarrera ... 5

 

2.

 

Oinarrizko nozioak eta notazioa ... 7

 

3.

 

Konputagarritasuna versus konputaezintasuna ... 13

 

3.1  Konputagarritasuna eta konputagarritasun eskuragaitza ... 15 

3.2  Church-Turing-en Tesia ... 19 

4.

 

Funtzio Unibertsala ... 23

 

4.1  While-programen gaineko eragiketa sintaktikoak ... 24 

4.2  Zerrendatze Teorema ... 26 

4.3  Etendako egikaritzapena ... 32 

4.4  Prozesu tartekatzea ... 34 

4.4.1  Prozesu-kopuru mugatuaren tartekatzea ... 37 

4.4.2  Prozesu-kopuru ez-mugatuaren tartekatzea ... 39 

4.4.3  Kodeketa funtzioen erabilpena ... 41 

4.4.4  Funtzioen alderanzketa ... 44 

5.

 

Diagonalizazioa ... 47

 

(5)

5.2  Geratze-problema ... 50 

5.3  Paradoxak eta diagonalak ... 52 

5.4  Diagonalizazio teknika ... 57 

5.5  Diagonalizazio teknikaren aldaerak ... 63 

5.5.1  Diagonalaren desplazamendua ... 64 

5.5.2  Diagonalaren desitxuratzea ... 67 

5.5.3  Diagonalizazio asimetrikoa ... 69 

6.

 

Erabakigarritasuna eta sasierabakigarritasuna ... 75

 

6.1  Erabakitze-problemak eta multzoak ... 76 

6.2  Multzo erabakigarriak eta beren propietateak ... 78 

6.2.1  Multzo erabakigarrien itxitura-propietateak ... 80 

6.3  Multzo sasierabakigarriak eta beren propietateak ... 81 

6.3.1  Sasierabakigarritasunaren eta erabakigarritasunaren arteko erlazioa ... 83 

6.3.2  Multzo sasierabakigarrien itxitura-propietateak ... 85 

6.3.3  Multzo sasierabakigarrien karakterizazioa ... 87 

6.3.4  Diagonalizazioa eta ez-sasierabakigarritasuna ... 91 

7.

 

Ondorioak ... 97

 

A eranskina: while-programen lengoaia ... 99

 

(6)

C eranskina: Funtzio konputagarrien eta predikatu

erabakigarrien zerrenda ... 103

 

a)  Hitzekin erabilitako eragiketa ohikoenak ... 103 

b)  Kodeketa funtzioak ... 104 

c)  Beste datu-mota batzuei lotutako funtzioak ... 105 

d)  Makroprogrametan eragiketak erabiltzeko beste era batzuk ... 107 

e)  While-programei lotutako funtzioak ... 108 

(7)
(8)

1.

Sarrera

Konputagarritasunaren Teoria Informatika Teorikoaren barnean sartzen den arloa da, sistema informatikoek algoritmoen diseinuaren bitartez problemak ebaztean dituzten muga logikoak ezartzea helburua duena, hain zuzen ere. Egunez egun konputagailuen aplikagarritasun praktikoa zabaltzen doazen diziplina eta tekniken aurrean, informazioaren prozesamendurako edozein teknologia digitalek gainditu ezingo duen muga-taldea ezartzen du teoria honek. Oinarrizko Lege moduan ezartzen ditu, informatikaren existentziaren baldintza propioak zuzentzen dituzten legeak bezala.

Konputagarritasunaren Teoriaren berezko metodoak izugarri konplexuak izan daitezke, eta gehien bat alderdi teknologikora bideratutatako formakuntzarentzat arraro samarrak suerta daitezke, batez ere. Bere emaitza aurreratuenak oso formakuntza tekniko ona duten informatikari esperientziadunentzat ere ulertzeko zailak dira. Hala ere, oinarrizko emaitzen nukleo bat badago, eskura dauden tekniken bitartez ekin daitezkeenak, eta erabakiezintazun konputazionalaren kontzeptu nagusia isladatzeko bertutea badutenak. Esan bezala emaitza horiek zenbait teknikei esker erator daitezke, Konputagarritasunaren Teoriaren bere-berezkoak ez izan arren, arlo honetan guztiz emankorrak suertatu direnak.

Txosten honetan Teoriaren oinarrizko nukleo hori osatzen duten kontzeptu eta tekniken deskribapena sartzen da. Informatikan ezagunak eta nabarmenak diren zenbait problemen konputaezintasunarekin erlazionatutako emaitzen lehenengo bateria ematea da bere helburua. Emaitzak aurkeztean while-programena izango da erabiliko den programazio estandarra, aurreko txosten batean [IIS 98] deskribatu genuena, eta Diagonalizazio teknikaren azalpen zehaztua eta sistematikoa ere sartuko da.

UPV/EHUko Informatika Fakultatean ematen den Ingeniaritza Informatikoko Ikasketa Planaren Konputazioaren Eredu Abstraktuak II irakasgaiaren ikasleentzat irakaskuntza laguntza moduan idatzia izan den arren, egileen asmoa edo nahia, lehen aipaturiko emaitza eta tekniken deskribapen ulergarria ematea da. Txosten hau aurreko paragrafoan aipaturikoaren jarraipena den arren, azken hori irakurtzea ekidin nahi duenak, oinarrizko kontzeptu eta definizioak bigarren kapituluan aurkituko ditu, eta while-programen lengoaiaren despribapen zehaztua eta testuingurua osatzeko beste zenbait informazio, berriz, eranskinetan.

Hala ere, lan honetara [IIS 98] txostenaren ondoren iristen den horrek, 2. kapituluan definizio ezagun asko aurkituko ditu (nahiz eta, bertan sartu ez ziren zenbait definizio ere badauden), eta ziurrenik eranskinen edukia azalekotzat hartuko

(9)

du. Hemen dokumentu hartan azaldu ziren emaitzak hartu eta bertan ezarri ziren hitzarmen guztiak mantenduko ditugu, makroprogramen goiburukoari buruzko hura izan ezik. Aipatu txosteneko 3.5 atalean aurretik inplementaturiko funtzioen inportazioaren nozioa sartu genuen, package KONPUTAGARRIAK notazioaren bitartez eta konputagarritasun frogapenen prozesu inkrementalaren zentzu hierarkikoa barneratzeko bide bezala; baina gauden puntu honetan hau ez da beharrezkoa eta, aldiz, neketsua gertatzen da zehaztasun hori sistematikoki adieraztea.

3. kapituluan lan honen gai nagusiari ekiten diogu, formala ez den ikuspegi batetik oraindik. Konputaezintasunaren kontzeptua, sistema informatikoei buruz uneko ezagueran oinarritutako ausazko interpretazioetatik banatzea garrantzitsua da. Hori egiteko era egoki bat bereizketa egitea da: funtzio konputaezinen eta konputagarritasun eskuragaitza duten funtzioen artean bereiztea. Era berean, horrek Konputagarritasunaren Teoriaren analisia guztia oinarritzen den funtsezko premisa ezartzera garamatza: konputaezintasunaren ezaugarriak aukeratutako programazio sistemaren independenteak dira.

5. kapituluan, funtzioen konputaezintasuna eta predikatuen erabakiezintasuna frogatzeko funtsezkoa den diagonalizazio teknika nahiko zehaztasunez azaltzen da. Bere aurretik, berriz, gure helburuetarako guztiz erabilgarriak diren zenbait emaitza eta teknika biltzen duen kapitulua ere sartu da. Aipatu emaitza horiek zenbait egite nabarmenen froga dira, esaterako, helburu orokorreko ordenadoreak egon behar direla edo prozesu paraleloen ereduen eta sekuentzialen arteko baliokidetasuna, baina, batez ere, funtzio nabarmen askoren konputagarritasuna zein konputaezintasuna frogatzeko erabiliko diren tresna garrantzitsuak ematen dituzte.

Behin diagonalizazioa eta bere aplikazioak aztertu ondoren, erabakitze-problematan zentratutako azken kapitulu bat sartu da. Honek kontzeptu berria azaltzen du, sasierabakigarritasuna, zenbait problemen konputaezintasunaren inguruan ikuspegi posibilistagoa edukitzeko argigarria gertatzen dena.

(10)

2.

Oinarrizko nozioak eta notazioa

ALFABETOA ETA HITZA: Informazioaren prozesamenduaren nozioa, ikurren konbinaziotik eratortzen diren objektuen eraldaketa kontrolatuaren ideiara lotuta dago. Horregatik, alfabetoa ikurren edozein ∑ multzo finituri esango diogu. Edozein ∑ alfabeto emanik, bere gainean definituriko hitzen edo kateen multzoa

∑* definitzen dugu. Hitz hutsaren (

) eta hitzen kateamendu eta alderanzketaren nozio klasikoak erabiliko ditugu. Hauek eta ikurrak maneiatzeko beste funtzio batzuk C eranskinean (a atalean) zerrendan ageri dira.

Hitzak dira domeinuko objektuak errepresentatzeko aukera ematen diguten elementuak, eta beraz, informazioaren oinarria osatzen dutenak. Horrela, programen eginkizuna, beste hitz (emaitza) batzuk lortzeko zenbait hitz (datu) maneiatzea izango da.

FUNTZIOAK: Programen portaera sarrera/irteera moduan deskribatzeko, hitzen arteko funtzio partzialak erabiliko ditugu. Hauek, bere balizko sarreretako zenbaitentzat indefinituta egon daitezke.

: ∑*  ∑* funtzioak, sarrerako

x hitzaren gainean aplikaturik, konbergitzen badu (irudia badauka)

(x) ikurraren bitartez adieraziko dugu. Aldiz, puntu horretan funtzioa indefinituta badago,

(x) idatziko dugu eta dibergitu egiten duela esango dugu.

Argumentu bat baino gehiago duten baina betiere emaitza bakarra itzultzen duten funtzioak ere erabiliko ditugu,

: ∑*k * erakoak, hain zuzen ere. Kasu horretan

(x1,...,xk) edo

(x1,...,xk) adieraziko dugu.

PROGRAMAK: Programa ikurrak maneiatzen dituen prozesu baten espezifikazio ez-anbiguoa da, eta prozesu horrek sarrerako katea (datu) bat edo batzuk eraldatzen ditu, irteerako beste bat (emaitza) lortzeko. Programa, programazio-lengoaia definitzen duten arau sintaktiko batzuen arabera eraikita egon behar da. Gure kasuan erabilitako lengoaia while-programena da, bere sintaxi zehatza A eranskinean deskribatzen da baina deskribapen zehatzagoa [IIS 98]-n kontsulta daiteke.

P programa baten portaera, funtzio partzial baten bitartez deskribatua izango da. Funtzio hori

P: ∑*  ∑* eran idatziko dugu eta P-k jasotzen duen sarrera-katearen eta emaitza moduan sortzen duenaren artean dagoen erlazioa deskribatuko du. Emaitza bat itzultzeko, programak bere egikaritzapena bukatu egin behar duenez, x sarreraren gainean P-ren portaera indefinituki ziklatzea denean, hori

P(x) eraren bitartez islatuko da, programaren emaitza indefinitua delako.

P funtzioa osoa bada (hots, bere balizko argumentu guztientzat definituta badago) orduan P programa edozein baldintzen pean bukatzen da. Beste muturrean

(11)

P funtzio hutsa ( ) deneko kasua dago: hau beti indefinituta dago eta ondorioz,

P-k edozein sarrerarekin ziklatu egiten duela adierazten du.

Kontzeptua era naturalean hedatzen da, datu bakarraren ordez P programak sarreran k datu jasotzen dituenean. Orduan bere portaera deskribatzen duen funtzioa honakoa da:

P

k

: ∑*k *.

KONPUTAGARRITASUNA:

: ∑*k  ∑* funtzioa while-konputagarria da

P while-programa existitzen bada bera konputatzen duena (

P k

), hots, bere argumentuen edozein baliotarako sistematikoki funtzioaren emaitzak lortzen ditu.

Konputagarritasuna baino ez esaten badugu,

funtzioa konputatzeari buruz ari gara baina irudikatu dezakegun edozein lengoaia edo programazio sistemarekin erabiliz eta ez while-programen lengoaiarekin ezinbestez. While-konputagarritasuna eta While-konputagarritasunaren artean dagoen erlazioa 3.2 atalean aztertuko dugu.

Txosten honen helburua funtzio konputagarri eta konputaezinen arteko bereizte mekanismoak ezartzea da.

PREDIKATUAK: Konputagarritasunaren Teorian garrantzia berezia duten funtzioen klase berezi bat dago: predikatuak, edo funtzio boolear osoak (ikus 6. kapitulua). Funtzioak while-konputagarriak edo konputaezinak bezala sailkatzen ditugu funtzioaren balioak kalkulatuko dituen while-programa dagoenaren arabera, eta era berean predikatuak ere sailka ditzakegu, bere egiazko kasuak eta kasu faltsuak bereiztuko dituen programa dagoenaren arabera. Horrela,

S : ∑* 

predikatua (non

{true,false} balio boolearren multzoa den) while-erabakigarria dela esaten dugu, baldin eta P while-programa existitzen bada S(x) betetzen duten balio guztietarako r1 emaitza sortzen duena eta beste emaitza deberdin bat r2, S(x) betetzen den balioetarako. Bere izenak berak adierazten duen bezala, predikatu bat while-erabakigarria da bere egiazkotasuna while-programa baten bitartez erabaki badaiteke.

Ideia hori k-tarrak diren predikatuetara era naturalean hedatzen da, honela:

S : ∑*k

.

MAKROPROGRAMAK: funtzio konplexuen while-konputagarritasuna frogatzeko lana erraztearren while-programen gainean makro lengoaia bat definitzen da, horrela programen idazketa laburtzea eta beren esanahia hobeto ulertzea ahalbidetzen dute. Ondorioz sortzen diren laburdurei makroprograma deitzen diegu, eta horrela, lehendik beren konputagarritasuna frogatu zaien funtzioak erabil ahal izango dira, lengoaiaren parte izango balira bezala. B eranskinean makroen klase garrantzitsuenak deskribatzen dira, makro horien

(12)

erabilera justifikatuta geratzen da benetan while-programen lengoaiaren berezko egituren baliokideak direla (egitura horietara hedatu daitezkeela) frogatuz.

Makroprogrametan edozein funtzio while-konputagarriri edo predikatu while-erabakigarriri deiak egiteko aukera ematen denez, programazio-lengoaian gehituko bagenitu bezala, C eranskinean hainbat funtzio eta predikaturen zerrenda ematen da, horien while-konputagarritasuna [IIS 98] erreferentzian frogatu zen eta hemendik aurrera idatziko diren programetan erabiliko dira. Konbentzio edo hitzarmen hauei guztiei esker, lanerako edukiko dugun lengoaia while-programena baino askoz aberatsagoa eta maneiatzeko erosoagoa izango da.

DATU-MOTAK: while-programak karaktere-kateen (hitzen) gainean soilik lan egiteko definiturik dauden arren, ∑*-ko elementuen eta beste datu multzo batzuen arteko elkarrekikotasun errazak definitzea posible da, eta horrela kate bakoitzak multzo berriko elementu bat errepresentatuko duelarik eta hitzen gaineko konputazioa mota berriko elementuen errepresentazioarekin bat etorriko delarik. Horrela, errazak eta baliogarriak diren datu-mota batzuen inplementazioa lortzen dugu, hala nola, boolearrak

, edo zenbaki naturalak

. Era berean mota egituratuak inplementatzen dira, esaterako pilak

eta bektore dinamikoak

. Azkenik while-programak

ere datu-mota bezala inplementa daitezkeela frogatzen da. Honek guztiak ∑*–ren desberdinak diren domeinuetan funtzio konputagarriekin lan egitea ahalbidetzen digu, eta gure makroprogrametan mota horien elementuak eta eragiketak erabiltzea ere.

C eranskineko c, d eta e ataletan datu-mota horiekin definituriko funtzioen eta predikatuen zerrendak ematen dira, beraien while-konputagarritasuna [IIS 98] erreferentzian frogatua izan zen eta hemendik aurrera eraikiko ditugun makroprogrametan erabiliko dira. Berriz ere abantaila bezala programazio-lengoaiaren aberasketa lortzen dugu, gure helburuetarako oso baliogarriak diren datu-moten berezko objektuak (konstanteak, funtzioak eta predikatuak) gehituz.

HITZEN ZERRENDATZEA: boolearren kasuan izan ezik (arrazoi nabariengatik) inplementazioak bijektibo moduan defini daitezke beti. Honek esan nahi du, adibidez, zenbaki naturalen eta horiek errepresentatzeko erabiltzen diren ∑*–ko hitzen artean korrespondentzia biunibokoa badagoela, eta hori aukeratutako ∑

alfabetoaren guztiz independientea gertatzen dela. Horregatik, edozein hitz multzo,

∑*, honela zerrenda dezakegu, ∑* = {w0, w1, w2, w3, ...}, non wi hitza i zenbakia errepresentatzeko balio duena den. Behin ordena definituta, sarrera-datu bezala jasotako hitzaren ondoren datorren hitza lortzen duen funtzioa programa dezakegu (hur funtzioa), edo aurreko hitza lortzen duena (aurre funtzioa).

(13)

Gure kasuan aukeratutako ordena hitzak luzeraren arabera ordenatzen dituena da, eta luzera berdinarekin orden lexikografikoa aplikatzen duena. Horrela, {a, b, c} alfabetoarekin hitzen gainean ezarritako ordena honakoa litzateke:

- a - b

- c - aa - ab - ac - ba - bb - bc - ca - cb - cc - aaa - aab - aac ..., non w0 =

eta w9 = bc, hur(abc) = aca eta aurre(aaaa) = ccc izango diren.

KODEKETA-FUNTZIOAK: funtzio konputagarrien beste bilduma bat ere bereiz dezakegu, kodeketa-funtzioak (kodk funtzioak) deitzen ditugunak eta hitz segidak

bakar batean trinkotzea edo taldekatzea ahalbidetzen dutenak. Horrela, deskod

funtzioen bitartez, modu konputagarrian ere, kodeketatik abiatuz jatorrizko seriea berreskuratzea posible izango da. k=2 kasurako, hitz-bikoteei kodeak lotzeko modua 2.1 irudiko taulan adierazten da.

w0 w1 w2 w3 w4 ... w0 w0 w2 w5 w9 w14 w1 w1 w4 w8 w13 w19 w2 w3 w7 w12 w18 w25 w3 w6 w11 w17 w24 w32 w4 w10 w16 w23 w31 w40 ... ...

2.1 irudia: hitz-bikote baten kodea zehaztea ahalbidetzen duen elkarrekikotasun taula. Horrela, kod2(w0, w3) = w9 da (∑ = {a, b, c} alfabetoaren adibide zehatzean

kod2(

, c) = bc dela adieraz dezakegu). Bere kodetik abiatuz, bikote baten

elementuak berreskuratzen dituzten funtzioak deskod2,1(w9) = w0 eta

deskod2,2(w9) = w3 dira.

C eranskineko b atalean funtzio hauen deskribapen zehatz eta xeheagoa ematen da.

PROGRAMEN ETA FUNTZIOEN ZERRENDATZEA: Hitzen zerrendatzea

inplementaturiko edozein datu-motara iragan daiteke, eta while-programen kasua oso nabarmentzekoa da. Horiek honela

= {P0, P1, P2, P3, ...} zerrenda daitezke, non Pi programa wi hitzak errepresentatzen duen programa den. Orduan wi hitza (eta hedapenez, i zenbakia) Pi programaren kodea dela esaten da.

Zerrendatze horretan balizko programa guzti-guztiak daudenez, funtzio konputagarri guztien klasea ere zerrenda dezakegu, honela {

0,

1,

2,

3, …}, non

i funtzioa Pi programak kalkulatzen duen funtzioa den, programa hori wi hitzak errepresentatzen duelarik. Horrela, wi hitza (eta hedapenez, erlazionaturiko i zenbakia ere)

i funtzioaren indizea dela esango dugu.

(14)

Ondorioz, eta

funtzioa konputagarria dela adieraztea hori konputatzen duen P programa existitzen dela frogatzearen baliokidea denez, funtzioarentzako indize bat badagoela baieztatzearen baliokidea ere ba da, hots, indize hori e balioa da non

e den. Alabaina, kode bakarra duten programetan ez bezala, funtzio konputagarri guztiek infinitu indize dauzkatela azpimarratu behar dugu, baliokideak diren infinitu programa aurki baititzakegu. Programa baten testua eraldatzeko infinitu aukera daude, betiere bere semantika aldatu gabe.

Azkenik notaziorako beste hitzarmen bat azpimarratuko dugu:

i funtzioaren

domeinua Wi bezala adieraziko dugu, eta bere heina Ri1 moduan. Multzo hauek programen portaera deskribatzeko orduan garrantzia dute, Wi multzoak Pi programak baliozkotzat jotzen dituen datuen multzoa errepresentatzen baitu, eta

Ri-k berriz, programa horrek berak sor ditzakeen emaitzen multzoari erreferentzia egiten dio.

1 Zentzu hertsian, programa bera hainbat eratara erabil daiteke, sarreran ematen zaizkion datuen

kopuruaren arabera. Lehenago deskribatu dugun zerrendatzeak argumentu bakarreko funtzioak bakarrik kontuan hartzen ditu. Argumentuen kopuru arbitrarioa duten funtzioak interesatzen bazaizkigu, k>0 bakoitzerako { 0 k , 1 k , 2 k , 3 k

…} zerrenda defini dezakegu, non i k

funtzioa sarreran k datu ematen zaizkionean Pi programak konputatzen duen funtzioa den. Argumentu

bakar batentzat esandakoa modu naturalean k argumentuetara zabaltzen da, eta bereziki Wik eta

Ri k

notazioa, i k

(15)
(16)

3.

Konputagarritasuna versus konputaezintasuna

Funtzio while-konputagarritzat ulertzen duguna deskribatu dugu: funtzio bat zeinak bera konputatzen duen while-programa bat existitzea onartzen duen. Nozio hori, pentsa dezakegun edozein problematara heda daiteke era naturalean. Problema bat konputagarria izango da funtzio partzial baten bitartez adieraz badaiteke eta hau konputatu ahal bada (funtzio horren datuak eta emaitzak karaktere-kateak izango dira edo bere inplementazioa frogatuta duen datu-motaren batekoak). Adibidez, hauteskundetan hautagai-zerrenda bakoitzak lortutako boto kopurutik abiatuz eta D’Hont legearen arabera parlamentuko aulkien banaketa zehaztearen problema while-konputagarria da. Problema hori honako funtzioaren bitartez adieraz daiteke:

banaketa:



non, baldin eta n banatu beharreko aulki kopurua eta V kandidatura desberdinen botoak gordetzen dituen bektorea badira, orduan banaketa(n,V) beste bektore bat den, V-ren dimentsio bera duena eta hautagaitzen aulkiak gordetzen dituena, hain zuzen ere. Funtzio hau ondo definituta dago (n,V) bikote zehatz batentzat aulkien balizko banaketa bakarra dagoelako2. Gainera badakigu konputagarria dela,

informatikariek beste programazio-ingurune batzuetan aspaldi ebatzi dutelako (zalantzaren bat geratuz gero, egiaztatzea oso erraza izango litzateke, zuzenean makroprograma txiki bat eginez).

Oraingo honetan galderak beste batzuk dira, problema bat while-konputagarria ez dela baieztatzeak zer esan nahiko luke? Eta, behin hau argi edukita, problema konputaezinak ba al daude? Eta baldin badaude, nola aurki ditzakegu eta nola antzeman?

Funtzioa konputaezina dela diogu hori konputatuko duen while-programarik ez dagoenean. Eta problema konputaezina dela ulertzen dugu karaktere-kateen arteko funtzio moduan adieraz daitekeenean baina funtzio hori konputaezina suertatzen denean. Beste era batera esanda, problema funtzioren baten bitartez adieraztea lortzen ez badugu (ikus orri-oineko oharra), edo bere datuak edo emaitzak ikur-kateen bitartez adierazteko zailtasunak baditugu, orduan problema espezifikatzen zaila (edo ezinezkoa) da, baina konputagarria denetz eztabaidatzen

2 Berez, hori egia izango da soilik baldin eta boto-kopuru bera lortuko luketen hautagaitzen arteko

berdinketak hausteko arau zehatz eta determinista badago. Araudiak zozketa-motaren bat aurreikusten badu, orduan banaketa ez da ondo definitutako funtzioa izango, emaitza ez baita datuen menpekoa bakarrik izango. Kasu horretan problema ezin da funtzionalki adierazi eta while-konputagarria denetz galdetzeak ez du zentzurik.

(17)

hasteak ez dauka zentzurik. While-konputagarritasuna, beraz, problemaren espezifikazio funtzionala egin eta gero planteatzen da, hori dela eta, orokorrean funtzio (eta ez problema) konputagarriei eta konputaezinei buruz hitz egitera mugatuko gara.

Beren espezifikazioa oso zaila den problema pila dago bizitza errealean. Adimen Artifizialean ohiko kontua da. Adibidez, problema bezala “xakean ondo jokatu” planteatzen badugu, nola jar dezakegu hori sarrera/irteera moduan, problema hori ebatziko duen programa eraikitzeko? Ahal den gehiena zehaztuta ere (adibidez, xakean ondo jokatzea ELO puntuaketan 7.500 baino gehiago lortzea dela esanez) problemak funtzio erako planteamendua onartu gabe jarraituko du. Arlo honetan ezin ditugu ez konputagarritasunaren ezta konputaezintasunaren kontzeptuak aplikatu.

Jakina, honek ez du esan nahi Informatikak problema hauek alboratzen dituenik, baina beren ebazpideari ekin ordez (zentzurik ez duena problemaren “ebazpenaz” hitz egin ezin dugulako) beren hurbilketarako teknikak erabiltzen ditu (hala nola, heuristikoak, probabilistikak, etab.).

Zein arlotan mugituko garen argitu ondoren, funtzio while-konputaezinak badauden edo ez galdetzea dator. Zalantza egokia da: informatikariak konputagarritasunaren definizioa lehenengo aldiz aurkitzen duenean oso arraroa da programatzea ezinezkoak diren problemak badaudela aurretik planteatu izana. Bere esperientziaren arabera, batzuk beste zenbaitzuk baino zailagoak direla jakingo du, baina oro har nahiko ahaltsuak diren tresnen bidez konputazioaren munduan dena posible izaten bukatzen dela. Alabaina, hori faltsua da: problema konputaezinak egon ez ezik, beraien kopurua konputagarriena baino askoz handiagoa da, aurrerago ikusiko dugun bezala.

Demagun informatikari bat honako problemaren aurrean aurkitzen dela: edozein programa emanda, bere eraiketan erabilitako espezifikaziora egokitzen dela egiaztatu, hau da, balizko edozein sarreratarako itxaroten den huraxe egiten duela egiaztatu. Problema hori funtzionalki defini daiteke, lehendabizi espezifikazioen

datu-mota definitu eta ikur-kateen bitartez inplementatzen badugu (adibidez, pre-post espezifikazioak erabil ditzakegu, programen egiaztapenerako Hoare-ren kalkuluan erabiltzen direnen antzekoak). Orduan, problema honako funtzioaren (predikatua, egia esan) bitartez definituta geratuko litzateke:

espezifikazioa_bete?:



Hala ere, funtzio hau konputatuko duen programa bat eraikitzen saiatzen bagara, lan erraza ez daukagula berehala konturatuko gara. Egiaz, bibliografia kontsultatuz gero, inolako programazio-ingurunetan inork ez duela programa hori

(18)

eraikitzea lortu ikusiko dugu, ondorioz while-konputagarria ere agian ez dela izango susmatzen has gaitezke. Zer egingo dugu orduan? Ondoko hauek bezalako argumentuak erabil ditzakegu: “nik ez dakit hori egiten”, “egingo duen norbait kontratatzerik ez dut lortu”, “Fakultatean ez didate horrelakorik irakatsi”, “arazo hori ebazteko utilitateak eskaintzen dituen software enpresarik ez dut aurkitu amaraunean edo web-ean”. Agian programa aurkitzeko ideia ederren eskukada bat behar dugu, agian eraikitzeko hemendik hogeita hamar urte barruko teknologia itxaron beharko dugu. Baina konputaezintasuna askoz serioagoa da:

espezifikazioa_bete? funtzioa while-konputagarria ez bada, dagokion programa garatzeko inork inoiz ezta 5 minutu emateak ere ez du merezi, helburu hori besterik gabe ezinezkoa delako. Baina nola lor dezakegu egite horrentzat argumentu sinesgarriren bat? hau da, ezintasun horren inguruan mundu guztia ados jarriko duena. Nola pasa gaitezke “oraindik ez da lortu” bezalako inpotentziatik “ezinezkoa da” erako zorigaitzera? Logika matematikoan bakarrik aurkituko dugu arazo honentzat irtenbidea: programa existitzea, egia direla jadanik badakigun beste zenbait egiterekin kontraesanean egongo litzatekeela frogatuz.

3.1

Konputagarritasuna eta konputagarritasun eskuragaitza

Funtzio batzuen konputaezintasuna frogatzearen problemari ekin baino lehen, kapituluaren hasieran aipatu dugun “ezin dugu” eta “ezin da” esamoldeen arteko oinarrizko desberdintasun horren inguruan xehetasun gehiagorekin hausnartzea komeni da. Oraingoz, funtzioaren konputagarritasuna frogatzen saiatzen garenean hori kalkulatuko duen programa bat aurkitu behar dugu. Baina zenbaitetan funtzioa while-konputagarria dela frogatuko lukeen while-programa topatzea ezinezkoa da, eta, edozelan ere, funtzioa while-konputagarria da!. Baina nola? while-programak deskribatzera orrialde mordoa eskaini eta orain errepresentatzen duten eredu hori osoa ez dela aurkitu?, hau da, funtzio konputagarri guztiak biltzeko ez duela balio.

Urduritasunean murgildu eta beste eredu alternatiboren bat bilatzen hasi baino lehen, funtzio while-konputagarriaren definizioak “bera konputatuko duen programa bat existitzea” exijitzen duela beste behin azpimarratzea komeni da. Eta

programa existitzea ez da programa hori aurkitzeko gai izatea-ren berdina. Jakina bigarrenak lehenengoa ondorioztatzen du, baina bien artekoa elkarrekiko erlazioa ez dela ikusiko dugu: zenbaitetan programa ziur existitzen da, alabaina zein ote den ezin dugu jakin. Orduan zalantza honakoa da: nola demontre dakigu existitzen dela? Adibide moduan honako predikatua har dezagun:

    bestela false ditu ile 10.253 zehazki bizarrak Fidelen true ) (x f

(19)

Ebaluatu beharreko predikatua absurdua dela eman dezake, bere balioa zehazteko zailtasun handiak daudelako. Fidel ezagutzen dugun, bere bizarra ukitzen uzten digun, edo bizkartzaina ote duenaren menpe dago. Bere bizarrera iristeko inolako mugarik ez dugula suposatuz, bere ileak kontatuko dizkiogun une zehatzaren inguruan ere zailtasunak daude: berriren bat ahaztea gerta daiteke, edo baten bat erori, bizarra kentzea erabaki dezake, ustekabean hil eta bere gorpua erraustua izan daiteke. Arrazoizkoa da pentsatzea Fidelen bizarrak zenbat ile dauzkan ez dugula inoiz jakingo (CIA-k horri buruz ezkutuko txostenen bat ez badauka behintzat), eta beraz, 10.253 direnentz ez dugula jakingo, eta ondorioz,

f predikatua ezingo dugula inoiz konputatu.

Baina, zenbakia jakitea egiazki behar al dugu? Eraiki beharko dugun programaren egituran pentsa dezagun. Programa horrek itzuli beharreko balioa zeinen menpekoa da? Funtzioaren definizioan arreta gehiago jarriz gero, irteerak

x sarrerarekin inolako zerikusirik ez duela ikusten dugu, hots, predikatuaren ebaluazioan bi aukera bakarrik daudela: Fidelen bizarrak 10.253 ile ditu (eta f-k edozein x-rako true emaitza itzultzen du) ala ez ditu (eta f-k edozein x-rako false

emaitza itzultzen du). Hau da, f predikatua beti egiazkoa da ala beti faltsua (beste aukerarik ez dago). Hortaz, f funtzioa kalkulatzeko bi programa hautagai ditugu: Ala

X0 := true;

ala

X0 := false;

Predikatua konputatzen duena bietatik zehazki zein den ezin dugu erabaki, baina bietako batek egiten duenaren ziurtasun osoa dugu. Honek f konputatzen duen programa bat existitzen dela frogatzen du, eta beraz erabakigarria dela. Erabili dugun argumentua polizi nobela batzuetan erakutsitakoaren antzekoa da: hiltzailea hilketaren unean etxean zegoenetako bat dela ziur dakigu, baina ez zehazki zein den, alabaina etxeko biztanle horiek zeintzuk diren jakina denez, hiltzailea gizonezkoa dela edo bere helburua lapurreta ez zela ondoriozta dezakegu.

Era berean, gure kasuan f predikatuaren definizioa ez dago nahiko doituta zehazki zein funtzio den jakin dezagun, baina konputagarria izan behar dela zehazteko adina bai.

Funtzioa konstantea dela deduzitzea ez da, programa idatzi beharrik gabe, bere konputagarritasuna ondorioztatzeko metodo bakarra. Bedi, adibidez, honako predikatua:

(20)

    bestela false ditu ile zehazki bizarrak Fidelen true x ) x ( g

Noski, orain ezin dugu g konstantea dela esan, kasuetako batean (x-ren menpekoa) egiazkoa delako eta gainontzekoetan faltsua. Fidelek bizarrean zenbat ile dituen jakitera behartuta al gaude orain? g konputatzen duen programa zehatza idatzi nahiko bagenu, hori derrigorrezkoa litzateke. Alabaina, hori ez da gure asmoa. Ez ahaztu programa mahaiaren gainean jartzea ez dugula behar: bere existentzia frogatzea nahikoa izango da.

Nolakoa da g orain, eta programak zer egin beharko luke bera konputatzeko? Aipatu dugun bezala, programak true kasu bakar batean itzuli behar du (sarrerak Fidelen bizarraren ile kopuruarekin bat egiten duenean) eta false gainontzeko guztietan. Fidelen bizarraren M ile kopuruaren berri bagenu, honako makroprograma idazterik edukiko genuke:

X0 := X1 = M;

Baina, berriz ere, programaren existentzia frogatzeko M-ren balioa hutsala, gutxienekoa, da. Itxura horretako programa guztiekin, hots, M-ren balizko balio bakoitzeko programa bat hartuz, zerrenda presta dezakegu:

X0 := X1 = 0; ala X0 := X1 = 1; ala X0 := X1 = 2; ala X0 := X1 = 10.253;

Ona zein zen erabaki ezin genuelarik, f predikatuarentzat bi programa (edo beraien baliokideak) genituela esaten genuen bezala, g-rentzat infinitu hautagai ditugu, M-ren balio bakoitzeko bana, eta zehatz bat aukeratzea ezinezkoa zaigu. Baina programa horietako batek g konputatzen duenaren ziurtasun osoa badaukagu eta ondorioz g ere konputagarria badela.

Pixka bat bihurriagoa den azken adibide bat azter dezagun. Honako multzoa defini dezakegu: A = {z: existitu daiteke izaki bizidunen bat zeinaren genomaren luzera zehazki z den}. Azaleko azterketa batekin ere definizio honek alderdi korapilatsuak biltzen dituela antzeman daiteke.

(21)

Alde batetik, izaki bizidun gutxi batzuen genomen luzera zehatzak bakarrik ezagutzen ditugu. Bestetik, espezie ezezagun asko dago eta egunero beste batzuk galtzen dira, eta zer esanik ez, eboluzioak oraindik eman ez dituenak, ingeniaritza genetikoak sortu ez dituenak edo, besterik gabe, “existitu daitezkeenak” baina inoiz existituko ez direnak. Hori guztia kontuan hartuz honako predikatua defini dezakegu:      bestela false ) + ( true = ) (x y x y A h

Eta gure buruari galde diezaiokegu, konputagarria al da, bai ala ez? Baietz frogatzeko genetikari buruzko inolako jakintzarik edukitzea ez dugula behar ikusiko dugu. Argi dago h(x)-ren balioa true izango dela bere genomaren luzera x-ren berdina edo handiagoa duen izakiren bat existitu litekeenean. Beraz, h(x) betetzen denean x-ren azpiko sarreretarako ere h-ren emaitza egiazkoa izango da.

Hasiera batean, A multzoa infinitua izatearen aukera badago (hau da, bizitzeko gai diren izakien genomen luzeraren inguruan goi-mugarik ez egotearen aukera). Kasu horretan h funtzioa true funtzio konstantea izango zela edukiko genuke, edozein x hartuta ere, A multzoan x hori baino handiagoko z balioak egongo liratekeelako.

Baina A finitua izan liteke: agian genomarako L luzera maximoa egon daiteke, inolako izaki bizidunik gainditu ezin duena. Kasu horretan h predikatua L-ren berdinak edo txikiagoak diren balioetarako egiazkoa izango litzateke, eta gainontzekoetarako faltsua. Eta ez dago beste aukerarik (A finitua ala infinitua izan daiteke bakarrik), ondorioz honako programetatik baten batek nahitaez h konputatu behar du: X0 := true; ala X0 := X1 <= 0; ala X0 := X1 <= 1; ala X0 := X1 <= 100.893.873.343.157.2245.234.388.253;

Aurreko kasuetan bezala, zein den erabakitzeko modurik ez daukagun arren (agian Biologia Teorikoaren arloan egindako ikerketek etorkizunean hori argitu ezean).

(22)

Funtzio while-konputagarrien artean ikusi dugu badaudela batzuk ezin zaiena dagokien programa aurkitu. Orduan, beraien konputagarritasuna eskuragaitza dela esaten dugu, programa zehatza eraikitzea, hots, eskuratzea, posible dutenetatik bereizteko. Lehenengoen interes praktikoa mugatua den arren, horrelako funtzioak existitzeak konputaezintasunaren kontzeptuaren inguruan sakonkiago hausnartzeko bidea zabaltzen digu. Kontzeptu horren izaera absolutua dela, hots, problemaren espezifikazioan jarritako zehaztasuna bezalako faktoreen menpe ez dagoela hausnar dezakegu. Aitzitik, funtzio konputaezinak argi eta garbi espezifikatzen direla, hots, beraien esanahiari edo interpretazioari buruz zalantzarik ez dagoela ikusiko dugu.

3.2

Church-Turing-en Tesia

Beste aztergai garrantzitsua aukeratutako programazio-lengoaiaren egokitasunarena da: while-programek zein mailataraino osatzen dute lengoaia adierazkor bat? Zenbait problema while-konputagarriak direla ikusi dugu eta laster while-konputaezinak diren beste batzuk aurkitzen hasiko gara. Alabaina, zer gertatuko litzateke beste programazio-lengoaia desberdin bat, esaterako, ahaltsuagoren bat, erabiltzen hasiko bagina? Primitiba gehiago gehituz gure lengoaia zabaltzen badugu, lengoaiaren bertsio sinplerako konputagarriak ez ziren funtzio batzuk konputagarriak bihurtzen direla ez al genuke aurkituko agian?

Gai hau guztiz funtsezkoa da, berez, guretzat while-programek ez baitute inolako interesik. While-konputagarritasunaren kontzeptua lengoaia honekin bakarrik aplika daitekeela aurkituko bagenu, gure emaitza edo ondorio guztiek ez lukete inolako interesik edukiko, while-programak ez baititugu praktikan erabiliko. Aitzitik, problema bakoitzerako zein lengoaia zehatzetan izango den programagarria jakiteak garrantziren bat eduki dezakeen arren, konputaezintasunak kontzeptu absolutu bezala du interesa: funtzio bati konputaezina esan beharko genioke bakarrik bere balioak kalkulatzeko prozedurarik ezartzea ezinezkoa balitz, edozein metodo, lengoaia edo sistema konputazional erabilita ere. Problema zehatz bat S

sisteman konputagarria ez den arren, aldiz, T-n hala dela frogatzera mugatzeak ez dauka zentzu gehiegirik. Horrek, gaitasun adierazkor gutxiago daukalako, S sistema kalitate okerragokoa dela eta agian baztertu, utzi, egin beharko genukeela besterik ez digu adieraziko.

Edozein programazio-sistemari bere bidez konputagarriak diren funtzioen klasea dagokio. Ikur-kateen gaineko funtzio guztien klaseari deitzen badiogu,

S programazio-sistema bakoitzak S-konputagarriak diren funtzioak

S-konputaezinak direnetatik bereizteko marra bat ezartzen du. Konputagarritasunaren nozio orokorra programazio-sistema zehatzaren menpekoa

(23)

ezin denez izan, funtzio bat besterik gabe konputagarria dela esango dugu,

S-konputagarrian bihurtuko duen S programazio-sistema existitzen bada. Funtzio konputagarri guztien klaseari

C

deituko diogu, eta beste klaseekiko erlazioa 3.1 irudiko diagraman adierazten dugu.

Adierazitako hori egoera erreala izango balitz arazo larria edukiko genuke: funtzioa konputagarria ez dela frogatzeko, existitzen diren programazio-sistema guztiak banan-banan probatu beharko genituzke, funtzio horrekin ezin dutela egiaztatzeko. Zorionez 3.1 irudian erakutsitako panorama ez dator bat errealitatearekin eta programazio-lengoaiak beraien artean oso antzekoak dira, susma genezakeena baino askoz gehiago. Adibidez, [IIS 98]-n makroekin egin dugun lan guztiak, while-programen lengoaian erraztasunen baten hutsunea (hala nola, kabiatze-adierazpenak, aurreprogramaturiko azpierrutina gehiago, datu-mota gehiago, egitura konplexuagoak, erabiltzaile-objektuak, etab.) aurkitu dugun bakoitzean hori lengoaiari gehitzea ez zela beharrezkoa erakutsi digu. Eta ez zen beharrezkoa lengoaian jadanik definituta zeuden elementuen bitartez simulatu zitekeelako. Beste era batera esanda, while-programek desiratu beharko luketen eta beste programazio-lengoaiaren batek daukan ezaugarririk ez dugu topatu.

W‐konputagarriak W*‐konputagarriak

T‐konputagarriak

F

C

3.1 irudia: W programazio-sistema edukiko bagenu, zeinarekin W-konputagarriak diren funtzioen klasea konputatzera iritsiko litzatekeen, sistemaren bertsio hobetua W* lortzea gerta liteke eta berarekin, lehen aipatutako klasea W-rentzat konputaezinak ziren funtzioekin zabaltzea. Irudian T deitu duguna bezalako sistema independenteak gara litezke, funtzio berriak konputatzea ahalbidetu lezaketenak, baina W-konputagarriak diren funtzio batzuk programatzea ezinezkoa egingo luketenak. Funtzio konputagarrien

C

klasea (lodiagoa den marra) sistema partikular guztien bitartez konputatutako guztien bildura izango litzateke. Eta konputaezinak, balizko edozein metodo hartuta ere ebazpenik onartuko ez luketenak izango lirateke (eremu grisa).

Alabaina, honen inguruan eduki dezakegun gure esperientzia oso argigarria izan arren, Konputazio Zientziek dituzten ia 70 urteetan zehar sortutako erabateko unanimitate sendoa are gehiago da: beraien artean oso urruti dauden ereduak eraiki

(24)

diren arren (horietako batzuk esoterismoaren ingurukoak ere esan dezakegu), while-programak baino perfektuagoa den programazio-lengoaiarik ez da sekula lortu. Oraindik adierazgarriagoa dena, perfekzio gutxiagoko ereduak ere ez dira eman: orain arte asmatutako S sistema guztiek S-konputagarriak diren funtzioen klase bera sortu dute zehatz-mehatz3. Egoera 3.2 irudian erakutsitakoa izango litzateke.

W‐konputagarriak W*‐konputagarriak

T‐konputagarriak

C

F

3.2 irudia: Orain arte aurkitutako programazio-sistema guztiek, eta beraien aldakuntzek, funtzio berdin-berdinak konputatzen dituzte. Hala ere, gaur egun konputaezinak suertatzen diren funtzioetako batzuk konputatzea ahalbidetuko luketen programazio-sistema berriak agertzeko atea irekita gera zitekeen. Hori horrela balitz, egungo sistemek lortu ez duten funtzio konputagarrien eremu bat egongo litzateke.

Jokaleku honetan zenbait gauza hobetu dira baina beste batzuk ez. Alde batetik, funtzio bat while-konputagarria ez dela frogatzen badugu, aldi berean ezaguna den beste edozein lengoaiarekin ere ezin dela konputatu frogatzen ariko ginateke, eta hori ez da gutxi. Alabaina, “benetan” konputaezina dela egiaztatzeko inolako modurik ez genuke izango, horretarako oraindik asmatu ez diren, eta agian inoiz izango ez diren, programazio-sistemekin duten erlazioa aztertu beharko genukeelako.

Hala ere, programazio-sistema guztiak behin eta berriz bat etortzeak, konputagarritasunaren nozio berdina sortuz, informatikari teorikoak ondorio zorrotz batera eraman zituen oso goiztik: konputagarritasunaren nozio absolutua existitzen diren sistema konputazionaletatik baino haratago ez da joango, hau da, ezagunak direnak baino hobea den programazio-sistemarik ez da existitzen. Eta hori izango litzateke, hain zuzen ere, Informatikan burutu diren berrikuntzetatik bakar

3 Baieztapen honi ñabardurak egin behar dizkiogu. Programazio-lengoaia behar adina murrizten

bada, zenbait funtzio konputatzeko gaitasuna gal daiteke. Esaterako, while-programekin egin genuenaren antzera, baina begizta orokortuak for motakoak diren begizta kontrolatuengatik ordezkatuz, for-programak definitzen baditugu, lengoaia berriak gaitasun adierazkorra galtzen du eta jatorrizko lengoaiarekin baino funtzio gutxiago konputatzen dira.

(25)

batek ere hasierako konputazio eredu abstraktuek konputatzen ez zituzten funtzioak konputatzea ez lortu izanaren arrazoia. Teoria hau Church-Turing-en tesia bezala ezaguna da eta era zabalean onartutzat hartzen da. Badira urteak Konputazio Zientziatan hori horrela dela inolako erreserbarik gabe kontuan hartuz lan egiten dela. Bere ondorioak 3.3 irudian adierazten dira.

W‐konputagarriak W*‐konputagarriak T‐konputagarriak

C

F

3.3 irudia: Church-Turing-en Tesiaren ondorioa: programazio-sistema desberdinetarako lortutako konputagarritasun-nozioa erabatekoa da, eta etorkizunean inolako sistemarik ez du aldatuko.

Church-Turing-en Tesiaren berehalako ondorioa da while-konputagarritasun eta while-konputaezintasunaren nozioak egungo eta etorkizuneko programazio-sistema guztietarako ere baliozkoak direla. Hortaz, funtzio jakin bat konputatzen duen while-programarik ez dagoela frogatzea lortzen dugunean, askoz sakonagoa den zerbait frogatzen arituko gara: Informatikak funtzio hori konputatzeko bitartekorik ez daukala, ez orain ezta inoiz ere. Lege Unibertsalaren mailako muga aurkitua izango dugu.

Konputagarritasuna, konputaezintasuna, erabakigarritasuna edo erabakiezintasuna hitzen aurretik hemendik aurrera while aurrizkia ez erabiltzearen arrazoia arestian aipatutako horixe izango da, hain zuzen ere. Funtzio bat konputagarria dela frogatzeko bera konputatuko duen while-programa aurkituz jarraituko dugu, edo konputaezina dela frogatzeko inolako while-programarik ez duela horrelakorik egiten egiaztatuz. Hala ere, badakigu frogapen horien ondorioak euskarria besterik ez den erabilitako lengoaia baino haratago doazela, eta Konputazioaren Legeen barnean funtzio horrek duen estatutuari eragiten diotela.

(26)

4.

Funtzio Unibertsala

Konputagarritasun eta konputaezintasunaren nozioen hedapena argitzen duten zenbait funtsezko kontzeptu ezarri ondoren, lehenengo funtzio konputaezinen bilaketari ekiteko prest gaude. Alabaina, hurrengo kapituluan ikusiko dugun lez, lan hori ez da batere arrunta eta arrakastaz praktikan jartzeko kasu batzuetan tresna gehigarriak beharko ditugu. Konputaezintasun frogapenen ezaugarri bitxienetako bat programen eraikuntzan oinarritzen direla da, askotan nahiko konplexuak diren programak eraiki behar izaten direlarik.

Funtzio konputagarri gehiago aztertzeko beste arrazoi bat konputagarritasunaren azken muga arakatzearen aukeran datza. Kapitulu honetan landuko ditugun funtzioak eta predikatuak, nolabait konputagarritasunaren barnean plantea ditzakegun bihurrienak dira. Pixka bat urrutirago joaten saiatzen bagara, lehenengo konputaezinekin aurkituko gara (ikus 5. kapitulua).

Badago datu-mota bat, zeinen interesa aurretik ezaguna izan dezakegun beste edozeinena baino haratago doan,

datu-motari buruz ari gara. Karaktere-kate, balio logiko, zenbaki edo, pilak edo zuhaitzak bezalako egituren kasuan era praktikoan planteatzen zaizkigun problema gehien-gehienak konputagarriak dira eta aspaldidanik (zenbait kasutan zibilizazio egiptiarretik) ebatzita daude, baina programak (eta bereziki, while-programak) askoz konplexuagoak diren objektuak dira eta hauetan konputaezintasuna ia-ia agerian geratzen da.

Beste inplementazio batzuekin gertatu den bezala, programen gainean definitutako eragiketa zehatzen konputagarritasuna plantea dezakegu eta ondoren eragiketa horiek (hobeto esanda, horien artetik konputagarriak direnak) beste problema batzuk ebazteko tresna lagungarri bezala erabil ditzakegu. Era berean programa-multzoak definitu eta gure definiziotan erabil ditzakegu:

VAC = { x

: y∑*

x(y) } = { x

: Wx = Ø }

COF = { x

: Wx kofinitua da } = { x

: Wx finitua da }

SUP = { x

:

x supraiektiboa da } = { x

: Rx = ∑* }

INJ = { x

:

x injektiboa da } = { x

: yz (yz

x(y)=

x(z)) } K = { x

:

x(x) }

(27)

SIC = { x

: x–n ez dago if_then erako azpiprogramarik }

CER = { x

: x-ren egikaritzapenik ez dago X0-ren edukia erabiltzen duenik } Horrela, VAC multzoa sarrera guztiekin begizta baten barnean geratzen diren programen multzoa da, COF ia datu guztietarako konbergitzen dutenena da (hots, portaera dibergenteen kopurua finitua dutenena), SUP edozein emaitza onartzen dutenena da, eta INJ datu desberdinetarako emaitzak errepikatzen ez dituztenen multzoa da. Era berean, K bere kodearen gainean konbergitzen duten programen multzoa da, SIC bere testuan baldintzazko agindurik ez daukatenena da eta CER multzoa X0-ren edukia erabiltzen ez dutenena da (hots, bere eskuin aldean X0 aldagaia daukan esleipenen batetik pasatzen ez direnena). Ikusiko dugun bezala, programa-multzo hauek guztiak (bat ezik) erabakiezinak dira.

Azaldu ditugun arrazoi horiek direla eta, datozen ataletan ahalegina egingo dugu while-programak datuak bezala hartzen dituen programazioaren inguruan trebetasuna garatzeko. Horrela, zenbait funtzio konputagarri eta predikatu erabakigarri lortuko dugu ere, beste funtzio eta predikatu batzuk hala ez direla frogatzeko laguntza handikoak izango direnak hain zuzen ere.

4.1

While-programen gaineko eragiketa sintaktikoak

While-programak beste edozein datu arrunt bezala erabiltzea planteatzen badugu, defini dezakegun maneiatze-maila errazena sintaktikoarena da: programa baten testua azter dezakegu, hots, bere eragiketak edo egitura arakatu, eta horren inguruan galdera errazak ebatzi ditzakegu. Maila honetan, oro har, argumentu bezala while-programa bat hartu eta emaitza sinple bat (zenbakizkoa edo boolearra) itzultzen duten funtzioak aurkituko ditugu.

Adibidez, honako erantzunak ematen dituzten funtzioak defini ditzakegu: programa batek dituen aldagaien edo aginduen kopurua, habiaratuta dauzkan begizten kopuru maximoa, ezaugarri bereziak dituen egituraren bat (esaterako, bere barnean while-aren kontrol aldagaia aldatzen ez duen begizta susmagarriren bat) ba ote duen, etab. Programen ezaugarri estatikoekin, hots, konpilatze-unean zehaztuak izan daitezkeenekin, bakarrik lan egiten duten funtzioen konputagarritasuna frogatzen joatea ez da zaila. Hori ikusteko honako funtzioa adibide moduan hartuko dugu:

(28)

edozein programa harturik, bertan agertzen den aldagai-indize handiena adierazten duena. Bere konputagarritasuna frogatzeko makroprograma bat idatziko dugu. Honek, azken_aldagaia(x) kalkulatzeko,

datu-motaren berezko eragiketak erabiliko ditu eta Px programa arakatuko du, bere oinarrizko aginduen (esleipenen eta baldintzen) bila, aldagaiak bertan erreferentziatzen baitira. Analisi-prozesu hau kasu gehienetan lineala da. Adibidez, Px esleipena bada, bere aldagaien indizeak atera eta handienarekin geratzea nahikoa izango da. Baldintza edo iterazio agindua bada, baldintzan parte hartzen duen aldagaia aztertuko dugu, barneko agindua atera eta prozesua honekin jarraituko dugu. Alabaina, Px agindua P Q motako konposaketa sekuentziala bada, lehenik P eta gero Q (edo alderantziz) arakatu behar ditugula aurkitzen dugu. Baina P, era berean, R S motako konposaketa sekuentziala izan daitekeenez, bere analisiak R aztertzen dugun bitartean S

baztertuta uztea eska dezake. Jakina, hau amaierarik gabeko egoera izan daiteke, beraz Px-ren azpiprograma diren eta aztertzeko zain dauden aginduen kopuru mugagabea eduki dezakegula aurreikusi behar dugu (ikus 4.1 irudia)

4.1 irudia: Zuhaitz egitura duen while-programa bat analizatzean, azterketaren zain dauden azpiprogramen zerrenda mantentzea beharrezkoa izan daiteke. Zerrenda horren luzera arbitrarioa izango da.

Arazo hau konpontzearren oraindik analizatu gabe dauden while-programak dituen pila bat mantenduko dugu une oro. Pila honek hasiera batean Px programa edukiko du eta begizta batek kudeatuko du. Honek, iterazio bakoitzean, pilaren

P

x

P Q

P

Q

R S

R

S

T U

T

U

||

||

||

...

azterketa atzeratua (lehenik amaitu behar da)

P

azterketa atzeratua (lehenik amaitu behar da)

R

azterketa atzeratua (lehenik amaitu behar da)

T

(29)

tontorrean aurkitutako while-programa prozesatuko du eta bere azpiprogramak pilan berriro sartuko ditu, ondoren eta komeni denean prozesa daitezen. Pila husteak lanarekin amaitu dela adieraziko du.

While-programak maneiatzeko datu-motaren eragiketak erabiliko ditugu, 3. Eranskinaren e atalean deskribatuta daudenak hain zuzen ere.

PILA := <];

PILA := pilaratu (X1, PILA); X0 := 0;

-- X0-n orain arte aurkitutako indize maximoa mantenduko dugu

whilenot P_hutsa? (PILA) loop

-- Une honetan analizatu beharreko azpiprograma pilatik ateratzen da

PROG := tontorra (PILA); PILA := despilatu (PILA);

-- Azpiprograma hori bere motaren arabera prozesatzen da

if esleipen_hutsa? (PROG) then

if aldagai_indize (PROG) > X0 then

X0 := aldagai_indize (PROG);

end if;

elsif esleipen_cons? (PROG) or esleipen_cdr? (PROG) then if aldagai_indize (PROG) > X0 then

X0 := aldagai_indize (PROG);

end if;

if 2_aldagai_indize (PROG) > X0 then

X0 := 2_aldagai_indize (PROG);

end if;

elsif baldintzazkoa? (PROG) or iterazioa? (PROG) then if aldagai_indize (PROG) > X0 then

X0 := aldagai_indize (PROG);

end if;

PILA := pilaratu (barne_agindu (PROG), PILA);

else PILA := pilaratu (2_ barne_agindu (PROG), PILA);

PILA := pilaratu (barne_agindu (PROG), PILA);

end if; end loop;

4.2

Zerrendatze Teorema

While-programen beste ezaugarri estatiko batzuk ere antzeko eran tratatzen dira. Alabaina, programen portaera dinamikoaren menpekoak diren, hots, egikaritzapen-unean egiaztatzen diren egoeren menpekoak diren beste ezaugarri batzuetan murgiltzen garenean emaitza interesgarriagoak lortzen dira.

Horrela, ikusiko dugun bezala konputagarria izango den funtzio berezi batean jarriko dugu gure arreta: funtzio unibertsala. Honek argumentu bezala Px

(30)

while-programa eta y datua (hitza) hartzen ditu, eta aipatu datu hori sarrera bezala emanda Px programak sortuko lukeen emaitzarekin erlazionatzen du bikotea. Beraz, funtzio unibertsala edozein konputazioren portaeraren emaitza deskribatzeko gai izango da, eta horregatik bere hantusteko izena. Funtzioa

hizkiaren bitartez adierazten da eta honela definitzen da:

(x,y) 

x(y)

Funtzio honen garrantzia azpimarratu behar dugu, sarrera bezala, kalkulatu beharreko funtzioaren indizea eta sarrera-datua besterik eman gabe, argumentu bakarreko edozein funtzio konputagarriren portaera simulatzen duelako. Funtzio unibertsala konputatzen duen programa, nolabait, gainontzeko programa guztiak duintasunez errepresentatzeko gai da, bere barnean konputazioaren mamia bilduz.

TEOREMA (ZERRENDATZEARENA):

:

∑*  ∑* funtzioa konputagarria da:

(x,y)      

bestela ) ( ) (y x y x

konputagarria dela frogatzeko idatzi behar dugun U programak (programa unibertsalak) sarrera bezala edozein x programa-kodea eta y datua hartuko ditu, eta emaitza bezala Px-k y-ren gainean sortuko lukeen irteera (egonez gero) lortu beharko du (ikus 4.2 irudia).

z = P

x

(y)

x

y

U

4.2 irudia: Diseinatu behar dugun U programaren funtzionamenduaren eskema.

U programak Px-k y datuaren gainean daukan portaera (hots, bere konputazioa) simulatzea izango da hau egiteko era naturala. Beraz, U while-programen interpretatzailea izango da: egokia den egoera-bektorea hasieratu eta mantendu beharko du, Px programaren aginduek egoeran burutzen dituzten eraldaketak kontu handiz jarraituz. Hala ere, U idazteko unean egoera-bektore

(31)

horrek izango duen tamaina ez dakigu, zein Px programa zehatza simulatu beharko dugun ez baitakigu. Egitez, egoera-bektore horrentzat ezin dugu ezta k tamaina maximoa finkatu, espazio gehiago behar duen eta aurreikuspen horiek hausten dituen programaren bat beti existituko delako. Irtenbidea egoera-bektore osoa edukiko duen VARS bektore dinamikoa erabiltzea da, eta honela une oro VARS(i) balioa Px programaren XI aldagaiak daukan edukia izango da. VARS-en hasieratzea, lehenengoan ezik gainontzeko bere posizio guztietan

balioa jarriz egingo da, eta VARS(1)-ek y datua eduki beharko du. Era berean, behin Px-ren egikaritzapenaren simulazioa bukatzen denean, bere emaitza bektorearen 0-garren posizioan bilatzera joko dugu.

XI := conss(XJ);

...

...

...

VARS

PILA

j i u v R

...

...

...

...

j i sv v R

...

4.3 irudia: U-ren egikaritzapen-zikloa, egikaritu beharreko hurrengo programa esleipena denean.

Bestaldetik, Px-ren egikaritzapenak berak azken_aldagaia funtzioarekin genuenaren (hots, 4.1 irudian deskribatzen genuenaren) antzeko arazoa agertzen digu. Modu berean ebatziko dugu, baina abagune honetan pilak, egikaritzeko zain dauden programak edukiko ditu, oraindik analizatu gabe daudenen ordez. Ondoren zuzena izango den egikaritzapen-ordena sor dadin, zain dauden programak pilan sartzean kontuz ibili beharko dugu, besterik ez. Hasiera batean PILA-k Px programa bakarrik edukiko du, eta egikaritzapenaren oinarrizko zikloa PILA-tik programa bat atera eta hau egikaritzen saiatzea izango da. Esleipena bada, ondorioz VARS konputazio-egoeran aldaketa egingo da (4.3 irudia).

Konposaketa sekuentziala izanez gero, programa sinpleagoak izango diren bere bi osagaietan zatitu eta pilan sartzearekin konformatuko gara (4.4 irudia). Baldintzazko konposaketa bada, baldintza VARS konputazio-egoeran ebaluatuko dugu eta if-aren barneko agindua egikaritzea egokitzen bada, hori pilan sartuko dugu (4.5 irudia) hurrengo iterazioan egikaritua izan dadin. Azkenik, iteraziozko programa bada, bere baldintza ebaluatuko dugu ere, baina kasu honetan begiztan sartzea egokitzen bada, pilan bere barneko agindua ez ezik begizta osoaren kopia

(32)

ere sartuko dugu, uneko iterazioa bukatu ondoren berriz kontuan hartua izan dadin (4.6 irudia). R

...

VARS

PILA

P Q

...

P Q

...

R

...

4.4 irudia: U-ren egikaritzapen-zikloa, egikaritu beharreko hurrengo programa konposaketa sekuentziala denean.

if cars?(XI) then

P end if ; R

...

VARS

PILA

...

i sv

...

P R

...

...

i sv

...

4.5 irudia: U-ren egikaritzapen-zikloa, egikaritu beharreko hurrengo programa baldintzazko konposaketa denean, bere baldintza betetzen delarik.

P R

...

...

i sv

...

while nonem?(XI) loop

P end loop ; R

...

VARS

PILA

...

svi

...

while nonem?(XI) loop

P end loop ;

4.6 irudia: U-ren egikaritzapen-zikloa, egikaritu beharreko hurrengo programa iteraziozkoa denean, eta gainera bere baldintza betetzen delarik: orduan gutxienez bere lehen iterazioa burutuko da.

(33)

Lehen itxura batean azken_aldagaia eta

funtzioen programek oinarri berdinak jarraitzen dituztela eta antzeko portaerak dituztela eman dezake, baina beraien artean badago oso diferentzia funtsezkoa, pilaren erabilerari eragiten diona. Lehenengoa analisi-prozesu bati dagokio, eta pilatik ateratzen den programa ez da han berriro sartuko (seguraski bere pusketak sartu beharko diren arren). Alabaina U

simulazio-prozesu bati dagokio eta begizten egikaritzapenak programa bera behin eta berriz pilaratzea exiji dezake.

Aurreko paragrafo eta irudietan zehaztutako estrategiak honako U

programara garamatza:

VARS(azken_aldagaia (X1)) :=

; VARS(1) := X2;

-- y kargatu baino lehen, Px-ren egoera-bektorearen aldagai guztiak

-ekin hasieratzen ditugu

PILA := pilaratu (X1, <]);

while not P_hutsa? (PILA) loop

PROG := tontorra (PILA); PILA := despilatu (PILA);

if esleipen_hutsa? (PROG) then

VARS(aldagai_indize(PROG)) :=

;

elsif esleipen_cons? (PROG) then

VARS(aldagai_indize(PROG)) :=

ikur_erabili (PROG) & VARS(2_aldagai_indize(PROG));

elsif esleipen_cdr? (PROG) then

VARS(aldagai_indize(PROG)) :=

cdr (VARS(2_aldagai_indize (PROG)));

elsif konposaketa?(PROG) then

PILA := pilaratu (barne_agindu (PROG),

pilaratu (2_barne_agindu (PROG), PILA));

elsif baldintzazkoa? (PROG) then

if ikur_erabili(PROG) = lehena (VARS(aldagai_indize(PROG))) then

PILA := pilaratu (barne_agindu (PROG), PILA);

end if; else

-- iterazioa da

if nonem? (VARS(aldagai_indize (PROG))) then

PILA := pilaratu (barne_agindu (PROG), pilaratu (PROG, PILA));

end if; end if; end loop;

-- Px-ren egikaritzapena bukatzen bada, emaitza deskargatzen dugu

X0 := VARS (0); 

Makroprograman erabiltzen diren datu-motekin burututako eragiketen inguruan argibide gehiago behar izanez gero C Eranskinera jotzea gomendatzen dugu.

(34)

OROKORTZEA: Aurreko emaitza orokortzen da, k argumentudun funtzio konputagarrientzat den funtzio unibertsala ere konputagarria dela frogatzeko. Horrela, k≥0 guztietarako

k+1 :

*k * funtzioa konputagarria dela daukagu:

k+1 (x,y1, …,yk) =     

bestela ) ,..., , ( ) ,..., , ( 1 2 k x 1 2 k x y y y y y y

 Aurretik deskribaturiko programa berbera nahikoa izango da, baina bigarren lerroaren ordez honakoa jarriz:

VARS(1):= X2; VARS(2):= X3; VARS(3):= X4; ...

VARS(K):= X[K+1]; 

Historikoki, Zerrendatze Teoremaren frogapenak honek agerian uzten duena baino aurrerakuntza kontzeptual handiagoa suposatu zuen. Kontuan hartu behar da Konputagarritasun Teoriaren hastapenetan (gogoratu, oraindik konputagailuak existitzen ez zirenean) programa bakoitza sistema konputazional zehatz baten portaera operatiboaren deskribapentzat hartzen zela. Hau da, algoritmo bat existitzeak ataza zehatz hori egiteko gai zen makina bat eraikitzea posible zela frogatzen zuen. Funtzio Unibertsalaren konputagarritasunak helburu orokorreko konputagailuen existentzia frogatzea suposatu zuen, gailu bakar bat (U programa konputatzeko gai den hori), existitzen den beste edozein gailu fisikoren portaera eraginkortasunez simulatzearren, bere portaera modulatzeko gai delako. Honek hardware/software dualtasuna behin-betikoz ezartzea eta programagarritasunaren kontzeptua formalizatzea ekarri zituen. Programagarritasunarekin, gailu konputazionalek beren egitura fisikoa aldatu behar izan gabe beren funtzionalitatea errotik aldatzeko duten gaitasuna adierazten dugu.

Funtzio unibertsala, frogatu dugun moduan, konputagarria denez, beste edozein programaren makroadierazpenetan erabil ahal izango dugu, eta horrela beste funtzio batzuen konputagarritasuna frogatu ahal izango dugu, esaterako, ondoren definitzen dugun

:

∑*  ∑* funtzioarena:

         

bestela ) ( ) ?( car ) ?( car ) ( ) , ( yR y x x y y y x b x a x

(35)

Hau konputatuko duen makroprograma hau bezain sinplea izango da:

if cara?(X2) then

X0 :=

(X1, X2);

elsif carb?(X2) then

R :=

(X1, X1&X1); X0 := X2R;

else X0 := ; end if;

Kontuan hartu R :=

(X1, X1&X1); makroaginduaren helburua filtro-lana egitea dela. Baldin eta

x(xx)-k dibergitzen badu, itxaroten dugun portaera lortzen dugu,

(x,y) ere indefinituta geratuko delako. Beste kasuan, programa hurrengo agindura pasako da, eta horrela kalkulatu eta yR itzuli ahal izango du.

4.3

Etendako egikaritzapena

Zerrendatze teoremarekin edozein while-programaren funtzionamendua amaieraraino simula dezakegula egiaztatzen dugu, baina zenbaitetan hau ez da egokia, programa horrek ziklatzen badu bere konputazio infinituan atzetik eramango gaituelako.

Noizean behin, programa baten egikaritzapena neurrizko denbora baten ondoren etetea komenigarriagoa izango da, nahiz eta horrela eginez konputazio horrek azkenean bukatuko ote zuen ziurtasunez jakingo ez dugun. Horretarako T

predikatua oso onuragarria gertatuko zaigu, honek, pausoetarako goi-muga maximoa hartuz, programa batek datu baten gainean konbergitzen duenetz behatzen duelako. Konputazio-pausoa Px programaren ekintza bat burutzeari, hots, esleipen bat egikaritzeari edo baldintza baten egiaztapenari, dagokiola ulertzen dugu.

PROPOSIZIOA: Ondoren definitzen dugun T :

∑* 

predikatua erabakigarria da:

T(x,y,p) Px-k y-ren gainean konbergitzen du p pausotan edo gutxiagotan

T predikatua konputatzen duen programa

-renaren oso antzekoa izango da, baina egikaritzapena eteteko pauso-kontagailu bat erabiliz:

VARS(azken_aldagaia (X1)) :=

; VARS(1) := X2; PAUSOAK := 0; PILA := pilaratu (X1, <]);

while not P_hutsa? (PILA) and PAUSOAK<X3 loop

PAUSOAK := PAUSOAK+1;

PROG := tontorra (PILA); PILA := despilatu (PILA);

(36)

VARS(aldagai_indize(PROG)) :=

;

elsif esleipen_cons? (PROG) then

VARS (aldagai_indize(PROG)) :=

ikur_erabili (PROG) • VARS (2_aldagai_indize (PROG));

elsif esleipen_cdr? (PROG) then

VARS (aldagai_indize(PROG)) :=

cdr (VARS (2_aldagai_indize(PROG)));

elsif konposaketa?(PROG) then

PILA:= pilaratu(barne_agindu(PROG),

pilaratu(2_barne_agindu (PROG), PILA));

PAUSOAK := PAUSOAK–1;

-- inolako ekintzarik burutzen ez den kasu bakarra

elsif baldintzazkoa? (PROG) then

if ikur_erabili(PROG) = lehena(VARS(aldagai_indize(PROG))) then

PILA := pilaratu (barne_agindu (PROG), PILA);

end if; else

if nonem? (VARS (aldagai_indize (PROG))) then

PILA := pilaratu (barne_agindu(PROG), pilaratu (PROG, PILA));

end if; end if; end loop;

-- predikatua egiazkoa izango da Px-ren egikaritzapena bukatu bada

X0 := P_hutsa? (PILA); 

Programa baten egikaritzapenak gutxienez beti pauso bat eman beharko duela kontuan hartu beharrekoa da, hortaz, T(x,y,0) beti faltsua izango dela.

Jakina, T(x,y,p)-ren emaitza faltsua denean ez dugu arrazoiari buruzko informazioa jasotzen. Px-k y-ren gainean ez konbergitzeagatik izan daiteke edo bestela konputazioa bukatzeko p pauso-kopurua nahikoa ez izateagatik.

Batzuetan konputazioa bukatzen denentz ez ezik, zein emaitzarekin egiten duen galdetzea erabilgarria gerta daiteke. Horregatik beste predikatu bat definitzen dugu, E predikatua, zeinek argumentu gehigarria hartzen duen, bilatu nahi dugun emaitza hain zuzen ere.

PROPOSIZIOA: Honako E :

∑* 

∑* 

predikatua erabakigarria da:

E(x,y,p,z) Px-k y-ren gainean konbergitzen du p pausotan edo gutxiagotan, eta irteera bezala z sortuz

E-ren programa lortzeko T konputatzen duenaren gainean ukitu txiki bat bakarrik da beharrezkoa. Bere azken aginduaren ordez honakoa jartzea nahikoa izango da:

(37)

X0 := P_hutsa? (PILA) and VARS(0) = X4; 

E(x,y,p,z)-rentzat emaitza negatiboa edukitzea zio desberdinengatik izan daitekeelako aurkitzen gara berriz ere. Px-k y-ren gainean ez konbergitzeagatik izan daiteke, edo konputazioa bukatzeko p pauso kopurua nahikoa ez izateagatik, edo bestela konputazioa z-ren desberdina den emaitza sortuz bukatzeagatik.

OROKORTZEA: k sarrerekin erabilitako while-programetarako T eta E

predikatuak ere erabakigarriak direla frogatzeko aurreko emaitzak orokortzen dira. Horrela, k≥0 denetarako, ondoren definitutako Tk+2 :

*k

eta

Ek+3 :

*k

*

predikatuak erabakigarriak direla daukagu

Tk+2(x,y1, …,yk,p) P

x-k (y1, …,yk)-ren gainean konbergitzen du p pauso edo gutxiagotan

Ek+3(x,y1, …,yk,p,z) P

x-k (y1, …,yk)-ren gainean konbergitzen du p pauso edo gutxiagotan eta irteera bezala z sortuz

Tk+2-ren kasuan T-ren programa aldatu egin beharko da, bere lehen lerroa

hauengatik ordezkatzeko: VARS (1) := X2; VARS (2) := X3; VARS (3) := X4; ... VARS (K) := X[K+1];

eta begiztaren baldintza, honengatik:

while not P_hutsa? (PILA) and PAUSOAK < X[K+2] loop

Ek+3-rentzat, aurrekoaz gainera, bukaerako esleipena, honengatik ordezkatzea

beharrezkoa izango da ere:

X0 := P_hutsa? (PILA) and VARS(0) = X[K+3]; 

Hasieran definitutako T eta E predikatuak, jakina, T3 eta E4 kasu partikularrak

besterik ez dira.

4.4

Prozesu tartekatzea

Funtzioren baten konputagarritasuna frogatzeko algoritmo bat programatzen dugunean, gure helburua lortzeko, datu bat edo gehiago behar duten programa bat edo gehiago egikaritzeko beharrarekin aurki gaitezke gure prozesuaren barnean. Adibidez, ondorengoko

:



funtzioa konputagarria dela frogatu nahi badugu:

Referensi

Dokumen terkait

Berdasarkan perhitungan Effect Size (ES) tersebut dapat disimpulkan bahwa pembelajaran dengan menggunakan alat peraga Algebraic Experience Material (AEM) terhadap

Pada fase ini misil harus terbang menanjak untuk dapat memenuhi kondisi nilai akhir pada sudut lintasan terbang.. γ Pada awal menanjak gaya dorong berada pada

Nastavnici Odsjeka za muzikologiju u akademskoj su godini 2015/2016. Prassl) Hrvatska glazba srednjega vijeka (H. Kiš Žuvela) Notacija rane glazbe (H. Breko Kustura) Glazba baroka

Penerimaan penggunaan teknologi aplikasi web dan sms gateway dapat dibandingkan dari proses secara lebih lanjut dengan melihat pada titik dimana biaya total prosesnya

yang dikatakan lebih layak untuk dijadikan investasi yaitu ikan bandeng karena net present value, Profitabilitas index, pay back period dan avarage rate of return nya lebih

A szegedi Dél-Magyarország című lap interjújából ki- derült, hogy Selye magyarországi utazását a kapcsolat- építés szempontjából is fontosnak tartotta, hiszen na- gyon

Berdasarkan data skor hasil belajar tes akhir itu dilakukan perhitungan terhadap skor rata-rata, simpangan baku ( S ), dan varians ( S 2 ) kelas eksperimen dan kelas

Penyusunan Proposal Skripsi ini adalah tahapan awal sebelum melaksanakan penelitian Skripsi yang merupakan salah satu syarat untuk menyelesaikan program Sarjana di Program