Example #1
0
 public Multiobjective(NeatParameters _np)
 {
     np=_np;
     population= new GenomeList();
     ranks=new List<RankInformation>();
     nov = new noveltyfixed(10.0);
     doNovelty=false;
     generation=0;
 }
		/// <summary>
		/// Default Constructor.
		/// </summary>
		public EvolutionAlgorithm(Population pop, IPopulationEvaluator populationEvaluator, NeatParameters neatParameters)
		{
			this.pop = pop;
			this.populationEvaluator = populationEvaluator;
			this.neatParameters = neatParameters;
			neatParameters_Normal = neatParameters;

			neatParameters_PrunePhase = new NeatParameters(neatParameters);
			neatParameters_PrunePhase.pMutateAddConnection = 0.0;
            neatParameters_PrunePhase.pMutateAddNode = 0.0;
            neatParameters_PrunePhase.pMutateAddModule = 0.0;
            neatParameters_PrunePhase.pMutateConnectionWeights = 0.33;
			neatParameters_PrunePhase.pMutateDeleteConnection = 0.33;
			neatParameters_PrunePhase.pMutateDeleteSimpleNeuron = 0.33;

			// Disable all crossover as this has a tendency to increase complexity, which is precisely what
			// we don't want during a pruning phase.
			neatParameters_PrunePhase.pOffspringAsexual = 1.0;
			neatParameters_PrunePhase.pOffspringSexual = 0.0;
			
			if(neatParameters.multiobjective) {
				this.multiobjective=new Multiobjective.Multiobjective(neatParameters);
				neatParameters.compatibilityThreshold=100000000.0; //disable speciation w/ multiobjective
			}
			
            if(neatParameters.noveltySearch)
            {
                if(neatParameters.noveltyHistogram)
                {
                    this.noveltyFixed = new noveltyfixed(neatParameters.archiveThreshold);
                    this.histogram = new noveltyhistogram(neatParameters.histogramBins);
					noveltyInitialized=true;
                    InitialisePopulation();
                }
                
                if(neatParameters.noveltyFixed || neatParameters.noveltyFloat)
                {
                    this.noveltyFixed = new noveltyfixed(neatParameters.archiveThreshold);
                    InitialisePopulation();
                    noveltyFixed.initialize(this.pop);
					noveltyInitialized=true;
			        populationEvaluator.EvaluatePopulation(pop, this);			
			        UpdateFitnessStats();
			        DetermineSpeciesTargetSize();
                }
               
            }
            else
            {
			InitialisePopulation();
			}
		}
Example #3
0
        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="copyFrom"></param>
        public NeatParameters(NeatParameters copyFrom)
        {
            // Schrum: Added
            pMMP = copyFrom.pMMP;
            pMMR = copyFrom.pMMR;
            pMMD = copyFrom.pMMD;

            //joel
            noveltySearch    = copyFrom.noveltySearch;
            noveltyHistogram = copyFrom.noveltyHistogram;
            noveltyFixed     = copyFrom.noveltyFixed;
            noveltyFloat     = copyFrom.noveltyFloat;
            histogramBins    = copyFrom.histogramBins;

            populationSize = copyFrom.populationSize;

            pOffspringAsexual   = copyFrom.pOffspringAsexual;
            pOffspringSexual    = copyFrom.pOffspringSexual;
            pInterspeciesMating = copyFrom.pInterspeciesMating;

            pDisjointExcessGenesRecombined = copyFrom.pDisjointExcessGenesRecombined;

            pMutateConnectionWeights  = copyFrom.pMutateConnectionWeights;
            pMutateAddNode            = copyFrom.pMutateAddNode;
            pMutateAddModule          = copyFrom.pMutateAddModule;
            pMutateAddConnection      = copyFrom.pMutateAddConnection;
            pMutateDeleteConnection   = copyFrom.pMutateDeleteConnection;
            pMutateDeleteSimpleNeuron = copyFrom.pMutateDeleteSimpleNeuron;

            // Copy the list.
            ConnectionMutationParameterGroupList = new ConnectionMutationParameterGroupList(copyFrom.ConnectionMutationParameterGroupList);

            compatibilityThreshold        = copyFrom.compatibilityThreshold;
            compatibilityDisjointCoeff    = copyFrom.compatibilityDisjointCoeff;
            compatibilityExcessCoeff      = copyFrom.compatibilityExcessCoeff;
            compatibilityWeightDeltaCoeff = copyFrom.compatibilityWeightDeltaCoeff;

            elitismProportion   = copyFrom.elitismProportion;
            selectionProportion = copyFrom.selectionProportion;

            targetSpeciesCountMin = copyFrom.targetSpeciesCountMin;
            targetSpeciesCountMax = copyFrom.targetSpeciesCountMax;

            pruningPhaseBeginComplexityThreshold         = copyFrom.pruningPhaseBeginComplexityThreshold;
            pruningPhaseBeginFitnessStagnationThreshold  = copyFrom.pruningPhaseBeginFitnessStagnationThreshold;
            pruningPhaseEndComplexityStagnationThreshold = copyFrom.pruningPhaseEndComplexityStagnationThreshold;

            speciesDropoffAge = copyFrom.speciesDropoffAge;

            connectionWeightRange = copyFrom.connectionWeightRange;
        }
Example #4
0
        EvolutionManager()
        {
            //generic neat params, if need to change, just create a function that swaps them in
            neatParams = new NeatParameters();
            //neatParams.noveltySearch = true;
            //neatParams.noveltyFloat = true;
            neatParams.multiobjective = true;
            neatParams.archiveThreshold = 0.5;
            //neatParams.archiveThreshold = 300000.0;

            //maybe we load this idgenerator from server or local database, just keep that in mind
            idgen = new IdGenerator();

            //we just default to this, but it doesn't have to be so
            this.setDefaultCPPNs(4, 3);

            genomeListDictionary.Add(CurrentGenomePool, new GenomeList());
        }
        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="copyFrom"></param>
        public NeatParameters(NeatParameters copyFrom)
        {
            populationSize = copyFrom.populationSize;

            pOffspringAsexual   = copyFrom.pOffspringAsexual;
            pOffspringSexual    = copyFrom.pOffspringSexual;
            pInterspeciesMating = copyFrom.pInterspeciesMating;

            pDisjointExcessGenesRecombined = copyFrom.pDisjointExcessGenesRecombined;

            pMutateConnectionWeights  = copyFrom.pMutateConnectionWeights;
            pMutateAddNode            = copyFrom.pMutateAddNode;
            pMutateAddConnection      = copyFrom.pMutateAddConnection;
            pMutateDeleteConnection   = copyFrom.pMutateDeleteConnection;
            pMutateDeleteSimpleNeuron = copyFrom.pMutateDeleteSimpleNeuron;

            // Copy the list.
            ConnectionMutationParameterGroupList = new ConnectionMutationParameterGroupList(copyFrom.ConnectionMutationParameterGroupList);

            compatibilityThreshold        = copyFrom.compatibilityThreshold;
            compatibilityDisjointCoeff    = copyFrom.compatibilityDisjointCoeff;
            compatibilityExcessCoeff      = copyFrom.compatibilityExcessCoeff;
            compatibilityWeightDeltaCoeff = copyFrom.compatibilityWeightDeltaCoeff;

            elitismProportion   = copyFrom.elitismProportion;
            selectionProportion = copyFrom.selectionProportion;

            targetSpeciesCountMin = copyFrom.targetSpeciesCountMin;
            targetSpeciesCountMax = copyFrom.targetSpeciesCountMax;

            pruningPhaseBeginComplexityThreshold         = copyFrom.pruningPhaseBeginComplexityThreshold;
            pruningPhaseBeginFitnessStagnationThreshold  = copyFrom.pruningPhaseBeginFitnessStagnationThreshold;
            pruningPhaseEndComplexityStagnationThreshold = copyFrom.pruningPhaseEndComplexityStagnationThreshold;

            speciesDropoffAge = copyFrom.speciesDropoffAge;

            connectionWeightRange = copyFrom.connectionWeightRange;
        }
Example #6
0
		/// <summary>
		/// Create a default minimal genome that describes a NN with the given number of inputs and outputs.
		/// </summary>
		/// <returns></returns>
		public static IGenome CreateGenome(NeatParameters neatParameters, IdGenerator idGenerator, int inputNeuronCount, int outputNeuronCount, int outputsPerPolicy, float connectionProportion)
		{
            IActivationFunction actFunct;
			NeuronGene neuronGene; // temp variable.
			NeuronGeneList inputNeuronGeneList = new NeuronGeneList(); // includes bias neuron.
			NeuronGeneList outputNeuronGeneList = new NeuronGeneList();
			NeuronGeneList neuronGeneList = new NeuronGeneList();
			ConnectionGeneList connectionGeneList = new ConnectionGeneList();

			// IMPORTANT NOTE: The neurons must all be created prior to any connections. That way all of the genomes
			// will obtain the same innovation ID's for the bias,input and output nodes in the initial population.
			// Create a single bias neuron.
            //TODO: DAVID proper activation function change to NULL?
            actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn");
            //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Bias, actFunct);
            neuronGene = new NeuronGene(null, idGenerator.NextInnovationId, NeuronGene.INPUT_LAYER, NeuronType.Bias, actFunct);
			inputNeuronGeneList.Add(neuronGene);
			neuronGeneList.Add(neuronGene);

			// Create input neuron genes.
            actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn");
			for(int i=0; i<inputNeuronCount; i++)
			{
                //TODO: DAVID proper activation function change to NULL?
                //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Input, actFunct);
                neuronGene = new NeuronGene(null, idGenerator.NextInnovationId, NeuronGene.INPUT_LAYER, NeuronType.Input, actFunct);
				inputNeuronGeneList.Add(neuronGene);
				neuronGeneList.Add(neuronGene);
			}

			// Create output neuron genes. 
            //actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn");
			for(int i=0; i<outputNeuronCount; i++)
			{
                actFunct = ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid");
                //actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters);
                //TODO: DAVID proper activation function
                //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Output, actFunct);
                neuronGene = new NeuronGene(null, idGenerator.NextInnovationId, NeuronGene.OUTPUT_LAYER, NeuronType.Output, actFunct);
				outputNeuronGeneList.Add(neuronGene);
				neuronGeneList.Add(neuronGene);
			}

			// Loop over all possible connections from input to output nodes and create a number of connections based upon
			// connectionProportion.
			foreach(NeuronGene targetNeuronGene in outputNeuronGeneList)
			{
				foreach(NeuronGene sourceNeuronGene in inputNeuronGeneList)
				{
					// Always generate an ID even if we aren't going to use it. This is necessary to ensure connections
					// between the same neurons always have the same ID throughout the generated population.
					uint connectionInnovationId = idGenerator.NextInnovationId;

					if(Utilities.NextDouble() < connectionProportion)
					{	// Ok lets create a connection.
						connectionGeneList.Add(	new ConnectionGene(connectionInnovationId, 
							sourceNeuronGene.InnovationId,
							targetNeuronGene.InnovationId,
							(Utilities.NextDouble() * neatParameters.connectionWeightRange ) - neatParameters.connectionWeightRange/2.0));  // Weight 0 +-5
					}
				}
			}

            // Don't create any hidden nodes at this point. Fundamental to the NEAT way is to start minimally!
            // Schrum: Added outputsPerPolicy: If outputsPerPolicy == outputNeuronCount, then behaves like default NEAT
            return new NeatGenome(idGenerator.NextGenomeId, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount, outputsPerPolicy);
		}
