Algoritmos 1 Ejemplo 1: el algoritmo Enigma

Anuncio
Algoritmos
Cualquiera en su vida ha encontrado e implementado, con distintos grados de éxito,
“procedimientos”, ya sea para llenar una forma, para armar algo o para cocinar. Y
cualquiera también sabe de algunas de las limitaciones con las que vienen acompañados: escrituras con términos o sintaxis incomprensibles, operaciones sugeridas imprecisas o irrealizables, obtención de un resultado diferente del esperado o el tiempo de
elaboración es exageradamente largo. Cuidarse contra esos infortunios es esencial: por
lo tanto es necesario fijar un marco para la expresión de tales procedimientos.
Sin intentar desarrollar una definición precisa de la palabra algoritmo, que deriva
del nombre del matemático Al Juarismi (Bagdad, siglo IX), nos conformaremos con ver
cuál es su uso o función: dentro de este marco, la funcion de un algoritmo es guiar un
procesador (un ejecutante) en la ejecución de un conjunto de acciones básicas.
El objetivo de este capítulo es presentar el modo de escritura de los algoritmos que
utilizaremos en lo que sigue, apoyándonos en un algunos ejemplos simples. Será también ocasión de introducir dos nociones básicas sobre algoritmos, la noción de invariante como auxiliar para la prueba de un algoritmo y la noción de algoritmo no determinista.
1 Ejemplo 1: el algoritmo Enigma
Empecemos con un enigma: ¿qué produce el algoritmo siguiente?
A partir de este primer algoritmo, precisaremos de abordar algunos elementos de la
terminología. Primero echaremos un ojo a la traza, ésto es una descripción de la ejecución del algoritmo para un conjunto datos dados, para finalmente resolver el enigma.
La notación ⌊x⌋ designa la parte entera del número x.
Algorithm 1: Enigma
Entrada: dos números naturales a y b
Resultado: ?
x ←− a
y ←− b
z ←− 0
mientras x 6= 0 hacer
si x es impar entonces z ←− z + y
x ←− ⌊x/2⌋
y ←− y × 2
regresa z
fin
1
En el contexto que usaremos aquí, una acción básica es la asignación, ordenadas por
la escritura:
h variable i ←− h expresión i
es decir que una asignación es de la forma del nombre de una variable seguida por el
símbolo ←−, seguida de la escritura de una expresión, como por ejemplo: z ←− z + y.
En el algoritmo Enigma, las asignaciones que intervienen son:
• 3 variables: x, y y z;
• 6 expresiones: a, b, 0, z + y ⌊x/2⌋ y y × 2.
Las expresiones son expresiones en el sentido algebraico del término, esto es, arreglos con respecto a las reglas de formación aplicadas a expresiones básicas que son las
constantes y las variables en el entorno de cómputo. La ejecución de una asignación es
un trabajo que se ejecuta en dos tiempos:
1. evaluar la expresión (llamada miembro derecho de la asignación) en función del valor
actual de las varaibles que han tenido una ocurrencia y aplicar las reglas de cálculo
“usuales”;
2. asignar a la variable dada (llamada miembro izquierdo de la asignación) el valor resultante de la evaluación precedente.
Por ejemplo, ejecutar la asignacion z ←− z + y si los valores de las variables
y y z son respectivamente seis y once, respectivamente, nos lleva a:
1. evaluar la expresión z + y (miembro derecho de la asignación), lo que
nos conduce al resultado de 17,
2. asignar este valor 17 a la variable z (miembro izquierdo de la asignación).
Si la asignación resultante z ←− z + 2y, la variable z tednrá el valor 29
después de la ejecución.
Otra acción básica es:
regresar h expresión i
dada por la palabra reservada regresar y donde la instrucción consiste en regresar el
resultado final de la evaluación de la expresión indicada después de esta palabra reservada. En nuestro ejemplo, el resultado del cálculo efectuado por el algoritmo es el valor
de la variable z cuando el programa termina (pensando por supuesto que termina).
El papel de las otras palabras reservadas (las palabras en negritas en el algoritmo)
utilizadas como en el ejemplo se comprende gracias a la noción de instrucción:
• una acción básica es una instrucción.
2
• si uno llama condición a toda expresión booleana, es decir, toda expresión donde
el resultado de la evaluación sea el valor verdadero, sea el valor falso entonces las
cuatro formas sintácticas siguientes son instrucciones:
1. si condición entonces instrucción
2. si condición entonces instrucción 1 sino instrucción 2
3. mientras condición hacer instrucción
4. instrucción 1; instrucción 2; ..., instrucción k sobre una misma línea
o
4. | instrucción 1
| instrucción 2
| ...
| instrucción k
Para fijar ideas, diremos que:
1. una instrucción de tipo 1 es una estructura condicional;
2. una instrucción de tipo 2 es una estructura alternativa;
3. una instrucción de tipo 3 es una estructura iterativa;
4. una instrucción de tipo 4 es una estructura secuencial
La ejecución de estas instrucción puede ser descrita con la ayuda de los diagramas:
Notemos que, por la definición de instrucción iterativa: “mientras C hacer I”, donde
C representa una condicion e I una instrucción llamada el cuerpo de la iteración, si el
valor regresado por la evaluación de C es falso, la ejecución de la iteración se termina, si
el valor es verdadero, la instrucción I se ejecuta y sera repetida hasta que la condición C
tome el valor de falso.
A priori, no sabemos si la iteración terminará ni el número de veces que la iteración
deberá ejecutarse.
Así, si k es un entero positivo cualquiera, definiremos la sucesión de Syracusa (un )
por u0 = k y un+1 = un /2 si un es par, (3un + 1)/2 si un es impar. No sabemos para
que valor de k la sucesión (un ) no tiene nunca un término igual a uno, pero tampoco
podemos demostrar que para todo valor de k, la sucesión (un ) tiene un término igual a
uno. En consecuencia, no sabemos si en las instrucciones u ←− k; mientras u 6= 1 hacer
si u es un número par entonces u ←− u div 2 sino u ←− (3u + 1) div 2“ la repetición
termina y, si es el caso, el número de veces que se repetirá la iteración.
Se sigue que dos casos extremos particulares pueden presentarse:
1. La ejecución repite la iteración sin cambiar el valor de la condición, como por
ejemplo con la instrucción: ”mientras x = x hacer x ←− x + 1“ y la ejecución
de la iteración genera la ejecución de un número infinito de acciones básicas. Tal
3
situación no es admisible y será conveniente probar que para todo algoritmo que
use iteraciones, que tal condición es imposible para el juego de datos declarados
válidos para el algoritmo.
2. La condición para la ejecución de la iteración siempre es falsa, como por ejemplo
con la instrucción ”mientras x 6= x hacer x ←− x + 1“. En otras palabras, la
instrucción I debe ”repetirse cero veces“, en cuyo caso diremos que la iteración
ha sido ejecutada y que esta ejecución se traduce en la forma de una acción nula
(la acción nula se invoca de forma similar cuando se ejecuta la condicional ”si C
entonces I“).
La lista de los cuatro tipos de instrucciones definidas arriba no es exhaustiva y los
lenguajes de programación usualmente los ofrecen con variantes y adiciones.
Notemos que la iteración de tipo por usualmente es usada (donde I es una instrucción cualquiera):
para i ←− 1 hasta n hacer I
que podemos considerar como equivalente a la secuencia:
y es conveniente usarlo
i ←− 1;
mientras i ≤ n hacer
I;
i ←− i + 1;
fin
siempre que conozcamos el número específico de iteraciones a realizar.
Más aún, podemos mostrar que las estructuras secuencial e iterativa mientras serán
por sí mismas suficientes para llevar a cabo todos nuestras cálculos, todos las otras instrucciones pueden reducirse a ellas 1 . Por ejemplo, la instrucción condicional ”si C
entonces I“ puede ser definidia con un atajo equivalente a escribir la siguiente secuencia, donde b es una variable boleana. y aparece como un elemento de comodidad para
expresar algoritmos y no como un tipo de instrucción que abra posibilidades nuevas de
cálculo en el modelo que sólo posee las secuencias y la iteración mientras.
Regresando al algoritmo Enigma, para dar una traza (figura ): se fijan valores numéricos para los datos del algoritmo, por ejemplo diez para a y trece para b, y se ejecutan
acción básica tras acción básica, escrupulosamente siguiente las instrucciones dadas por
el enunciaado del algoritmo. Notemos que el algoritmo requiere que el ejecutante sepa:
1
Sin embargo, se conocen algoritmos escritos según el modelo secuencia+iterativa mientras que no
pueden ser escritos según el modelo secuencia+iterativa para
4
b ←− C;
mientras b hacer
I;
i ←− falso;
fin
• sumar dos números;
• diferenciar los números pares de los impares;
• obtener la mitad de un número;
• doblar un número;
• comparar un número con cero.
x
10
y
?
13
0
z
?
?
0
5
26
26
2
52
1
104
130
0
208
instrucción o expresion evaluación
x ←− a
y ←− a
z ←− 0
x 6= 0
verdadero
x es impar
falso
x ←− ⌊x/2⌋
y ←− y × 2
x 6= 0
verdadero
x es impar
verdadero
z ←− z + y
x ←− ⌊x/2⌋
y ←− x × 2
x 6= 0
verdadero
x es impar
falso
1 ←− |x/2|
x ←− ytimes2
x 6= 0
verdadero
x es impar
verdadero
z ←− z + y
x ←− ⌊x/2⌋
y ←− y × 2
x 6= 0
falso
regresa z
130
5
Se deja al lector probar otras trazas. Algunos experimentos o la simple lectura del
algoritmo para lectores más sofisticados, permiten conjeturar que es para calcular el
producto de los números dados en la entrada, lo interesante aquí es hacerlo desde la
duplicación y la división por dos.
Podría ser conveniente, especialmente para usar en otros algoritmos,
ver el algoQ
ritmo como formado por un solo enunciado, que podríamos llamar (a, b) (preferentemente después de haber demostrado que ese algoritmo es ciertamente el producto de
a por b) y poder analizar la estructura. En efecto, estas instrucciones se descomponen
en una secuencia de cinco instrucciones (figura 3): tres asignaciones, una iteración y
una instrucción de regreso. Las tres primeras instrucciones y la última instrucción son
instrucciones elementales, es decir, que su ejecucion se traduce directamente por la ejecución de una acción básica. En contraste, la cuarta es una iteración cuyo cuerpo se
descompone en uuna secuencia de tres instrucciones donde la primera es una condicional que también se puede descomponer y donde las dos últimas son asinganciones,
que no son descomponibles.
Notemos para la memoria que este concepto de instrucciones que, a partir de los
años 60, se empezaba a hablar de programación estructura por oposicón al modo de programación anterio llamada programacion con ’goto’2
Pero una sola traza o mil trazas, no muestran que tenemos una técnica universal de
multiplicación (técnica sin utilización de tablas, será notado). Así, ¿cpomo podemos
probar que dados dos enteros naturales a y b, el resutlado del algoritmo es siempre su
producto ab? La prueba se hace en dos partes: primero mostraremos que la iteración
del algoritmo converge y, dando dos enteros positivos a y b, el resultado regresado por
el algoritmo es el producto ab.
• El algoritmo converge
Cuando el algoritmo incluye una o más iteraciones, debemos mostrar que cada
una converge, es decir, que para todas las entradas permitidas de datos, su ejecución termina en algún momento. Lo que siempre mostraremos para cada iteración
es una expresión que, tomando en cuenta la evolución de los valores de las variables que ocurren alguna vez, sólo pueden tomar un número finito de valores (una
expresiones puede ser reducida a una sola variable).
En nuestro ejemplo, en cada iteración, es decir, en cada ejecución del cuerpo de
la iteración, el valor de la variable x es modificada por la única asignación x ←−
⌊x/2⌋. Uno deduce que la sucesión de valores tomadas sucesivamente por la variable x es un sucesión de enteros, estrictamente decrecientes mientras no alcance el
0 y la ejecución de la iteración termia en cero. Como sólo existe un número finito
de valores entre cero y el valor inicial, la iteración converge.
2
Programación en la que el algoritmo se expresa como un secuencia de instrucciones ejecutadas en
secuencia, algunas instrucciones están identificadas por una etiqueta; la instrucción ”goto etiq“ permite
romper la secuencia de ejecución para hacer la instrucción marcada con la etiqueta etiq.
6
Nota. Analicemos qué pasa si, debido a un erro tipograico, la condición x 6= 0 se
escribe como y 6= 0. En este caso, ninguan ejecución del algoritmo para la cual
la entrada b es diferente de 0 terminará después de un número finito de acciones
básicas: el algoritmo que tenga este error no convergerá.
• Ahora mostraremos que el algoritmo Enigma calcula el producto ab de los números
a y b provistos en la entrada.
Propondremos una técnica, llamada demostración invariante, donde el objetivo es
estables los valores de ciertas variables escogidas son ligadas de manera especial
al final de la ejecución de la iterativa, habiendo probado que esta termina (de aquí
el requiisto de mostrar la convergencia de la iteración).
Siguiendo con el ejemplo del algoritmo Enigma, definamos la proposición:
z + xy = ab
(P )
1. La propiedad (P) se preserva por la iteración.
Lo que queremos decir es que si la propiedad (P) se satisface antes de la ejecución
de una iteración, se satisface después de la ejecución de la iteración.
Regresando a nuestro ejemplo y a la propiedad (P) definida arriba, supongamos
que en la ejecución de la iteración las tres variables x, y y z tienen valores asignados
de la última ejecución de la iteración y que la propiedad (P) se satisface, es decir,
z +xy = ab. En otras palabras, llamemos, respectivamente, α, β y γ a los valores de
esas tres variables obtenidas en la última ejecución de la iteración. Supongamos
que tenemos:
α 6= 0 y γ + αβ = ab.
Ahroa debemos verificar que la propiedad (P) se sigue satisfaciendo por las variables x, y y z después de la ejecución de la iteración, con los nuevos valores que
reciban: que es el cuerpo de la iteración.
si x es impar entonces z ←− z + y
x ←− ⌊x/2⌋
y ←− y × 2
La primera instrucción es una condicional cuya condición es ”x es impar“, analicemos qué casos son posibles:
(a) Primer caso: el valor α asignado a x es par, sea α = 2k.
7
La ejecución de la condicional conduce a no hacer nada. Las instrucciones
restantes asignan a x el valor k y la tercera y última instrucción de la iteración
asigna a y el valor 2β.
¿La propiedad (P) se sigue satisfaciendo? La respuesta está dada por la evaluación de la expresión z + xy calculada con los nuevos valores de x, y, z:
z + xy 7−→ γ + k(2β) = γ + (2k)β = γ + αβ = ab.
(b) Segundo caso: el valor de α asignado a x es impar, sea α = 2k + 1.
Ya que α es un entero impar, la ejecución de la condicional nos lleva a ejecutar
la asignación de z del resultado de la evaluación de la expresión z + y, a saber
el valor de γ + β.
La instrucción siguiente asinga a x el valor k y la tercera y última instrucción
de la iteración asigna a γ el valor 2β.
La evaluación de la expresión z + xy entonces da:
z + xy 7−→ (γ + β) + k(2β) = γ + (2k + 1)β = γ + αβ = ab.
De los dos casos la propiedad (P) se sigue satisfaciendo después de la ejecución de la iteración, de ahí que sea preservada por la iteración.
2. La propiedad (P) es estable antes de la iteración.
Queremos decir que las instrucciones que preceden la iterativa, que constituyen
la secuencia ”x ←− a; y ←− b; z ←− 0“ y que sirven para inicializar las variables, aseguran que la propiedad (P) se satisface cuando empieza la ejecución de
la iteración: se tiene: z + xy = ab.
3. Una aplicación del principio de inducción nos permite así concluir que en cada
iteración la propiedad (P) se satisface y que en particular, si la iteración converge,
su ejecución termina cuando satisface:
non(x 6= 0) y z + xy = ab
de donde concluimos que z = ab.
Nota. Si un desafortunado error tipográfico (¿otra vez?) nos lleva a escribir ”z ←− 10“
en vez de ”z ←− 0“ que está en la última instrucción que precede a la interacion, el
algoritmo convergerá, P será bien preservado por la iteración pero no nos será de mayor
interés, naturalmente.
Así, para establecer que una propiedad (Q) está establecida por la ejecución de una
iteración ”mientras C hacer I“, el pirncipio de demostración por invarientes que hemos
utilizado consiste en mostrar que:
• la iteración converge;
8
• una propiedad (P) es estable antes de la iteración;
• esta misma propiedad (P) es preservada por la iteración, es decir, que si uno ejecuta la instrucción I bajo la doble hipótesis C y (P), la propiedad (P) se sigue satisfaciendo después de esta ejecución;
• finalmente, (no C y (P)) ⇒ (Q).
Antes de terminar con este eejmplo, notemos que este algoritmo es similar al que
escribió el egipcio Ahmes describió en el papirus de Rhind (1650 a.C.) para multiplicar
dos números. Tal operación ha sido por largo tiempo preocupación de los adultos más
hábiles en el campo numérico. Hoy en día, poemos dar una versión elemental de primaria del método implementado por el algoirimto Enigma (que convendrá renombrar
como Algoritmo producto):
1. bajo el número a, construye una columna tal que cada número sea la mitad o la
mitad del piso del número que le precede; hasta parar en el valor uno.
2. bajo el número b, construye una columna tal que cada número sea el doble del que
le precede; uno construye esta columna tan larga como la primera;
3. construir una tercera columna de la forma siguiente: por cada línea, copiamos el
valor de la segunda columna cada vez que el contenido de la primera columna es
un número impar;
4. el resutlado de la multiplicación de a por b se obtiene al sumar los números de la
tercera columna.
9
Descargar