public void ToOrderedMutationEvent_Should_ReturnMutationForEachItem()
        {
            var product = ProductFactory.GetProduct("0");

            Assert.Equal(10, product.Available);

            var mutations = ProductFactory.GetProductStockMutations(product.Id);

            var actual = MutationFactory.ToOrderedMutationEvent <Product, ProductStockMutation, string, int, DateTimeOffset>(
                x => x.Available,
                mutations,
                x => x.Id,
                x => x.Amount,
                x => x.OrderDate).ToList();

            Assert.Equal(mutations.Count, actual.Count);
            var mutation1 = actual[0];
            var mutation2 = actual.Last();

            mutation1.Revert(product);
            product.Available.Should().Be(10 - mutations[0].Amount);

            mutation2.Apply(product);
            product.Available.Should().Be(10 - mutations[0].Amount + mutations.Last().Amount);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Adds Connection (Structural Mutation) to Genome from Nodes
        /// </summary>
        /// <param name="nodeFrom">From-Node (Innovation-Number) for Connection</param>
        /// <param name="nodeTo">To-Node (Innovation-Number) for Connection</param>
        internal void MutateAddConnection(ulong nodeFrom, ulong nodeTo)
        {
            if (nodeFrom == 0)
            {
                throw new ArgumentException("NodeInnovation cannot be 0", "nodeFrom");
            }
            if (nodeTo == 0)
            {
                throw new ArgumentException("NodeInnovation cannot be 0", "nodeTo");
            }
            if (nodeFrom == nodeTo)
            {
                throw new ArgumentException("Cannot create Connection with a single Node");
            }
            if (!Nodes.ContainsKey(nodeFrom))
            {
                throw new ArgumentException("Node does not exist in Genome", "nodeFrom");
            }
            if (!Nodes.ContainsKey(nodeTo))
            {
                throw new ArgumentException("Node does not exist in Genome", "nodeTo");
            }
            NodeGene from = Nodes[nodeFrom];
            NodeGene to   = Nodes[nodeTo];

            if (from.Type == NodeType.OUTPUT || to.Type == NodeType.INPUT)
            {
                throw new InvalidOperationException($"Invalid NodeTypes for Connection. Type NodeFrom: {from.Type} Type NodeTo: {to.Type}");
            }
            // TODO: Check if Connection does not exist already in Genome
            AddConnection(MutationFactory.GetConnection(from, to));
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Adds Connection (Structural Mutation) to Genome from Nodes
 /// </summary>
 /// <param name="nodeFrom">From-Node for Connection</param>
 /// <param name="nodeTo">To-Node for Connection</param>
 internal void MutateAddConnection(NodeGene nodeFrom, NodeGene nodeTo)
 {
     if (!nodeFrom.IsValid)
     {
         throw new ArgumentException("NodeFrom is Invalid", "nodeFrom");
     }
     if (!nodeTo.IsValid)
     {
         throw new ArgumentException("NodeTo is Invalid", "nodeTo");
     }
     if (nodeFrom.Equals(nodeTo))
     {
         throw new ArgumentException("Cannot create Connection with a single Node");
     }
     if (!Nodes.ContainsKey(nodeFrom.Innovation))
     {
         throw new ArgumentException("Node does not exist in Genome", "nodeFrom");
     }
     if (!Nodes.ContainsKey(nodeTo.Innovation))
     {
         throw new ArgumentException("Node does not exist in Genome", "nodeTo");
     }
     if (nodeFrom.Type == NodeType.OUTPUT || nodeTo.Type == NodeType.INPUT)
     {
         throw new InvalidOperationException($"Invalid NodeTypes for Connection. Type NodeFrom: {nodeFrom.Type} Type NodeTo: {nodeTo.Type}");
     }
     // TODO: Check if Connection does not exist already in Genome
     AddConnection(MutationFactory.GetConnection(nodeFrom, nodeTo));
 }
        public void ToMutationEvent_Should_ReturnMutationForEachItem()
        {
            var product = ProductFactory.GetProduct("0");

            product.Available.Should().Be(10);

            var product1 = ProductFactory.GetProduct("1");
            var product2 = ProductFactory.GetProduct("2");

            var mutations = new List <Product>
            {
                product1,
                product2
            };

            var actual = MutationFactory.ToMutationEvent <Product, Product, Guid, int>(
                x => x.Available,
                mutations,
                x => x.Id,
                x => x.InStock)
                         .ToList();

            Assert.Equal(mutations.Count, actual.Count);
            var mutation1 = actual[0];
            var mutation2 = actual.Last();

            mutation1.Revert(product);
            product.Available.Should().Be(10 - product1.InStock);

            mutation2.Apply(product);
            product.Available.Should().Be(10 - product1.InStock + product2.InStock);
        }
Ejemplo n.º 5
0
        internal static List <IEvent <Product, string> > GetChanges(Guid itemId)
        {
            var priceChanges         = ProductFactory.GetProductPriceChanges(itemId).ToList();
            var stockMutationChanges = ProductFactory.GetProductStockMutations(itemId).ToList();

            var changes = ChangeFactory.ToOrderedChangeEvent <Product, ProductPriceChange, string, double, DateTime>(
                x => x.Price,
                0,
                priceChanges,
                x => x.Id,
                x => x.Price,
                x => x.ChangeDate).Cast <IEvent <Product, string> >().ToList();

            changes.AddRange(MutationFactory.ToMutationEvent <Product, ProductStockMutation, string, int>(
                                 x => x.Available,
                                 stockMutationChanges,
                                 x => x.Id,
                                 x => x.ApplyableAmount).Cast <IEvent <Product, string> >());

            changes.AddRange(MutationFactory.ToOrderedMutationEvent <Product, ProductStockMutation, string, int, DateTime>(
                                 x => x.InStock,
                                 stockMutationChanges,
                                 x => x.Id,
                                 x => x.ApplyableAmount,
                                 x => x.DeliveryDate.Date).Cast <IEvent <Product, string> >());

            return(changes);
        }
Ejemplo n.º 6
0
 private EvolutionThread()
 {
     GenerationCounter = 0;
     Timestamp         = System.DateTime.Now;
     Fitness           = FitnessFunctionFactory.CreateDefaultFunction();
     Crossover         = CrossoverFactory.CreateDefaultCrossover();
     Mutation          = MutationFactory.CreateDefaultMutation();
 }
Ejemplo n.º 7
0
        private void PerformMutation(IRandomizer randomizer)
        {
            var x        = new ChromosomeSelector(_currentGeneration);
            var parent1  = x.Get(randomizer);
            var strategy = MutationFactory.GetMutationStrategy(randomizer);
            var mutant   = strategy.Mutate(parent1);

            CheckAndAddValidChild(mutant, false, true);
        }
Ejemplo n.º 8
0
        internal static DL.Models.Product SetProduct(ProductStock.DL.Models.Product product)
        {
            if (!ProductStocks.ContainsKey(product.Id))
            {
                ProductStocks.Add(product.Id, product);

                var result = new DL.Models.Product(product.Id, product.Number, product.Description);
                Products.Add(product.Id, result);

                var priceChanges = ChangeFactory.ToOrderedChangeEvent <
                    DL.Models.Product,
                    ProductStock.DL.Models.ProductPrice,
                    Guid,
                    double,
                    DateTimeOffset>(
                    x => x.Price,
                    0,
                    product.Prices,
                    x => x.Id,
                    x => x.Price,
                    x => x.RegisterDate).
                                   Cast <IEvent <DL.Models.Product, Guid> >().ToList();

                var stockAvailableMutations = MutationFactory.ToOrderedMutationEvent <
                    DL.Models.Product,
                    ProductStock.DL.Models.ProductStockMutation,
                    Guid,
                    int,
                    DateTimeOffset>(
                    x => x.Available,
                    product.StockMutations,
                    x => x.Id,
                    x => x.Amount * (x.Type == ProductStock.DL.Enums.MutationType.Purchase ? -1 : 1),
                    x => x.OrderDate).Cast <IEvent <DL.Models.Product, Guid> >().ToList();

                var stockInStockMutations = MutationFactory.ToOrderedMutationEvent <
                    DL.Models.Product,
                    ProductStock.DL.Models.ProductStockMutation,
                    Guid,
                    int,
                    DateTimeOffset>(
                    x => x.InStock,
                    product.StockMutations,
                    x => x.Id,
                    x => x.Amount * (x.Type == ProductStock.DL.Enums.MutationType.Purchase ? -1 : 1),
                    x => x.ShipmentDate).Cast <IEvent <DL.Models.Product, Guid> >().ToList();

                AddEvents(product.Id, new OrderedEventCollection <DL.Models.Product, Guid, DateTimeOffset>(priceChanges.ToList()));
                AddEvents(product.Id, new OrderedEventCollection <DL.Models.Product, Guid, DateTimeOffset>(stockAvailableMutations.ToList()));
                AddEvents(product.Id, new OrderedEventCollection <DL.Models.Product, Guid, DateTimeOffset>(stockInStockMutations.ToList()));

                return(result);
            }

            return(Products[product.Id]);
        }
        public PolynomialMutationOffspring(double mutationProbability, double distributionIndexForMutation)
        {
            Dictionary <string, object> parameters;            // Operator parameters

            parameters = new Dictionary <string, object>();
            parameters.Add("probability", this.mutationProbability     = mutationProbability);
            parameters.Add("distributionIndex", this.distributionIndex = distributionIndexForMutation);
            mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);

            selection = SelectionFactory.GetSelectionOperator("BinaryTournament", null);
            Id        = "PolynomialMutation";
        }
        private static List <MLNode> GetMLNodes()
        {
            List <MLNode> nodes = new List <MLNode>();

            foreach (MutationCategory category in MutationFactory.GetCategories())
            {
                MLNode mLNode = new MLNode();
                mLNode.bExpand  = false;
                mLNode.Category = category;
                nodes.Add(mLNode);
                foreach (MutationEntry entry in category.Entries)
                {
                    MLNode mLNode2 = new MLNode();
                    mLNode2.ParentNode = mLNode;
                    mLNode2.Entry      = entry;
                    nodes.Add(mLNode2);
                }
            }
            return(nodes);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Adds Node for Connection (Structural Mutation)
        /// </summary>
        /// <param name="connectionInnovation">Connection to add Node for</param>
        internal void MutateAddNode(ConnectionGene conn)
        {
            if (!conn.IsValid)
            {
                throw new ArgumentException("Connection is not Valid", "conn");
            }
            if (!conn.Expressed)
            {
                return; // Connection is not active
            }
            ConnectionGene conn1, conn2;
            NodeGene       newNode = MutationFactory.GetNode(ref conn, out conn1, out conn2);

            // Overwrite old Connection (now disabled)
            Connections[conn.Innovation] = conn;
            // Add new Objects
            AddNode(newNode);
            AddConnection(conn1);
            AddConnection(conn2);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Breeds a Population of Genomes
        /// </summary>
        public void BreedNewPopulation()
        {
            if (population.Count == 0)
            {
                CreateInitialPopulation();
                return;
            }
            if (species.Count == 0)                       // No Species from previous Generation
            {
                Functions.FisherYatesShuffle(population); // Shuffle Previous Generation (so that initial Species-Mascots are randomized)
            }
            Speciate();
            // Clear old population to make room for new population (references exist through species)
            population.Clear();
            // Create new Population
            float sum = 0;

            // Find population-size per species
            for (int i = 0; i < species.Count; i++)
            {
                sum += species[i].GetFitness();     // Total Fitness
            }
            for (int i = 0; i < species.Count; i++) // For Each Species
            {
                Species s       = species[i];
                int     popSize = (int)Math.Ceiling(s.GetFitness() / sum * PopulationSize);
                // Darwin multikill:
                s.KillOffPercentage(breedingPercentage);
                // Breed within Species
                s.BreedPopulation(popSize, mutationChance);
                // Add to population
                population.AddRange(s.Genomes);
            }
            while (population.Count > PopulationSize)                      // Remove Excess from Math.Ceil
            {
                population.Remove(Functions.GetRandomElement(population)); // Darwin Sniper
            }
            MutationFactory.EndGeneration();
        }
        private void Start()
        {
            _geneticManager = new GeneticManager()
            {
                PixelCollection = PixelCollection,
                ScoringTable    = ScoringTableFactory.Create(CurrentScoringType),
                Crossing        = CrossingFactory.Create(CurrentCrossingType),
                PixelsToSelect  = PixelsToSelect,
                HowManyChildren = HowManyChildren,
                Mutation        = MutationFactory.Create(CurrentMutationType),
                MutationRate    = CurrentMutationRate,
            };

            IsVisualisationEnabled = true;
            _backgroundWorker      = new BackgroundWorker
            {
                WorkerReportsProgress      = true,
                WorkerSupportsCancellation = true
            };
            _backgroundWorker.DoWork          += DoVisualisation;
            _backgroundWorker.ProgressChanged += OnNextGeneration;
            _backgroundWorker.RunWorkerAsync();
        }
Ejemplo n.º 14
0
        public Operator GetMutation()
        {
            string filepath = DirPath + "/Parameter.txt";

            string[] line6 = { "probabilityOfMutation " + 1.0 / problem.NumberOfVariables, "distributionIndexOfMutation " + diom, "" };

            Dictionary <string, object> parameters = new Dictionary <string, object>();

            switch (mu)
            {
            case "PolynomialMutation":
                parameters = new Dictionary <string, object>();
                parameters.Add("probability", 1.0 / problem.NumberOfVariables);
                //parameters.Add("probability", 0.2);
                parameters.Add("distributionIndex", double.Parse(diom));
                mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);
                File.AppendAllLines(filepath, line6);
                break;

            case "DynamicPolynomialMutation":
                parameters = new Dictionary <string, object>();
                parameters.Add("probability", 1.0);
                parameters.Add("distributionIndex", double.Parse(diom));
                mutation = MutationFactory.GetMutationOperator("DynamicPolynomialMutation", parameters);
                File.AppendAllLines(filepath, line6);
                break;

            case null:
                break;

            default:
                break;
            }

            return(mutation);
        }
        /// <summary>
        /// Usage:
        ///     - NSGAIImTSP
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        public static void Main(string[] args)
        {
            Problem   problem;                      // The problem to solve
            Algorithm algorithm;                    // The algorithm to use
            Operator  crossover;                    // Crossover operator
            Operator  mutation;                     // Mutation operator
            Operator  selection;                    // Selection operator

            Dictionary <string, object> parameters; // Operator parameters

            QualityIndicator indicators;            // Object to get quality indicators

            // Logger object and file to store log messages
            var logger = Logger.Log;

            var appenders    = logger.Logger.Repository.GetAppenders();
            var fileAppender = appenders[0] as log4net.Appender.FileAppender;

            fileAppender.File = "NSGAIImTSP.log";
            fileAppender.ActivateOptions();

            indicators = null;
            problem    = new MTSP("Permutation", "kroA150.tsp", "kroB150.tsp");

            algorithm = new JMetalCSharp.Metaheuristics.NSGAII.NSGAII(problem);
            //algorithm = new ssNSGAII(problem);

            // Algorithm parameters
            algorithm.SetInputParameter("populationSize", 100);
            algorithm.SetInputParameter("maxEvaluations", 10000000);

            /* Crossver operator */
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 0.95);
            //crossover = CrossoverFactory.getCrossoverOperator("TwoPointsCrossover", parameters);
            crossover = CrossoverFactory.GetCrossoverOperator("PMXCrossover", parameters);

            /* Mutation operator */
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 0.2);
            mutation = MutationFactory.GetMutationOperator("SwapMutation", parameters);

            /* Selection Operator */
            parameters = null;
            selection  = SelectionFactory.GetSelectionOperator("BinaryTournament", parameters);

            // Add the operators to the algorithm
            algorithm.AddOperator("crossover", crossover);
            algorithm.AddOperator("mutation", mutation);
            algorithm.AddOperator("selection", selection);

            // Add the indicator object to the algorithm
            algorithm.SetInputParameter("indicators", indicators);

            // Execute the Algorithm
            long        initTime      = Environment.TickCount;
            SolutionSet population    = algorithm.Execute();
            long        estimatedTime = Environment.TickCount - initTime;

            // Result messages
            logger.Info("Total execution time: " + estimatedTime + "ms");
            logger.Info("Variables values have been writen to file VAR");
            population.PrintVariablesToFile("VAR");
            logger.Info("Objectives values have been writen to file FUN");
            population.PrintObjectivesToFile("FUN");

            if (indicators != null)
            {
                logger.Info("Quality indicators");
                logger.Info("Hypervolume: " + indicators.GetHypervolume(population));
                logger.Info("GD         : " + indicators.GetGD(population));
                logger.Info("IGD        : " + indicators.GetIGD(population));
                logger.Info("Spread     : " + indicators.GetSpread(population));
                logger.Info("Epsilon    : " + indicators.GetEpsilon(population));

                int evaluations = (int)algorithm.GetOutputParameter("evaluations");
                logger.Info("Speed      : " + evaluations + " evaluations");
            }
        }
