Población y desempeño
En los capítulos 1 y 2 fue el comienzo de las simulaciones en las cuales dada una entrada y una salida se buscaba la ecuación o el algoritmo que se acercara a esas condiciones de entrada y salida. Para tal fin, al inicio se hacia generación completamente al azar, luego la mejor ecuación o el mejor algoritmo empezaba a "tener hijos" con una pequeña diferencia con respecto al padre (a esto se le llamó mutación), algún hijo lo hacía mejor que el padre, entonces pasaba a ocupar el primer lugar desechando el antepasado. Aquí se detecta un problema y es conocido en el medio como caer en un "mínimo local" o "máximo local" y significa que se encontró un punto en donde hay una buena aproximación pero sin importar cuanto se mute no hay mucho progreso, en cambio, puede nacer otra ecuación o algoritmo radicalmente distinto al campeón local que al principio falla, pero a medida que muta va volviéndose mejor que el campeón local hasta llegar a lo que buscamos. En los capítulos 1 y 2 el campeón local le cierra las oportunidades a las prometedoras ecuaciones o algoritmos porque siempre es temporalmente mejor que las potenciales.
Por esa razón nace el concepto de Población, ahora pueden habitar N organismos donde cada uno se multiplica y los hijos "conviven" con los padres, ya no hay un campeón local sino varios distintos organismos compitiendo. El objetivo es dada la diversidad se encuentra el mejor organismo.
En cuanto al desempeño, han habido unos muy interesantes cambios que harán el código mas sencillo y mucho mas rápido.
Los organismos serán ecuaciones con la siguiente estructura:
Identificación del Organismo
|
Cada instrucción tiene la siguiente estructura:
Tipo Instrucción | Variable A | Variable B | Variable C |
El tipo de instrucción puede ser suma, resta, multiplicación, división, módulo, asignar, .... hasta 256 distintas.
Variable A,B,C marcan posiciones de memoria donde se guardan los valores... hay hasta 256 posiciones de memoria distintas.
Un ejemplo: Representar C=A+B
La instrucción es suma, se suma lo que tiene A y B a C, eso sería así
Sumar | Variable C | Variable A | Variable B |
Sumar | [56] | [31] | [89] |
Simplemente, voy a la posición [31] de la memoria y traigo el dato, por ejemplo 7.6, luego voy a la posición [89] de la memoria y traigo el dato, por ejemplo 5.8, ahora sumo esos dos números 7.6+5.8=13.4 y ese valor 13.4 lo guardo en la posición [56] de la memoria. Hay hasta 256 posiciones de memoria distintas.
Los límites, entonces, de esta estructura son:
Hasta 256 tipos de instrucciones | Hasta 256 posiciones de memoria | Hasta 256 posiciones de memoria | Hasta 256 posiciones de memoria |
Obsérvese que son los límites de un byte que puede tener 256 valores distintos (recordar que un byte es igual a ocho bits).
byte | byte | byte | byte |
¿Si se unen 4 bytes que se obtiene? Respuesta: Un entero de 32 bits
Es mucho mas rápido manejar enteros y mas rápido manejar sus bytes y bits que cualquier otra estructura. Esta aproximación simple y flexible dará a simulaciones mucho más rápidas que las encontradas en los capítulos 1 y 2 y con menos consumo de recursos.
Para extraer los cuatro bytes de un entero se usa esto:
int iNumero = 1705498053;
int iByte0 = ((iNumero >> 24) & 0xFF);
int iByte1 = ((iNumero >> 16) & 0xFF);
int iByte2 = ((iNumero >> 8) & 0xFF);
int iByte3 = (iNumero & 0xFF);
Y dado los bytes para convertirlo a entero es tan simple como:
iNumero = (iByte0<<24) + (iByte1<<16) + (iByte2<<8) + iByte3
Los tipos de instrucciones
Se pueden hacer hasta 256 tipos distintos de instrucciones.
Operación | Código instrucción, posiciones de memoria usadas |
Suma C=A+B | 1,[],[],[] |
Resta C=A-B | 2,[],[],[] |
Multiplica C=A*B | 3,[],[],[] |
Divide C=A/B | 4,[],[],[] |
Módulo C=A%B | 5,[],[],[] |
Asigna C=A | 6,[],[] |
IF A==B GOTO instrucción | 7,[],[], GOTO [] |
IF A>=B GOTO instrucción | 8,[],[], GOTO [] |
IF A>B GOTO instrucción | 9,[],[], GOTO [] |
IF A<B GOTO instrucción | 10,[],[], GOTO [] |
IF A<=B GOTO instrucción | 11,[],[], GOTO [] |
IF A<>B GOTO instrucción | 12,[],[], GOTO [] |
GOTO instrucción | 13,GOTO [] |
Habrán nuevas instrucciones dependiendo de las necesidades encontradas.
Como se simula una Población
El algoritmo que tengo planeado para simular el comportamiento de una población es el siguiente:
1. Dado un arreglo unidimensional de N posiciones.
2. En cada posición de ese arreglo "vivirá" un organismo.
3. Se escoge una posición del arreglo unidimensional al azar.
4. Si esa posición estaba vacía entonces se genera un organismo al azar y se guarda así.
5. Si esa posición estaba ya ocupada por un organismo entonces se toma este, se reproduce, se muta y se busca una posición al azar en el arreglo para que el "hijo" viva. Si esa nueva posición estaba vacía entonces se almacena el hijo, si estaba ocupada entonces se compara frente a la "selección artificial" el "hijo" vs "el huésped original" cual es el mejor. Solo el mejor ocupará esa posición.