Example #7
0
 public void initalizeEvoManager(int cInputs, int cOuputs, NeatParameters np, IPopulationEvaluator popEval)
 {
     cppnInputs = cInputs;
     cppnOutputs = cOuputs;
     neatParams = np;
     populationEval = popEval;
 }
Example #8
0
        /// <summary>
        /// Add a new node to the Genome. We do this by removing a connection at random and inserting 
        /// a new node and two new connections that make the same circuit as the original connection.
        /// 
        /// This way the new node is properly integrated into the network from the outset.
        /// </summary>
        /// <param name="ea"></param>
        private void Mutate_AddNode(NeatParameters neatParameters, IdGenerator idGen, Hashtable NewNeuronGeneStructTable)
        {
            if(connectionGeneList.Count==0)
                return;

            // Select a connection at random.
            int connectionToReplaceIdx = (int)Math.Floor(Utilities.NextDouble() * connectionGeneList.Count);
            ConnectionGene connectionToReplace = connectionGeneList[connectionToReplaceIdx];

            // Delete the existing connection. JOEL: Why delete old connection?
            //connectionGeneList.RemoveAt(connectionToReplaceIdx);

            // Check if this connection has already been split on another genome. If so then we should re-use the
            // neuron ID and two connection ID's so that matching structures within the population maintain the same ID.
            object existingNeuronGeneStruct = NewNeuronGeneStructTable[connectionToReplace.InnovationId];

            NeuronGene newNeuronGene;
            ConnectionGene newConnectionGene1;
            ConnectionGene newConnectionGene2;
            IActivationFunction actFunct;

            WINManager win = WINManager.SharedWIN;
            WINNode node;
            WINConnection connection;

            if(existingNeuronGeneStruct==null)
            {	// No existing matching structure, so generate some new ID's.

                //TODO: DAVID proper random activation function
                // Replace connectionToReplace with two new connections and a neuron.
                actFunct=ActivationFunctionFactory.GetRandomActivationFunction(neatParameters);
                //newNeuronGene = new NeuronGene(ea.NextInnovationId, NeuronType.Hidden, actFunct);

                //we should be making a call to WIN anytime we call for a new innovationID

                //here we create a new node, and two new connections
                //we don't send in a genomeID here, so we get it set for us!
                node = win.createWINNode(new PropertyObject() { { WINNode.SNodeString, NeuronType.Hidden.ToString()}});
                newNeuronGene = new NeuronGene(null, node.UniqueID, (neuronGeneList.GetNeuronById(connectionToReplace.SourceNeuronId).Layer + neuronGeneList.GetNeuronById(connectionToReplace.TargetNeuronId).Layer) / 2.0, NeuronType.Hidden, actFunct);

                //we don't send in any uniqueIDs so they are generated for us, and we update our idGen object
                connection = win.createWINConnection(WINConnection.ConnectionWithProperties(connectionToReplace.SourceNeuronId, newNeuronGene.InnovationId), idGen);
                newConnectionGene1 = new ConnectionGene(connection.UniqueID, connection.SourceID,  connection.TargetID , 1.0);

                //we don't send in any uniqueIDs so they are generated for us, and we update our idGen object
                connection = win.createWINConnection(WINConnection.ConnectionWithProperties(newNeuronGene.InnovationId, connectionToReplace.TargetNeuronId), idGen);
                newConnectionGene2 = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID, connectionToReplace.Weight);

                // Register the new ID's with NewNeuronGeneStructTable.
                NewNeuronGeneStructTable.Add(connectionToReplace.InnovationId,
                                                new NewNeuronGeneStruct(newNeuronGene, newConnectionGene1, newConnectionGene2));
            }
            else
            {	// An existing matching structure has been found. Re-use its ID's

                //Since we don't call idGen.nextinnovationID,  we don't have to create anything new
                //however, we need to note the change in weights override previous weight values
                //this should be documented in WIN - either explicitly (calling a function to note changes) or implicitly (by scanning the changes in a saved genome)
                //Probably explicitly, calling a mutate function for a SingleStep (since we are in the SingleStep process of creating new individuals)

                //TODO: DAVID proper random activation function
                // Replace connectionToReplace with two new connections and a neuron.
                actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters);
                NewNeuronGeneStruct tmpStruct = (NewNeuronGeneStruct)existingNeuronGeneStruct;
                //newNeuronGene = new NeuronGene(tmpStruct.NewNeuronGene.InnovationId, NeuronType.Hidden, actFunct);
                newNeuronGene = new NeuronGene(null, tmpStruct.NewNeuronGene.InnovationId, tmpStruct.NewNeuronGene.Layer, NeuronType.Hidden, actFunct);

                newConnectionGene1 = new ConnectionGene(tmpStruct.NewConnectionGene_Input.InnovationId, connectionToReplace.SourceNeuronId, newNeuronGene.InnovationId, 1.0);
                newConnectionGene2 = new ConnectionGene(tmpStruct.NewConnectionGene_Output.InnovationId, newNeuronGene.InnovationId, connectionToReplace.TargetNeuronId, connectionToReplace.Weight);
            }

            // Add the new genes to the genome.
            neuronGeneList.Add(newNeuronGene);
            connectionGeneList.InsertIntoPosition(newConnectionGene1);
            connectionGeneList.InsertIntoPosition(newConnectionGene2);
        }
 /// <summary>
 /// Compare this IGenome with the provided one. They are compatibile if their calculated difference
 /// is below the current threshold specified by NeatParameters.compatibilityThreshold
 /// </summary>
 /// <param name="comparisonGenome"></param>
 /// <param name="neatParameters"></param>
 /// <returns></returns>
 abstract public bool IsCompatibleWithGenome(IGenome comparisonGenome, NeatParameters neatParameters);