Ejemplo n.º 16
0
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new LoadConfig());

            // VariabilityModel model = new VariabilityModel("Model1");
            //  InfluenceModel infModel = new InfluenceModel(model, new NFProperty("Test"));

            //  BettyFileParser bfp = new BettyFileParser(model, infModel);

            String[] file = System.IO.File.ReadAllLines(@"C:\Users\Tom\Desktop\Masterarbeit\SPLConqueror\SPLConqueror\BettyConqueror\FeatureModel0.afm");

            //  bfp.readConfiguration(file);
            //ILArray<float> A = ILMath.tosingle()
            //ILArray<float> A = ILMath.tosingle(ILMath.rand(3, 100));


            // RDotNet.NativeLibrary.UnmanagedDll.SetDllDirectory(@"C:\Program Files\R\R-3.2.0\bin\i386\R.dll");


            engine = REngine.GetInstance();

            NumericVector group1 = engine.CreateNumericVector(new double[] { 30.02, 29.99, 30.11, 29.97, 30.01, 29.99 });

            engine.SetSymbol("group1", group1);

            // e.Evaluate("hist(group1)");
            // e.Evaluate("hist(group1)");

            Problem  problem;
            Operator crossover; // Crossover operator
            Operator mutation;  // Mutation operator
            Operator selection; // Selection operator

            var logger = Logger.Log;

            // var appenders = logger.Logger.Repository.GetAppenders();
            // var fileAppender = appenders[0] as log4net.Appender.FileAppender;
            // fileAppender.File = "NSGAII.log";
            //.ActivateOptions();

            Dictionary <string, object> parameters; // Operator parameters

            QualityIndicator indicators;            // Object to get quality indicators

            problem = new GeneratorProblem("Real", 30);


            NSGAII algorithm = new NSGAII(problem);

            indicators = null;

            algorithm.SetInputParameter("populationSize", 200);
            algorithm.SetInputParameter("maxEvaluations", 25000);

            // Mutation and Crossover for Real codification
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 0.9);
            parameters.Add("distributionIndex", 20.0);
            crossover = CrossoverFactory.GetCrossoverOperator("SBXCrossover", parameters);

            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 1.0 / problem.NumberOfVariables);
            parameters.Add("distributionIndex", 20.0);
            mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);

            // Selection Operator
            parameters = null;
            selection  = SelectionFactory.GetSelectionOperator("BinaryTournament2", parameters);

            // Add the operators to the algorithm
            algorithm.AddOperator("crossover", crossover);
            algorithm.AddOperator("mutation", mutation);
            algorithm.AddOperator("selection", selection);

            // Add the indicator object to the algorithm
            algorithm.SetInputParameter("indicators", indicators);

            // Execute the Algorithm
            long initTime = Environment.TickCount;
            //SolutionSet population = algorithm.Execute();
            long estimatedTime = Environment.TickCount - initTime;

            logger.Info("Variables values have been writen to file VAR");
