Exemplo n.º 1
0
        /// <summary>
        ///     The map evaluator constructor.
        /// </summary>
        /// <param name="experimentParameters">The experiment definition and control parameters.</param>
        /// <param name="agentInputNeuronCount">The number of input neurons in the agent neural controller.</param>
        /// <param name="agentOutputNeuronCount">The number of output neurons in the agent neural controller.</param>
        public MapEvaluator(ExperimentParameters experimentParameters, int agentInputNeuronCount,
                            int agentOutputNeuronCount)
        {
            // Create the NEAT genome (agent) decoder - acyclic activation is always used
            _agentDecoder = new NeatGenomeDecoder(CreateActivationScheme(experimentParameters.ActivationScheme,
                                                                         experimentParameters.ActivationIters, experimentParameters.ActivationDeltaThreshold));

            // Create the maze decoder
            _mazeDecoder = new MazeDecoder(experimentParameters.MazeScaleMultiplier);

            // Initialize evaluation units
            EvaluationUnits = new List <MazeNavigatorEvaluationUnit>();

            // Create maze factory with default dimensions (NEAT factory will be set later based on structure of first
            // genome encountered)
            _mazeGenomeFactory = new MazeGenomeFactory(experimentParameters.MazeHeight, experimentParameters.MazeWidth,
                                                       experimentParameters.MazeQuadrantHeight, experimentParameters.MazeQuadrantWidth);
            _neatGenomeFactory = new NeatGenomeFactory(agentInputNeuronCount, agentOutputNeuronCount);

            // Set experiment parameters
            _experimentParameters = experimentParameters;

            // Create new agent ID list and maze ID/structure map
            _agentGenomeIds     = new List <int>();
            _mazeIdStructureMap = new Dictionary <int, MazeStructure>();
        }
Exemplo n.º 2
0
        /// <summary>
        ///     Generates the specified number of maze genomes with the specified complexity (i.e. number of interior partitions).
        /// </summary>
        /// <param name="numMazeGenomes">The number of maze genomes to generate.</param>
        /// <param name="numPartitions">The number of initial partitions (the starting complexity of the genome).</param>
        /// <param name="mazeGenomeFactory">Reference to the maze genome factory.</param>
        /// <returns></returns>
        public static List <MazeGenome> GenerateMazeGenomes(int numMazeGenomes, int numPartitions,
                                                            MazeGenomeFactory mazeGenomeFactory)
        {
            var mazeGenomes = new List <MazeGenome>(numMazeGenomes);
            var rand        = RandomDefaults.CreateRandomSource();

            for (var curMazeCnt = 0; curMazeCnt < numMazeGenomes; curMazeCnt++)
            {
                // Reset innovation IDs
                mazeGenomeFactory.InnovationIdGenerator.Reset();

                // Create a new genome and pass in the requisite factory
                var mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0);

                // Create the specified number of interior partitions (i.e. maze genes)
                for (var cnt = 0; cnt < numPartitions; cnt++)
                {
                    // Create new maze gene and add to genome
                    mazeGenome.WallGeneList.Add(new WallGene(mazeGenomeFactory.InnovationIdGenerator.NextId,
                                                             rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5));
                }

                mazeGenomes.Add(mazeGenome);
            }

            return(mazeGenomes);
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Reads a list of maze genomes from an XML file.
        /// </summary>
        /// <param name="xr">Reference to the XmlReader.</param>
        /// <param name="genomeFactory">A MazeGenomeFactory to construct genomes against.</param>
        /// <returns>Instantiated list of maze genomes.</returns>
        public static List<MazeGenome> ReadCompleteGenomeList(XmlReader xr, MazeGenomeFactory genomeFactory)
        {
            // Find <Root>
            XmlIoUtils.MoveToElement(xr, false, __ElemRoot);

            // Find <Mazes>
            XmlIoUtils.MoveToElement(xr, true, __ElemMazes);

            // Read mazes
            List<MazeGenome> genomeList = new List<MazeGenome>();
            using (XmlReader xrSubtree = xr.ReadSubtree())
            {
                // Re-scan for the root <Mazes> element
                XmlIoUtils.MoveToElement(xrSubtree, false);

                // Move to first Maze element
                XmlIoUtils.MoveToElement(xrSubtree, true, __ElemMaze);

                // Read maze elements
                do
                {
                    MazeGenome genome = ReadGenome(xrSubtree);
                    genomeList.Add(genome);
                } while (xrSubtree.ReadToNextSibling(__ElemMaze));
            }

            // Check for empty list
            if (genomeList.Count == 0)
            {
                return genomeList;
            }

            // Determine the max genome ID
            uint maxGenomeId = genomeList.Aggregate<MazeGenome, uint>(0,
                (current, genome) => Math.Max(current, genome.Id));

            // Determine the max gene innovation ID
            uint maxInnovationId = genomeList.Aggregate<MazeGenome, uint>(0,
                (curMaxPopulationInnovationId, genome) =>
                    genome.GeneList.Aggregate(curMaxPopulationInnovationId,
                        (curMaxGenomeInnovationId, mazeGene) =>
                            Math.Max(curMaxGenomeInnovationId, mazeGene.InnovationId)));

            // Set the genome factory ID generator and innovation ID generator to one more than the max
            genomeFactory.GenomeIdGenerator.Reset(Math.Max(genomeFactory.GenomeIdGenerator.Peek, maxGenomeId + 1));
            genomeFactory.InnovationIdGenerator.Reset(Math.Max(genomeFactory.InnovationIdGenerator.Peek,
                maxInnovationId + 1));

            // Retrospecitively assign the genome factory to the genomes
            foreach (MazeGenome genome in genomeList)
            {
                genome.GenomeFactory = genomeFactory;
            }

            return genomeList;
        }
        /// <inheritdoc />
        /// <summary>
        ///     Creates the MCC algorithm container using the given agent and maze population sizes.
        /// </summary>
        /// <param name="populationSize1">The agent population size.</param>
        /// <param name="populationSize2">The maze population size.</param>
        /// <returns>The instantiated MCC algorithm container.</returns>
        public override IMCCAlgorithmContainer <NeatGenome, MazeGenome> CreateMCCAlgorithmContainer(
            int populationSize1, int populationSize2)
        {
            // Create a genome factory for the NEAT genomes
            IGenomeFactory <NeatGenome> neatGenomeFactory = new NeatGenomeFactory(AnnInputCount, AnnOutputCount,
                                                                                  NeatGenomeParameters);

            // Create a genome factory for the maze genomes
            IGenomeFactory <MazeGenome> mazeGenomeFactory = new MazeGenomeFactory(MazeGenomeParameters, MazeHeight,
                                                                                  MazeWidth, MazeQuadrantHeight, MazeQuadrantWidth);

            // Create an initial population of maze navigators
            var neatGenomeList = neatGenomeFactory.CreateGenomeList(populationSize1, 0);

            // Create an initial population of mazes
            // NOTE: the population is set to 1 here because we're just starting with a single, completely open maze space
            var mazeGenomeList = mazeGenomeFactory.CreateGenomeList(populationSize2, 0);

            // Create the evolution algorithm container
            return(CreateMCCAlgorithmContainer(neatGenomeFactory, mazeGenomeFactory, neatGenomeList,
                                               mazeGenomeList, false));
        }
