Beispiel #1
0
        public void AddGenomesToSpeciesTest()
        {
            UnitTests.RandomStub randomStub = new UnitTests.RandomStub();
            Simulation           sim        = new Simulation(randomStub, gen, 10);

            // Create some fake species and genomes
            Species species1 = new Species(randomStub);

            // Two genomes are matching, one is not so we should get 2 species (with 2 and 1 Genomes respectively)
            Genome gen1 = new Genome(randomStub);
            Genome gen2 = new Genome(randomStub);

            Genome gen3 = new Genome(randomStub);

            gen3.ParentSimulation = sim;
            gen3.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            gen3.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            gen3.AddNode(new Node(Node.ENodeType.OUTPUT, 3));
            gen3.AddNode(new Node(Node.ENodeType.OUTPUT, 4));
            gen3.AddConnectionGene(1, 2, true);
            gen3.AddConnectionGene(1, 3, true);
            gen3.AddConnectionGene(1, 4, true);


            sim.Species.Clear();

            sim.AddGenomesToSpecies(new List <Genome> {
                gen1, gen2, gen3
            });

            Assert.AreEqual(2, sim.Species.Count);
            Assert.AreEqual(2, sim.Species[0].Genomes.Count);
            Assert.AreEqual(1, sim.Species[1].Genomes.Count);
        }
Beispiel #2
0
        public static void Test4()
        {
            Genome        genome = new Genome();
            NeuralNetwork net;

            float[] input;
            float[] output;
            string  logs = "======================TEST 4===================================\n\n";

            genome = new Genome();
            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.INPUT, 0));
            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.INPUT, 1));
            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.INPUT, 2));
            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.OUTPUT, 3));
            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.HIDDEN, 4));
            genome.AddConnectionGene(new ConnectionGene(0, 4, 0.4f, true, 0));
            genome.AddConnectionGene(new ConnectionGene(1, 4, 0.7f, true, 1));
            genome.AddConnectionGene(new ConnectionGene(2, 4, 0.1f, true, 2));
            genome.AddConnectionGene(new ConnectionGene(4, 3, 1f, true, 3));

            net   = new NeuralNetwork(genome, Neuron.ActivationType.SIGMOID, false);
            input = new float[] { 0.5f, 0.75f, 0.90f };
            for (int i = 0; i < 3; i++)
            {
                output = net.FeedForward(input);
                logs  += "output is of length=" + output.Length + " and has output[0]=" + output[0] + " expecting 0.9924\n";
            }

            Debug.Log(logs);
        }
Beispiel #3
0
    // Use this for initialization
    void Start()
    {
        Genome parent3GenomeSimple = new Genome();

        //Create the input nodes
        parent3GenomeSimple.AddNodeGene(new NodeGene(1, NodeGeneType.INPUT, 0f));
        parent3GenomeSimple.AddNodeGene(new NodeGene(2, NodeGeneType.INPUT, 0f));
        parent3GenomeSimple.AddNodeGene(new NodeGene(3, NodeGeneType.INPUT, 0f));

        //Create the output node
        parent3GenomeSimple.AddNodeGene(new NodeGene(4, NodeGeneType.OUTPUT, 1f));

        //Create connections
        parent3GenomeSimple.AddConnectionGene(new ConnectionGene(1, 4, 1.0, true, 1));
        parent3GenomeSimple.AddConnectionGene(new ConnectionGene(2, 4, 1.0, true, 2));
        parent3GenomeSimple.AddConnectionGene(new ConnectionGene(3, 4, 1.0, true, 3));


        //Init the connection gene counter with 11
        connectionCounter = new GeneCounter(4);
        nodeCounter       = new GeneCounter(5);

        manager.Callback = this;

        manager.CreateInitialPopulation(parent3GenomeSimple, nodeCounter, connectionCounter, 100);
    }