//population.PrintVariablesToFile("VAR");
            logger.Info("Objectives values have been writen to file FUN");
            //   population.PrintObjectivesToFile("FUN");
            Console.WriteLine("Time: " + estimatedTime);
            Console.ReadLine();
            //Application.Run(new Form1(e, group1, new double[] { 30.02, 29.99, 30.11, 29.97, 30.01, 29.99, 1.3, 1.7, 9.4, 11.1  }));
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Adds random connection (Structural Mutation) to Genome
        /// </summary>
        internal void MutateAddRandomConnection()
        {
            if (Nodes.Count < 2)
            {
                throw new InvalidOperationException("Not enough Existing Nodes");
            }
            // Separate out the Nodes by Type
            List <NodeGene> inputNodes  = new List <NodeGene>();
            List <NodeGene> hiddenNodes = new List <NodeGene>();
            List <NodeGene> outputNodes = new List <NodeGene>();

            foreach (NodeGene node in Nodes.Values)
            {
                switch (node.Type)
                {
                case NodeType.INPUT:
                    inputNodes.Add(node);
                    break;

                case NodeType.HIDDEN:
                    hiddenNodes.Add(node);
                    break;

                case NodeType.OUTPUT:
                    outputNodes.Add(node);
                    break;

                default:
                    break;
                }
            }
            // Add hiddenNodes to both lists to create the choice-lists
            inputNodes.AddRange(hiddenNodes);
            outputNodes.AddRange(hiddenNodes);

            // Find 2 nodes in these 2 lists which are NOT connected
            NodeGene inputNode = inputNodes[Functions.GetRandomNumber(0, inputNodes.Count)]; // Pick random inputNode
            int      attempts  = 0;

            while (attempts < MaxFindAttempts) // TODO: Improve this
            {
                attempts++;
                NodeGene outputNode = outputNodes[Functions.GetRandomNumber(0, outputNodes.Count)];
                if (inputNode.Equals(outputNode)) // Same (hidden) node, can't connect to self
                {
                    continue;
                }
                bool foundConnection = false;
                foreach (ConnectionGene conn in Connections.Values)
                {
                    if (conn.HasNode(inputNode) && conn.HasNode(outputNode))
                    {
                        foundConnection = true;
                        break; // Connection Exists
                    }
                }
                if (foundConnection)
                {
                    continue; // failed to find valid pair
                }
                // InputNode != OutputNode and !(I->O) && !(O->I)
                AddConnection(MutationFactory.GetConnection(inputNode, outputNode));
                return;
            }
            Console.WriteLine("Failed to add Connection");
        }
        /// <summary>
        ///Usage: three choices
        ///     - AbYSS
        ///     - AbYSS problemName
        ///     - AbYSS problemName paretoFrontFile
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        public static void Main(string[] args)
        {
            Problem   problem;                      // The problem to solve
            Algorithm algorithm;                    // The algorithm to use
            Operator  crossover;                    // Crossover operator
            Operator  mutation;                     // Mutation operator
            Operator  improvement;                  // Operator for improvement

            Dictionary <string, object> parameters; // Operator parameters

            QualityIndicator indicators;            // Object to get quality indicators

            // Logger object and file to store log messages
            var logger       = Logger.Log;
            var appenders    = logger.Logger.Repository.GetAppenders();
            var fileAppender = appenders[0] as log4net.Appender.FileAppender;

            fileAppender.File = "AbYSS.log";
            fileAppender.ActivateOptions();


            indicators = null;
            if (args.Length == 1)
            {
                object[] param = { "Real" };
                problem = ProblemFactory.GetProblem(args[0], param);
            }
            else if (args.Length == 2)
            {
                object[] param = { "Real" };
                problem    = ProblemFactory.GetProblem(args[0], param);
                indicators = new QualityIndicator(problem, args[1]);
            }
            else
            {             // Default problem
                problem = new Kursawe("Real", 3);
                //problem = new Kursawe("BinaryReal", 3);
                //problem = new Water("Real");
                //problem = new ZDT4("ArrayReal", 10);
                //problem = new ConstrEx("Real");
                //problem = new DTLZ1("Real");
                //problem = new OKA2("Real") ;
            }

            // STEP 2. Select the algorithm (AbYSS)
            algorithm = new JMetalCSharp.Metaheuristics.AbYSS.AbYSS(problem);

            // STEP 3. Set the input parameters required by the metaheuristic
            algorithm.SetInputParameter("populationSize", 20);
            algorithm.SetInputParameter("refSet1Size", 10);
            algorithm.SetInputParameter("refSet2Size", 10);
            algorithm.SetInputParameter("archiveSize", 100);
            algorithm.SetInputParameter("maxEvaluations", 25000);

            // STEP 4. Specify and configure the crossover operator, used in the
            //         solution combination method of the scatter search
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 0.9);
            parameters.Add("distributionIndex", 20.0);
            crossover = CrossoverFactory.GetCrossoverOperator("SBXCrossover", parameters);

            // STEP 5. Specify and configure the improvement method. We use by default
            //         a polynomial mutation in this method.
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 1.0 / problem.NumberOfVariables);
            parameters.Add("distributionIndex", 20.0);
            mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);

            parameters = new Dictionary <string, object>();
            parameters.Add("improvementRounds", 1);
            parameters.Add("problem", problem);
            parameters.Add("mutation", mutation);
            improvement = new MutationLocalSearch(parameters);

            // STEP 6. Add the operators to the algorithm
            algorithm.AddOperator("crossover", crossover);
            algorithm.AddOperator("improvement", improvement);

            long initTime = Environment.TickCount;

            // STEP 7. Run the algorithm
            SolutionSet population    = algorithm.Execute();
            long        estimatedTime = Environment.TickCount - initTime;

            // STEP 8. Print the results
            logger.Info("Total execution time: " + estimatedTime + "ms");
            logger.Info("Variables values have been writen to file VAR");
            population.PrintVariablesToFile("VAR");
            logger.Info("Objectives values have been writen to file FUN");
            population.PrintObjectivesToFile("FUN");

            Console.WriteLine("Total execution time: " + estimatedTime + "ms");
            Console.ReadLine();
            if (indicators != null)
            {
                logger.Info("Quality indicators");
                logger.Info("Hypervolume: " + indicators.GetHypervolume(population));
                logger.Info("GD         : " + indicators.GetGD(population));
                logger.Info("IGD        : " + indicators.GetIGD(population));
                logger.Info("Spread     : " + indicators.GetSpread(population));
                logger.Info("Epsilon    : " + indicators.GetEpsilon(population));
            }
        }
        /// <summary>
        /// Usage: three options
        ///     - NSGAII
        ///     - NSGAII problemName
        ///     - NSGAII problemName paretoFrontFile
        /// </summary>
        /// <param name="args"></param>
        public NSGAIIRunner(string[] args, Problem p, string Path, MOO comp)
        {
            Problem   problem = p; // The problem to solve
            Algorithm algorithm;   // The algorithm to use
            Operator  crossover;   // Crossover operator
            Operator  mutation;    // Mutation operator
            Operator  selection;   // Selection operator

            this.comp = comp;

            Dictionary <string, object> parameters; // Operator parameters

            QualityIndicator indicators;            // Object to get quality indicators

            // Logger object and file to store log messages
            //var logger = Logger.Log;

            //var appenders = logger.Logger.Repository.GetAppenders();
            //var fileAppender = appenders[0] as log4net.Appender.FileAppender;
            //fileAppender.File = "NSGAII.log";
            //fileAppender.ActivateOptions();

            indicators = null;
            //if (args.Length == 1)
            //{
            //    object[] param = { "Real" };
            //    problem = ProblemFactory.GetProblem(args[0], param);
            //}
            //else if (args.Length == 2)
            //{
            //    object[] param = { "Real" };
            //    problem = ProblemFactory.GetProblem(args[0], param);
            //    indicators = new QualityIndicator(problem, args[1]);
            //}
            //else
            //{ // Default problem
            //    //problem = ;
            //    //problem = new Kursawe("BinaryReal", 3);
            //    //problem = new Water("Real");
            //    //problem = new ZDT3("ArrayReal", 30);
            //    //problem = new ConstrEx("Real");
            //    //problem = new DTLZ1("Real");
            //    //problem = new OKA2("Real") ;
            //}

            algorithm = new NSGAII(problem, comp);
            //algorithm = new ssNSGAII(problem);

            // Algorithm parameters
            algorithm.SetInputParameter("populationSize", comp.popSize);
            algorithm.SetInputParameter("maxEvaluations", comp.maxEvals);
            comp.LogAddMessage("Population Size = " + comp.popSize);
            comp.LogAddMessage("Max Evaluations = " + comp.maxEvals);

            // Mutation and Crossover for Real codification
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 0.9);
            parameters.Add("distributionIndex", 20.0);
            crossover = CrossoverFactory.GetCrossoverOperator("SBXCrossover", parameters);
            comp.LogAddMessage("Crossover Type = " + "SBXCrossover");
            comp.LogAddMessage("Crossover Probability = " + 0.9);
            comp.LogAddMessage("Crossover Distribution Index = " + 20);

            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 1.0 / problem.NumberOfVariables);
            parameters.Add("distributionIndex", 20.0);
            mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);
            comp.LogAddMessage("Mutation Type = " + "Polynomial Mutation");
            comp.LogAddMessage("Mutation Probability = " + (1 / problem.NumberOfVariables));
            comp.LogAddMessage("Mutation Distribution Index = " + 20);

            // Selection Operator
            parameters = null;
            selection  = SelectionFactory.GetSelectionOperator("BinaryTournament2", parameters);
            comp.LogAddMessage("Selection Type = " + "Binary Tournament 2");

            // Add the operators to the algorithm
            algorithm.AddOperator("crossover", crossover);
            algorithm.AddOperator("mutation", mutation);
            algorithm.AddOperator("selection", selection);

            // Add the indicator object to the algorithm
            algorithm.SetInputParameter("indicators", indicators);

            // Execute the Algorithm
            long        initTime      = Environment.TickCount;
            SolutionSet population    = algorithm.Execute();
            long        estimatedTime = Environment.TickCount - initTime;

            comp.LogAddMessage("Total Execution Time = " + estimatedTime + "ms");

            // Result messages
            //logger.Info("Total execution time: " + estimatedTime + "ms");
            //logger.Info("Variables values have been writen to file VAR");

            //population.PrintVariablesToFile(@"C:\Users\Jonathas\Desktop\text.txt");
            population.PrintVariablesToFile(@"" + comp.fileName + "VAR-" + comp.fileName);
            //logger.Info("Objectives values have been writen to file FUN");
            population.PrintObjectivesToFile(@"" + comp.fileName + "OBJ-" + comp.fileName);
            // Saving all solutions to file


            //Console.WriteLine("Time: " + estimatedTime);
            //Console.ReadLine();
            if (indicators != null)
            {
                //logger.Info("Quality indicators");
                //logger.Info("Hypervolume: " + indicators.GetHypervolume(population));
                //logger.Info("GD         : " + indicators.GetGD(population));
                //logger.Info("IGD        : " + indicators.GetIGD(population));
                //logger.Info("Spread     : " + indicators.GetSpread(population));
                //logger.Info("Epsilon    : " + indicators.GetEpsilon(population));

                int evaluations = (int)algorithm.GetOutputParameter("evaluations");
                //logger.Info("Speed      : " + evaluations + " evaluations");
            }
        }
        /// <summary>
        /// Usage: three options
        ///    - SPEA2
        ///    - SPEA2 problemName
        ///    - SPEA2 problemName ParetoFrontFile
        /// </summary>
        /// <param name="args">Command line arguments. The first (optional) argument specifies the problem to solve.</param>
        public static void Main(string[] args)
        {
            Problem   problem;                      // The problem to solve
            Algorithm algorithm;                    // The algorithm to use
            Operator  crossover;                    // Crossover operator
            Operator  mutation;                     // Mutation operator
            Operator  selection;                    // Selection operator

            QualityIndicator indicators;            // Object to get quality indicators

            Dictionary <string, object> parameters; // Operator parameters

            // Logger object and file to store log messages
            var logger = Logger.Log;

            var appenders    = logger.Logger.Repository.GetAppenders();
            var fileAppender = appenders[0] as log4net.Appender.FileAppender;

            fileAppender.File = "SPEA2.log";
            fileAppender.ActivateOptions();

            indicators = null;
            if (args.Length == 1)
            {
                object[] param = { "Real" };
                problem = ProblemFactory.GetProblem(args[0], param);
            }
            else if (args.Length == 2)
            {
                object[] param = { "Real" };
                problem    = ProblemFactory.GetProblem(args[0], param);
                indicators = new QualityIndicator(problem, args[1]);
            }
            else
            {             // Default problem
                problem = new Kursawe("Real", 3);
                //problem = new Water("Real");
                //problem = new ZDT1("ArrayReal", 1000);
                //problem = new ZDT4("BinaryReal");
                //problem = new WFG1("Real");
                //problem = new DTLZ1("Real");
                //problem = new OKA2("Real") ;
            }

            algorithm = new JMetalCSharp.Metaheuristics.SPEA2.SPEA2(problem);

            // Algorithm parameters
            algorithm.SetInputParameter("populationSize", 100);
            algorithm.SetInputParameter("archiveSize", 100);
            algorithm.SetInputParameter("maxEvaluations", 25000);

            // Mutation and Crossover for Real codification
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 0.9);
            parameters.Add("distributionIndex", 20.0);
            crossover = CrossoverFactory.GetCrossoverOperator("SBXCrossover", parameters);

            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 1.0 / problem.NumberOfVariables);
            parameters.Add("distributionIndex", 20.0);
            mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);

            // Selection operator
            parameters = null;
            selection  = SelectionFactory.GetSelectionOperator("BinaryTournament", parameters);

            // Add the operators to the algorithm
            algorithm.AddOperator("crossover", crossover);
            algorithm.AddOperator("mutation", mutation);
            algorithm.AddOperator("selection", selection);

            // Execute the algorithm
            long        initTime      = Environment.TickCount;
            SolutionSet population    = algorithm.Execute();
            long        estimatedTime = Environment.TickCount - initTime;

            // Result messages
            logger.Info("Total execution time: " + estimatedTime + "ms");
            logger.Info("Objectives values have been writen to file FUN");
            population.PrintObjectivesToFile("FUN");
            logger.Info("Variables values have been writen to file VAR");
            population.PrintVariablesToFile("VAR");

            if (indicators != null)
            {
                logger.Info("Quality indicators");
                logger.Info("Hypervolume: " + indicators.GetHypervolume(population));
                logger.Info("GD         : " + indicators.GetGD(population));
                logger.Info("IGD        : " + indicators.GetIGD(population));
                logger.Info("Spread     : " + indicators.GetSpread(population));
                logger.Info("Epsilon    : " + indicators.GetEpsilon(population));
            }
            Console.WriteLine("Total execution time: " + estimatedTime + "ms");
            Console.ReadLine();
        }
        /// <summary>
        /// Usage: three options
        ///      - PMOEAD
        ///      - PMOEAD problemName
        ///      - PMOEAD problemName ParetoFrontFile
        ///      - PMOEAD problemName numberOfThreads dataDirectory
        /// </summary>
        /// <param name="args">Command line arguments. The first (optional) argument specifies the problem to solve.</param>
        public static void Main(string[] args)
        {
            Problem   problem;                      // The problem to solve
            Algorithm algorithm;                    // The algorithm to use
            Operator  crossover;                    // Crossover operator
            Operator  mutation;                     // Mutation operator

            QualityIndicator indicators;            // Object to get quality indicators

            Dictionary <string, object> parameters; // Operator parameters

            int    numberOfThreads = 4;
            string dataDirectory   = "";

            // Logger object and file to store log messages
            var logger = Logger.Log;

            var appenders    = logger.Logger.Repository.GetAppenders();
            var fileAppender = appenders[0] as log4net.Appender.FileAppender;

            fileAppender.File = "PMOEAD.log";
            fileAppender.ActivateOptions();

            indicators = null;
            if (args.Length == 1)
            {             // args[0] = problem name
                object[] paramsList = { "Real" };
                problem = ProblemFactory.GetProblem(args[0], paramsList);
            }
            else if (args.Length == 2)
            {             // args[0] = problem name, [1] = pareto front file
                object[] paramsList = { "Real" };
                problem    = ProblemFactory.GetProblem(args[0], paramsList);
                indicators = new QualityIndicator(problem, args[1]);
            }
            else if (args.Length == 3)
            {             // args[0] = problem name, [1] = threads, [2] = data directory
                object[] paramsList = { "Real" };
                problem         = ProblemFactory.GetProblem(args[0], paramsList);
                numberOfThreads = int.Parse(args[1]);
                dataDirectory   = args[2];
            }
            else
            {             // Problem + number of threads + data directory
                problem = new Kursawe("Real", 3);
                //problem = new Kursawe("BinaryReal", 3);
                //problem = new Water("Real");
                //problem = new ZDT1("ArrayReal", 100);
                //problem = new ConstrEx("Real");
                //problem = new DTLZ1("Real");
                //problem = new OKA2("Real") ;
            }

            algorithm = new JMetalCSharp.Metaheuristics.MOEAD.PMOEAD(problem);

            // Algorithm parameters
            algorithm.SetInputParameter("populationSize", 300);
            algorithm.SetInputParameter("maxEvaluations", 150000);
            algorithm.SetInputParameter("numberOfThreads", numberOfThreads);

            // Directory with the files containing the weight vectors used in
            // Q. Zhang,  W. Liu,  and H Li, The Performance of a New Version of MOEA/D
            // on CEC09 Unconstrained MOP Test Instances Working Report CES-491, School
            // of CS & EE, University of Essex, 02/2009.
            // http://dces.essex.ac.uk/staff/qzhang/MOEAcompetition/CEC09final/code/ZhangMOEADcode/moead0305.rar
            algorithm.SetInputParameter("dataDirectory", "Data/Parameters/Weight");

            algorithm.SetInputParameter("T", 20);
            algorithm.SetInputParameter("delta", 0.9);
            algorithm.SetInputParameter("nr", 2);

            // Crossover operator
            parameters = new Dictionary <string, object>();
            parameters.Add("CR", 1.0);
            parameters.Add("F", 0.5);
            crossover = CrossoverFactory.GetCrossoverOperator("DifferentialEvolutionCrossover", parameters);

            // Mutation operator
            parameters = new Dictionary <string, object>();
            parameters.Add("probability", 1.0 / problem.NumberOfVariables);
            parameters.Add("distributionIndex", 20.0);
            mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);

            algorithm.AddOperator("crossover", crossover);
            algorithm.AddOperator("mutation", mutation);

            // Execute the Algorithm
            long        initTime      = Environment.TickCount;
            SolutionSet population    = algorithm.Execute();
            long        estimatedTime = Environment.TickCount - initTime;

            // Result messages
            logger.Info("Total execution time: " + estimatedTime + " ms");
            logger.Info("Objectives values have been writen to file FUN");
            population.PrintObjectivesToFile("FUN");
            logger.Info("Variables values have been writen to file VAR");
            population.PrintVariablesToFile("VAR");
            Console.ReadLine();

            if (indicators != null)
            {
                logger.Info("Quality indicators");
                logger.Info("Hypervolume: " + indicators.GetHypervolume(population));
                logger.Info("GD         : " + indicators.GetGD(population));
                logger.Info("IGD        : " + indicators.GetIGD(population));
                logger.Info("Spread     : " + indicators.GetSpread(population));
            }
        }