Exemplo n.º 5
0
        /// <summary>
        ///     Reads in seed maze genomes used to bootstrap MCC experiments.
        /// </summary>
        /// <param name="seedMazePath">
        ///     The path of the single maze genome or a directory containing multiple XML genome
        ///     definitions.
        /// </param>
        /// <param name="mazeGenomeFactory">The maze genome factory to assign to each genome.</param>
        /// <returns>The list of seed maze genomes.</returns>
        public static IEnumerable <MazeGenome> ReadSeedMazeGenomes(string seedMazePath,
                                                                   MazeGenomeFactory mazeGenomeFactory)
        {
            var mazeGenomes = new List <MazeGenome>();

            // Get the maze genome files in the given path
            var mazeGenomeFiles = GetGenomeFiles(seedMazePath);

            // Read in all maze genomes and add them to the list
            foreach (var mazeGenomeFile in mazeGenomeFiles)
            {
                using (var xr = XmlReader.Create(mazeGenomeFile))
                {
                    // Read in the maze genomes
                    var curMazeGenomes = MazeGenomeXmlIO.ReadCompleteGenomeList(xr, mazeGenomeFactory);

                    // Add the genomes to the overall genome list
                    mazeGenomes.AddRange(curMazeGenomes);
                }
            }

            return(mazeGenomes);
        }
        /// <summary>
        ///     Handles the process of rendering a bitmap file of an existing maze genome.
        /// </summary>
        private static void HandleMazeImageReproduction()
        {
            MazeGenome mazeGenome = null;

            // Get the maze genome file path and image output path
            string mazeGenomeFile  = _executionConfiguration[ExecutionParameter.MazeGenomeFile];
            string imageOutputPath = _executionConfiguration[ExecutionParameter.BitmapOutputBaseDirectory];

            // Create a new (mostly dummy) maze genome factory
            MazeGenomeFactory mazeGenomeFactory = new MazeGenomeFactory();

            // Read in the genome
            using (XmlReader xr = XmlReader.Create(mazeGenomeFile))
            {
                mazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xr, mazeGenomeFactory);
            }

            // Get the maze genome ID
            uint mazeGenomeId = mazeGenome.Id;

            // Render the maze phenotype (i.e. the graphical structure0 and print to a bitmap file
            PrintMazeToFile(mazeGenome,
                            Path.Combine(imageOutputPath, string.Format("EvolvedMaze_ID_{0}.bmp", mazeGenomeId)));
        }
        /// <summary>
        ///     Handles the process of generating maze genomes and rendering bitmap files of their structure.
        /// </summary>
        private static void HandleMazeGeneration()
        {
            IRandomSource rand = RandomDefaults.CreateRandomSource();

            // Get the evolved maze height and width
            int mazeHeight         = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeHeight]);
            int mazeWidth          = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeWidth]);
            int mazeQuadrantHeight = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeQuadrantHeight]);
            int mazeQuadrantWidth  = Int32.Parse(_executionConfiguration[ExecutionParameter.MazeQuadrantWidth]);

            // Get the number of interior walls and maze genome output directory
            int    numWaypoints              = Int32.Parse(_executionConfiguration[ExecutionParameter.NumWaypoints]);
            int    numInteriorWalls          = Int32.Parse(_executionConfiguration[ExecutionParameter.NumWalls]);
            string mazeGenomeOutputDirectory = _executionConfiguration[ExecutionParameter.MazeGenomeOutputBaseDirectory];

            // Get the number of sample mazes to generate (or just 1 maze if not specified)
            int numMazes = _executionConfiguration.ContainsKey(ExecutionParameter.NumMazes)
                ? Int32.Parse(_executionConfiguration[ExecutionParameter.NumMazes])
                : 1;

            // Get whether images are being generated for the sample mazes
            bool generateMazeImages = _executionConfiguration.ContainsKey(ExecutionParameter.OutputMazeBitmap) &&
                                      Boolean.Parse(_executionConfiguration[ExecutionParameter.OutputMazeBitmap]);

            // Get whether maze genomes are being serialized to the same file (defaults to false)
            bool isSingleOutputFile = _executionConfiguration.ContainsKey(ExecutionParameter.SingleGenomeOutputFile) &&
                                      Boolean.Parse(_executionConfiguration[ExecutionParameter.SingleGenomeOutputFile]);

            // Create a new maze genome factory
            MazeGenomeFactory mazeGenomeFactory =
                new MazeGenomeFactory(mazeHeight, mazeWidth, mazeQuadrantHeight, mazeQuadrantWidth);

            // Instantiate list to hold generated maze genomes
            // (only really used when we're writing everything out to one file)
            List <MazeGenome> mazeGenomeList = new List <MazeGenome>(numMazes);

            for (int curMazeCnt = 0; curMazeCnt < numMazes; curMazeCnt++)
            {
                MazeGenome mazeGenome;

                // Lay out the base file name
                string fileBaseName =
                    string.Format("GeneratedMazeGenome_{0}_Height_{1}_Width_{2}_Waypoints_{3}_Walls_{4}", mazeHeight,
                                  mazeWidth, numWaypoints, numInteriorWalls, curMazeCnt);

                // With a single output file, the genomes are likely being used for separate experiments, so we
                // reset the innovation IDs and assign the maze a constant identifier
                if (isSingleOutputFile == false)
                {
                    // Reset innovation IDs
                    mazeGenomeFactory.InnovationIdGenerator.Reset();

                    // Create a new genome and pass in the requisite factory
                    mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0);
                }
                // Otherwise, we leave the innovation ID generator alone and create a new maze genome with
                // an identifier that's incremented by one
                else
                {
                    mazeGenome = new MazeGenome(mazeGenomeFactory, (uint)curMazeCnt, 0);
                }

                // Add the specified number of waypoints (less one because center waypoint is created on maze initialization)
                for (int cnt = 0; cnt < numWaypoints - 1; cnt++)
                {
                    Point2DInt waypoint;

                    // Randomly select an orientation
                    IntersectionOrientation newPointOrientation = mazeGenomeFactory.Rng.NextBool()
                        ? IntersectionOrientation.Horizontal
                        : IntersectionOrientation.Vertical;

                    // Iterate until we get a waypoint that's valid
                    do
                    {
                        waypoint = new Point2DInt(mazeGenomeFactory.Rng.Next(mazeGenome.MazeBoundaryWidth - 1),
                                                  mazeGenomeFactory.Rng.Next(mazeGenome.MazeBoundaryHeight - 1));
                    } while (
                        MazeUtils.IsValidWaypointLocation(mazeGenome, waypoint, UInt32.MaxValue, newPointOrientation) ==
                        false);

                    mazeGenome.PathGeneList.Add(new PathGene(mazeGenomeFactory.InnovationIdGenerator.NextId, waypoint,
                                                             newPointOrientation));
                }

                // Create the specified number of interior walls (i.e. maze genes)
                for (int cnt = 0; cnt < numInteriorWalls; cnt++)
                {
                    // Create new maze gene and add to genome
                    mazeGenome.WallGeneList.Add(new WallGene(mazeGenomeFactory.InnovationIdGenerator.NextId,
                                                             rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5));
                }

                // Only serialize genomes to separate files if single output file option is turned off
                if (isSingleOutputFile == false)
                {
                    // Serialize the genome to XML
                    using (
                        XmlWriter xmlWriter =
                            XmlWriter.Create(
                                Path.Combine(mazeGenomeOutputDirectory, string.Format("{0}.xml", fileBaseName)),
                                new XmlWriterSettings {
                        Indent = true
                    }))
                    {
                        // Get genome XML
                        MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenome);
                    }
                }
                // Otherwise, just add genome to list to be serialized to single file in bulk
                else
                {
                    mazeGenomeList.Add(mazeGenome);
                }

                // Print the maze to a bitmap file if that option has been specified
                if (generateMazeImages)
                {
                    PrintMazeToFile(mazeGenome, string.Format("{0}_Structure.bmp", fileBaseName));
                }
            }

            // If serialize to single output file is turned off, go ahead and write everything out to the file
            if (isSingleOutputFile)
            {
                // Serialize all genomes to XML
                using (
                    XmlWriter xmlWriter =
                        XmlWriter.Create(Path.Combine(mazeGenomeOutputDirectory,
                                                      string.Format("GeneratedMaze_{0}_Genomes_{1}_Height_{2}_Width_{3}_Waypoints_{4}_Walls.xml",
                                                                    numMazes,
                                                                    mazeHeight, mazeWidth, numWaypoints, numInteriorWalls))))
                {
                    MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenomeList);
                }
            }
        }
