INTRODUCCIÓN A LA TEORÍA DE AUTÓMATAS Y LENGUAJES FORMALES Práctica 1 1. Introducción. 2. Listas. 2.1 Sintaxis. 2.2 Operaciones con listas. 2.3 Operadores lógicos y relacionales 3. Programación 3.1 Funciones simples 3.2 Programación procedural 3.2.1 Módulos 3.2.2 Estructuras condicionales y de repetición 4. Actividades 4.1 Actividades relacionadas con el manejo de Mathematica 4.2 Actividades relacionadas con la teoría de lenguajes formales 5. Soluciones a algunos ejercicios propuestos 1. Introducción. El lenguaje de programación escogido para las prácticas es Mathematica [Wolfram,91]. En las implementaciones que se van a llevar a cabo, hay que manejar objetos abstractos como son los autómatas y las gramáticas, sobre los que se realizarán una serie de transformaciones. Tanto unos como otras pueden ser concebidos como estructuras más complejas realizadas en base a otras más sencillas. El interés de las prácticas no estriba en conseguir implementaciones eficientes, sino en utilizar un lenguaje que facilite la construcción de estos objetos abstractos y el manejo de los mismos. Teniendo en cuenta todos estos aspectos, veamos a continuación algunas de las características de Mathematica que lo hacen adecuado para su uso en dichas prácticas. Mathematica es un paquete de desarrollo para aplicaciones de tipo general en las que los aspectos de desarrollo matemático, algebraico, numérico, simbólico y gráfico juegan un papel preponderante. Mathematica está diseñado para tratar tanto cálculos matemáticos, así como aquellos cálculos numéricos tradicionalmente llevados a cabo en FORTRAN. La mayoría de funciones especiales de la física matemática y funciones matriciales, ya están construidas en Mathematica. Además, tiene una extensa capacidad gráfica para la visualización de los resultados de los cálculos. La aplicaciones de Mathematica engloban prácticamente todas las áreas de investigación y desarrollo tanto en investigaciones científicas, de ingeniería, económicas, arquitectura, etc. Dentro de estas mismas áreas se pueden utilizar tanto como herramienta de trabajo como herramienta docente para aquellas materias que conlleven un alta carga de desarrollo matemático. Mathematica como lenguaje de programación se diferencia del FORTRAN o C o PASCAL, por una parte por su habilidad en el tratamiento de expresiones matemáticas, números, expresiones simbólicas, etc., y por otra en que es un lenguaje interpretado. Como consecuencia de ser interpretado, un cálculo tarda más tiempo en ejecutarse que en un lenguaje compilado, sin embargo, el escribir un programa en Mathematica requiere una fracción del tiempo necesario para escribir el mismo programa en C, y lo que es más importante, permite concentrar los esfuerzos en los detalles conceptuales y no en los de implementación. El sistema Mathematica es interactivo, lo cual significa que no hay que compilar programas. En lugar de eso, los cálculos se hacen típicamente ejecutando una línea cada vez, y por tanto, los resultados intermedios pueden verse inmediatamente. Mathematica es potente, puede usarse para realizar grandes cálculos interactivos, evitando los típicos errores algebraicos, y los resultados se pueden comprobar al instante. El lenguaje Mathematica es conciso, cálculos complicados pueden ser escritos en pocas líneas (aunque hay que controlar las limitaciones de memoria del ordenador usado). Es también flexible, pueden establecerse conexiones con otros programas ya existentes, etc.. Mathematica está siendo desarrollado por Wolfram Research, Inc. Actualmente está disponible en prácticamente todas las plataformas de ordenadores. Los códigos se pueden transportar en ficheros ASCII o en ficheros Mathematica Notebook, si se trabaja con versiones compatibles. En esta primera práctica se pretende introducir algunos conceptos elementales del lenguaje asociado a la aplicación Mathematica, así como el desarrollo de aplicaciones relacionadas con palabras y lenguajes empleando esta herramienta. 2. Listas. Quizá la estructura de datos más importante en Mathematica (y, sin duda la que nosotros emplearemos más) es la lista. Se pueden emplear listas tanto para las palabras de los lenguajes con los que trabajemos, como para las transiciones de los autómatas que reconozcan dichos lenguajes. 2.1. Sintaxis list1 = {a, b, {c, d}} asigna a la variable "list1" la lista con primer elemento "a", segundo "b" y tercero la lista {c, d}". El elemento i-ésimo de una lista se referencia como nombre[[i]]. Así, list1[[3]] es {c, d}. 2.2. Operaciones con listas Notas: l Las mayoría de las operaciones no actualizan las listas a menos que se asignen a una variable. l Mathematica es sensible a las mayúsculas. No es lo mismo Table que table. En lo sucesivo, l1, l2... designarán listas, x, y... designarán elementos o variables, mientras que m, n... designarán enteros positivos. l Las funciones definidas a continuación admiten variantes no especificadas aquí para no hacer demasiado larga esta exposición. Solo se indica alguno de los usos más frecuentes. Para conocer todas las posibilidades se puede teclear ?Nombre. Sintaxis Table[f(x), {x,n}] Range[m] Length[ l1] Position[l1,x] Join [l1, l2] Union[l1, l2] Intersection[l1, l2] Complement[l1, l2] Sort[l1] Reverse[l1] RotateRight[l1] RotateLeft[l1] First[l1] Rest[l1] Drop[l1, n] Take[l1, n] Append[l1, x] Prepend[l1, x] AppendTo[l1, x], PrependTo[l1, x] Delete[l1,n] Select[l1, condición] l1 /. izq -> dcha Significado Devuelve la lista {f(1), f(2)...f(n)} Devuelve una lista con los m primeros números naturales. Devuelve la longitud de la lista. Devuelve una lista con las posiciones de x en l1. (¡cuidado !) Concatena dos listas. Devuelve una lista con los elementos que se encuentran en l1 o l2 y los ordena. Devuelve una lista con los elementos que se encuentran en l1 y l2 Lista con los elementos de l1 que no estan en l2. Devuelve l1 ordenada de menor a mayor (no actualiza l1). Devuelve el reverso de l1. Devuelve l1 con los elementos desplazados un lugar a la derecha (el último pasa a ser el primero). Idéntico al anterior pero desplazando hacia la izquierda Devuelve el primer elemento de la lista. Lista l1 sin el primer elemento. Devuelve la lista sin los primeros n elementos. Devuelve los primeros n elementos de la lista. Añade el elemento x al final. Añade el elemento x al comienzo. Idénticas a las anteriores pero actualizan la lista. Elimina el elemento n-ésimo de la lista. Lista con los elementos de l1 que cumplen condición. Sustituye en l1 los elementos que se llaman izq por dcha). Pueden ser de utilidad las siguientes funciones de Mathematica: Cases[lista, patrón]: Devuelve una lista con los elementos de lista que concuerdan con patrón. Ejemplo 3 lista={{a,a},{b,a},{b,b},{a,b}} Cases[lista,{a,_} ] {{a,a},{a,b}}. 2.3. Operadores lógicos y relacionales Son operadores que dan como resultado True o False: Operación Negación Conjunción Disyunción Igualdad No igualdad Operador ! && || == =!= Además están los conocidos: >, <, >=, <=. MemberQ[l1,x] : Devuelve True si x pertenece a l1 y False si no. 3.- Programación Mathematica lleva incorporado un lenguaje de programaci ón propio que permite incorporar funciones para realizar tareas específicas al mismo nivel que las funciones predefinidas. Al ser un intérprete, el modo de trabajo puede ser totalmente interactivo; Así si ejecutamos la expresión For[i = 1, i < 10, i++, Print[i]] se escriben en pantalla los dígitos del 1 al 9 (se ha introducido la sentencia For cuya sintaxis es totalmente idéntica a la que tiene en C). 3.1.- Funciones simples La forma mas sencilla de definir una función es n_función[var_]:=valor. Ejemplos: f[x_]:=x^2. A partir de este momento, si se teclea f[n], Mathematica devuelve el valor n2 . g[x_,y_]:=2x + y (función de dos variables). valab[x_]:=If[ x > 0, x, -x]; (se ha definido el valor absoluto de un número. Esta función lo es a todos los efectos, se puede dibujar con Plot[valab[x], {x,-3,3}]. De paso se ha introducido la función If, cuya sintaxis es If[condición, verdad, falso]). kron[x_,y_]:= If[x==y, 1, 0]; (delta de Kronecker). 3.2.-Programación procedural 3.2.1.-Módulos El concepto de módulo es totalmente parecido al de procedure en Pascal. Su esquema genérico es : nombre[parámetros] : = Module [{variables locales separadas por comas}, Acciones (separadas por ;); Return[nvar] (si el módulo devuelve un valor) ] Ejemplo Módulo que toma como entrada un número positivo n y devuelve la suma de los n primeros números enteros. suma[n_Integer]:=Module[{i,suma1}, suma1=0; For[i =1,i <= n,i++,suma1 = suma1 + i]; Return[suma1]; ] Para ejecutarlo se escribiría por ejemplo suma[3] (que dar á como resultado 6). 3.2.2.- Estructuras condicionales y de repetición Condicional Sintaxis If[condición, sent_verdad, sent_falso] Estructuras de repetición Sintaxis Do[sentencias, {var,com,fin}] Se ejecuta repetidamente sentencias desde var = com hasta var = fin. Por defecto el incremento de la variable es 1. Se puede utilizar alternativamente{var, com, fin, paso} Sintaxis For[comienzo, test, incremento, sentencias] Se evalúa comienzo y se ejecutan sentencias e incremento hasta que test falla. Sintaxis While[condición, sentencias] Se ejecuta sentencias mientras condición es cierta. 4.- Actividades 4.1.- Actividades relacionadas con el manejo de Mathematica Listas Para trabajar con listas es cómodo disponer de una función que las genere autom áticamente. Haremos uso de las funciones Random[ ] y Table[ ]. Random[Integer,{imin,imax}] devuelve un número entero pseudoaleatorio comprendido entre los enteros imin e imax. Ejemplo: Random[Integer,{0,9}] devuelve un dígito. l = Table[ Random[Integer,{imin,imax}],{n}] devuelve una lista de n números y los asigna a la variable l. Si no se desea ver la lista por pantalla hay que terminar la expresión con ";". Bucles simples Ejercicio Simulación de la función Length La expresión Length[l], donde l es una lista, devuelve la longitud de l. Se pide, sin el uso de la función Length, un fragmento de programa iterativo que simule dicha función. Ayudas: l l l La lista vacía se representa mediante {}. l = Rest[l] asigna a la variable l (que es una lista) la lista l sin el primer elemento. Se recuerda la estructura repetitiva While[condición,expresiones]. Hay que tener cuidado en no entrar en un bucle sin fin. En caso de hacerlo, Alt + "." aborta la ejecución. Nota: Las palabras de un lenguaje se representarán mediante listas, por lo que el fragmento anterior puede servir para calcular la longitud de una palabra de forma iterativa. La definición recursiva (ver libro de apuntes, página 7) se puede transcribir casi literalmente con el siguiente programa recursivo: long[{}]:=0; long[l_]:=1+long[Rest[l]]; Una vez ejecutado este fragmento, ejecútese por ejemplo long[{a,b,a,a}]. Ejercicio Escriba un fragmento de programa que suprima los elementos repetidos de una lista dejando el primero de cada uno de ellos. Ejercicio Escriba un fragmento de programa que, dados una lista y dos enteros i y j, devuelva la lista con los elementos de las posiciones i y j intercambiados. Bucles anidados Ejecute el siguiente programa y estúdielo detenidamente: For[i=1, i<=4, i++, Print["i___: ", i]; For[j=i+1, j<=5, j++, Print["j : ", j] ] ] Módulos. Por defecto, todas las variables definidas en Mathematica son globales. Para evitar interferencias y para generalizar las funciones que se definen se emplean los módulos. Por ejemplo, el programa escrito como ejemplo de bucles anidados se puede introducir en un módulo de la siguiente manera: imprime[m_Integer]:=Module [{i,j}, For[i=1, i<=m-1, i++, Print["i___: ", i]; For[j=i+1, j<=m, j++, Print["j : ", j] ] (*del For j*) ] (*del For i*) ] (*del módulo*) Una vez ejecutado el módulo anterior, la función "imprime" está disponible en la sesión de Mathematica. Ejecute por ejemplo imprime[5] . Ejercicio Escríbanse módulos para todos los fragmentos realizados anteriormente. 4.2. - Actividades relacionadas con la teoría de lenguajes formales En lo que sigue, una palabra se representa como una una lista de símbolos sobre un determinado alfabeto. Así la palabra x=abbaca, se representará como {a,b,b,a,c,a}; la palabra vacía se representa como la lista de longitud 0, es decir, {}. Un lenguaje finito es un conjunto finito de palabras. Por tanto, un lenguaje se representa como una lista cuyos elementos (palabras) son listas. Por ejemplo, el lenguaje L={abba, bb }, se representará como {{a,b,b,a},{b,b}}; el lenguaje vacío se representa como {}. Escribid módulos Mathematica que realicen los siguientes cálculos Ejercicio 1 Con entrada una palabra x y un símbolo a, calcular |x|a (número de ocurrencias de a en x). Ejercicio 2 Con entrada una palabra x y un entero positivo n, obtenga xn . Ejercicio 3 Conjunto de prefijos de una palabra x. Ejercicio 4 Conjunto de segmentos de una palabra x. Ejercicio 5 Conjunto de segmentos de longitud k (k>0) de una palabra x. Ejercicio 6 Producto de lenguajes finitos. Ejercicio 7 Con entrada un lenguaje finito L y un entero n>0 calcular Ln . Ejercicio 8 Palabras de longitud n sobre un alfabeto de entrada .(una manera posible consiste en usar la solución a 6), Ejercicio 9 Desarrollar una función que, dados un alfabeto de entrada y un número n, obtenga todas las palabras de longitud menor o igual que n sobre ese alfabeto. Ejercicio 10 Modificar el programa anterior obtenido a partir de la solución a 9 para obtener solamente las palabras de longitud n. Puede ser una forma alternativa de resolver 8. Ejercicio 11 Palabras de longitud n sobre un alfabeto que son palíndromos. Ejercicio 12 Con entrada una palabra x, y un homomorfismo h, calcular h(x). Si, por ejemplo, se tiene un homomorfismo h(a)=010, h(b)= λ , h se puede representar por una lista halfa={{a,{0,1,0}},{b,{}}} Ejercicio 13 Con entrada una palabra x, y una sustitución finita σ , calcular σ (x). Si, por ejemplo, se tiene una sustitución, σ (a)={010,11}, σ (b)= {λ ,110,0} σ se puede representar por una lista salfa={{a,{{0,1,0},{1,1}}},{b,{{},{1,1,0},{0}}}}. Ejercicio 14 Dado un alfabeto Σ en el que se asume un orden en los símbolos y una palabra x sobre dicho alfabeto, calcular la siguiente palabra en orden lexicográfico. Ejercicio 15 Función que con entrada una palabra x, calcule f(x) definido como sigue: Si |x|<2, f(x)=x Si no, si x=aby, f(x)=af(y)b 5.- Soluciones a algunos ejercicios propuestos Solución al ejercicio 1 frec[pal_,sim_]:=Length[Position[pal,sim]] Solución al ejercicio 4 seg[pal_]:=Module[{l,i,j,w}, l={{}}; For[i=1,i<=Length[pal],i++, For[j=i,j<=Length[pal],j++, w=Take[pal,{i,j}]; l=Union[Append[l,w]] ] ]; Return[l] ] Solución al ejercicio 9 Lo que se presenta no es un programa. A partir de este algoritmo, el alumno, mediante un traducción casi literal a Mathematica, podrá obtener un programa. Módulo_listar[n :Entero, Alfabeto :lista] listado = {cadena_vacia}; auxiliar = {cadena_vacia}; Para i=1 hasta n hacer auxiliar2 = ∅; Para j = 1 hasta Longitud de auxiliar hacer Para k = 1 hasta Longitud de Alfabeto hacer nuevapal = prolongar la palabra j de auxiliar con el símbolo k del Alfabeto ; auxiliar2 = Añadir a auxiliar2 la palabra nuevapal; listado = Añadir a listado la palabra nuevapal ; FinPara FinPara auxiliar = auxiliar2 ; FinPara Resultado : listado Fin Módulo Solución al ejercicio 12 (w es la palabra e imag el homomorfismo): h[w_,imag_]:=Module[{hw,i,l}, hw=w; For[i=1,i<=Length[w],i++, l=Cases[imag,{w[[i]],_}]; hw[[i]]=l[[1,2]] ]; hw=Flatten[hw]; Return[hw] ] Bibliografía [Wolfram,91]. S. Wolfram. Mathematica : A System for doing mathematica by computer. Addison Wesley, 1991.