Example #10
0
        /// <summary>
        /// Given a description of a connection in two parents, decide how to copy it into their child.
        /// A helper function that is only called by CreateOffspring_Sexual().
        /// </summary>
        /// <param name="correlationItem">Describes a connection and whether it exists on one parent, the other, or both.</param>
        /// <param name="fitSwitch">If this is 1, then the first parent is more fit; if 2 then the second parent. Other values are not defined.</param>
        /// <param name="combineDisjointExcessFlag">If this is true, add disjoint and excess genes to the child; otherwise, leave them out.</param>
        /// <param name="np">Not used.</param>
		private void CreateOffspring_Sexual_ProcessCorrelationItem(CorrelationItem correlationItem,
                                                                   byte fitSwitch,
                                                                   bool combineDisjointExcessFlag,
                                                                   NeatParameters np)
		{
			switch(correlationItem.CorrelationItemType)
			{	
				// Disjoint and excess genes.
				case CorrelationItemType.DisjointConnectionGene:
				case CorrelationItemType.ExcessConnectionGene:
				{
					// If the gene is in the fittest parent then override any existing entry in the connectionGeneTable.
					if(fitSwitch==1 && correlationItem.ConnectionGene1!=null)
					{
						CreateOffspring_Sexual_AddGene(correlationItem.ConnectionGene1, true);
						return;
					}

					if(fitSwitch==2 && correlationItem.ConnectionGene2!=null)
					{
						CreateOffspring_Sexual_AddGene(correlationItem.ConnectionGene2, true);
						return;
					}

					// The disjoint/excess gene is on the less fit parent.
                    //if(Utilities.NextDouble() < np.pDisjointExcessGenesRecombined)	// Include the gene n% of the time from whichever parent contains it.
					if(combineDisjointExcessFlag)
					{
						if(correlationItem.ConnectionGene1!=null)
						{
							CreateOffspring_Sexual_AddGene(correlationItem.ConnectionGene1, false);
							return;
						}
						if(correlationItem.ConnectionGene2!=null)
						{
							CreateOffspring_Sexual_AddGene(correlationItem.ConnectionGene2, false);
							return;
						}
					}
					break;
				}

                case CorrelationItemType.MatchedConnectionGenes:
				{
					if(RouletteWheel.SingleThrow(0.5))
					{
						// Override any existing entries in the table.
						CreateOffspring_Sexual_AddGene(correlationItem.ConnectionGene1, true);
					}
					else
					{
						// Override any existing entries in the table.
						CreateOffspring_Sexual_AddGene(correlationItem.ConnectionGene2, true);
					}
					break;
				}
			} 
		}
		private void BeginPruningPhase()
		{
			// Enter pruning phase.
			pruningMode = true;
			prunePhase_generationAtLastSimplification = generation;
			prunePhase_MinimumStructuresPerGenome = pop.AvgComplexity;
			neatParameters = neatParameters_PrunePhase;

			// Copy the speciation threshold as this is dynamically altered during a search and we wish to maintain
			// the tracking during pruning.
			neatParameters.compatibilityThreshold = neatParameters_Normal.compatibilityThreshold;

			System.Diagnostics.Debug.WriteLine(">>Prune Phase<< Complexity=" + pop.AvgComplexity.ToString("0.00"));
		}
		/// <summary>
		/// Default Constructor.
		/// </summary>
		public EvolutionAlgorithm(Population pop, IPopulationEvaluator populationEvaluator, NeatParameters neatParameters)
		{
			this.pop = pop;
			this.populationEvaluator = populationEvaluator;
			this.neatParameters = neatParameters;
			neatParameters_Normal = neatParameters;

			neatParameters_PrunePhase = new NeatParameters(neatParameters);
			neatParameters_PrunePhase.pMutateAddConnection = 0.0;
            neatParameters_PrunePhase.pMutateAddNode = 0.0;
            neatParameters_PrunePhase.pMutateAddModule = 0.0;
            neatParameters_PrunePhase.pMutateConnectionWeights = 0.33;
			neatParameters_PrunePhase.pMutateDeleteConnection = 0.33;
			neatParameters_PrunePhase.pMutateDeleteSimpleNeuron = 0.33;

			// Disable all crossover as this has a tendency to increase complexity, which is precisely what
			// we don't want during a pruning phase.
			neatParameters_PrunePhase.pOffspringAsexual = 1.0;
			neatParameters_PrunePhase.pOffspringSexual = 0.0;

            if (neatParameters.mapelites)
            {
                meInitialisePopulation();
                meGridInit(pop);
                Console.WriteLine("Mapelites stuff has been initialized. Oh btw, we're doing mapelites.");
                if (neatParameters.me_simpleGeneticDiversity)
                {
                    Console.WriteLine("Mapelites reinforced by the power of 51MPLE gENET1C d1VER51TY!!!!1  *fireworks* *applause* *receive phd*");
                }
                if (neatParameters.me_noveltyPressure)
                {
                    Console.WriteLine("Mapelites now with NOVELTY PRESSURE! (>'')>");
                }
            } // Skip all that other stupid shit if we are doing MapElites
            else if (neatParameters.NS2)
            {
                if (neatParameters.NS1) ns1 = true;

                ns2InitializePopulation();
                if (neatParameters.track_me_grid)
                {
                    Console.WriteLine("Initializing mapelites-style-grid genome tracking..");
                    meGridInit(pop);
                }
                Console.WriteLine("Novelty Search 2.0 has been initialized.");
            } // Skip the code jungle below if we are doing Novelty Search 2.0
            else if (neatParameters.NSLC) // (Steady-State NSLC -- NEW!!)
            {
                // TODO: JUSTIN: SS-NSLC GOES HERE!
                ns1 = true;
                ns2InitializePopulation();
                if (neatParameters.track_me_grid)
                {
                    Console.WriteLine("Initializing mapelites-style-grid genome tracking..");
                    meGridInit(pop);
                }
                Console.WriteLine("Initializing STEADY STATE -- NSLC! NEW! This is a thing that is happening now. You cannot stop it. Relax.");
                // TODO: INITIALIZATION for SS-NSLC (is like NS1... but make it separate so we can stop being so intertwined. cleaner is better, yo)


            } // Skip the nasty quagmire of unverified bogus rotten banana sandwiches if doing Steady-State NSLC
            else
            {
                if (neatParameters.multiobjective)
                {
                    this.multiobjective = new Multiobjective.Multiobjective(neatParameters);
                    neatParameters.compatibilityThreshold = 100000000.0; //disable speciation w/ multiobjective
                }

                if (neatParameters.noveltySearch)
                {
                    if (neatParameters.noveltyHistogram)
                    {
                        this.noveltyFixed = new noveltyfixed(neatParameters.archiveThreshold);
                        this.histogram = new noveltyhistogram(neatParameters.histogramBins);
                        noveltyInitialized = true;
                        InitialisePopulation();
                    }

                    if (neatParameters.noveltyFixed || neatParameters.noveltyFloat)
                    {
                        this.noveltyFixed = new noveltyfixed(neatParameters.archiveThreshold);
                        InitialisePopulation();
                        noveltyFixed.initialize(this.pop);
                        noveltyInitialized = true;
                        populationEvaluator.EvaluatePopulation(pop, this);
                        UpdateFitnessStats();
                        DetermineSpeciesTargetSize();
                    }

                    if (neatParameters.track_me_grid)
                    {
                        Console.WriteLine("Initializing mapelites-style-grid genome tracking..");
                        meGridInit(pop); // JUSTIN: Trying to add grid-tracking to NS1
                    }

                }
                else
                {
                    InitialisePopulation();

                    if (neatParameters.track_me_grid)
                    {
                        Console.WriteLine("Initializing mapelites-style-grid genome tracking..");
                        meGridInit(pop); // JUSTIN: Trying to add grid-tracking to fitness-based search
                    }
                }
            }
		}
Example #13
0
        /// <summary>
        /// Paul: Modified the mutation function to take in the required objects, instead of Evolution Algorithm.
        /// This way, mutation isn't tied to a large EA object, but can still function without issue. Useful for interactive evolution framework.
        /// </summary>
        /// <param name="neatParameters"></param>
        /// <param name="idGen"></param>
        /// <param name="genomeHashtable"></param>
        /// <param name="connectionHashTable"></param>
        public void Mutate(NeatParameters neatParameters, IdGenerator idGen, Hashtable genomeHashtable, Hashtable connectionHashTable)
        {
            // Determine the type of mutation to perform.
            double[] probabilities = new double[]
            {
                neatParameters.pMutateAddNode,
                neatParameters.pMutateAddModule,
                neatParameters.pMutateAddConnection,
                neatParameters.pMutateDeleteConnection,
                neatParameters.pMutateDeleteSimpleNeuron,
                neatParameters.pMutateConnectionWeights
            };

            int outcome = RouletteWheel.SingleThrow(probabilities);

            switch(outcome)
            {
                case 0:
                    //basic support by WIN, but doesn't acknowledge weight changes
                    Mutate_AddNode(neatParameters, idGen, genomeHashtable);
                    break;
                case 1:
                    //currently not totally supported by WIN
                    Mutate_AddModule(neatParameters, idGen, connectionHashTable);
                    break;
                case 2:
                    //WIN basic support, doesn't acknowledge weight changes
                    Mutate_AddConnection(neatParameters, idGen, connectionHashTable);
                    break;
                case 3:
                    //Doesn't acknowledge weight changes yet
                    Mutate_DeleteConnection();
                    break;
                case 4:
                    //WIN doesn't acknowledge deletion of neurons yet
                    Mutate_DeleteSimpleNeuronStructure(neatParameters, idGen, connectionHashTable);
                    break;
                case 5:
                    //Win doesn't yet acknowledge the weight changes
                    Mutate_ConnectionWeights(neatParameters);
                    break;
            }
        }
Example #14
0
        public static GenomeList CreateGenomeListPreserveIDs(NeatParameters neatParameters, IdGenerator idGenerator, 
            int inputNeuronCount, int outputNeuronCount, float connectionProportion, int length, AssessGenotypeFunction assess)
        {
            GenomeList genomeList = new GenomeList();

            int testCount = 0; int maxTests = 5;

            //for (int i = 0; i < length; i++)
            while(genomeList.Count < length)
            {
                    IGenome genome = CreateGenomePreserveID(neatParameters, idGenerator, inputNeuronCount, outputNeuronCount, connectionProportion);

                    if (assess != null && assess(genome) && testCount++ < maxTests)
                    {
                        //after adding the genome, reset test count
                        genomeList.Add(genome);
                        testCount = 0;
                    }
                    else if (assess == null)
                        genomeList.Add(genome);
                    else if (testCount >= maxTests)
                    {
                        genomeList.Add(genome);
                        testCount = 0;
                    }
            }

            return genomeList;
        }
Example #15
0
        public IGenome CreateOffspring_Asexual(NeatParameters neatParameters, IdGenerator idGen, Hashtable newNeuronTable, Hashtable newConnectionTable)
        {
            // Make an exact copy this Genome.
            NeatGenome offspring = new NeatGenome(this, idGen.NextGenomeId);

            // Mutate the new genome.
            //WIN acknowledges any connection or node mutations, but doesn't save any other mutations
            offspring.Mutate(neatParameters, idGen, newNeuronTable, newConnectionTable);

            return offspring;
        }