Exemplo n.º 8
0
        /// <summary>
        ///     The map evaluator constructor.
        /// </summary>
        /// <param name="experimentParameters">The experiment definition and control parameters.</param>
        /// <param name="agentInputNeuronCount">The number of input neurons in the agent neural controller.</param>
        /// <param name="agentOutputNeuronCount">The number of output neurons in the agent neural controller.</param>
        public MapEvaluator(ExperimentParameters experimentParameters, int agentInputNeuronCount,
            int agentOutputNeuronCount)
        {
            // Create the NEAT genome (agent) decoder - acyclic activation is always used
            _agentDecoder = new NeatGenomeDecoder(NetworkActivationScheme.CreateAcyclicScheme());

            // Create the maze decoder
            _mazeDecoder = new MazeDecoder(experimentParameters.MazeHeight, experimentParameters.MazeWidth,
                experimentParameters.MazeScaleMultiplier);

            // Initialize evaluation units
            EvaluationUnits = new List<MazeNavigatorEvaluationUnit>();

            // Create default maze factory (NEAT factory will be set later based on structure of first genome encountered)
            _mazeGenomeFactory = new MazeGenomeFactory();
            _neatGenomeFactory = new NeatGenomeFactory(agentInputNeuronCount, agentOutputNeuronCount);

            // Set experiment parameters
            _experimentParameters = experimentParameters;

            // Create new agent ID list and maze ID/structure map
            _agentGenomeIds = new List<int>();
            _mazeIdStructureMap = new Dictionary<int, MazeStructure>();
        }
        /// <summary>
        ///     Handles per-batch comparison of coevolution-generated mazes on a reference algorithm (e.g. novelty search).
        /// </summary>
        /// <param name="batchesWithGenomeData">List of the batches that contain maze genome data.</param>
        /// <param name="curCoevoExperimentId">Identifier of the coevolution experiment.</param>
        /// <param name="curCoevoExperimentName">Name of the coevolution experiment.</param>
        /// <param name="curRun">The current run.</param>
        /// <param name="numRuns">The total number of runs in the experiment.</param>
        /// <param name="mazeDecoder">Reference to the maze genome decoder.</param>
        /// <param name="noveltySearchExperimentConfig">The experiment configuration for the reference (novelty search) experiment.</param>
        private static void RunPerBatchComparativeAnalysis(IList<int> batchesWithGenomeData,
            int curCoevoExperimentId, string curCoevoExperimentName, int curRun, int numRuns, MazeDecoder mazeDecoder,
            ExperimentDictionary noveltySearchExperimentConfig)
        {
            // Declare list to hold maze IDs that have already been evaluated using the comparison algorithm
            List<int> evaluatedMazeGenomeIds = new List<int>();

            // Get the total number of initialization evaluations for the current run
            int coEvoInitEvaluations = ExperimentDataHandler.GetInitializationEvaluationsForRun(curCoevoExperimentId,
                curRun);

            // Iterate through each batch and run comparative algorithm on each maze
            foreach (int curBatch in batchesWithGenomeData)
            {
                _executionLogger.Info(string.Format("Executing comparative analysis for batch [{0}] of run [{1}/{2}]",
                    curBatch, curRun, numRuns));

                // Get list of all extant maze genomes for this batch
                IList<string> mazeGenomeXml = ExperimentDataHandler.GetMazeGenomeXml(curCoevoExperimentId, curRun,
                    curBatch);

                foreach (string genomeXml in mazeGenomeXml)
                {
                    MazeStructure curMazeStructure = null;
                    MazeGenome curMazeGenome = null;

                    // Create a new (mostly dummy) maze genome factory
                    MazeGenomeFactory curMazeGenomeFactory = new MazeGenomeFactory();

                    // Convert each genome string to an equivalent genome object
                    using (XmlReader xr = XmlReader.Create(new StringReader(genomeXml)))
                    {
                        curMazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xr, curMazeGenomeFactory);
                    }

                    // If the maze has already been processed, continue on to the next one
                    // (also exclude the initialization maze as a special case)
                    if (evaluatedMazeGenomeIds.Contains((int) curMazeGenome.BirthGeneration) ||
                        curMazeGenome.BirthGeneration == 0)
                    {
                        continue;
                    }

                    // Get the total number of evaluations required to solve this maze
                    // (this amounts to the total number of evaluations from both queues at the time of maze birth)
                    int coEvoTotalEvaluations = coEvoInitEvaluations +
                                                ExperimentDataHandler.GetTotalPrimaryEvaluationsAtBatch(
                                                    curCoevoExperimentId, curRun, (int) curMazeGenome.BirthGeneration);

                    // Decode the maze structure
                    curMazeStructure =
                        mazeDecoder.Decode(curMazeGenome);

                    // Instantiate new novelty search experiment for the current experiment/batch/maze
                    NoveltySearchRunner nsRunner = new NoveltySearchRunner(noveltySearchExperimentConfig,
                        curCoevoExperimentName, curMazeStructure, curRun, numRuns, _executionLogger);

                    _executionLogger.Info(string.Format(
                        "Executing novelty search on maze [{0}] with birth batch [{1}]", curMazeGenome.Id,
                        curMazeGenome.BirthGeneration));

                    // Run novelty search on that maze until the maze is solved or the max evals have been reached
                    INeatEvolutionAlgorithm<NeatGenome> eaFinalState = nsRunner.RunNoveltySearch();

                    // Write comparison results to output file
                    ExperimentDataHandler.WriteNoveltySearchComparisonResults(curCoevoExperimentId,
                        noveltySearchExperimentConfig.ExperimentDictionaryID, curRun, curBatch,
                        (int) curMazeGenome.Id, (int) curMazeGenome.BirthGeneration,
                        (int) eaFinalState.Statistics._minComplexity,
                        (int) eaFinalState.Statistics._maxComplexity, eaFinalState.Statistics._meanComplexity,
                        coEvoTotalEvaluations, (int) eaFinalState.CurrentEvaluations,
                        !((int) eaFinalState.CurrentEvaluations >= noveltySearchExperimentConfig.MaxEvaluations), false);

                    // Add maze genome ID to the list of processed mazes to its not considered for evaluation again
                    evaluatedMazeGenomeIds.Add((int) curMazeGenome.Id);
                }
            }
        }
        /// <summary>
        ///     Handles the process of rendering a bitmap file of an existing maze genome.
        /// </summary>
        private static void HandleMazeImageReproduction()
        {
            MazeGenome mazeGenome = null;

            // Get the maze genome file path and image output path
            string mazeGenomeFile = _executionConfiguration[ExecutionParameter.MazeGenomeFile];
            string imageOutputPath = _executionConfiguration[ExecutionParameter.BitmapOutputBaseDirectory];

            // Create a new (mostly dummy) maze genome factory
            MazeGenomeFactory mazeGenomeFactory = new MazeGenomeFactory();

            // Read in the genome
            using (XmlReader xr = XmlReader.Create(mazeGenomeFile))
            {
                mazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xr, mazeGenomeFactory);
            }

            // Get the maze genome ID
            uint mazeGenomeId = mazeGenome.Id;

            // Render the maze phenotype (i.e. the graphical structure0 and print to a bitmap file
            PrintMazeToFile(mazeGenome,
                Path.Combine(imageOutputPath, string.Format("EvolvedMaze_ID_{0}.bmp", mazeGenomeId)));
        }
        /// <summary>
        ///     Computes the natural clustering of the maze genomes along with their respective entropy.
        /// </summary>
        /// <param name="mazeGenomeListXml">The list of serialized maze genome XML.</param>
        /// <param name="isGreedySilhouetteCalculation">
        ///     Dictates whether optimal clustering is based on number of clusters that
        ///     maximize silhouette score until the first decrease in score (true), or based on the silhouette score calculated for
        ///     a range of clusters with the number of clusters resulting in the maximum score used as the optimal number of
        ///     clusters (false).
        /// </param>
        /// <param name="clusterRange">The range of clusters values for which to compute the silhouette width (optional).</param>
        /// <returns>The cluster diversity unit for maze genomes.</returns>
        public static ClusterDiversityUnit CalculateMazeClustering(IList <string> mazeGenomeListXml,
                                                                   bool isGreedySilhouetteCalculation, int clusterRange = 0)
        {
            // Always start with one cluster
            const int initClusterCnt = 1;

            // Initialize list of maze genome objects
            var mazeGenomes = new List <MazeGenome>(mazeGenomeListXml.Count());

            // Convert all maze genome XML strings to maze genome objects
            foreach (var genomeXml in mazeGenomeListXml)
            {
                MazeGenome curMazeGenome;

                // Create a new, dummy maze genome factory
                var tempMazeGenomeFactory = new MazeGenomeFactory();

                // Convert genome XML to genome object
                using (var xr = XmlReader.Create(new StringReader(genomeXml)))
                {
                    curMazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xr, tempMazeGenomeFactory);
                }

                // Add to the genome object list
                mazeGenomes.Add(curMazeGenome);
            }

            // Define observation matrix in which to store all gene coordinate vectors for each maze
            var observationMatrix = new double[mazeGenomes.Count()][];

            // Get the maximum observation vector length (max number of maze genes)
            var maxObservationLength = mazeGenomes.Max(g => g.WallGeneList.Count());

            for (var idx = 0; idx < mazeGenomes.Count(); idx++)
            {
                // If there are more observations than the total elements in the observation vector,
                // zero out the rest of the vector
                if (mazeGenomes[idx].WallGeneList.Count() < maxObservationLength)
                {
                    observationMatrix[idx] =
                        mazeGenomes[idx].Position.CoordArray.Select(ca => ca.Value)
                        .Concat(Enumerable.Repeat(0.0,
                                                  maxObservationLength - mazeGenomes[idx].Position.CoordArray.Length))
                        .ToArray();
                }
                // Otherwise, if the observation and vector length are the same, just set the elements
                else
                {
                    observationMatrix[idx] = mazeGenomes[idx].Position.CoordArray.Select(ca => ca.Value).ToArray();
                }
            }

            // Determine the optimal number of clusters to fit these data
            var optimalClustering = DetermineOptimalClusters(observationMatrix, initClusterCnt, false,
                                                             isGreedySilhouetteCalculation, clusterRange);

            // Compute shannon entropy given optimal clustering
            var shannonEntropy = ComputeShannonEntropy(optimalClustering);

            // Compute the silhouette width given optimal clustering
            var silhouetteWidth = ComputeSilhouetteWidth(optimalClustering.Clusters, observationMatrix, false);

            // Return the resulting maze genome cluster diversity info
            return(new ClusterDiversityUnit(optimalClustering.Clusters.Count, silhouetteWidth, shannonEntropy));
        }
