Ejemplo n.º 1
0
        public Population(int nbInputs, int nbOutputs, NEATConfig config)
        {
            this.config = config;

            // Initialize a population with the input and output layers fully connected
            individuals = new Individual[config.populationSize];

            for (int i = 0; i < individuals.Length; i++)
            {
                individuals[i] = new Individual(NeuralGraph.generateFullyConnected(nbInputs + 1, nbOutputs)); // Add a bias input
            }
        }
Ejemplo n.º 2
0
        public Individual clone()
        {
            Dictionary <Neuron, Neuron> addedNeurons = new Dictionary <Neuron, Neuron>();
            NeuralGraph cloneGraph = new NeuralGraph(graph.getInputNeurons(), graph.getOutputNeurons());

            // TODO !Important! If we allow recurrent connections on outputs, need to clone the outputs too

            foreach (Connection connection in graph.getConnectionList())
            {
                addClonedConnection(connection, cloneGraph, addedNeurons);
            }

            return(new Individual(cloneGraph));
        }
Ejemplo n.º 3
0
        public static NeuralGraph generateFullyConnected(int nbInputs, int nbOutputs)
        {
            NeuralGraph graph = new NeuralGraph(nbInputs, nbOutputs);

            // Use specific innovation numbers such that all graphs created through this method are identical
            int innovation = 0;

            foreach (Neuron input in graph.getInputNeurons())
            {
                foreach (Neuron output in graph.getOutputNeurons())
                {
                    graph.addConnection(new Connection(input, output, -1, innovation++, true));
                }
            }

            return(graph);
        }
Ejemplo n.º 4
0
        private static void addClonedConnection(Connection connection, NeuralGraph child, Dictionary <Neuron, Neuron> addedNeurons, bool disabled)
        {
            Neuron[] oldNeurons = new Neuron[] { connection.getSource(), connection.getDest() };
            Neuron[] newNeurons = new Neuron[oldNeurons.Length];

            for (int i = 0; i < oldNeurons.Length; i++)
            {
                if (oldNeurons[i].getType() != NeuronType.Hidden)
                {
                    // TODO !Important! If we allow recurrent connections on outputs, need to clone the outputs too
                    newNeurons[i] = oldNeurons[i];
                    continue;
                }
                if (!addedNeurons.ContainsKey(oldNeurons[i]))
                {
                    newNeurons[i] = oldNeurons[i].clone();
                    addedNeurons.Add(oldNeurons[i], newNeurons[i]);
                    child.addHiddenNeuron(newNeurons[i]);
                }
                else
                {
                    newNeurons[i] = addedNeurons[oldNeurons[i]];
                }
            }

            Dictionary <Neuron, Dictionary <Neuron, Connection> > childConnections = child.getConnections();

            if (childConnections.ContainsKey(newNeurons[1]) && childConnections[newNeurons[1]].ContainsKey(newNeurons[0]))
            {
                // If the link already exists, enable it
                if (!disabled)
                {
                    childConnections[newNeurons[1]][newNeurons[0]].enable();
                }
            }
            else
            {
                Connection newConnection = new Connection(newNeurons[0], newNeurons[1], connection.getParentInnovation(), connection.getInnovation(), true);
                newConnection.setDisabled(disabled);
                child.addConnection(newConnection);
            }
        }