Example #16
0
        public IGenome CreateOffspring_Sexual(NeatParameters np, IdGenerator idGen, IGenome parent)
        {
            NeatGenome otherParent = parent as NeatGenome;
            if (otherParent == null)
                return null;

            // Build a list of connections in either this genome or the other parent.
            CorrelationResults correlationResults = CorrelateConnectionGeneLists(connectionGeneList, otherParent.connectionGeneList);
            Debug.Assert(correlationResults.PerformIntegrityCheck(), "CorrelationResults failed integrity check.");

            //----- Connection Genes.
            // We will temporarily store the offspring's genes in newConnectionGeneList and keeping track of which genes
            // exist with newConnectionGeneTable. Here we ensure these objects are created, and if they already existed
            // then ensure they are cleared. Clearing existing objects is more efficient that creating new ones because
            // allocated memory can be re-used.

            // Key = connection key, value = index in newConnectionGeneList.
            if (newConnectionGeneTable == null)
            {	// Provide a capacity figure to the new Hashtable. The offspring will be the same length (or thereabouts).
                newConnectionGeneTable = new Hashtable(connectionGeneList.Count);
            }
            else
            {
                newConnectionGeneTable.Clear();
            }
            //TODO: No 'capacity' constructor on CollectionBase. Create modified/custom CollectionBase.
            // newConnectionGeneList must be constructed on each call because it is passed to a new NeatGenome
            // at construction time and a permanent reference to the list is kept.
            newConnectionGeneList = new ConnectionGeneList(ConnectionGeneList.Count);

            // A switch that stores which parent is fittest 1 or 2. Chooses randomly if both are equal. More efficient to calculate this just once.
            byte fitSwitch;
            if (Fitness > otherParent.Fitness)
                fitSwitch = 1;
            else if (Fitness < otherParent.Fitness)
                fitSwitch = 2;
            else
            {	// Select one of the parents at random to be the 'master' genome during crossover.
                if (Utilities.NextDouble() < 0.5)
                    fitSwitch = 1;
                else
                    fitSwitch = 2;
            }

            bool combineDisjointExcessFlag = Utilities.NextDouble() < np.pDisjointExcessGenesRecombined;

            // Loop through the correlationResults, building a table of ConnectionGenes from the parents that will make it into our
            // new [single] offspring. We use a table keyed on connection end points to prevent passing connections to the offspring
            // that may have the same end points but a different innovation number - effectively we filter out duplicate connections.
            int idxBound = correlationResults.CorrelationItemList.Count;
            for (int i = 0; i < idxBound; i++)
            {
                CreateOffspring_Sexual_ProcessCorrelationItem((CorrelationItem)correlationResults.CorrelationItemList[i], fitSwitch, combineDisjointExcessFlag, np);
            }

            //----- Neuron Genes.
            // Build a neuronGeneList by analysing each connection's neuron end-point IDs.
            // This strategy has the benefit of eliminating neurons that are no longer connected too.
            // Remember to always keep all input, output and bias neurons though!
            NeuronGeneList newNeuronGeneList = new NeuronGeneList(neuronGeneList.Count);

            // Keep a table of the NeuronGene ID's keyed by ID so that we can keep track of which ones have been added.
            // Key = innovation ID, value = null for some reason.
            if (newNeuronGeneTable == null)
                newNeuronGeneTable = new Hashtable(neuronGeneList.Count);
            else
                newNeuronGeneTable.Clear();

            // Get the input/output neurons from this parent. All Genomes share these neurons, they do not change during a run.
            idxBound = neuronGeneList.Count;
            for (int i = 0; i < idxBound; i++)
            {
                if (neuronGeneList[i].NeuronType != NeuronType.Hidden)
                {
                    newNeuronGeneList.Add(new NeuronGene(neuronGeneList[i]));
                    newNeuronGeneTable.Add(neuronGeneList[i].InnovationId, null);
                }
                else
                {	// No more bias, input or output nodes. break the loop.
                    break;
                }
            }

            // Now analyse the connections to determine which NeuronGenes are required in the offspring.
            // Loop through every connection in the child, and add to the child those hidden neurons that are sources or targets of the connection.
            idxBound = newConnectionGeneList.Count;
            for (int i = 0; i < idxBound; i++)
            {
                NeuronGene neuronGene;
                ConnectionGene connectionGene = newConnectionGeneList[i];
                if (!newNeuronGeneTable.ContainsKey(connectionGene.SourceNeuronId))
                {
                    //TODO: DAVID proper activation function
                    // We can safely assume that any missing NeuronGenes at this point are hidden heurons.
                    neuronGene = this.neuronGeneList.GetNeuronById(connectionGene.SourceNeuronId);
                    if (neuronGene != null)
                        newNeuronGeneList.Add(new NeuronGene(neuronGene));
                    else
                        newNeuronGeneList.Add(new NeuronGene(otherParent.NeuronGeneList.GetNeuronById(connectionGene.SourceNeuronId)));
                    //newNeuronGeneList.Add(new NeuronGene(connectionGene.SourceNeuronId, NeuronType.Hidden, ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoid")));
                    newNeuronGeneTable.Add(connectionGene.SourceNeuronId, null);
                }

                if (!newNeuronGeneTable.ContainsKey(connectionGene.TargetNeuronId))
                {
                    //TODO: DAVID proper activation function
                    // We can safely assume that any missing NeuronGenes at this point are hidden heurons.
                    neuronGene = this.neuronGeneList.GetNeuronById(connectionGene.TargetNeuronId);
                    if (neuronGene != null)
                        newNeuronGeneList.Add(new NeuronGene(neuronGene));
                    else
                        newNeuronGeneList.Add(new NeuronGene(otherParent.NeuronGeneList.GetNeuronById(connectionGene.TargetNeuronId)));
                    //newNeuronGeneList.Add(new NeuronGene(connectionGene.TargetNeuronId, NeuronType.Hidden, ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoid")));
                    newNeuronGeneTable.Add(connectionGene.TargetNeuronId, null);
                }
            }

            // Determine which modules to pass on to the child in the same way.
            // For each module in this genome or in the other parent, if it was referenced by even one connection add it and all its dummy neurons to the child.
            List<ModuleGene> newModuleGeneList = new List<ModuleGene>();

            // Build a list of modules the child might have, which is a union of the parents' module lists, but they are all copies so we can't just do a union.
            List<ModuleGene> unionParentModules = new List<ModuleGene>(moduleGeneList);
            foreach (ModuleGene moduleGene in otherParent.moduleGeneList)
            {
                bool alreadySeen = false;
                foreach (ModuleGene match in unionParentModules)
                {
                    if (moduleGene.InnovationId == match.InnovationId)
                    {
                        alreadySeen = true;
                        break;
                    }
                }
                if (!alreadySeen)
                {
                    unionParentModules.Add(moduleGene);
                }
            }

            foreach (ModuleGene moduleGene in unionParentModules)
            {
                // Examine each neuron in the child to determine whether it is part of a module.
                foreach (List<long> dummyNeuronList in new List<long>[] { moduleGene.InputIds, moduleGene.OutputIds })
                {
                    foreach (long dummyNeuronId in dummyNeuronList)
                    {
                        if (newNeuronGeneTable.ContainsKey(dummyNeuronId))
                        {
                            goto childHasModule;
                        }
                    }
                }

                continue; // the child does not contain this module, so continue the loop and check for the next module.
            childHasModule: // the child does contain this module, so make sure the child gets all the nodes the module requires to work.

                // Make sure the child has all the neurons in the given module.
                newModuleGeneList.Add(new ModuleGene(moduleGene));
            foreach (List<long> dummyNeuronList in new List<long>[] { moduleGene.InputIds, moduleGene.OutputIds })
                {
                    foreach (long dummyNeuronId in dummyNeuronList)
                    {
                        if (!newNeuronGeneTable.ContainsKey(dummyNeuronId))
                        {
                            newNeuronGeneTable.Add(dummyNeuronId, null);
                            NeuronGene neuronGene = this.neuronGeneList.GetNeuronById(dummyNeuronId);
                            if (neuronGene != null)
                            {
                                newNeuronGeneList.Add(new NeuronGene(neuronGene));
                            }
                            else
                            {
                                newNeuronGeneList.Add(new NeuronGene(otherParent.NeuronGeneList.GetNeuronById(dummyNeuronId)));
                            }
                        }
                    }
                }
            }

            // TODO: Inefficient code?
            newNeuronGeneList.SortByInnovationId();

            //PAUL: WIN should go here some more!
            //in the future, we're going to call out to WIN to create our NeatGenome for us, where it will save it
            //TODO: WIN calls for sexual reproduction

            // newConnectionGeneList is already sorted because it was generated by passing over the list returned by
            // CorrelateConnectionGeneLists() - which is always in order.
            return new NeatGenome(idGen.NextGenomeId, newNeuronGeneList, newModuleGeneList, newConnectionGeneList, inputNeuronCount, outputNeuronCount);
        }