Beispiel #4
0
    /// <summary>
    /// Crossover of two parent genomes to procuce one child
    /// </summary>
    /// <param name="parent1">the more fit parent!</param>
    /// <param name="parent2">the less fit parent</param>
    /// <returns>the newly breed child genome</returns>
    public static Genome CrossOver(Genome parent1, Genome parent2)
    {
        Genome childGenome = new Genome();

        //Copy nodes of the more fit parent
        foreach (NodeGene parent1Node in parent1.Nodes.Values)
        {
            childGenome.AddNodeGene(new NodeGene(parent1Node));
        }

        //Iterate through every connection
        foreach (ConnectionGene parent1Connection in parent1.Connections.Values)
        {
            if (parent2.Connections.ContainsKey(parent1Connection.InnovationNumber))
            {
                //Matching genes
                if (Random.Range(-1.0f, 1.0f) >= 0)
                {
                    childGenome.AddConnectionGene(new ConnectionGene(parent1Connection));
                }
                else
                {
                    childGenome.AddConnectionGene(new ConnectionGene(parent2.Connections[parent1Connection.InnovationNumber]));
                }
            }
            else
            {
                //Distjoint or excess gene
                childGenome.AddConnectionGene(new ConnectionGene(parent1Connection));
            }
        }

        return(childGenome);
    }
    /// <summary>
    /// Create the start genome
    /// </summary>
    private void SetStartGenome()
    {
        _nodeCounter       = new GeneCounter(0);
        _connectionCounter = new GeneCounter(0);

        _startGenome = new Genome();

        int amountPlayerInputs = PlayerController.GetAmountOfInputs(_levelViewWidht, _levelViewHeight);

        List <NodeGene> tmpInputNodes = new List <NodeGene>();

        //Crate input nodes
        for (int i = 0; i < amountPlayerInputs; i++)
        {
            NodeGene node = new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.SIGMOID);
            _startGenome.AddNodeGene(node);
            tmpInputNodes.Add(node);
        }

        //Create output nodes
        NodeGene outputNode1 = new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.SIGMOID);
        NodeGene outputNode2 = new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.SIGMOID);

        _startGenome.AddNodeGene(outputNode1);
        _startGenome.AddNodeGene(outputNode2);

        //Create connections
        for (int i = 0; i < amountPlayerInputs; i++)
        {
            _startGenome.AddConnectionGene(new ConnectionGene(tmpInputNodes[i].ID, outputNode1.ID, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
            _startGenome.AddConnectionGene(new ConnectionGene(tmpInputNodes[i].ID, outputNode2.ID, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        }
    }
Beispiel #6
0
        public void CompatibilityDistanceTest_TwoDifferentGenomes_3()
        {
            Simulation tmpSim = new Simulation(r, gen1, 1);

            Genome genCopy = gen1.Copy();

            gen1.ParentSimulation    = tmpSim;
            genCopy.ParentSimulation = tmpSim;

            // Change some weights and add connections
            genCopy.ConnectionGenes[0].Weight = 0.0f;
            genCopy.ConnectionGenes[1].Weight = 0.0f;
            genCopy.AddConnectionGene(1, 2, 0.0f);
            genCopy.AddConnectionGene(1, 3, 0.0f);

            float epsilon = 0.0001f;

            Assert.IsTrue(Genome.DisjointGenesCount(gen1, genCopy) == 2);

            float distance   = Math.Abs(gen1.CompatibilityDistance(genCopy));
            float weightDiff = 0.4f * (0.5f + 1.0f) / 6.0f;
            float expected   = 2.0f + weightDiff; // -> 2 new genes (2 x 1.0) + average weight difference

            Assert.IsTrue(Math.Abs(distance - expected) < epsilon, String.Format("Expected {0}, got {1}", expected, distance));
        }
Beispiel #7
0
        public void AddConnectionTest_Null_ExpectectedException()
        {
            Simulation tmpSim = new Simulation(r, gen1, 1);

            gen1.ParentSimulation = tmpSim;

            gen1.AddConnectionGene(null);
        }
Beispiel #8
0
        public void SetupTest()
        {
            r = new Random(0);

            // Genome 1
            gen1 = new Genome(r);

            // Create 3 sensors
            gen1.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            gen1.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            gen1.AddNode(new Node(Node.ENodeType.SENSOR, 3));

            // Create 1 output
            gen1.AddNode(new Node(Node.ENodeType.OUTPUT, 4));

            // Create 1 hidden node
            gen1.AddNode(new Node(Node.ENodeType.HIDDEN, 5));

            // Add connections from the paper
            gen1.AddConnectionGene(1, 4, 0.5f);
            gen1.AddConnectionGene(2, 4, false);
            gen1.AddConnectionGene(3, 4);
            gen1.AddConnectionGene(2, 5);
            gen1.AddConnectionGene(5, 4);
            gen1.AddConnectionGene(1, 5, 8, true);



            // Genome 2
            gen2 = new Genome(r);

            // Create 3 sensors
            gen2.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            gen2.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            gen2.AddNode(new Node(Node.ENodeType.SENSOR, 3));

            // Create 1 output
            gen2.AddNode(new Node(Node.ENodeType.OUTPUT, 4));

            // Create 2 hidden nodes
            gen2.AddNode(new Node(Node.ENodeType.HIDDEN, 5));
            gen2.AddNode(new Node(Node.ENodeType.HIDDEN, 6));

            // Add connections from the paper
            gen2.AddConnectionGene(1, 4);
            gen2.AddConnectionGene(2, 4, false);
            gen2.AddConnectionGene(3, 4);
            gen2.AddConnectionGene(2, 5);
            gen2.AddConnectionGene(5, 4, false);
            gen2.AddConnectionGene(5, 6);
            gen2.AddConnectionGene(6, 4);
            gen2.AddConnectionGene(3, 5, 9, true);
            gen2.AddConnectionGene(1, 6, 10, true);
        }
Beispiel #9
0
        public void CrossoverTest()
        {
            // Parent 1
            Genome parent1 = new Genome();

            for (int i = 0; i < 3; i++)
            {
                NodeGene node = new NodeGene(NodeGene.TYPE.INPUT, i + 1);
                parent1.AddNodeGene(node);
            }

            parent1.AddNodeGene(new NodeGene(NodeGene.TYPE.OUTPUT, 4));
            parent1.AddNodeGene(new NodeGene(NodeGene.TYPE.HIDDEN, 5));

            parent1.AddConnectionGene(new ConnectionGene(1, 4, 1f, true, 1));
            parent1.AddConnectionGene(new ConnectionGene(2, 4, 1f, false, 2));
            parent1.AddConnectionGene(new ConnectionGene(3, 4, 1f, true, 3));
            parent1.AddConnectionGene(new ConnectionGene(2, 5, 1f, true, 4));
            parent1.AddConnectionGene(new ConnectionGene(5, 4, 1f, true, 5));
            parent1.AddConnectionGene(new ConnectionGene(1, 5, 1f, true, 8));

            // Parent 2 (More Fit)
            Genome parent2 = new Genome();

            for (int i = 0; i < 3; i++)
            {
                NodeGene node = new NodeGene(NodeGene.TYPE.INPUT, i + 1);
                parent2.AddNodeGene(node);
            }
            parent2.AddNodeGene(new NodeGene(NodeGene.TYPE.OUTPUT, 4));
            parent2.AddNodeGene(new NodeGene(NodeGene.TYPE.HIDDEN, 5));
            parent2.AddNodeGene(new NodeGene(NodeGene.TYPE.HIDDEN, 6));

            parent2.AddConnectionGene(new ConnectionGene(1, 4, 1f, true, 1));
            parent2.AddConnectionGene(new ConnectionGene(2, 4, 1f, false, 2));
            parent2.AddConnectionGene(new ConnectionGene(3, 4, 1f, true, 3));
            parent2.AddConnectionGene(new ConnectionGene(2, 5, 1f, true, 4));
            parent2.AddConnectionGene(new ConnectionGene(5, 4, 1f, false, 5));
            parent2.AddConnectionGene(new ConnectionGene(5, 6, 1f, true, 6));
            parent2.AddConnectionGene(new ConnectionGene(6, 4, 1f, true, 7));
            parent2.AddConnectionGene(new ConnectionGene(3, 5, 1f, true, 9));
            parent2.AddConnectionGene(new ConnectionGene(1, 6, 1f, true, 10));

            // Crossover
            Genome child = Genome.Crossover(parent2, parent1, new System.Random(), 0.75f);

            // Return Results
            Debug.Log(String.Format("PARENT 1\n{0}\n\nPARENT 2\n{1}\n\nCROSSOVER CHILD\n{2}", parent1.ToString(), parent2.ToString(), child.ToString()));
        }
Beispiel #10
0
        public void EvaluatorTestInit()
        {
            Genome genome = new Genome();
            int    n1     = _nodeInnovation.GetNewInnovationNumber();
            int    n2     = _nodeInnovation.GetNewInnovationNumber();
            int    n3     = _nodeInnovation.GetNewInnovationNumber();

            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.INPUT, n1));
            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.INPUT, n2));
            genome.AddNodeGene(new NodeGene(NodeGene.TYPE.OUTPUT, n3));

            int c1 = _connectionInnovation.GetNewInnovationNumber();
            int c2 = _connectionInnovation.GetNewInnovationNumber();

            genome.AddConnectionGene(new ConnectionGene(n1, n3, 0.5f, true, c1));
            genome.AddConnectionGene(new ConnectionGene(n2, n3, 0.5f, true, c2));

            _eval = new EvalutorTestEvaluator(_config, genome, _nodeInnovation, _connectionInnovation);
        }
