/// <summary> /// Initializes a new instance of the <see cref="DoubleArrayChromosome"/> class. /// </summary> /// /// <param name="source">Source chromosome to copy.</param> /// /// <remarks><para>This is a copy constructor, which creates the exact copy /// of specified chromosome.</para></remarks> /// public DoubleArrayChromosome(DoubleArrayChromosome source) { this.chromosomeGenerator = source.chromosomeGenerator; this.mutationMultiplierGenerator = source.mutationMultiplierGenerator; this.mutationAdditionGenerator = source.mutationAdditionGenerator; this.length = source.length; this.fitness = source.fitness; this.mutationBalancer = source.mutationBalancer; this.crossoverBalancer = source.crossoverBalancer; // copy genes val = (double[])source.val.Clone( ); }
/// <summary> /// Crossover operator. /// </summary> /// /// <param name="pair">Pair chromosome to crossover with.</param> /// /// <remarks><para>The method performs crossover between two chromosomes, selecting /// randomly the exact type of crossover to perform, which depends on <see cref="CrossoverBalancer"/>. /// Before crossover is done a random number is generated in [0, 1] range - if the /// random number is smaller than <see cref="CrossoverBalancer"/>, then the first crossover /// type is used, otherwise second type is used.</para> /// /// <para>The <b>first crossover type</b> is based on interchanging /// range of genes (array elements) between these chromosomes and is known /// as one point crossover. A crossover point is selected randomly and chromosomes /// interchange genes, which start from the selected point.</para> /// /// <para>The <b>second crossover type</b> is aimed to produce one child, which genes' /// values are between corresponding genes of parents, and another child, which genes' /// values are outside of the range formed by corresponding genes of parents. /// Let take, for example, two genes with 1.0 and 3.0 valueû (of course chromosomes have /// more genes, but for simplicity lets think about one). First of all we randomly choose /// a factor in the [0, 1] range, let's take 0.4. Then, for each pair of genes (we have /// one pair) we calculate difference value, which is 2.0 in our case. In the result we’ll /// have two children – one between and one outside of the range formed by parents genes' values. /// We may have 1.8 and 3.8 children, or we may have 0.2 and 2.2 children. As we can see /// we add/subtract (chosen randomly) <i>difference * factor</i>. So, this gives us exploration /// in between and in near outside. The randomly chosen factor is applied to all genes /// of the chromosomes participating in crossover.</para> /// </remarks> /// public override void Crossover(IChromosome pair) { DoubleArrayChromosome p = (DoubleArrayChromosome)pair; // check for correct pair if ((p != null) && (p.length == length)) { if (rand.NextDouble( ) < crossoverBalancer) { // crossover point int crossOverPoint = rand.Next(length - 1) + 1; // length of chromosome to be crossed int crossOverLength = length - crossOverPoint; // temporary array double[] temp = new double[crossOverLength]; // copy part of first (this) chromosome to temp Array.Copy(val, crossOverPoint, temp, 0, crossOverLength); // copy part of second (pair) chromosome to the first Array.Copy(p.val, crossOverPoint, val, crossOverPoint, crossOverLength); // copy temp to the second Array.Copy(temp, 0, p.val, crossOverPoint, crossOverLength); } else { double[] pairVal = p.val; double factor = rand.NextDouble( ); if (rand.Next(2) == 0) { factor = -factor; } for (int i = 0; i < length; i++) { double portion = (val[i] - pairVal[i]) * factor; val[i] -= portion; pairVal[i] += portion; } } } }
/// <summary> /// Runs learning epoch. /// </summary> /// /// <param name="input">Array of input vectors.</param> /// <param name="output">Array of output vectors.</param> /// /// <returns>Returns summary squared learning error for the entire epoch.</returns> /// /// <remarks><para><note>While running the neural network's learning process, it is required to /// pass the same <paramref name="input"/> and <paramref name="output"/> values for each /// epoch. On the very first run of the method it will initialize evolutionary fitness /// function with the given input/output. So, changing input/output in middle of the learning /// process, will break it.</note></para></remarks> /// public double RunEpoch( double[][] input, double[][] output ) { Debug.Assert( input.Length > 0 ); Debug.Assert( output.Length > 0 ); Debug.Assert( input.Length == output.Length ); Debug.Assert( network.InputsCount == input.Length ); // check if it is a first run and create population if so if ( population == null ) { // sample chromosome DoubleArrayChromosome chromosomeExample = new DoubleArrayChromosome( chromosomeGenerator, mutationMultiplierGenerator, mutationAdditionGenerator, numberOfNetworksWeights ); // create population ... population = new Population( populationSize, chromosomeExample, new EvolutionaryFitness( network, input, output ), selectionMethod ); // ... and configure it population.CrossoverRate = crossOverRate; population.MutationRate = mutationRate; population.RandomSelectionPortion = randomSelectionRate; } // run genetic epoch population.RunEpoch( ); // get best chromosome of the population DoubleArrayChromosome chromosome = (DoubleArrayChromosome) population.BestChromosome; double[] chromosomeGenes = chromosome.Value; // put best chromosome's value into neural network's weights int v = 0; for ( int i = 0; i < network.Layers.Length; i++ ) { Layer layer = network.Layers[i]; for ( int j = 0; j < layer.Neurons.Length; j++ ) { ActivationNeuron neuron = layer.Neurons[j] as ActivationNeuron; for ( int k = 0; k < neuron.Weights.Length; k++ ) { neuron.Weights[k] = chromosomeGenes[v++]; } neuron.Threshold = chromosomeGenes[v++]; } } Debug.Assert( v == numberOfNetworksWeights ); return 1.0 / chromosome.Fitness; }
/// <summary> /// Initializes a new instance of the <see cref="DoubleArrayChromosome"/> class. /// </summary> /// /// <param name="source">Source chromosome to copy.</param> /// /// <remarks><para>This is a copy constructor, which creates the exact copy /// of specified chromosome.</para></remarks> /// public DoubleArrayChromosome( DoubleArrayChromosome source ) { this.chromosomeGenerator = source.chromosomeGenerator; this.mutationMultiplierGenerator = source.mutationMultiplierGenerator; this.mutationAdditionGenerator = source.mutationAdditionGenerator; this.length = source.length; this.fitness = source.fitness; this.mutationBalancer = source.mutationBalancer; this.crossoverBalancer = source.crossoverBalancer; // copy genes val = (double[]) source.val.Clone( ); }