Example #17
0
        private void RemoveSimpleNeuron(long neuronId, NeatParameters neatParameters, IdGenerator idGen, Hashtable NewConnectionGeneTable)
        {
            WINManager win = WINManager.SharedWIN;
            //WINNode node;
            WINConnection connection;
            // Create new connections that connect all of the incoming and outgoing neurons
            // that currently exist for the simple neuron.
            NeuronConnectionLookup lookup = (NeuronConnectionLookup)neuronConnectionLookupTable[neuronId];
            foreach(ConnectionGene incomingConnection in lookup.incomingList)
            {
                foreach(ConnectionGene outgoingConnection in lookup.outgoingList)
                {
                    if(TestForExistingConnection(incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId))
                    {	// Connection already exists.
                        continue;
                    }

                    // Test for matching connection within NewConnectionGeneTable.
                    ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(incomingConnection.SourceNeuronId,
                                                                                            outgoingConnection.TargetNeuronId);
                    ConnectionGene existingConnection = (ConnectionGene)NewConnectionGeneTable[connectionKey];
                    ConnectionGene newConnectionGene;
                    if(existingConnection==null)
                    {

                        // No matching connection found. Create a connection with a new ID.

                        //create our newest conncetion, noting the source,target and weight
                        connection = win.createWINConnection(
               WINConnection.ConnectionWithProperties(incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId), idGen);

                        // Create a new connection with a new ID and add it to the Genome.
                        newConnectionGene = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID,
                             (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0
                             );

                        //newConnectionGene = new ConnectionGene(idGen.NextInnovationId,
                        //    incomingConnection.SourceNeuronId,
                        //    outgoingConnection.TargetNeuronId,
                        //    (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange/2.0);

                        // Register the new ID with NewConnectionGeneTable.
                        NewConnectionGeneTable.Add(connectionKey, newConnectionGene);

                        // Add the new gene to the genome.
                        connectionGeneList.Add(newConnectionGene);
                    }
                    else
                    {
                        //WIN should acknowledge change in individual here

                        // Matching connection found. Re-use its ID.
                        newConnectionGene = new ConnectionGene(existingConnection.InnovationId,
                            incomingConnection.SourceNeuronId,
                            outgoingConnection.TargetNeuronId,
                            (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange/2.0);

                        // Add the new gene to the genome. Use InsertIntoPosition() to ensure we don't break the sort
                        // order of the connection genes.
                        connectionGeneList.InsertIntoPosition(newConnectionGene);
                    }

                }
            }

            // Delete the old connections.
            foreach(ConnectionGene incomingConnection in lookup.incomingList)
                connectionGeneList.Remove(incomingConnection);

            foreach(ConnectionGene outgoingConnection in lookup.outgoingList)
            {
                // Filter out recurrent connections - they will have already been
                // deleted in the loop through 'lookup.incomingList'.
                if(outgoingConnection.TargetNeuronId != neuronId)
                    connectionGeneList.Remove(outgoingConnection);
            }

            // Delete the simple neuron - it no longer has any connections to or from it.
            neuronGeneList.Remove(neuronId);
        }
Example #18
0
        /// <summary>
        /// We define a simple neuron structure as a neuron that has a single outgoing or single incoming connection.
        /// With such a structure we can easily eliminate the neuron and shift it's connections to an adjacent neuron.
        /// If the neuron's non-linearity was not being used then such a mutation is a simplification of the network
        /// structure that shouldn't adversly affect its functionality.
        /// </summary>
        private void Mutate_DeleteSimpleNeuronStructure(NeatParameters neatParameters, IdGenerator idGen, Hashtable NewConnectionGeneTable)
        {
            //TODO: WIN acknowledge deletion of neurongene
            // We will use the NeuronConnectionLookupTable to find the simple structures.
            EnsureNeuronConnectionLookupTable();

            // Build a list of candidate simple neurons to choose from.
            ArrayList simpleNeuronIdList = new ArrayList();

            foreach(NeuronConnectionLookup lookup in neuronConnectionLookupTable.Values)
            {
                // If we test the connection count with <=1 then we also pick up neurons that are in dead-end circuits,
                // RemoveSimpleNeuron is then able to delete these neurons from the network structure along with any
                // associated connections.
                // All neurons that are part of a module would appear to be dead-ended, but skip removing them anyway.
                if (lookup.neuronGene.NeuronType == NeuronType.Hidden
                            && !(lookup.neuronGene.ActivationFunction is ModuleInputNeuron)
                            && !(lookup.neuronGene.ActivationFunction is ModuleOutputNeuron) ) {
                    if((lookup.incomingList.Count<=1) || (lookup.outgoingList.Count<=1))
                        simpleNeuronIdList.Add(lookup.neuronGene.InnovationId);
                }
            }

            // Are there any candiate simple neurons?
            if(simpleNeuronIdList.Count==0)
            {	// No candidate neurons. As a fallback lets delete a connection.
                Mutate_DeleteConnection();
                return;
            }

            // Pick a simple neuron at random.
            int idx = (int)Math.Floor(Utilities.NextDouble() * simpleNeuronIdList.Count);
            long neuronId = (long)simpleNeuronIdList[idx];
            RemoveSimpleNeuron(neuronId, neatParameters, idGen, NewConnectionGeneTable);
        }
Example #19
0
        private void Mutate_ConnectionWeights(NeatParameters neatParameters)
        {
            // Determine the type of weight mutation to perform.
            int groupCount = neatParameters.ConnectionMutationParameterGroupList.Count;
            double[] probabilties = new double[groupCount];
            for(int i=0; i<groupCount; i++)
            {
                probabilties[i] = ((ConnectionMutationParameterGroup)neatParameters.ConnectionMutationParameterGroupList[i]).ActivationProportion;
            }

            // Get a reference to the group we will be using.
            ConnectionMutationParameterGroup paramGroup = (ConnectionMutationParameterGroup)neatParameters.ConnectionMutationParameterGroupList[RouletteWheel.SingleThrow(probabilties)];

            // Perform mutations of the required type.
            if(paramGroup.SelectionType==ConnectionSelectionType.Proportional)
            {
                bool mutationOccured=false;
                int connectionCount = connectionGeneList.Count;
                for(int i=0; i<connectionCount; i++)
                {
                    if(Utilities.NextDouble() < paramGroup.Proportion)
                    {
                        MutateConnectionWeight(connectionGeneList[i], neatParameters, paramGroup);
                        mutationOccured = true;
                    }
                }
                if(!mutationOccured && connectionCount>0)
                {	// Perform at least one mutation. Pick a gene at random.
                    MutateConnectionWeight(	connectionGeneList[(int)(Utilities.NextDouble() * connectionCount)],
                                            neatParameters,
                                            paramGroup);
                }
            }
            else // if(paramGroup.SelectionType==ConnectionSelectionType.FixedQuantity)
            {
                // Determine how many mutations to perform. At least one - if there are any genes.
                int connectionCount = connectionGeneList.Count;
                int mutations = Math.Min(connectionCount, Math.Max(1, paramGroup.Quantity));
                if(mutations==0) return;

                // The mutation loop. Here we pick an index at random and scan forward from that point
                // for the first non-mutated gene. This prevents any gene from being mutated more than once without
                // too much overhead. In fact it's optimal for small numbers of mutations where clashes are unlikely
                // to occur.
                for(int i=0; i<mutations; i++)
                {
                    // Pick an index at random.
                    int index = (int)(Utilities.NextDouble()*connectionCount);
                    ConnectionGene connectionGene = connectionGeneList[index];

                    // Scan forward and find the first non-mutated gene.
                    while(connectionGeneList[index].IsMutated)
                    {	// Increment index. Wrap around back to the start if we go off the end.
                        if(++index==connectionCount)
                            index=0;
                    }

                    // Mutate the gene at 'index'.
                    MutateConnectionWeight(connectionGeneList[index], neatParameters, paramGroup);
                    connectionGeneList[index].IsMutated = true;
                }
            }
        }
Example #20
0
		public static GenomeList CreateGenomeList(Population seedPopulation, int length, NeatParameters neatParameters, IdGenerator idGenerator)
		{
			//Build the list.
			GenomeList genomeList = new GenomeList();
			int seedIdx=0;
			
			for(int i=0; i<length; i++)
			{
				NeatGenome newGenome = new NeatGenome((NeatGenome)seedPopulation.GenomeList[seedIdx], idGenerator.NextGenomeId);

				// Reset the connection weights
				foreach(ConnectionGene connectionGene in newGenome.ConnectionGeneList)
					connectionGene.Weight = (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange/2.0;

				genomeList.Add(newGenome);

				if(++seedIdx >= seedPopulation.GenomeList.Count)
				{	// Back to first genome.
					seedIdx=0;
				}
			}
			return genomeList;
		}
Example #21
0
        public static GenomeList CreateGenomeListPreserveIDs(GenomeList seedGenomes, int length, NeatParameters neatParameters, IdGenerator idGenerator, AssessGenotypeFunction assess)
        {
            //Eventually, WIN will be brought in to maintain the genomes, for now, no need

            //Build the list.
            GenomeList genomeList = new GenomeList();

            if (length < seedGenomes.Count)
                throw new Exception("Attempting to generate a population that is smaller than the number of seeds (i.e. some seeds will be lost). Please change pop size to accomodate for all seeds.");
            NeatGenome newGenome;

            for (int i = 0; i < seedGenomes.Count; i++)
            {
                // Use each seed directly just once.
                newGenome = new NeatGenome((NeatGenome)seedGenomes[i], idGenerator.NextGenomeId);
                genomeList.Add(newGenome);
            }

            int testCount = 0; int maxTests = 5;

            // For the remainder we alter the weights.
            //for (int i = 1; i < length; i++)
            //{
            while (genomeList.Count < length)
            {
                newGenome = new NeatGenome((NeatGenome)seedGenomes[Utilities.Next(seedGenomes.Count)], idGenerator.NextGenomeId);

                // Reset the connection weights

                //in this particular instance, we would take a snapshot of the genome AFTER mutation for WIN purposes. But we don't track genomes yet
                foreach (ConnectionGene connectionGene in newGenome.ConnectionGeneList)
                    connectionGene.Weight += (0.1 - Utilities.NextDouble() * 0.2);

                //!connectionGene.Weight = (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange/2.0;
                //Console.WriteLine((0.1 - Utilities.NextDouble() * 0.2));
                //newGenome.ConnectionGeneList.Add(new ConnectionGene(idGenerator.NextInnovationId,5,newGenome.NeuronGeneList[Utilities.Next(newGenome.NeuronGeneList.Count-7)+7].InnovationId ,(Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange/2.0));
                //newGenome.ConnectionGeneList.Add(new ConnectionGene(idGenerator.NextInnovationId, 6, newGenome.NeuronGeneList[Utilities.Next(newGenome.NeuronGeneList.Count - 7) + 7].InnovationId, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0));
                //if we have an assess function, it should be used for generating this individual!

                if (assess != null && assess(newGenome) && testCount++ < maxTests)
                {
                    //after adding the genome, reset test count
                    genomeList.Add(newGenome);
                    testCount = 0;
                }
                else if (assess == null)
                    genomeList.Add(newGenome);
                else if (testCount >= maxTests)
                {
                    genomeList.Add(newGenome);
                    testCount = 0;
                }
            }

            //

            return genomeList;
        }
Example #22
0
		/// <summary>
		/// Construct a GenomeList. This can be used to construct a new Population object.
		/// </summary>
		/// <param name="evolutionAlgorithm"></param>
		/// <param name="inputNeuronCount"></param>
		/// <param name="outputNeuronCount"></param>
		/// <param name="length"></param>
		/// <returns></returns>
        // Schrum: Added outputsPerPolicy
        public static GenomeList CreateGenomeList(NeatParameters neatParameters, IdGenerator idGenerator, int inputNeuronCount, int outputNeuronCount, int outputsPerPolicy, float connectionProportion, int length)
		{
			GenomeList genomeList = new GenomeList();
			
			for(int i=0; i<length; i++)
			{
				idGenerator.ResetNextInnovationNumber();
                // Schrum: Added outputsPerPolicy
				genomeList.Add(CreateGenome(neatParameters, idGenerator, inputNeuronCount, outputNeuronCount, outputsPerPolicy, connectionProportion));
			}

			return genomeList;
		}
Example #23
0
        public static IGenome CreateGenomePreserveID(NeatParameters neatParameters, IdGenerator idGenerator, int inputNeuronCount, int outputNeuronCount, float connectionProportion)
        {
            IActivationFunction actFunct;
            NeuronGene neuronGene; // temp variable.
            NeuronGeneList inputNeuronGeneList = new NeuronGeneList(); // includes bias neuron.
            NeuronGeneList outputNeuronGeneList = new NeuronGeneList();
            NeuronGeneList neuronGeneList = new NeuronGeneList();
            ConnectionGeneList connectionGeneList = new ConnectionGeneList();

            int nodeCount = 0;

            WINManager win = WINManager.SharedWIN;

            // IMPORTANT NOTE: The neurons must all be created prior to any connections. That way all of the genomes
            // will obtain the same innovation ID's for the bias,input and output nodes in the initial population.
            // Create a single bias neuron.
            //TODO: DAVID proper activation function change to NULL?
            actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn");
            //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Bias, actFunct);
            WINNode neuronNode = win.findOrInsertNodeWithProperties(idGenerator,
                WINNode.NodeWithProperties(nodeCount++, NeuronType.Bias)
                );

            neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.INPUT_LAYER, NeuronType.Bias, actFunct);
            inputNeuronGeneList.Add(neuronGene);
            neuronGeneList.Add(neuronGene);

            // Create input neuron genes.
            actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn");
            for (int i = 0; i < inputNeuronCount; i++)
            {
                //TODO: DAVID proper activation function change to NULL?
                //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Input, actFunct);
                neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Input));

                neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.INPUT_LAYER, NeuronType.Input, actFunct);
                inputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Create output neuron genes.
            //actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn");
            for (int i = 0; i < outputNeuronCount; i++)
            {
                actFunct = ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid");
                //actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters);
                //TODO: DAVID proper activation function
                //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Output, actFunct);
                neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Output));

                neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.OUTPUT_LAYER, NeuronType.Output, actFunct);
                outputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            int currentConnCount = 0;
            WINConnection winConn;
            // Loop over all possible connections from input to output nodes and create a number of connections based upon
            // connectionProportion.
            foreach (NeuronGene targetNeuronGene in outputNeuronGeneList)
            {
                foreach (NeuronGene sourceNeuronGene in inputNeuronGeneList)
                {
                    // Always generate an ID even if we aren't going to use it. This is necessary to ensure connections
                    // between the same neurons always have the same ID throughout the generated population.
                    //PAUL NOTE:
                    //instead of generating and not using and id, we use the target and connection properties to uniquely identify a connection in WIN
                    //uint connectionInnovationId = idGenerator.NextInnovationId;

                    if (Utilities.NextDouble() < connectionProportion)
                    {
                        // Ok lets create a connection.
                        //first we search or create the winconnection object
                        winConn = win.findOrInsertConnectionWithProperties(idGenerator,
                            WINConnection.ConnectionWithProperties(currentConnCount, sourceNeuronGene.InnovationId, targetNeuronGene.InnovationId));

                        //our winconn will have our innovationID, and our weight like normal
                        //this will also respect the idgenerator, since it gets sent in as well, for legacy purposes
                        connectionGeneList.Add(new ConnectionGene(winConn.UniqueID,
                            sourceNeuronGene.InnovationId,
                            targetNeuronGene.InnovationId,
                            (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0)
                            );
                            //(Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0));  // Weight 0 +-5
                    }

                    currentConnCount++;

                }
            }
            //WIN will eventually be in control of all the genomes that are created as well, but not quite yet!
            //TODO: WIN should be generating genomeIDs explicitly

            // Don't create any hidden nodes at this point. Fundamental to the NEAT way is to start minimally!
            return new NeatGenome(idGenerator.NextGenomeId, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount);
        }
		private void EndPruningPhase()
		{
			// Leave pruning phase.
			pruningMode = false;

			// Set new threshold 110% of current level or 10 more if current complexity is very low.
			pop.PrunePhaseAvgComplexityThreshold = pop.AvgComplexity + neatParameters.pruningPhaseBeginComplexityThreshold;
			System.Diagnostics.Debug.WriteLine("complexity=" + pop.AvgComplexity.ToString() + ", threshold=" + pop.PrunePhaseAvgComplexityThreshold.ToString());

			neatParameters = neatParameters_Normal;
			neatParameters.compatibilityThreshold = neatParameters_PrunePhase.compatibilityThreshold;

			// Update species.AgaAtLastimprovement. Originally we reset this age to give all of the species
			// a 'clean slate' following the pruning phase. This though has the effect of giving all of the 
			// species the same AgeAtLastImprovement - which in turn often results in all of the species 
			// reaching the dropoff age simulataneously which results in the species being culled and therefore
			// causes a radical fall in population diversity.
			// Therefore we give the species a new AgeAtLastImprovement which reflects their relative 
			// AgeAtLastImprovement, this gives the species a new chance following pruning but does not allocate
			// them all the same AgeAtLastImprovement.
			NormalizeSpeciesAges();

			if(connectionWeightFixingEnabled)
			{
				// Fix all of the connection weights that remain after pruning (proven to be good values).
				foreach(NeatGenome.NeatGenome genome in pop.GenomeList)
					genome.FixConnectionWeights();
			}
		}