Beispiel #11
0
        public void InnovationNumberTest()
        {
            // Genome
            Genome gen1 = new Genome(r);

            Assert.IsTrue(gen1.GetInnovationNumber() == 0);

            // Create 3 sensors
            gen1.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            gen1.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            gen1.AddNode(new Node(Node.ENodeType.SENSOR, 3));

            // Create 1 output
            gen1.AddNode(new Node(Node.ENodeType.OUTPUT, 4));

            // Create 1 hidden node
            gen1.AddNode(new Node(Node.ENodeType.HIDDEN, 5));

            // Add connections from the paper
            gen1.AddConnectionGene(1, 4, 0.5f);
            Assert.IsTrue(gen1.GetInnovationNumber() == 1);

            gen1.AddConnectionGene(2, 4, false);
            Assert.IsTrue(gen1.GetInnovationNumber() == 2);
            gen1.AddConnectionGene(3, 4);
            Assert.IsTrue(gen1.GetInnovationNumber() == 3);
            gen1.AddConnectionGene(2, 5);
            Assert.IsTrue(gen1.GetInnovationNumber() == 4);
            gen1.AddConnectionGene(5, 4);
            Assert.IsTrue(gen1.GetInnovationNumber() == 5);
            gen1.AddConnectionGene(1, 5, true);
            Assert.IsTrue(gen1.GetInnovationNumber() == 6);
        }
        // Use this for initialization
        void Start()
        {
            startingGenome = new Genome();
            startingGenome.AddNodeGene(new NodeGene(0, NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
            startingGenome.AddNodeGene(new NodeGene(1, NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
            startingGenome.AddNodeGene(new NodeGene(2, NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
            startingGenome.AddNodeGene(new NodeGene(3, NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));


            startingGenome.AddConnectionGene(new ConnectionGene(0, 3, Random.Range(0f, 1f), true, 0));
            startingGenome.AddConnectionGene(new ConnectionGene(1, 3, Random.Range(0f, 1f), true, 1));
            startingGenome.AddConnectionGene(new ConnectionGene(2, 3, Random.Range(0f, 1f), true, 2));



            //Nodes for a complete network

            /*
             * startingGenome.AddNodeGene(new NodeGene(4, NodeGeneType.HIDDEN, 0.5f));
             * startingGenome.AddNodeGene(new NodeGene(5, NodeGeneType.HIDDEN, 0.5f));
             *
             * startingGenome.AddConnectionGene(new ConnectionGene(0, 4, Random.Range(0f, 1f), true, 0));
             * startingGenome.AddConnectionGene(new ConnectionGene(0, 5, Random.Range(0f, 1f), true, 1));
             * startingGenome.AddConnectionGene(new ConnectionGene(1, 4, Random.Range(0f, 1f), true, 2));
             * startingGenome.AddConnectionGene(new ConnectionGene(1, 5, Random.Range(0f, 1f), true, 3));
             *
             * startingGenome.AddConnectionGene(new ConnectionGene(4, 3, Random.Range(0f, 1f), true, 4));
             * startingGenome.AddConnectionGene(new ConnectionGene(5, 3, Random.Range(0f, 1f), true, 5));
             *
             * startingGenome.AddConnectionGene(new ConnectionGene(2, 3, Random.Range(0f, 1f), true, 6));
             * startingGenome.AddConnectionGene(new ConnectionGene(2, 4, Random.Range(0f, 1f), true, 7));
             * startingGenome.AddConnectionGene(new ConnectionGene(2, 5, Random.Range(0f, 1f), true, 8));
             */

            result = new List <int>();

            _manager          = new PopulationManager();
            _manager.Callback = this;
            _manager.CreateInitialPopulation(startingGenome, new GeneCounter(6), new GeneCounter(9), 400, true);
        }
Beispiel #13
0
    public static Genome Crossover(Genome parent1, Genome parent2)
    {
        Genome child = new Genome();

        foreach (NodeGene parent1Node in parent1.GetNodeGenes().Values)
        {
            child.AddNodeGene(parent1Node.Clone());
        }

        foreach (ConnectionGene parent1Node in parent1.GetConnectionGenes().Values)
        {
            if (parent2.GetConnectionGenes().ContainsKey(parent1Node.innovation)) //matching gene
            {
                child.AddConnectionGene(Random.value < 0.5f ? parent1Node.Clone() : parent2.GetConnectionGenes()[parent1Node.innovation].Clone());
            }
            else
            {
                child.AddConnectionGene(parent1Node.Clone());
            }
        }

        return(child);
    }
Beispiel #14
0
        public static void MutateAddNode(this Genome genome)
        {
            var connection = genome.ConnectionGenes.Values.Where(cg => cg.IsEnabled).GetRandomElement();

            if (connection == null)
            {
                return;
            }

            var newNode = new NodeGene();

            genome.AddNodeGene(newNode);

            var newPreviousConnection = new ConnectionGene(connection.PreviousNodeId, newNode.Id, 1);

            genome.AddConnectionGene(newPreviousConnection);

            var newNextConnection = new ConnectionGene(newNode.Id, connection.NextNodeId, connection.Weight);

            genome.AddConnectionGene(newNextConnection);

            connection.Toggle(false);
        }
Beispiel #15
0
        public void TestAddNodeMutation()
        {
            Simulation tmpSim = new Simulation(r, gen1, 1);

            gen1.ParentSimulation = tmpSim;


            List <Innovation> innovations = new List <Innovation>();
            Genome            gen3        = new Genome(r);

            gen3.ParentSimulation = tmpSim;

            gen3.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            gen3.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            gen3.AddNode(new Node(Node.ENodeType.OUTPUT, 3));

            gen3.AddConnectionGene(1, 3, 0.5f);
            gen3.AddConnectionGene(2, 3, 1.0f);

            Assert.IsTrue(gen3.Nodes.Count == 3);
            gen3.AddNodeMutation(innovations);
            Assert.IsTrue(gen3.Nodes.Count == 4);
        }
Beispiel #16
0
        public void FindConnectionGeneToSplitTest_NoEnabledGenes_Expected_False()
        {
            Genome genome = new Genome(r);

            genome.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            genome.AddNode(new Node(Node.ENodeType.OUTPUT, 2));

            genome.AddConnectionGene(1, 2, false);

            int  connectionIndex = -1;
            bool found           = genome.FindConnectionGeneToSplit(out connectionIndex);

            Assert.AreEqual(false, found);
            Assert.AreEqual(-1, connectionIndex);
        }
Beispiel #17
0
        public void TestAddConnectionMutation()
        {
            List <Innovation> innovations = new List <Innovation>();


            Simulation tmpSim = new Simulation(r, gen1, 1);

            gen1.ParentSimulation = tmpSim;


            Genome gen4 = new Genome(r);

            gen4.ParentSimulation = tmpSim;

            // Create 3 sensors
            gen4.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            gen4.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            gen4.AddNode(new Node(Node.ENodeType.SENSOR, 3));

            // Create 1 output
            gen4.AddNode(new Node(Node.ENodeType.OUTPUT, 4));

            // Create 1 hidden node
            gen4.AddNode(new Node(Node.ENodeType.HIDDEN, 5));

            // Add connections from the paper
            gen4.AddConnectionGene(1, 4);
            gen4.AddConnectionGene(2, 4);
            gen4.AddConnectionGene(3, 4);
            gen4.AddConnectionGene(2, 5);
            gen4.AddConnectionGene(5, 4);

            Assert.IsTrue(gen4.ConnectionGenes.Count == 5);
            gen4.AddConnectionMutation(innovations);
            Assert.IsTrue(gen4.ConnectionGenes.Count == 6);
        }
Beispiel #18
0
    public static Genome Crossover(Genome parent1, Genome parent2)
    { // parent1 always more fit parent - no equal fitness parents
        System.Random rand      = new System.Random();
        Genome        offspring = new Genome();

        foreach (NodeGene parent1Node in parent1.GetNodes().Values)
        {
            offspring.AddNodeGene(parent1Node.CopyNode());
        }

        foreach (ConnectionGene parent1Connection in parent1.GetConnections().Values)
        {
            if (parent2.GetConnections().ContainsKey(parent1Connection.getInnovation()))
            {
                offspring.AddConnectionGene((rand.NextDouble() > 0.5) ? parent1Connection.CopyConnection() : parent2.GetConnections()[parent1Connection.getInnovation()].CopyConnection());
            }
            else
            {
                offspring.AddConnectionGene(parent1Connection.CopyConnection());
            }
        }

        return(offspring);
    }
Beispiel #19
0
    public static Genome Clone(Genome genome)
    {
        Genome child = new Genome();

        foreach (NodeGene node in genome.GetNodeGenes().Values)
        {
            child.AddNodeGene(node.Clone());
        }

        foreach (ConnectionGene con in genome.GetConnectionGenes().Values)
        {
            child.AddConnectionGene(con.Clone());
        }

        return(child);
    }
Beispiel #20
0
        public void CompatibilityDistanceTest_TwoDifferentGenomes_2()
        {
            Simulation tmpSim = new Simulation(r, gen1, 1);

            Genome genCopy = gen1.Copy();

            gen1.ParentSimulation    = tmpSim;
            genCopy.ParentSimulation = tmpSim;

            genCopy.AddConnectionGene(1, 2, 0.0f);

            float epsilon = 0.0001f;

            Assert.IsTrue(Genome.DisjointGenesCount(gen1, genCopy) == 1);
            float distance = Math.Abs(gen1.CompatibilityDistance(genCopy));

            Assert.IsTrue(Math.Abs(distance - 1.0f) < epsilon, String.Format("Expected {0}, got {1}", 1.0f, distance));
        }
Beispiel #21
0
        public void FindConnectionGeneToSplitTest_Correct_Expected_True()
        {
            UnitTests.RandomStub randomStub = new UnitTests.RandomStub();
            randomStub.NextIntValue = 0; randomStub.NextDoubleValue = 0.0;

            Genome genome = new Genome(randomStub);

            genome.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            genome.AddNode(new Node(Node.ENodeType.OUTPUT, 2));

            genome.AddConnectionGene(1, 2, true);

            int  connectionIndex = -1;
            bool found           = genome.FindConnectionGeneToSplit(out connectionIndex);

            Assert.AreEqual(true, found);
            Assert.AreEqual(0, connectionIndex);
        }
Beispiel #22
0
        public static void MutateAddConnection(this Genome genome, bool forceBias = false)
        {
            NodeGene firstNode;

            if (forceBias)
            {
                firstNode = genome.NodeGenes.Values.Where(g => g.Type == NodeGeneType.Input).Last();
            }
            else
            {
                firstNode = genome.NodeGenes.Values.GetRandomElement();
            }

            var secondNode = genome.NodeGenes.Values.GetRandomElement();
            // TODO: Fix this hack that prevent possible endless loop
            int limiter = 0;

            while (firstNode.Id == secondNode.Id ||
                   genome.ConnectionGenes.GetConnection(firstNode, secondNode) != null ||
                   firstNode.Type == NodeGeneType.Input && secondNode.Type == NodeGeneType.Input ||
                   firstNode.Type == NodeGeneType.Output && secondNode.Type == NodeGeneType.Output)
            {
                secondNode = genome.NodeGenes.Values.GetRandomElement();
                if (limiter > 100)
                {
                    return;
                }
                limiter++;
            }

            if (firstNode.Type == NodeGeneType.Output && secondNode.Type == NodeGeneType.Hidden ||
                firstNode.Type == NodeGeneType.Hidden && secondNode.Type == NodeGeneType.Input ||
                firstNode.Type == NodeGeneType.Output && secondNode.Type == NodeGeneType.Input)
            {
                var tmp = secondNode;
                secondNode = firstNode;
                firstNode  = tmp;
            }

            var newConnection = new ConnectionGene(firstNode.Id, secondNode.Id);

            genome.AddConnectionGene(newConnection);
        }
Beispiel #23
0
    public Genome InitGenome()
    {
        Genome g1 = new Genome(gt);



        for (int i = 0; i < inputSize + outputSize; i++)
        {
            NodeGene node = GetDeafultGenome().GetNodeGenes()[i].Copy();
            if (node.GetNodeType() == NodeGene.NODETYPE.OUTPUT || node.GetNodeType() == NodeGene.NODETYPE.HIDDEN)
            {
                node.SetBias(Random.Range(-1.0f, 1.0f));
                //node.SetBias(1.0f);
            }
            g1.AddNodeGene(node);
            //g1.GetNodeGenes()[inputSize + i].SetBias(Random.Range(-1.0f, 1.0f));
        }
        for (int i = 0; i < startConnections; i++)//sample n connections
        {
            ConnectionGene con = connections[Random.Range(0, connections.Count)].Copy();
            //ConnectionGene con = connections[i].Copy();
            con.SetWeight(Random.Range(-weightRange, weightRange));
            //con.SetWeight(1.0f);
            int inId = con.GetInNode().GetId();
            con.SetInNode(g1.GetNodeGenes()[inId]);
            int outId = con.GetOutNode().GetId();
            //Debug.Log(con.GetOutNode());
            //Debug.Log(outId);
            con.SetOutNode(g1.GetNodeGenes()[outId]);
            g1.AddConnectionGene(con);
        }
        if (speciation)
        {
            InsertGenomeIntoSpecies(g1, species);
            impf.StatsSpecies(species.Count);
        }
        genomes.Add(g1);

        return(g1);
    }
Beispiel #24
0
    public Genome Copy()
    {
        Genome          g         = new Genome(track);
        List <NodeGene> nodesList = new List <NodeGene>();

        for (int i = 0; i < nodes.Count; i++)
        {
            nodesList.Add(nodes[i].Copy());
            g.AddNodeGene(nodesList[i]);
        }

        List <ConnectionGene> connectionsList = new List <ConnectionGene>();

        for (int i = 0; i < connections.Count; i++)
        {
            connectionsList.Add(connections[i].Copy());
            connectionsList[i].SetInNode(g.FindNode(connections[i].GetInNode().GetId()));
            connectionsList[i].SetOutNode(g.FindNode(connections[i].GetOutNode().GetId()));
            //Debug.Log(connectionsList[i]);
            g.AddConnectionGene(connectionsList[i]);
        }
        g.SetLayers(layers);
        return(g);
    }
Beispiel #25
0
    public Genome CrossoverGenes(Genome genome1, Genome genome2, GeneTracker track)
    {
        Genome          child        = new Genome(track);
        List <NodeGene> newNodeGenes = new List <NodeGene>();

        //for (int i = 0; i < genome1.GetNodeGenes().Count; i++)
        //{
        //    commonNodeGenes.Add(genome1.GetNodeGenes()[i].Copy());

        //}
        //for (int i = 0; i < genome2.GetNodeGenes().Count; i++)
        //{
        //    if (!commonNodeGenes.Contains(genome2.GetNodeGenes()[i]))
        //    {
        //        commonNodeGenes.Add(genome2.GetNodeGenes()[i].Copy());

        //    }


        //}

        if (genome1.GetFitness() < genome2.GetFitness())
        {//swap so genome1 has the higher fitness
            Genome temp = genome2;
            genome2 = genome1;
            genome1 = temp;
        }
        //Debug.Log("g1 "+genome1+ "\ng2 " + genome2);

        child.SetLayers(genome1.GetLayers());

        /*
         * for (int i = 0; i < genome1.GetNodeGenes().Count; i++) {
         *  for (int i2 = 0; i2 < genome2.GetNodeGenes().Count; i2++)
         *  {
         *
         *
         *  }
         * }
         */

        for (int i = 0; i < genome1.GetNodeGenes().Count; i++)
        {
            newNodeGenes.Add(genome1.GetNodeGenes()[i].Copy());
        }

        for (int i = 0; i < genome2.GetNodeGenes().Count; i++)
        {
            if (newNodeGenes.Contains(genome2.GetNodeGenes()[i]))
            {
                if (Random.Range(0, 2) == 1)
                {
                    // newNodeGenes.RemoveAt(newNodeGenes.IndexOf(genome2.GetNodeGenes()[i]));
                    //newNodeGenes.Add(genome2.GetNodeGenes()[i].Copy());
                    newNodeGenes[newNodeGenes.IndexOf(genome2.GetNodeGenes()[i])].SetBias(genome2.GetNodeGenes()[i].GetBias());
                }
            }
        }
        for (int i = 0; i < genome1.GetNodeGenes().Count; i++)
        {
            child.AddNodeGene(newNodeGenes[i]);
        }

        List <ConnectionGene> newConnectionGenes = new List <ConnectionGene>();

        //if equal choose random
        for (int i = 0; i < genome1.GetConnectionGenes().Count; i++)  //copy all connections
        {
            newConnectionGenes.Add(genome1.GetConnectionGenes()[i].Copy());
            newConnectionGenes[i].SetInNode(child.FindNode(genome1.GetConnectionGenes()[i].GetInNode().GetId()));
            newConnectionGenes[i].SetOutNode(child.FindNode(genome1.GetConnectionGenes()[i].GetOutNode().GetId()));
        }
        for (int i = 0; i < genome2.GetConnectionGenes().Count; i++)
        {
            //Debug.Log(newConnectionGenes.Contains(genome2.GetConnectionGenes()[i]));
            if (newConnectionGenes.Contains(genome2.GetConnectionGenes()[i]))
            {
                //Debug.Log(Random.Range(0, 2) );
                if (Random.Range(0, 2) == 1)
                {
                    //newConnectionGenes.RemoveAt(newConnectionGenes.IndexOf(genome2.GetConnectionGenes()[i]));
                    //newConnectionGenes.Add(genome2.GetConnectionGenes()[i].Copy());

                    //newConnectionGenes[i].SetWeight(genome2.GetConnectionGenes()[i].GetWeight());
                    //Debug.Log(newConnectionGenes[newConnectionGenes.IndexOf(genome2.GetConnectionGenes()[i])].GetWeight());
                    newConnectionGenes[newConnectionGenes.IndexOf(genome2.GetConnectionGenes()[i])].SetWeight(genome2.GetConnectionGenes()[i].GetWeight());
                }
            }
        }
        for (int i = 0; i < genome1.GetConnectionGenes().Count; i++)
        {
            child.AddConnectionGene(newConnectionGenes[i]);
        }
        //Debug.Log("child "+child);
        return(child);
    }
Beispiel #26
0
        private void CreateStartingGenomeAndEvaluator()
        {
            // Create New Genome
            Genome genome = new Genome(config.newWeightRange, config.perturbingProbability);

            // Check there is at least 1 Input & 1 Output Nodes
            if (config.inputNodeNumber == 0)
            {
                config.inputNodeNumber = 1;
            }
            if (config.outputNodeNumber == 0)
            {
                config.outputNodeNumber = 1;
            }

            // Create Input Nodes
            for (int i = 0; i < config.inputNodeNumber; i++)
            {
                genome.AddNodeGene(new NodeGene(NodeGene.TYPE.INPUT, _nodeInnovation.GetNewInnovationNumber()));
            }

            // Create Hidden Nodes
            foreach (int nb in config.hiddenNodeStartNumberByLayer)
            {
                for (int i = 0; i < nb; ++i)
                {
                    genome.AddNodeGene(new NodeGene(NodeGene.TYPE.HIDDEN, _nodeInnovation.GetNewInnovationNumber()));
                }
            }

            // Create Output Nodes
            for (int i = 0; i < config.outputNodeNumber; i++)
            {
                genome.AddNodeGene(new NodeGene(NodeGene.TYPE.OUTPUT, _nodeInnovation.GetNewInnovationNumber()));
            }

            // Create Connections
            if (config.addConnectionOnCreation)
            {
                if (config.hiddenNodeStartNumberByLayer.Count > 0)
                {
                    int inputStartId         = 0;
                    int previousHiddenStatId = 0;
                    int previousHiddenStopId = 0;
                    int hiddenStartId        = config.inputNodeNumber;
                    int hiddenStopId         = config.inputNodeNumber;
                    int outputStartId        = genome.Nodes.Count - config.outputNodeNumber;

                    // Loop through Hidden Layers
                    for (int hiddenLayer = 0; hiddenLayer < config.hiddenNodeStartNumberByLayer.Count; hiddenLayer++)
                    {
                        // Get Hidden Start & Stop Ids
                        if (hiddenLayer > 0)
                        {
                            hiddenStartId += config.hiddenNodeStartNumberByLayer[hiddenLayer - 1];
                        }
                        hiddenStopId += config.hiddenNodeStartNumberByLayer[hiddenLayer];

                        // Loop through Nodes of the current Layer
                        for (int hiddenNodeId = hiddenStartId; hiddenNodeId < hiddenStopId; ++hiddenNodeId)
                        {
                            // If current Hidden Layer is the first Layer
                            if (hiddenLayer == 0)
                            {
                                // Add Connections from Inputs to First Hidden Layer
                                for (int inputNodeId = inputStartId; inputNodeId < config.inputNodeNumber; ++inputNodeId)
                                {
                                    genome.AddConnectionGene(new ConnectionGene(inputNodeId, hiddenNodeId, Random.Range(config.newWeightRange.x, config.newWeightRange.y), true, _connectionInnovation.GetNewInnovationNumber()));
                                }
                            }
                            else
                            {
                                // Add Connections from previous Hidden Layer to current Hidden Layer
                                for (int previousHiddenNodeId = previousHiddenStatId; previousHiddenNodeId < previousHiddenStopId; ++previousHiddenNodeId)
                                {
                                    genome.AddConnectionGene(new ConnectionGene(previousHiddenNodeId, hiddenNodeId, Random.Range(config.newWeightRange.x, config.newWeightRange.y), true, _connectionInnovation.GetNewInnovationNumber()));
                                }

                                // If current Hidden Layer is the last Layer
                                if (hiddenLayer + 1 == config.hiddenNodeStartNumberByLayer.Count)
                                {
                                    // Add Connections from Last Hidden Layer to Outputs
                                    for (int outputNodeId = outputStartId; outputNodeId < genome.Nodes.Count; ++outputNodeId)
                                    {
                                        genome.AddConnectionGene(new ConnectionGene(hiddenNodeId, outputNodeId, Random.Range(config.newWeightRange.x, config.newWeightRange.y), true, _connectionInnovation.GetNewInnovationNumber()));
                                    }
                                }
                            }
                        }

                        // Save previous Hidden Layer Start & Stop Ids
                        previousHiddenStatId = hiddenStartId;
                        previousHiddenStopId = hiddenStopId;
                    }
                }
                else
                {
                    int outputStartId = config.inputNodeNumber;
                    int outputStopId  = config.inputNodeNumber + config.outputNodeNumber;

                    // Loop Input Node
                    for (int inputNodeId = 0; inputNodeId < outputStartId; ++inputNodeId)
                    {
                        // Loop Output Node & add Connection between Input Node & Hidden Node
                        for (int outputNodeId = outputStartId; outputNodeId < outputStopId; ++outputNodeId)
                        {
                            genome.AddConnectionGene(new ConnectionGene(inputNodeId, outputNodeId, Random.Range(config.newWeightRange.x, config.newWeightRange.y), true, _connectionInnovation.GetNewInnovationNumber()));
                        }
                    }
                }
            }

            _startingGenome = genome;
            Debug.Log("Starting Genome:\n" + genome.ToString());

            // Create Evaluator
            _evaluator = new CreatureEvaluator(config, genome, _nodeInnovation, _connectionInnovation);
        }
Beispiel #27
0
    public void LoadGenome(string filename, bool all)
    {
        string path = filename;

        Genome genome = new Genome();

        using (StreamReader reader = new StreamReader(path))
        {
            bool   node       = false;
            bool   connection = false;
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (line.Equals("Nodes"))
                {
                    node       = true;
                    connection = false;
                }
                else if (line.Equals("Connections"))
                {
                    node       = false;
                    connection = true;
                }
                else
                {
                    string[] info = line.Split(',');

                    if (node)
                    {
                        int                    id         = int.Parse(info[0]);
                        NodeGene.Type          type       = (NodeGene.Type)System.Enum.Parse(typeof(NodeGene.Type), info[1]);
                        GenomeUtils.Activation activation = (GenomeUtils.Activation)System.Enum.Parse(typeof(GenomeUtils.Activation), info[2]);
                        genome.AddNodeGene(new NodeGene(type, id, activation));
                        Counter.SetNodeCounter(id);
                    }
                    else if (connection)
                    {
                        int   innovation = int.Parse(info[0]);
                        bool  expressed  = bool.Parse(info[1]);
                        int   inNode     = int.Parse(info[2]);
                        int   outNode    = int.Parse(info[3]);
                        float weight     = float.Parse(info[4]);
                        genome.AddConnectionGene(new ConnectionGene(inNode, outNode, weight, expressed, innovation));
                        Counter.SetConnectionCounter(innovation);
                    }
                    else
                    {
                        Debug.LogError("Invalid genome file");
                    }
                }
            }
        }

        genomes.Clear();
        genomes.Add(genome);

        if (all)
        {
            for (int i = 1; i < GenomeUtils.POP_SIZE; i++)
            {
                genomes.Add(GenomeUtils.Clone(genome));
            }
        }
        else
        {
            for (int i = 1; i < GenomeUtils.POP_SIZE; i++)
            {
                genomes.Add(new Genome(inputNodes, outputNodes));
            }
        }

        SetSpecies();
        MakeNNets();
    }
Beispiel #28
0
    /// <summary>
    /// Create the start genome
    /// </summary>
    private void SetStartGenome()
    {
        _nodeCounter       = new GeneCounter(0);
        _connectionCounter = new GeneCounter(0);

        _startGenome = new Genome();

        //5 input nodes + 1 bias node
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));

        //OutputNodes
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));
        _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID));

        //Add connections to first output nde
        _startGenome.AddConnectionGene(new ConnectionGene(0, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(1, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(2, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(3, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(4, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(5, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));

        //Connection to second ouztputNode
        _startGenome.AddConnectionGene(new ConnectionGene(0, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(1, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(2, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(3, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(4, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
        _startGenome.AddConnectionGene(new ConnectionGene(5, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber()));
    }
Beispiel #29
0
        private static void PoleBalanceSingleTest(Random r)
        {
            Genome startGenome = new Genome(r);

            startGenome.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            startGenome.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            startGenome.AddNode(new Node(Node.ENodeType.SENSOR, 3));
            startGenome.AddNode(new Node(Node.ENodeType.SENSOR, 4));
            startGenome.AddNode(new Node(Node.ENodeType.SENSOR, 5));
            startGenome.AddNode(new Node(Node.ENodeType.OUTPUT, 6));
            startGenome.AddNode(new Node(Node.ENodeType.OUTPUT, 7));

            startGenome.AddConnectionGene(1, 6, 0.0f);
            startGenome.AddConnectionGene(2, 6, 0.0f);
            startGenome.AddConnectionGene(3, 6, 0.0f);
            startGenome.AddConnectionGene(4, 6, 0.0f);
            startGenome.AddConnectionGene(5, 6, 0.0f);
            startGenome.AddConnectionGene(1, 7, 0.0f);
            startGenome.AddConnectionGene(2, 7, 0.0f);
            startGenome.AddConnectionGene(3, 7, 0.0f);
            startGenome.AddConnectionGene(4, 7, 0.0f);
            startGenome.AddConnectionGene(5, 7, 0.0f);

            // Run simulation
            Simulation sim          = new Simulation(r, startGenome, 150);
            int        numberOfRuns = 200;
            int        numnodes;       // Used to figure out how many nodes should be visited during activation
            int        thresh;         // How many visits will be allowed before giving up (for loop detection)
            int        MAX_STEPS     = 100000;
            bool       solutionFound = false;
            Genome     bestGenome    = null;

            for (int i = 0; i < numberOfRuns; ++i)
            {
                double epochBestFitness   = 0.0f;
                float  avgConnectionGenes = 0.0f;

                // Evaluate all genomes
                foreach (Genome gen in sim.Genomes)
                {
                    Network network = gen.GetNetwork();
                    numnodes = gen.Nodes.Count;
                    thresh   = numnodes * 2;

                    gen.Fitness = Go_cart(network, MAX_STEPS, thresh, r);
                    if (gen.Fitness > epochBestFitness)
                    {
                        epochBestFitness = gen.Fitness;
                    }
                    avgConnectionGenes += gen.ConnectionGenes.Count;

                    if (gen.Fitness >= MAX_STEPS)
                    {
                        bestGenome    = gen;
                        solutionFound = true;
                        break;
                    }
                }

                avgConnectionGenes /= sim.Genomes.Count;

                Console.WriteLine(String.Format("Epoch {0} | best: {1} | avg genes: {2} | species: {3}", i, epochBestFitness, avgConnectionGenes, sim.Species.Count));

                if (solutionFound)
                {
                    break;
                }

                sim.Epoch();
            }

            if (solutionFound)
            {
                Console.WriteLine(String.Format("Solution network nodes count: {0} | connections count: {1}", bestGenome.Nodes.Count, bestGenome.ConnectionGenes.Count));
            }
            else
            {
                Console.WriteLine("Solution NOT found!");
            }
        }
Beispiel #30
0
        private static void XorTest(Random r)
        {
            Genome xorGene = new Genome(r);

            xorGene.AddNode(new Node(Node.ENodeType.SENSOR, 1));
            xorGene.AddNode(new Node(Node.ENodeType.SENSOR, 2));
            xorGene.AddNode(new Node(Node.ENodeType.SENSOR, 3));
            xorGene.AddNode(new Node(Node.ENodeType.OUTPUT, 4));

            xorGene.AddConnectionGene(1, 4, 0.0f);
            xorGene.AddConnectionGene(2, 4, 0.0f);
            xorGene.AddConnectionGene(3, 4, 0.0f);

            // Run simulation
            Simulation sim = new Simulation(r, xorGene, 150);

            sim.Parameters.AreConnectionWeightsCapped = false;
            sim.Parameters.MaxWeight           = 1.0f;
            sim.Parameters.WeightMutationPower = 2.5f;

            int    numberOfRuns  = 200;
            bool   solutionFound = false;
            Genome bestGenome    = null;

            float[] output     = { 0.0f, 0.0f, 0.0f, 0.0f };
            float[] bestOutput = new float[4];
            float[,] input =
            {
                { 1.0f, 0.0f, 0.0f },
                { 1.0f, 0.0f, 1.0f },
                { 1.0f, 1.0f, 0.0f },
                { 1.0f, 1.0f, 1.0f }
            };
            for (int i = 0; i < numberOfRuns; ++i)
            {
                double epochBestFitness   = 0.0f;
                float  avgConnectionGenes = 0.0f;

                // Evaluate all genomes
                foreach (Genome gen in sim.Genomes)
                {
                    Network network = gen.GetNetwork();
                    //network.ActivationFunction = new NeuralEvolution.ActivationFunctions.ReLU();
                    bool couldActivate = true;
                    for (int inputIdx = 0; inputIdx < 4; ++inputIdx)
                    {
                        float[] inputRow = new float[3];
                        for (int k = 0; k < 3; ++k)
                        {
                            inputRow[k] = input[inputIdx, k];
                        }
                        network.SetInput(inputRow);
                        if (!network.Activate())
                        {
                            couldActivate = false;
                        }

                        // Relax network
                        int networkDepth = network.GetMaxDepth();
                        for (int relax = 0; relax <= networkDepth; ++relax)
                        {
                            network.Activate();
                        }

                        output[inputIdx] = network.Output[0].Activation;

                        network.Reset();
                    }

                    float errorsum = (float)(Math.Abs(output[0]) + Math.Abs(1.0 - output[1]) + Math.Abs(1.0 - output[2]) + Math.Abs(output[3]));
                    if (!couldActivate)
                    {
                        errorsum = 4;
                    }
                    gen.Fitness = Math.Pow((4.0 - errorsum), 2);
                    gen.Error   = errorsum;

                    if (gen.Fitness > epochBestFitness)
                    {
                        bestOutput[0]    = output[0]; bestOutput[1] = output[1]; bestOutput[2] = output[2]; bestOutput[3] = output[3];
                        epochBestFitness = gen.Fitness;
                    }

                    avgConnectionGenes += gen.ConnectionGenes.Count;

                    if ((output[0] < 0.5f) && (output[1] >= 0.5f) && (output[2] >= 0.5f) && (output[3] < 0.5f))
                    {
                        bestOutput[0] = output[0]; bestOutput[1] = output[1]; bestOutput[2] = output[2]; bestOutput[3] = output[3];
                        bestGenome    = gen;
                        solutionFound = true;
                        break;
                    }
                }

                avgConnectionGenes /= sim.Genomes.Count;

                Console.WriteLine(String.Format("Epoch {0} | best: {1} | best output: [{2}, {3}, {4}, {5}] | avg genes: {6} | species: {7}", i, epochBestFitness, bestOutput[0], bestOutput[1], bestOutput[2], bestOutput[3], avgConnectionGenes, sim.Species.Count));

                // We found a solution so we can exit already
                if (solutionFound)
                {
                    break;
                }

                // Advance to the next step of simulation
                sim.Epoch();
            }

            if (solutionFound)
            {
                Console.WriteLine(String.Format("Solution found: [{0}, {1}, {2}, {3}]", bestOutput[0], bestOutput[1], bestOutput[2], bestOutput[3]));
                Console.WriteLine(String.Format("Solution network nodes count: {0} | connections count: {1}", bestGenome.Nodes.Count, bestGenome.ConnectionGenes.Count));
            }
            else
            {
                Console.WriteLine("Solution NOT found!");
            }
        }