Exemplo n.º 12
0
        /// <summary>
        ///     Reads in seed maze genomes used to bootstrap coevolutionary experiments.
        /// </summary>
        /// <param name="seedMazePath">
        ///     The path of the single maze genome or a directory containing multiple XML genome
        ///     definitions.
        /// </param>
        /// <param name="mazeGenomeFactory">The maze genome factory to assign to each genome.</param>
        /// <returns>The list of seed maze genomes.</returns>
        public static List<MazeGenome> ReadSeedMazeGenomes(string seedMazePath, MazeGenomeFactory mazeGenomeFactory)
        {
            string[] mazeGenomeFiles;
            List<MazeGenome> mazeGenomes = new List<MazeGenome>();

            // Get the attributes of the given path/file
            FileAttributes fileAttributes = File.GetAttributes(seedMazePath);

            // Determine whether this is a directory or a file
            if ((fileAttributes & FileAttributes.Directory) == FileAttributes.Directory)
            {
                // Get all of the genome files in the directory
                mazeGenomeFiles = Directory.GetFiles(seedMazePath, "*.xml");
            }
            else
            {
                // There's only one file, so make array length 1 and add that file
                mazeGenomeFiles = new string[1];
                mazeGenomeFiles[0] = seedMazePath;
            }

            // Read in all maze genomes and add them to the list
            foreach (string mazeGenomeFile in mazeGenomeFiles)
            {
                using (XmlReader xr = XmlReader.Create(mazeGenomeFile))
                {
                    // Read in the maze genomes
                    List<MazeGenome> curMazeGenomes = MazeGenomeXmlIO.ReadCompleteGenomeList(xr, mazeGenomeFactory);

                    // Assign the genome factory
                    foreach (MazeGenome curMazeGenome in curMazeGenomes)
                    {
                        curMazeGenome.GenomeFactory = mazeGenomeFactory;
                    }

                    // Add the genomes to the overall genome list
                    mazeGenomes.AddRange(curMazeGenomes);
                }
            }

            return mazeGenomes;
        }