Example #25
0
        private void Mutate_AddConnection(NeatParameters neatParameters, IdGenerator idGen, Hashtable NewConnectionGeneTable)
        {
            // We are always guaranteed to have enough neurons to form connections - because the input/output neurons are
            // fixed. Any domain that doesn't require input/outputs is a bit nonsensical!

            // Make a fixed number of attempts at finding a suitable connection to add.

            if(neuronGeneList.Count>1)
            {	// At least 2 neurons, so we have a chance at creating a connection.

                WINManager win = WINManager.SharedWIN;
                WINConnection connection;

                for(int attempts=0; attempts<5; attempts++)
                {
                    // Select candidate source and target neurons. Any neuron can be used as the source. Input neurons
                    // should not be used as a target
                    int srcNeuronIdx;
                    int tgtNeuronIdx;

                    /* Here's some code for adding connections that attempts to avoid any recursive conenctions
                     * within a network by only linking to neurons with innovation id's greater than the source neuron.
                     * Unfortunately this doesn't work because new neurons with large innovations ID's are inserted
                     * randomly through a network's topology! Hence this code remains here in readyness to be resurrected
                     * as part of some future work to support feedforward nets.
            //					if(ea.NeatParameters.feedForwardOnly)
            //					{
            //						/* We can ensure that all networks are feedforward only by only adding feedforward connections here.
            //						 * Feed forward connections fall into one of the following categories.  All references to indexes
            //						 * are indexes within this genome's neuronGeneList:
            //						 * 1) Source neuron is an input or hidden node, target is an output node.
            //						 * 2) Source is an input or hidden node, target is a hidden node with an index greater than the source node's index.
            //						 * 3) Source is an output node, target is an output node with an index greater than the source node's index.
            //						 *
            //						 * These rules are easier to understand if you understand how the different types if neuron are arranged within
            //						 * the neuronGeneList array. Neurons are arranged in the following order:
            //						 *
            //						 * 1) A single bias neuron is always first.
            //						 * 2) Experiment specific input neurons.
            //						 * 3) Output neurons.
            //						 * 4) Hidden neurons.
            //						 *
            //						 * The quantity and innovationID of all neurons within the first 3 categories remains fixed throughout the life
            //						 * of an experiment, hence we always know where to find the bias, input and output nodes. The number of hidden nodes
            //						 * can vary as ne nodes are created, pruned away or perhaps dropped during crossover, however they are always arranged
            //						 * newest to oldest, or in other words sorted by innovation idea, lowest ID first.
            //						 *
            //						 * If output neurons were at the end of the list with hidden nodes in the middle then generating feedforward
            //						 * connections would be as easy as selecting a target neuron with a higher index than the source neuron. However, that
            //						 * type of arrangement is not conducive to the operation of other routines, hence this routine is a little bit more
            //						 * complicated as a result.
            //						 */
            //
            //						// Ok, for a source neuron we can pick any neuron except the last output neuron.
            //						int neuronIdxCount = neuronGeneList.Count;
            //						int neuronIdxBound = neuronIdxCount-1;
            //
            //						// Generate count-1 possibilities and avoid the last output neuron's idx.
            //						srcNeuronIdx = (int)Math.Floor(Utilities.NextDouble() * neuronIdxBound);
            //						if(srcNeuronIdx>inputBiasOutputNeuronCountMinus2) srcNeuronIdx++;
            //
            //
            //						// Now generate a target idx depending on what type of neuron srcNeuronIdx is pointing to.
            //						if(srcNeuronIdx<inputAndBiasNeuronCount)
            //						{	// Source is a bias or input neuron. Target can be any output or hidden neuron.
            //							tgtNeuronIdx = inputAndBiasNeuronCount + (int)Math.Floor(Utilities.NextDouble() * (neuronIdxCount-inputAndBiasNeuronCount));
            //						}
            //						else if(srcNeuronIdx<inputBiasOutputNeuronCount)
            //						{	// Source is an output neuron, but not the last output neuron. Target can be any output neuron with an index
            //							// greater than srcNeuronIdx.
            //							tgtNeuronIdx = (inputAndBiasNeuronCount+1) + (int)Math.Floor(Utilities.NextDouble() * ((inputBiasOutputNeuronCount-1)-srcNeuronIdx));
            //						}
            //						else
            //						{	// Source is a hidden neuron. Target can be any hidden neuron after srcNeuronIdx or any output neuron.
            //							tgtNeuronIdx = (int)Math.Floor(Utilities.NextDouble() * ((neuronIdxBound-srcNeuronIdx)+outputNeuronCount));
            //
            //							if(tgtNeuronIdx<outputNeuronCount)
            //							{	// Map to an output neuron idx.
            //								tgtNeuronIdx += inputAndBiasNeuronCount;
            //							}
            //							else
            //							{
            //								// Map to one of the hidden neurons after srcNeuronIdx.
            //								tgtNeuronIdx = (tgtNeuronIdx-outputNeuronCount)+srcNeuronIdx+1;
            //							}
            //						}
            //					}

            //					// Source neuron can by any neuron. Target neuron is any neuron except input neurons.
            //					srcNeuronIdx = (int)Math.Floor(Utilities.NextDouble() * neuronGeneList.Count);
            //					tgtNeuronIdx = inputAndBiasNeuronCount + (int)Math.Floor(Utilities.NextDouble() * (neuronGeneList.Count-inputAndBiasNeuronCount));
            //
            //                  NeuronGene sourceNeuron = neuronGeneList[srcNeuronIdx];
            //                  NeuronGene targetNeuron = neuronGeneList[tgtNeuronIdx];

                    // Find all potential inputs, or quit if there are not enough.
                    // Neurons cannot be inputs if they are dummy input nodes of a module.
                    NeuronGeneList potentialInputs = new NeuronGeneList();
                    foreach (NeuronGene n in neuronGeneList) {
                        if (!(n.ActivationFunction is ModuleInputNeuron)) {
                            potentialInputs.Add(n);
                        }
                    }
                    if (potentialInputs.Count < 1)
                        return;

                    // Find all potential outputs, or quit if there are not enough.
                    // Neurons cannot be outputs if they are dummy input or output nodes of a module, or network input or bias nodes.
                    NeuronGeneList potentialOutputs = new NeuronGeneList();
                    foreach (NeuronGene n in neuronGeneList) {
                        if (n.NeuronType != NeuronType.Bias && n.NeuronType != NeuronType.Input
                                && !(n.ActivationFunction is ModuleInputNeuron)
                                && !(n.ActivationFunction is ModuleOutputNeuron)) {
                            potentialOutputs.Add(n);
                        }
                    }
                    if (potentialOutputs.Count < 1)
                        return;

                    NeuronGene sourceNeuron = potentialInputs[Utilities.Next(potentialInputs.Count)];
                    NeuronGene targetNeuron = potentialOutputs[Utilities.Next(potentialOutputs.Count)];

                    // Check if a connection already exists between these two neurons.
                    long sourceId = sourceNeuron.InnovationId;
                    long targetId = targetNeuron.InnovationId;

                    if(!TestForExistingConnection(sourceId, targetId))
                    {
                        // Check if a matching mutation has already occured on another genome.
                        // If so then re-use the connection ID.
                        ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId);
                        ConnectionGene existingConnection = (ConnectionGene)NewConnectionGeneTable[connectionKey];
                        ConnectionGene newConnectionGene;
                        if(existingConnection==null)
                        {
                            //WIN HAS ARRIVED, BITCH
                            //create our newest conncetion, noting the source,target and weight
                            connection = win.createWINConnection(
                   WINConnection.ConnectionWithProperties(sourceId, targetId), idGen);

                            // Create a new connection with a new ID and add it to the Genome.
                            newConnectionGene = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID,
                                 (Utilities.NextDouble() * neatParameters.connectionWeightRange / 4.0) - neatParameters.connectionWeightRange / 8.0);

                            //newConnectionGene =
                                //new ConnectionGene(idGen.NextInnovationId, sourceId, targetId,
                                //(Utilities.NextDouble() * neatParameters.connectionWeightRange/4.0) - neatParameters.connectionWeightRange/8.0);

                            // Register the new connection with NewConnectionGeneTable.
                            NewConnectionGeneTable.Add(connectionKey, newConnectionGene);

                            // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end
                            // of the list without risk of breaking the innovation ID order.
                            connectionGeneList.Add(newConnectionGene);
                        }
                        else
                        {
                            //TODO: WIN should note the mutation in weight from previous connection
                            //WIN AIN'T HERE YET, DAWG. Nothing new being created, just adjusted weights -- which we'll need to note, but not yet

                            // Create a new connection, re-using the ID from existingConnection, and add it to the Genome.
                            newConnectionGene = new ConnectionGene(existingConnection.InnovationId, sourceId, targetId,
                                (Utilities.NextDouble() * neatParameters.connectionWeightRange/4.0) - neatParameters.connectionWeightRange/8.0);

                            // Add the new gene to this genome. We are re-using an ID so we must ensure the connection gene is
                            // inserted into the correct position (sorted by innovation ID).
                            connectionGeneList.InsertIntoPosition(newConnectionGene);
                        }

                        return;
                    }
                }
            }

            // We couldn't find a valid connection to create. Instead of doing nothing lets perform connection
            // weight mutation.
            Mutate_ConnectionWeights(neatParameters);
        }
 /// <summary>
 /// Compare this IGenome with the provided one. They are compatibile if their calculated difference 
 /// is below the current threshold specified by NeatParameters.compatibilityThreshold
 /// </summary>
 /// <param name="comparisonGenome"></param>
 /// <param name="neatParameters"></param>
 /// <returns></returns>
 public abstract bool IsCompatibleWithGenome(IGenome comparisonGenome, NeatParameters neatParameters);
		public Multiobjective (NeatParameters _np)
		{
			np=_np;
			population= new GenomeList();
			ranks=new List<RankInformation>();
			nov = new noveltyfixed(10.0);
			doNovelty=_np.noveltySearch;
			Console.WriteLine("multiobjective novelty " + doNovelty);
			generation=0;
		}
