예제 #1
0
 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);
     }
 }
예제 #2
0
    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
    }
예제 #3
0
 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)
         }
     }
 }
예제 #4
0
    public void Mutate()
    {
        int indexToMutate = (int)(RandHolder.NextDouble() * genes.Length);

        if (RandHolder.NextDouble() > 0.5)
        {
            genes[indexToMutate] = 1;
        }
        else
        {
            genes[indexToMutate] = 0;
        }
    }
예제 #5
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);
    }
예제 #6
0
 public void Randomize()
 {
     for (int i = 0; i < genes.Length; i++)
     {
         if (RandHolder.NextDouble() > 0.5)
         {
             genes[i] = 1;
         }
         else
         {
             genes[i] = 0;
         }
     }
 }
예제 #7
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;
    }
예제 #8
0
    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);
    }