Exemplo n.º 13
0
        /// <summary>
        ///     Generates the specified number of maze genomes with the specified complexity (i.e. number of interior partitions).
        /// </summary>
        /// <param name="numMazeGenomes">The number of maze genomes to generate.</param>
        /// <param name="numPartitions">The number of initial partitions (the starting complexity of the genome).</param>
        /// <param name="mazeGenomeFactory">Reference to the maze genome factory.</param>
        /// <returns></returns>
        public static List<MazeGenome> GenerateMazeGenomes(int numMazeGenomes, int numPartitions,
            MazeGenomeFactory mazeGenomeFactory)
        {
            List<MazeGenome> mazeGenomes = new List<MazeGenome>(numMazeGenomes);
            Random rand = new Random();

            for (int curMazeCnt = 0; curMazeCnt < numMazeGenomes; curMazeCnt++)
            {
                // Reset innovation IDs
                mazeGenomeFactory.InnovationIdGenerator.Reset();

                // Create a new genome and pass in the requisite factory
                MazeGenome mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0);

                // Create the specified number of interior partitions (i.e. maze genes)
                for (int cnt = 0; cnt < numPartitions; cnt++)
                {
                    // Create new maze gene and add to genome
                    mazeGenome.GeneList.Add(new MazeGene(mazeGenomeFactory.InnovationIdGenerator.NextId,
                        rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5));
                }

                mazeGenomes.Add(mazeGenome);
            }

            return mazeGenomes;
        }
        /// <summary>
        ///     Creates the coevolution algorithm container using the given agent and maze population sizes.
        /// </summary>
        /// <param name="populationSize1">The agent population size.</param>
        /// <param name="populationSize2">The maze population size.</param>
        /// <returns>The instantiated coevolution algorithm container.</returns>
        public override ICoevolutionAlgorithmContainer<NeatGenome, MazeGenome> CreateCoevolutionAlgorithmContainer(
            int populationSize1, int populationSize2)
        {
            // Create a genome factory for the NEAT genomes
            IGenomeFactory<NeatGenome> neatGenomeFactory = new NeatGenomeFactory(AnnInputCount, AnnOutputCount,
                NeatGenomeParameters);

            // Create a genome factory for the maze genomes
            IGenomeFactory<MazeGenome> mazeGenomeFactory = new MazeGenomeFactory(MazeGenomeParameters, _mazeHeight,
                _mazeWidth);

            // Create an initial population of maze navigators
            List<NeatGenome> neatGenomeList = neatGenomeFactory.CreateGenomeList(populationSize1, 0);

            // Create an initial population of mazes
            // NOTE: the population is set to 1 here because we're just starting with a single, completely open maze space
            List<MazeGenome> mazeGenomeList = mazeGenomeFactory.CreateGenomeList(populationSize2, 0);

            // Create the evolution algorithm container
            return CreateCoevolutionAlgorithmContainer(neatGenomeFactory, mazeGenomeFactory, neatGenomeList,
                mazeGenomeList);
        }
        /// <summary>
        ///     Handles the process of generating maze genomes and rendering bitmap files of their structure.
        /// </summary>
        private static void HandleMazeGeneration()
        {
            Random rand = new Random();

            // Get the number of interior walls and maze genome output directory
            int numInteriorWalls = Int32.Parse(_executionConfiguration[ExecutionParameter.NumWalls]);
            string mazeGenomeOutputDirectory = _executionConfiguration[ExecutionParameter.MazeGenomeOutputBaseDirectory];

            // Get the number of sample mazes to generate (or just 1 maze if not specified)
            int numMazes = _executionConfiguration.ContainsKey(ExecutionParameter.NumMazes)
                ? Int32.Parse(_executionConfiguration[ExecutionParameter.NumMazes])
                : 1;

            // Get whether images are being generated for the sample mazes
            bool generateMazeImages = _executionConfiguration.ContainsKey(ExecutionParameter.OutputMazeBitmap) &&
                                      Boolean.Parse(_executionConfiguration[ExecutionParameter.OutputMazeBitmap]);

            // Get whether maze genomes are being serialized to the same file (defaults to false)
            bool isSingleOutputFile = _executionConfiguration.ContainsKey(ExecutionParameter.SingleGenomeOutputFile) &&
                                      Boolean.Parse(_executionConfiguration[ExecutionParameter.SingleGenomeOutputFile]);

            // Create a new maze genome factory
            MazeGenomeFactory mazeGenomeFactory = new MazeGenomeFactory();

            // Instantiate list to hold generated maze genomes
            // (only really used when we're writing everything out to one file)
            List<MazeGenome> mazeGenomeList = new List<MazeGenome>(numMazes);

            for (int curMazeCnt = 0; curMazeCnt < numMazes; curMazeCnt++)
            {
                MazeGenome mazeGenome = null;

                // Lay out the base file name
                string fileBaseName = string.Format("GeneratedMazeGenome_{0}_Walls_{1}", numInteriorWalls, curMazeCnt);

                // With a single output file, the genomes are likely being used for separate experiments, so we
                // reset the innovation IDs and assign the maze a constant identifier
                if (isSingleOutputFile == false)
                {
                    // Reset innovation IDs
                    mazeGenomeFactory.InnovationIdGenerator.Reset();

                    // Create a new genome and pass in the requisite factory
                    mazeGenome = new MazeGenome(mazeGenomeFactory, 0, 0);
                }
                // Otherwise, we leave the innovation ID generator along and create a new maze genome with
                // an identifier that's incremented by one
                else
                {
                    mazeGenome = new MazeGenome(mazeGenomeFactory, (uint) curMazeCnt, 0);
                }

                // Create the specified number of interior walls (i.e. maze genes)
                for (int cnt = 0; cnt < numInteriorWalls; cnt++)
                {
                    // Create new maze gene and add to genome
                    mazeGenome?.GeneList.Add(new MazeGene(mazeGenomeFactory.InnovationIdGenerator.NextId,
                        rand.NextDouble(), rand.NextDouble(), rand.NextDouble() < 0.5));
                }

                // Only serialize genomes to separate files if single output file option is turned off
                if (isSingleOutputFile == false)
                {
                    // Serialize the genome to XML
                    using (
                        XmlWriter xmlWriter =
                            XmlWriter.Create(
                                Path.Combine(mazeGenomeOutputDirectory, string.Format("{0}.xml", fileBaseName)),
                                new XmlWriterSettings {Indent = true}))
                    {
                        // Get genome XML
                        MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenome);
                    }
                }
                // Otherwise, just add genome to list to be serialized to single file in bulk
                else
                {
                    mazeGenomeList.Add(mazeGenome);
                }

                // Print the maze to a bitmap file if that option has been specified
                if (generateMazeImages)
                {
                    PrintMazeToFile(mazeGenome, string.Format("{0}_Structure.bmp", fileBaseName));
                }
            }

            // If serialize to single output file is turned off, go ahead and write everything out to the file
            if (isSingleOutputFile)
            {
                // Serialize all genomes to XML
                using (
                    XmlWriter xmlWriter =
                        XmlWriter.Create(Path.Combine(mazeGenomeOutputDirectory,
                            string.Format("GeneratedMaze_{0}_Genomes_{1}_Walls.xml", numMazes, numInteriorWalls))))
                {
                    MazeGenomeXmlIO.WriteComplete(xmlWriter, mazeGenomeList);
                }
            }
        }
        private static void Main(string[] args)
        {
            // TODO: Refactor all of this to be more configurable - just hard-coding everything now to get results

            // Base path for maze bitmap output
            string mazeImageBase =
                @"F:\User Data\Jonathan\Documents\school\Jonathan\Graduate\PhD\Minimal Criteria Search\Analysis\Coevolution MCS\Images\Final Batch Mazes";

            // These are the experiments for which we want to get mazes in the final population
            List<string> experimentNames = new List<string>
            {
                "Coevolution MCS with Maze Initialization 9",
                "Coevolution MCS with Maze Initialization 10",
                "Coevolution MCS with Maze Initialization 11",
                "Coevolution MCS with Maze Initialization 12",
                "Coevolution MCS with Maze Initialization 13",
                "Coevolution MCS with Maze Initialization 14",
                "Coevolution MCS with Maze Initialization 15",
                "Coevolution MCS with Maze Initialization 16"
            };

            // Setup maze decoder with hard-coded height/width and scale multiplier
            MazeDecoder mazeDecoder = new MazeDecoder(10, 10, 32);

            // Create default maze genome factory
            MazeGenomeFactory mazeGenomeFactory = new MazeGenomeFactory();

            foreach (string experimentName in experimentNames)
            {
                // Get the current experiment configuration
                ExperimentDictionary curExperiment = ExperimentDataHandler.LookupExperimentConfiguration(experimentName);

                // Get the total number of runs of the experiment
                int numRuns = ExperimentDataHandler.GetNumRuns(curExperiment.ExperimentDictionaryID);

                for (int runIdx = 1; runIdx <= numRuns; runIdx++)
                {
                    // Get the total number of batches in the run
                    int numBatches = ExperimentDataHandler.GetNumBatchesForRun(curExperiment.ExperimentDictionaryID,
                        runIdx);

                    // Get the maze population extant in the last batch of the run
                    IList<string> mazePopulationGenomes =
                        ExperimentDataHandler.GetMazeGenomeXml(curExperiment.ExperimentDictionaryID, runIdx, numBatches);

                    // Build output directory
                    string imageOutputDirectory = Path.Combine(mazeImageBase,
                        string.Format("ExperimentName_{0}", curExperiment.ExperimentName),
                        string.Format("Run_{0}", runIdx));

                    if (Directory.Exists(imageOutputDirectory) == false)
                    {
                        Directory.CreateDirectory(imageOutputDirectory);
                    }

                    // Decode all genomes and render image of structure
                    foreach (string mazeGenomeStr in mazePopulationGenomes)
                    {
                        MazeGenome curMazeGenome;

                        // Unmarshall to maze genome object
                        using (XmlReader xmlReader = XmlReader.Create(new StringReader(mazeGenomeStr)))
                        {
                            curMazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xmlReader, mazeGenomeFactory);
                        }

                        // Generate maze bitmap image
                        ImageGenerationHandler.GenerateMazeStructureImage(
                            Path.Combine(imageOutputDirectory,
                                string.Format("ExperimentID_{0}_Run_{1}_MazeID_{2}.bmp",
                                    curExperiment.ExperimentDictionaryID, runIdx, curMazeGenome.Id)),
                            mazeDecoder.Decode(curMazeGenome));
                    }
                }
            }
        }
Exemplo n.º 17
0
 /// <summary>
 ///     Reads a single genome from a population from the given XML file.  This is typically used in cases where a
 ///     population file is being read in, but it only contains one genome.
 /// </summary>
 /// <param name="xr">Reference to the XmlReader.</param>
 /// <param name="genomeFactory">A MazeGenomeFactory to construct genomes against.</param>
 /// <returns>Instantiated maze genome.</returns>
 public static MazeGenome ReadSingleGenomeFromRoot(XmlReader xr, MazeGenomeFactory genomeFactory)
 {
     return ReadCompleteGenomeList(xr, genomeFactory)[0];
 }