private void Mutate(int individualIndex)//a helper method which calls itself recursively to make mutation truly probabalistic { if (RandHolder.NextDouble() < mutationChance) { individuals[individualIndex].Mutate(); Mutate(individualIndex); } }
public IGeneticIndividual TrainGeneration(int numGenerations)//execute a number of iterations of the algorithm creating more fit solutions. Return most fit individual { for (int i = 0; i < numGenerations; i++) { generationCount++; //create elite array IGeneticIndividual[] eliteIndividuals = new IGeneticIndividual[numToSave]; for (int j = 0; j < numToSave; j++) { eliteIndividuals[j] = individuals[j]; } //create 2 dim array of parents(1) for each child(0) IGeneticIndividual[,] reproductionGroups = new IGeneticIndividual[numChildrenNeeded, numParents]; //uses tournament selection process to fill array for (int childIter = 0; childIter < reproductionGroups.GetLength(0); childIter++) //iterate once per child { for (int parentIter = 0; parentIter < reproductionGroups.GetLength(1); parentIter++) //iterate once per parent. This will { IGeneticIndividual[] tournamentSubset = new IGeneticIndividual[tournamentSize]; for (int touranmentIter = 0; touranmentIter < tournamentSubset.Length; touranmentIter++) { tournamentSubset[touranmentIter] = individuals[(int)(RandHolder.NextDouble() * populationSize)];//pick a random individual } Array.Sort(tournamentSubset); reproductionGroups[childIter, parentIter] = tournamentSubset[0]; } } //generate children IGeneticIndividual[] newChildren = new IGeneticIndividual[numChildrenNeeded];//create empty array to hold newly generated children for (int childIter = 0; childIter < newChildren.Length; childIter++) { IGeneticIndividual[] reproductionGroup = new IGeneticIndividual[numParents];//fill the single dimensioned array, reproductionGroup, with its corresponding individuals from the 2 dimensional array, reproductionGroups. for (int parentIter = 0; parentIter < reproductionGroup.Length; parentIter++) { reproductionGroup[parentIter] = reproductionGroups[childIter, parentIter]; } newChildren[childIter] = reproductionGroup[0].Reproduce(reproductionGroup, numCrossoverPoints, 1)[0];//generate a single child with reproductionGroup as its parents. Method called by reproductionGroup[0] for convenience. } //mutate over children array for (int mutationIter = 0; mutationIter < populationSize; mutationIter++) { Mutate(mutationIter); } //combine elite and children array and copy into individuals array for (int eliteIter = 0; eliteIter < eliteIndividuals.Length; eliteIter++)//copy the high fitness individuals that were saved from the previous generation { individuals[eliteIter] = eliteIndividuals[eliteIter]; } for (int childIter = 0; childIter < newChildren.Length; childIter++)//copy the newly generated children after the elite individuals { individuals[eliteIndividuals.Length + childIter] = newChildren[childIter]; } FitnessSort(); //order the individuals by fitness } return(individuals[0]); //the highest fitness }
void RandomizeWeights() //randomizes biases and weights { for (int i = 0; i < weights.GetLength(0); i++) { for (int j = 0; j < weights.GetLength(1); j++) { weights[i, j] = RandHolder.NextDouble() * 2 - 1;//from [-1, 1) } } }
public void Mutate() { int indexToMutate = (int)(RandHolder.NextDouble() * genes.Length); if (RandHolder.NextDouble() > 0.5) { genes[indexToMutate] = 1; } else { genes[indexToMutate] = 0; } }
public IGeneticIndividual[] Reproduce(IGeneticIndividual[] IParents, int numCrossoverPoints, int numChildren) { int numParents = IParents.Length;//convenient variable to have //convert array of type IGeneticIndividual to type TestGeneticIndividual TestGeneticIndividual[] parents = new TestGeneticIndividual[numParents]; for (int i = 0; i < numParents; i++) { parents[i] = IParents[i] as TestGeneticIndividual; } TestGeneticIndividual[] children = new TestGeneticIndividual[numChildren]; //variable to hold generated children. Will be output by method for (int childIter = 0; childIter < numChildren; childIter++) //iterate once for each child to be generated { int[] crossoverPoints = new int[numCrossoverPoints]; //fill crossoverPoints array with random ints which are indexes of genes array for (int i = 0; i < crossoverPoints.Length; i++) { crossoverPoints[i] = (int)(RandHolder.NextDouble() * parents[0].genes.Length); } int activeParentIndex = 0; //generate child children[childIter] = new TestGeneticIndividual(parents[0].genes.Length); for (int i = 0; i < parents[0].genes.Length; i++) { children[childIter].genes[i] = parents[activeParentIndex].genes[i]; for (int iter = 0; iter < numCrossoverPoints; iter++) { if (i == crossoverPoints[iter]) { int temp = (int)(RandHolder.NextDouble() * (parents.Length - 1));//minus one for value exclusion, so between first and second to last index if (temp != activeParentIndex) { activeParentIndex = temp; } else { activeParentIndex = parents.Length - 1;//minus one because it is max index of array } } } } } //convert array of type TestGeneticIndividual to type IGeneticIndividual IGeneticIndividual[] IChildren = new IGeneticIndividual[numChildren]; for (int i = 0; i < numChildren; i++) { IChildren[i] = children[i] as IGeneticIndividual; } return(IChildren); }
public void Randomize() { for (int i = 0; i < genes.Length; i++) { if (RandHolder.NextDouble() > 0.5) { genes[i] = 1; } else { genes[i] = 0; } } }
public void Mutate()//set a single random weight to a random value from 0 to 1 { //layer to mutate// int i = (int)(RandHolder.NextDouble() * (numHiddenLayers + 1)); //+1 for output //node to mutate// int j = -1; //should cause an index out of bounds if not set by subsequent if cases if (i == 0) //if first hidden layer (same as else case)(same number of nodes as hidden layer so doesn't matter) { j = (int)(RandHolder.NextDouble() * hiddenLayerSize); } else if (i == numHiddenLayers) //if output layer { j = (int)(RandHolder.NextDouble() * numOutputs); } else //if any other hidden layer { j = (int)(RandHolder.NextDouble() * hiddenLayerSize); } //weight to mutate// int k = -1; //should cause an index out of bounds if not set by subsequent if cases if (i == 0) //if first hidden layer (same as else case)(same number of nodes as hidden layer so doesn't matter) { k = (int)(RandHolder.NextDouble() * (numInputs + 1)); //+1 for bias } else if (i == numHiddenLayers) //if output layer same as else case { k = (int)(RandHolder.NextDouble() * (hiddenLayerSize) + 1); //+1 for bias } else//if any other hidden layer { k = (int)(RandHolder.NextDouble() * (hiddenLayerSize) + 1);//+1 for bias } //set new value; double currentValue = Layers[i].Weights[j, k]; double newValue = (RandHolder.NextDouble() + 0.5) * currentValue; //[0.5, 1.5) if (RandHolder.NextDouble() > 0.5) { newValue = -newValue;//(-1.5, -0.5] union [0.5, 1.5) } Layers[i].Weights[j, k] = newValue; }
public IGeneticIndividual[] Reproduce(IGeneticIndividual[] IParents, int numCrossoverPoints, int numChildren) //returns an array of nets given an array of all parents. // Doesn't necessarily need to be called by one of the parents but that's probably convenient. //numCrossover points SHOULD be > numParents-1 (to use all parents at least once), but it's fine if not { int numParents = IParents.Length;//convenient variable to have //convert array of type IGeneticIndividual to type NeuralNet NeuralNet[] parents = new NeuralNet[numParents]; for (int i = 0; i < numParents; i++) { parents[i] = IParents[i] as NeuralNet; } NeuralNet[] children = new NeuralNet[numChildren]; //variable to hold generated children. Will be output by method for (int childIter = 0; childIter < numChildren; childIter++) //iterate once for each child to be generated { //generate random crossoverPoints int[,] crossoverPoints = new int[numCrossoverPoints, 3]; //3 because (i, j, k) are (layer, node, weight) for (int cpIter = 0; cpIter < numCrossoverPoints; cpIter++) //iterate for each crossover point and generate it. Code copied from Mutate() { //layer to cp// int i = (int)(RandHolder.NextDouble() * (parents[0].numHiddenLayers + 1)); //+1 for output //node to cp// int j = -1; //should cause an index out of bounds if not set by subsequent if cases if (i == 0) { //if first hidden layer (same as else case)(same number of nodes as hidden layer so doesn't matter) j = (int)(RandHolder.NextDouble() * parents[0].hiddenLayerSize); } else if (i == parents[0].numHiddenLayers) {//if output layer j = (int)(RandHolder.NextDouble() * parents[0].numOutputs); } else {//if any other hidden layer j = (int)(RandHolder.NextDouble() * parents[0].hiddenLayerSize); } //weight to cp// int k = -1; //should cause an index out of bounds if not set by subsequent if cases if (i == 0) //if first hidden layer (same as else case)(same number of nodes as hidden layer so doesn't matter) { k = (int)(RandHolder.NextDouble() * (parents[0].numInputs) + 1); //+1 for bias } else if (i == parents[0].numHiddenLayers) //if output layer same as else case { k = (int)(RandHolder.NextDouble() * (parents[0].hiddenLayerSize) + 1); //+1 for bias } else//if any other hidden layer { k = (int)(RandHolder.NextDouble() * (parents[0].hiddenLayerSize) + 1);//+1 for bias } //assign i,j,k to crossoverPoints crossoverPoints[cpIter, 0] = i; crossoverPoints[cpIter, 1] = j; crossoverPoints[cpIter, 2] = k;//duplicate crossover points might exist but honestly who cares } //create array to hold new layers, nodes, weights Layer[] newLayers = new Layer[parents[0].numHiddenLayers + 1]; //fill newLayers int activeParentIndex = 0; for (int i = 0; i < parents[0].numHiddenLayers + 1; i++) //+1 for output layer { if (i == 0) //first hidden layer { double[,] newWeights = new double[parents[0].hiddenLayerSize, parents[0].numInputs + 1]; //create empty container, +1 for bias for (int j = 0; j < newWeights.GetLength(0); j++) { for (int k = 0; k < newWeights.GetLength(1); k++)//this will run for each weight and bias { //check if currently at a crossover point if so then swap the activeParentIndex for (int iter = 0; iter < numCrossoverPoints; iter++)//check for each crossover point { if (crossoverPoints[iter, 0] == i && crossoverPoints[iter, 1] == j && crossoverPoints[iter, 2] == k) { activeParentIndex = (int)(RandHolder.NextDouble() * (numParents));//choose a random parent including currently active parent } } newWeights[j, k] = parents[activeParentIndex].layers[i].Weights[j, k];//copy the value from the active aprent } } newLayers[i] = new Layer(parents[0].numInputs, parents[0].hiddenLayerSize, newWeights); //assign new weights to newLayers array in the form of a newly instantiated Layer } else if (i > 0 && i < parents[0].numHiddenLayers) //all other hidden layers { double[,] newWeights = new double[parents[0].hiddenLayerSize, parents[0].hiddenLayerSize + 1]; //create empty container, +1 for bias for (int j = 0; j < newWeights.GetLength(0); j++) { for (int k = 0; k < newWeights.GetLength(1); k++)//this will run for each weight and bias { //check if currently at a crossover point if so then swap the activeParentIndex for (int iter = 0; iter < numCrossoverPoints; iter++)//check for each crossover point { if (crossoverPoints[iter, 0] == i && crossoverPoints[iter, 1] == j && crossoverPoints[iter, 2] == k) { int temp = (int)(RandHolder.NextDouble() * (numParents - 1));//the minus one is because we are avoiding the current activeParentIndex in this reassignment if (temp < activeParentIndex) { activeParentIndex = temp; } else//if greater than or equal to activeParentIndex { activeParentIndex = temp + 1; } } } newWeights[j, k] = parents[activeParentIndex].layers[i].Weights[j, k];//copy the value from the active parent } } newLayers[i] = new Layer(parents[0].numInputs, parents[0].hiddenLayerSize, newWeights); //assign new weights to newLayers array in the form of a newly instantiated Layer } else if (i == parents[0].numHiddenLayers) //output layer { double[,] newWeights = new double[parents[0].numOutputs, parents[0].hiddenLayerSize + 1]; //create empty container, +1 for bias for (int j = 0; j < newWeights.GetLength(0); j++) { for (int k = 0; k < newWeights.GetLength(1); k++)//this will run for each weight and bias { //check if currently at a crossover point if so then swap the activeParentIndex for (int iter = 0; iter < numCrossoverPoints; iter++)//check for each crossover point { if (crossoverPoints[iter, 0] == i && crossoverPoints[iter, 1] == j && crossoverPoints[iter, 2] == k) { int temp = (int)(RandHolder.NextDouble() * (numParents - 1));//the minus one is because we are avoiding the current activeParentIndex in this reassignment if (temp < activeParentIndex) { activeParentIndex = temp; } else//if greater than or equal to activeParentIndex { activeParentIndex = temp + 1; } } } newWeights[j, k] = parents[activeParentIndex].layers[i].Weights[j, k];//copy the value from the active aprent } } newLayers[i] = new Layer(parents[0].hiddenLayerSize, parents[0].numOutputs, newWeights);//assign new weights to newLayers array in the form of a newly instantiated Layer } else { throw new IndexOutOfRangeException(); } } children[childIter] = new NeuralNet(parents[0].numInputs, parents[0].numOutputs, parents[0].numHiddenLayers, parents[0].hiddenLayerSize, parents[0].TestInputSets, parents[0].TestOutputSets) //create empty with same params as parent { layers = newLayers //assign the data to complete the child }; } //convert array of type NeuralNet to type IGeneticIndividual IGeneticIndividual[] IChildren = new IGeneticIndividual[numChildren]; for (int i = 0; i < numChildren; i++) { IChildren[i] = children[i] as IGeneticIndividual; } return(IChildren); }