Example #28
0
		private void MutateConnectionWeight(ConnectionGene connectionGene, NeatParameters np, ConnectionMutationParameterGroup paramGroup)
		{
			switch(paramGroup.PerturbationType)
			{
				case ConnectionPerturbationType.JiggleEven:
				{
					connectionGene.Weight += (Utilities.NextDouble()*2-1.0) * paramGroup.PerturbationFactor;

					// Cap the connection weight. Large connections weights reduce the effectiveness of the search.
					connectionGene.Weight = Math.Max(connectionGene.Weight, -np.connectionWeightRange/2.0);
					connectionGene.Weight = Math.Min(connectionGene.Weight, np.connectionWeightRange/2.0);
					break;
				}
				case ConnectionPerturbationType.JiggleND:
				{
					connectionGene.Weight += RandLib.gennor(0, paramGroup.Sigma);

					// Cap the connection weight. Large connections weights reduce the effectiveness of the search.
					connectionGene.Weight = Math.Max(connectionGene.Weight, -np.connectionWeightRange/2.0);
					connectionGene.Weight = Math.Min(connectionGene.Weight, np.connectionWeightRange/2.0);
					break;
				}
				case ConnectionPerturbationType.Reset:
				{
					// TODO: Precalculate connectionWeightRange / 2.
					connectionGene.Weight = (Utilities.NextDouble()*np.connectionWeightRange) - np.connectionWeightRange/2.0;
					break;
				}
				default:
				{
					throw new Exception("Unexpected ConnectionPerturbationType");
				}
			}
		}
        /// <summary>
        /// Default Constructor.
        /// </summary>
        public EvolutionAlgorithm(Population pop, IPopulationEvaluator populationEvaluator, NeatParameters neatParameters)
        {
            this.pop = pop;
            this.populationEvaluator = populationEvaluator;
            this.neatParameters = neatParameters;
            neatParameters_Normal = neatParameters;

            neatParameters_PrunePhase = new NeatParameters(neatParameters);
            neatParameters_PrunePhase.pMutateAddConnection = 0.0;
            neatParameters_PrunePhase.pMutateAddNode = 0.0;
            neatParameters_PrunePhase.pMutateConnectionWeights = 0.33;
            neatParameters_PrunePhase.pMutateDeleteConnection = 0.33;
            neatParameters_PrunePhase.pMutateDeleteSimpleNeuron = 0.33;

            // Disable all crossover as this has a tendency to increase complexity, which is precisely what
            // we don't want during a pruning phase.
            neatParameters_PrunePhase.pOffspringAsexual = 1.0;
            neatParameters_PrunePhase.pOffspringSexual = 0.0;

            InitialisePopulation();
        }
Example #30
0
		public override bool IsCompatibleWithGenome(IGenome comparisonGenome, NeatParameters neatParameters)
		{
			/* A very simple way of implementing this routine is to call CorrelateConnectionGeneLists and to then loop 
			 * through the correlation items, calculating a compatibility score as we go. However, this routine
			 * is heavily used and in performance tests was shown consume 40% of the CPU time for the core NEAT code.
			 * Therefore this new routine has been rewritten with it's own version of the logic within  
			 * CorrelateConnectionGeneLists. This allows us to only keep comparing genes up to the point where the
			 * threshold is passed. This also eliminates the need to build the correlation results list, this difference
			 * alone is responsible for a 200x performance improvement when testing with a 1664 length genome!!
			 * 
			 * A further optimisation is achieved by comparing the genes starting at the end of the genomes which is
			 * where most disparities are located - new novel genes are always attached to the end of genomes. This
			 * has the result of complicating the routine because we must now invoke additional logic to determine
			 * which genes are excess and when the first disjoint gene is found. This is done with an extra integer:
			 * 
			 * int excessGenesSwitch=0; // indicates to the loop that it is handling the first gene.
			 *						=1;	// Indicates that the first gene was excess and on genome 1.
			 *						=2;	// Indicates that the first gene was excess and on genome 2.
			 *						=3;	// Indicates that there are no more excess genes.
			 * 
			 * This extra logic has a slight performance hit, but this is minor especially in comparison to the savings that
			 * are expected to be achieved overall during a NEAT search.
			 * 
			 * If you have trouble understanding this logic then it might be best to work through the previous version of
			 * this routine (below) that scans through the genomes from start to end, and which is a lot simpler.
			 * 
			 */
			ConnectionGeneList list1 = this.connectionGeneList;
			ConnectionGeneList list2 = ((NeatGenome)comparisonGenome).connectionGeneList;
			int excessGenesSwitch=0;

			// Store these heavily used values locally.
			int list1Count = list1.Count;
			int list2Count = list2.Count;

			//----- Test for special cases.
			if(list1Count==0 && list2Count==0)
			{	// Both lists are empty! No disparities, therefore the genomes are compatible!
				return true;
			}

			if(list1Count==0)
			{	// All list2 genes are excess.
				return ((list2.Count * neatParameters.compatibilityExcessCoeff) < neatParameters.compatibilityThreshold);
			}

			if(list2Count==0)
			{	
				// All list1 genes are excess.
				return ((list1Count * neatParameters.compatibilityExcessCoeff) < neatParameters.compatibilityThreshold);
			}

		//----- Both ConnectionGeneLists contain genes - compare the contents.
			double compatibility=0;
			int list1Idx=list1Count-1;
			int list2Idx=list2Count-1;
			ConnectionGene connectionGene1 = list1[list1Idx];
			ConnectionGene connectionGene2 = list2[list2Idx];
			for(;;)
			{
				if(connectionGene2.InnovationId > connectionGene1.InnovationId)
				{	
					// Most common test case(s) at top for efficiency.
					if(excessGenesSwitch==3)
					{	// No more excess genes. Therefore this mismatch is disjoint.
						compatibility += neatParameters.compatibilityDisjointCoeff;
					}
					else if(excessGenesSwitch==2)
					{	// Another excess gene on genome 2.
						compatibility += neatParameters.compatibilityExcessCoeff;
					}
					else if(excessGenesSwitch==1)
					{	// We have found the first non-excess gene.
						excessGenesSwitch=3;
						compatibility += neatParameters.compatibilityDisjointCoeff;
					}
					else //if(excessGenesSwitch==0)
					{	// First gene is excess, and is on genome 2.
						excessGenesSwitch = 2;
						compatibility += neatParameters.compatibilityExcessCoeff;
					}

					// Move to the next gene in list2.
					list2Idx--;
				}
				else if(connectionGene1.InnovationId == connectionGene2.InnovationId)
				{
					// No more excess genes. It's quicker to set this every time than to test if is not yet 3.
					excessGenesSwitch=3;

					// Matching genes. Increase compatibility by weight difference * coeff.
					compatibility += Math.Abs(connectionGene1.Weight-connectionGene2.Weight) * neatParameters.compatibilityWeightDeltaCoeff;

					// Move to the next gene in both lists.
					list1Idx--;
					list2Idx--;
				}
				else // (connectionGene2.InnovationId < connectionGene1.InnovationId)
				{	
					// Most common test case(s) at top for efficiency.
					if(excessGenesSwitch==3)
					{	// No more excess genes. Therefore this mismatch is disjoint.
						compatibility += neatParameters.compatibilityDisjointCoeff;
					}
					else if(excessGenesSwitch==1)
					{	// Another excess gene on genome 1.
						compatibility += neatParameters.compatibilityExcessCoeff;
					}
					else if(excessGenesSwitch==2)
					{	// We have found the first non-excess gene.
						excessGenesSwitch=3;
						compatibility += neatParameters.compatibilityDisjointCoeff;
					}
					else //if(excessGenesSwitch==0)
					{	// First gene is excess, and is on genome 1.
						excessGenesSwitch = 1;
						compatibility += neatParameters.compatibilityExcessCoeff;
					}

					// Move to the next gene in list1.
					list1Idx--;
				}
				
				if(compatibility >= neatParameters.compatibilityThreshold)
					return false;

				// Check if we have reached the end of one (or both) of the lists. If we have reached the end of both then 
				// we execute the first 'if' block - but it doesn't matter since the loop is not entered if both lists have 
				// been exhausted.
				if(list1Idx < 0)
				{	
					// All remaining list2 genes are disjoint.
					compatibility +=  (list2Idx+1) * neatParameters.compatibilityDisjointCoeff;
					return (compatibility < neatParameters.compatibilityThreshold);
				}

				if(list2Idx < 0)
				{
					// All remaining list1 genes are disjoint.
					compatibility += (list1Idx+1) * neatParameters.compatibilityDisjointCoeff;
					return (compatibility < neatParameters.compatibilityThreshold);
				}

				connectionGene1 = list1[list1Idx];
				connectionGene2 = list2[list2Idx];
			}
		}
