los lenguajes WHILE y LOOP X2 := X1; while X2 ≠ 0 do X1 := X1 + 1; X2 := X2 – 1 od índice de materias • • • • • • • sintaxis, semántica y introducción histórica capacidad expresiva modelos de cálculo lenguajes WHILE y LOOP funciones µ-recursivas teorema de equivalencia indexaciones y universalidad problemas no resolubles WHILE y LOOP están basados en el bucle indefinido y el bucle definido LOOP WHILE veremos: - sintaxis - semántica informal - semántica formal ? 15 sintaxis del lenguaje WHILE identificadores X1 , X2 , X3 , ... , Xi , ... instrucciones de asignación Xi := Xj Xi := Xi + 1 Xi := Xi − 1 ( 0 − 1 = 0 ) Xi := 0 código secuencia finita no vacía de instrucciones separadas por ";" instrucción de control bucle indefinido: while Xi ≠ 0 do (cabecera) código (cuerpo) od (cola) programa (n, p, código) p≥n ambos naturales Nota: el índice de anidamiento siempre es finito ejemplo de programa WHILE • Ejemplo 1: Sea el programa WHILE (1, 2, código) con código: X2 := X1 ; while X2 ≠ 0 do X1 := X1 + 1 ; X2 := X2 – 1 od ejemplo de programa WHILE • Ejemplo 2: Sea el programa WHILE (1, 1, código) con código: X1 := X1 + 1 ; while X1 ≠ 0 do X1 := X1 od semántica informal del lenguaje WHILE • trabaja sólo con naturales • no hay instrucciones de entrada ni de salida • para un programa (n, p, código) – n variables de entrada: X1 , X2 , ... , Xn – 1 variable de salida: X1 – p variables de uso: X1 , X2 , ... , Xp con p ≥ n • las variables que no son de entrada se inicializan implícitamente a cero • una única función (que puede ser parcial) de Nn en N se puede asociar a cada programa ejemplo de programa WHILE • Semántica del programa del ejemplo 1: Sea el programa WHILE (1, 2, código) con código: X2 := X1 ; while X2 ≠ 0 do X1 := X1 + 1 ; X2 := X2 – 1 od Este programa tiene una variable de entrada (X1), usa dos variables (X1 , X2), y X2 se inicializa implícitamente a cero. Calcula: f(n)= 2n ∀n∈N ejemplo de programa WHILE • Semántica del programa del ejemplo 2: Sea el programa WHILE (1, 1, código) con código: X1 := X1 + 1 ; while X1 ≠ 0 do X1 := X1 od Este programa tiene una variable de entrada (X1), que es la única que usa. Calcula: f(n)= ↑ ∀n∈N (función que siempre diverge) semántica formal del lenguaje WHILE versión etiquetada de un programa WHILE Dado un programa WHILE (n, p, código) lo escribimos de manera que cada línea contenga una de las siguientes cosas: • una instrucción de asignación • una cabecera de (bucle) while: while Xi ≠ 0 do • una cola de (bucle) while: od Además: • numeramos las líneas consecutivamente empezando por el 1 • tras una cabecera de while ponemos el número que le ha correspondido a su cola • tras una cola de while ponemos el número que le ha correspondido a su cabecera ejemplo de programa WHILE • Versión etiquetada del programa WHILE del ejemplo 1 Sea el programa WHILE Q = (1, 2, código) con código 1: X2 := X1 ; 2: while X2 ≠ 0 do 3: X1 := X1 + 1 ; 4: X2 := X2 – 1 5: od :5 :2 concepto de configuración de un programa WHILE • sea Q = (n, p, código) un programa WHILE, con líneas numeradas de 1 a f , una configuración de Q es una (p+1)-tupla (s, x) con s∈{1, 2, 3,…, f, f +1} y x∈Np • una configuración es inicial si s=1 y xn+1 = … = xp = 0 • una configuración es final si s = f +1 • CQ denota al conjunto de las configuraciones de Q ejemplos de configuraciones Sea el programa WHILE Q = (1, 2, código) con código 1: X2 := X1 ; 2: while X2 ≠ 0 do 3: X1 := X1 + 1 ; 4: X2 := X2 – 1 5: od :5 :2 (1,3,5) es configuración, no inicial y no final (1,5,0) (6,8,3) (2,2,2) (0,3,5) es configuración, inicial y no final es configuración final, y no inicial es configuración, no inicial y no final no es configuración concepto de cálculo en un paso Sea Q = (n, p, código) un programa WHILE, con líneas numeradas de 1 a f . Diremos que la configuración c1=(s, x) se transforma en la configuración c2=(t, y) en un paso de cálculo (representado por c1 Q c2 ) sii concepto de cálculo en un paso (para la asignación) < (s, x) Q (t, y) > • Si s: “asignación” aparece en la versión etiquetada de Q , entonces – t=s+1 – yi = 0 xj si " asignación" es Xi := 0 si " asignación" es Xi := Xj xi + 1 si " asignación" es Xi := Xi + 1 xi − 1 si " asignación" es Xi := Xi − 1 – yr = xr para todo r tal que 1 ≤ r ≤ p y r ≠ i concepto de cálculo en un paso (para el bucle) < (s, x) Q (t, y) > • Si s: while Xi ≠ 0 do :s’ aparece en la versión etiquetada de Q , entonces – y=x – si xi ≠ 0 entonces t = s + 1 – si xi = 0 entonces t = s’ + 1 • Si s: od :s’ aparece en la versión etiquetada de Q , entonces – y=x – si xi ≠ 0 entonces t = s’ + 1 ( xi está en la cabecera s’ ) – si xi = 0 entonces t = s + 1 ejemplos de cálculo en un paso Sea el programa WHILE Q = (1, 2, código) con código 1: X2 := X1 ; 2: while X2 ≠ 0 do 3: X1 := X1 + 1 ; 4: X2 := X2 – 1 5: od :5 :2 ¿ (1, 2, 0) Q (1, 2, 2) ? ¿ (1, 2, 0) Q (2, 2, 2) ? ¿ (3, 4, 6) Q (4, 5, 6) ? ¿ (2, 6, 0) Q (6, 6, 0) ? (1, 6, 0) Q ? (2, 3, 7) Q ? (5, 4, 2) Q ? (5, 8, 0) Q ? extendemos el “cálculo en un paso” función siguiente configuración • sea Q = (n, p, codigo) un programa WHILE y CQ el conjunto de todas las configuraciones de Q • la función siguiente SIGQ: Np+1→Np+1 es SIGQ ( c ) = c' si c c Q c' si c ∉ CQ ∨ ¬∃c' / c Q c' siguiente para el programa Q ya visto (a,b,c) (2,b,b) si a = 0 si a =1 (3,b,c) si a = 2 ∧ c ≠ 0 (6,b,c) si a = 2 ∧ c = 0 SIGQ (a, b, c) = (4,b +1,c) si a = 3 (5,b,c −1) si a = 4 (3,b,c) si a = 5∧ c ≠ 0 (6,b,c) si a = 5∧ c = 0 (a,b,c) si a > 5 función cálculo de un programa (configuración alcanzada tras i pasos) • sea Q = (n, p, c) un programa WHILE, con líneas numeradas de 1 a f , la función cálculo del programa Q es la función CALQ: Np+1→Np+1 • CALQ(a, i) = (t, b) , siendo a∈Np y (1, a) Q c1 Q c2 Q… Q ci = (t, b) el cálculo de Q en i pasos, que comienza con valores a de las variables que usa el programa (las de no entrada inicializadas) • se define recursivamente en función de SIGQ CALQ ( a , i ) = (1, a ) si i = 0 SIGQ (CALQ ( a , i − 1)) si i > 0 ejemplo de función cálculo • dado el programa Q ya visto, encontrar el valor de CALQ(6, 0, 4) solución: (1, 6, 0) Q (4, 7, 6) (2, 6, 6) Q Q (5, 7, 5) CALQ(6, 0, 4) = (5, 7, 5) (3, 6, 6) Q función complejidad temporal (nº de pasos de un programa, según la entrada) • sea Q = (n, p, código) un programa WHILE, con líneas numeradas de 1 a f , la función complejidad temporal de Q es la función TQ: Nn→N TQ ( x ) = µj[π 1p +1 (CALQ ( x, 0, j )) = f + 1] siendo x∈Nn , 0 un vector de p−n ceros y π1p+1 la función proyección de la primera componente de un vector de p+1 componentes ( µj ≡ el menor j tal que) ejemplo de función complejidad temporal • dado el programa Q ya visto, determinar la complejidad temporal solución: (1, a, 0) Q (2, a, a) Q (4, a+1, a) Q (4, a+2, a−1) Q Q (3, a, a) (5, a+1, a−1) Q (5, a+2, a−2) (3, a+1, a−1) Q (3, a+2, a−2) Q (3, ··· Q Q (4, 2a, 1) Q (5, 2a, 0) TQ(a) = 3a+2 Q (6, 2a, 0) 2a−1, 1) concepto de función calculada por un programa WHILE • sea Q = (n, p, código) un programa WHILE, la función calculada fQ: Nn→N se define por f Q ( x ) = π 2p +1 (CALQ ( x, 0, TQ ( x ))) siendo x∈Nn y 0 un vector de p−n ceros expresado informalmente: dados unos valores para las variables de entrada (x), se inicializan a cero las demás variables, se realizan pasos de cálculo hasta alcanzar una configuración final, y se toma como resultado la segunda componente (variable X1); si no es posible alcanzar tal configuración final, entonces el programa no acaba para esos valores de entrada, y la función está indefinida (diverge) la clase de funciones WHILE-calculables • Fn(WHILE) es el conjunto de todas las funciones f:Nn→N tales que existe un programa WHILE, con n variables de entrada, que calcula f • F(WHILE) es la unión de todas las Fn(WHILE) , para n≥0 • si f∈F(WHILE) diremos que f es una función WHILE-calculable ejercicios de WHILE-calculabilidad Demostrar (dando programa y funciones SIG , CAL , T y f ) que cada una de las siguientes funciones es WHILE-calculable: - suma - resta ( x − y = 0 si x < y ) - valor absoluto de la resta ( x − y si x ≥ y , y − x si x < y ) - signo ( 0 si x = 0 , 1 si x > 0 ) - complementario del signo ( 0 si x > 0 , 1 si x = 0 ) - producto - función que siempre diverge - la función identidad de N en N - función constante Ckj : Nk→N , Ckj(x) = j ∀x∈Nk lenguaje WHILE ampliado • utilización de denominaciones libres para las variables de entrada y para la variable de salida (hay que especificar cuáles son de entrada y cuál es de salida) • permitiremos en el lenguaje ampliado incluir instrucciones de asignación cuyo miembro de la derecha implica la activación de otras funciones while-calculables (macroinstrucción) • inclusión de líneas de comentarios una función en WHILE ampliado es WHILE-calculable ejemplo de WHILE ampliado Ejemplo de “denominaciones libres” y de “comentario”: Entradas: dato Salida: doble (* = 2 × dato *) Código: doble := dato ; while dato ≠ 0 do doble := doble + 1 ; dato := dato – 1 od ejemplo de WHILE ampliado Ejemplo de “activación de funciones while-calculables”. Sea el programa doble = (1, 2, código) con código X2 := X1 ; while X2 ≠ 0 do X1 := X1 + 1 ; X2 := X2 – 1 od Sea el programa (macroprograma) exp = (1, 2, código) con código X2 := X2 + 1 ; while X1 ≠ 0 do X2 := doble( X2 ) ; X1 := X1 – 1 od ; X1 := X2 ← macroinstrucción ( exp calcula f(n)=2n ) conversión a WHILE: variables y comentarios • un programa con denominaciones libres para las variables se convierte en un programa WHILE haciendo las siguientes transformaciones: – reemplazar la primera variable de entrada por X1 , la segunda por X2 , …, la n-ésima por Xn – reemplazar la variable de salida por Xn+1 – reemplazar las variables de uso interno, según su orden de aparición por Xn+2 , … – añadir al final del código resultante la instrucción X1 := Xn+1 • los comentarios se eliminan sin efecto para el código ejemplo de conversión a WHILE Entradas: dato Salida: doble (* 2×dato *) Código: doble := dato ; while dato ≠ 0 do doble := doble + 1 ; dato := dato − 1 od (1, 2, código-doble) código-doble: X2 := X1 ; while X1 ≠ 0 do X2 := X2 + 1 ; X1 := X1 − 1 od ; X1 := X2 conversión a WHILE: macroinstrucciones • las macroinstrucciones se eliminan como sigue – sea la macroinstrucción Xi := f ( Xj1 , …, Xjn ) , donde f es calculada por el programa (n, p, código) – sea Q un macroprograma que usa q variables en el cual aparece la macroinstrucción anterior, la expansión PQ de la macroinstrucción en Q da lugar a: Xq+1 := Xj1 ; Xq+2 := Xj2 ; … Xq+n := Xjn ; Xq+n+1 := 0 ; Xq+n+2 := 0 ; … Xq+p := 0 ; “el código de P sustituyendo Xi por Xq+i , con 1 ≤ i ≤ p ” Xi := Xq+1 • cada macroinstrucción se expande independientemente ejemplo de conversión a WHILE exp = (1, 2, cod) cod: X2 := X2 + 1 ; while X1 ≠ 0 do X2 := doble( X2 ) ; X1 := X1 − 1 od ; X1 := X2 doble = (1, 2, cod) cod: X2 := X1 ; while X2 ≠ 0 do X1 := X1 + 1 ; X2 := X2 − 1 od exp = (1, 4, cod) cod: X2 := X2 + 1 ; while X1 ≠ 0 do X3 := X2 ; X4 := 0 ; X4 := X3 ; while X4 ≠ 0 do X3 := X3 + 1 ; X4 := X4 − 1 od ; X2 := X3 ; X1 := X1 − 1 od ; X1 := X2 lenguaje WHILE ampliado • Podemos combinar variables libres y macroinstrucciones Ejemplo: Entradas: x, y Salida: Código: prod (* = x × y *) while y ≠ 0 do prod := suma(prod, x) ; y := y – 1 od lenguaje WHILE ampliado • Para las macroinstrucciones relativas a funciones conocidas y con representación infija, estándar en matemáticas, usaremos dicha representación Así, las macros se escribirán z := suma(x,y) z := x + y z := resta(x,y) z := x − y z := producto(x,y) z := x × y z := exp(x) z := 2x • Permitiremos más de una función while-calculable en una macroinstrucción p.e.: z := x + ( x × (z - y)) ejemplos con WHILE ampliado Demostrar que las siguientes funciones son while-calculables: — — — — máximo ( max(x,y) ) diferencia en valor absoluto ( | x - y | ) igualdad ( igualdad(x,y) , o bien x=y ) (calcula 1 si son iguales, 0 si son distintos) potencia ( x y ) soluciones: — potencia: — max(x,y) := ( x – y ) + y Entradas: x, y — | x - y | := ( x – y ) + ( y - x ) Salida: — igualdad(x,y) := csg( | x - y | ) Código: ( csg ≡ complemento del signo) z z := z + 1 ; while y ≠ 0 do z := z × x ; y := y – 1 od composición de funciones sean f y g dos funciones de N en N , ambas while-calculables; la composición de ellas g°f también es una función while-calculable sea (1, pf, Q) el programa while que calcula f : N → N y (1, pg, R) el programa que calcula g: N → N, el siguiente macroprograma calcula g°f Entrada: x Salida: y Código: x := f(x) ; y := g(x) capacidad expresiva de WHILE: estructuras de control do x times S od if x ≠ 0 then S fi if x ≠ 0 then S else T fi z := x; while z ≠ 0 do S z := z − 1 od y := sg (x); do y times S od y := sg (x); z := csg(x); do y times S od do z times T od (* z es una nueva variable *) (* y es una nueva variable *) capacidad expresiva de WHILE: expresiones booleanas para cualquier condición booleana C existe una expresión EC tal que si la condición es verdadera toma el valor 1 y si es falsa toma el valor 0 C EC X=Y X>Y X<Y C1 ∨ C 2 C 1 ∧ C2 ¬C 1 − [(Y − X) + (X − Y)] (X − Y) − [(X − Y) − 1] (Y − X) − [(Y − X) − 1] sg(EC1 + EC2) (EC1 + EC2) − 1 1 − EC while C do S od z := EC ; while z ≠ 0 do S z := EC ; od capacidad expresiva de WHILE: expresiones con funciones siendo f y g funciones de N en N while-calculables y S , S1 y S2 códigos, permitiremos escribir instrucciones de la forma: instrucción expansión do f(x) times S od w := f(x); do w times S od while f(x) ≠ 0 do S od w := f(x); while w ≠ 0 do S; w := f(x) od if f(x) ≠ g(x) then S1 else S2 fi w := |f(x)–g(x)|; if w ≠ 0 then S1 else S2 fi if f(x) ≠ 0 then S fi w := f(x); if w ≠ 0 then S fi sintaxis del lenguaje LOOP identificadores X1 , X2 , X3 , ... , Xi , ... instrucciones de asignación Xi := Xj Xi := Xi + 1 Xi := Xi − 1 ( 0 − 1 = 0 ) Xi := 0 código secuencia finita no vacía de instrucciones separadas por ";" instrucción de control bucle definido: (cabecera) do Xi times código (cuerpo) od (cola) programa (n, p, código) p≥n ambos naturales Nota: el índice de anidamiento siempre es finito clase de funciones LOOP-calculables • Fn(LOOP) es el conjunto de las funciones f: Nn → N tales que existe un programa LOOP, con n variables de entrada, que calcula f • F(LOOP) es la unión de todas las Fn(LOOP) , para todo n ≥ 0 • si f∈F(LOOP) decimos que f es una función LOOP-calculable lenguajes LOOPi • para cada i ≥ 0 , se define el lenguaje LOOPi como el sublenguaje de LOOP formado por los programas que tiene nivel de anidamiento de bucles a lo sumo i • F(LOOPi) es la clase de funciones calculadas por programas LOOPi • si una función pertenece a una clase, entonces pertenece a todas las que están por encima de ella F(LOOP0) ⊂ F(LOOP1) ⊂ F(LOOP2) ⊂ … ⊂ F(LOOP) ¿cómo son los programas escritos en LOOP0 y las funciones de F(LOOP0) ?