UTNianos

Versión completa: Implementación de Algoritmo genético
Actualmente estas viendo una versión simplificada de nuestro contenido. Ver la versión completa con el formato correcto.
Buenas, hice una implementación de AG que me sirvió bastante para internalizar un poco el funcionamiento. La dejo acá por si a alguien le sirve.

En este caso simplemente busco el numero más grande, pero se ve que toda la magia está en la función de adaptación.


<?php
$funcion_de_adaptacion=function($individuo) {
return $individuo;
};

$algoritmo_genetico=new Algoritmo_genetico();
$poblacion_final=$algoritmo_genetico->ejecutar($funcion_de_adaptacion);
exit();

class Algoritmo_genetico
{
const GENES_POR_INDIVIDUO=8;
const POBLACION_INICIAL=500;
const CANTIDAD_DE_INDIVIDUOS_SELECCIONADOS=20;
const CANTIDAD_DE_CRUCES_POR_INDIVIDUO=25; # Mantener la poblacion inicial constante!
const PROBABILIDAD_DE_MUTACION_DE_GEN=0.5; # Porcentaje # Mutacion simple, pero hay otros tipos de mutacion
const CANTIDAD_DE_VUELTAS_MAXIMAS=100; # Hay muchos criterios de detencion
public function ejecutar($funcion_de_adaptacion){
$poblacion=$this->generar_poblacion_inicial();
echo 'Promedio inicial de la población: '.array_sum($poblacion)/count($poblacion).PHP_EOL;
$detencion=false;
for ($i=0; $i < self::CANTIDAD_DE_VUELTAS_MAXIMAS AND !$detencion; $i++) {
$poblacion=$this->mutacion($this->cruzamiento($this->seleccion($poblacion,$funcion_de_adaptacion)));
if($i % (self::CANTIDAD_DE_VUELTAS_MAXIMAS/100)==0) {
echo 'Promedio actual: '.array_sum($poblacion)/count($poblacion).PHP_EOL;
}
}
echo 'Promedio final de la población: '.array_sum($poblacion)/count($poblacion).PHP_EOL;
return $poblacion;
}

// Poblacion inicial
private function generar_poblacion_inicial(){
$poblacion=array();
for ($i=0; $i < self::POBLACION_INICIAL; $i++) {
$poblacion[]=$this->generar_individuo();
}
return $poblacion;
}
private function generar_individuo(){
return rand(0,pow(2, self::GENES_POR_INDIVIDUO));
}
private function seleccion($poblacion,$funcion_de_adaptacion){
return $this->seleccion_ruleta($poblacion,$funcion_de_adaptacion);
}
// Seleccion
private function seleccion_torneo($poblacion){
}
private function seleccion_ranking($poblacion,$funcion_de_adaptacion) {
$ranking=array();
foreach ($poblacion as $individuo) {
$ranking[$individuo]=$funcion_de_adaptacion($individuo);
}
arsort($ranking);
return array_slice(array_keys($ranking),0, self::CANTIDAD_DE_INDIVIDUOS_SELECCIONADOS);
}
private function seleccion_ruleta($poblacion,$funcion_de_adaptacion){
$total=0;
foreach ($poblacion as $individuo) {
$total+=$funcion_de_adaptacion($individuo);
}
$ruleta=array();
$acumulado=0;
foreach ($poblacion as $individuo) {
$adaptacion= $funcion_de_adaptacion($individuo)/$total;
$acumulado+=$adaptacion;
$ruleta[]=array($individuo,$adaptacion, $acumulado);
// error_log($individuo.' : '.$adaptacion.' : '.$acumulado);
}
$poblacion_seleccionada=array();
for ($i=0; $i < self::CANTIDAD_DE_INDIVIDUOS_SELECCIONADOS; $i++) {
$rand=rand(0,10000000000)/10000000000;
$individuo_seleccionado=false;
foreach ($ruleta as $key => $array) {
if(!$individuo_seleccionado AND $rand<=$array[2]){
$individuo_seleccionado=$array[0];
}
}
$poblacion_seleccionada[]=$individuo_seleccionado;
}
return $poblacion_seleccionada;
}
private function seleccion_control_sobre_numero_esperado($poblacion){
}
private function cruzamiento($poblacion){
$poblacion_cruzada=array();
foreach ($poblacion as $key => $individuo) {
for ($i=0; $i < self::CANTIDAD_DE_CRUCES_POR_INDIVIDUO; $i++) {
$individuo_al_azar=$poblacion[rand(0,count($poblacion)-1)];
$poblacion_cruzada[]=$this->cruzar_individuos_simple($individuo,$individuo_al_azar);
}
}
return $poblacion_cruzada;
}
// Cruzamiento
private function cruzar_individuos_simple($x,$y){
$punto_de_corte=rand(0,self::GENES_POR_INDIVIDUO-1);
$x_binario=decbin($x);
$y_binario=decbin($y);
$hijo_binario=substr($x_binario,0,$punto_de_corte).substr($y_binario, $punto_de_corte);
$hijo=bindec($hijo_binario);
return $hijo;
}
private function cruzar_individuos_multipunto($x,$y){
}
private function cruzar_individuos_binomial($x,$y){
}
private function cruzar_individuos_azar($x,$y){
}
// Mutacion
private function mutacion($poblacion){
$poblacion_mutada=array();
foreach ($poblacion as $individuo) {
$poblacion_mutada[]=$this->mutar_individuo($individuo);
}
return $poblacion_mutada;
}
private function mutar_individuo($individuo){
$individuo_binario=str_pad(decbin($individuo),self::GENES_POR_INDIVIDUO,'0',STR_PAD_LEFT) ;
$individuo_mutado_binario='';
$length=strlen($individuo_binario);
for ($i=0; $i < self::GENES_POR_INDIVIDUO; $i++) {
$rand=rand(0,100);
if($rand<=self::PROBABILIDAD_DE_MUTACION_DE_GEN){
if($individuo_binario[$i]=='1'){
$individuo_mutado_binario.='0';
}
else{
$individuo_mutado_binario.='1';
}
}
else{
$individuo_mutado_binario.=$individuo_binario[$i];
}
}
return bindec($individuo_mutado_binario);
}
}


Pueden copiar el código en alguna página que permita ejecutar código PHP y ver el resultado. Por ej. http://phptester.net/
URLs de referencia