Esempio n. 1
0
        /// <summary>
        ///     Preps for running the maze navigation simulations by decoding the given maze/navigator combinations genomes.  These
        ///     are presumably combinations that were determined to be successful in solving the respective maze.
        /// </summary>
        /// <param name="navigationCombos">The combinations of mazes and navigators.</param>
        public void Initialize(
            IEnumerable <Tuple <MccexperimentMazeGenome, MccexperimentNavigatorGenome> > navigationCombos)
        {
            foreach (var navigationCombo in navigationCombos)
            {
                MazeGenome mazeGenome;
                NeatGenome navigatorGenome;

                // Deserialize the maze XML into a maze genome
                using (var xmlReader = XmlReader.Create(new StringReader(navigationCombo.Item1.GenomeXml)))
                {
                    mazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xmlReader, _mazeGenomeFactory);
                }

                // Deserialize the navigator XML into a NEAT genome
                using (var xmlReader = XmlReader.Create(new StringReader(navigationCombo.Item2.GenomeXml)))
                {
                    navigatorGenome = NeatGenomeXmlIO.ReadSingleGenomeFromRoot(xmlReader, false, _neatGenomeFactory);
                }

                // Decode to maze and navigator phenomes and add to the evaluation units list
                EvaluationUnits.Add(new MazeNavigatorEvaluationUnit(_mazeDecoder.Decode(mazeGenome),
                                                                    _agentDecoder.Decode(navigatorGenome), navigationCombo.Item1.GenomeId,
                                                                    navigationCombo.Item2.GenomeId));
            }
        }
Esempio n. 2
0
        /// <summary>
        ///     Preps for running the maze navigation simulations by constructing all combinations of mazes/navigators that need to
        ///     be evaluated in tandem.
        /// </summary>
        /// <param name="mazes">The mazes that were in the maze queue during the given batch.</param>
        /// <param name="navigators">The navigators that were in the navigator queue during the given batch.</param>
        public void Initialize(IEnumerable <MccexperimentMazeGenome> mazes,
                               IList <MccexperimentNavigatorGenome> navigators)
        {
            IList <NeatGenome> cachedAgents = new List <NeatGenome>(navigators.Count);

            foreach (var serializedMaze in mazes)
            {
                MazeGenome mazeGenome;

                // Deserialize the maze XML into a maze genome
                using (var xmlReader = XmlReader.Create(new StringReader(serializedMaze.GenomeXml)))
                {
                    mazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xmlReader, _mazeGenomeFactory);
                }

                // If no agents have been deserialized yet, we need to parse the XML and load the genotype list
                if (cachedAgents.Count < 1)
                {
                    // Go through every serialized navigator genome, deserialize it, and use it with the maze to build
                    // a new evaluation unit
                    foreach (var serializedNavigator in navigators)
                    {
                        NeatGenome agentGenome;

                        // Read in the current navigator agent genome
                        using (var xmlReader = XmlReader.Create(new StringReader(serializedNavigator.GenomeXml)))
                        {
                            agentGenome =
                                NeatGenomeXmlIO.ReadSingleGenomeFromRoot(xmlReader, false, _neatGenomeFactory);
                        }

                        // Decode to maze and navigator phenomes and add to the evaluation units list
                        EvaluationUnits.Add(new MazeNavigatorEvaluationUnit(_mazeDecoder.Decode(mazeGenome),
                                                                            _agentDecoder.Decode(agentGenome), serializedMaze.GenomeId, serializedNavigator.GenomeId));

                        // Also add to the list of cached genomes
                        cachedAgents.Add(agentGenome);
                    }
                }
                // Otherwise, skip the deserialization process
                else
                {
                    // Add each genome with the current maze to create new evaluation units
                    foreach (var cachedAgent in cachedAgents)
                    {
                        EvaluationUnits.Add(new MazeNavigatorEvaluationUnit(_mazeDecoder.Decode(mazeGenome),
                                                                            _agentDecoder.Decode(cachedAgent), serializedMaze.GenomeId, (int)cachedAgent.Id));
                    }
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        ///     Preps for generating the maze structures by decoding the given list of maze genomes.  This is in support of
        ///     post-hoc analyses that doesn't consider navigator trajectories.
        /// </summary>
        /// <param name="mazes">The mazes that were in the maze queue during the given batch.</param>
        public void Initialize(IEnumerable <MccexperimentMazeGenome> mazes)
        {
            foreach (var serializedMaze in mazes)
            {
                MazeGenome mazeGenome;

                // Deserialize the maze XML into a maze genome
                using (var xmlReader = XmlReader.Create(new StringReader(serializedMaze.GenomeXml)))
                {
                    mazeGenome = MazeGenomeXmlIO.ReadSingleGenomeFromRoot(xmlReader, _mazeGenomeFactory);
                }

                // Decode to maze phenome and add to the maze/id map
                _mazeIdStructureMap.Add(serializedMaze.GenomeId, _mazeDecoder.Decode(mazeGenome));
            }
        }
Esempio n. 4
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)));
        }
Esempio n. 6
0
 /// <inheritdoc />
 /// <summary>
 ///     Save a population of maze genomes to an XmlWriter.
 /// </summary>
 public void SaveMazePopulation(XmlWriter xw, IList <MazeGenome> mazeGenomeList)
 {
     MazeGenomeXmlIO.WriteComplete(xw, mazeGenomeList);
 }
        /// <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);
                }
            }
        }
        /// <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));
        }