$population List of all elements with their parameters (i.e. list of "objects" as arrays). * The constraints are defined as array values. * @param \Closure $fitness Fitness function calculates score/feasibility of solution * @param \Closure $mutate Mutation function to change the parameters of an "object" * @param \Closure $crossover Crossover function to exchange parameter values between "objects". * Sometimes single parameters can be exchanged but sometimes interdependencies exist * between parameters which is why this function is required. * @param int $generations Number of generations to create * @param float $mutationRate Rate at which parameters are changed. * How this is used depends on the mutate function. * * @return array{solutions:array, fitnesses:float[]} * * @since 1.0.0 */ public static function optimize( array $population, \Closure $fitness, \Closure $mutate, \Closure $crossover, int $generations = 500, float $mutationRate = 0.1 ) : array { $populationSize = \count($population); $parameterCount = $populationSize === 0 ? 0 : \count(\reset($population)); // Genetic Algorithm Loop for ($generation = 0; $generation < $generations; ++$generation) { $fitnessScores = []; foreach ($population as $parameters) { $fitnessScores[] = ($fitness)($parameters); } // Select parents for crossover based on fitness scores $parents = []; for ($i = 0; $i < $populationSize; ++$i) { do { $parentIndex1 = \array_rand($population); $parentIndex2 = \array_rand($population); } while ($parentIndex1 === $parentIndex2); $parents[] = $fitnessScores[$parentIndex1] > $fitnessScores[$parentIndex2] ? $population[$parentIndex1] : $population[$parentIndex2]; } // Crossover and mutation to create next generation $newPopulation = []; for ($i = 0; $i < $populationSize; $i += 2) { $crossover = ($crossover)($parents[$i], $parents[$i + 1], $parameterCount); $child1 = ($mutate)($crossover[0], $mutationRate); $child2 = ($mutate)($crossover[1], $mutationRate); $newPopulation[] = $child1; $newPopulation[] = $child2; } $population = $newPopulation; } $fitnesses = []; foreach ($population as $key => $parameters) { $fitnesses[$key] = ($fitness)($parameters); } \asort($fitnesses); return [ 'solutions' => $population, 'fitnesses' => $fitnesses, ]; } }