Example #31
0
        public static GenomeList CreateGenomeListAddedInputs(NeatGenome seedGenome, int length, NeatParameters neatParameters, IdGenerator idGenerator)
        {
            //Build the list.
            GenomeList genomeList = new GenomeList();

            // Use the seed directly just once.
            NeatGenome newGenome = new NeatGenome(seedGenome, idGenerator.NextGenomeId);
            //genomeList.Add(newGenome);

            // For the remainder we alter the weights.
            for (int i = 0; i < length; i++)
            {
                newGenome = new NeatGenome(seedGenome, idGenerator.NextGenomeId);

                // Reset the connection weights
                foreach (ConnectionGene connectionGene in newGenome.ConnectionGeneList)
                    connectionGene.Weight = (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0;
                newGenome.ConnectionGeneList.Add(new ConnectionGene(idGenerator.NextInnovationId, 5, newGenome.NeuronGeneList[Utilities.Next(newGenome.NeuronGeneList.Count - 7) + 7].InnovationId, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0));
                newGenome.ConnectionGeneList.Add(new ConnectionGene(idGenerator.NextInnovationId, 6, newGenome.NeuronGeneList[Utilities.Next(newGenome.NeuronGeneList.Count - 7) + 7].InnovationId, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0));
                genomeList.Add(newGenome);
            }

            //

            return genomeList;
        }
Example #32
0
        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="copyFrom"></param>
        public NeatParameters(NeatParameters copyFrom)
        {
            //joel
            noveltySearch = copyFrom.noveltySearch;
            noveltyHistogram = copyFrom.noveltyHistogram;
            noveltyFixed = copyFrom.noveltyFixed;
            noveltyFloat = copyFrom.noveltyFloat;
            histogramBins = copyFrom.histogramBins;

            populationSize = copyFrom.populationSize;

            pOffspringAsexual = copyFrom.pOffspringAsexual;
            pOffspringSexual = copyFrom.pOffspringSexual;
            pInterspeciesMating = copyFrom.pInterspeciesMating;

            pDisjointExcessGenesRecombined = copyFrom.pDisjointExcessGenesRecombined;

            pMutateConnectionWeights = copyFrom.pMutateConnectionWeights;
            pMutateAddNode = copyFrom.pMutateAddNode;
            pMutateAddModule = copyFrom.pMutateAddModule;
            pMutateAddConnection = copyFrom.pMutateAddConnection;
            pMutateDeleteConnection = copyFrom.pMutateDeleteConnection;
            pMutateDeleteSimpleNeuron = copyFrom.pMutateDeleteSimpleNeuron;

            // Copy the list.
            ConnectionMutationParameterGroupList = new ConnectionMutationParameterGroupList(copyFrom.ConnectionMutationParameterGroupList);

            compatibilityThreshold = copyFrom.compatibilityThreshold;
            compatibilityDisjointCoeff = copyFrom.compatibilityDisjointCoeff;
            compatibilityExcessCoeff = copyFrom.compatibilityExcessCoeff;
            compatibilityWeightDeltaCoeff = copyFrom.compatibilityWeightDeltaCoeff;

            elitismProportion = copyFrom.elitismProportion;
            selectionProportion = copyFrom.selectionProportion;

            targetSpeciesCountMin = copyFrom.targetSpeciesCountMin;
            targetSpeciesCountMax = copyFrom.targetSpeciesCountMax;

            pruningPhaseBeginComplexityThreshold = copyFrom.pruningPhaseBeginComplexityThreshold;
            pruningPhaseBeginFitnessStagnationThreshold = copyFrom.pruningPhaseBeginFitnessStagnationThreshold;
            pruningPhaseEndComplexityStagnationThreshold = copyFrom.pruningPhaseEndComplexityStagnationThreshold;

            speciesDropoffAge = copyFrom.speciesDropoffAge;

            connectionWeightRange = copyFrom.connectionWeightRange;
        }
Example #33
0
        private void Mutate_AddModule(NeatParameters neatParameters, IdGenerator idGen, Hashtable NewConnectionGeneTable)
        {
            // Find all potential inputs, or quit if there are not enough.
            // Neurons cannot be inputs if they are dummy input nodes created for another module.
            NeuronGeneList potentialInputs = new NeuronGeneList();
            foreach (NeuronGene n in neuronGeneList) {
                if (!(n.ActivationFunction is ModuleInputNeuron)) {
                    potentialInputs.Add(n);
                }
            }
            if (potentialInputs.Count < 1)
                return;

            // Find all potential outputs, or quit if there are not enough.
            // Neurons cannot be outputs if they are dummy input or output nodes created for another module, or network input or bias nodes.
            NeuronGeneList potentialOutputs = new NeuronGeneList();
            foreach (NeuronGene n in neuronGeneList) {
                if (n.NeuronType != NeuronType.Bias && n.NeuronType != NeuronType.Input
                        && !(n.ActivationFunction is ModuleInputNeuron)
                        && !(n.ActivationFunction is ModuleOutputNeuron)) {
                    potentialOutputs.Add(n);
                }
            }
            if (potentialOutputs.Count < 1)
                return;

            // Pick a new function for the new module.
            IModule func = ModuleFactory.GetRandom();

            WINManager win = WINManager.SharedWIN;
            WINNode node;
            WINConnection connection;

            // Choose inputs uniformly at random, with replacement.
            // Create dummy neurons to represent the module's inputs.
            // Create connections between the input nodes and the dummy neurons.
            IActivationFunction inputFunction = ActivationFunctionFactory.GetActivationFunction("ModuleInputNeuron");
            List<long> inputDummies = new List<long>(func.InputCount);
            for (int i = 0; i < func.InputCount; i++) {

                //we are calling nextinnovationID, this is the place for WIN!
                //in reality, win should know the activation function as well, but that's not currently implemented

                //here we create a new node, and two new connections
                //we don't send in a genomeID here, so we get it set for us!
                //do we need to inform it of the activation function? I think so?
                node = win.createWINNode(new PropertyObject() { { WINNode.SNodeString, NeuronType.Hidden.ToString()}});

                NeuronGene newNeuronGene = new NeuronGene(node.UniqueID, NeuronType.Hidden, inputFunction);
                neuronGeneList.Add(newNeuronGene);

                long sourceId = potentialInputs[Utilities.Next(potentialInputs.Count)].InnovationId;
                long targetId = newNeuronGene.InnovationId;

                inputDummies.Add(targetId);

                //aha! we must call the innovationID again, we check against win

                //we don't send in any uniqueIDs so they are generated for us, and we update our idGen object
                connection = win.createWINConnection(
                    WINConnection.ConnectionWithProperties(sourceId, targetId), idGen);

                // Create a new connection with a new ID and add it to the Genome.
                ConnectionGene newConnectionGene = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID,
                    (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0
                    );

                // Register the new connection with NewConnectionGeneTable.
                ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId);
                NewConnectionGeneTable.Add(connectionKey, newConnectionGene);

                // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end
                // of the list without risk of breaking the innovation ID order.
                connectionGeneList.Add(newConnectionGene);
            }

            // Choose outputs uniformly at random, with replacement.
            // Create dummy neurons to represent the module's outputs.
            // Create connections between the output nodes and the dummy neurons.
            IActivationFunction outputFunction = ActivationFunctionFactory.GetActivationFunction("ModuleOutputNeuron");
            List<long> outputDummies = new List<long>(func.OutputCount);
            for (int i = 0; i < func.OutputCount; i++) {

                node = win.createWINNode(new PropertyObject() { { WINNode.SNodeString, NeuronType.Hidden.ToString() } });

                NeuronGene newNeuronGene = new NeuronGene(node.UniqueID, NeuronType.Hidden, outputFunction);
                neuronGeneList.Add(newNeuronGene);

                long sourceId = newNeuronGene.InnovationId;
                long targetId = potentialOutputs[Utilities.Next(potentialOutputs.Count)].InnovationId;

                outputDummies.Add(sourceId);

                connection = win.createWINConnection(
                   WINConnection.ConnectionWithProperties(sourceId, targetId), idGen);

                // Create a new connection with a new ID and add it to the Genome.
                ConnectionGene newConnectionGene = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID,
                   (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0
                    );

                    //new ConnectionGene(idGen.NextInnovationId, sourceId, targetId,
                    //(Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0);

                // Register the new connection with NewConnectionGeneTable.
                ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId);
                NewConnectionGeneTable.Add(connectionKey, newConnectionGene);

                // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end
                // of the list without risk of breaking the innovation ID order.
                connectionGeneList.Add(newConnectionGene);
            }

            // Pick a new ID for the new module and create it.
            // Modules do not participate in history comparisons, so we will always create a new innovation ID.
            // We can change this here if it becomes a problem.

            //TODO: Paul check win conditions here
            //this is confusing from a WIN perspective, I don't know if I'm going to support modules
            //I can create a generic NextInnovationID object, but don't know if it's worth it

            ModuleGene newModule = new ModuleGene(idGen.NextInnovationId, func, inputDummies, outputDummies);
            moduleGeneList.Add(newModule);
        }