UNIVERSIDAD AUTONOMA METROPOLITANA

Anuncio
UNIVERSIDAD AUTONOMA METROPOLITANA
UNIDAD IZTAPALAPA
División de Ciencias Básicas e Ingeniería
Departamento de Ingeniería Eléctrica
Licenciatura en Computación
“Alternativa Para la solución del problema de clasificación por medio de un Programa Evolutivo”
Trimestre 03-I
Alumno: Fernández trejo Oscar
Mat: 96320368
Asesor
---------------------------------------------Dra Graciela Roman Alonso
Prof. Titular tiempo completo
Núm. Emp. 17161
Lugar de realización: Laboratorio T-169 de la propia unidad
Periodo de Realización: 18/09/2002-10/04/2003
Asesor
----------------------------------------------MC. Alma Martinez Licona
Prof. Titular tiempo completo
Núm. Emp. 20901
Indice
Objetivos…………………………………………………………………………………………………….. 2
Introducción…................................................................................................................................................. 2
Conceptos y mecanismos de base…………………………………………………………………………… 4
Redes Neuronales artificiales…………………………………………………………….. ………..4
Redes Neuronales de tipo biológico……………………………………………………… 5
Funciones de base y activación…………………………………………………. 5
Redes Neuronales para aplicaciones concretas…………………………………………... 6
Estructura de las redes neuronales……………………………………………………….. 7
Tamaño de las redes neuronales………………………………………………… 7
Aproximaciones ACON frente a OCON……………………………………….. 7
Asociación y Clasificación……………………………………………………………….. 9
Optimización………………………………………………………………………..……. 10
Red Neuronal Backpropagation…………………………………………………..……… 10
Algoritmos Genéticos……………………………………………………………………………… 11
Extensiones y modificaciones del Algoritmos Genético Simple………………………… 12
Función Objetivo………………………………………………………………………… 12
Algoritmos Evolutivos…………………………………………………………………… 13
Estructura de datos que representa a un perceptron multicapa……………………………14
La Población……………………………………………………………………………… 14
Función de Evaluación…………………………………………………………………… 14
Algoritmos Genéticos Paralelos…………………………………………………………………… 16
PVM……………………………………………………………………………………………….. 17
Metodología………………………………………………………………………………………………… 18
Esquemas de Apoyo………………………………………………………………………………. 18
Bases de Datos…………………………………………………………………………………….. 18
Acerca de PVM……………………………………………………………………………………. 19
Definición de variables…………………………………………………………………………….. 20
Versión Central…………………………………………………………………………………….. 22
Mejoramiento de Algoritmo Evolutivo………………………………………………………………………23
Criterios de Reemplazo………………………………………………………………………………………24
Conclusiones………………………………………………………………………………………………… 24
Bibliografía………………………………………………………………………………………………….. 26
Anexo A (Bases de Datos)…………………………………………………………………………………...28
Anexo B (Codigo Fuente)……………………………………………………………………………………47
2
OBJETIVO
Encontrar la alternativa para la solución del problema de clasificación mediante un programa
evolutivo, basándonos en la arquitectura de una red neuronal para problemas de clasificación usando envio de
mensajes como medio de comunicación entre los procesos.
INTRODUCCIÓN
El problema de clasificación agrupa conjuntos de objetos de acuerdo a sus características, si dichas
características son comunes el conjunto de objetos forman una clase. Un ejemplo claro de esto es el
diagnostico medico, en donde el objeto a analizar seria cada una de las enfermedades (clases) y sus atributos
son las características que las definen como los rangos de temperatura, los rangos de presión, niveles de
azúcar, etc. Este problema se encuentra en diferentes áreas (botánica, reconocimiento automático del habla,
etc.) con grandes volúmenes de datos a manejar, lo cual hace imposible su clasificación de forma manual, es
por eso que se han diseñado métodos y herramientas para apoyar el proceso de clasificación buscando que
este se haga de forma automática.
Una alternativa para la solución a este problema es el uso de redes neuronales (perceptron), sin embargo
la definición de la red neuronal es otro problema. Solucionando este aspecto se soluciona el problema de
clasificación. Existen varias alternativas para la definición de una red neuronal perceptron, una de ellas es por
medio de la programación evolutiva, la idea del programa evolutivo es definir una población de cromosomas
en donde cada cromosoma represente una red neuronal perceptron.
El objetivo principal de este proyecto es la paralelización de un programa evolutivo que define la
arquitectura de una red neuronal para problemas de clasificación. Actualmente se cuenta con una versión
funcional del algoritmo en Lenguaje C++ que se ha probado con bases de datos relativamente pequeñas para
las cuales el tiempo de ejecución es razonablemente corto. La naturaleza secuencial (ejecución en un solo
procesador) del algoritmo, impone ciertas limitaciones en cuanto al tamaño de las bases de datos a tratar, el
número de nodos ocultos, el tamaño de la población y el número de generaciones del algoritmo evolutivo.
Una de las posibilidades para solventar estas limitaciones es la utilización del paralelismo, es decir, la
construcción de un programa que explote una arquitectura paralela para resolver el mismo problema en un
menor tiempo.
En este reporte se inicia con un acercamiento teórico a las redes neuronales, algoritmos genéticos y a los
algoritmos genéticos paralelos.
Después se procede a describir la metodología utilizada para implementar los distintos esquemas de
algoritmos evolutivos paralelos propuestos. Se finaliza presentando los resultados obtenidos al ejecutar las
tres versiones existentes con sus distintos esquemas comparándolos con el algoritmo centralizado y la
versión mejorada. De igual manera se presentan los objetivos, metas alcanzadas, y conclusiones.
La red neuronal que se trabajó en paralelo es una red utilizada para la clasificación de
patrones. Los patrones son presentados en una base de datos donde cada patrón tiene un número determinado
de propiedades y una de ellas (pueden ser varios valores) indica(n) a que grupo de patrones pertenece. Lo red
neuronal recibe una base de datos de este tipo dividido en dos partes, primero un 70% del total para (base de
datos de entrenamiento) y después una base mas pequeña con patrones del mismo tipo (el 30% restante) para
ver que tan bien es capaz de seleccionar correctamente o que grupo pertenece cada patrón (base de datos de
prueba).
En un principio se utilizaron como base tres versiones utilizando la consola de PVM cada una
de los cuales se explicara brevemente mas adelante. PVM es un paquete de software para crear aplicaciones
en paralelo y se baso en el modelo de paso de mensajes. Los programas de aplicación son escritos en C y para
tener acceso a PVM se hacen llamadas a rutinas de la biblioteca "pvm3.h" lo cual contiene funciones para
lanzamiento, transmisión y recepción de mensajes, y algo muy importante, la sincronización. En la consola
de PVM un usuario define una colección de computadoras con un solo procesador para simular una gran
memoria distribuida; proporciona las funciones para iniciar tareas en una máquina virtual y permite a éstos
sincronizarse y comunicarse.
El sistema PVM está compuesto por dos partes, la primera parte del sistema la conforma un
demonio (procesos que siempre están ejecutándose) llamado pvmd3. La segunda parte del paquete PVM son
las librerías de rutina de interfaz y son alrededor de 20 rutinas de interfaz.
3
CONCEPTOS Y MECANISMOS DE BASE REDES NEURONALES ARTIFICIALES
Las Redes Neuronales Artificiales (ANN's de Artificial Neural Networks) fueron originalmente una
simulación abstracta de los sistemas nerviosos biológicos, formados por un conjunto de unidades llamadas
"neuronas" o "nodos" conectadas unas con otras. Estas conexiones tienen una gran semejanza con las
dendritas y los axones en los sistemas nerviosos biológicos.
El primer modelo de red neuronal fue propuesto en 1943 por McCulloch y Pitts en términos de un
modelo computacional de "actividad nerviosa". El modelo de McCulloch-Pitts es un modelo binario, y cada
neurona tiene un escalón o umbral prefijado. Este primer modelo sirvió de ejemplo para los modelos
posteriores de Jhon Von Neumann. Marvin Minsky, Frank Rosenblatt, y muchos otros. Una primera
clasificación de los modelos de ANN's podría ser:
1. Los modelos de tipo biológico. Este comprende las redes que tratan de simular los sistemas neuronales
biológicos así como las funciones auditivas o algunas funciones básicas de la visión.
2. EI modelo dirigido a aplicación. Estos modelos no tienen porque guardar similitud con los sistemas
biológicos. Sus arquitecturas están fuertemente ligadas a las necesidades de las aplicaciones para las que son
diseñados.
Redes Neuronales de tipo Biológico
Se estima que el cerebro humano contiene más de cien mil millones de neuronas y sinapsis en el sistema
nervioso humano. Estudios sobre la anatomía del cerebro humano concluyen que hay más de 1000 sinapsis a
la entrada y a la salida de cada neurona. Es importante notar que aunque el tiempo de conmutación de la
neurona (unos pocos milisegundos) es casi un millón de veces menor que en los actuales elementos de las
computadoras, ellas tienen una conectividad miles de veces superior que las actuales supercomputadoras.
El objetivo principal de las redes neuronales de tipo biológico es desarrollar un elemento sintético para
verificar las hipótesis que conciernen a los sistemas biológicos.
Las neuronas y las conexiones entre ellas (sinapsis) constituyen la clave para el procesado de la
información. Observe la figura:
Red neuronal de tipo biológico.
La mayor parte de las neuronas poseen una estructura de árbol llamadas dendritas que reciben las señales
de entrada que vienen de otras neuronas a través de las uniones llamadas sinapsis. Algunas neuronas se
comunican solo con las cercanas, mientras que otras se conectan con miles.
Hay tres partes en una neurona:
1 .el cuerpo de la neurona,
2. ramas de extensión llamadas dendritas para recibir las entradas
3. un axón que lleva la salida de la neurona a las dendritas de otras neuronas.
La forma que dos neuronas interactúan no está totalmente conocida, dependiendo además de cada
neurona. En general, una neurona envía su salida a otras por su axón. El axón lleva la información por medio
4
de diferencias de potencial, u ondas de corriente, que depende del potencial de la neurona. Este proceso es a
menudo modelado como una regla de propagación representada por la función de red u(.).La neurona recoge
las señales por su sinapsis sumando todas las influencias excitadoras e inhibidoras. Si las influencias
excitadoras positivas dominan, entonces la neurona da una señal positiva y manda este mensaje a otras
neuronas por sus sinapsis de salida. En este sentido la neurona puede ser modelada como una simple función
escalón f(.). Como se muestra en la próxima figura, la neurona se activa si la fuerza combinada de la señal de
entrada es superior a un cierto nivel, en el caso general el valor de activación de la neurona viene dado por
una función de activación f(.).
Funciones de Base y Activación
Una red neuronal típica se puede caracterizar por las descripciones funcionales de la red de
conexión y la red de activación. Cada célula (unidad de proceso), suministra un valor a1 a su salida. Este
valor se propaga a través de la red de conexiones unidireccionales hacia otras células de la red.
Asociada a cada conexión hay un peso sináptico Wij, que determina el efecto de la célula j-ésima
sobre la célula i-ésima. Las entradas a la célula i-ésima que provienen de las otras células son acumuladas
junto con el umbral extemo Фi, para dar el valor de red Ui. La forma de hacerlo lo determina
matemáticamente la función de base f para dar un valor de activación a¡. La salida final y se puede expresar
como una función de la entrada y los pesos y=Ф (x,W).
Función de Base (Función de Red)
Para un estudio analítico, las redes de conexión son matemáticamente representadas por la función de base u
(w, x), donde w es la matriz de pesos, y x el vector de entrada. La función de base tiene dos formas típicas:
- Función Lineal de Base (LBF) es una función de tipo hiperplano. Esto es, una función de primer orden. El
valor de red es una combinación lineal de las entradas,
- Función de base Radial (RBF) es una función de tipo hiperesférico. Esto implica una función de base de
segundo orden no lineal. El valor de red representa la distancia a un determinado patrón de referencia,
La función de segundo orden se puede extender a otra más general llamada función de base elíptica.
Función de Activación (Función de neurona)
El valor de red, expresado por la función de base, u(w,x), será inmediatamente transformada por una función
de activación no lineal. Por ejemplo, las funciones de activación más comunes son la función paso, rampa o
sigmoidal y gausiana. En particular,
• Función sigmoidal
• Función gausiana
5
Redes Neuronales para aplicaciones concretas
Las ANN's dirigidas a aplicación están en general poco ligadas a las redes neuronales
biológicas. Ya que el conocimiento que se posee sobre el sistema nervioso en general no es completo, se han
de definir otras funcionalidades y estructuras de conexión distintas a las vistas desde la perspectiva biológica.
Las características principales de este tipo de ANN's son los siguientes:
1 .Auto-Organización y Adaptatividad: Utilizan algoritmos de aprendizaje adaptativo y auto organización, por lo que ofrecen posibilidades de procesado robusto y adaptativo (véase entrenamiento
adaptativo y redes auto - organizativas).
2. Procesado No Lineal: aumenta la capacidad de la red de aproximar, clasificar y su inmunidad
frente al ruido.
3. Procesado paralelo: normalmente se usa un gran número de células de procesado por el alto nivel
de ínter conectividad.
Estas características juegan un importante papel en las ANN's aplicadas al procesado de señal e imagen.
Una red para una determinada aplicación presenta una arquitectura muy concreta, que comprende elementos
de procesado adaptativo masivo paralelo combinadas con estructuras de interconexión de red jerárquica.
Taxonomía de las Redes Neuronales
Existen dos fases en toda aplicación de las redes neuronales: la fase de aprendizaje o entrenamiento y la
fase de prueba. En la fase de entrenamiento, se usa un conjunto de datos o patrones de entrenamiento para
determinar los pesos (parámetros de diseño) que definen el modelo neurona!. Una vez entrenado este modelo,
se usará en la llamada fase de prueba o funcionamiento directo, en la que se procesan los patrones de prueba
que constituyen la entrada habitual de la red, analizándose de esta manera las prestaciones definitivas de la
red.
• Fase de Prueba: los parámetros de diseño de la red neuronal se han obtenido a partir de unos patrones
representativos de las entradas que se denominan patrones de entrenamiento. Los resultados pueden ser tanto
calculados de una vez como adaptada iterativa mente, según el tipo de red neuronal, y en función de las
ecuaciones dinámicas de prueba. Una vez calculados los pesos de la red, los valores de las neuronas de la
última capa, se comparan con la salida deseada para determinar la validez del diseño.
• Fase de Aprendizaje: una característica de las redes neuronales es su capacidad de aprender. Aprenden por la
actualización o cambio de los pesos sinápticos que caracterizan a las conexiones. Los pesos son adaptados de
acuerdo a la información extraída de los patrones de entrenamiento nuevos que se van presentando.
Normalmente, los pesos óptimos se obtienen optimizando (minimizando o maximizando) alguna "función de
energía". Por ejemplo, un criterio popular en el entrenamiento supervisado es minimizar el least-square-error
(error cuadrático medio) entre el valor del maestro y el valor de salida actual.
Las aplicaciones del mundo real deben acometer dos tipos diferentes de requisitos en el procesado. En
un caso, se requiere la prueba en tiempo real pero el entrenamiento ha de realizarse "fuera de línea". En otras
ocasiones, se requieren los dos procesos, el de prueba y el de entrenamiento en tiempo real. Estos dos
requisitos implican velocidades de proceso muy diferentes, que afectan a los algoritmos y hardware usados.
Atendiendo al tipo de entrenamiento, una posible taxonomía de las redes neuronales es:
Fijo
Redes Neuronales
No supervisado
Red de Hamming
Mapa de características
Red de Hopfield
Aprendizaje competitivo
Supervisado
Basadas en decisión
Perceptrón
ADALINE (LMS)
Perceptrón Multicapa
Modelos Temporales Dinámicos
Modelos Ocultos de Markov
6
Estructuras de las Redes Neuronales Artificiales
Los aspectos más característicos de las estructuras son la estructura de conexión, el tamaño de la red y la
elección entre ACÓN (AII-Class-in-On-Metwork) y OCON (One-Class-in-One-Network).
Una red neuronal se determina por la neurona y la matriz de pesos. El comportamiento de la red
depende en gran medida del comportamiento de la matriz de pesos. Hay tres tipos de capas de neuronas: la de
entrada, las ocultas y la de salida. Entre dos capas de neuronas existe una red de pesos de conexión, que puede
ser de los siguientes tipos: Hacia delante, hada atrás, lateral y de retardo, tal como puede verse en la siguiente
figura:
1 .Conexiones hacia delante: para todos los modelos neuronales, los datos de las neuronas de una capa
inferior son propagados hacia las neuronas de la capa superior por medio de las redes de conexiones hacia
adelante. 2. Conexiones hacia atrás: estas conexiones llevan los datos de las neuronas de una capa superior a
otras de la capa inferior. S.Conexiones laterales. Un ejemplo típico de este tipo es el circuito "el ganador toma
todo" (winner-takes-all), que cumple un papel importante en la elección del ganador. 4. Conexiones con
retardo: los elementos de retardo se incorporan en las conexiones para implementar modelos dinámicos y
temporales, es decir, modelos que precisan de memoria. Las conexiones sinápticas pueden ser total o
parcialmente interconectadas, como muestra la figura. También es posible que las redes sean de una capa con
el modelo de pesos hacia atrás o bien el modelo multicapa hacia adelante. Es posible así mismo, el conectar
varias redes de una sola capa para dar lugar a redes más grandes.
Tamaño de las Redes Neuronales
•En una red multicapa de propagación hacia delante, puede haber una o más capas ocultas entre las capas de
entrada y salida. El tamaño de las redes depende del número de capas y del número de neuronas ocultas por
capa.
- Número de capas: en una red multicapa, hay una o más capas de neuronas ocultas entre la entrada y la
salida. El número de capas se cuenta a menudo a partir del número de capas de pesos (en vez de las capas de
neuronas).
- Número de unidades ocultas: El número de unidades ocultas está directamente relacionado con las
capacidades de la red. Para que el comportamiento de la red sea correcto (esto es, generalización), se tiene que
determinar apropiadamente el número de neuronas de la capa oculta.
Aproximaciones ACÓN frente a OCON
Abordamos el problema de cuantas redes son necesarias para la clasificación en multicategorías.
Típicamente, cada nodo de salida se usa para representar una clase. Por ejemplo, en un problema de
reconocimiento alfanumérico, hay 36 clases; así que en total habrá 36 nodos de salida. Dado un patrón de
entrada en la fase de prueba, el ganador (i.e., la clase que gana) es normalmente el nodo que tiene el valor más
alto a la salida.
7
Dos posibles tipos de arquitectura son "AII-Class-in-One-Network" (ACÓN), esto es, todas las clases en
una red y "One-Class-in-One-Network" (OCON), esto es, una red para cada clase. En la aproximación
ACÓN, todas las clases son reconocidas dentro de una única super red. En algunos casos es ventajoso
descomponer esta macro red en varias subredes más pequeñas. Por ejemplo, una red de 36 salidas se puede
descomponer en 12 subredes, cada una responsable de tres salidas. La descomposición mas extrema es la
llamada OCON, donde una subred se dedica para una sola clase. Aunque el número de subredes en la
estructura OCON es relativamente largo, cada subred individual tiene un tamaño menor que la red ACÓN.
Esto se puede explicar con las siguientes figuras
La red entera se divide en varias subredes.
Por conveniencia, supongamos que todas las redes tienen el mismo tamaño, por ejemplo k. El número de
unidades ocultas de las macro - red ACÓN se denota por K. Obviamente, k << K. Las dos estructuras difieren
claramente en tamaño y rapidez, esto es, en el número total de pesos sinápticos y en el tiempo de
entrenamiento. Sean los vectores de entrada y salida de dimensiones n y N respectivamente. El número total
de pesos sinápticos es para la estructura ACÓN (N+n) * K. De la misma forma, el número para la estructura
OCON es N * (n+1) * k aproximadamente N*n * k. Los dos casos extremos son analizados a continuación.
Cuando N es relativamente pequeña (comparado con n), la estructura ACÓN podría tener el mismo número
de pesos o algo menos que la OCON. Si N es muy grande, entonces la OCON podría tener una mayor ventaja
en términos del tamaño de la red. Además, la OCON parece ser que aventaja a la ACÓN en la rapidez de
reconocimiento y entrenamiento cuando el número de clases es grande.
En la estructura ACÓN, la única macro - red tiene que "satisfacer" todas estas clases, así que el número
de unidades ocultas K ha de ser muy grande. Aplicaciones
Con el fín de llegar al entendimiento global de ANN's, adoptamos la siguiente perspectiva llamada topdown que empieza por la aplicación se pasa al algoritmo y de aquí a la arquitectura:
Esta aproximación a las ANN's está motivada por la aplicación, basada en la teoría y orientada hada la
implementación. Las principales aplicaciones son para el procesado de señal y el reconocimiento de patrones.
La primera etapa algorítmica representa una combinación de la teoría matemática y la fundamentación
heurística por los modelos neuronales. El fin último es la construcción de neurocomputadores digitales, con la
ayuda de las tecnologías VLSI y el procesado adaptativo, digital y paralelo.
8
Desde el punto de vista de las aplicaciones, la ventaja de la ANN's reside en el procesado paralelo,
adaptativo y no lineal. Las ANN's han encontrado muchas aplicaciones con éxito en la visión artificial, en el
procesado de señales e imágenes, reconocimiento del habla y de caracteres, sistemas expertos, análisis de
imágenes médicas, control remoto, control de robots, inspección industrial y exploración científica. El
dominio de aplicación de las ANN's se puede clasificar de la siguiente forma: asociación y clasificación,
regeneración de patrones, regresión y generalización, y optimización.
Asociación y Clasificación
En esta aplicación, los patrones de entrada estáticos o señales temporales deben ser clasificados o
reconocidas. Idealmente, un clasificador debería ser entrenado para que cuando se le presente una versión
distorsionada ligeramente del patrón, pueda ser reconocida correctamente sin problemas. De la misma forma,
la red debería presentar cierta inmunidad contra el ruido, esto es, debería ser capaz de recuperar una señal
"limpia" de ambientes o canales ruidosos. Esto es fundamental en las aplicaciones holográficas. Asociativas o
regenerativas.
•Asociación: de especial interés son las dos clases de asociación: autoasociación y heteroasociación. El
problema de la autoasociación es recuperar un patrón enteramente, dada una información parcial del patrón
deseado. La heteroasociación es recuperar un conjunto de patrones B, dado un patrón de ese conjunto. Los
pesos en las redes asociativas son a menudo predeterminados basados en la regla de Hebb. Normalmente, la
autocorrelación del conjunto de patrones almacenado determina los pesos en las redes autoasociativas. Por
otro lado. La correlación cruzada de muchas parejas de patrones se usa para determinar los pesos de la red de
heteroasociación.
•Clasificación no Supervisada: para esta aplicación, los pesos sinápticos de la red son entrenados por la regla
de aprendizaje no supervisado, esto es, la red adapta los pesos y verifica el resultado basándose únicamente en
los patrones de entrada.
•Clasificación Supervisada: esta clasificación adopta algunas formas del criterio de interpolación o
aproximación. En muchas aplicaciones de clasificación, por ejemplo, reconocimiento de voz, los datos de
entrenamiento consisten de pares de patrones de entrada y salida. En este caso, es conveniente adoptar las
redes Supervisadas, como las bien conocidas y estudiadas redes de retropropagación. Este tipo de redes son
apropiadas para las aplicaciones que tienen una gran cantidad de clases con límites de separación complejos.
Completar los patrones
En muchos problemas de clasificación, una cuestión a solucionar es la recuperación de la
información, esto es, recuperar el patrón original dada sola una información parcial. Hay dos clases de
problemas: temporales y estáticos. El uso apropiado de la información contextual es la llave para tener éxito
en el reconocimiento.
Generalización
Se puede extender a un problema de interpolación. El sistema es entrenado por un gran conjunto
de muestras de entrenamiento basados en un procedimiento de aprendizaje supervisado. Una red se considera
que esta entrenada con éxito si puede aproximar los valores de los patrones de entrenamiento y puede dar
interpolaciones "suaves" para el espado de datos no entrenado. El objetivo de la
Generalización es dar una respuesta correcta a la salida para un estímulo de entrada que no ha sido
entrenado con anterioridad. El sistema debe inducir la característica saliente del estímulo a la entrada y
detectar la regularidad. Tal habilidad para el descubrimiento de esa regularidad es crítica en muchas
aplicaciones. Esto hace que el sistema funcione eficazmente en todo el espacio, incluso ha sido entrenado por
un conjunto limitado de ejemplos. Observe la siguiente figura:
9
Optimización
Las ANN's son unas herramientas interesantes para la optimización de aplicaciones, que
normalmente implican la búsqueda del mínimo absoluto de una función de energía:
Una vez que se define la función de energía, entonces la determinación de los pesos sinápticos se
hace rápidamente. Para algunas aplicaciones, la función de energía es fácilmente deducible. En otras, sin
embargo, esta función de energía se obtiene de ciertos criterios de coste y limitaciones especiales. El mayor
problema asociado al problema de optimización es la alta posibilidad de converger hada un mínimo local, en
vez de hacia el mínimo absoluto. Para combatir este problema se utilizan algunas propuestas estadísticas,
como por ejemplo procedimientos estocásticos.
Red Neuronal BackPropagation
En 1986. Rumerhart, Hinton y Williams [Rumerhait 82], basándose en los trabajos de otros
investigadores [Werbos 74] [Parker 82] formalizaron un método para que una red neuronal aprendiera la
asociación que existe entre los patrones de entrada a la misma y las clases correspondientes, utilizando mas
niveles de neuronas que los que utilizo Rosenblatt para desarrollar el Perceptron.
El algoritmo de propagación hacia atrás, o retropropagación, es una regla de aprendizaje que se
puede aplicar en modelos de redes con mas de dos capas de células.
El funcionamiento de una red backpropagation (backpropagation net, BPN) consiste en un
aprendizaje de un conjunto predefinido de pares entradas-salidas dados como ejemplo, empleando un ciclo
propagación-adaptación de dos fases: primero se aplica un patrón de entrada como estimulo para la primera
capa de las neuronas de la red, se va propagando a través de todas las capas superiores hasta generar una
salida, se compara el resultado obtenido en las neuronas de salida con la salida que se desea obtener y se
calcula un valor de error para cada neurona de salida. A continuación, estos errores se transmiten hacia atrás,
partiendo de la capa de salida, hacia todas las neuronas de la capa intermedia que contribuyan directamente a
la salida, recibiendo el porcentaje de error aproximado a la participación de la neurona intermedia en la salida
original. Este proceso se repite, capa por capa, hasta que todas las neuronas de la red hayan recibido un error
que describa su aportación relativa al error total. Basándose en el valor del error recibido, se reajustan los
pesos de conexión de cada neurona, de manera que en la siguiente vez que se presente el mismo patrón, la
salida este mas cercana a la deseada; es decir, el error disminuya.
La importancia de la red backpropagation consiste en su capacidad de autoadaptar los pesos de
las neuronas de las capas intermedias para aprender la relación que existe entre un conjunto de patrones dados
como ejemplo y sus salidas correspondientes. Para poder aplicar esa misma relación, después del
10
entrenamiento, a nuevos vectores de entrada con ruido o incompletas, dando una salida activa si la nueva
entrada es parecida a las presentadas durante el aprendizaje. Esta característica importante que se exige a los
sistemas de aprendizaje, es la capacidad de generalización, entendida como la facilidad de dar salidas
satisfactorias a entradas que el sistema no ha visto nunca en su fase de
entrenamiento.
La técnica backpropagation requiere el uso de neuronas cuya función de activación sea continua,
y, por tanto, diferenciable. Generalmente, la función utilizada será del tipo sigmoidal.
ALGORITMOS GENÉTICOS
Los Algoritmos Genéticos (AG's) son métodos adaptativos que pueden usarse para resolver
problemas de búsqueda y optimización. Están basados en el proceso genético de los organismos vivos.
A lo largo de las generaciones, las poblaciones evolucionan en la naturaleza de acuerdo con los principios
de la selección natural y la supervivencia de los más fuertes, postulados por Darwin [9]. Por imitación de este
proceso, los Algoritmos Genéticos son capaces de ir creando soluciones para problemas del mundo real. La
evolución de dichas soluciones hacia valores óptimos del problema depende en buena medida de una
adecuada codificación de las mismas.
Los principios básicos de los Algoritmos Genéticos fueron establecidos por Holland [22], y se
encuentran bien descritos en varios textos - Goldberg [19], Davis [11], Michalewicz [29], Reeves [32] --.
En la naturaleza los individuos de una población compiten entre sí en la búsqueda de recursos tales
como comida, agua y refugio. Incluso los miembros de una misma especie compiten a menudo en la búsqueda
de un compañero. Aquellos individuos que tienen más éxito en sobrevivir y en atraer compañeros tienen
mayor probabilidad de generar un gran número de descendientes. Por el contrario individuos poco dotados
producirán un menor número de descendientes. Esto significa que los genes de los individuos mejor
adaptados se propagarán en sucesivas generaciones hacia un número de individuos creciente. La combinación
de buenas características provenientes de diferentes ancestros, puede a
veces producir descendientes "súper
individuos", cuya adaptación es mucho mayor que la de cualquiera de sus ancestros. De esta manera, las
especies evolucionan logrando unas características cada vez mejor adaptadas al entorno en el que viven.
Los Algoritmos Genéticos usan una analogía directa con el comportamiento natural. Trabajan con una
población de individuos, cada uno de los cuales representa una solución factible a un problema dado. A cada
individuo se le asigna un valor ó puntuación, relacionado con la bondad de dicha solución.
En la naturaleza esto equivaldría al grado de efectividad de un organismo para competir por unos
determinados recursos. Cuanto mayor sea la adaptación de un individuo al problema, mayor será la
probabilidad de que el mismo sea seleccionado para reproducirse, cruzando su material genético con otro
individuo seleccionado de igual forma. Este cruce producirá nuevos individuos - descendientes de los
anteriores - los cuales comparten algunas de las características de sus padres. Cuanto menor sea la adaptación
de un individuo, menor será la probabilidad de que dicho individuo sea seleccionado para la
reproducción,
y por tanto de que su material genético se propague en sucesivas generaciones.
De esta manera se produce una nueva población de posibles soluciones, la cual reemplaza a la
anterior y verifica la interesante propiedad de que contiene una mayor proporción de buenas características en
comparación con la población anterior. Así a lo largo de las generaciones las buenas características se
propagan a través de la población. Favoreciendo el cruce de los individuos mejor adaptados, van siendo
exploradas las áreas más prometedoras del espacio de búsqueda. Si el Algoritmo Genético ha sido bien
diseñado, la, población convergerá hacia una solución óptima del problema.
El poder de los Algoritmos Genéticos proviene del hecho de que se trata de una técnica robusta, y
pueden tratar con éxito una gran variedad de problemas provenientes de diferentes áreas, incluyendo aquellos
en los que otros métodos encuentran dificultades. Si bien no se garantiza que el Algoritmo Genético encuentre
la solución óptima, del problema, existe evidencia empírica de que se encuentran soluciones de un nivel
aceptable, en un tiempo competitivo con el resto de algoritmos de optimización combinatoria. En el caso de
que existan técnicas especializadas para resolver un determinado problema, lo más probable es que superen al
Algoritmo Genético, tanto en rapidez como en eficacia. El gran campo
de aplicación de los Algoritmos
Genéticos se relaciona con aquellos problemas para los cuales no existen técnicas especializadas. Incluso en
el caso en que dichas técnicas existan, y funcionen bien, pueden efectuarse mejoras de las mismas
hibridándolas con los Algoritmos Genéticos.
11
Extensiones y Modificaciones del Algoritmo Genético Simple
En este apartado se introducirán algunas extensiones y modificaciones del Algoritmo Genético
Simple Se comenzará dando un pseudocódigo para un Algoritmo Genético Abstracto AGA), para a
continuación introducir algunas variantes que se han ido proponiendo en trabajos desarrollados en estos
últimos años.
BEGIN AGA
Obtener la población inicial al azar
WHILE NOT stop Do
BEGIN
Seleccionar padres de la población
Producir hijos a partir de los padres seleccionados
Mutar los individuos hijos
Extender la población añadiendo los hijos
Reducir la población extendida
END
END AGA
Población
Tamaño de la población
Una cuestión que uno puede plantearse es la relacionada con el tamaño idóneo de la población.
Parece intuitivo que las poblaciones pequeñas corren el riesgo de no cubrir adecuadamente el espacio de
busqueda mientras que el trabajar con poblaciones de gran tamaño puede acarrear problemas relacionados con
el excesivo costo computacional. Goldberq [19] efectuó un estudio teórico, obteniendo como conclusión que
el tamaño óptimo de la población para cadenas de longitud I, con codificación binaria, crece
exponencialmente con el tamaño de la cadena. Este resultado traería como consecuencia que la aplicabilidad
de los Algoritmos Genéticos en problemas reales sería muy limitada, ya que resultarían no competitivos con
otros métodos de optimización combinatoria. Alander [4], basándose en evidencia empírica sugiere que un
tamaño de población comprendida entre 1 y 21 es suficiente para atacar con éxito los problemas por el
considerados.
Población inicial
Habitualmente la población inicial se escoge generando cadenas al azar, pudiendo contener
cada quie uno de los posibles valores del alfabeto con probabilidad uniforme. Nos podríamos preguntar que es
lo que sucedería si los individuos de la población inicial se obtuviesen como resultado de alguna técnica
heurística o de optimización local. En los pocos trabajos que existen sobre este aspecto, se constata que esta
inicialización no aleatoria de la población inicial, puede acelerar la convergencia del Algoritmo Genético. Sin
embargo en algunos casos la desventaja resulta ser la prematura convergencia del algoritmo, queriendo
indicar con esto la convergencia hacia óptimos locales.
Función objetivo
Dos aspectos que resultan cruciales en el comportamiento de los Algoritmos Genéticos son la
determinación de una adecuada función de adaptación o función objetivo, así como la codificación utilizada.
Idealmente nos interesaría construir funciones objetivo con "ciertas regularidades", es decir a funciones
objetivo que verifiquen que para dos individuos que se encuentren cercanos en el espacio de búsqueda, sus
respectivos valores en las funciones objetivo sean similares. Por otra parte una dificultad en el
comportamiento del Algoritmo Genético puede ser la existencia de gran cantidad de óptimos locales, así
como el hecho de que el óptimo global se encuentre muy aislado.
La regla general para construir una buena función objetivo es que ésta debe reflejar el valor del
individuo de una manera "real", pero en muchos problemas de optimización combinatoria, donde existe una
12
gran cantidad de restricciones, buena parte de los puntos del espacio de búsqueda representan individuos no
válidos.
Para este planteamiento en el que los individuos están sometidos a restricciones, se han
propuesto varias soluciones. La primera sería la que podríamos denominar absolutista, en la que aquellos
individuos que no verifican las restricciones, no son considerados como tales, y se siguen efectuando cruces y
mutaciones-hasta obtener individuos válidos, o bien, a dichos individuos se les asigna una función objetivo
igual a cero. Otra posibilidad consiste en reconstruir aquellos individuos que no verifican las restricciones.
Dicha reconstrucción suele llevarse a cabo por medio de un nuevo operador que se acostumbra a
denominar reparador.
Otro enfoque está basado en la penalización de la función objetivo. La idea general consiste en
dividir la función objetivo del individuo por una cantidad (la penalización) que guarda relación con las
restricciones que dicho individuo viola. Dicha cantidad puede simplemente tener en cuenta el número de
restricciones violadas ó bien el denominado costo esperado de reconstrucción, es decir el coste asociado a la
conversión de dicho individuo en otro que no viole ninguna restricción.
Otra técnica que se ha venido utilizando en el caso en que la computación de la función
objetivo sea muy compleja es la denominada evaluación aproximada de la función objetivo. En algunos casos
la obtención de n funciones objetivo aproximadas puede resultar mejor que la evaluación exacta de una única
función objetivo (supuesto el caso de que la evaluación aproximada resulta como mínimo n veces más rápida
que la, evaluación exacta).
Un problema habitual en las ejecuciones de los Algoritmos Genéticos surge debido a la
velocidad con la que el algoritmo converge. En algunos casos la convergencia es muy rápida, lo que suele a
denominarse convergencia prematura, en la cual el algoritmo converge hacia óptimos locales, mientras que en
otros casos el problema es justo el contrario, es decir se produce una convergencia lenta del algoritmo. Una
posible solución a estos problemas pasa por efectuar transformaciones en la función objetivo. El problema de
la convergencia prematura, surge a menudo cuando la selección de individuos se realiza de manera
proporcional a su función objetivo. En tal caso, pueden existir individuos con una
adaptación al
problema muy superior al resto, que a medida que avanza el algoritmo "dominan" a la población. Por medio
de una transformación de la función objetivo, en este caso una comprensión del "primer rango de variación de
la función objetivo, se pretende que dichos "súper individuos" no lleguen a dominar a la población.
El problema de la lenta convergencia del algoritmo, se resolvería de manera análoga, pero en
este caso efectuando una expansión del rango de la función objetivo.
La idea de especies de organismos, ha sido imitada en el diseño de los Algoritmos Genéticos
en un método propuesto por Goldberg y Richardson [20], utilizando una modificación de la función objetivo
de cada individuo, de tal manera que individuos que estén muy cercanos entre sí devalúen su función objetivo,
con objeto de que la población gane en diversidad.
PROGRAMACIÓN EVOLUTIVA
La Programación Evolutiva, se fundamenta en las ideas expresadas por Fogel [16], [17], [18], y
trata de resolver problemas de optimización combinatoria.
A grandes rasgos, la estructura de dichos algoritmos se asemeja a la de los Algoritmos
Genéticos, si bien la diferencia fundamental entre ambos radica en el hecho de que los nuevos individuos son
creados utilizando tan sólo mutación, es decir no existen operadores de cruce. De esta forma la Programación
Evolutiva puede verse como un Algoritmo Genético asexual.
La Codificación del algoritmo de base como vimos anteriormente, antes de crear un programa
evolutivo o algoritmo genético debemos de considerar la estructura que va a tener y como va a funcionar para
obtener resultados de buena calidad. Para los fines que se persiguen en este trabajo lo que se eligió fue
trabajar con redes neuronales tipo Perceptron Multicapa, aplicándoles operadores genéticos. Cada cromosoma
de la población representa un PM el cual contará con una sola capa oculta donde el número de nodos ocultos
puede variar.
13
Cada cromosoma de la población debe generar, codificar y variar, tanto su número de nodos
ocultos como los pesos de conexión entre las entradas con los nodos de la capa oculta y los pesos de los nodos
de la capa oculta con los de las salidas. Con esto tenemos que los cromosomas tienen una longitud variable
por lo que para implementarlos haremos uso de una lista donde cada nodo de la lista representa
conceptualmente un nodo oculto del PM.
Un cromosoma típico se muestra en la siguiente figura junto con el PM que representa.
Perceptron Mulicapa (PM)
En cada nodo de la lista guardamos la información que es importante y que es representativa de
la estructura del PM. Esta información consta de los valores de los pesos numéricos sobre las conexiones que
llegan al nodo oculto de los nodos de entrada y los que salen de los nodos ocultos hacia los nodos de salida.
Para representar toda la población del PE en la memoria de la máquina, se codifica en un arreglo
de estructuras de tamaño n que define n-1 cromosomas de la población. La estructura mantiene información
sobre la aptitud de cada cromosoma, lo cual se explicará más adelante, además de un apuntador a la lista del
cromosoma. La posición n del arreglo se utiliza para dejar el mejor PM encontrado de una generación a otra.
Véase la siguiente figura.
Estructura que representa los cromosomas en una población.
El Algoritmo Principal
El algoritmo principal del PE se muestra a continuación.
Inicio
Generación=0
Inicializar la población
Evaluar cada cromosoma
14
Guardar el mejor cromosoma
Mientras (generación<MAXGENS)
Inicio
Seleccionar la nueva población
Aplicar Mutación Estructural
Aplicar Mutación de los pesos
Evaluar cada cromosoma
Guardar el mejor cromosoma
Generación=Generación+1
Fin
Fin
Lo que hace éste algoritmo es inicializar una población aleatoria de cromosomas los cuales evalúa
utilizando una función de evaluación, a esta población la llamamos generación cero Algo importante que se
debe mencionar es que la población tiene tamaño fijo durante todas las generaciones
Después de evaluados los cromosomas, guarda el mejor en el último elemento del arreglo de
estructuras para después entrar en un ciclo donde la población evoluciona varias generaciones a las cuales se
les aplican los operadores genéticos.
Iniciación de la Población
Una función inicializa cada elemento de la población de la siguiente manera: el número de
nodos ocultos representados en cada cromosoma se genera de manera aleatoria, cuidando que no exceda un
número máximo definido por el usuario. De igual manera los pesos de cada nodo se inicializan de forma
aleatoria con valores entre -1 y 1.
Función de Evaluación
La función de evaluación, como ya vimos anteriormente, es una función que nos indica que tan
apto es un cromosoma para participar en la creación de la siguiente generación. En el caso particular de este
trabajo la aptitud del PM se refiere a qué tan bien clasifica un conjunto de datos.
Para encontrar esta aptitud de los cromosomas lo que se hace es primeramente calcular la
entrada a cada uno de los nodos ocultos del cromosoma y esto se hace mediante el producto interno del vector
de los pesos que entran en el nodo con el vector de los valores de la entrada a la red.
Para el caso del PM de la figura de la página anterior tenemos:
-0.12+0.074*x1+0.017*x2
-0.59+0.146*x1+0.937*x2
La función de transferencia que se ocupa es la función sigmoide, definida de la siguiente
manera:
f(u)=1/(1+exp(-u))
Se aplica esta función de transferencia para calcular la salida de cada uno de los nodos ocultos
dando:
z1=f(-0.12+0.074*x1+0.017*x2)
z2=f(-0.59+0.146*x1+0.937*x2)
Finalmente, para calcular la salida del nodo en la capa de salida, se vuelve a aplicar la función
de transferencia al producto interno del vector de los pesos que entran en el nodo con el vector de las salidas
de los nodos ocultos, dando:
yl=f((0.7-0.7*zl-0.9*z2)
La función de evaluación se basa en el error cuadrático medio, ECM, que comúnmente se usa en
el algoritmo de retropropagación para determinar el error. El ECM se define de la siguiente manera:
ECM=S(yi-di)2
Donde la suma es sobre todos los patrones de los datos, yi es la salida del PM para el patrón
calculado como se describió anteriormente, y di es la salida deseada, que seria el valor que queremos asociar
con el patrón.
Selección de la Nueva Población
15
Para esta parte se eligió utilizar el método de la ruleta el cual se describió anteriormente pero lo
mencionaremos aquí con un poco de más detalle. Este método consiste en particionar un disco en rebanadas o
sectores los cuales dependen en tamaño de la aptitud del cromosoma que representa dicho sector, a mayor
aptitud mayor es el sector o la rebanada y viceversa. Ya que tenemos el disco particionado con todos los
cromosomas participantes (deben de estar todos los de la población) se gira el disco y de acuerdo al sector
donde éste para, se escoge el cromosoma correspondiente para que sea parte de la nueva población. Esto se
repite n-11 veces que es el tamaño de la población. Para hacer la partición del disco y simular el giro de éste
lo que se hace es lo siguiente. Primero encuentra la aptitud total de la población sumando todas las aptitudes
menos el del último cromosoma. Después calcula la aptitud relativa de cada cromosoma dividiendo la aptitud
de ese cromosoma entre la aptitud total. Luego, con la aptitud relativa calcula la aptitud acumulada: se
inicializa la aptitud acumulada del primer cromosoma con su aptitud relativa y se calcula la aptitud acumulada
del siguiente cromosoma sumando su aptitud relativa más la acumulada del cromosoma anterior y así
sucesivamente para cada cromosoma. Esta aptitud acumulada representa la proporción de cada cromosoma.
Para simular el giro del disco se genera un número aleatorio x, entre O y 1, y se elige el
cromosoma cuya aptitud acumulada correspondiente contiene a x. Este proceso se repite el número de
cromosomas existentes. Los cromosomas que ocupan una porción mayor del disco tienen más probabilidad de
ser escogidos para la nueva población, sin embargo, no excluye la elección de cromosomas con peor aptitud.
Al final de este proceso el arreglo que representa la nueva población puede quedar con cromosomas repetidos.
La aptitud relativa y la acumulada son campos de la estructura que se guardan en el arreglo.
Mutación Estructural
Esta mutación se creó para estar modificando el número de nodos ocultos en cada cromosoma
ya que esta variación nos puede ayudar a encontrar el tamaño de la capa oculta necesario para que el
cromosoma logre hacer el mejor porcentaje de clasificación. Para lograr esto el PE utiliza dos operadores ='
los cuales se mencionan y describen a continuación:
1. Adicionar, se encarga de aumentar un nodo oculto al cromosoma en cuestión inicializando sus
pesos con 0. Se valida que al aumentar este nodo no sobrepase el número máximo de nodos permitidos por el
usuario; si ya se tiene ese número máximo no se añade otro nodo. Este nodo se incorpora al final de la lista y
se hace de acuerdo a un número generado de forma aleatoria: si este es menor a una probabilidad de adición
definida por el usuario se adiciona el nodo, en otro caso no se hace ningún cambio al cromosoma.
2. Para equilibrar el efecto que pudiera tener la función Adiciona, y para reducir el número de nodos
ocultos en un cromosoma, se define otro operador de nombre Eliminar. De forma similar se genera un
número aleatorio y se compara con la probabilidad de eliminación definida por el usuario, si dicho
número es menor se elimina el primer nodo de la lista del cromosoma en cuestión.
En los dos casos se reduce linealmente el parámetro de probabilidad de su valor inicial a un
valor pequeño definido por el usuario, conforme evoluciona el algoritmo; con esto, al final de la corrida no
es necesario modificar la arquitectura del PM.
Mutación Paramétrica
En esta parte la mutación se enfoca hacia los pesos de un nodo oculto y esta se realiza a través
de un operador. Esto quiere decir que para cada nodo oculto de un cromosoma se genera un número aleatorio
y si éste número es menor a una probabilidad de mutación, se modifican los pesos agrupados en el nodo; en
caso contrario se conserva el mismo valor de los pesos. Si se va a cambiar el valor de un peso se le agrega el
valor generado por una gaussiana, con media O y varianza definida.
Guardar el mejor cromosoma
En la literatura se han reportado buenos resultados usando un operador llamado elitismo. La
función de éste es asegurar que el mejor cromosoma encontrado sobreviva de una generación a otra. En el PE,
si el cromosoma con mejor aptitud de la población actual supera al seleccionado en la población a anterior,
éste es reemplazado, conservando siempre al mejor cromosoma de una generación a otra. En otro caso
reemplaza el peor cromosoma de la población actual con el mejor de la generación anterior.
16
ALGORITMOS GENÉTICOS PARALELOS
En este apartado se introducirán tres maneras diferentes de explotar el paralelismo de los Algoritmos
Genéticos, por medio de los denominados modelos de islas. Para una profundización sobre el tema puede
consultarse Stender [38]. Modelos de islas
La idea básica consiste en dividir la población total en varias subpoblaciones en cada una de las cuales se
lleva a cabo un Algoritmo Genético. Cada cierto número de generaciones, se efectúa un intercambio de
información entre las subpoblaciones, proceso que se denomina migración. La introducción de la migración
hace que los modelos de islas sean capaces de explotar las diferencias entre las diversas subpoblaciones,
obteniéndose de esta manera una fuente de diversidad genética. Cada subpoblación es una "isla", definiéndose
un procedimiento por medio del cual se mueve el material genético de una "isla" a otra. La determinación de
la 'tasa de migración' es un asunto de capital importancia, ya que de ella puede depender la convergencia
prematura de la búsqueda. Se pueden distinguir diferentes modelos de islas en función de la comunicación
entre las sub-poblaciones. Algunas comunicaciones típicas son las siguientes:
•Comunicación en estrella, en la cual existe una subpoblación que es seleccionada como maestra (aquella que
tiene mejor media en el valor de la función objetivo), siendo las demás consideradas como esclavas. Todas
las subpoblaciones esclavas mandan sus h1 mejores individuos (h1, > 1) a la subpoblación maestra la cual a
su vez manda sus h2 mejores individuos (h2 > 1) a cada una de las subpoblaciones esclavas.
PVM (Paralell Virtual Machine)
PVM es un paquete de software que permite a un programador crear y accesar un sistema de
computo concurrente hecho de una red de elementos de procesamiento libres de conexión. El hardware
coleccionado dentro de la maquina virtual del usuario puede ser estaciones de trabajo con un solo procesador,
"vector machines" o supercomputadoras paralelas.
Los elementos individuales pueden ser de un solo tipo (homogéneos) o todos diferentes
(heterogéneos) o cualquier mezcla, así como las maquinas usadas pueden estar conectadas a una o más tipos
de redes. Estas redes pueden ser pequeñas como una LAN conectada en un solo cuarto, tan grande como la
Internet conectando maquinas alrededor del mundo o cualquier combinación que se quiera.
Esta habilidad de poner juntas diversas arquitecturas bajo un control central permite al usuario
PVM dividir el problema en subtareas y asignar la ejecución de cada una de ellas en la arquitectura del
procesador que mejor convenga para dicha subtarea.
Mientras que no hay restricción en el tamaño de tareas, por el tiempo necesitado para enviar un
mensaje entre dos maquinas en una red externa, es recomendado que las tareas sean de un tamaño moderado
para hacer un uso más efectivo de PVM.
Para ser tan general y flexible como sea posible, PVM esta basado en un modelo de paso de
mensaje paralelo. Los mensajes son pasados entre tareas que no comparten la misma representación de datos.
Las tareas de los usuarios son capaces de inicializar y terminar procesos, compartir datos y sincronizarse con
otra a través de una biblioteca estándar de rutinas de interfase.
El control y dependencia de tareas es arbitrario y bajo el control completo del usuario de
acuerdo a lo dictado por la aplicación.
Hay dos modelos de programación principales que los códigos bajo PVM siguen: master/worker y
hostiess.
Bajo el paradigma master/worker, una tarea es usada como el maestro ("master"). El propósito
de la tarea maestro es crear todas las otras tareas que están designadas a trabajar en el problema ("workers") y
llevar un control general del proceso.
Bajo el modelo hostiess, la tarea inicial crea copias del mismo como tarea y luego comienza a
trabajar en su porción del problema, mientras que las tareas creadas inmediatamente empiezan a trabajar en su
porción. Los requerimientos de entrada/salida son regularmente manejados por las tareas individuales, pero
puede ser benéfico tener algunos resultados recolectados por una sola tarea, específicamente si estos
resultados necesitan ser esparcidos hacia todas las tareas.
Las aplicaciones PVM pueden ser escritas en C o Fortran 77. Para ejecutar un programa bajo
PVM, el usuario agrega llamadas a rutinas de biblioteca de PVM que lanzan tareas a otras maquinas dentro de
la maquina virtual del usuario y permite a las tareas enviar y recibir mensajes.
17
METODOLOGÍA
A continuación se presentan los distintos esquemas del algoritmo evolutivo paralelo planteados
por la Dra. Graciela, se explican también algunas particularidades existentes que conforman las distintas
versiones de los algoritmos desarrollados.
Finalmente se establecen las variables que servirán para comparar las distintas versiones del
algoritmo evolutivo paralelo.
Paralelización de los algoritmos evolutivos
NOTA:
Para codificar cada uno de los esquemas propuestos, se utilizo el modelo de programación
PVM 'master/worker1.
El termino modificar población se refiere a aplicar los operadores genéticos a los individuos de
dicha población.
- Primer esquema (Central i. i=POPSIZE)
Este esquema corresponde al modelo de islas con comunicación en estrella descrito en la
sección de algoritmos genéticos paralelos, como podrá deducirse al comprender la siguiente descripción. En
este esquema el proceso "master":
- Inicialmente crea y lanza los 'workers'."
- Crea su población aleatoria, guarda el mejor individuo en la posición POPSIZE de su arreglo (population),
y pide a cada proceso "worker" crear su propia población aleatoria.
-A continuación recibe las poblaciones de cada "worker", junta todos estos individuos (los creados por él y
por los demás) en un arreglo de Individuos (Array ()).
- Después de hacer esto pide a todos los "workers" modificar su población - que deben conservar- y las recibe
nuevamente, modifica su población - aplicando elitismo nuevamente- y junta todos estos individuos en otro
arreglo de Individuos (Array).
- Repite lo siguiente para el número de generaciones establecidas:
- Selecciona de los dos arreglos (ArrayO y Arrayí) informados en los pasos previos los POPSIZE
mejores individuos, haciéndolos propios del proceso 'master1.
- Después envía a cada "worker" esta población para que la hagan propia, y les pide modificar esta
población. El proceso 'master' modifica su propia población.
- Recibe la población modificada por cada uno de los procesos 'workers'.
- Se aplica Elitismo a los POPSIZE mejores individuos, asegurando que el individuo más apto esta en
la posición POPSIZE del arreglo de Individuos "population".
- Después se guardan todas estas poblaciones en un arreglo de Individuos (ArrayO o Arrayí).
- Finalmente se aplica el algoritmo de Retropropagación al individuo population [POPSIZE].
Para cada esquema descrito anteriormente y el mejorado se usaron las siguientes bases de datos:
Base de datos Iris
Contiene el análisis de una especie de plantas llamada 'iris'. En la base de datos se describe en 3
valores numéricos ciertas características de las plantas las cuales se clasifican en tres clases que son
iris-setosa, iris-versicolor e iris-virginica. Se manejan cuatro características a las que llamamos atributos
y estos son los que se utilizan para obtener la clasificación. Se tienen un total de 119 ejemplos de los
cuales 85 son para entrenamiento y 34 para prueba. Esta es la base de datos más pequeña que se
utilizo.
Base de datos Diabetes
Esta base de datos contiene 768 ejemplos los cuales se dividen en dos clases donde la clase 1
indica que el paciente no dio positivo con la enfermedad y la clase 2 indica que el paciente si dio positivo
con la enfermedad. Se manejan 500 ejemplos de la clase 1 y 268 de la clase 2. Cada ejemplo contiene 8
atributos que son los que se utilizan para hacer la clasificación.
Base de datos Heart
Esta base de datos contiene 270 ejemplos los cuales se dividen en dos clases donde la clase 1
indica que una persona no esta propensa a tener un ataque al corazón y la clase 2 indica que la persona
si es propensa a tener un ataque. Los ejemplos se distribuyen en 150 para la clase 1 y 120 para la clase
Cada ejemplo contiene 13 atributos.
Base de datos DNA
18
Esta base de datos contiene 3186 ejemplos los cuales están clasificados en tres clases. Para su
manejo la base de datos esta dividida en 2000 ejemplos para entrenamiento y 1186 para prueba. La
clase 1 contiene 464 ejemplos de entrenamiento y 303 de prueba, la clase 2 contiene 485 ejemplos de
entrenamiento y 280 de prueba, y por ultimo la clase 3 contiene1051 ejemplos de entrenamiento y 603 •
de prueba. Para la clasificación cada ejemplo contiene 180 atributos.
En cada uno de los esquemas se esta obteniendo un valor llamado calidad (fitness) el cual nos
indica que tan bien clasifica nuestra red en cada una de las bases de datos, este valor se obtiene
después de aplicar el Backpropagation a nuestro mejor individuo. Cada algoritmo nos da el valor calidad
tanto para los ejemplos de entrenamiento como para los de prueba, sin embargo, para efectos de
análisis de resultados, solo se utiliza el de prueba. También se obtiene el tiempo de ejecución da cada
uno de los algoritmos descritos.
ACERCA DE PVM.
Antes de entrar de lleno a lo que son los algoritmos paralelos veremos los elementos básicos
necesarios de PVM que se necesitan para poder correr los programas de una forma correcta.
Primero, antes que nada se necesita crear el archivo hostfíle. Este archivo define la
configuración inicial de los hosts o máquinas, que PVM combina para crear la máquina virtual.
Este archivo también contiene información acerca de los hosts que el usuario desee agregar
posteriormente a la configuración. El archivo hostfile se creo en el directorio raíz del usuario que va a utilizar
PVM y dentro de él lo mínimo que puede contener es una lista de los nombres de los hosts. Un nombre por
línea. Los líneas en blanco son ignoradas, y las líneas que comienzan con un # son líneas de comentario.
Para nuestro caso que se trabajo con el cluster pacífico.uam.mx, nuestro archivo hostfile se veía
más o menos así:
Configuración para pacifico
pacificol.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/pvm3/lib
pacifico2.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacifico3.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacifico4.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacifico5.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacifico6.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacifico7.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacifico8.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacifico9.uam.mx
ep
=
/home/ejecutables/pvm3/bin/LINUX
dx
=
/usr/share/
pvm3/lib
pacificol0.uam.mx ep
= /home/ejecutables/pvm3/bin/LINUX
dx = /usr/share/ pvm3/lib
Donde ep permite indicar al usuario una ruta donde se van a encontrar los archivos ejecutables; dx
permite especificar la dirección donde se encuentra el pvmd (el proceso demonio de pvm) para cada máquina.
Ya que se tiene configurado el archivo hostfile se procede o iniciar la consola pvm. Para hacer esto
simplemente en cualquiera de los hosts o maquinas que van a integrar la consola, se obre una sesión y en una
terminal desde la línea de comandos se teclea $pvm hostfile
Esto hace que se entre a lo consola de pvm donde se despliega el prompt
pvm>
La creación y utilización del archivo hostfile se hace para que PVM integre los hosts que se
encuentran dentro de ese archivo. Si se desean agregar mas existe un comando add que agrega hosts a la
máquina virtual. Para ver en detalle los comandos que acepta el pvm simplemente hay que ejecutar el
comando help desde el prompt de pvm. Los comandos más importantes son quit y halt. El primero sale de la
consola dejando a los demonios y tareas pvm en ejecución. El segundo termina todos los procesos pvm
incluyendo la consola y los demonios deteniendo la ejecución de pvm.
A continuación se muestran y describen cada uno de los funciones de PVM que se utilizaron en la
creación de las tres versiones paralelos:
pvm_mytid()
Retorna el tid del proceso.
Sinopsis. int tid = pvm_mytid(void)
Parámetros.
tid : Entero identificador de la tarea es retornado por la llamada a un proceso PVM. Un
valor menor que cero indica error.
19
pvm_parent()
Regresa el tid del proceso que inició al mismo.
Sinopsis. int tid = pvm_parent(void)
Parámetros.
tid : Tipo entero, indica el identificador de tareas, en este caso del proceso padre.
pvm_recv()
Recibe un mensaje.
Sinopsis. int bufid = pvm_recv(int tid. int msgtag)
Parámetros.
tid
:
identificador
de
tareas
tipo
entero
para
mandar
procesos.
msgtag : Etiqueta de mensaje tipo entero dada por el usuario.
bufid : Valor entero que tiene el identificador del búfer activo receptor.
pvm_initsend()
Limpia el búfer de envío y crea uno nuevo para encapsular el nuevo mensaje.
Sinopsis. int bufid = pvm_initsend(int encoding)
Parámetros.
encoding : Entero que especifica alguno de los siguientes mensajes:
PvmDataDefault, PvmDataRaw o Pvm DataInP lace.
bufid : Entero que regresa el contenido del identificador del búfer del
mensaje. Un valor menor que cero indica error.
pvm_send()
Manda datos al búfer de mensajes activo.
Sinopsis.
int info = pvm_send(int tid, int msgtag)
Parámetros.
tid : identificador de tareas tipo entero para mandar procesos.
msgtag : Etiqueta de mensaje tipo entero dada por el usuario.
info : Código de estado, de tipo entero regresado por la rutina.
Pvm_spawn()
Inicia uno o mas nuevos procesos PVM.
Sinopsis. int numt = pvm_spawn(char *task. chor **argv. int flog. char
*where, int ntask, Int *tids)
Parámetros.
task ; Una cadena de caracteres que contiene el nombre del archivo
ejecutable a ejecutarse como proceso PVM.
argv : Apuntador o un arreglo de argumentos para el archivo
ejecutable, al final del arreglo se especifica como NULL.
flag : Valor de tipo entero indicando las opciones del spawn.
where : Cadena de caracteres especificando donde iniciar el proceso de
PVM.
ntask : Entero especificando el número de copias del ejecutable a
iniciar.
tids : Arreglo de enteros de longitud ntask
numt : Valor entero regresado con el número de tareas iniciadas.
pvm_pk*()
Empaqueta el búfer activo de mensajes con el tipo de datos respectivo.
Sinopsis: int info = pvm_pkint(int *ip. int nitem, int stride)
int info = pvm_pkfloat(float *fp. int nitem, int stride)
Parámetros.
ip : Arreglo de enteros.
fp : Arreglo real de punto flotante.
nitem : El total de dotos a empacar (no el número de bytes).
stride : El tipo de empaquetación a ser usado mientras se empacan
los datos.
info : Valor entero que indica estado. regresado por lo rutina, si es
menor de cero indica error.
pvm_upk*0
20
Desempaco a el búfer de mensajes activo a los arreglos del tipo definido.
Sinopsis.
int info = pvm_upkint(int *ip. int nitem, int strid
int info = pvm__upkfloat(float *fp. int nitem, int stride)
Parámetros.
ip : Arreglo de enteros.
fp : Arreglo real de punto flotante.
nitem : El total de datos a desempacar (no el número de bytes).
stride : El tipo de empaquetación a ser usado mientras se
desempacan los datos.
info : Valor entero que indica estado. regresado por la rutina, si
es menor que cero indica error.
Pvm_exit()
Afecta al pvmd local en el que se proceso la salida de PVM.
Sinopsis. int info = pvm_exit(void)
Parámetros.
info : Entero del código de status retornado por la rutina. Un
valor > 0 indica error.
Se presenta sólo una breve descripción, paro más detalles consulte un manual
especializado en rutinas de PVM. para terminar esta parte mostraremos la forma de compilar los programas
paralelos que utilizan las librerías de PVM. La forma de compilación que utilizamos es la siguiente:
$gcc -o ejecutable archivo_fuente.c -I$PVM_HOME/include -lpvm3 -L$PVM_HOME/lib
Esto se hace desde el directorio donde se encuentran los archivos fuente.
La variable de entorno $PVM_HOME debe ser igual al directorio donde se encuentra
instalado PVM. Cabe mencionar que PVM buscará el código de los procesos lanzados con spawn ya sea
en el directorio $PVM_BIN o en el directorio raíz del usuario que esté ejecutando PVM. Así es necesario
definir dicha variable de entorno (PVM_BIN) o copiar los ejecutables al , directorio raíz de nuestra cuenta.
Resta describir un archivo rhosts. que define parámetros para lo ejecución correcta
de PVM en los host remotos. Se trata del archivo .rhosts. en el cual se define para cada máquina el usuario
que ejecutará PVM, ya que si no se hace esto no se podrá iniciar el pvm desde esa máquina. Este archivo de
autorización es necesario para tener acceso a ciertos comandos como rlogin. rcp y rsh. esenciales para el
funcionamiento de PVM.
Un ejemplo de dicho archivo es:
pacificol.uam.mx trejo
pacifico2.uam.mx trejo
pacifico3.uam.mx trejo
pacifico4.uam.mx trejo
pacifico5.uam.mx trejo
pacifico6.uam.mx trejo
Dicho archivo debe estar colocado en el directorio raíz del usuario.
DEFINICIONES Y VARIABLES DE LOS PROGRAMAS DE APOYO
En esta sección se describirán las variables globales y las definiciones que se establecieron para
los programas. Estas variables y definiciones son similares en las tres versiones de apoyo y en la versión final
donde mejoramos los resultados, cabe mencionar que las 3 primeras versiones cambian es en su forma de
comunicación mas no en su estructura básica de código fuente y la versión final cambio radicalmente tanto
en estructura como en código fuente pero siempre utilizando las mismas variables globales. Las definiciones y
variables globales definidas se encuentran en los archivos algor.h. algor2.h y algor3.h los cuales se utilizan en
los archivos maestro, cpp y esclavo, cpp, maestro2.cpp y esclavo2.cpp. y maestro3.cpp y esclavo3.cpp
respectivamente para las versiones de apoyo y en la ver final algor.h, envia.h, Arch.h, hello.c y hello_other.c
A continuación se describen dichas variables y definiciones:
Variables Globales:
- PELIMIN Es la probabilidad de eliminación de un nodo de una red neuronal
(esto es en la capa oculta).
- PADIC Probabilidad de adicionar un nodo a una red neuronal (en la capa oculta).
- PMUTNODO Es la probabilidad de aplicar mutación o uno de los nodos de una
21
de las redes neurona les.
Definiciones:
- NENT Define el número de entradas a la red neuronal (sin contar el sesgo).
- NSAL Define el número de salidas de lo red.
- MaxSize Define el tamaño máximo que puede tener cada cromosoma de la red
neuronal (el mínimo se definió como 3).
- POPSIZE Define el tamaño de lo población (el número de cromosomas).
- MAXGENS Aquí se define el número máximo de generaciones que se deben
entrenar las redes con algoritmos genéticos.
- PXOVER Define la probabilidad de cruzamiento entre dos cromosomas.
- PMUTATION Probabilidad de mutación a un cromosoma.
- n Razón de aprendizaje (es una constante que se uso en el bockpropagation).
- NPROC Define el número de procesos esclavos que se van a generar y a lanzar.
Para poder enviar y recibir toda esta información a través de las funciones de PVM que solo
pueden recibir enteros o flotantes lo que se hizo fue crear dos funciones. La primera se llamo EnviaPob y se
encarga de agrupar la información mas importante necesaria y enviarlo para que quien reciba esta información
a partir de ésta pueda reconstruir la red neuronal. La segunda función se llama RcvPob y se encarga de recibir
toda la información que necesita para después reconstruir la red neuronal. Estas dos funciones se encuentran
declarados en el archivo envía.h.
Finalmente en el archivo algor.h se define ENVÍA como un parámetro el cual indica a cada
proceso cada cuántas generaciones se envía su población a los demás procesos.
Como mencionamos anteriormente se realizaron las tres versiones del algoritmo genético de
apoyo en paralelo. Las tres manejan parámetros semejantes, en lo que realmente cambian es en su arquitectura
y en su forma de comunicación.
El funcionamiento general de las tres versiones es el siguiente: Primero se creo un proceso
maestro el cual va a tener el control del programa paralelo. Este proceso maestro genera un número
determinado de procesos esclavo donde cada uno de estos creará su propia población aleatoria de individuos.
Cada individuo es una red neuronal y éstas son las que tomaran los valores de las bases de datos para hacer la
clasificación de patrones. Todos los esclavos irán mutando o evolucionando sus poblaciones y después de un
tiempo determinado (una iteración) envían sus individuos finales al proceso maestro el cual elige el mejor
individuo de todos los que recibe y este es el que utiliza para aplicarle la retropropagación así como para
hacer la clasificación de los patrones de la base de datos.
A continuación se describen brevemente las características de solo la versión que se denomino
como la mejor y la cual brindo mas información para así mejorarla:
Versión "Central".
El proceso central o maestro es el que tiene el control total del desarrollo de las redes
neuronales. El proceso central es creado y entonces este genera un número determinado de procesos esclavo,
este número está determinado por un valor definido en el archivo algor.h el cual se le llamó NPROC. Ya que
se crean los procesos esclavos, el maestro les indica que generen cada uno su población aleatoria y espera a
recibir las poblaciones de cada esclavo para guardarlos en un arreglo. Cada población de los procesos esclavo
esta compuesta de POPSIZE individuos donde este valor también está definido en el archivo algor.h y se
puede modificar según a las necesidades del usuario.
Ya que recibió las poblaciones aleatorias de los procesos esclavo entonces el proceso maestro
genera su propia población aleatoria y guarda todas estas poblaciones en un arreglo de tamaño POPSIZE *
(NPROC) + 1 , es mas uno porque en el último elemento del arreglo guardo el mejor individuo (la mejor red
neuronal) de los que tiene en ese momento. Ya hecho esto indica otra vez a todos los esclavos crear su
siguiente población y esto lo hacen mutando la población actual que en este momento es la que generaron
aleatoria mente. El proceso maestro cuando recibe las nuevas poblaciones de todos los esclavos también las
guarda en un segundo arreglo y guarda el mejor individuo en el último elemento.
Lo que sigue es una acción iterativa la cual se hace un determinado número de generaciones,
las cuales están limitadas hasta cierto valor definido también el algor.h como MAXGENS y dicho valor
22
también lo puede modificar el usuario para definir cuantas generaciones quiere que se desarrollen las
poblaciones. Esta acción iterativa consiste de lo siguiente:
El proceso maestro elige de todos los individuos que tiene en los dos arreglos los
POPSIZE mejores, esto lo hace viendo el campo del individuo donde tiene el valor obtenido al aplicarle lo
función de evaluación (fitness o calidad). Cuando obtiene los POPSIZE mejores los envía en un arreglo a
coda uno de los procesos esclavo para que sea a esta población a la que le apliquen la mutación y obtengan la
siguiente generación. Ya que el esclavo hizo esto le vuelve a mandar la población generada al proceso
maestro y se queda esperando a que el proceso maestro mande la siguiente población. El proceso maestro
recibe las poblaciones de todos los esclavos y las guarda en el arreglo que tenga las penúltimas poblaciones
recibidas ya que las guarda las compara junto con las del arreglo de las últimas recibidas y vuelve a obtener
los POPSIZE mejores (recuerde que siempre guarda el mejor individuo de todos en el último elemento del
arreglo) y los vuelve a mandar o los esclavos. Cuando termina el proceso maestro de hacer esta operación, lo
que sigue es enviarles un mensaje a los esclavos para que puedan terminar y por lo tanto morir. Ya que hizo
esto guarda los POPSIZE mejores individuos en un archivo y hace los cálculos de error de prueba y error de
entrenamiento seleccionando nuevamente al mejor (elitismo). Por último le aplica la retropropagación al
mejor individuo y vuelve a calcular el error de prueba y el error de entrenamiento los cuales despliega en
pantalla terminando el proceso maestro.
Los procesos esclavo hacen lo siguiente: Comienzan por identificar quien es su proceso
padre (el proceso maestro). ya que lo identifican esperan recibir una indicación de éste para realizar alguna de
las cuatro siguientes tareas:
1. Inicializar una población aleatoria de tamaño POPSIZE. evaluarla y enviársela al proceso
maestro.
2. Modificar o mutar lo población inicial para producir la próxima generación, aplicándole los
operadores genéticos y enviársela al proceso maestro.
3. Recibe los mejores individuos seleccionados por el proceso maestro. Estos individuos forman
la generación actual del proceso esclavo. El esclavo modifica dicha población aplicándole los operadores
genéticos para enviársela después al proceso maestro.
4. Recibe la notificación por porte del proceso maestro de que termine su trabajo en la
paralelización. Si lo hace así quiere decir que no hay ningún problema y termina el esclavo.
La parte correspondiente a la realización de alguno de esos cuatro pasos se realiza mientras
no se envía la opción 4. y mientras no sucede esto el proceso esclavo cuando termina de hacer alguna de estas
opciones se queda en espero de la siguiente instrucción del proceso maestro, es decir que si el proceso
maestro no le envía alguna instrucción entonces el esclavo se queda esperando infinitamente.
MEJORAMIENTO DEL ALGORITMO EVOLUTIVO
La idea del programa evolutivo es definir una población de cromosomas en donde cada cromosoma
represente una red neuronal perceptron. Consideremos al perceptron con una sola capa oculta donde el
número de nodos ocultos puede variar. El número de nodos de entrada y de salida son constantes,
dependiendo del problema considerado. Un cromosoma deberá codificar el numero de nodos ocultos que
tendrá esa capa y los pesos que unen a los nodos de entrada con los de la capa oculta, y los de esta hacia los
nodos de salida, así como los pesos de los sesgos que se definieron en la capa de entrada y en la capa oculta.
Esto no lleva a la necesidad de considerar cromosomas con una longitud variable. Cada cromosoma, o
perceptron, esta implementado ahora como una lista donde cada elemento de la lista representa
conceptualmente un nodo oculto del perceptron multicapa.
El algoritmo principal del programa evolutivo se muestra a continuación su funcionamiento detallado
puede verse en [ 49].
Inicio
Generación = 0
Iniciar y evaluar la población
Guardar el mejor cromosoma
Mientras (generación < MAXGENS)
Seleccionar la nueva población (método de la rueda)
Para I=1 a TamañoPoblacion
Aplicar mutación estructural(Cromosoma[I]) (*Modifica num. de nodos ocultos*)
23
Aplicar mutación de los pesos(Cromosoma[I])
FinPara
Evaluar la nueva población
Guardar el mejor cromosoma(Elitismo)
Generación = generación + 1
FinMientras
Fin
CRITERIOS DE REEMPLAZO
Ahora se presenta una alternativa basada en la modificación del algoritmo principal mediante la
inclusión de un criterio de reemplazamiento. Con este cambio cada cromosoma de la población genera un hijo
que parte de la misma estructura de su padre (una copia) sufriendo luego mutaciones en su estructura y en el
paso de sus nodos. Para la siguiente generación los padres que sean de una calidad menor que la de sus hijos
serán reemplazados por estos, sobreviviendo los mejores cromosomas. Tal comportamiento se describe a
continuación:
Inicio
Generación = Ho
Iniciar y evaluar la población
Guardar el mejor cromosoma
Mientras (generacion<MAXGENS)
Seleccionar la nueva población (método de la rueda)
Para I=1 a TamañoPoblacion
Hijo = Mutación estructural (Cromosoma[I])
Hijo = Mutación de pesos (Hijo)
Si Calidad(Hijo) > Calidad(Cromosoma[I]) Ent
Reemplaza(Hijo,Cromosoma[I])
FinPara
Evaluar la nueva población
Guardar el mejor cromosoma(Elitismo)
Generación = generación + 1
FinMientras
Fin
CONCLUSIONES
Comparando la versión original con la modificada, después de realizar diversos experimentos, se
toman en cuenta los mejores resultados obtenidos por cada versión. Los resultados obtenidos por el algoritmo
modificado superaron a los obtenidos por la versión original en cuanto al porcentaje de aciertos de
clasificación usando tonto los datos de entrenamiento, como los de prueba e incluso a los reportados en otros
trabajos.
24
Resultados de las pruebas
BD
Poblacion Generaciones Max.Tam. Entrenamiento Prueba
Cromosoma %aciertos
%aciertos
iris
30
300
10
98.0952381
100
Pima
26
2400
11 85.97560976 72.97297
Corazon
25
1800
10 96.82539683 80.24691
Peterson B
25
2400
10 91.50943396 78.26087
Vino
25
1000
10
100
100
Fitness
0.1394
0.0531
0.12707
0.06602
1.83161
Nodos
Ocultos
10
10
10
9
10
%aciertos
Tiempo(seg)
reportados Ejecucion
100
17.8
76
188.35
77.5 y 81
211.29
80
192.35
96-100
88.31
Nodos
Ocultos
10
10
10
9
10
Tiempo(seg) Numero de
Ejecucion
Procesadores
100
5
76
5
77.5 y 81
5
80
5
96-100
5
Resultados de las pruebas algoritmo paralelo
BD
Poblacion Generaciones Max.Tam. Entrenamiento Prueba
Cromosoma %aciertos
%aciertos
iris
6
300
5
98.0952381
100
Pima
26
2400
11 85.97560976 72.97297
Corazon
25
1800
10 96.82539683 80.24691
Peterson B
25
2400
10 91.50943396 78.26087
Vino
25
1000
10
100
100
Fitness
0.1394
0.0531
0.12707
0.06602
1.83161
La alternativa propuesta logro mejorar los resultados obtenidos por el algoritmo original. El hecho de integrar
un criterio de reemplazo permitio la generación de poblaciones de cromosomas con mejor calidad sin embargo, se nota
en los resultados del algoritmo modificado que se requirieron un numero de generaciones y un tamaño de población
mayores que en la versión original, lo cual aumento el tiempo de ejecución. Cuando se trabaja con bases de datos
grandes o cuando se requieren de tiempo de respuesta cortos, la ejecución paralela de este algoritmo puede ser una
buena solución, tal aproximación se contempla dentro del trabajo actual.
25
BIBLIOGRAFÍA
[1] Aarts, E.H.L. y Korst, J.H.M. (1989) Simulated Annealing and Boitzmann Machines,
Wiley, Chichester.
[2] Aarts, E.H.L. y Van Laarhoven, P.J.M. (1985) Statistical cooling: A general ap-proach to
combinatorial optimization problems, Philips Journal of Research, 40, 193-226.
[3] Ackiey, D.H. (1987) A Connectionist Machiae for Genetic Hilldimbing, Kluwer Aca-demic
Publishers.
[4] Alander, J.T. (1992) On optimal population size ofgenetic algorithms, en Proceedings
CompEuro 1992, Computer Systems and Software Engineering, 6th Annual European
"Computer Conference, 65-70.
[5] Baker, J.E. (1987) Reducing bias and inefficiency in the selection algorithm, en Pro-ceedings of
the * Second Enternational Coaference oa Genetic Algorithms and Their Applications, 14-21.
[6] Bramiette, M.F. (1991) Initialization, mutation and selection methods ¡n genetic algo-rithms for
function optimization, en Proceedings of the Fourth International Conference on Genetic
Algorithms, 100-107.
[7] Brindie, A. (1991) Genetic algorithms for function optimization, Tesis doctoral, Univer-sidad de
Alberta, Canadá.
[8] Chakraborty, U.K. y Dastidar, D.G. (1993) Using reliability analysis to estímate the number of
generations to convergence ¡n genetic algorithms, Information Processing Letters, 4B, 199-209.
[9] Darwin, C. (1859) On the Origin of Species by Means of Natural Selection, Murray,
London.
[10] Davis, L. (1985) Appiying adaptive algorithms to epistatic domains, en Proceedings of the
International Joint Conference on Artificial Intelligence, 162-164.
[11] Davis, L. (ed.) (1991) Handbook of Genetic Algorithms, Van Nostrand Reinhold, New
York.
[12] Davis, T.E. y Principe, J.C. (1993) A Marhov chain framework for the simple genetic algorithm,
Evolutionary Computation, 1(3), 269-288.
[13] De Jong, K.A. (1975) An analysis of the behaviour of a class of genetic adaptive systems,
Tesis doctoral, University of Michigan.
[14] Eiben, A.E., Aarts, E.H.L. y Van Hee, K.M. (1990) Global convergence of genetic algorithms:
An infinite Markov chain analysis, Computing Science Notes, Eindhoven Uni-versity of
Technology, The Netherlands.
[15] Fogarty, T.C. (1989) Varying the probability of mutation in the genetic algorithm, en
Proceedings of the Third International Conference on Genetic Algorithms, 104-109.
[16] Fogel, L.J. (1962) Atonomous autómata, End. Res., 4, 14-19.
[17] Fogel, L.J. (1964) On the organisation ofthe intellect, Tesis doctoral, pCLA.
[18] Fogel, L.J.; Owens, A.J. yWaIsh, M.J. (1966) Artificial Intelligence through Simu-lated
Evolution, Wiley, New York. a
[19] Goldberg, D.E. (1989) Genetic Algorithms in Search, Optimization and Machine Learn-ing,
Addison- Wesley, Reading, MA.
[20] Goldberg, D.E. y Richardson, J.T. J1987) Genetic algorithms with sharing for multi-modal
function optimization, en Genetic Algorithms and their Applications: Proceedings ofthe Second
International Conference on Genetic Algorithms and Their Applications, 41-49.
[21] Gorges-SchIeuter, M. (1989) ASPARAGOS An asynchronous parallel genetic opti-mization
strategy en Proceedings on the Third International Conference on Genetic Al-gorithms, 422-427.
[22] Holland, J. (1975) Adaptatioa in Natural and Arti5cial Systems, University of Michigan
Press, Ann Arbor.
[23] Kirkpatrick, S., Oelatt, C.D. yVecchi, M.P. (1983) Optimization bysimulated annealing, Science
220(4598), 671-680.
[24] Koza, J.R. (1992) Genetic Programing: On the Programming of Computers by Means of Natural
Selection, MIT Press.
[25] Larrañaga, P., Grana, M., D'Anjou, A. y Torrealdea, F.J. (1993) Genetic al-gorithms elitist
probabilistic of degree I, a general ization of simulated annealing, en Torasso, P. (ed.) Lecture
Notes in Computer Science 728. Advances in Artihcial Intel-ligence, Springer Verlag, 208-217.
[26] Larrañaga, P. y Poza, M. (1994) Structure learning of Bayesian network by genetic algorithms,
en Diday, E. (ed.) New Approaches in Classihcation and Data Analysis, Springer-Verlag, 300-
26
307.
[27] Levenick, J.R. (1991) Inserting introns improves genetic algorithm success rate: Tak-ing cue
from biology, en Proceedings of the Fourth International Conference on Genetic Algorithms,
123-127.
[28] Liepins, G.E. (1992) On global convergence of genetic algorithms, Neural and Stochastic
Methods in Image and Signal Processing, 61-65.
[29] Michalewicz, Z. (1992) Genetic Algorithms + Data Structures = Evolution Programs, SpringerVerlag Berlin Heidelberg.
[30] Michalewicz, Z. y Janikow C.Z. (1991) Handiing constraints in genetic algorithms, en
Proceedings of the Fourth International Conference on Genetic Algorithms, 151-157.
[31] Rechenberg, I. (1973) Optimierung Technischer Systeme Nach Prinzipien der Biologis-chen
Information, Frommann Verlag, Stuttgart.
[32] Reeves, C. (1993) Modern Heuristic Techniques for Combinatorial Problems, BlackweII
Scientific Publications.
[33] Rudolph, C. (1994) Convergence analysis of canonical genetic algorithms, IEEE Trans-actions
on Neural Networks, 96-101.
[34] SchafFer, J.D., Caruna, R.A;, Eshelman, L.J, y Das, R. (1989) A study of control parameters
affecting onl¡n'e performance of genetic algorithms for function optimization, .en Schaffer, J.D.
(ed.) Proceedings of the Third International Conference on Genetic Algorithms, Morgan
Kaufmann, 51-60.
[35] Schaffer, J.D. y Morishima, A. (1987) An adaptive crossover distribution mechanism for genetic
algorithms, en Genetic Algorithms and their applications: Proceedings of the Second
International Conference on Genetic Algorithms and Their Applications, 36-40.
[36] Schwefel, H.-P (1981) Numérica! Optimization for Computer Modeis, Wiley, Chichester, UK.
[37]. Sirag, D.J. y Weisser, P.T. (1987) Toward a unified thermodynamic genetic operator,' en
Genetic Algorithms and their applications: Proceedings of the Second International Conference
on Genetic Algorithms and Their Applications, 116-122.
[38] Stender, J. (1993) Parallel Genetic Algorithms: Theory and Applications, IOS Press.
[39] Suzuki, J. (1993) A Markov chain analysis on a genetic algorithm, en Proceedings of the
Fifth International Conference on Genetic Algorithms, 146-153.
[40] Syswerda, G. (1991) Schedule optimization using genetic algorithms, en Davis, L. (ed.)
Handbook of Genetic Algorithms, Van Nostrand Reinhold, New York, 332-349.
[41] Tañese, R. (1987) Parallel genetic algorithm for a hypercube, en Proceedings of the
Second International Conference on Genetic Algorithms; 177-183.
[42] Whitley, D. (1989) The GENITOR algorithm and selection pressure: Why rank-based allocation
of reproductive triáis is best, en Proceedings on the Third International Con-ference on Genetic
Algorithms, 116-121.
[43] Whitley, D. y Kauth, J. (1988) GENITOR: A different genetic algorithm, en Proceed-ings of the
Rocl;y Mountain Conference onArtihcial Intelligence, Denver, CO, 118-130.
[44] Whitley, D. y Starkweather, T. (1990) Genitor II: A distributed genetic algorithm,
Journal of Experimental and Theorical Artihcial Intelligence, 2, 189-214.
[45] Mohamad H. Hassoun, "Fundamentáis of artificial Neural Networks", The MIT Press
1995
[46] David J. Montana, "Neural Network Weight Selection Using Genetic
Algorithms", capítulo 5 de Intelligent Hybrid Systems, Goonatilake and Khebbal
(Eds.), John Wiley & Sons, 1995.
[47] Peter J. Angeline, Gregory M. Saunders y Jordán B. Pollack, "An Evolutionary
Algorithm that Constructs Recurrent Neural Networks", IEEE Transactions on
Neural Networks, 5 (1), pp. 54-65, 1994.
[48] José Hilera, Víctor I.
Redes Neuronales Artificiales. Fundamentos, modelos y aplicaciones.
Addison-Wesley Iberoamericana.
[49] Alma Martínez Licona, John Goddard Close, “Definición de una red neuronal para clasificación
por medio de un programa evolutivo”. Revista Mexicana de Ingeniería Biomedica. Vol XXII,
Numero 1. Marzo 2001. pp4-11
27
IRIS
5.1
4.9
4.7
4.6
5
5.4
4.6
5
4.4
4.9
5.4
4.8
4.8
4.3
5.8
5.7
5.4
5.1
5.7
5.1
5.4
5.1
4.6
5.1
4.8
5
5
5.2
5.2
4.7
4.8
5.4
5.2
5.5
4.9
5
5.5
4.9
4.4
5.1
5
4.5
4.4
5
5.1
4.8
5.1
4.6
5.3
5
7
6.4
6.9
5.5
6.5
3.5
3
3.2
3.1
3.6
3.9
3.4
3.4
2.9
3.1
3.7
3.4
3
3
4
4.4
3.9
3.5
3.8
3.8
3.4
3.7
3.6
3.3
3.4
3
3.4
3.5
3.4
3.2
3.1
3.4
4.1
4.2
3.1
3.2
3.5
3.1
3
3.4
3.5
2.3
3.2
3.5
3.8
3
3.8
3.2
3.7
3.3
3.2
3.2
3.1
2.3
2.8
1.4
1.4
1.3
1.5
1.4
1.7
1.4
1.5
1.4
1.5
1.5
1.6
1.4
1.1
1.2
1.5
1.3
1.4
1.7
1.5
1.7
1.5
1
1.7
1.9
1.6
1.6
1.5
1.4
1.6
1.6
1.5
1.5
1.4
1.5
1.2
1.3
1.5
1.3
1.5
1.3
1.3
1.3
1.6
1.9
1.4
1.6
1.4
1.5
1.4
4.7
4.5
4.9
4
4.6
0.2
0.2
0.2
0.2
0.2
0.4
0.3
0.2
0.2
0.1
0.2
0.2
0.1
0.1
0.2
0.4
0.4
0.3
0.3
0.3
0.2
0.4
0.2
0.5
0.2
0.2
0.4
0.2
0.2
0.2
0.2
0.4
0.1
0.2
0.1
0.2
0.2
0.1
0.2
0.2
0.3
0.3
0.2
0.6
0.4
0.3
0.2
0.2
0.2
0.2
1.4
1.5
1.5
1.3
1.5
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-setosa
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
28
5.7
6.3
4.9
6.6
5.2
5
5.9
6
6.1
5.6
6.7
5.6
5.8
6.2
5.6
5.9
6.1
6.3
6.1
6.4
6.6
6.8
6.7
6
5.7
5.5
5.5
5.8
6
5.4
6
6.7
6.3
5.6
5.5
5.5
6.1
5.8
5
5.6
5.7
5.7
6.2
5.1
5.7
6.3
5.8
7.1
6.3
6.5
7.6
4.9
7.3
6.7
7.2
6.5
6.4
2.8
3.3
2.4
2.9
2.7
2
3
2.2
2.9
2.9
3.1
3
2.7
2.2
2.5
3.2
2.8
2.5
2.8
2.9
3
2.8
3
2.9
2.6
2.4
2.4
2.7
2.7
3
3.4
3.1
2.3
3
2.5
2.6
3
2.6
2.3
2.7
3
2.9
2.9
2.5
2.8
3.3
2.7
3
2.9
3
3
2.5
2.9
2.5
3.6
3.2
2.7
4.5
4.7
3.3
4.6
3.9
3.5
4.2
4
4.7
3.6
4.4
4.5
4.1
4.5
3.9
4.8
4
4.9
4.7
4.3
4.4
4.8
5
4.5
3.5
3.8
3.7
3.9
5.1
4.5
4.5
4.7
4.4
4.1
4
4.4
4.6
4
3.3
4.2
4.2
4.2
4.3
3
4.1
6
5.1
5.9
5.6
5.8
6.6
4.5
6.3
5.8
6.1
5.1
5.3
1.3
1.6
1
1.3
1.4
1
1.5
1
1.4
1.3
1.4
1.5
1
1.5
1.1
1.8
1.3
1.5
1.2
1.3
1.4
1.4
1.7
1.5
1
1.1
1
1.2
1.6
1.5
1.6
1.5
1.3
1.3
1.3
1.2
1.4
1.2
1
1.3
1.2
1.3
1.3
1.1
1.3
2.5
1.9
2.1
1.8
2.2
2.1
1.7
1.8
1.8
2.5
2
1.9
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-versicolor
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
29
6.8
5.7
5.8
6.4
6.5
7.7
7.7
6
6.9
5.6
7.7
6.3
6.7
7.2
6.2
6.1
6.4
7.2
7.4
7.9
6.4
6.3
6.1
7.7
6.3
6.4
6
6.9
6.7
6.9
5.8
6.8
6.7
6.7
6.3
6.5
6.2
5.9
iris
iris
iris
iris
3
2.5
2.8
3.2
3
3.8
2.6
2.2
3.2
2.8
2.8
2.7
3.3
3.2
2.8
3
2.8
3
2.8
3.8
2.8
2.8
2.6
3
3.4
3.1
3
3.1
3.1
3.1
2.7
3.2
3.3
3
2.5
3
3.4
3
5.5
5
5.1
5.3
5.5
6.7
6.9
5
5.7
4.9
6.7
4.9
5.7
6
4.8
4.9
5.6
5.8
6.1
6.4
5.6
5.1
5.6
6.1
5.6
5.5
4.8
5.4
5.6
5.1
5.1
5.9
5.7
5.2
5
5.2
5.4
5.1
2.1
2
2.4
2.3
1.8
2.2
2.3
1.5
2.3
2
2
1.8
2.1
1.8
1.8
1.8
2.1
1.6
1.9
2
2.2
1.5
1.4
2.3
2.4
1.8
1.8
2.1
2.4
2.3
1.9
2.3
2.5
2.3
1.9
2
2.3
1.8
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
Iris-virginica
setosa 0
iris-versicolor=1
setosa 100
versicolor 010
virginica 001
iris-virginica=2
VINO
0.842
0.571
0.561
0.879
0.582
0.834
0.884
0.797
1.000
0.745
0.808
0.192
0.206
0.320
0.239
0.366
0.202
0.223
0.279
0.178
0.121
0.281
0.572
0.417
0.701
0.610
0.807
0.583
0.583
0.668
0.433
0.487
0.503
0.258
0.031
0.412
0.320
0.536
0.237
0.206
0.361
0.175
0.278
0.381
0.620
0.326
0.337
0.467
0.522
0.457
0.283
0.554
0.293
0.304
0.380
0.628
0.576
0.628
0.990
0.628
0.790
0.524
0.559
0.628
0.690
0.679
0.574
0.511
0.612
0.665
0.496
0.643
0.460
0.458
0.557
0.593
0.629
0.283
0.245
0.321
0.208
0.491
0.396
0.321
0.340
0.302
0.170
0.170
0.593
0.274
0.757
0.558
0.445
0.492
0.495
0.265
0.495
0.454
0.621
0.372
0.265
0.375
0.556
0.259
0.467
0.339
0.322
0.334
0.507
0.381
0.455
0.463
0.447
0.309
0.455
0.463
0.439
0.472
0.488
0.431
0.626
0.971
0.780
0.696
0.799
0.608
0.579
0.846
0.846
0.579
0.835
0.696
0.561
0.551
0.647
0.857
0.326
0.836
0.722
0.725
0.547
0.547
0.879
30
1
1
1
1
1
1
1
1
1
1
1
0.813
0.716
0.979
0.882
0.684
0.861
0.737
0.832
0.687
0.797
0.500
0.705
0.479
0.650
0.532
0.621
0.597
0.747
0.787
0.711
0.671
0.697
0.718
0.653
0.645
0.592
0.532
0.537
0.839
0.666
0.626
0.750
0.582
0.532
0.837
0.882
0.755
0.808
0.766
0.532
0.737
0.734
0.721
0.713
0.666
0.839
0.595
0.708
0.353
0.342
0.424
0.695
0.353
0.300
0.353
0.547
0.353
0.146
0.196
0.196
0.223
0.211
0.233
0.164
0.168
0.466
0.176
0.605
0.221
0.170
0.211
0.259
0.204
0.194
0.229
0.186
0.150
0.182
0.215
0.156
0.209
0.211
0.178
0.180
0.150
0.642
0.192
0.613
0.227
0.640
0.204
0.652
0.563
0.186
0.253
0.196
0.196
0.180
0.200
0.229
0.184
0.196
0.190
0.243
0.136
0.040
0.071
0.123
0.101
0.077
0.140
0.093
0.053
0.085
0.513
0.561
0.551
0.545
0.717
0.727
0.674
0.599
0.642
0.492
0.690
0.535
0.620
0.668
0.995
0.674
0.417
0.770
0.455
0.717
0.535
0.535
0.717
0.690
0.561
0.791
0.636
0.396
0.615
0.508
0.406
0.658
0.497
0.396
0.578
0.492
0.406
0.556
0.487
0.364
0.663
0.567
0.706
0.476
0.588
0.503
0.706
0.610
0.000
0.492
0.353
0.299
0.428
0.626
0.642
0.182
0.299
0.320
0.278
0.041
0.072
0.340
0.485
0.485
0.304
0.237
0.278
0.412
0.309
0.371
0.485
0.742
0.284
0.330
0.454
0.278
0.613
0.438
0.340
0.459
0.433
0.510
0.253
0.381
0.253
0.134
0.289
0.423
0.227
0.356
0.330
0.428
0.278
0.278
0.423
0.351
0.093
0.340
0.175
0.335
0.299
0.510
0.294
0.320
0.314
0.000
0.278
0.320
0.381
0.433
0.433
0.387
0.227
0.464
0.272
0.207
0.228
0.348
0.457
0.543
0.489
0.413
0.500
0.609
0.348
0.337
0.272
0.283
0.587
0.250
0.261
0.402
0.283
0.337
0.391
0.370
0.674
0.435
0.326
0.435
0.304
0.304
0.630
0.511
0.217
0.337
0.359
0.402
0.446
0.348
0.337
0.359
0.413
0.239
0.261
0.446
0.489
0.522
0.500
0.522
0.348
0.413
0.196
0.337
0.326
0.261
0.185
0.370
0.304
0.087
0.087
0.421
0.559
0.731
0.800
0.645
0.628
0.679
0.800
0.593
0.697
0.493
0.562
0.517
0.534
0.569
0.645
0.490
0.679
0.576
0.697
0.648
0.497
0.679
0.472
0.593
0.559
0.507
0.490
0.697
0.748
0.507
0.783
0.572
0.697
0.645
0.783
0.731
0.610
0.655
0.600
0.507
1.000
0.697
0.559
0.683
0.766
0.697
0.834
0.345
0.369
0.359
0.386
0.869
0.314
0.497
0.690
0.390
0.441
0.511
0.707
0.696
0.542
0.591
0.646
0.757
0.568
0.597
0.437
0.536
0.428
0.479
0.494
0.549
0.390
0.555
0.420
0.614
0.601
0.496
0.506
0.462
0.557
0.494
0.441
0.485
0.570
0.622
0.494
0.679
0.483
0.561
0.487
0.597
0.643
0.544
0.675
0.618
0.559
0.717
0.517
0.540
0.515
0.561
0.610
0.703
0.049
0.158
0.226
0.306
0.582
0.297
0.487
0.599
0.350
0.245
0.302
0.566
0.302
0.321
0.377
0.509
0.358
0.075
0.208
0.226
0.264
0.245
0.283
0.642
0.396
0.264
0.453
0.245
0.302
0.170
0.547
0.698
0.302
0.245
0.396
0.302
0.283
0.132
0.396
0.264
0.075
0.358
0.283
0.321
0.264
0.151
0.358
0.358
0.075
0.170
0.358
0.491
0.151
0.132
0.245
0.340
0.113
0.283
0.943
0.755
0.358
0.113
0.604
0.453
0.245
0.264
0.366
0.442
0.757
0.804
0.331
0.492
0.413
0.457
0.394
0.533
0.495
0.404
0.331
0.394
0.476
0.328
0.297
0.426
0.495
0.621
0.486
0.492
0.297
0.356
0.457
0.300
0.325
0.303
0.527
0.609
0.338
0.407
0.394
0.511
0.265
0.562
0.546
0.621
0.527
0.789
0.593
0.461
0.401
0.382
0.644
0.511
0.394
0.514
0.003
0.000
0.066
0.101
0.461
0.196
0.527
0.590
0.199
0.317
0.369
0.352
0.531
0.514
0.420
0.454
0.633
0.326
0.373
0.275
0.215
0.226
0.191
0.196
0.300
0.228
0.275
0.292
0.377
0.480
0.218
0.352
0.249
0.326
0.283
0.253
0.206
0.326
0.414
0.256
0.354
0.263
0.321
0.338
0.309
0.411
0.420
0.650
0.505
0.369
0.492
0.428
0.390
0.424
0.435
0.403
0.471
0.057
0.170
0.381
0.215
0.270
0.142
0.283
0.343
0.290
0.561
0.545
0.626
0.585
0.650
0.480
0.528
0.610
0.390
0.496
0.447
0.512
0.496
0.520
0.528
0.358
0.439
0.626
0.455
0.577
0.496
0.610
0.626
0.504
0.455
0.496
0.520
0.569
0.333
0.382
0.350
0.325
0.276
0.325
0.317
0.455
0.350
0.480
0.520
0.520
0.618
0.431
0.528
0.358
0.407
0.374
0.480
0.333
0.463
0.626
0.407
0.610
0.602
0.789
0.577
0.520
0.520
0.568
0.597
0.535
0.634
0.590
0.505
0.476
0.568
0.766
0.894
0.824
1.000
0.864
0.934
0.707
0.714
0.549
0.780
0.850
0.527
0.590
0.586
0.634
0.586
0.806
0.553
0.454
0.520
0.828
0.773
0.634
0.839
0.634
0.762
0.755
0.795
0.755
0.542
0.670
0.601
0.769
0.729
0.608
0.707
0.645
0.747
0.575
0.586
0.201
0.147
0.117
0.436
0.586
0.352
0.377
0.700
0.810
0.715
0.743
0.622
0.905
0.736
0.715
0.608
1.000
0.404
0.358
0.351
0.540
0.526
0.404
0.394
0.654
0.718
0.454
0.540
0.718
0.882
0.508
0.683
0.583
0.458
0.429
0.590
0.529
0.344
0.369
0.540
0.583
0.287
0.433
0.572
0.561
0.504
0.558
0.700
0.622
0.704
0.650
0.782
0.558
0.601
0.494
0.708
0.718
0.173
0.287
0.123
0.251
0.101
0.055
0.285
0.160
0.165
31
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
2
2
2
2
2
2
2
2
2
0.608
0.311
0.332
0.745
0.647
0.516
0.245
0.166
0.526
0.213
0.342
0.439
0.255
0.445
0.276
0.532
0.213
0.432
0.297
0.163
0.161
0.276
0.276
0.255
0.437
0.332
0.155
0.379
0.205
0.332
0.353
0.332
0.276
0.413
0.345
0.208
0.389
0.366
0.321
0.445
0.313
0.153
0.113
0.392
0.192
0.100
0.276
0.000
0.208
0.366
0.458
0.255
0.111
0.139
0.366
0.532
0.221
0.040
0.089
0.172
0.152
0.182
0.184
0.069
0.225
0.032
0.425
0.049
0.619
0.036
0.211
0.077
0.617
0.030
0.047
0.172
0.184
0.261
0.117
0.215
0.152
0.156
0.413
0.247
0.154
0.273
0.132
0.065
0.480
0.265
0.119
0.338
0.194
0.196
0.358
0.196
0.200
0.109
0.121
0.593
0.334
0.383
0.000
0.128
0.152
0.144
0.172
0.532
0.532
0.328
0.259
0.729
1.000
0.706
0.535
0.209
0.455
0.701
0.471
0.663
0.503
0.299
0.187
0.465
0.316
0.556
0.342
0.449
0.615
0.513
0.652
0.471
0.508
0.674
0.588
0.503
0.513
0.567
0.481
0.460
0.492
0.449
0.738
0.332
0.396
0.455
0.182
0.289
0.588
0.278
0.332
0.487
0.406
0.492
0.310
0.717
0.246
0.433
0.834
0.610
0.610
0.449
0.337
0.444
0.332
0.342
0.567
1.000
0.733
0.412
0.551
0.330
0.320
0.505
0.742
0.691
1.000
0.536
0.278
0.278
0.381
0.216
0.639
0.433
0.423
0.691
0.613
0.381
0.381
0.629
0.794
0.567
0.670
0.407
0.588
0.521
0.381
0.381
0.433
0.562
0.278
0.407
0.381
0.356
0.407
0.536
0.459
0.510
0.588
0.433
0.613
0.433
0.485
0.459
0.536
0.485
0.536
0.613
0.562
0.526
0.613
0.278
0.433
0.485
0.923
0.820
0.562
0.536
0.435
0.880
0.359
0.174
0.185
0.750
0.337
0.293
0.174
0.457
0.717
0.337
0.174
0.174
0.087
0.163
0.261
0.315
0.217
0.196
0.152
0.000
0.120
0.174
0.109
0.196
0.304
1.000
0.696
0.163
0.196
0.196
0.293
0.196
0.304
0.174
0.163
0.217
0.109
0.152
0.239
0.261
0.402
0.196
0.359
0.196
0.152
0.163
0.174
0.413
0.109
0.185
0.283
0.533
0.348
0.174
0.130
0.534
0.300
0.041
0.679
0.310
0.800
0.828
0.217
0.334
0.255
0.317
0.638
0.497
0.421
0.352
0.231
0.421
0.421
0.276
0.324
0.334
0.421
0.214
0.162
0.138
0.507
0.703
0.524
0.214
0.541
0.876
0.645
0.431
0.162
0.545
0.524
0.421
0.241
0.231
0.138
0.476
0.607
0.759
0.541
0.266
0.517
0.545
0.510
0.345
0.352
0.224
0.352
0.662
0.759
0.421
0.566
0.648
0.203
0.198
0.143
0.532
0.316
0.538
0.380
0.259
0.357
0.207
0.319
0.466
0.405
0.462
0.262
0.264
0.395
0.338
0.285
0.268
0.285
0.264
0.245
0.192
0.236
0.403
0.405
0.407
0.137
0.456
0.719
0.559
0.386
0.215
0.373
0.274
0.333
0.316
0.357
0.300
0.359
0.544
0.473
0.407
0.357
0.352
0.411
0.386
0.266
0.369
0.192
0.274
0.517
1.000
0.378
0.487
0.568
0.792
0.019
0.453
0.151
0.264
0.151
0.000
0.396
0.208
0.566
0.415
0.566
0.321
0.245
0.509
0.906
0.170
0.321
0.566
0.509
0.660
0.547
0.736
0.698
0.849
0.226
0.075
0.358
0.019
0.302
0.208
0.604
0.245
0.302
0.396
0.453
0.358
1.000
0.453
0.660
0.491
0.302
0.208
0.245
0.887
0.547
0.566
0.736
0.321
0.396
0.566
0.453
0.358
0.642
0.566
0.321
0.151
0.003
0.659
0.331
0.461
0.196
0.489
0.391
0.233
0.331
0.170
0.741
0.486
0.322
0.429
0.312
0.382
0.612
0.331
0.363
0.293
0.297
0.306
0.388
0.385
0.382
0.498
0.297
0.905
0.363
0.429
0.486
0.757
0.312
0.297
0.284
0.319
0.338
0.319
0.385
0.385
0.527
0.656
1.000
0.256
0.202
0.325
0.199
0.505
0.353
0.379
0.132
0.461
0.448
0.461
0.410
0.505
0.789
0.161
0.134
0.151
0.179
0.210
0.177
0.165
0.215
0.283
0.117
0.181
0.110
0.104
0.224
0.078
0.300
0.151
0.114
0.100
0.113
0.130
0.039
0.096
0.198
0.151
0.074
0.168
0.113
0.104
0.138
0.275
0.087
0.172
0.100
0.130
0.067
0.142
0.121
0.181
0.172
0.121
0.117
0.138
0.061
0.215
0.154
0.138
0.053
0.057
0.067
0.181
0.000
0.168
0.403
0.068
0.113
0.130
0.439
0.650
0.346
0.715
0.407
0.675
0.415
0.610
0.577
0.390
0.472
0.577
0.732
0.553
0.675
0.293
0.252
0.610
0.691
0.715
0.423
0.480
0.488
0.463
0.390
0.545
0.553
0.553
0.382
0.610
0.455
0.764
0.642
0.455
0.260
0.374
0.455
0.309
0.423
0.325
0.309
0.390
0.220
0.341
0.610
0.504
0.366
1.000
0.382
0.472
0.179
0.366
0.260
0.366
0.358
0.203
0.220
0.242
0.659
0.201
0.692
0.553
0.817
0.681
0.319
0.443
0.458
0.381
0.681
0.678
0.685
0.531
0.271
0.663
0.692
0.363
0.711
0.542
0.711
0.366
0.505
0.289
0.744
0.619
0.498
0.363
0.538
0.549
0.571
0.619
0.549
0.773
0.429
0.842
0.744
0.696
0.421
0.641
0.729
0.564
0.553
0.451
0.381
0.703
0.586
0.755
0.619
0.311
0.652
0.777
0.886
0.678
0.670
0.868
0.337
0.314
0.422
0.094
0.138
0.504
0.434
0.107
0.081
0.158
0.337
0.132
0.000
0.311
0.251
0.169
0.173
0.123
0.155
0.203
0.287
0.248
0.144
0.123
0.155
0.009
0.048
0.470
0.248
0.107
0.272
0.091
0.308
0.203
0.114
0.098
0.281
0.026
0.165
0.150
0.024
0.287
0.203
0.034
0.235
0.111
0.076
0.092
0.155
0.048
0.067
0.204
0.248
0.133
0.062
0.073
0.073
32
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
0.274
0.368
0.200
0.353
0.266
0.482
0.487
0.468
0.439
0.389
0.413
0.321
0.395
0.647
0.476
0.500
0.613
0.655
0.682
0.321
0.561
0.750
0.484
0.603
0.539
0.650
0.463
0.547
0.579
0.408
0.563
0.739
0.374
0.871
0.645
0.350
0.700
0.479
0.508
0.724
0.711
0.637
0.471
0.671
0.624
0.308
0.458
0.824
0.705
0.624
0.589
0.563
0.816
0.281
0.156
0.275
0.176
0.704
0.121
0.445
0.310
0.555
0.099
0.340
0.787
0.943
0.563
0.439
0.409
0.360
0.480
0.832
0.621
0.559
0.850
0.765
0.494
0.625
0.470
0.381
0.229
0.506
0.109
0.879
0.668
0.453
0.186
0.184
0.611
0.498
0.500
0.536
0.399
0.715
0.585
0.520
0.364
0.763
0.453
0.326
0.350
0.970
0.626
0.700
0.366
0.664
0.433
0.497
0.759
0.503
0.545
0.513
0.556
0.556
0.535
0.476
0.449
0.631
0.684
0.444
0.668
0.717
0.529
0.727
0.529
0.449
0.422
0.465
0.599
0.545
0.535
0.674
0.599
0.743
0.492
0.396
0.513
0.545
0.684
0.717
0.684
0.545
0.631
0.652
0.529
0.503
0.481
0.663
0.503
0.711
0.802
0.513
0.492
0.599
0.583
0.599
0.481
0.540
0.738
0.536
0.562
0.923
0.716
0.588
0.381
0.485
0.691
0.562
0.356
0.407
0.536
0.742
0.459
0.691
0.536
0.485
0.665
0.485
0.407
0.536
0.485
0.562
0.562
0.562
0.691
0.588
0.768
0.407
0.485
0.588
0.459
0.845
0.742
0.613
0.536
0.485
0.588
0.407
0.588
0.613
0.639
0.459
0.716
0.742
0.433
0.459
0.485
0.510
0.639
0.485
0.485
0.716
0.163
0.174
0.239
0.196
0.109
0.565
0.370
0.304
0.391
0.163
0.261
0.207
0.283
0.196
0.337
0.283
0.207
0.293
0.239
0.457
0.348
0.109
0.174
0.239
0.467
0.576
0.457
0.500
0.304
0.359
0.250
0.207
0.293
0.304
0.207
0.196
0.402
0.391
0.391
0.217
0.196
0.446
0.196
0.380
0.457
0.283
0.174
0.228
0.272
0.348
0.543
0.543
0.283
0.559
0.607
0.397
0.428
0.386
0.183
0.110
0.059
0.248
0.352
0.221
0.138
0.279
0.221
0.462
0.193
0.145
0.197
0.352
0.138
0.179
0.000
0.248
0.328
0.148
0.145
0.172
0.421
0.283
0.172
0.262
0.283
0.317
0.628
0.559
0.455
0.293
0.231
0.141
0.128
0.103
0.248
0.172
0.197
0.345
0.093
0.141
0.241
0.241
0.283
0.210
0.231
0.369
0.487
0.593
0.401
0.445
0.297
0.192
0.186
0.158
0.181
0.051
0.068
0.027
0.055
0.030
0.055
0.034
0.034
0.038
0.097
0.093
0.044
0.000
0.065
0.089
0.222
0.259
0.215
0.198
0.103
0.051
0.061
0.103
0.051
0.205
0.160
0.122
0.046
0.055
0.076
0.072
0.027
0.122
0.068
0.105
0.131
0.032
0.036
0.076
0.057
0.086
0.074
0.072
0.089
0.453
0.491
0.849
0.509
0.547
0.151
0.208
0.264
0.075
0.887
0.943
0.755
0.943
0.849
0.755
0.755
0.453
0.698
0.642
0.302
0.566
0.509
0.642
0.604
0.396
0.170
0.208
0.245
0.906
0.755
0.906
0.660
0.943
0.755
0.736
0.698
0.698
0.887
0.509
0.528
0.736
0.566
0.509
0.491
0.264
0.509
0.660
0.585
0.736
0.566
0.566
0.755
0.811
0.297
0.429
0.426
0.470
0.297
0.167
0.132
0.132
0.136
0.265
0.167
0.123
0.218
0.148
0.126
0.107
0.073
0.044
0.192
0.230
0.281
0.085
0.142
0.265
0.230
0.265
0.268
0.363
0.461
0.312
0.360
0.363
0.230
0.722
0.593
0.199
0.123
0.174
0.167
0.196
0.233
0.331
0.177
0.356
0.221
0.101
0.073
0.262
0.205
0.315
0.297
0.331
0.297
0.126
0.227
0.147
0.072
0.113
0.241
0.352
0.377
0.317
0.356
0.497
0.219
0.317
0.377
0.311
0.283
0.369
0.262
0.266
0.591
0.232
0.309
0.544
0.609
0.693
0.625
0.812
0.497
0.788
0.539
0.565
0.660
0.531
1.000
0.893
0.544
0.392
0.367
0.341
0.708
0.456
0.802
0.766
0.630
0.616
0.360
0.735
0.718
0.548
0.514
0.761
0.684
0.676
0.309
0.171
0.398
0.333
0.252
0.228
0.211
0.146
0.244
0.220
0.203
0.220
0.276
0.268
0.333
0.236
0.179
0.333
0.350
0.138
0.098
0.081
0.049
0.057
0.073
0.089
0.000
0.106
0.065
0.081
0.098
0.073
0.154
0.073
0.073
0.065
0.390
0.317
0.163
0.179
0.244
0.301
0.195
0.211
0.154
0.146
0.073
0.114
0.130
0.179
0.089
0.098
0.106
0.736
0.575
0.429
0.553
0.476
0.007
0.055
0.033
0.007
0.088
0.114
0.000
0.154
0.201
0.322
0.381
0.440
0.289
0.286
0.267
0.150
0.022
0.216
0.128
0.022
0.011
0.073
0.022
0.088
0.103
0.077
0.136
0.168
0.253
0.187
0.114
0.201
0.308
0.176
0.150
0.176
0.106
0.176
0.194
0.238
0.205
0.132
0.161
0.172
0.106
0.106
0.128
0.121
0.071
0.053
0.134
0.046
0.215
0.251
0.180
0.201
0.230
0.265
0.297
0.315
0.169
0.215
0.223
0.230
0.358
0.173
0.194
0.412
0.394
0.098
0.248
0.265
0.194
0.158
0.144
0.105
0.283
0.258
0.319
0.144
0.429
0.272
0.244
0.173
0.287
0.208
0.283
0.240
0.173
0.297
0.290
0.337
0.251
0.165
0.137
0.272
0.330
0.337
0.397
0.401
0.201
DIABETES
6 148 72 35 0 33.6 0.627 50 2
33
2
2
2
2
2
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
1 85 66 29 0 26.6 0.351 31 1
8 183 64 0 0 23.3 0.672 32 2
1 89 66 23 94 28.1 0.167 21 1
0 137 40 35 168 43.1 2.288 33 2
5 116 74 0 0 25.6 0.201 30 1
3 78 50 32 88 31.0 0.248 26 2
10 115 0 0 0 35.3 0.134 29 1
2 197 70 45 543 30.5 0.158 53 2
8 125 96 0 0 0.0 0.232 54 2
4 110 92 0 0 37.6 0.191 30 1
10 168 74 0 0 38.0 0.537 34 2
10 139 80 0 0 27.1 1.441 57 1
1 189 60 23 846 30.1 0.398 59 2
5 166 72 19 175 25.8 0.587 51 2
7 100 0 0 0 30.0 0.484 32 2
0 118 84 47 230 45.8 0.551 31 2
7 107 74 0 0 29.6 0.254 31 2
1 103 30 38 83 43.3 0.183 33 1
1 115 70 30 96 34.6 0.529 32 2
3 126 88 41 235 39.3 0.704 27 1
8 99 84 0 0 35.4 0.388 50 1
7 196 90 0 0 39.8 0.451 41 2
9 119 80 35 0 29.0 0.263 29 2
11 143 94 33 146 36.6 0.254 51 2
10 125 70 26 115 31.1 0.205 41 2
7 147 76 0 0 39.4 0.257 43 2
1 97 66 15 140 23.2 0.487 22 1
13 145 82 19 110 22.2 0.245 57 1
5 117 92 0 0 34.1 0.337 38 1
5 109 75 26 0 36.0 0.546 60 1
3 158 76 36 245 31.6 0.851 28 2
3 88 58 11 54 24.8 0.267 22 1
6 92 92 0 0 19.9 0.188 28 1
10 122 78 31 0 27.6 0.512 45 1
4 103 60 33 192 24.0 0.966 33 1
11 138 76 0 0 33.2 0.420 35 1
9 102 76 37 0 32.9 0.665 46 2
2 90 68 42 0 38.2 0.503 27 2
4 111 72 47 207 37.1 1.390 56 2
3 180 64 25 70 34.0 0.271 26 1
7 133 84 0 0 40.2 0.696 37 1
7 106 92 18 0 22.7 0.235 48 1
9 171 110 24 240 45.4 0.721 54 2
7 159 64 0 0 27.4 0.294 40 1
0 180 66 39 0 42.0 1.893 25 2
1 146 56 0 0 29.7 0.564 29 1
2 71 70 27 0 28.0 0.586 22 1
7 103 66 32 0 39.1 0.344 31 2
7 105 0 0 0 0.0 0.305 24 1
1 103 80 11 82 19.4 0.491 22 1
1 101 50 15 36 24.2 0.526 26 1
5 88 66 21 23 24.4 0.342 30 1
8 176 90 34 300 33.7 0.467 58 2
7 150 66 42 342 34.7 0.718 42 1
1 73 50 10 0 23.0 0.248 21 1
7 187 68 39 304 37.7 0.254 41 2
0 100 88 60 110 46.8 0.962 31 1
34
0 146 82 0 0 40.5 1.781 44 1
0 105 64 41 142 41.5 0.173 22 1
2 84 0 0 0 0.0 0.304 21 1
8 133 72 0 0 32.9 0.270 39 2
5 44 62 0 0 25.0 0.587 36 1
2 141 58 34 128 25.4 0.699 24 1
7 114 66 0 0 32.8 0.258 42 2
5 99 74 27 0 29.0 0.203 32 1
0 109 88 30 0 32.5 0.855 38 2
2 109 92 0 0 42.7 0.845 54 1
1 95 66 13 38 19.6 0.334 25 1
4 146 85 27 100 28.9 0.189 27 1
2 100 66 20 90 32.9 0.867 28 2
5 139 64 35 140 28.6 0.411 26 1
13 126 90 0 0 43.4 0.583 42 2
4 129 86 20 270 35.1 0.231 23 1
1 79 75 30 0 32.0 0.396 22 1
1 0 48 20 0 24.7 0.140 22 1
7 62 78 0 0 32.6 0.391 41 1
5 95 72 33 0 37.7 0.370 27 1
0 131 0 0 0 43.2 0.270 26 2
2 112 66 22 0 25.0 0.307 24 1
3 113 44 13 0 22.4 0.140 22 1
2 74 0 0 0 0.0 0.102 22 1
7 83 78 26 71 29.3 0.767 36 1
0 101 65 28 0 24.6 0.237 22 1
5 137 108 0 0 48.8 0.227 37 2
2 110 74 29 125 32.4 0.698 27 1
13 106 72 54 0 36.6 0.178 45 1
2 100 68 25 71 38.5 0.324 26 1
15 136 70 32 110 37.1 0.153 43 2
1 107 68 19 0 26.5 0.165 24 1
1 80 55 0 0 19.1 0.258 21 1
4 123 80 15 176 32.0 0.443 34 1
7 81 78 40 48 46.7 0.261 42 1
4 134 72 0 0 23.8 0.277 60 2
2 142 82 18 64 24.7 0.761 21 1
6 144 72 27 228 33.9 0.255 40 1
2 92 62 28 0 31.6 0.130 24 1
1 71 48 18 76 20.4 0.323 22 1
6 93 50 30 64 28.7 0.356 23 1
1 122 90 51 220 49.7 0.325 31 2
1 163 72 0 0 39.0 1.222 33 2
1 151 60 0 0 26.1 0.179 22 1
0 125 96 0 0 22.5 0.262 21 1
1 81 72 18 40 26.6 0.283 24 1
2 85 65 0 0 39.6 0.930 27 1
1 126 56 29 152 28.7 0.801 21 1
1 96 122 0 0 22.4 0.207 27 1
4 144 58 28 140 29.5 0.287 37 1
3 83 58 31 18 34.3 0.336 25 1
0 95 85 25 36 37.4 0.247 24 2
3 171 72 33 135 33.3 0.199 24 2
8 155 62 26 495 34.0 0.543 46 2
1 89 76 34 37 31.2 0.192 23 1
4 76 62 0 0 34.0 0.391 25 1
7 160 54 32 175 30.5 0.588 39 2
35
4 146 92 0 0 31.2 0.539 61 2
5 124 74 0 0 34.0 0.220 38 2
5 78 48 0 0 33.7 0.654 25 1
4 97 60 23 0 28.2 0.443 22 1
4 99 76 15 51 23.2 0.223 21 1
0 162 76 56 100 53.2 0.759 25 2
6 111 64 39 0 34.2 0.260 24 1
2 107 74 30 100 33.6 0.404 23 1
5 132 80 0 0 26.8 0.186 69 1
0 113 76 0 0 33.3 0.278 23 2
1 88 30 42 99 55.0 0.496 26 2
3 120 70 30 135 42.9 0.452 30 1
1 118 58 36 94 33.3 0.261 23 1
1 117 88 24 145 34.5 0.403 40 2
0 105 84 0 0 27.9 0.741 62 2
4 173 70 14 168 29.7 0.361 33 2
9 122 56 0 0 33.3 1.114 33 2
3 170 64 37 225 34.5 0.356 30 2
8 84 74 31 0 38.3 0.457 39 1
2 96 68 13 49 21.1 0.647 26 1
2 125 60 20 140 33.8 0.088 31 1
0 100 70 26 50 30.8 0.597 21 1
0 93 60 25 92 28.7 0.532 22 1
0 129 80 0 0 31.2 0.703 29 1
5 105 72 29 325 36.9 0.159 28 1
3 128 78 0 0 21.1 0.268 55 1
5 106 82 30 0 39.5 0.286 38 1
2 108 52 26 63 32.5 0.318 22 1
10 108 66 0 0 32.4 0.272 42 2
4 154 62 31 284 32.8 0.237 23 1
0 102 75 23 0 0.0 0.572 21 1
9 57 80 37 0 32.8 0.096 41 1
2 106 64 35 119 30.5 1.400 34 1
5 147 78 0 0 33.7 0.218 65 1
2 90 70 17 0 27.3 0.085 22 1
1 136 74 50 204 37.4 0.399 24 1
4 114 65 0 0 21.9 0.432 37 1
9 156 86 28 155 34.3 1.189 42 2
1 153 82 42 485 40.6 0.687 23 1
8 188 78 0 0 47.9 0.137 43 2
7 152 88 44 0 50.0 0.337 36 2
2 99 52 15 94 24.6 0.637 21 1
1 109 56 21 135 25.2 0.833 23 1
2 88 74 19 53 29.0 0.229 22 1
17 163 72 41 114 40.9 0.817 47 2
4 151 90 38 0 29.7 0.294 36 1
7 102 74 40 105 37.2 0.204 45 1
0 114 80 34 285 44.2 0.167 27 1
2 100 64 23 0 29.7 0.368 21 1
0 131 88 0 0 31.6 0.743 32 2
6 104 74 18 156 29.9 0.722 41 2
3 148 66 25 0 32.5 0.256 22 1
4 120 68 0 0 29.6 0.709 34 1
4 110 66 0 0 31.9 0.471 29 1
3 111 90 12 78 28.4 0.495 29 1
6 102 82 0 0 30.8 0.180 36 2
6 134 70 23 130 35.4 0.542 29 2
36
2 87 0 23 0 28.9 0.773 25 1
1 79 60 42 48 43.5 0.678 23 1
2 75 64 24 55 29.7 0.370 33 1
8 179 72 42 130 32.7 0.719 36 2
6 85 78 0 0 31.2 0.382 42 1
0 129 110 46 130 67.1 0.319 26 2
5 143 78 0 0 45.0 0.190 47 1
5 130 82 0 0 39.1 0.956 37 2
6 87 80 0 0 23.2 0.084 32 1
0 119 64 18 92 34.9 0.725 23 1
1 0 74 20 23 27.7 0.299 21 1
5 73 60 0 0 26.8 0.268 27 1
4 141 74 0 0 27.6 0.244 40 1
7 194 68 28 0 35.9 0.745 41 2
8 181 68 36 495 30.1 0.615 60 2
1 128 98 41 58 32.0 1.321 33 2
8 109 76 39 114 27.9 0.640 31 2
5 139 80 35 160 31.6 0.361 25 2
3 111 62 0 0 22.6 0.142 21 1
9 123 70 44 94 33.1 0.374 40 1
7 159 66 0 0 30.4 0.383 36 2
11 135 0 0 0 52.3 0.578 40 2
8 85 55 20 0 24.4 0.136 42 1
5 158 84 41 210 39.4 0.395 29 2
1 105 58 0 0 24.3 0.187 21 1
3 107 62 13 48 22.9 0.678 23 2
4 109 64 44 99 34.8 0.905 26 2
4 148 60 27 318 30.9 0.150 29 2
0 113 80 16 0 31.0 0.874 21 1
1 138 82 0 0 40.1 0.236 28 1
0 108 68 20 0 27.3 0.787 32 1
2 99 70 16 44 20.4 0.235 27 1
6 103 72 32 190 37.7 0.324 55 1
5 111 72 28 0 23.9 0.407 27 1
8 196 76 29 280 37.5 0.605 57 2
5 162 104 0 0 37.7 0.151 52 2
1 96 64 27 87 33.2 0.289 21 1
7 184 84 33 0 35.5 0.355 41 2
2 81 60 22 0 27.7 0.290 25 1
0 147 85 54 0 42.8 0.375 24 1
7 179 95 31 0 34.2 0.164 60 1
0 140 65 26 130 42.6 0.431 24 2
9 112 82 32 175 34.2 0.260 36 2
12 151 70 40 271 41.8 0.742 38 2
5 109 62 41 129 35.8 0.514 25 2
6 125 68 30 120 30.0 0.464 32 1
5 85 74 22 0 29.0 1.224 32 2
5 112 66 0 0 37.8 0.261 41 2
0 177 60 29 478 34.6 1.072 21 2
2 158 90 0 0 31.6 0.805 66 2
7 119 0 0 0 25.2 0.209 37 1
7 142 60 33 190 28.8 0.687 61 1
1 100 66 15 56 23.6 0.666 26 1
1 87 78 27 32 34.6 0.101 22 1
0 101 76 0 0 35.7 0.198 26 1
3 162 52 38 0 37.2 0.652 24 2
4 197 70 39 744 36.7 2.329 31 1
37
0 117 80 31 53 45.2 0.089 24 1
4 142 86 0 0 44.0 0.645 22 2
6 134 80 37 370 46.2 0.238 46 2
1 79 80 25 37 25.4 0.583 22 1
4 122 68 0 0 35.0 0.394 29 1
3 74 68 28 45 29.7 0.293 23 1
4 171 72 0 0 43.6 0.479 26 2
7 181 84 21 192 35.9 0.586 51 2
0 179 90 27 0 44.1 0.686 23 2
9 164 84 21 0 30.8 0.831 32 2
0 104 76 0 0 18.4 0.582 27 1
1 91 64 24 0 29.2 0.192 21 1
4 91 70 32 88 33.1 0.446 22 1
3 139 54 0 0 25.6 0.402 22 2
6 119 50 22 176 27.1 1.318 33 2
2 146 76 35 194 38.2 0.329 29 1
9 184 85 15 0 30.0 1.213 49 2
10 122 68 0 0 31.2 0.258 41 1
0 165 90 33 680 52.3 0.427 23 1
9 124 70 33 402 35.4 0.282 34 1
1 111 86 19 0 30.1 0.143 23 1
9 106 52 0 0 31.2 0.380 42 1
2 129 84 0 0 28.0 0.284 27 1
2 90 80 14 55 24.4 0.249 24 1
0 86 68 32 0 35.8 0.238 25 1
12 92 62 7 258 27.6 0.926 44 2
1 113 64 35 0 33.6 0.543 21 2
3 111 56 39 0 30.1 0.557 30 1
2 114 68 22 0 28.7 0.092 25 1
1 193 50 16 375 25.9 0.655 24 1
11 155 76 28 150 33.3 1.353 51 2
3 191 68 15 130 30.9 0.299 34 1
3 141 0 0 0 30.0 0.761 27 2
4 95 70 32 0 32.1 0.612 24 1
3 142 80 15 0 32.4 0.200 63 1
4 123 62 0 0 32.0 0.226 35 2
5 96 74 18 67 33.6 0.997 43 1
0 138 0 0 0 36.3 0.933 25 2
2 128 64 42 0 40.0 1.101 24 1
0 102 52 0 0 25.1 0.078 21 1
2 146 0 0 0 27.5 0.240 28 2
10 101 86 37 0 45.6 1.136 38 2
2 108 62 32 56 25.2 0.128 21 1
3 122 78 0 0 23.0 0.254 40 1
1 71 78 50 45 33.2 0.422 21 1
13 106 70 0 0 34.2 0.251 52 1
2 100 70 52 57 40.5 0.677 25 1
7 106 60 24 0 26.5 0.296 29 2
0 104 64 23 116 27.8 0.454 23 1
5 114 74 0 0 24.9 0.744 57 1
2 108 62 10 278 25.3 0.881 22 1
0 146 70 0 0 37.9 0.334 28 2
10 129 76 28 122 35.9 0.280 39 1
7 133 88 15 155 32.4 0.262 37 1
7 161 86 0 0 30.4 0.165 47 2
2 108 80 0 0 27.0 0.259 52 2
7 136 74 26 135 26.0 0.647 51 1
38
5 155 84 44 545 38.7 0.619 34 1
1 119 86 39 220 45.6 0.808 29 2
4 96 56 17 49 20.8 0.340 26 1
5 108 72 43 75 36.1 0.263 33 1
0 78 88 29 40 36.9 0.434 21 1
0 107 62 30 74 36.6 0.757 25 2
2 128 78 37 182 43.3 1.224 31 2
1 128 48 45 194 40.5 0.613 24 2
0 161 50 0 0 21.9 0.254 65 1
6 151 62 31 120 35.5 0.692 28 1
2 146 70 38 360 28.0 0.337 29 2
0 126 84 29 215 30.7 0.520 24 1
14 100 78 25 184 36.6 0.412 46 2
8 112 72 0 0 23.6 0.840 58 1
0 167 0 0 0 32.3 0.839 30 2
2 144 58 33 135 31.6 0.422 25 2
5 77 82 41 42 35.8 0.156 35 1
5 115 98 0 0 52.9 0.209 28 2
3 150 76 0 0 21.0 0.207 37 1
2 120 76 37 105 39.7 0.215 29 1
10 161 68 23 132 25.5 0.326 47 2
0 137 68 14 148 24.8 0.143 21 1
0 128 68 19 180 30.5 1.391 25 2
2 124 68 28 205 32.9 0.875 30 2
6 80 66 30 0 26.2 0.313 41 1
0 106 70 37 148 39.4 0.605 22 1
2 155 74 17 96 26.6 0.433 27 2
3 113 50 10 85 29.5 0.626 25 1
7 109 80 31 0 35.9 1.127 43 2
2 112 68 22 94 34.1 0.315 26 1
3 99 80 11 64 19.3 0.284 30 1
3 182 74 0 0 30.5 0.345 29 2
3 115 66 39 140 38.1 0.150 28 1
6 194 78 0 0 23.5 0.129 59 2
4 129 60 12 231 27.5 0.527 31 1
3 112 74 30 0 31.6 0.197 25 2
0 124 70 20 0 27.4 0.254 36 2
13 152 90 33 29 26.8 0.731 43 2
2 112 75 32 0 35.7 0.148 21 1
1 157 72 21 168 25.6 0.123 24 1
1 122 64 32 156 35.1 0.692 30 2
10 179 70 0 0 35.1 0.200 37 1
2 102 86 36 120 45.5 0.127 23 2
6 105 70 32 68 30.8 0.122 37 1
8 118 72 19 0 23.1 1.476 46 1
2 87 58 16 52 32.7 0.166 25 1
1 180 0 0 0 43.3 0.282 41 2
12 106 80 0 0 23.6 0.137 44 1
1 95 60 18 58 23.9 0.260 22 1
0 165 76 43 255 47.9 0.259 26 1
0 117 0 0 0 33.8 0.932 44 1
5 115 76 0 0 31.2 0.343 44 2
9 152 78 34 171 34.2 0.893 33 2
7 178 84 0 0 39.9 0.331 41 2
1 130 70 13 105 25.9 0.472 22 1
1 95 74 21 73 25.9 0.673 36 1
1 0 68 35 0 32.0 0.389 22 1
39
5 122 86 0 0 34.7 0.290 33 1
8 95 72 0 0 36.8 0.485 57 1
8 126 88 36 108 38.5 0.349 49 1
1 139 46 19 83 28.7 0.654 22 1
3 116 0 0 0 23.5 0.187 23 1
3 99 62 19 74 21.8 0.279 26 1
5 0 80 32 0 41.0 0.346 37 2
4 92 80 0 0 42.2 0.237 29 1
4 137 84 0 0 31.2 0.252 30 1
3 61 82 28 0 34.4 0.243 46 1
1 90 62 12 43 27.2 0.580 24 1
3 90 78 0 0 42.7 0.559 21 1
9 165 88 0 0 30.4 0.302 49 2
1 125 50 40 167 33.3 0.962 28 2
13 129 0 30 0 39.9 0.569 44 2
12 88 74 40 54 35.3 0.378 48 1
1 196 76 36 249 36.5 0.875 29 2
5 189 64 33 325 31.2 0.583 29 2
5 158 70 0 0 29.8 0.207 63 1
5 103 108 37 0 39.2 0.305 65 1
4 146 78 0 0 38.5 0.520 67 2
4 147 74 25 293 34.9 0.385 30 1
5 99 54 28 83 34.0 0.499 30 1
6 124 72 0 0 27.6 0.368 29 2
0 101 64 17 0 21.0 0.252 21 1
3 81 86 16 66 27.5 0.306 22 1
1 133 102 28 140 32.8 0.234 45 2
3 173 82 48 465 38.4 2.137 25 2
0 118 64 23 89 0.0 1.731 21 1
0 84 64 22 66 35.8 0.545 21 1
2 105 58 40 94 34.9 0.225 25 1
2 122 52 43 158 36.2 0.816 28 1
12 140 82 43 325 39.2 0.528 58 2
0 98 82 15 84 25.2 0.299 22 1
1 87 60 37 75 37.2 0.509 22 1
4 156 75 0 0 48.3 0.238 32 2
0 93 100 39 72 43.4 1.021 35 1
1 107 72 30 82 30.8 0.821 24 1
0 105 68 22 0 20.0 0.236 22 1
1 109 60 8 182 25.4 0.947 21 1
1 90 62 18 59 25.1 1.268 25 1
1 125 70 24 110 24.3 0.221 25 1
1 119 54 13 50 22.3 0.205 24 1
5 116 74 29 0 32.3 0.660 35 2
8 105 100 36 0 43.3 0.239 45 2
5 144 82 26 285 32.0 0.452 58 2
3 100 68 23 81 31.6 0.949 28 1
1 100 66 29 196 32.0 0.444 42 1
5 166 76 0 0 45.7 0.340 27 2
1 131 64 14 415 23.7 0.389 21 1
4 116 72 12 87 22.1 0.463 37 1
4 158 78 0 0 32.9 0.803 31 2
2 127 58 24 275 27.7 1.600 25 1
3 96 56 34 115 24.7 0.944 39 1
0 131 66 40 0 34.3 0.196 22 2
3 82 70 0 0 21.1 0.389 25 1
3 193 70 31 0 34.9 0.241 25 2
40
4 95 64 0 0 32.0 0.161 31 2
6 137 61 0 0 24.2 0.151 55 1
5 136 84 41 88 35.0 0.286 35 2
9 72 78 25 0 31.6 0.280 38 1
5 168 64 0 0 32.9 0.135 41 2
2 123 48 32 165 42.1 0.520 26 1
4 115 72 0 0 28.9 0.376 46 2
0 101 62 0 0 21.9 0.336 25 1
8 197 74 0 0 25.9 1.191 39 2
1 172 68 49 579 42.4 0.702 28 2
6 102 90 39 0 35.7 0.674 28 1
1 112 72 30 176 34.4 0.528 25 1
1 143 84 23 310 42.4 1.076 22 1
1 143 74 22 61 26.2 0.256 21 1
0 138 60 35 167 34.6 0.534 21 2
3 173 84 33 474 35.7 0.258 22 2
1 97 68 21 0 27.2 1.095 22 1
4 144 82 32 0 38.5 0.554 37 2
1 83 68 0 0 18.2 0.624 27 1
3 129 64 29 115 26.4 0.219 28 2
1 119 88 41 170 45.3 0.507 26 1
2 94 68 18 76 26.0 0.561 21 1
0 102 64 46 78 40.6 0.496 21 1
2 115 64 22 0 30.8 0.421 21 1
8 151 78 32 210 42.9 0.516 36 2
4 184 78 39 277 37.0 0.264 31 2
0 94 0 0 0 0.0 0.256 25 1
1 181 64 30 180 34.1 0.328 38 2
0 135 94 46 145 40.6 0.284 26 1
1 95 82 25 180 35.0 0.233 43 2
2 99 0 0 0 22.2 0.108 23 1
3 89 74 16 85 30.4 0.551 38 1
1 80 74 11 60 30.0 0.527 22 1
2 139 75 0 0 25.6 0.167 29 1
1 90 68 8 0 24.5 1.138 36 1
0 141 0 0 0 42.4 0.205 29 2
12 140 85 33 0 37.4 0.244 41 1
5 147 75 0 0 29.9 0.434 28 1
1 97 70 15 0 18.2 0.147 21 1
6 107 88 0 0 36.8 0.727 31 1
0 189 104 25 0 34.3 0.435 41 2
2 83 66 23 50 32.2 0.497 22 1
4 117 64 27 120 33.2 0.230 24 1
8 108 70 0 0 30.5 0.955 33 2
4 117 62 12 0 29.7 0.380 30 2
0 180 78 63 14 59.4 2.420 25 2
1 100 72 12 70 25.3 0.658 28 1
0 95 80 45 92 36.5 0.330 26 1
0 104 64 37 64 33.6 0.510 22 2
0 120 74 18 63 30.5 0.285 26 1
1 82 64 13 95 21.2 0.415 23 1
2 134 70 0 0 28.9 0.542 23 2
0 91 68 32 210 39.9 0.381 25 1
2 119 0 0 0 19.6 0.832 72 1
2 100 54 28 105 37.8 0.498 24 1
14 175 62 30 0 33.6 0.212 38 2
1 135 54 0 0 26.7 0.687 62 1
41
5 86 68 28 71 30.2 0.364 24 1
10 148 84 48 237 37.6 1.001 51 2
9 134 74 33 60 25.9 0.460 81 1
9 120 72 22 56 20.8 0.733 48 1
1 71 62 0 0 21.8 0.416 26 1
8 74 70 40 49 35.3 0.705 39 1
5 88 78 30 0 27.6 0.258 37 1
10 115 98 0 0 24.0 1.022 34 1
0 124 56 13 105 21.8 0.452 21 1
0 74 52 10 36 27.8 0.269 22 1
0 97 64 36 100 36.8 0.600 25 1
8 120 0 0 0 30.0 0.183 38 2
6 154 78 41 140 46.1 0.571 27 1
1 144 82 40 0 41.3 0.607 28 1
0 137 70 38 0 33.2 0.170 22 1
0 119 66 27 0 38.8 0.259 22 1
7 136 90 0 0 29.9 0.210 50 1
4 114 64 0 0 28.9 0.126 24 1
0 137 84 27 0 27.3 0.231 59 1
2 105 80 45 191 33.7 0.711 29 2
7 114 76 17 110 23.8 0.466 31 1
8 126 74 38 75 25.9 0.162 39 1
4 132 86 31 0 28.0 0.419 63 1
3 158 70 30 328 35.5 0.344 35 2
0 123 88 37 0 35.2 0.197 29 1
4 85 58 22 49 27.8 0.306 28 1
0 84 82 31 125 38.2 0.233 23 1
0 145 0 0 0 44.2 0.630 31 2
0 135 68 42 250 42.3 0.365 24 2
1 139 62 41 480 40.7 0.536 21 1
0 173 78 32 265 46.5 1.159 58 1
4 99 72 17 0 25.6 0.294 28 1
8 194 80 0 0 26.1 0.551 67 1
2 83 65 28 66 36.8 0.629 24 1
2 89 90 30 0 33.5 0.292 42 1
4 99 68 38 0 32.8 0.145 33 1
4 125 70 18 122 28.9 1.144 45 2
3 80 0 0 0 0.0 0.174 22 1
6 166 74 0 0 26.6 0.304 66 1
5 110 68 0 0 26.0 0.292 30 1
2 81 72 15 76 30.1 0.547 25 1
7 195 70 33 145 25.1 0.163 55 2
6 154 74 32 193 29.3 0.839 39 1
2 117 90 19 71 25.2 0.313 21 1
3 84 72 32 0 37.2 0.267 28 1
6 0 68 41 0 39.0 0.727 41 2
7 94 64 25 79 33.3 0.738 41 1
3 96 78 39 0 37.3 0.238 40 1
10 75 82 0 0 33.3 0.263 38 1
0 180 90 26 90 36.5 0.314 35 2
1 130 60 23 170 28.6 0.692 21 1
2 84 50 23 76 30.4 0.968 21 1
8 120 78 0 0 25.0 0.409 64 1
12 84 72 31 0 29.7 0.297 46 2
0 139 62 17 210 22.1 0.207 21 1
9 91 68 0 0 24.2 0.200 58 1
2 91 62 0 0 27.3 0.525 22 1
42
3 99 54 19 86 25.6 0.154 24 1
3 163 70 18 105 31.6 0.268 28 2
9 145 88 34 165 30.3 0.771 53 2
7 125 86 0 0 37.6 0.304 51 1
13 76 60 0 0 32.8 0.180 41 1
6 129 90 7 326 19.6 0.582 60 1
2 68 70 32 66 25.0 0.187 25 1
3 124 80 33 130 33.2 0.305 26 1
6 114 0 0 0 0.0 0.189 26 1
9 130 70 0 0 34.2 0.652 45 2
3 125 58 0 0 31.6 0.151 24 1
3 87 60 18 0 21.8 0.444 21 1
1 97 64 19 82 18.2 0.299 21 1
3 116 74 15 105 26.3 0.107 24 1
0 117 66 31 188 30.8 0.493 22 1
0 111 65 0 0 24.6 0.660 31 1
2 122 60 18 106 29.8 0.717 22 1
0 107 76 0 0 45.3 0.686 24 1
1 86 66 52 65 41.3 0.917 29 1
6 91 0 0 0 29.8 0.501 31 1
1 77 56 30 56 33.3 1.251 24 1
4 132 0 0 0 32.9 0.302 23 2
0 105 90 0 0 29.6 0.197 46 1
0 57 60 0 0 21.7 0.735 67 1
0 127 80 37 210 36.3 0.804 23 1
3 129 92 49 155 36.4 0.968 32 2
8 100 74 40 215 39.4 0.661 43 2
3 128 72 25 190 32.4 0.549 27 2
10 90 85 32 0 34.9 0.825 56 2
4 84 90 23 56 39.5 0.159 25 1
1 88 78 29 76 32.0 0.365 29 1
8 186 90 35 225 34.5 0.423 37 2
5 187 76 27 207 43.6 1.034 53 2
4 131 68 21 166 33.1 0.160 28 1
1 164 82 43 67 32.8 0.341 50 1
4 189 110 31 0 28.5 0.680 37 1
1 116 70 28 0 27.4 0.204 21 1
3 84 68 30 106 31.9 0.591 25 1
6 114 88 0 0 27.8 0.247 66 1
1 88 62 24 44 29.9 0.422 23 1
1 84 64 23 115 36.9 0.471 28 1
7 124 70 33 215 25.5 0.161 37 1
1 97 70 40 0 38.1 0.218 30 1
8 110 76 0 0 27.8 0.237 58 1
11 103 68 40 0 46.2 0.126 42 1
11 85 74 0 0 30.1 0.300 35 1
6 125 76 0 0 33.8 0.121 54 2
0 198 66 32 274 41.3 0.502 28 2
1 87 68 34 77 37.6 0.401 24 1
6 99 60 19 54 26.9 0.497 32 1
0 91 80 0 0 32.4 0.601 27 1
2 95 54 14 88 26.1 0.748 22 1
1 99 72 30 18 38.6 0.412 21 1
6 92 62 32 126 32.0 0.085 46 1
4 154 72 29 126 31.3 0.338 37 1
0 121 66 30 165 34.3 0.203 33 2
3 78 70 0 0 32.5 0.270 39 1
43
2 130 96 0 0 22.6 0.268 21 1
3 111 58 31 44 29.5 0.430 22 1
2 98 60 17 120 34.7 0.198 22 1
1 143 86 30 330 30.1 0.892 23 1
1 119 44 47 63 35.5 0.280 25 1
6 108 44 20 130 24.0 0.813 35 1
2 118 80 0 0 42.9 0.693 21 2
10 133 68 0 0 27.0 0.245 36 1
2 197 70 99 0 34.7 0.575 62 2
0 151 90 46 0 42.1 0.371 21 2
6 109 60 27 0 25.0 0.206 27 1
12 121 78 17 0 26.5 0.259 62 1
8 100 76 0 0 38.7 0.190 42 1
8 124 76 24 600 28.7 0.687 52 2
1 93 56 11 0 22.5 0.417 22 1
8 143 66 0 0 34.9 0.129 41 2
6 103 66 0 0 24.3 0.249 29 1
3 176 86 27 156 33.3 1.154 52 2
0 73 0 0 0 21.1 0.342 25 1
11 111 84 40 0 46.8 0.925 45 2
2 112 78 50 140 39.4 0.175 24 1
3 132 80 0 0 34.4 0.402 44 2
2 82 52 22 115 28.5 1.699 25 1
6 123 72 45 230 33.6 0.733 34 1
0 188 82 14 185 32.0 0.682 22 2
0 67 76 0 0 45.3 0.194 46 1
1 89 24 19 25 27.8 0.559 21 1
1 173 74 0 0 36.8 0.088 38 2
1 109 38 18 120 23.1 0.407 26 1
1 108 88 19 0 27.1 0.400 24 1
6 96 0 0 0 23.7 0.190 28 1
1 124 74 36 0 27.8 0.100 30 1
7 150 78 29 126 35.2 0.692 54 2
4 183 0 0 0 28.4 0.212 36 2
1 124 60 32 0 35.8 0.514 21 1
1 181 78 42 293 40.0 1.258 22 2
1 92 62 25 41 19.5 0.482 25 1
0 152 82 39 272 41.5 0.270 27 1
1 111 62 13 182 24.0 0.138 23 1
3 106 54 21 158 30.9 0.292 24 1
3 174 58 22 194 32.9 0.593 36 2
7 168 88 42 321 38.2 0.787 40 2
6 105 80 28 0 32.5 0.878 26 1
11 138 74 26 144 36.1 0.557 50 2
3 106 72 0 0 25.8 0.207 27 1
6 117 96 0 0 28.7 0.157 30 1
2 68 62 13 15 20.1 0.257 23 1
9 112 82 24 0 28.2 1.282 50 2
0 119 0 0 0 32.4 0.141 24 2
2 112 86 42 160 38.4 0.246 28 1
2 92 76 20 0 24.2 1.698 28 1
6 183 94 0 0 40.8 1.461 45 1
0 94 70 27 115 43.5 0.347 21 1
2 108 64 0 0 30.8 0.158 21 1
4 90 88 47 54 37.7 0.362 29 1
0 125 68 0 0 24.7 0.206 21 1
0 132 78 0 0 32.4 0.393 21 1
44
5 128 80 0 0 34.6 0.144 45 1
4 94 65 22 0 24.7 0.148 21 1
7 114 64 0 0 27.4 0.732 34 2
0 102 78 40 90 34.5 0.238 24 1
2 111 60 0 0 26.2 0.343 23 1
1 128 82 17 183 27.5 0.115 22 1
10 92 62 0 0 25.9 0.167 31 1
13 104 72 0 0 31.2 0.465 38 2
5 104 74 0 0 28.8 0.153 48 1
2 94 76 18 66 31.6 0.649 23 1
7 97 76 32 91 40.9 0.871 32 2
1 100 74 12 46 19.5 0.149 28 1
0 102 86 17 105 29.3 0.695 27 1
4 128 70 0 0 34.3 0.303 24 1
6 147 80 0 0 29.5 0.178 50 2
4 90 0 0 0 28.0 0.610 31 1
3 103 72 30 152 27.6 0.730 27 1
2 157 74 35 440 39.4 0.134 30 1
1 167 74 17 144 23.4 0.447 33 2
0 179 50 36 159 37.8 0.455 22 2
11 136 84 35 130 28.3 0.260 42 2
0 107 60 25 0 26.4 0.133 23 1
1 91 54 25 100 25.2 0.234 23 1
1 117 60 23 106 33.8 0.466 27 1
5 123 74 40 77 34.1 0.269 28 1
2 120 54 0 0 26.8 0.455 27 1
1 106 70 28 135 34.2 0.142 22 1
2 155 52 27 540 38.7 0.240 25 2
2 101 58 35 90 21.8 0.155 22 1
1 120 80 48 200 38.9 1.162 41 1
11 127 106 0 0 39.0 0.190 51 1
3 80 82 31 70 34.2 1.292 27 2
10 162 84 0 0 27.7 0.182 54 1
1 199 76 43 0 42.9 1.394 22 2
8 167 106 46 231 37.6 0.165 43 2
9 145 80 46 130 37.9 0.637 40 2
6 115 60 39 0 33.7 0.245 40 2
1 112 80 45 132 34.8 0.217 24 1
4 145 82 18 0 32.5 0.235 70 2
10 111 70 27 0 27.5 0.141 40 2
6 98 58 33 190 34.0 0.430 43 1
9 154 78 30 100 30.9 0.164 45 1
6 165 68 26 168 33.6 0.631 49 1
1 99 58 10 0 25.4 0.551 21 1
10 68 106 23 49 35.5 0.285 47 1
3 123 100 35 240 57.3 0.880 22 1
8 91 82 0 0 35.6 0.587 68 1
6 195 70 0 0 30.9 0.328 31 2
9 156 86 0 0 24.8 0.230 53 2
0 93 60 0 0 35.3 0.263 25 1
3 121 52 0 0 36.0 0.127 25 2
2 101 58 17 265 24.2 0.614 23 1
2 56 56 28 45 24.2 0.332 22 1
0 162 76 36 0 49.6 0.364 26 2
0 95 64 39 105 44.6 0.366 22 1
4 125 80 0 0 32.3 0.536 27 2
5 136 82 0 0 0.0 0.640 69 1
45
2 129 74 26 205 33.2 0.591 25 1
3 130 64 0 0 23.1 0.314 22 1
1 107 50 19 0 28.3 0.181 29 1
1 140 74 26 180 24.1 0.828 23 1
1 144 82 46 180 46.1 0.335 46 2
8 107 80 0 0 24.6 0.856 34 1
13 158 114 0 0 42.3 0.257 44 2
2 121 70 32 95 39.1 0.886 23 1
7 129 68 49 125 38.5 0.439 43 2
2 90 60 0 0 23.5 0.191 25 1
7 142 90 24 480 30.4 0.128 43 2
3 169 74 19 125 29.9 0.268 31 2
0 99 0 0 0 25.0 0.253 22 1
4 127 88 11 155 34.5 0.598 28 1
4 118 70 0 0 44.5 0.904 26 1
2 122 76 27 200 35.9 0.483 26 1
6 125 78 31 0 27.6 0.565 49 2
1 168 88 29 0 35.0 0.905 52 2
2 129 0 0 0 38.5 0.304 41 1
4 110 76 20 100 28.4 0.118 27 1
6 80 80 36 0 39.8 0.177 28 1
10 115 0 0 0 0.0 0.261 30 2
2 127 46 21 335 34.4 0.176 22 1
9 164 78 0 0 32.8 0.148 45 2
2 93 64 32 160 38.0 0.674 23 2
3 158 64 13 387 31.2 0.295 24 1
5 126 78 27 22 29.6 0.439 40 1
10 129 62 36 0 41.2 0.441 38 2
0 134 58 20 291 26.4 0.352 21 1
3 102 74 0 0 29.5 0.121 32 1
7 187 50 33 392 33.9 0.826 34 2
3 173 78 39 185 33.8 0.970 31 2
10 94 72 18 0 23.1 0.595 56 1
1 108 60 46 178 35.5 0.415 24 1
5 97 76 27 0 35.6 0.378 52 2
4 83 86 19 0 29.3 0.317 34 1
1 114 66 36 200 38.1 0.289 21 1
1 149 68 29 127 29.3 0.349 42 2
5 117 86 30 105 39.1 0.251 42 1
1 111 94 0 0 32.8 0.265 45 1
4 112 78 40 0 39.4 0.236 38 1
1 116 78 29 180 36.1 0.496 25 1
0 141 84 26 0 32.4 0.433 22 1
2 175 88 0 0 22.9 0.326 22 1
2 92 52 0 0 30.1 0.141 22 1
3 130 78 23 79 28.4 0.323 34 2
8 120 86 0 0 28.4 0.259 22 2
2 174 88 37 120 44.5 0.646 24 2
2 106 56 27 165 29.0 0.426 22 1
2 105 75 0 0 23.3 0.560 53 1
4 95 60 32 0 35.4 0.284 28 1
0 126 86 27 120 27.4 0.515 21 1
8 65 72 23 0 32.0 0.600 42 1
2 99 60 17 160 36.6 0.453 21 1
1 102 74 0 0 39.5 0.293 42 2
11 120 80 37 150 42.3 0.785 48 2
3 102 44 20 94 30.8 0.400 26 1
46
1 109 58 18 116 28.5 0.219 22 1
9 140 94 0 0 32.7 0.734 45 2
13 153 88 37 140 40.6 1.174 39 1
12 100 84 33 105 30.0 0.488 46 1
1 147 94 41 0 49.3 0.358 27 2
1 81 74 41 57 46.3 1.096 32 1
3 187 70 22 200 36.4 0.408 36 2
6 162 62 0 0 24.3 0.178 50 2
4 136 70 0 0 31.2 1.182 22 2
1 121 78 39 74 39.0 0.261 28 1
3 108 62 24 0 26.0 0.223 25 1
0 181 88 44 510 43.3 0.222 26 2
8 154 78 32 0 32.4 0.443 45 2
1 128 88 39 110 36.5 1.057 37 2
7 137 90 41 0 32.0 0.391 39 1
0 123 72 0 0 36.3 0.258 52 2
1 106 76 0 0 37.5 0.197 26 1
6 190 92 0 0 35.5 0.278 66 2
2 88 58 26 16 28.4 0.766 22 1
9 170 74 31 0 44.0 0.403 43 2
9 89 62 0 0 22.5 0.142 33 1
10 101 76 48 180 32.9 0.171 63 1
2 122 70 27 0 36.8 0.340 27 1
5 121 72 23 112 26.2 0.245 30 1
1 126 60 0 0 30.1 0.349 47 2
1 93 70 31 0 30.4 0.315 23 1
47
ALGOR.H
/************************************************************************
/
/*Declaracion de las estructuras de datos para messy y de las funciones
*/
/************************************************************************
/
// Archivos que se usan:
// InputFile son los datos de entrada con los que entrene la red
// OutFile es el archivo que creo durante la ejecucion del programa que
//
contiene el reporte y guarda los resultados que voy generando
// SalFile es donde se guardan las salidas del mejor individuo
// Aciertos guarda los aciertos y errores de todos los individuos
char OutFile[55]= "/home/alumnos/trejo/bd/iris/reporte.dat",
InputFile[55]="/home/alumnos/trejo/bd/iris/iris70.dat",
Datprue[55]= "/home/alumnos/trejo/bd/iris/iris30.dat",
SalFile[55]= "/home/alumnos/trejo/bd/iris/Sal1.dat" ,
SalFilebp[55]="/home/alumnos/trejo/bd/iris/Salbp.dat" ,
SalFilep[55]= "/home/alumnos/trejo/bd/iris/Salp.dat" ,
PesosFile[55]="/home/alumnos/trejo/bd/iris/pesosfin.dat",
Salprue[55]= "/home/alumnos/trejo/bd/iris/salprue.dat",
Salpruead[55]="/home/alumnos/trejo/bd/iris/salpruead.dat",
Salbpent[50]= "/home/alumnos/trejo/bd/iris/salbpent.dat",
Aciertos[55]= "/home/alumnos/trejo/bd/iris/aciertos.dat" ;
int
fitness_aciertos=0; //var. que contabilizan aciertos y errores
long
totaldepruebas=0;
int conta=1;
int cont=0; //son var. para escribir solo las salidas del ultimo
individuo
float
float
float
float
PELIMIN= 1.0;
// probabilidad de eliminacion de un nodo 1
PADIC=1.0;
// probabilidad de adicionar un nodo 0.4
sigma=1; //se utiliza al hacer la mutaci¢n en randval1
PMUTNODO=0.8; // probabilidad de mutacion de un nodo
// Apuntadores a los archivos
FILE *out, *in, *sal, *salbp,*ac, *datp, *salprue, *salpruead, *salp,
*pesos, *salbpen;
#define
#define
NENT
NSAL
4
3
// Nodos de entrada, no cuenta el sesgo
// Nodos de salida
#define
ocultos
#define
#define
#define
MaxSize 7 // max. tama¤o de un cromosoma, minimo es 3, nodos
POPSIZE 6
//tama¤o de la poblacion
MAXGENS 400
// numero de generaciones
NPROC 5 //NUMERO DE PROCESOS A SER CREADOS
#define PXOVER 0.15
// probabilidad de cruzamiento 0.9
#define PMUTATION 0.8 // probabilidad de mutacion
#define n
0.1; // raz¢n de aprendizaje (se ocupa en el
backprop.)
#define alfa
0.1 //ctes. para el error tipo d
#define beta
0.2
#define ListaVaciaP (Procesador == NULL)
48
#define
ListaVaciaG (Poblaciones == NULL)
float
vector_pesos[(NSAL+NENT)*MaxSize];
float
SalidaDeseada[NSAL];
float
f_transf[5*MaxSize]; /* funci¢n de transferencia*/
float
f_t[5*MaxSize];
float
Salida[NSAL];
float
Dif[NSAL];
//diferencia entre La salida deseada y la real
float
d[MaxSize];
float
docul[MaxSize];
int
generacion;
int ArID[NPROC];
typedef struct Nodo Nodo;
typedef struct Genotype Genotype;
typedef struct Proceso Proceso;
struct Nodo
{
float peso[NENT+1+NSAL];
Nodo *Sig_vert;
};
struct Genotype
{
float
sesgo[NSAL];
int
nmax;
float
fitness;
float
rfitness;
float
cfitness;
Genotype* sig_gen;
Nodo*
chrom;
};
struct Proceso
{
int id;
int num_ind;
Genotype* ap_pob;
Proceso* sig_proc;
};
/* Funciones.*/
void error(void)
{
perror("error: insuficiente espacio de memoria.");
exit(1);
}
Nodo *new_Nodo()
{
Nodo *q = (Nodo *)malloc(sizeof(Nodo));
if (!q) error();
q->Sig_vert=NULL;
return q;
}
Genotype *new_Gen()
49
{
Genotype *q = (Genotype *)malloc(sizeof(Genotype));
if (!q) error();
q->sig_gen=NULL;
q->chrom =NULL;
return q;
}
Proceso *new_Proc()
{
Proceso *q = (Proceso *)malloc(sizeof(Proceso));
if (!q) error();
q->sig_proc=NULL;
q->ap_pob =NULL;
return q;
}
// Prototipos de las funciones:
void
inicializa(Genotype **, int);
Nodo* crea_lista(int ocultos);
void
Evaluared(Genotype **, int, FILE *);
void
Evaluanodo ( Genotype **, FILE * );
float Calcula(Nodo*, int, int, Genotype *,FILE *);
float Calculap(Nodo*, int, int,Genotype *,FILE *);
int
ReadFact(FILE*,float *);
void
Calculaf_net(Nodo*,int,float *);
void
Saca_pesos(Nodo*,int,int);
float multiplica(float *A,float *B, int);
float Sigmoide(float);
void
Calcula_salida(Nodo*, int,int,struct Genotype *);
float Calculaerror(FILE*);
float Calculaerror1(FILE *);
void
Saca_pesos2(Nodo*, int,int,int,struct Genotype *);
float Calcula_error(void);
void
keep_the_best(Genotype **, int);
void
CopyGene(Genotype *, int,Genotype **);
void
CopyGeneFD(Genotype *, int,Genotype **, int);
Nodo* Copia_lista(Genotype *A,int);
void
Select(Genotype **, int );
void
ini_newpopul(Genotype **, int);
void
fin(Genotype **);
void
mutatenode( Genotype ** );
float randval1(float);
void
Mutacion( Genotype **, int, int,FILE *);
void
Salvapesos( Genotype *);
void
Salvapesosad(void);
float Calculaprop(Nodo*, int, int, Genotype *);
void
Retroprop(Nodo* , int , int, Genotype *,float *);
void
Caldelta_sal();
void
Modificapesos_sesgo(int, Genotype *);
void
Modificapesos(Nodo*,int);
void
Caldelta_oculta(Nodo*, int);
float Calculasumat(Nodo*);
void
Modificapesos1capa(Nodo*, int, float *);
void
Crea_Procesos (Proceso **, int);
void
Crea_Poblacion (Proceso **);
void
Tabla_Hash
(Proceso *);
50
/************************************************************************
****/
void Crea_Procesos(Proceso **Pro, int num_Proc)
{
int i;
Proceso *Procesador=*Pro;
Proceso *actual=Procesador,*q;
for (i=1;i<=num_Proc;i++)
{
if ( ListaVaciaP )
{
Procesador=new_Proc();
Procesador->id = ArID[i-1];
Procesador->num_ind = POPSIZE;
actual = Procesador;
}
else
{
q = new_Proc();
q->id = ArID[i-1];
q->num_ind = POPSIZE;
actual->sig_proc = q;
actual=actual->sig_proc;
}
}
*Pro=Procesador;
}
/*Visualizar la lista.*/
void Tabla_Hash(Proceso *Procesador)
{
Proceso *actual=Procesador;
Genotype *ap;
if (ListaVaciaP)
printf("Lista Vacia\n");
else
{
while(actual!=NULL)
{
printf ("Proceso con indentificador %d\n",actual->id);
ap = actual->ap_pob;
printf ("Individuos: %d\n",actual->num_ind);
if (ap==NULL)
printf("Lista vacia de individuos\n");
else
while ( ap!=NULL )
{
printf ("Dimension de cromosoma: %d\n",ap>nmax);
printf ("Fitness : %f\n",ap->fitness);
ap=ap->sig_gen;
}
actual=actual->sig_proc;
}
}
51
}
/************************************************************************
****/
/* Nombre de la funci¢n: inicializa
*/
/* Descripci¢n de la funci¢n:
*/
/* inicializa es una funci¢n que manda llamar a las funciones necesarias
*/
/* para ir creando la estructura que se va a manejar y tambien para irla
*/
/* inicializando, en este proceso se van inicializar los pesos de forma
*/
/* aleatoria al igual que los nodos ocultos
*/
/* Funciones que llama: crea_lista
*/
/* Funciones que la llaman:main
*/
/************************************************************************
****/
void inicializa(Genotype **pop, int num_ind)
{
Genotype *population=*pop;
Genotype *actual=population, *q;
int i,j,ocultos;
for(j=1; j<=num_ind; j++)
{
if ( population == NULL )
{
population = new_Gen();
//los nodos ocultos se inicializan aleatoriamente para
cada individuo
ocultos=rand()%MaxSize+1; //el rango va de 0 a MaxSize
for (i=0; i<NSAL;i++)
//inicializacion aleatoria de
los sesgos
population->sesgo[i]=((2*((rand()%1000)/1000.0))0.99); //el rango va
de -1 a 1
population->fitness = 0.0;
population->rfitness = 0.0;
population->cfitness = 0.0;
population->nmax=ocultos;
population->chrom=crea_lista(ocultos);
actual = population;
}
else
{
q = new_Gen();
//los nodos ocultos se inicializan aleatoriamente para
cada individuo
ocultos=rand()%MaxSize+1; //el rango va de 0 a MaxSize
for (i=0; i<NSAL;i++)
//inicializac. aleatoria de los
sesgos
52
q->sesgo[i]=((2*((rand()%1000)/1000.0))-0.99);
//el rango va de -1 a 1
q->fitness=0.0;
q->rfitness=0.0;
q->cfitness=0.0;
q->nmax=ocultos;
q->chrom=crea_lista(ocultos);
actual->sig_gen = q;
actual=actual->sig_gen;
}
}
//Inicializa el ultimo individuo
q = new_Gen();
for (i=0; i<NSAL;i++)
//inicializacion aleatoria de los sesgos
q->sesgo[i]=0.0;
q->fitness
= 0.0;
q->rfitness
= 0.0;
q->cfitness
= 0.0;
q->nmax
= 0;
actual->sig_gen = q;
actual = actual->sig_gen;
*pop = population;
}
/************************************************************************
****/
/* Nombre de la funci¢n: crea_lista
*/
/* Descripci¢n de la funci¢n:
*/
/* Se crea una lista ligada que representa cada elemento de la lista un
nodo*/
/* oculto de la red, a su vez cada nodo tiene un arreglo del tama¤o de
nodos*/
/* de entrada + 1 sesgo + nodos de salida y se inicializan los pesos de
*/
/* estos nodos con respecto al nodo oculto, ie, los pesos que le llegan y
*/
/* los que salen del nodo oculto se guardan en este arreglo, la
inicializac.*/
/* es aleatoria
*/
/* Funciones que llama:
*/
/* Funci¢n que la llama: inicializa
*/
/************************************************************************
****/
Nodo* crea_lista(int ocultos)
{
Nodo *Nodos_ocultos, *ap_lista, *Aux;
int i,j;
Nodos_ocultos=new_Nodo();
for (i=0;i<(NENT+1+NSAL); i++)
Nodos_ocultos->peso[i]=((2*((rand()%1000)/1000.0))-0.99);
53
ap_lista=Nodos_ocultos;
for (i=1;i<ocultos;i++)
{
Aux=new_Nodo();
for (j=0;j<NENT+1+NSAL; j++)
Aux->peso[j]=((2*((rand()%1000)/1000.0))-0.99);
ap_lista->Sig_vert=Aux;
ap_lista=Aux;
}
return(Nodos_ocultos);
}
/************************************************************************
****/
/* Nombre de la funci¢n. Evaluared
*/
/* Descripci¢n de la funci¢n:
*/
/* Se manda llamar a la funci¢n Calcula quien va a calcular el error de
la
*/
/* red y lo guarda como el fitness
*/
/* ap_nodo es un apuntador al nodo que apunta el inicio de la lista que
*/
/* representa a los nodos ocultos y ocultos me dice el tamaño de esa
lista
*/
/* Funciones que llama: Calcula
*/
/* Funciones que la llaman:main()
*/
/************************************************************************
****/
void Evaluared(Genotype **pop, int num_ind, FILE *salida)
{
Genotype *population = *pop;
Genotype *actual
= population;
Nodo* ap_nodo;
int i,ocultos;
for (i=1;i<=num_ind;i++)
{
ap_nodo=actual->chrom;
ocultos=actual->nmax;
actual->fitness=Calcula(ap_nodo,ocultos,i,actual,salida);
actual = actual->sig_gen;
}
*pop = population;
}
/************************************************************************
****/
/* Nombre de la funci¢n. Evaluanodo
*/
/* Descripci¢n de la funci¢n:
54
*/
/* Se manda llamar a la funci¢n Calcula quien va a calcular el error de
un
*/
/* nodo y lo guarda como el fitness
*/
/* ap_nodo es un apuntador al nodo que apunta al nodo que
*/
/* representa a los nodos ocultos y ocultos me dice el tamaño de esa
lista
*/
/* Funciones que llama: Calcula
*/
/* Funciones que la llaman:main()
*/
/************************************************************************
****/
void Evaluanodo( Genotype **pop,FILE *salida )
{
Genotype *poblacion = *pop;
Genotype *actual
= poblacion;
Nodo* ap_nodo;
int ocultos;
ap_nodo=actual->chrom;
ocultos=actual->nmax;
actual->fitness=Calcula(ap_nodo,ocultos,1,actual,salida);
*pop = poblacion;
}
/************************************************************************
****/
/* Nombre de la funci¢n: Calcula
*/
/* Descripci¢n de la funci¢n:
*/
/* Calcula abre el archivo de datos manda llamar a ReadFact que saca los
*/
/* datos a un vector y manda llamar a las funciones necesarias para
*/
/* calcular el error de la red
*/
/* Funciones que llama: ReadFact,
Calculaf_net,Calcula_salida,calculaerror
*/
/* Funciones que la llaman: Evaluared
*/
/************************************************************************
****/
float Calcula(Nodo* ap_nodo,int ocultos, int k, Genotype *population,FILE
*salida)
{
float errort=0.0,e1=0.0,MSE=0.0,Vectors[NENT+1];
55
if ((in=fopen(InputFile,"r"))==NULL)
{
printf("Error al abrir el archivo de datos\n");
exit(1);
}
while( ReadFact(in,Vectors) )
{
Calculaf_net(ap_nodo,ocultos,Vectors);
Calcula_salida(ap_nodo,ocultos,k,population);
//Las siguientes tres lineas calculan sumatoria(y-d)^2
e1=Calculaerror1(salida);
MSE=MSE+e1;//float(MSE+e1);
}
if( MSE<0.01)
errort=100;
else
errort=1/MSE;//float(1/MSE);
fclose(in);
return(errort);
error b
}
/************************************************************************
****/
/* Nombre de la funci¢n:ReadFact
*/
/* Descripci¢n de la funci¢n:
*/
/* Saca la informacion del archivo de datos y la coloca en dos vectores
*/
/* un vector de nombre Vectors tiene la info. de los atributos, el otro
*/
/* se llama SalidaDeseada y tiene la clase de los atributos seleccionados
*/
/* Funciones que llama:
*/
/* Funciones que la llaman:Calcula
*/
/************************************************************************
****/
int ReadFact(FILE *f,float *Vectors)
{
int i;
// Lee entradas
Vectors[0]=1;
//sesgo de la entrada
for( i=1; i<NENT+1; i++ )
{
if( feof( f ) )
return 0;
fscanf( f, " %f ", &(Vectors[i]) );
}
// Lee salidas deseadas
for( i=0; i<NSAL; i++ )
{
if( feof( f ) )
return 0;
fscanf( f, " %f ", &(SalidaDeseada[i]) );
56
}
return 1;
}
/************************************************************************
****/
/* Nombre de la funci¢n: Calculaf_net
*/
/* Descripci¢n de la funci¢n:
*/
/* Calcula la funci¢n de transferencia de la red, primero saca los pesos
*/
/* del nodo oculto correspondiente en un vector, luego los multiplica con
el*/
/* vector de los datos, para sacar la sumatoria del producto de pesos por
*/
/* los datos de entrada y finalmente se le aplica la funci¢n de
transferen*/
/* cia, que en este caso es la sigmoide para ir llenando el vector con
estos*/
/* resultados
*/
/* Los parametros que recibe son: ap_nodo que apunta a la lista ligada de
*/
/* nodos ocultos y ocultos que dice el tama¤o de la lista
*/
/* Funciones que llama:Saca_pesos, multiplica, Sigmoide
*/
/* Funciones que la llaman: Calcula
*/
/************************************************************************
****/
void Calculaf_net(Nodo* ap_nodo,int ocultos,float *Vectors)
{
Nodo *apunta_nodo;
float net;
int i;
f_transf[0]=1; //Guardo el sesgo de la segunda capa
f_t[0]=1;
apunta_nodo=ap_nodo;
for (i=0; i<ocultos;i++)
{
Saca_pesos(apunta_nodo,0,NENT+1);
net=multiplica(vector_pesos, Vectors,NENT+1);
f_transf[i+1]=Sigmoide(net);
f_t[i+1]=f_transf[i+1];
apunta_nodo=apunta_nodo->Sig_vert;
}
}
/************************************************************************
****/
/* Nombre de la funci¢n: Saca_pesos
*/
/* Descripci¢n de la funci¢n:
57
*/
/* Saca los pesos de entrada de un nodo oculto en espec¡fico en un vector
*/
/* Los parametros que recibe son: ap_nodo que dice de que nodo se van a
*/
/* sacar los pesos para guardarlos en el arreglo vector_pesos
*/
/* y los limites que indican de que posici¢n del arreglo a cual posici¢n
se
*/
/* van sacar
*/
/* Funci¢n que llama:
*/
/* Funci¢n que la llama:Calculaf_net
*/
/************************************************************************
****/
void Saca_pesos(Nodo* ap_nodo,int lim_inf, int lim_sup)
{
Nodo* apunta_nodo=ap_nodo;
int i,k=0;
for (i=lim_inf; i<lim_sup; i++)
{
vector_pesos[k]=apunta_nodo->peso[i];
k++;
}
}
/************************************************************************
****/
/* Nombre de la funci¢n. multiplica
*/
/* Descripci¢n de la funci¢n:
*/
/* Multiplica los pesos por los datos de entrada y realiza la sumatoria
de
*/
/* estos productos
*/
/* Funciones que llama:
*/
/* Funciones que la llaman: Calculaf_net, Calcula_salida
*/
/************************************************************************
****/
float multiplica(float *A,float *B, int limite)
{
int i;
float sumatoria=0.0;
for(i=0; i<limite;i++)
sumatoria+=A[i]*B[i];
return(sumatoria);
}
58
/************************************************************************
****/
/* Nombre de la funci¢n: Sigmoide
*/
/* Descripci¢n de la funci¢n:
*/
/* Evalua la funci¢n de transferencia para evaluar la red neuronal
*/
/* Funci¢n que llama:
*/
/* Funci¢n que la llama:Calcula
*/
/************************************************************************
****/
float Sigmoide(float u)
{
float sol;
int a=-1;
sol=1/(1+exp(a*u));
return(sol);
}
/************************************************************************
****/
/* Nombre de la funci¢n: Calcula_salida
*/
/* Descripci¢n de la funci¢n:
*/
/* ap_nodo es un apuntador a la lista ligada de nodos ocultos, ocultos
*/
/* dice el tama¤o de la lista, k, dice que individuo estoy evaluando
*/
/* Saca_pesos2 saca los pesos que salen de los nodos ocultos a los de
*/
/* salida, multiplica hace el calculo de la sumatoria del producto de los
*/
/* pesos por la entrada, de la capa oculta hacia la salida y Salida
*/
/* es un vector que guarda el resultado de evaluar toda la red para cada
*/
/* nodo de salida
*/
/* Funciones que llama: Saca_pesos2, multiplica
*/
/* Funciones que la llama: Calcula
*/
/************************************************************************
****/
void Calcula_salida( Nodo* ap_nodo, int ocultos, int k, Genotype
*population)
{
Nodo* apunta_nodo;
int i;
float net;
59
for (i=0; i<NSAL; i++)
{
apunta_nodo=ap_nodo;
Saca_pesos2(apunta_nodo, i+1, ocultos,k,population);
net=multiplica(vector_pesos, f_transf,ocultos+1);
Salida[i]=Sigmoide(net);
}
}
/************************************************************************
****/
/* Nombre de la funci¢n: Saca_pesos2
*/
/* Descripci¢n de la funci¢n:
*/
/* k nos dice que individuo estoy evaluando y por lo tanto por medio de k
*/
/* saco los sesgos que le corresponden de la capa intermedia a las
salidas
*/
/* en vector_pesos guardo los pesos de entrada para cada salida, ie, los
de
*/
/* salida de cada nodo oculto, cont me dice a partir de cual posicion
dentro*/
/* del arreglo estan los pesos de salida de cada nodo oculto
*/
/* Funciones que llama:
*/
/* Funciones que la llaman: Calcula_salida
*/
/************************************************************************
****/
void Saca_pesos2( Nodo* apunta_nodo,int cont, int ocultos,int k,Genotype
*population)
{
Nodo* ap_nodo=apunta_nodo;
int i;
vector_pesos[0]=population->sesgo[cont-1]; //peso del sesgo
for (i=0; i<ocultos; i++)
{
vector_pesos[i+1]=ap_nodo->peso[NENT+cont];
ap_nodo=ap_nodo->Sig_vert;
}
}
/************************************************************************
****/
/* Nombre de la funci¢n: Calculaerror
*/
/* Descripci¢n de la funci¢n:
*/
/* Calcula el error de la siguiente manera: la sumatoria
*/
60
/* la diferencia de la salida deseada menos la salida de la red
*/
/* esta funci¢n regresa un real que al final se divide entre el n£mero de
*/
/* patrones totales que existen
*/
/* Funciones que llama:
*/
/* Funciones que la llaman:Calcula
*/
/************************************************************************
****/
float Calculaerror(FILE *salida)
{
float e=0.0;
int i,aux=0;
for (i=0; i<NSAL; i++)
{
e=e+fabs(SalidaDeseada[i]-Salida[i]);
Dif[i]=fabs(SalidaDeseada[i]-Salida[i]);
if (conta==0)
{
if (cont<NSAL)
{
fprintf(salida,"%f ",Salida[i]);
cont++;
}
else
if (cont>NSAL-1)
{
cont=1;
fprintf(salida,"\n");
fprintf(salida, "%f ", Salida[i]);
}
}
if (Dif[i]<=0.45)
aux=aux+1;
}
if (aux==NSAL)
fitness_aciertos=fitness_aciertos+1;
totaldepruebas=totaldepruebas+1;
return(e);
}
/************************************************************************
****/
/* Nombre de la funci¢n: Calculaerror1
*/
/* Descripci¢n de la funci¢n:
*/
/* Calcula el error de la siguiente manera: la sumatoria del cuadrado de
*/
/* la diferencia de la salida deseada menos la salida de la red
*/
/* esta funci¢n regresa un real que al final se divide entre el n£mero de
61
*/
/* patrones totales que existen
*/
/* Funciones que llama:
*/
/* Funciones que la llaman:Calcula
*/
/************************************************************************
****/
float Calculaerror1(FILE *salida)
{
float e1=0.0;
int i,aux=0;
for (i=0; i<NSAL; i++)
{
e1+=fabs ((SalidaDeseada[i]-Salida[i])*(SalidaDeseada[i]-Salida[i])
);
Dif[i]=fabs(SalidaDeseada[i]-Salida[i]);
if (conta==0)
{
if (cont<NSAL)
{
fprintf(salida,"%f ",Salida[i]);
cont++;
}
else
if (cont>NSAL-1)
{
cont=1;
fprintf(salida,"\n");
fprintf(salida, "%f ", Salida[i]);
}
}
if (Dif[i]<=0.49)
aux=aux+1;
}
if (aux==NSAL)
fitness_aciertos=fitness_aciertos+1;
totaldepruebas=totaldepruebas+1;
return(e1);
}
/************************************************************************
****/
/* Nombre de la funci¢n: keep_the_best
*/
/* Descripci¢n de la funci¢n:
*/
/* Encuentra el mejor individuo de la poblacion buscando el de menor
*/
/* fitness, el fitness es el error cuadratico y manda llamar CopyGene
para
*/
/* copiar el mejor individuo en la ultima casilla de la poblaci¢n
*/
62
/* Funcines que llama: CopyGene
*/
/* Funciones que la llaman: main
*/
/************************************************************************
****/
void keep_the_best(Genotype **pop, int num_ind)
{
Genotype *actual = *pop;
Genotype *population = actual, *anterior = actual;
float min = population->fitness;
int el_mejor=0,mem;
//indice del mejor individuo de la poblacion
population = population->sig_gen;
for (mem = 1; mem < num_ind; mem++)
{
if (population->fitness > min)
{
el_mejor = mem;
min = population->fitness;
}
population = population->sig_gen;
}
// una vez encontrado el mejor individuo copia los genes
CopyGene(anterior,el_mejor,&population);
*pop = actual;
}
/************************************************************************
***/
/* Nombre de la funci¢n: CopyGene
*/
/* Descripci¢n de la funci¢n:
*/
/* copia un dindividuo de una casilla del vector a otra o de un vector
*/
/* poblaci¢n a otro vector nueva poblaci¢n, A y B son vectores donde A es
*/
/* el vector fuente y B el destino y fuente dice la posici¢n del
individuo
*/
/* que se va a copiar del vector A al vector B en la posisci¢n destino
*/
/* Funciones que llama: Copia_lista
*/
/* Funciones que la llaman:keep_the_best, select, elitist
*/
/************************************************************************
***/
void CopyGene(Genotype *A, int fuente, Genotype **Be)
{
Genotype *b = *Be;
Genotype *B = b;
int i,ocultos;
for (i=1;i<=fuente;i++)
63
A=A->sig_gen;
for (i=0; i<NSAL;i++)
B->sesgo[i]=A->sesgo[i];
B->fitness=A->fitness;
B->rfitness=A->rfitness;
B->cfitness=A->cfitness;
B->nmax=A->nmax;
ocultos=B->nmax;
B->chrom=Copia_lista(A,ocultos);
*Be = b;
}
void CopyGeneFD(Genotype *A, int fuente, Genotype **Be, int destino)
{
Genotype *b = *Be;
Genotype *B = b;
int i,ocultos;
for (i=1;i<=fuente;i++)
A=A->sig_gen;
for (i=1;i<=destino;i++)
B=B->sig_gen;
for (i=0; i<NSAL;i++)
B->sesgo[i]=A->sesgo[i];
B->fitness=A->fitness;
B->rfitness=A->rfitness;
B->cfitness=A->cfitness;
B->nmax=A->nmax;
ocultos=B->nmax;
B->chrom=Copia_lista(A,ocultos);
*Be = b;
}
/************************************************************************
****/
/* Nombre de la funci¢n: Copia_lista
*/
/* Descripci¢n de la funci¢n:
*/
/* Los nodos ocultos se van ligando en una lista y cada nodo tiene un
*/
/* vector de pesos que le correponde, copia_lista copia esta lista, del
*/
/* vector poblaci¢n A, copia el individuo el_mejor y ocultos dice de que
*/
/* tama¤o es la lista, para cada individuo el tama¤o de la lista cambia
*/
/* Funciones que llama:
*/
/* Funciones que la llaman:Copy_Gene
*/
/************************************************************************
****/
Nodo* Copia_lista(Genotype *A, int ocultos)
{
64
Nodo *apunta_nodo,*Nodos_ocultos,*ap_lista,*Aux;
int i,j;
apunta_nodo=A->chrom;
Nodos_ocultos=new_Nodo();
for (i=0;i<(NENT+1+NSAL); i++)
Nodos_ocultos->peso[i]=apunta_nodo->peso[i];
ap_lista=Nodos_ocultos;
apunta_nodo=apunta_nodo->Sig_vert;
for (i=1;i<ocultos;i++)
{
Aux=new_Nodo();
for (j=0;j<NENT+1+NSAL; j++)
Aux->peso[j]=apunta_nodo->peso[j];
ap_lista->Sig_vert=Aux;
ap_lista=Aux;
apunta_nodo=apunta_nodo->Sig_vert;
}
return(Nodos_ocultos);
}
/************************************************************************
*****/
/* Nombre de la funci¢n: Reporte
*/
/* Descripci¢n de la funci¢n:
*/
/* Reporta el desarrollo de la simulaci¢n, por cada generaci¢n guarda en
el
*/
/* archivo de salida la siguiente informaci¢n:
*/
/* generacion,mejor_val=mejor fitness,avg=promedio del
fitness,stddev=desviac*/
/* standar del fitness,poblacion[TAMPOB]->nmax=num. m x. de nodos del
ult.
*/
/* individuo, es decir, del mejor individuo
*/
/* Funciones que llama:
*/
/* Funci¢n que la llama: main
*/
/************************************************************************
*****/
void Reporte(Genotype *poblacion)
{
int i;
float mejor_val;
/* mejor fitness */
float prom;
/* promedio de fitness de la pob.*/
float desv_std;
/* desviacion standar de fitness */
float sum_cuad;
/* suma de cuadrados para el calc. std*/
float cuad_sum;
/* el cuadtrado de la suma para el calc. std */
float sum;
/* total pop fitness */
float a;
65
sum = 0.0;
sum_cuad = 0.0;
while (poblacion->sig_gen!=NULL)
{
sum += (float)poblacion->fitness;
sum_cuad += pow((float)poblacion->fitness,2) ;
poblacion=poblacion->sig_gen;
}
prom = sum/(float)POPSIZE;
cuad_sum = prom * prom * (float)POPSIZE;
a=(sum_cuad-cuad_sum)/(POPSIZE - 1);
desv_std = sqrt(abs(a));
mejor_val = (float)poblacion->fitness;
fprintf(out,"\n%d
%6.5f
%6.5f
%6.5f
%d\n
",generacion,mejor_val,prom,desv_std,poblacion->nmax);
}
/************************************************************************
****/
/* Nombre de la funci¢n: select
*/
/* Descripci¢n de la funci¢n:
*/
/* Encuentra el fitness total de la poblaci¢n sumando todos los fitness
*/
/* menos el ultimo, calcula el fitness relativo de cada individuo
dividiendo*/
/* su fitness entre el fitness total, con el fitness relativo calcula el
*/
/* fitness acumulado y con el fitness acumulado se obtiene la proporci¢n
de
*/
/* cada cromosoma y se trata de seleccionar por lo general al mejor
individ.*/
/* sin descartar la posibilidad de guardar uno que otro peor individuo
*/
/* Funciones que llama:ini_newpopul,fin, CopyGene
*/
/* Funci¢n que la llama: main
*/
/************************************************************************
****/
void Select(Genotype **pop, int num_ind )
{
Genotype *popul = *pop;
Genotype *population = popul, *popu = popul;
Genotype *newp=NULL, *newpopulation=NULL;
int i,j;
float sum = 0,p;
ini_newpopul ( &newp,num_ind );
newpopulation = newp;
// Encuentra el fitness total de la poblacion
66
for (i=1; i<=num_ind; i++)
{
sum += population->fitness;
population = population -> sig_gen;
}
population = popul;
// calcula el fitness relativo
for (i=1; i<=num_ind; i++)
{
population->rfitness = (population->fitness)/sum;
population = population -> sig_gen;
}
population = popul;
popu = popul;
population->cfitness = population->rfitness;
popu->cfitness = popu->rfitness;
population = population -> sig_gen;
// calcula fitness acumulado
for (i=1; i<num_ind; i++)
{
population->cfitness = popu->cfitness + population->rfitness;
population = population -> sig_gen;
popu = popu->sig_gen;
}
// selecciona al individ. sobreviviente usando el fitness acumulado
population = popul;
popu = popul;
for (i=1;i<=num_ind;i++)
{
p = rand()%1000/1000.0;
if (p < population->cfitness)
CopyGene(popu,0,&newpopulation);
else
for (j=1; j<=num_ind; j++)
{
if (p >= population->cfitness && p < population>sig_gen->cfitness)
CopyGene(popu,j+1,&newpopulation);
population = population->sig_gen;
}
population = popul;
newpopulation = newpopulation -> sig_gen;
}
population = newp;
fin ( &newp );
*pop = popul;
}
/************************************************************************
****/
/* Nombre de la funci¢n: ini_newpopul
*/
/* Descripci¢n de la funci¢n:
*/
/* Inicializa un vector como el de population llamado newpopulation y
sirve
67
*/
/* como auxiliar para hacer copias de los individuos seg£n los procesos
*/
/* donde sea llamado
*/
/* Funci¢n que llama:
*/
/* Funciones que la llaman: select
*/
/************************************************************************
****/
void ini_newpopul(Genotype **pop, int num_ind)
{
Genotype *population=*pop;
Genotype *actual=population, *q;
int i,j,ocultos;
for(j=0; j<=num_ind; j++)
{
if ( population == NULL )
{
population = new_Gen();
for (i=0; i<NSAL;i++)
population->sesgo[i]=0.0;
population->fitness=0.0;
population->rfitness=0.0;
population->cfitness=0.0;
population->nmax=ocultos;
population->chrom=NULL;
population->sig_gen = NULL;
actual = population;
}
else
{
q = new_Gen();
for (i=0; i<NSAL;i++)
q->sesgo[i]=0.0;
q->fitness=0.0;
q->rfitness=0.0;
q->cfitness=0.0;
q->nmax=ocultos;
q->chrom=NULL;
q->sig_gen = NULL;
actual->sig_gen = q;
actual=actual->sig_gen;
}
}
*pop = population;
}
/************************************************************************
****/
/* Nombre de la funci¢n: fin
*/
/* Descripci¢n de la funci¢n:
*/
68
/* Elimina todo el individuo de la posici¢n indice del vector A, esto es,
*/
/* pone en ceros los valores reales y borra la lista de los nodos ocultos
*/
/* dejando este campo en NULL
*/
/* Funci¢n que llama:
*/
/* Funciones que la llaman: select, elitist
*/
/************************************************************************
****/
void fin (Genotype **a)
{
Genotype *aa = *a;
Genotype *A = aa,*w;
Nodo* ap_nodo, *q;
while ( A!=NULL )
{
w=A;
ap_nodo = A->chrom;
while ( ap_nodo!=NULL )
{
q=ap_nodo;
ap_nodo=ap_nodo->Sig_vert;
free(q);
}
A=A->sig_gen;
free(w);
}
A=NULL;
*a = aa;
}
/************************************************************************
****/
/* Nombre de la funci¢n: mutatenode
*/
/* Descripci¢n de la funci¢n:
*/
/* Se selecciona cuales nodos tendra sus pesos mutados
*/
/* usando una "Random
gaussian mutation"
*/
/* Funciones que llama: randval1
*/
/* Funciones que la llaman: main
*/
/************************************************************************
****/
void mutatenode( Genotype **pop )
{
Genotype *actual = *pop;
Genotype *population = actual;
int j;
69
float x,peso,sesgo=1;
Nodo* ap_nodo;
for (j=0;j<NSAL;j++)
{
x=rand()%1000/1000.0;
if (x < PMUTNODO)
//recorre los sesgos de cada
individuo
{
sesgo=population->sesgo[j];
population->sesgo[j]=randval1(sesgo);
}
}
ap_nodo = population->chrom;
while (ap_nodo != NULL) //recorre a todos los nodos ocultos de un
individ.
{
x = rand()%1000/1000.0;
if (x < PMUTNODO)
{
for (j=0;j<NENT+1+NSAL; j++)
{
peso=ap_nodo->peso[j];
ap_nodo->peso[j] = randval1(peso);
}
}
ap_nodo=ap_nodo->Sig_vert;
}
*pop = actual;
}
/************************************************************************
****/
/* Nombre de la funci¢n: randval1
*/
/* Descripci¢n de la funci¢n:
*/
/* Se calcula una aproximaci¢n Gaussiana, este es el valor de la mutaci¢n
*/
/* que se aplica, es decir, el peso seleccionado para mutarlo, se cambia
por*/
/* este valor, el parametro value es el peso que se va a mutar (o
cambiar)
*/
/* Funciones que llama:
*/
/* Funciones que la llaman: mutate,mutatenode
*/
/************************************************************************
****/
float randval1(float value)
{
int i;
float val=0;
for (i = 0; i < 12; i++)
val += (float)((rand()%1000)/1000.0);
70
val= value+sigma*(val-6);
return (val);
}
/************************************************************************
****/
/* Nombre de la funcion: Mutacion
*/
/* Descripcion de la funcion:
*/
/* Hace una copia de cada elemento de la lista mientras la recorre,
aplica
*/
/* la mutacion y evalua el nodo copiado, si el fitness resultante de la
*/
/* copia es mejor lo sustituye sino lo deja como estaba.
*/
/* Funciones que llama: CopyGene, mutatenode, Evaluanodo
*/
/* Funcion de la llama: Hello_Other
*/
/************************************************************************
****/
void Mutacion ( Genotype **pop, int ind, int gene,FILE *salida )
{
Genotype *actual = *pop;
Genotype *poblacion = actual,*q,*r;
while ( poblacion->sig_gen != NULL )
{
q = new_Gen();
CopyGene ( poblacion,0,&q );
mutatenode ( &q );
Evaluanodo ( &q,salida );
//SI EL NUEVO NODO CREADO ES MEJOR LO REEMPLAZA, SINO LO DEJA
COMO ESTABA
if ( q->fitness > poblacion->fitness )
CopyGene ( q,0,&poblacion );
poblacion = poblacion->sig_gen;
free(q);
}
sigma=1-(gene/MAXGENS);
PMUTNODO=1-(gene/MAXGENS);
*pop=actual;
}
/************************************************************************
****/
/* Nombre de la funci¢n: Salvapesos
*/
/* Descripci¢n de la funci¢n:
*/
/* Copia los pesos del mejor individuo de todas las generaciones asi como
el*/
/* resto de sus datos
*/
71
/* Funciones que llama:
*/
/* Funciones que la llaman: main
*/
/************************************************************************
****/
void Salvapesos(Genotype *pop)
{
Genotype *population = pop;
int i,j;
Nodo* Aux;
while ( population->sig_gen != NULL )
population = population->sig_gen;
fprintf(out,"\nindividuo:\n");
for (i=0; i<NSAL;i++)
fprintf(out, "sesgo
%f\n",population->sesgo[i]);
fprintf(out, "fitness
%f\n", population->fitness);
fprintf(out, "rfitness %f\n", population->rfitness);
fprintf(out, "cfitness %f\n", population->cfitness);
fprintf(out, "nmax
%d\n", population->nmax);
fprintf(out, "pesos\n");
Aux=population->chrom;
for (i=0;i<population->nmax;i++)
{
for (j=0;j<NENT+1+NSAL; j++)
fprintf(out,"%f\n", Aux->peso[j]);
fprintf(out,"\n");
Aux=Aux->Sig_vert;
}
}
/************************************************************************
***/
/*Nombre de la funci¢n: Retroprop
*/
/*Descripci¢n de la funci¢n:
*/
/*Modifica los pesos de atr s hacia delante utilizando el backpropagation
*/
/*sin momento, de los par metros que recibe, k indica a que individuo me
*/
/*refiero
*/
/*Funci¢n que la llama:main()
*/
/************************************************************************
***/
void Retroprop(Nodo* ap_nodo, int ocultos, int k,Genotype *population,
float
*Vector)
{
Caldelta_sal();
Modificapesos_sesgo(k,population);
Caldelta_oculta(ap_nodo, ocultos);
Modificapesos(ap_nodo,ocultos);
Modificapesos1capa(ap_nodo,ocultos,Vector);
72
}
/************************************************************************
/
/*Nombre de la funci¢n: Caldelta_sal
*/
/*Descripci¢n de la funci¢n:
*/
/*Calcula una d=(Deseada-Obtenida)*Obtenida*(1-Obtenida)
*/
/*Funci¢n que la llama:Backprop
*/
/************************************************************************
/
void Caldelta_sal()
{
int i;
for(i=0; i<NSAL; i++)
d[i]=Dif[i]*Salida[i]*(1-Salida[i]);
}
/************************************************************************
*/
/*Nombre de la funci¢n: Modificapesos_sesgo
*/
/*Descripci¢n de la funci¢n:
*/
/*funci¢n que la llama:Backprop
*/
/************************************************************************
/
void Modificapesos_sesgo(int k,struct Genotype *poblacion)
{
int i;
float aux,aux1;
for(i=0; i<NSAL; i++)
{
aux=d[i]*Salida[i]*n;
aux1=poblacion->sesgo[i];
poblacion->sesgo[i]=aux+aux1;
}
}
/************************************************************************
*/
/*Nombre de la funci¢n: Modificapesos
*/
/*Descripci¢n de la funci¢n:
*/
/*Funci¢n que la llama: Backprop
*/
73
/************************************************************************
*/
void Modificapesos(Nodo* ap_nodo, int ocultos)
{
Nodo* apunta_nodo=ap_nodo;
int i,j,k=0; //k es el n£mero de nodos de salida
float aux,aux1;
for(i=0;i<ocultos;i++)
{
for(j=NENT+1; j<NENT+NSAL+1; j++)
{
//con j solo tomo los pesos que van de la capa oculta a
la de salida
aux=apunta_nodo->peso[j];
aux1=d[k]*Salida[k]*n;
apunta_nodo->peso[j]=aux+aux1;
k++;
}
k=0;
apunta_nodo=apunta_nodo->Sig_vert;
}
}
/************************************************************************
**/
/*Nombre de la funci¢n: Caldelta_oculta
*/
/*Descripci¢n de la funci¢n: Calcula la funci¢n de transferencia para el
*/
/*backpropagation
*/
/*Funci¢n que la llama: Backprop
*/
/************************************************************************
**/
void Caldelta_oculta(Nodo* ap_nodo, int ocultos)
{
Nodo* apunta_nodo=ap_nodo;
int i;
float suma;
for(i=0; i<ocultos;i++)
{
suma=Calculasumat(apunta_nodo);
docul[i]=f_t[i+1]*(1-f_t[i+1])*suma;
apunta_nodo=apunta_nodo->Sig_vert;
}
}
/************************************************************************
**/
/*Nombre de la funci¢n: Calculasumat
*/
74
/*Descripci¢n de la funci¢n:
*/
/*Funci¢n que la llama: Calculad_interm
*/
/************************************************************************
**/
float Calculasumat(Nodo* apunta_nodo)
{
int j;
float suma=0;
Nodo* apunt_nodo=apunta_nodo;
for (j=0; j<NSAL;j++)
suma+=apunt_nodo->peso[NENT+1+j]*d[j];
return(suma);
}
/************************************************************************
**/
/*Nombre de la funci¢n: Modificapesos1cap
*/
/*Descripci¢n de la funci¢n:
*/
/*Funci¢n que la llama: Backprop
*/
/************************************************************************
**/
void Modificapesos1capa(Nodo* ap_nodo, int ocultos,float *Vector)
{
Nodo* inicio=ap_nodo;
Nodo* apunta_nodo=ap_nodo;
int i,j;
float aux,aux1;
for(j=0; j<NENT+1;j++)
{
for (i=0; i<ocultos; i++)
{
aux=docul[i]*Vector[j]*n;
//JLMR 1/junio/2001
apunta_nodo->peso[j]=apunta_nodo->peso[j]+aux;
apunta_nodo=apunta_nodo->Sig_vert;
}
apunta_nodo=inicio;
}
}
/************************************************************************
****/
/* Nombre de la funci¢n: Calculap
*/
/* Descripci¢n de la funci¢n:
*/
/* Calcula abre el archivo de datos de prueba manda llamar a LeeArch que
75
*/
/* saca los datos a un vector y manda llamar a las funciones necesarias
para*/
/* calcular el error de la red del Ultimo individuo
*/
/* Funciones que llama: LeeArch, Calculaf_net,Calcula_salida,Calculaerror
*/
/* Funciones que la llaman: hello
*/
/************************************************************************
****/
float Calculap(Nodo* ap_nodo,int ocultos, int k, Genotype
*population,FILE
*salida)
{
float errort=0.0,e1=0.0,MSE=0.0,Vectors[NENT+1];
if ((datp=fopen(Datprue,"r"))==NULL)
{
printf("Error al abrir el archivo de datos\n");
exit(1);
}
while( ReadFact(in,Vectors) )
{
Calculaf_net(ap_nodo,ocultos,Vectors);
Calcula_salida(ap_nodo,ocultos,k,population);
//Las siguientes tres lineas calculan sumatoria(y-d)^2
e1=Calculaerror1(salida);
MSE=MSE+e1;
}
if( MSE<0.01)
errort=100;
else
errort=1/MSE;
fclose(datp);
return(errort);
error b
}
ARCH.H
/*archivos de escritura*/
void Ab_arch_esc()
{
if ((out=fopen(OutFile,"w"))==NULL)
{
printf("Error al abrir el archivo de salida\n");
exit(1);
}
if ((sal=fopen(SalFile,"w"))==NULL)
{
printf("Error al abrir el archivo de salida\n");
exit(1);
}
if ((salbp=fopen(SalFilebp,"w"))==NULL)
{
76
printf("Error al abrir el archivo de salida con bp\n");
exit(1);
}
if ((salprue=fopen(Salprue,"w"))==NULL)
{
printf("Error al abrir el archivo de salida con los datos de
prueba\n");
exit(1);
}
if ((ac=fopen(Aciertos,"w"))==NULL)
{
printf("Error al abrir el archivo de aciertos\n");
exit(1);
}
if ((salp=fopen(SalFilep,"w"))==NULL)
{
printf("Error al abrir el archivo de salida con bp adicionado\n");
exit(1);
}
if ((salpruead=fopen(Salpruead,"w"))==NULL)
{
printf("Error al abrir el archivo de salida con bp adicionado\n");
exit(1);
}
if ((pesos=fopen(PesosFile,"w"))==NULL)
{
printf("Error al abrir el archivo de salida con bp adicionado\n");
exit(1);
}
}
void Cierrarch()
{
fclose(out);
fclose(sal);
fclose(salbp);
fclose(ac);
fclose(salprue);
fclose(salp);
fclose(pesos);
fclose(salpruead);
}
ENVIA.H
void EnviaPob( Genotype *population)
{
int i,j;//var. auxiliar para acceder a cada nodo oculto
Genotype *pop = population;
Nodo *aux=NULL;//apuntador auxiliar a cada nodo oculto
while (pop!=NULL)
{
pvm_pkint(&pop->nmax,1,1);//envio el # de nodos ocultos
77
pvm_pkfloat(&pop->fitness,1,1);//envio el fitness de este, el
mejor
individuo
pvm_pkfloat(pop->sesgo,NSAL,1);//envio el arreglo de sesgos
aux=pop->chrom;
for(i=0;i<pop->nmax;i++)
{
pvm_pkfloat(aux->peso,NENT+1+NSAL,1);
aux=aux->Sig_vert;
}
pop= pop->sig_gen;
}
}
void RcvPob(Genotype **Pro, int num_ind)
{
int nmax=0,i,ind;
Nodo *aux=NULL;
Nodo *nuevo=NULL;
Genotype *pop=*Pro;
Genotype *actual=pop, *q;
for(ind=0;ind<=num_ind;ind++)
{
if ( actual==NULL )
{
pop = new_Gen();
pvm_upkint(&nmax,1,1);
pop->nmax=nmax;
pvm_upkfloat(&pop->fitness,1,1);
pvm_upkfloat(pop->sesgo,NSAL,1);
pop->chrom=NULL;
for(i=0;i<nmax;i++)
{
nuevo=new_Nodo();
if(i==0)
pop->chrom=nuevo;
else
aux->Sig_vert=nuevo;
aux=nuevo;
pvm_upkfloat(aux->peso,NENT+1+NSAL,1);
aux->Sig_vert=NULL;
}
pop->sig_gen = NULL;
actual = pop;
}
else
{
q = new_Gen();
q->sig_gen = NULL;
pvm_upkint(&nmax,1,1);
q->nmax=nmax;
pvm_upkfloat(&q->fitness,1,1);
pvm_upkfloat(q->sesgo,NSAL,1);
q->chrom=NULL;
for(i=0;i<nmax;i++)
{
78
nuevo=new_Nodo();
if(i==0)
q->chrom=nuevo;
else
aux->Sig_vert=nuevo;
aux=nuevo;
pvm_upkfloat(aux->peso,NENT+1+NSAL,1);
aux->Sig_vert=NULL;
}
actual->sig_gen = q;
actual = actual->sig_gen;
}
}
*Pro = pop;
}
HELLO.C
static char rcsid[] =
"$Id: hello.c,v 1.2 1997/07/09 13:24:44 pvmsrc Exp $";
/************************************************************************
*****/
/*Implementacion de un programa evolutivo basado en cromosomas de
longitud
*/
/*variable, donde cada individuo de la poblaci¢n representa la
arquitectura
*/
/*de una red neuronal perceptron multicapa.
*/
/*Cada individuo tiene como informaci¢n a la de un conjunto de nodos
*/
/*ocultos, los cuales forman la arquitectura de una red, dicha
informaci¢n
*/
/*son sus respectivos pesos de entrada y salida de cada nodo oculto
*/
/************************************************************************
*****/
#include<time.h>
#include<sys/timeb.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include"Algor.h"
#include"pvm3.h"
#include"envia.h"
#include"Arch.h"
void CreaPobAleat(Proceso **Others)
{
int opcion=0; //opcion que determinara la accion del worker
int workers_running=0; //# de procesos worker creados
int i,cc;
79
Proceso *Procesador=*Others, *ap=NULL;
//SE CREAN LOS PROCESOS
for (i=0;i<NPROC;i++)
{
cc = pvm_spawn("hello_other", (char**)0, 0, "", 1, &ArID[i]);
if (cc!=1)
i--;
else
workers_running++;
}
printf("\tSE CREARON %d PROCESOS\n",workers_running);
//SE CONSTRUYE LA LISTA PARA LOS PROCESADORES
Crea_Procesos (&Procesador,workers_running);
ap = Procesador;
//ENVIA LA OPCION 0 A TODOS LOS PROCESOS LEVANTADOS
SATISFACTORIAMENTE
//PARA QUE CREEN SU POBLACION INICIAL
while ( ap != NULL )
{
pvm_initsend(PvmDataDefault);
pvm_pkint(&opcion,1,1);
pvm_pkint(&ap->num_ind,1,1);
pvm_send(ap->id,5);
ap = ap->sig_proc;
}
ap = Procesador;
//RECIBE LA POBLACION DE CADA PROCESO
while ( ap!=NULL )
{
pvm_recv(ap->id,0);
pvm_upkint (&ap->num_ind,1,1);
RcvPob(&ap->ap_pob, ap->num_ind);
ap = ap->sig_proc;
}
*Others=Procesador;
}
void DifundeMejores ( Genotype *poblacion, Proceso **Others, int MEJOR )
{
Proceso *Procesador=*Others;
Proceso *ap=Procesador;
int PEOR;
while ( ap!=NULL )
{
PEOR = Encuentra_Peor (ap->ap_pob);
CopyGeneFD (poblacion,MEJOR,&ap->ap_pob,PEOR);
ap = ap->sig_proc;
}
*Others=Procesador;
}
//OBTIENE LA LISTA CON LOS MEJORES INDIVIDUOS
void lista_mejores ( Genotype *pob,int num_ind,Genotype **Lista )
{
80
Genotype *lista=*Lista;
Genotype *poblacion=lista,*q;
if ( poblacion == NULL )
{
lista = new_Gen();
CopyGene (pob,num_ind,&lista);
}
else
{
while ( poblacion->sig_gen!=NULL )
poblacion = poblacion->sig_gen;
q = new_Gen();
CopyGene (pob,num_ind,&q);
poblacion->sig_gen = q;
}
*Lista=lista;
}
//REGRESA LA POSICION EN DONDE SE ENCUENTRA EL MEJOR DE LOS MEJORES
int Encuentra_Mejor (Genotype *pop)
{
int cont=1,mejor, posicion=1;
mejor = pop->fitness;
pop = pop->sig_gen;
while (pop->sig_gen!=NULL)
{
cont++;
if (pop->fitness > mejor )
{
mejor = pop->fitness;
posicion = cont;
}
pop = pop->sig_gen;
}
return posicion;
}
//REGRESA LA POSICION EN DONDE SE ENCUENTRA EL PEOR DE LOS MEJORES
int Encuentra_Peor (Genotype *pop)
{
int cont=1,peor, posicion=1;
peor = pop->fitness;
pop = pop->sig_gen;
while (pop->sig_gen!=NULL)
{
cont++;
if (pop->fitness < peor )
{
peor = pop->fitness;
posicion = cont;
}
pop = pop->sig_gen;
}
return posicion;
}
81
//Envia la opcion 2 a los workers, con el fin de que ellos modifiquen su
propia poblacion.
//Espera recibir todas las poblaciones ya modificadas.
Genotype *MutaPoblaciones(Proceso **Others)
{
Proceso *Procesador=*Others;
Proceso *ap=Procesador;
Genotype *population = NULL,*q;
int opcion=1,MEJOR;
//ENVIA LA OPCION 1 A CADA UNO DE LOS PRCESOS PARA QUE MUTEN SU
POBLACION
while ( ap != NULL )
{
pvm_initsend(PvmDataDefault);
pvm_pkint(&opcion,1,1);
pvm_pkint(&ap->num_ind,1,1);
pvm_send(ap->id,5);
ap = ap->sig_proc;
}
//RECIBE LA POBLACION DE CADA PROCESO, CREA UNA LISTA CON LOS
MEJORES
INDIVIDUOS
ap = Procesador;
while ( ap!=NULL )
{
pvm_recv(ap->id,1);
fin ( &ap->ap_pob );
ap->ap_pob=NULL;
pvm_upkint (&ap->num_ind,1,1);
RcvPob(&ap->ap_pob,ap->num_ind);
//CREA UNA LISTA CON LOS MEJORES INDIVIDUOS DE CADA POBLACION
lista_mejores(ap->ap_pob,ap->num_ind,&population);
ap = ap->sig_proc;
}
ap = Procesador;
//GUARDA EL MEJOR DE LOS MEJORES EN LA ULTIMA POSICION
lista_mejores(ap->ap_pob,ap->num_ind,&population);
keep_the_best(&population,NPROC);
//ENCUENTRA EL MEJOR DE LOS MEJORES
MEJOR = Encuentra_Mejor(population);
//DIFUNDE EL MEJOR INDIVIDUO DE LOS MEJORES Y LOS SUSTITUYE POR EL
PEOR
//DE CADA POBLACION
DifundeMejores(population,&ap,MEJOR);
*Others = Procesador;
return (population);
}
void DifundeMejor (Proceso **Others)
{
Proceso *Procesador=*Others,*ap=Procesador;
int opcion=2;
//ENVIA LA OPCION 2 A CADA UNO DE LOS PROCESOS PARA QUE
//RECIBAN LA NUEVA POBLACION CON LA QUE VAN A TRABAJAR,
82
//ESTA NUEVA POBLACION ES LA QUE TENIAN ANTERIORMENTE
//MAS LOS MEJORES INDIVIDUOS DE LOS DEMAS PROCESOS
while ( ap != NULL )
{
pvm_initsend(PvmDataDefault);
pvm_pkint(&opcion,1,1);
pvm_pkint(&ap->num_ind,1,1);
EnviaPob (ap->ap_pob);
pvm_send(ap->id,5);
ap = ap->sig_proc;
}
*Others=Procesador;
}
//Envia a cada proceso la opcion=valor, con el fin de que cada proceso
finalice su ejecucion
void Finaliza(Proceso *Others, int valor)
{
Proceso *ap = Others;
int opcion=valor;
while ( ap != NULL )
{
pvm_initsend(PvmDataRaw);
pvm_pkint(&opcion,1,1);
pvm_send(ap->id,5);
ap=ap->sig_proc;
}
}
void Cambio_Ent()
{
int cont=1;
float aux,auxi;
FILE *in,*out;
// Archivo donde esta la salida a analizar
//sal1iris.dat
char InputFile[50]= "/home/alumnos/trejo/bd/iris/Sal1.dat",
// Archivo donde estan los datos ya modificados, este
se genera aqui
OutFile[50]= "/home/alumnos/trejo/bd/iris/reporte.dat";
//Abro archivos de lectura y escritura
if ((in=fopen(InputFile,"r"))==NULL)
{
printf("Error al abrir el archivo de datos\n");
exit(1);
}
if ((out=fopen(OutFile,"w"))==NULL)
{
printf("Error al abrir el archivo de salida\n");
exit(1);
}
while (!feof(in))
{
fscanf( in, " %f ", &aux);
if (aux>=0.5) /*umbral de 0.5*/
83
aux=1;
else
aux=0;
if (cont==NSAL)
{
fprintf(out,"%f \n ",aux);
cont=1;
}
else
{
fprintf(out,"%f ",aux);
cont++;
}
}
fclose(in);
fclose(out);
}
void Analisis_Ent()
{
int i,contaux=0, aciertos=0, ejemplos=0,errores=0;
float aux, auxi;
FILE *sal,*mod;
//archivo donde estan los datos de salida, estas son
las puras clases
char SalFile[50]= "/home/alumnos/trejo/bd/iris/iris70c.dat",
// Archivo donde estan los datos ya modificados, archivo
creado en
cambio
ModFile[50]= "/home/alumnos/trejo/bd/iris/reporte.dat";
//Abro archivos de lectura
if ((sal=fopen(SalFile,"r"))==NULL)
{
printf("Error al abrir el archivo de datos de salida\n");
exit(1);
}
if ((mod=fopen(ModFile,"r"))==NULL)
{
printf("Error al abrir el archivo de datos modificados\n");
exit(1);
}
while (!feof(sal))
{
for (i=0; i<NSAL;i++)
{
fscanf( sal, " %f ", &aux);
fscanf( mod,"%f", &auxi);
if (aux==auxi)
contaux++;
if (contaux==NSAL)
aciertos++;
ejemplos++;
}
contaux=0;
}
ejemplos=ejemplos/NSAL;
84
errores=ejemplos-aciertos;
fclose(sal);
fclose(mod);
errores=
printf("Entrenamiento: aciertos= %d
errores);
}
errores= %d\n", aciertos,
void Cambio_Prue()
{
int cont=1;
float aux,auxi;
FILE *in,*out;
// Archivo donde esta la salida a analizar
//sal1iris.dat
char InputFile[50]= "/home/alumnos/trejo/bd/iris/salprue.dat",
// Archivo donde estan los datos ya modificados, este
se genera aqui
OutFile[50]= "/home/alumnos/trejo/bd/iris/reporte.dat";
//Abro archivos de lectura y escritura
if ((in=fopen(InputFile,"r"))==NULL)
{
printf("Error al abrir el archivo de datos\n");
exit(1);
}
if ((out=fopen(OutFile,"w"))==NULL)
{
printf("Error al abrir el archivo de salida\n");
exit(1);
}
while (!feof(in))
{
fscanf( in, " %f ", &aux);
if (aux>=0.5) /*umbral de 0.5*/
aux=1;
else
aux=0;
if (cont==NSAL)
{
fprintf(out,"%f \n ",aux);
cont=1;
}
else
{
fprintf(out,"%f ",aux);
cont++;
}
}
fclose(in);
fclose(out);
}
void Analisis_Prue()
{
int i,contaux=0, aciertos=0, ejemplos=0,errores=0;
float aux, auxi;
85
FILE *sal,*mod;
//archivo donde estan los datos de salida, estas son
las puras clases
char SalFile[50]= "/home/alumnos/trejo/bd/iris/iris30c.dat",
// Archivo donde estan los datos ya modificados, archivo
creado en
cambio
ModFile[50]= "/home/alumnos/trejo/bd/iris/reporte.dat";
//Abro archivos de lectura
if ((sal=fopen(SalFile,"r"))==NULL)
{
printf("Error al abrir el archivo de datos de salida\n");
exit(1);
}
if ((mod=fopen(ModFile,"r"))==NULL)
{
printf("Error al abrir el archivo de datos modificados\n");
exit(1);
}
while (!feof(sal))
{
for (i=0; i<NSAL;i++)
{
fscanf( sal, " %f ", &aux);
fscanf( mod,"%f", &auxi);
if (aux==auxi)
contaux++;
if (contaux==NSAL)
aciertos++;
ejemplos++;
}
contaux=0;
}
ejemplos=ejemplos/NSAL;
errores=ejemplos-aciertos;
fclose(sal);
fclose(mod);
errores=
printf("Prueba:
aciertos= %d
errores= %d\n", aciertos,
errores);
}
main()
{
Nodo *apu=NULL;
int ocult,bp=0,mili;
float err,errp;
int indi=POPSIZE;
Proceso *Others
= NULL;
Genotype *poblacion = NULL,*q;
struct timeb tp1,tp2;
ftime (&tp1);
system("clear");
generacion=0;
Ab_arch_esc();
//encabezados del reporte que se genera en el archivo reporte.dat
86
fprintf(out, "\n Poblacion %d, Max_gener %2.0f, Max_tam_crom %d,
\n",
POPSIZE, MAXGENS,MaxSize );
fprintf(out, "\n generac., mejor_val, promedio , ");
fprintf(out, " fit_desv_stand, nmax");
CreaPobAleat(&Others); //pide a los "workers" crear su 1er gen.
aleatoriamente
while (generacion<MAXGENS)
{
generacion++;
fin(&poblacion);
poblacion=NULL;
//PIDE A CADA WORKER MUTAR SU 1ER GENERACION Y DIFUNDIR
SU MEJOR
INDIVIDUO
poblacion = MutaPoblaciones (&Others);
//ENVIA A CADA PROCESO LA NUEVA POBLACION, QUE CONTIENE AHORA
LOS MEJORES
INDIVIDUOS
//DE LOS DEMAS PROCESOS, MAS LA POBLACION QUE TENIA
ANTERIORMENTE
DifundeMejor
(&Others);
Reporte(poblacion);
q=poblacion;
while ( q->sig_gen!=NULL )
q=q->sig_gen;
printf ("Generación: %d, Best fitness: %f, Size:
%d\n",generacion,q->fitness,q->nmax);
}
//
Tabla_Hash (Others);
Finaliza(Others,3);
conta=0;
q=poblacion;
while ( q->sig_gen!=NULL )
q=q->sig_gen;
apu
= q->chrom;
ocult = q->nmax;
err = Calcula (apu,ocult,1,q,sal);
fprintf(sal,"%f",err);
errp= Calculap (apu,ocult,1,q,salp);
fprintf(sal,"%f",errp);
Salvapesos(poblacion); //Guarda todo sobre los POPSIZE+1 mejores
individuos
conta=0;
apu =q->chrom;
ocult=q->nmax;
errp= Calculap(apu,ocult,1,q,salprue);
Cierrarch();
pvm_exit();
ftime(&tp2);
tp2.time=tp2.time-tp1.time;
mili=(int)tp2.millitm-(int)tp1.millitm;
if(mili<0)
{
mili+=1000;
tp2.time-1;
87
}
printf("\nTiempo de respuesta:");
printf("\nsegundos: %d",tp2.time);
printf("\nmilisegundos: %d\n",mili);
Cambio_Ent();
Analisis_Ent();
Cambio_Prue();
Analisis_Prue();
return(1);
}
HELLO_OTHER.C
static char rcsid[] =
"$Id: hello_other.c,v 1.2 1997/07/09 13:24:45 pvmsrc Exp $";
#include"pvm3.h"
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include"Algor.h"
#include"envia.h"
#include"Arch.h"
int main()
{
int mytid,parentid;
Genotype *population = NULL;
int opcion=0, num_ind=0;
int generacion=0;
srandom(time(NULL));
mytid=pvm_mytid();
if(mytid<0)
{
pvm_exit();
return -1;
}
parentid=pvm_parent();
if(parentid==PvmNoParent)
{
printf("I'm a worker!\n");
pvm_exit();
return -1;
}
pvm_recv(parentid,5);
pvm_upkint(&opcion,1,1); //recibo la opcion del proceso "master", que
me
indica las acciones a seguir
while(1)
{
switch(opcion)
{
case 0:
//inicializo la poblacion y la envio al proceso
"master"
pvm_upkint
( &num_ind,1,1 );
88
inicializa
( &population,num_ind );
Evaluared
( &population,num_ind,sal );
keep_the_best( &population,num_ind );
pvm_initsend ( PvmDataRaw
);
pvm_pkint
( &num_ind,1,1 );
EnviaPob
( population
);
pvm_send
( parentid,0
);
break;
case 1:
//Modifico la poblacion propia y la envio al
proceso "master"
pvm_upkint
( &num_ind,1,1 );
generacion=generacion+1;
//util para reducir
probabilidades de
adicion, eliminacion y mutacion
Select
( &population,num_ind );
Mutacion
(
&population,num_ind,generacion,sal );
keep_the_best( &population,num_ind );
pvm_initsend ( PvmDataRaw
);
pvm_pkint
( &num_ind,1,1 );
EnviaPob
( population
);
pvm_send
( parentid,1
);
break;
case 2:
pvm_upkint
( &num_ind,1,1);
fin ( &population );
population = NULL;
RcvPob(&population,num_ind);
break;
case 3:
pvm_exit();
return(opcion);
//solo por regresar algo
}//fin switch
pvm_recv(parentid,5);
pvm_upkint(&opcion,1,1);
//Espero recibir la nueva opcion que
el proceso
"master" requiera
}//fin while
pvm_exit();
//Codigo inalcanzable si todo marcha bien
return 1;
//Codigo inalcanzable si todo marcha bien
}
89
Descargar