Ejemplo n.º 22
0
        public Operator GetMutation()
        {
            if (Co2 != "")
            {
                DirPath = "Result/" + Al + "_" + Co + "_" + Co2 + "/" + Pb + "_" + St;
            }
            else
            {
                DirPath = "Result/" + Al + "_" + Co + "/" + Pb + "_" + St;
            }
            if (Directory.Exists(DirPath))
            {
                Console.WriteLine("The directory {0} already exists.", DirPath);
            }
            else
            {
                Directory.CreateDirectory(DirPath);
                Console.WriteLine("The directory {0} was created.", DirPath);
            }

            string filepath = DirPath + "/Parameter.txt";

            string[] line6 = { "probabilityOfMutation " + 1.0 / problem.NumberOfVariables, "distributionIndexOfMutation " + diom, "" };

            Dictionary <string, object> parameters = new Dictionary <string, object>();

            switch (mu)
            {
            case "PolynomialMutation":
                parameters = new Dictionary <string, object>();
                parameters.Add("probability", 1.0 / problem.NumberOfVariables);
                //parameters.Add("probability", 0.2);
                parameters.Add("distributionIndex", double.Parse(diom));
                mutation = MutationFactory.GetMutationOperator("PolynomialMutation", parameters);
                File.AppendAllLines(filepath, line6);
                break;

            case "DynamicPolynomialMutation":
                parameters = new Dictionary <string, object>();
                parameters.Add("probability", 1.0);
                parameters.Add("distributionIndex", double.Parse(diom));
                mutation = MutationFactory.GetMutationOperator("DynamicPolynomialMutation", parameters);
                File.AppendAllLines(filepath, line6);
                break;

            case "BoxMuller":
                parameters.Add("zeta", double.Parse(zeta));
                parameters.Add("probability", 1.0 / problem.NumberOfVariables);
                crossover = MutationFactory.GetMutationOperator("BoxMuller", parameters);
                File.AppendAllLines(filepath, line6);
                break;

            case null:
                break;

            default:
                break;
            }

            return(mutation);
        }