Ejemplo n.º 5
0
        public Individual mutate(NEATConfig config)
        {
            Individual  newIndiv = clone();
            NeuralGraph newGraph = newIndiv.getGraph();

            if (Utils.rand.NextDouble() < config.newConnectionProb)
            {
                // Select two random neurons and create (or enable) a link in-between
                int hiddenCount = newGraph.getHiddenNeurons().Count();
                int inputCount  = newGraph.getInputNeurons().Count();
                int outputCount = newGraph.getOutputNeurons().Count();

                // Select the input and output neurons
                int    sourceIndex = Utils.rand.Next(hiddenCount + inputCount + outputCount);
                int    destIndex = Utils.rand.Next(hiddenCount + outputCount);
                Neuron source, dest;

                if (sourceIndex < hiddenCount)
                {
                    source = newGraph.getHiddenNeurons()[sourceIndex];
                }
                else if (sourceIndex < hiddenCount + inputCount)
                {
                    source = newGraph.getInputNeurons()[sourceIndex - hiddenCount];
                }
                else
                {
                    source = newGraph.getOutputNeurons()[sourceIndex - hiddenCount - inputCount];
                }

                if (destIndex < hiddenCount)
                {
                    dest = newGraph.getHiddenNeurons()[destIndex];
                }
                else
                {
                    dest = newGraph.getOutputNeurons()[destIndex - hiddenCount];
                }

                Connection connection;
                if (!newGraph.getConnections()[dest].TryGetValue(source, out connection))
                {
                    connection = new Connection(source, dest, -1); // TODO what the crap is the parent innovation supposed to be here
                    newGraph.addConnection(connection);
                }
                else
                {
                    connection.enable();
                }
            }

            if (Utils.rand.NextDouble() < config.newNodeProb)
            {
                // When adding a node, disable a connection and replace it by a neuron and two connections
                // The new input connection to that neuron has weight of 1, while output has same weight as disabled connection
                Connection connection = newGraph.getConnectionList()[Utils.rand.Next(newGraph.getConnectionList().Count)];
                connection.disable();
                Neuron     neuron   = new Neuron(NeuronType.Hidden);
                Connection newConn1 = new Connection(connection.getSource(), neuron, connection.getInnovation());
                Connection newConn2 = new Connection(neuron, connection.getDest(), connection.getInnovation());
                newGraph.addHiddenNeuron(neuron);
                newGraph.addConnection(newConn1);
                newGraph.addConnection(newConn2);
            }

            // Mutate each connection weight
            foreach (Connection connection in newGraph.getConnectionList())
            {
                if (Utils.rand.NextDouble() < config.mutationProb)
                {
                    if (Utils.rand.NextDouble() < config.uniformPerturbationMutationProb)
                    {
                        connection.setWeight(connection.getWeight() + Utils.rand.NextDouble() * 2 * config.perturbationStep - config.perturbationStep);
                    }
                    else
                    {
                        connection.setWeight(Utils.nextGaussian(0, 1));
                    }
                }
            }

            return(newIndiv);
        }
Ejemplo n.º 6
0
 private static void addClonedConnection(Connection connection, NeuralGraph child, Dictionary <Neuron, Neuron> addedNeurons)
 {
     addClonedConnection(connection, child, addedNeurons, connection.isDisabled());
 }
Ejemplo n.º 7
0
 public Individual(NeuralGraph graph)
 {
     this.graph = graph;
 }
Ejemplo n.º 8
0
        public static Individual cross(Individual parent1, Individual parent2, NEATConfig config)
        {
            NeuralGraph graph1 = parent1.getGraph();
            NeuralGraph graph2 = parent2.getGraph();

            Dictionary <Neuron, Neuron> addedNeurons = new Dictionary <Neuron, Neuron>();
            NeuralGraph child = new NeuralGraph(graph1.getInputNeurons(), graph1.getOutputNeurons());

            // Add connections from both parents
            List <Connection> .Enumerator it1 = graph1.getConnectionList().GetEnumerator();
            List <Connection> .Enumerator it2 = graph2.getConnectionList().GetEnumerator();
            bool hasNext1 = it1.MoveNext(), hasNext2 = it2.MoveNext();

            while (hasNext1 || hasNext2)
            {
                if (!hasNext1)
                {
                    addClonedConnection(it2.Current, child, addedNeurons);
                    hasNext2 = it2.MoveNext();
                    continue;
                }
                if (!hasNext2)
                {
                    addClonedConnection(it1.Current, child, addedNeurons);
                    hasNext1 = it1.MoveNext();
                    continue;
                }

                int innov1 = it1.Current.getInnovation();
                int innov2 = it2.Current.getInnovation();
                if (innov1 == innov2)
                {
                    // If either parent's connection is disabled, there is a chance for it to be disabled in the child
                    bool disabled = false;
                    if (it1.Current.isDisabled() != it2.Current.isDisabled())
                    {
                        disabled = (Utils.rand.NextDouble() < config.disableGeneProb);
                    }
                    else if (it1.Current.isDisabled())
                    {
                        disabled = true;
                    }

                    Connection connectionToAdd = (Utils.rand.NextDouble() < 0.5) ? it1.Current : it2.Current;
                    addClonedConnection(connectionToAdd, child, addedNeurons, disabled);
                    hasNext1 = it1.MoveNext();
                    hasNext2 = it2.MoveNext();
                }
                else if (innov1 > innov2)
                {
                    addClonedConnection(it2.Current, child, addedNeurons);
                    hasNext2 = it2.MoveNext();
                }
                else
                {
                    addClonedConnection(it1.Current, child, addedNeurons);
                    hasNext1 = it1.MoveNext();
                }
            }

            return(new Individual(child));
        }