Free cookie consent management tool by TermsFeed Policy Generator

Changeset 17727 for branches/2825-NSGA3


Ignore:
Timestamp:
08/26/20 21:27:42 (4 years ago)
Author:
dleko
Message:

#2825 Refactoring.

Location:
branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/NSGA3.cs

    r17724 r17727  
    11using System;
    22using System.Collections.Generic;
     3using System.IO;
    34using System.Linq;
    45using System.Threading;
     
    1112using HeuristicLab.Parameters;
    1213using HeuristicLab.Problems.TestFunctions.MultiObjective;
     14using HeuristicLab.Problems.TestFunctions.MultiObjective.TestFunctions;
    1315using HeuristicLab.Random;
    1416
     
    6668        private NSGA3Selection selection;
    6769
     70        [Storable]
     71        private double[] allIgds;
     72
    6873        #endregion Storable fields
    6974
     
    7580        private const string MaximumGenerationsName = "Maximum Generations";
    7681        private const string CrossoverProbabilityName = "Crossover Probability";
     82        private const string CrossoverEtaName = "Crossover eta";
    7783        private const string MutationProbabilityName = "Mutation Probability";
    7884        private const string DominateOnEqualQualitiesName = "Dominate On Equal Qualities";
     
    9298        private const string ScatterPlotResultName = "Scatter Plot";
    9399        private const string CurrentFrontResultName = "Pareto Front"; // Do not touch this
     100        private const string RandomSeedUsedName = "Random Seed Used";
    94101
    95102        #endregion ParameterAndResultsNames
     
    112119        }
    113120
     121        private IFixedValueParameter<DoubleValue> CrossoverEtaParameter
     122        {
     123            get { return (IFixedValueParameter<DoubleValue>)Parameters[CrossoverEtaName]; }
     124        }
     125
    114126        private IFixedValueParameter<PercentValue> MutationProbabilityParameter
    115127        {
     
    146158
    147159        public PercentValue CrossoverProbability => CrossoverProbabilityParameter.Value;
     160
     161        public DoubleValue CrossoverEta => CrossoverEtaParameter.Value;
    148162
    149163        public PercentValue MutationProbability => MutationProbabilityParameter.Value;
     
    213227            get { return (DoubleMatrix)Results[CurrentFrontResultName].Value; }
    214228            set { Results[CurrentFrontResultName].Value = value; }
     229        }
     230
     231        public IntValue ResultsRandomSeedUsed
     232        {
     233            get { return (IntValue)Results[RandomSeedUsedName].Value; }
     234            set { Results[RandomSeedUsedName].Value = value; }
    215235        }
    216236
     
    224244            Parameters.Add(new FixedValueParameter<IntValue>(MaximumGenerationsName, "The maximum number of generations which should be processed.", new IntValue(1000)));
    225245            Parameters.Add(new FixedValueParameter<PercentValue>(CrossoverProbabilityName, "The probability that the crossover operator is applied on two parents.", new PercentValue(1.0)));
     246            Parameters.Add(new FixedValueParameter<DoubleValue>(CrossoverEtaName, "TODO: description of this parameter", new DoubleValue(30)));
    226247            Parameters.Add(new FixedValueParameter<PercentValue>(MutationProbabilityName, "The probability that the mutation operator is applied on a Individual.", new PercentValue(0.05)));
    227248            Parameters.Add(new FixedValueParameter<BoolValue>(DominateOnEqualQualitiesName, "Flag which determines wether Individuals with equal quality values should be treated as dominated.", new BoolValue(true)));
     
    231252        }
    232253
    233         // Persistence uses this ctor to improve deserialization efficiency. If we would use the
    234         // default ctor instead this would completely initialize the object (e.g. creating
    235         // parameters) even though the data is later overwritten by the stored data.
    236254        [StorableConstructor]
    237255        public NSGA3(StorableConstructorFlag _) : base(_) { }
     
    245263            referencePoints = original.referencePoints?.Select(cloner.Clone).ToList();
    246264            selection = cloner.Clone(original.selection);
     265            if (original.allIgds != null)
     266            {
     267                allIgds = new double[original.allIgds.Length];
     268                Array.Copy(original.allIgds, allIgds, allIgds.Length);
     269            }
    247270        }
    248271
     
    262285            InitResults();
    263286            InitFields();
    264             Analyze();
     287            Analyze(false);
    265288        }
    266289
     
    276299            Results.Add(new Result(ScatterPlotResultName, "A scatterplot displaying the evaluated solutions and (if available) the analytically optimal front", new ParetoFrontScatterPlot()));
    277300            Results.Add(new Result(CurrentFrontResultName, "The Pareto Front", new DoubleMatrix()));
     301            Results.Add(new Result(RandomSeedUsedName, "The random seed used in the end", new IntValue(-1)));
    278302
    279303            if (!(Problem is MultiObjectiveTestFunctionProblem problem)) return;
    280             // todo: add BestKnownFront parameter
    281             ResultsScatterPlot = new ParetoFrontScatterPlot(new double[0][], new double[0][], problem.BestKnownFront.ToJaggedArray(), problem.Objectives, problem.ProblemSize);
     304            var bestKnownFront = problem.BestKnownFront.ToJaggedArray();
    282305            if (problem.BestKnownFront == null) return;
     306            ResultsScatterPlot = new ParetoFrontScatterPlot(new double[0][], new double[0][], bestKnownFront, problem.Objectives, problem.ProblemSize);
    283307            ResultsBestKnownHypervolume = new DoubleValue(Hypervolume.Calculate(problem.BestKnownFront.ToJaggedArray(), problem.ReferencePoint.CloneAsArray(), problem.Maximization));
    284308        }
     
    286310        private void InitFields()
    287311        {
    288             random = new MersenneTwister();
    289             if (!SetSeedRandomly.Value)
    290                 random.Reset(Seed.Value);
     312            if (SetSeedRandomly.Value)
     313            {
     314                System.Random seedRand = new System.Random();
     315                ResultsRandomSeedUsed.Value = seedRand.Next();
     316                random = new MersenneTwister(Convert.ToUInt32(ResultsRandomSeedUsed.Value));
     317            }
     318            else
     319            {
     320                ResultsRandomSeedUsed.Value = Seed.Value;
     321                random = new MersenneTwister(Convert.ToUInt32(Seed.Value));
     322            }
    291323
    292324            solutions = GetInitialPopulation();
     
    296328
    297329            selection = new NSGA3Selection(problem.Objectives, problem.Maximization, PopulationSize.Value, random, DominateOnEqualQualities.Value);
     330
     331            allIgds = new double[MaximumGenerations.Value];
    298332        }
    299333
     
    311345                RealVector randomRealVector = new RealVector(Problem.Encoding.Length, random, minBound, maxBound);
    312346                var solution = new Solution(randomRealVector);
    313                 solution.Fitness = Evaluate(solution.Chromosome);
     347                solution.Objectives = Evaluate(solution.Chromosome);
    314348                solutions.Add(solution);
    315349            }
     
    328362                while (ResultsCurrentGeneration.Value < MaximumGenerations.Value)
    329363                {
    330                     // todo: make parameter out of this
    331364                    List<Solution> qt = Mutate(Recombine(solutions));
    332365                    foreach (var solution in qt)
    333                         solution.Fitness = Evaluate(solution.Chromosome);
     366                    {
     367                        solution.Objectives = Evaluate(solution.Chromosome);
     368                    }
    334369
    335370                    List<Solution> rt = Utility.Concat(solutions, qt);
     
    337372                    solutions = selection.SelectSolutionsForNextGeneration(rt, GetCopyOfReferencePoints());
    338373
    339                     if (AnalyzeEveryGeneration.Value)
    340                         Analyze();
     374                    Analyze(!AnalyzeEveryGeneration.Value);
    341375
    342376                    ResultsCurrentGeneration.Value++;
     
    354388            finally
    355389            {
    356                 Analyze();
    357             }
     390                Analyze(false);
     391                WriteIGDsToFile();
     392            }
     393        }
     394
     395        private void WriteIGDsToFile()
     396        {
     397            string resultsDirectory = "Results";
     398            Directory.CreateDirectory(resultsDirectory);
     399            var problem = Problem as MultiObjectiveTestFunctionProblem;
     400            string fileName = Path.Combine(resultsDirectory, $"{problem.TestFunction.Name}({problem.Objectives})_DOEQ={DominateOnEqualQualities.Value}_Seed={ResultsRandomSeedUsed.Value}.txt");
     401
     402            File.WriteAllLines(fileName, allIgds.Select(igd => igd.ToString()));
    358403        }
    359404
     
    369414        }
    370415
    371         private void Analyze()
    372         {
    373             ResultsScatterPlot = new ParetoFrontScatterPlot(solutions.Select(x => x.Fitness).ToArray(), solutions.Select(x => x.Chromosome.ToArray()).ToArray(), ResultsScatterPlot.ParetoFront, ResultsScatterPlot.Objectives, ResultsScatterPlot.ProblemSize);
    374             ResultsSolutions = solutions.Select(s => s.Chromosome.ToArray()).ToMatrix();
     416        private void Analyze(bool calculateOnlyIGD)
     417        {
     418            if (!calculateOnlyIGD)
     419            {
     420                ResultsScatterPlot = new ParetoFrontScatterPlot(solutions.Select(x => x.Objectives).ToArray(), solutions.Select(x => x.Chromosome.ToArray()).ToArray(), ResultsScatterPlot.ParetoFront, ResultsScatterPlot.Objectives, ResultsScatterPlot.ProblemSize);
     421                ResultsSolutions = solutions.Select(s => s.Chromosome.ToArray()).ToMatrix();
     422            }
    375423
    376424            if (!(Problem is MultiObjectiveTestFunctionProblem problem)) return;
    377425
    378             // Indicators
    379             ResultsGenerationalDistance = new DoubleValue(problem.BestKnownFront != null ? GenerationalDistance.Calculate(solutions.Select(s => s.Fitness), problem.BestKnownFront.ToJaggedArray(), 1) : double.NaN);
    380             ResultsInvertedGenerationalDistance = new DoubleValue(problem.BestKnownFront != null ? InvertedGenerationalDistance.Calculate(solutions.Select(s => s.Fitness), problem.BestKnownFront.ToJaggedArray(), 1) : double.NaN);
    381 
    382             var front = NonDominatedSelect.GetDominatingVectors(solutions.Select(x => x.Fitness), problem.ReferencePoint.CloneAsArray(), Problem.Maximization, true).ToArray();
    383             if (front.Length == 0) return;
    384             ResultsHypervolume = new DoubleValue(Hypervolume.Calculate(front, problem.ReferencePoint.CloneAsArray(), problem.Maximization));
    385             ResultsDifferenceToBestKnownHypervolume = new DoubleValue(ResultsBestKnownHypervolume.Value - ResultsHypervolume.Value);
    386 
    387             Problem.Analyze(
    388                 solutions.Select(s => (Individual)new SingleEncodingIndividual(Problem.Encoding, new Scope { Variables = { new Variable(Problem.Encoding.Name, s.Chromosome) } })).ToArray(),
    389                 solutions.Select(s => s.Fitness).ToArray(),
    390                 Results,
    391                 random);
     426            CalculateInvertedGenerationalDistance(problem);
     427
     428            if (!calculateOnlyIGD)
     429            {
     430                ResultsGenerationalDistance = new DoubleValue(problem.BestKnownFront != null ? GenerationalDistance.Calculate(solutions.Select(s => s.Objectives), problem.BestKnownFront.ToJaggedArray(), 1) : double.NaN);
     431                var front = NonDominatedSelect.GetDominatingVectors(solutions.Select(x => x.Objectives), problem.ReferencePoint.CloneAsArray(), Problem.Maximization, true).ToArray();
     432                if (front.Length == 0) return;
     433                ResultsHypervolume = new DoubleValue(Hypervolume.Calculate(front, problem.ReferencePoint.CloneAsArray(), problem.Maximization));
     434                ResultsDifferenceToBestKnownHypervolume = new DoubleValue(ResultsBestKnownHypervolume.Value - ResultsHypervolume.Value);
     435
     436                Problem.Analyze(
     437                    solutions.Select(s => (Individual)new SingleEncodingIndividual(Problem.Encoding, new Scope { Variables = { new Variable(Problem.Encoding.Name, s.Chromosome) } })).ToArray(),
     438                    solutions.Select(s => s.Objectives).ToArray(),
     439                    Results,
     440                    random);
     441            }
     442        }
     443
     444        private void CalculateInvertedGenerationalDistance(MultiObjectiveTestFunctionProblem problem)
     445        {
     446            double igd;
     447            if (problem.TestFunction is ScaledDTLZ dtlz)
     448            {
     449                // Normalize objectives before calculating the igd
     450                var scalingFactor = dtlz.GetScalingFactor(problem.Objectives);
     451                var front = new double[solutions.Count][];
     452
     453                for (int i = 0; i < solutions.Count; i++)
     454                {
     455                    front[i] = new double[problem.Objectives];
     456                    Array.Copy(solutions[i].Objectives, front[i], front[i].Length);
     457                    for (int objective = 0; objective < problem.Objectives; objective++)
     458                    {
     459                        // get normalized value
     460                        front[i][objective] = front[i][objective] / Math.Pow(scalingFactor, objective);
     461                    }
     462                }
     463
     464                // Normalize best known front before calculating the igd
     465                var bestKnownFront = problem.BestKnownFront.ToJaggedArray();
     466                foreach (var point in bestKnownFront)
     467                {
     468                    for (int objective = 0; objective < problem.Objectives; objective++)
     469                    {
     470                        point[objective] = point[objective] / Math.Pow(scalingFactor, objective);
     471                    }
     472                }
     473
     474                igd = InvertedGenerationalDistance.Calculate(front, bestKnownFront, 1);
     475            }
     476            else
     477            {
     478                igd = problem.BestKnownFront != null ? InvertedGenerationalDistance.Calculate(solutions.Select(s => s.Objectives), problem.BestKnownFront.ToJaggedArray(), 1) : double.NaN;
     479            }
     480            ResultsInvertedGenerationalDistance = new DoubleValue(igd);
     481            allIgds[ResultsCurrentGeneration.Value - 1] = ResultsInvertedGenerationalDistance.Value;
    392482        }
    393483
     
    403493        }
    404494
    405         // todo: try both recombination methods
    406495        private List<Solution> Recombine(List<Solution> solutions)
    407496        {
    408             //List<Solution> childSolutions = new List<Solution>();
    409             //for (int i = 0; i < solutions.Count; i++)
    410             //{
    411             //    var parent1 = solutions[random.Next(solutions.Count)];
    412             //    var parent2 = solutions[random.Next(solutions.Count)];
    413             //    var childChromosome = HeuristicLab.Encodings.RealVectorEncoding.SimulatedBinaryCrossover.Apply(random, parent1.Chromosome, parent2.Chromosome, new DoubleValue(5));
    414 
    415             // BoundsChecker.Apply(childChromosome, Problem.Encoding.Bounds);
    416 
    417             //    Solution child = new Solution(childChromosome);
    418             //    childSolutions.Add(child);
    419             //}
    420 
    421             //return childSolutions;
    422 
    423497            List<Solution> childSolutions = new List<Solution>();
    424498
    425499            for (int i = 0; i < solutions.Count; i += 2)
    426500            {
     501                if (solutions.Count != PopulationSize.Value) throw new Exception("solutions.Count != PopulationSize");
    427502                int parentIndex1 = random.Next(solutions.Count);
    428503                int parentIndex2 = random.Next(solutions.Count);
     
    434509                // Do crossover with crossoverProbabilty == 1 in order to guarantee that a crossover happens
    435510                var children = SimulatedBinaryCrossover.Apply(random,
    436                     Problem.Encoding.Bounds, parent1.Chromosome, parent2.Chromosome, CrossoverProbability.Value);
     511                    Problem.Encoding.Bounds, parent1.Chromosome, parent2.Chromosome, CrossoverProbability.Value, CrossoverEta.Value);
    437512
    438513                childSolutions.Add(new Solution(children.Item1));
  • branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/NSGA3Selection.cs

    r17724 r17727  
    6767
    6868        /// <summary>
    69         /// TODO: Description If the fitnesses of all solutions in <paramref name="rt" /> do not
    70         /// have the same number of objectives, undefined behavior happens.
     69        /// Select the solutions for the next generation from <see cref="rt" /> according to the
     70        /// NSGA-III algorithm.
    7171        /// </summary>
    72         /// <param name="rt">The previous generation and its mutated children.</param>
     72        /// <param name="rt">The current generation and its mutated children.</param>
    7373        /// <param name="referencePoints"></param>
    7474        /// <returns></returns>
     
    8484                .Select(list => new List<Solution>(list.Select(pair => pair.Item1))).ToList();
    8585
    86             int lf = -1; // last front to be included
    87             for (int i = 0; i < fronts.Count && st.Count < populationSize; i++)
    88             {
    89                 st = Utility.Concat(st, fronts[i]);
    90                 lf = i;
    91             }
     86            int last = 0; // last front to be included
     87            while (st.Count < populationSize)
     88            {
     89                st = Utility.Concat(st, fronts[last++]);
     90            }
     91
    9292            // remove useless fronts
    93             fronts.RemoveRange(lf + 1, fronts.Count - lf - 1);
     93            fronts.RemoveRange(last, fronts.Count - last);
    9494
    9595            List<Solution> nextGeneration = new List<Solution>();
    96             if (st.Count == populationSize) // no special selection needs to be done
     96            if (st.Count == populationSize)
     97            { // no special selection needs to be done
    9798                nextGeneration = st;
     99            }
    98100            else
    99101            {
    100102                // Add every front to the next generation list except for the one that is added only partially
    101103                nextGeneration = new List<Solution>();
    102                 for (int f = 0; f < lf; f++)
     104                for (int f = 0; f < last - 1; f++)
    103105                    nextGeneration = Utility.Concat(nextGeneration, fronts[f]);
     106
    104107                int k = populationSize - nextGeneration.Count;
    105108                Normalize(rt, fronts);
     
    115118        {
    116119            // Find the ideal point
     120            double[] idealPoint = TranslateObjectives(solutions, fronts[0]);
     121
     122            // Find the extreme points
     123            List<Solution> extremePoints = GetExtremePoints(fronts[0]);
     124
     125            // Compute intercepts
     126            double[] intercepts = GetIntercepts(extremePoints, fronts[0]);
     127
     128            // Normalize objectives
     129            NormalizeObjectives(solutions, intercepts, idealPoint);
     130        }
     131
     132        private double[] TranslateObjectives(List<Solution> solutions, List<Solution> firstFront)
     133        {
    117134            double[] idealPoint = new double[numberOfObjectives];
    118 
    119135            foreach (var solution in solutions)
    120                 solution.ConvertedFitness = new double[numberOfObjectives];
     136            {
     137                if (solution.NormalizedObjectives == null) solution.NormalizedObjectives = new double[numberOfObjectives];
     138            }
    121139
    122140            for (int j = 0; j < numberOfObjectives; j++)
    123141            {
    124142                // Compute ideal point
    125                 // todo: search only in first front
    126                 idealPoint[j] = Utility.Min(s => s.Fitness[j], solutions);
    127                 var x = Utility.Min(s => s.Fitness[j], fronts.First());
    128                 if (Math.Abs(idealPoint[j] - x) > 10e-5) throw new Exception("idealPoint value is not in first front");
    129 
    130                 // Translate objectives and save the modified fitness values in ConvertedFitness
     143                idealPoint[j] = Utility.Min(s => s.Objectives[j], firstFront);
     144
     145                // Translate objectives and save the modified fitness values in NormalizedObjectives
    131146                foreach (var solution in solutions)
    132                     solution.ConvertedFitness[j] = solution.Fitness[j] - idealPoint[j];
    133             }
    134 
    135             // Find the extreme points
     147                    solution.NormalizedObjectives[j] = solution.Objectives[j] - idealPoint[j];
     148            }
     149
     150            return idealPoint;
     151        }
     152
     153        private List<Solution> GetExtremePoints(List<Solution> firstFront)
     154        {
    136155            List<Solution> extremePoints = new List<Solution>(numberOfObjectives);
    137156            for (int j = 0; j < numberOfObjectives; j++)
     
    142161                weights[j] = 1;
    143162
    144                 var extremePoint = Utility.ArgMin(s => ASF(s.ConvertedFitness, weights), solutions);
     163                var extremePoint = Utility.ArgMin(s => ASF(s.NormalizedObjectives, weights), firstFront);
    145164                extremePoints.Add(extremePoint);
    146165            }
    147166
    148             // Compute intercepts
    149             double[] intercepts = GetIntercepts(extremePoints, solutions);
    150 
    151             // Normalize objectives
    152             NormalizeObjectives(solutions, intercepts, idealPoint);
     167            return extremePoints;
     168        }
     169
     170        private double ASF(double[] convertedFitness, double[] weight)
     171        {
     172            var dims = Enumerable.Range(0, numberOfObjectives);
     173
     174            return Utility.Max((dim) => convertedFitness[dim] / weight[dim], dims);
     175        }
     176
     177        private double[] GetIntercepts(List<Solution> extremePoints, List<Solution> solutions)
     178        {
     179            // Check whether there are duplicate extreme points. This might happen but the original
     180            // paper does not mention how to deal with it.
     181            bool duplicate = false;
     182            for (int i = 0; !duplicate && i < extremePoints.Count; i++)
     183            {
     184                for (int j = i + 1; !duplicate && j < extremePoints.Count; j++)
     185                {
     186                    duplicate = extremePoints[i] == extremePoints[j];
     187                }
     188            }
     189
     190            double[] intercepts = new double[numberOfObjectives];
     191
     192            bool negative_intercept = false;
     193            if (!duplicate)
     194            {
     195                // Find the equation of the hyperplane
     196                List<double> b = new List<double>(Enumerable.Repeat(1.0, numberOfObjectives));
     197
     198                List<List<double>> a = new List<List<double>>(extremePoints.Count);
     199
     200                for (int i = 0; i < extremePoints.Count; i++)
     201                {
     202                    List<double> convertedFitness = new List<double>(extremePoints[i].NormalizedObjectives);
     203                    a.Add(convertedFitness);
     204                }
     205                List<double> x = GaussianElimination(a, b);
     206
     207                // Find intercepts
     208                for (int i = 0; i < intercepts.Length; i++)
     209                {
     210                    intercepts[i] = 1.0 / x[i];
     211
     212                    if (x[i] < 0)
     213                    {
     214                        negative_intercept = true;
     215                        break;
     216                    }
     217                }
     218            }
     219
     220            // follow the method in Yuan et al. (GECCO 2015)
     221            if (duplicate || negative_intercept)
     222            {
     223                double[] maxObjectives = FindMaxObjectives(solutions);
     224                for (int i = 0; i < intercepts.Length; i++)
     225                    intercepts[i] = maxObjectives[i];
     226            }
     227
     228            return intercepts;
     229        }
     230
     231        private List<double> GaussianElimination(List<List<double>> a, List<double> b)
     232        {
     233            List<double> x = new List<double>();
     234
     235            int n = a.Count;
     236            for (int i = 0; i < n; i++)
     237                a[i].Add(b[i]);
     238
     239            for (int @base = 0; @base < n - 1; @base++)
     240                for (int target = @base + 1; target < n; target++)
     241                {
     242                    double ratio = a[target][@base] / a[@base][@base];
     243                    for (int term = 0; term < a[@base].Count; term++)
     244                        a[target][term] = a[target][term] - a[@base][term] * ratio;
     245                }
     246
     247            for (int i = 0; i < n; i++)
     248                x.Add(0.0);
     249
     250            for (int i = n - 1; i >= 0; i--)
     251            {
     252                for (int known = i + 1; known < n; known++)
     253                    a[i][n] = a[i][n] - a[i][known] * x[known];
     254                x[i] = a[i][n] / a[i][i];
     255            }
     256
     257            return x;
     258        }
     259
     260        private double[] FindMaxObjectives(List<Solution> solutions)
     261        {
     262            double[] maxPoint = new double[numberOfObjectives];
     263            for (int i = 0; i < maxPoint.Length; i++) maxPoint[i] = double.MinValue;
     264
     265            for (int f = 0; f < numberOfObjectives; f++)
     266            {
     267                maxPoint[f] = Utility.Max(s => s.Objectives[f], solutions);
     268            }
     269
     270            return maxPoint;
    153271        }
    154272
     
    159277                for (int i = 0; i < numberOfObjectives; i++)
    160278                {
    161                     // if (Math.Abs(intercepts[i] - idealPoints[i]) > EPSILON)
    162                     if (Math.Abs(intercepts[i]) > EPSILON)
    163                     {
    164                         //solution.ConvertedFitness[i] = solution.ConvertedFitness[i] / (intercepts[i] - idealPoint[i]);
    165                         // todo: try this
    166                         solution.ConvertedFitness[i] = solution.ConvertedFitness[i] / intercepts[i];
     279                    if (Math.Abs(intercepts[i] - idealPoint[i]) > 10e-10)
     280                    {
     281                        solution.NormalizedObjectives[i] = solution.NormalizedObjectives[i] / (intercepts[i] - idealPoint[i]);
    167282                    }
    168283                    else
    169284                    {
    170                         solution.ConvertedFitness[i] = solution.ConvertedFitness[i] / EPSILON;
     285                        solution.NormalizedObjectives[i] = solution.NormalizedObjectives[i] / 10e-10;
    171286                    }
    172287                }
     
    182297                    // find reference point for which the perpendicular distance to the current
    183298                    // solution is the lowest
    184                     var rpAndDist = Utility.MinArgMin(rp => GetPerpendicularDistance(rp.Values, solution.ConvertedFitness), referencePoints);
     299                    var rpAndDist = Utility.MinArgMin(rp => GetPerpendicularDistance(rp.Values, solution.NormalizedObjectives), referencePoints);
    185300                    // associated reference point
    186301                    var arp = rpAndDist.Item1;
     
    190305                    if (f + 1 != fronts.Count)
    191306                    {
    192                         // Todo: Add member for reference point on index min_rp
    193307                        arp.NumberOfAssociatedSolutions++;
    194308                    }
    195309                    else
    196310                    {
    197                         // Todo: Add potential member for reference point on index min_rp
    198311                        arp.AddPotentialAssociatedSolution(solution, dist);
    199312                    }
    200313                }
    201314            }
     315        }
     316
     317        private double GetPerpendicularDistance(double[] direction, double[] point)
     318        {
     319            double numerator = 0;
     320            double denominator = 0;
     321            for (int i = 0; i < direction.Length; i++)
     322            {
     323                numerator += direction[i] * point[i];
     324                denominator += Math.Pow(direction[i], 2);
     325            }
     326            double k = numerator / denominator;
     327
     328            double d = 0;
     329            for (int i = 0; i < direction.Length; i++)
     330            {
     331                d += Math.Pow(k * direction[i] - point[i], 2);
     332            }
     333            return Math.Sqrt(d);
    202334        }
    203335
     
    230362            int minNumber = Utility.Min(rp => rp.NumberOfAssociatedSolutions, referencePoints);
    231363
    232             // todo: try this instead of the current implementation
    233             //var min_rps = new List<ReferencePoint>(referencePoints.Where(r => r.NumberOfAssociatedSolutions == minNumber));
    234             //if (min_rps.Count == 0) return min_rps.Single();
    235             //else return min_rps[random.Next(min_rps.Count)];
    236 
    237             // the reference points that share the number of associated solutions where that number
    238             // is equal to minNumber
    239             List<ReferencePoint> minAssociatedReferencePoints = new List<ReferencePoint>();
    240             foreach (var referencePoint in referencePoints)
    241                 if (referencePoint.NumberOfAssociatedSolutions == minNumber)
    242                     minAssociatedReferencePoints.Add(referencePoint);
    243 
    244             if (minAssociatedReferencePoints.Count > 1)
    245                 return minAssociatedReferencePoints[random.Next(minAssociatedReferencePoints.Count)];
    246             else
    247                 return minAssociatedReferencePoints.Single();
     364            var minReferencePoints = new List<ReferencePoint>(referencePoints.Where(r => r.NumberOfAssociatedSolutions == minNumber));
     365            if (minReferencePoints.Count == 1) return minReferencePoints.Single();
     366            else return minReferencePoints[random.Next(minReferencePoints.Count)];
    248367        }
    249368
     
    260379            return chosen;
    261380        }
    262 
    263         private double GetPerpendicularDistance(double[] values, double[] fitness)
    264         {
    265             double numerator = 0;
    266             double denominator = 0;
    267             for (int i = 0; i < values.Length; i++)
    268             {
    269                 numerator += values[i] * fitness[i];
    270                 denominator += Math.Pow(values[i], 2);
    271             }
    272             double k = numerator / denominator;
    273 
    274             double d = 0;
    275             for (int i = 0; i < values.Length; i++)
    276             {
    277                 d += Math.Pow(k * values[i] - fitness[i], 2);
    278             }
    279             return Math.Sqrt(d);
    280         }
    281 
    282         private double ASF(double[] x, double[] weight)
    283         {
    284             List<int> dimensions = new List<int>();
    285             for (int i = 0; i < numberOfObjectives; i++)
    286                 dimensions.Add(i);
    287 
    288             return Utility.Max((dim) => x[dim] / weight[dim], dimensions);
    289         }
    290 
    291         private double[] GetIntercepts(List<Solution> extremePoints, List<Solution> solutions)
    292         {
    293             // Check whether there are duplicate extreme points. This might happen but the original
    294             // paper does not mention how to deal with it.
    295             bool duplicate = false;
    296             for (int i = 0; !duplicate && i < extremePoints.Count; i++)
    297             {
    298                 for (int j = i + 1; !duplicate && j < extremePoints.Count; j++)
    299                 {
    300                     duplicate = extremePoints[i] == extremePoints[j];
    301                 }
    302             }
    303 
    304             double[] intercepts = new double[numberOfObjectives];
    305 
    306             bool negative_intercept = false;
    307             if (!duplicate)
    308             {
    309                 // Find the equation of the hyperplane
    310                 List<double> b = new List<double>(numberOfObjectives);
    311                 for (int i = 0; i < numberOfObjectives; i++)
    312                     b.Add(1.0);
    313 
    314                 List<List<double>> a = new List<List<double>>(extremePoints.Count);
    315 
    316                 for (int i = 0; i < extremePoints.Count; i++)
    317                 {
    318                     List<double> convertedFitness = new List<double>(extremePoints[i].ConvertedFitness);
    319                     a.Add(convertedFitness);
    320                 }
    321                 List<double> x = GaussianElimination(a, b);
    322 
    323                 // Find intercepts
    324                 for (int i = 0; i < intercepts.Length; i++)
    325                 {
    326                     intercepts[i] = 1.0 / x[i];
    327 
    328                     if (x[i] < 0)
    329                     {
    330                         negative_intercept = true;
    331                         break;
    332                     }
    333                 }
    334             }
    335 
    336             // follow the method in Yuan et al. (GECCO 2015)
    337             if (duplicate || negative_intercept)
    338             {
    339                 double[] maxObjectives = FindMaxObjectives(solutions);
    340                 for (int i = 0; i < intercepts.Length; i++)
    341                     intercepts[i] = maxObjectives[i];
    342             }
    343 
    344             return intercepts;
    345         }
    346 
    347         private double[] FindMaxObjectives(List<Solution> solutions)
    348         {
    349             double[] maxPoint = new double[numberOfObjectives];
    350             for (int i = 0; i < maxPoint.Length; i++) maxPoint[i] = double.MinValue;
    351 
    352             foreach (var solution in solutions)
    353             {
    354                 for (int f = 0; f < numberOfObjectives; f++)
    355                 {
    356                     maxPoint[f] = Math.Max(maxPoint[f], solution.ConvertedFitness[f]);
    357                 }
    358             }
    359 
    360             return maxPoint;
    361         }
    362 
    363         private List<double> GaussianElimination(List<List<double>> a, List<double> b)
    364         {
    365             List<double> x = new List<double>();
    366 
    367             int n = a.Count;
    368             for (int i = 0; i < n; i++)
    369                 a[i].Add(b[i]);
    370 
    371             for (int @base = 0; @base < n - 1; @base++)
    372                 for (int target = @base + 1; target < n; target++)
    373                 {
    374                     double ratio = a[target][@base] / a[@base][@base];
    375                     for (int term = 0; term < a[@base].Count; term++)
    376                         a[target][term] = a[target][term] - a[@base][term] * ratio;
    377                 }
    378 
    379             for (int i = 0; i < n; i++)
    380                 x.Add(0.0);
    381 
    382             for (int i = n - 1; i >= 0; i--)
    383             {
    384                 for (int known = i + 1; known < n; known++)
    385                     a[i][n] = a[i][n] - a[i][known] * x[known];
    386                 x[i] = a[i][n] / a[i][i];
    387             }
    388 
    389             return x;
    390         }
    391381    }
    392382}
  • branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/ReferencePoint.cs

    r17724 r17727  
    227227        }
    228228
    229         internal Solution FindClosestMember()
     229        public Solution FindClosestMember()
    230230        {
    231231            if (!potentialAssociatedSolutions.Any())
     
    235235        }
    236236
    237         internal Solution RandomMember()
     237        public Solution RandomMember()
    238238        {
    239239            if (!potentialAssociatedSolutions.Any())
  • branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/SimulatedBinaryCrossover.cs

    r17657 r17727  
    1111     *
    1212     * The simulated binary crossover in HeuristicLab.Encodings.RealVectorEncoding/Crossovers/SimulatedBinaryCrossover.cs
    13      * is insufficient for NSGA3, because the static Apply-method only returns 1 child.
     13     * is not usable, because it takes different parameters than stated in the NSGA-III paper. It takes contiguity as a
     14     * parameter instead of an eta value.
    1415     */
    1516
     
    1819        private const double EPSILON = 10e-6; // a tiny number that is greater than 0
    1920
    20         public static Tuple<RealVector, RealVector> Apply(IRandom random, DoubleMatrix bounds, RealVector parent1, RealVector parent2, double crossoverProbability = 1.0, double eta = 30)
     21        public static Tuple<RealVector, RealVector> Apply(IRandom random, DoubleMatrix bounds, RealVector parent1, RealVector parent2, double crossoverProbability = 1.0, double eta = 20)
    2122        {
    2223            var child1 = new RealVector(parent1);
     
    3334                double y2 = Math.Max(parent1[i], parent2[i]);
    3435
    35                 // todo: is this correct? test it with Encoding.Length != Number of objectives
    3636                double lb;
    3737                double ub;
  • branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/Solution.cs

    r17724 r17727  
    1515        // actual fitness of solution as given by Problem
    1616        [Storable]
    17         public double[] Fitness { get; set; }
     17        public double[] Objectives { get; set; }
    1818
    1919        // normalized fitness used in selection process (in order to not overwrite the original Fitness)
    2020        [Storable]
    21         public double[] ConvertedFitness { get; set; }
     21        public double[] NormalizedObjectives { get; set; }
    2222
    2323        [StorableConstructor]
     
    3232        {
    3333            Chromosome = cloner.Clone(solution.Chromosome);
    34             if (solution.Fitness != null)
     34            if (solution.Objectives != null)
    3535            {
    36                 Fitness = new double[solution.Fitness.Length];
    37                 Array.Copy(solution.Fitness, Fitness, solution.Fitness.Length);
     36                Objectives = new double[solution.Objectives.Length];
     37                Array.Copy(solution.Objectives, Objectives, solution.Objectives.Length);
    3838            }
    39             if (solution.ConvertedFitness != null)
     39            if (solution.NormalizedObjectives != null)
    4040            {
    41                 ConvertedFitness = new double[solution.ConvertedFitness.Length];
    42                 Array.Copy(solution.ConvertedFitness, ConvertedFitness, solution.ConvertedFitness.Length);
     41                NormalizedObjectives = new double[solution.NormalizedObjectives.Length];
     42                Array.Copy(solution.NormalizedObjectives, NormalizedObjectives, solution.NormalizedObjectives.Length);
    4343            }
    4444        }
  • branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/Utility.cs

    r17724 r17727  
    6969        {
    7070            if (m == null) return null;
    71             var i = m.Rows - 1;
    72             var a = new double[i][];
    73             for (i--; i >= 0; i--)
    74             {
    75                 var j = m.Columns;
    76                 a[i] = new double[j];
    77                 for (j--; j >= 0; j--) a[i][j] = m[i, j];
     71            var a = new double[m.Rows][];
     72            for (int i = m.Rows - 1; i >= 0; i--)
     73            {
     74                a[i] = new double[m.Columns];
     75                for (int j = m.Columns - 1; j >= 0; j--) a[i][j] = m[i, j];
    7876            }
    7977            return a;
     
    9189            {
    9290                Solution solution = solutions[i];
    93                 data[i] = new double[solution.Fitness.Length];
    94                 for (int j = 0; j < solution.Fitness.Length; j++)
     91                data[i] = new double[solution.Objectives.Length];
     92                for (int j = 0; j < solution.Objectives.Length; j++)
    9593                {
    96                     data[i][j] = solution.Fitness[j];
     94                    data[i][j] = solution.Objectives[j];
    9795                }
    9896            }
Note: See TracChangeset for help on using the changeset viewer.