Ejemplo n.º 23
0
        public override bool FireEvent(Event E)
        {
            if (E.ID == "ApplyTonic")
            {
                GameObject target = E.GetGameObjectParameter("Target");
                target.PermuteRandomMutationBuys();
                var       Messages  = new List <string>();
                var       gainLimb  = false;
                Mutations mutations = null;
                if (target.IsPlayer())
                {
                    Popup.Show("As the tonic floods your veins, you feel the latent genetic pressure of eons.");
                }
                if (ParentObject.HasPart("Temporary") && !target.HasPart("Temporary"))
                {
                    Messages.Add((target.IsPlayer() ? "Your" :
                                  Grammar.MakePossessive(target.The + target.ShortDisplayName)) +
                                 " genes ache longingly.");
                }
                else
                {
                    var Random    = Utility.Random(this, target);
                    var goodColor = ColorCoding.ConsequentialColor(ColorAsGoodFor: target);
                    var badColor  = ColorCoding.ConsequentialColor(ColorAsBadFor: target);
                    if (target.IsTrueKin())
                    {
                        var which = new[] { "Strength", "Agility", "Toughness" }.GetRandomElement(Random);
                        if (target.HasStat(which))
                        {
                            ++target.Statistics[which].BaseValue;
                            Messages.Add(goodColor +
                                         (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                         target.GetVerb("gain") + " 1 point of " + which + "!");
                        }
                    }
                    else   /*if mutant*/
                    {
                        mutations = target.GetPart <Mutations>();
                        if (target.IsEsper())
                        {
                            // can't chimerify; reduce glimmer instead
                            int glimmerReduction = Random.Next(1, 5);
                            int currentGlimmer   = target.GetPsychicGlimmer();
                            if (glimmerReduction > currentGlimmer)
                            {
                                glimmerReduction = currentGlimmer;
                            }
                            _ = target.ModIntProperty("GlimmerModifier", -glimmerReduction);
                            target.SyncMutationLevelAndGlimmer();
                            Messages.Add("Nerves weave and ossify, unable to escape " +
                                         (target.IsPlayer() ? "your" : Grammar.MakePossessive(target.the + target.ShortDisplayName)) +
                                         " psychic cage.");
                        }
                        else if (!target.IsChimera())
                        {
                            var mentals       = target.GetMentalMutations();
                            var mentalDefects = target.GetMutationsOfCategory("MentalDefects");
                            var mpToTransfer  = 0;
                            if (mentals.Count > 0 || mentalDefects.Count > 0)
                            {
                                Messages.Add((target.IsPlayer() ? "Your" :
                                              Grammar.MakePossessive(target.The + target.ShortDisplayName)) +
                                             " genome sloughs off superfluous layers of alien thoughtstuff.");
                                Messages.Add("");
                            }
                            if (mentals.Count > 0)
                            {
                                // choose 1d4 MP of investment in mental mutations to remove...
                                mpToTransfer = Random.Next(1, 5);
                                var totalLevels = mentals.Map(m => m.BaseLevel).Sum();
                                var toReduce    = new List <Tuple <BaseMutation, int> >(mpToTransfer);
                                if (totalLevels <= mpToTransfer)
                                {
                                    // remove everything, will be eligible for Chimera
                                    mpToTransfer = totalLevels;
                                    foreach (var mental in mentals)
                                    {
                                        toReduce.Add(Tuple.Create(mental, mental.BaseLevel));
                                    }
                                }
                                else
                                {
                                    // magically pick mpToTransfer mutations weighted by level
                                    var remainingLevels    = totalLevels;
                                    var remainingReduction = mpToTransfer;
                                    foreach (var mental in mentals)
                                    {
                                        var thisMentalReduction = 0;
                                        while (0 < remainingReduction && Random.Next(0, remainingLevels) < mental.BaseLevel - thisMentalReduction + remainingReduction - 1)
                                        {
                                            ++thisMentalReduction;
                                            --remainingLevels;
                                            --remainingReduction;
                                        }
                                        if (0 < thisMentalReduction)
                                        {
                                            toReduce.Add(Tuple.Create(mental, thisMentalReduction));
                                        }
                                        remainingLevels -= mental.BaseLevel - thisMentalReduction;
                                        if (0 >= remainingReduction)
                                        {
                                            break;
                                        }
                                    }
                                }
                                // ... remove them...
                                var lostMentals = new List <MutationEntry>();
                                foreach (var mental in toReduce)
                                {
                                    var mutation  = mental.Item1;
                                    var reduction = mental.Item2;
                                    if (mutation.BaseLevel <= reduction)
                                    {
                                        // remove the mutation altogether
                                        lostMentals.Add(mutation.GetMutationEntry());
                                        mutations.RemoveMutation(mutation);
                                    }
                                    else
                                    {
                                        // reduce the mutation level
                                        mutations.LevelMutation(mutation, mutation.BaseLevel - reduction);
                                    }
                                }
                                // ... and replace any lost mental mutations with physical mutations
                                foreach (var mental in lostMentals)
                                {
                                    // expensive to regenerate this each time, but won't be very many times and
                                    // want to make sure exclusions from e.g. Stinger are handled correctly
                                    Messages.Add(badColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("lose") + " " + mental.DisplayName + "!");
                                    var eligiblePhysicals = mutations.GetMutatePool(m => m.Category.Name.EndsWith("Physical")).Shuffle(Random);
                                    var similarPhysicals  = eligiblePhysicals.Where(p => p.Cost == mental.Cost);
                                    var otherPhysicals    = eligiblePhysicals.Where(p => p.Cost != mental.Cost);
                                    foreach (var physical in similarPhysicals.Concat(otherPhysicals))
                                    {
                                        _ = mutations.AddMutation(physical, 1);
                                        Messages.Add(goodColor +
                                                     (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                     target.GetVerb("gain") + " " + physical.DisplayName + "!");
                                        --mpToTransfer;
                                        break;
                                    } // else if there are no valid physical mutations, don't add anything new
                                }
                            }
                            while (0 < mpToTransfer)
                            {
                                var          physicals        = target.GetPhysicalMutations();
                                BaseMutation which            = null;
                                var          canLevelNormally = physicals.Where(m => m.CanIncreaseLevel());
                                if (canLevelNormally.Any())
                                {
                                    which = canLevelNormally.GetRandomElement(Random);
                                }
                                else
                                {
                                    var underMaxLevel = physicals.Where(m => m.BaseLevel < m.MaxLevel);
                                    if (underMaxLevel.Any())
                                    {
                                        which = underMaxLevel.GetRandomElement(Random);
                                    }
                                }
                                if (which != null)
                                {
                                    mutations.LevelMutation(which, which.BaseLevel + 1);
                                    --mpToTransfer;
                                }
                                else
                                {
                                    // no physical mutations to put the levels in, spend the rest on a new one
                                    foreach (var physical in mutations.GetMutatePool(m => m.Category.Name.EndsWith("Physical")).Shuffle(Random))
                                    {
                                        _ = mutations.AddMutation(physical, 1);
                                        Messages.Add(goodColor +
                                                     (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                     target.GetVerb("gain") + " " + physical.DisplayName + "!");
                                        break;
                                    }
                                    mpToTransfer = 0;
                                }
                            }
                            if (target.GetMentalMutations().Count == 0)
                            {
                                foreach (var mutation in mentalDefects)
                                {
                                    mutations.RemoveMutation(mutation);

                                    var mental = mutation.GetMutationEntry();
                                    Messages.Add(goodColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("lose") + " " + mental.DisplayName + "!");

                                    var eligibleDefects = MutationFactory.GetMutationsOfCategory("PhysicalDefects").Shuffle(Random);
                                    var similarDefects  = eligibleDefects.Where(p => p.Cost == mental.Cost);
                                    var otherDefects    = eligibleDefects.Where(p => p.Cost != mental.Cost);
                                    foreach (var physical in similarDefects.Concat(otherDefects))
                                    {
                                        _ = mutations.AddMutation(physical, 1);
                                        Messages.Add(badColor +
                                                     (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                     target.GetVerb("gain") + " " + physical.DisplayName + "!");
                                        break;
                                    } // else if there are no valid physical defects, don't add anything new
                                }

                                target.Property["MutationLevel"] =
                                    target.Property.GetValueOrDefault("MutationLevel", "") + "Chimera";
                                Messages.Add("");
                                Messages.Add(goodColor +
                                             (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                             target.GetVerb("become") + " a Chimera!");
                            }
                        }
                        else   /*target.IsChimera*/
                        {
                            // 50% chance of new limb, 50% chance of mutation level gain
                            if (Random.Next(2) == 0)
                            {
                                // new limb! defer until the other messages are shown to actually gain it
                                gainLimb = true;
                            }
                            else
                            {
                                var physicals = target.GetPhysicalMutations().Where(m => m.CanLevel());
                                if (physicals.Any())
                                {
                                    // +1 to level of a physical mutation, uncapped
                                    var          which  = physicals.GetRandomElement(Random);
                                    const string source = "{{r-r-r-R-R-W distribution|limbic fluid}} injections";
                                    var          found  = false;
                                    foreach (var mod in mutations.MutationMods)
                                    {
                                        if (mod.sourceName == source && mod.mutationName == which.Name)
                                        {
                                            ++mod.bonus;
                                            found = true;
                                        }
                                    }
                                    if (!found)
                                    {
                                        _ = mutations.AddMutationMod(which.Name, 1, Mutations.MutationModifierTracker.SourceType.StatMod, source);
                                    }
                                    Messages.Add(goodColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("gain") + " one rank of " + which.DisplayName + "!");
                                }
                                else
                                {
                                    // +1 MP if we can't level anything
                                    target.GainMP(1);
                                    Messages.Add(goodColor +
                                                 (target.IsPlayer() ? "You" : target.The + target.ShortDisplayName) +
                                                 target.GetVerb("gain") + " one MP!");
                                }
                            }
                        }
                    }
                }
                if (target.IsPlayer() && Messages.Count > 0)
                {
                    var output = string.Join("\n", Messages);
                    output = _extraLines.Replace(output, "\n\n");
                    Popup.Show(output);
                }
                else
                {
                    foreach (var Message in Messages)
                    {
                        AddPlayerMessage(Message);
                    }
                }
                if (gainLimb)
                {
                    _ = mutations.AddChimericBodyPart();
                }
            }
            return(base.FireEvent(E));
        }