Number of layers to manage * @neurons Number of neurons per layer * * -- CLONING -- * @base Genome to clone to * * -- CROSS-OVER CREATION -- * @father First parent * @mother Second parent * * */ public function __construct(){ /* (1) Get arguments */ $argv = func_get_args(); $argc = count($argv); /* (2) If CrossoverCreation */ if( $argc > 1 && $argv[0] instanceof Genome && $argv[1] instanceof Genome ) $this->construct_crossover($argv[0], $argv[1]); /* (3) If RandomCreation */ else if( $argc > 1 && abs(intval($argv[0])) === $argv[0] && abs(intval($argv[1])) === $argv[1] ) $this->construct_new($argv[0], $argv[1]); /* (4) If InheritanceCreation (clone) */ else if( $argc > 0 && $argv[0] instanceof Genome ) $this->construct_inheritance($argv[0]); /* (5) If no match */ else throw new \Error('Invalid Genome constructor\'s arguments.'); } /* BUILDS A Genome RANDOMLY WITH PARAMETERS * * @layers The number of hidden layers to manage * @neurons The number neurons per layer * * @return created If Genome has been successfully created * */ private function construct_new($layers=-1, $neurons=-1){ /* (1) Checks parameters */ if( abs(intval($layers)) !== $layers || abs(intval($neurons)) !== $neurons ) return false; // set layers $this->layers = $layers; /* (2) Creating random neurons */ $this->neurons = []; for( $i = 0, $l = $neurons*$layers ; $i < $l ; $i++ ) $this->neurons[$i] = rand(self::MIN, self::MAX) / self::MAX; /* (3) Creating random synapses */ $this->synapses = []; for( $i = 0, $l = pow($neurons, $layers) ; $i < $l ; $i++ ) $this->synapses[$i] = rand(self::MIN, self::MAX) / self::MAX; // Success status return true; } /* BUILDS A Genome BASED ON A PARENT * * @parent Parent genome to clone into children * * @return created If cloned Genome has been created successfully * */ private function construct_inheritance($parent=null){ /* (1) Checks parent type */ if( !($parent instanceof Genome) ) return false; /* (2) Clones into this Genome */ $this->layers = $parent->layers; $this->neurons = array_slice($parent->neurons, 0); $this->synapses = array_slice($parent->synapses, 0); // Success state return true; } /* BUILDS A Genome BASED ON TWO PARENTS * * @father First parent ($father) * @mother Second parent ($mother) * * @return created If crossed-over Genome has been created successfully * */ private function construct_crossover($father=null, $mother=null){ /* (1) Checks parent type */ if( !($father instanceof Genome) || !($mother instanceof Genome) ) return false; /* (2) Checks number of layers+neurons (same species) */ if( $father->layers !== $mother->layers || count($father->neurons) !== count($mother->neurons) ) return false; /* (3) Set layer count */ $this->layers = $father->layers; /* (4) Do random crossover for neurons */ $this->neurons = []; for( $i = 0, $l = count($father->neurons) ; $i < $l ; $i++ ) if( !!rand(0,1) ) $this->neurons[$i] = $father->neurons[$i]; else $this->neurons[$i] = $mother->neurons[$i]; /* (5) Do random crossover for synapses */ $this->synapses = []; for( $i = 0, $l = pow(count($this->neurons)/$this->layers, $this->layers) ; $i < $l ; $i++ ) if( !!rand(0,1) ) $this->synapses[$i] = $father->synapses[$i]; else $this->synapses[$i] = $mother->synapses[$i]; // Success state return true; } /************************************************ **** Genome Actions **** ************************************************/ /* APPLIES A MUTATION ON THE Genome WITH A SPECIFIC @threshold * * @threshold Mutation threshold * */ public function mutation($threshold=0.5){ /* (1) Checks @threshold argument */ if( floatval($threshold) !== $threshold || $threshold < 0 || $threshold > 1 ) throw new \Error('Invalid threshold for Genome mutation.'); /* (2) Calculates how many neurons/synapses to mutate */ $neuronsMutations = round( (count($this->neurons) - 1) * $threshold ); $synapsesMutations = round( (count($this->synapses) - 1) * $threshold ); /* (3) Choose random neurons' indexes */ $iNeurons = []; while( count($iNeurons) < $neuronsMutations ){ $r = rand(0, count($this->neurons)-1); if( !in_array($r, $iNeurons) ) $iNeurons[] = $r; } /* (4) Choose random synapses' indexes */ $iSynapses = []; while( count($iSynapses) < $synapsesMutations ){ $r = rand(0, count($this->synapses)-1); if( !in_array($r, $iSynapses) ) $iSynapses[] = $r; } /* (5) Update chosen neurons */ for( $i = 0, $l = count($iNeurons) ; $i < $l ; $i++ ) $this->neurons[$iNeurons[$i]] = rand(self::MIN, self::MAX) / self::MAX; /* (6) Update chosen synapses */ for( $i = 0, $l = count($iSynapses) ; $i < $l ; $i++ ) $this->synapses[$iSynapses[$i]] = rand(self::MIN, self::MAX) / self::MAX; } /************************************************ **** Serialization **** ************************************************/ /* SERIALIZES A Genome * * @return serialized Serialized representation of the Genome * */ public function serialize(){ /* (1) Initialize result */ $csv = ''; /* (2) Adds global attributes */ $csv .= $this->layers .';'; /* (3) Adds neurons data */ $csv .= implode(',', $this->neurons) .';'; /* (4) Adds synapses data */ $csv .= implode(',', $this->synapses); return $csv; } /* BUILDS A Genome BASED ON HIS SERIALIZED REPRESENTATION * * @serialized Serialized representation of a Genome * */ public function unserialize($serialized){ /* (1) Segmenting data */ $segments = explode(';', $serialized); // Manage segmentation error if( count($segments) < 3 ) throw new \Error('Format error during Genome unserialization.'); /* (2) Get global attributes */ if( !is_numeric($segments[0]) ) throw new \Error('Format error during Genome unserialization.'); $this->layers = intval($segments[0]); /* (3) Get neurons values */ $this->neurons = explode(',', $segments[1]); /* (4) Get synapses values */ $this->synapses = explode(',', $segments[2]); } } /************************************************ **** USE CASE **** ************************************************/ $use_case = false; if( $use_case ){ /* (1) Basic Creation */ $a = new Genome(2, 3); // 2 layers of 3 neurons each -> randomly filled /* (2) Inheritance */ $b = new Genome($a); // Clone of @a /* (3) Section Title */ $b->mutation(0.3); // @b has now mutated with a threshold of 30% /* (4) Cross-over (father+mother) */ $c = new Genome($a, $b); // @c is a randomly-done mix of @a and @b } ?>