Pontificia Universidad Católica de Chile Escuela de Ingenierı́a Departamento de Ciencia de la Computación Tarea 1 Programas que programan IIC2622 – Taller de Inteligencia Artificial Primer Semestre, 2004 Fecha de Entrega: 31 de marzo. Objetivo En esta tarea usted deberá experimentar con la técnica de programación genética para programación de computadores y autómatas celulares. LFS: Un lenguaje funcional sencillo El elemento principal en un lenguaje funcional es la función. Una función puede recibir 0 o más parámetros y siempre retorna una expresión. A diferencia de los lenguajes imperativos, una función en un lenguaje funcional siempre retorna el mismo valor cuando recibe los mismos parámetros (esto se debe, entre otras razones, a que no existen variables globales). Una caracterı́stica de los lenguajes funcionales es que todas las expresiones del lenguaje se pueden evaluar matemáticamente. En LFS, todas las expresiones del lenguaje retornan números enteros (y por lo tanto, todas las funciones retornan números enteros). Para ocupar el n-ésimo parámetro, se utiliza la expresión paramn . Para definir la semántica de las expresiones, usaremos la función Vβ J·K, que dada una expresión, retorna el entero al que corresponde. El subı́ndice β es una función que sirve para obtener los valores tienen los parámetros de la función. Vβ JeK = e si e es número entero. Vβ Jparami K = β(i) (1 ≤ i ≤ n). Vβ J(? e1 e2)K = Vβ Je1K ? Vβ Je2K, donde ? ∈ {+, −, ∗, /}. ( Vβ Je2K si Vβ Je1K 6= 0 Vβ J(if e1 e2 e3)K = Vβ Je3K en otro caso ( 1 si Vβ Je1K ? Vβ Je2K Vβ J(? e1 e2)K = con ? ∈ {>, ≥, <, ≤, =}. 0 en otro caso ( 0 si Vβ Je1K = 0 o Vβ Je2K = 0 Vβ J(and e1 e2)K = 1 en otro caso ( 0 si Vβ Je1K = 0 y Vβ Je2K = 0 Vβ J(or e1 e2)K = 1 en otro caso ( 1 si Vβ JeK = 0 Vβ J(not e1)K = 0 en otro caso Vβ J(g e1 e2 . . . en )K = Vγ Jexpg K, si g es una función y expg es la expresión que la define y γ es tal que γ(i) = Vβ Jei K. Si f es una función matemática que está implementada por una función LSF f y p1 , . . . , pn son enteros, entonces para calcular el valor f (p1 , . . . , pn ) basta con computar Vβ J(f p1 p2 · · · pn )K, con β una función arbitraria. Pn A manera de ejemplo, para calcular f (n) = i=0 i2 , se puede definir la función f en LSF de la siguiente manera: (if (= param1 0) 0 (+ (* param1 param1) (f (- n 1)))) Autómatas Celulares Un autómata celular (AC) es una máquina discreta que puede realizar cierto tipo de cómputos. Un autómata celular unidimensional (ACU) está compuesto por una “grilla” unidimensional de n celdas (o células). Cada celda puede estar en un estado tomado de un conjunto finito de estados. Además, cada celda tiene un conjunto finito de celdas vecinas, definidas a través de una relación de vecindad uniforme (es decir, la vecindad es la misma para todas las celdas). Normalmente, la vecindad de una celda incluye a la misma celda. El cambio en los estados de las celdas se define a través de una función de transición discreta y temporal, que indica cuál será el estado de una celda en el instante t + 1 basada en los estados de sus vecinas y de ella misma en el tiempo t. La función es la misma para todas las celdas. La siguiente es una representación gráfica de un ACU de n celdas en el espacio y en el tiempo. Espacio Tiempo ct (1) ... ct (i − 2) ct (i − 1) ct (i) ... ct+1 (i) ct (i + 1) ct (i + 2) ... ct (n) ... El siguiente es un ejemplo de una función de transición de radio 1 (se le llama de radio 1 porque las vecinas de la celda i son las que están a distancia 1 de ella)1 . ( 1 si 1 ≤ ct (i − 1) + ct (i) + ct (i + 1) ≤ 2 ct+1 (i) = (1) 0 en otro caso A pesar de lo simple que son las funciones de transición, los ACUs pueden generar comportamientos bastante complejos. Por ejemplo, en la siguiente figura se muestra cómo a partir de una configuración inicial muy simple, se obtiene un comportamiento que podrı́amos considerar como bastante complejo usando la función definida arriba2 : 1 Normalmente se acostumbra a considerar que la vecina izquierda de la primera celda es la última celda, y que la vecina derecha de la última celda es la primera. 2 Las celdas blancas representan un 0 y las negras un 1 ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... Es interesante notar que una función de transición se puede escribir directamente en LSF. Por ejemplo, la ecuación (1) se puede computar por una función definida por la expresión: (if (and (>= (+ (+ param1 param2) param3) 1) (<= (+ (+ param1 param2) param3) 2)) 1 0) donde param1, param2 y param3 corresponden a los estados de las celdas i − 1, i e i + 1, respectivamente. Parte 1: Aprendiendo funciones conocidas y desconocidas En esta parte usted deberá construir un programa que, usando la técnica de programación genética, pueda sintetizar programas en LSF para: 1. Calcular la serie de números de Fibonacci. 2. Generar una función recursiva que genere las salidas en el archivo desconocida.csv, publicado en la página web del curso Oportunidades de bonus: Probar con funciones que contengan partes crecientes y partes decrecientes. Probar con funciones más complejas como bsinh(x)c. Probar todo lo anterior usando más de una función (o funciones auxiliares). Por ejemplo, f calcula una función de interés y en su código puede llamar a g y a f . Por otro lado, se puede imponer que la función auxiliar g puede ser recursiva, pero que no llame a f . Parte 2: Descubriendo cómo programar un ACU En esta parte se pide que, usando programación genética, usted descubra una función de transición de radio 2 para un ACU de 51 celdas que resuelve el problema de clasificación. En este problema, el ACU inicialmente contiene celdas que pueden estar en dos estados 0 o 1. La función de transición debe ser tal que, se converja a una situación en la que todas las celdas están en estado 0 si habı́a en el estado inicial mayorı́a de 0’s, y que converja a un estado sólo con 1’s en caso contrario. Antecedentes adicionales: Las mejores funciones de transición escritas por humanos para el problema de clasificación, lo resuelven con una precisión sólo del 82,1 %. En 1996, el inventor de la programación genética, John Koza, sintetizó una regla con una precisión del 82.326 %. ¿Podrá usted encontrar una mejor? Puede encontrar más detalles en el artı́culo publicado en el sitio web del curso. La tarea se podrá realizar en grupos de hasta 2 personas