/// <summary>
        ///     Creates the evolution algorithm container using the given factories and genome lists.
        /// </summary>
        /// <param name="genomeFactory1">The agent genome factory.</param>
        /// <param name="genomeFactory2">The maze genome factory.</param>
        /// <param name="genomeList1">The agent genome list.</param>
        /// <param name="genomeList2">The maze genome list.</param>
        /// <returns>The instantiated coevolution algorithm container.</returns>
        public override ICoevolutionAlgorithmContainer<NeatGenome, MazeGenome> CreateCoevolutionAlgorithmContainer(
            IGenomeFactory<NeatGenome> genomeFactory1,
            IGenomeFactory<MazeGenome> genomeFactory2, List<NeatGenome> genomeList1, List<MazeGenome> genomeList2)
        {
            List<NeatGenome> seedAgentPopulation = new List<NeatGenome>();

            // Compute the maze max complexity
            ((MazeGenomeFactory) genomeFactory2).MaxComplexity = MazeUtils.DetermineMaxPartitions(_mazeHeight,
                _mazeWidth, 200);

            // Create maze decoder to decode initialization mazes
            MazeDecoder mazeDecoder = new MazeDecoder(_mazeHeight, _mazeWidth, _mazeScaleMultiplier);

            // Loop through every maze and evolve the requisite number of viable genomes that solve it
            for (int idx = 0; idx < genomeList2.Count; idx++)
            {
                Console.WriteLine(@"Evolving viable agents for maze population index {0} and maze ID {1}", idx,
                    genomeList2[idx].Id);

                // Evolve the number of agents required to meet the success MC for the current maze
                List<NeatGenome> viableMazeAgents = EvolveViableAgents(genomeFactory1, genomeList1.ToList(),
                    mazeDecoder.Decode(genomeList2[idx]));

                // Add the viable agent genomes who solve the current maze (but avoid adding duplicates, as identified by the genome ID)
                // Note that it's fine to have multiple mazes solved by the same agent, so in this case, we'll leave the agent
                // in the pool of seed agent genomes
                foreach (
                    NeatGenome viableMazeAgent in
                        viableMazeAgents.Where(
                            viableMazeAgent =>
                                seedAgentPopulation.Select(sap => sap.Id).Contains(viableMazeAgent.Id) == false))
                {
                    seedAgentPopulation.Add(viableMazeAgent);
                }
            }

            // If we still lack the genomes to fill out agent specie count while still satisfying the maze MC,
            // iteratively pick a random maze and evolve agents on that maze until we reach the requisite number
            while (seedAgentPopulation.ToList().Count < _numAgentSuccessCriteria*AgentNumSpecies)
            {
                FastRandom rndMazePicker = new FastRandom();

                // Pick a random maze on which to evolve agent(s)
                MazeGenome mazeGenome = genomeList2[rndMazePicker.Next(genomeList2.Count - 1)];

                Console.WriteLine(
                    @"Continuing viable agent evolution on maze {0}, with {1} of {2} required agents in place",
                    mazeGenome.Id, seedAgentPopulation.Count, (_numAgentSuccessCriteria*AgentNumSpecies));

                // Evolve the number of agents required to meet the success MC for the maze
                List<NeatGenome> viableMazeAgents = EvolveViableAgents(genomeFactory1, genomeList1.ToList(),
                    mazeDecoder.Decode(mazeGenome));

                // Iterate through each viable agent and remove them if they've already solved a maze or add them to the list
                // of viable agents if they have not
                foreach (NeatGenome viableMazeAgent in viableMazeAgents)
                {
                    // If they agent has already solved maze and is in the list of viable agents, remove that agent
                    // from the pool of seed genomes (this is done because here, we're interested in getting unique
                    // agents and want to avoid an endless loop wherein the same viable agents are returned)
                    if (seedAgentPopulation.Select(sap => sap.Id).Contains(viableMazeAgent.Id))
                    {
                        genomeList1.Remove(viableMazeAgent);
                    }
                    // Otherwise, add that agent to the list of viable agents
                    else
                    {
                        seedAgentPopulation.Add(viableMazeAgent);
                    }
                }
            }

            // Set dummy fitness so that seed maze(s) will be marked as evaluated
            foreach (MazeGenome mazeGenome in genomeList2)
            {
                mazeGenome.EvaluationInfo.SetFitness(0);
            }

            // Reset primary NEAT genome parameters on agent genome factory
            ((NeatGenomeFactory) genomeFactory1).ResetNeatGenomeParameters(NeatGenomeParameters);

            // Create the NEAT (i.e. navigator) queueing evolution algorithm
            AbstractEvolutionAlgorithm<NeatGenome> neatEvolutionAlgorithm =
                new MultiQueueNeatEvolutionAlgorithm<NeatGenome>(
                    new NeatEvolutionAlgorithmParameters
                    {
                        SpecieCount = AgentNumSpecies,
                        MaxSpecieSize = AgentDefaultPopulationSize/AgentNumSpecies
                    },
                    new ParallelKMeansClusteringStrategy<NeatGenome>(new ManhattanDistanceMetric(1.0, 0.0, 10.0),
                        ParallelOptions), null, NavigatorBatchSize, RunPhase.Primary, _navigatorEvolutionDataLogger,
                    _navigatorLogFieldEnableMap, _navigatorPopulationGenomesDataLogger, _populationLoggingBatchInterval);

            // Create the maze queueing evolution algorithm
            AbstractEvolutionAlgorithm<MazeGenome> mazeEvolutionAlgorithm =
                new MultiQueueNeatEvolutionAlgorithm<MazeGenome>(
                    new NeatEvolutionAlgorithmParameters
                    {
                        SpecieCount = MazeNumSpecies,
                        MaxSpecieSize = MazeDefaultPopulationSize/MazeNumSpecies
                    },
                    new ParallelKMeansClusteringStrategy<MazeGenome>(new ManhattanDistanceMetric(1.0, 0.0, 10.0),
                        ParallelOptions), null, MazeBatchSize, RunPhase.Primary, _mazeEvolutionDataLogger,
                    _mazeLogFieldEnableMap, _mazePopulationGenomesDataLogger, _populationLoggingBatchInterval);

            // Create the maze phenome evaluator
            IPhenomeEvaluator<MazeStructure, BehaviorInfo> mazeEvaluator = new MazeEnvironmentMCSEvaluator(
                _maxTimesteps, _minSuccessDistance, BehaviorCharacterizationFactory, _numAgentSuccessCriteria, 0);

            // Create navigator phenome evaluator
            IPhenomeEvaluator<IBlackBox, BehaviorInfo> navigatorEvaluator = new MazeNavigatorMCSEvaluator(
                _maxTimesteps, _minSuccessDistance, BehaviorCharacterizationFactory, _numMazeSuccessCriteria);

            // Create maze genome decoder
            IGenomeDecoder<MazeGenome, MazeStructure> mazeGenomeDecoder = new MazeDecoder(_mazeHeight, _mazeWidth,
                _mazeScaleMultiplier);

            // Create navigator genome decoder
            IGenomeDecoder<NeatGenome, IBlackBox> navigatorGenomeDecoder = new NeatGenomeDecoder(ActivationScheme);

            // Create the maze genome evaluator
            IGenomeEvaluator<MazeGenome> mazeFitnessEvaluator =
                new ParallelGenomeBehaviorEvaluator<MazeGenome, MazeStructure>(mazeGenomeDecoder, mazeEvaluator,
                    SelectionType.Queueing, SearchType.MinimalCriteriaSearch, ParallelOptions);

            // Create navigator genome evaluator
            IGenomeEvaluator<NeatGenome> navigatorFitnessEvaluator =
                new ParallelGenomeBehaviorEvaluator<NeatGenome, IBlackBox>(navigatorGenomeDecoder, navigatorEvaluator,
                    SelectionType.Queueing, SearchType.MinimalCriteriaSearch, ParallelOptions);

            // Create the coevolution container
            ICoevolutionAlgorithmContainer<NeatGenome, MazeGenome> coevolutionAlgorithmContainer =
                new CoevolutionAlgorithmContainer<NeatGenome, MazeGenome>(neatEvolutionAlgorithm, mazeEvolutionAlgorithm);

            // Initialize the container and component algorithms
            coevolutionAlgorithmContainer.Initialize(navigatorFitnessEvaluator, genomeFactory1, seedAgentPopulation,
                AgentDefaultPopulationSize, mazeFitnessEvaluator, genomeFactory2, genomeList2, MazeDefaultPopulationSize,
                MaxGenerations, MaxEvaluations);

            return coevolutionAlgorithmContainer;
        }
        public void VerifyBootstrappedStateTest()
        {
            const string parentDirectory =
                "F:/User Data/Jonathan/Documents/school/Jonathan/Graduate/PhD/Development/C# NEAT/SharpNoveltyNeat/SharpNeatConsole/bin/Debug/";
            const string agentGenomeFile = "ViableSeedGenomes.xml";
            const string baseBitmapFilename = "AgentTrajectory";
            const int mazeHeight = 20;
            const int mazeWidth = 20;
            const int scaleMultiplier = 16;
            const int maxTimesteps = 400;
            const int minSuccessDistance = 5;

            // Setup stuff for the navigators
            List<NeatGenome> agentGenomes;
            NeatGenomeDecoder agentGenomeDecoder = new NeatGenomeDecoder(NetworkActivationScheme.CreateAcyclicScheme());
            NeatGenomeFactory agentGenomeFactory = new NeatGenomeFactory(10, 2);

            // Create new minimal maze (no barriers)
            MazeStructure mazeStructure = new MazeDecoder(mazeHeight, mazeWidth, scaleMultiplier).Decode(
                new MazeGenomeFactory(null, null, null).CreateGenome(0));

            // Create behavior characterization factory
            IBehaviorCharacterizationFactory behaviorCharacterizationFactory =
                new TrajectoryBehaviorCharacterizationFactory(null);

            // Create evaluator
            MazeNavigatorMCSEvaluator mazeNavigatorEvaluator = new MazeNavigatorMCSEvaluator(maxTimesteps,
                minSuccessDistance, behaviorCharacterizationFactory, 1);

            // Set maze within evaluator
            mazeNavigatorEvaluator.UpdateEvaluatorPhenotypes(new List<MazeStructure> {mazeStructure});

            // Read in agents
            using (XmlReader xr = XmlReader.Create(parentDirectory + agentGenomeFile))
            {
                agentGenomes = NeatGenomeXmlIO.ReadCompleteGenomeList(xr, false, agentGenomeFactory);
            }

            // Decode agent genomes to phenotype and run simulation
            for (int i = 0; i < agentGenomes.Count; i++)
            {
                // Decode navigator genome
                IBlackBox agentPhenome = agentGenomeDecoder.Decode(agentGenomes[i]);

                // Run simulation
                BehaviorInfo behaviorInfo = mazeNavigatorEvaluator.Evaluate(agentPhenome, 0, false, null, null);

                // Print the navigator trajectory through the maze
                DomainTestUtils.PrintMazeAndTrajectory(mazeStructure, behaviorInfo.Behaviors,
                    string.Format("{0}_{1}.bmp", baseBitmapFilename, i));
            }
        }