Changeset 17727 for branches/2825-NSGA3
- Timestamp:
- 08/26/20 21:27:42 (4 years ago)
- 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 1 1 using System; 2 2 using System.Collections.Generic; 3 using System.IO; 3 4 using System.Linq; 4 5 using System.Threading; … … 11 12 using HeuristicLab.Parameters; 12 13 using HeuristicLab.Problems.TestFunctions.MultiObjective; 14 using HeuristicLab.Problems.TestFunctions.MultiObjective.TestFunctions; 13 15 using HeuristicLab.Random; 14 16 … … 66 68 private NSGA3Selection selection; 67 69 70 [Storable] 71 private double[] allIgds; 72 68 73 #endregion Storable fields 69 74 … … 75 80 private const string MaximumGenerationsName = "Maximum Generations"; 76 81 private const string CrossoverProbabilityName = "Crossover Probability"; 82 private const string CrossoverEtaName = "Crossover eta"; 77 83 private const string MutationProbabilityName = "Mutation Probability"; 78 84 private const string DominateOnEqualQualitiesName = "Dominate On Equal Qualities"; … … 92 98 private const string ScatterPlotResultName = "Scatter Plot"; 93 99 private const string CurrentFrontResultName = "Pareto Front"; // Do not touch this 100 private const string RandomSeedUsedName = "Random Seed Used"; 94 101 95 102 #endregion ParameterAndResultsNames … … 112 119 } 113 120 121 private IFixedValueParameter<DoubleValue> CrossoverEtaParameter 122 { 123 get { return (IFixedValueParameter<DoubleValue>)Parameters[CrossoverEtaName]; } 124 } 125 114 126 private IFixedValueParameter<PercentValue> MutationProbabilityParameter 115 127 { … … 146 158 147 159 public PercentValue CrossoverProbability => CrossoverProbabilityParameter.Value; 160 161 public DoubleValue CrossoverEta => CrossoverEtaParameter.Value; 148 162 149 163 public PercentValue MutationProbability => MutationProbabilityParameter.Value; … … 213 227 get { return (DoubleMatrix)Results[CurrentFrontResultName].Value; } 214 228 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; } 215 235 } 216 236 … … 224 244 Parameters.Add(new FixedValueParameter<IntValue>(MaximumGenerationsName, "The maximum number of generations which should be processed.", new IntValue(1000))); 225 245 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))); 226 247 Parameters.Add(new FixedValueParameter<PercentValue>(MutationProbabilityName, "The probability that the mutation operator is applied on a Individual.", new PercentValue(0.05))); 227 248 Parameters.Add(new FixedValueParameter<BoolValue>(DominateOnEqualQualitiesName, "Flag which determines wether Individuals with equal quality values should be treated as dominated.", new BoolValue(true))); … … 231 252 } 232 253 233 // Persistence uses this ctor to improve deserialization efficiency. If we would use the234 // default ctor instead this would completely initialize the object (e.g. creating235 // parameters) even though the data is later overwritten by the stored data.236 254 [StorableConstructor] 237 255 public NSGA3(StorableConstructorFlag _) : base(_) { } … … 245 263 referencePoints = original.referencePoints?.Select(cloner.Clone).ToList(); 246 264 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 } 247 270 } 248 271 … … 262 285 InitResults(); 263 286 InitFields(); 264 Analyze( );287 Analyze(false); 265 288 } 266 289 … … 276 299 Results.Add(new Result(ScatterPlotResultName, "A scatterplot displaying the evaluated solutions and (if available) the analytically optimal front", new ParetoFrontScatterPlot())); 277 300 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))); 278 302 279 303 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(); 282 305 if (problem.BestKnownFront == null) return; 306 ResultsScatterPlot = new ParetoFrontScatterPlot(new double[0][], new double[0][], bestKnownFront, problem.Objectives, problem.ProblemSize); 283 307 ResultsBestKnownHypervolume = new DoubleValue(Hypervolume.Calculate(problem.BestKnownFront.ToJaggedArray(), problem.ReferencePoint.CloneAsArray(), problem.Maximization)); 284 308 } … … 286 310 private void InitFields() 287 311 { 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 } 291 323 292 324 solutions = GetInitialPopulation(); … … 296 328 297 329 selection = new NSGA3Selection(problem.Objectives, problem.Maximization, PopulationSize.Value, random, DominateOnEqualQualities.Value); 330 331 allIgds = new double[MaximumGenerations.Value]; 298 332 } 299 333 … … 311 345 RealVector randomRealVector = new RealVector(Problem.Encoding.Length, random, minBound, maxBound); 312 346 var solution = new Solution(randomRealVector); 313 solution. Fitness = Evaluate(solution.Chromosome);347 solution.Objectives = Evaluate(solution.Chromosome); 314 348 solutions.Add(solution); 315 349 } … … 328 362 while (ResultsCurrentGeneration.Value < MaximumGenerations.Value) 329 363 { 330 // todo: make parameter out of this331 364 List<Solution> qt = Mutate(Recombine(solutions)); 332 365 foreach (var solution in qt) 333 solution.Fitness = Evaluate(solution.Chromosome); 366 { 367 solution.Objectives = Evaluate(solution.Chromosome); 368 } 334 369 335 370 List<Solution> rt = Utility.Concat(solutions, qt); … … 337 372 solutions = selection.SelectSolutionsForNextGeneration(rt, GetCopyOfReferencePoints()); 338 373 339 if (AnalyzeEveryGeneration.Value) 340 Analyze(); 374 Analyze(!AnalyzeEveryGeneration.Value); 341 375 342 376 ResultsCurrentGeneration.Value++; … … 354 388 finally 355 389 { 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())); 358 403 } 359 404 … … 369 414 } 370 415 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 } 375 423 376 424 if (!(Problem is MultiObjectiveTestFunctionProblem problem)) return; 377 425 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; 392 482 } 393 483 … … 403 493 } 404 494 405 // todo: try both recombination methods406 495 private List<Solution> Recombine(List<Solution> solutions) 407 496 { 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 423 497 List<Solution> childSolutions = new List<Solution>(); 424 498 425 499 for (int i = 0; i < solutions.Count; i += 2) 426 500 { 501 if (solutions.Count != PopulationSize.Value) throw new Exception("solutions.Count != PopulationSize"); 427 502 int parentIndex1 = random.Next(solutions.Count); 428 503 int parentIndex2 = random.Next(solutions.Count); … … 434 509 // Do crossover with crossoverProbabilty == 1 in order to guarantee that a crossover happens 435 510 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); 437 512 438 513 childSolutions.Add(new Solution(children.Item1)); -
branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/NSGA3Selection.cs
r17724 r17727 67 67 68 68 /// <summary> 69 /// TODO: Description If the fitnesses of all solutions in <paramref name="rt" /> do not70 /// 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. 71 71 /// </summary> 72 /// <param name="rt">The previousgeneration and its mutated children.</param>72 /// <param name="rt">The current generation and its mutated children.</param> 73 73 /// <param name="referencePoints"></param> 74 74 /// <returns></returns> … … 84 84 .Select(list => new List<Solution>(list.Select(pair => pair.Item1))).ToList(); 85 85 86 int l f = -1; // last front to be included87 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 92 92 // remove useless fronts 93 fronts.RemoveRange(l f + 1, fronts.Count - lf - 1);93 fronts.RemoveRange(last, fronts.Count - last); 94 94 95 95 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 97 98 nextGeneration = st; 99 } 98 100 else 99 101 { 100 102 // Add every front to the next generation list except for the one that is added only partially 101 103 nextGeneration = new List<Solution>(); 102 for (int f = 0; f < l f; f++)104 for (int f = 0; f < last - 1; f++) 103 105 nextGeneration = Utility.Concat(nextGeneration, fronts[f]); 106 104 107 int k = populationSize - nextGeneration.Count; 105 108 Normalize(rt, fronts); … … 115 118 { 116 119 // 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 { 117 134 double[] idealPoint = new double[numberOfObjectives]; 118 119 135 foreach (var solution in solutions) 120 solution.ConvertedFitness = new double[numberOfObjectives]; 136 { 137 if (solution.NormalizedObjectives == null) solution.NormalizedObjectives = new double[numberOfObjectives]; 138 } 121 139 122 140 for (int j = 0; j < numberOfObjectives; j++) 123 141 { 124 142 // 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 131 146 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 { 136 155 List<Solution> extremePoints = new List<Solution>(numberOfObjectives); 137 156 for (int j = 0; j < numberOfObjectives; j++) … … 142 161 weights[j] = 1; 143 162 144 var extremePoint = Utility.ArgMin(s => ASF(s. ConvertedFitness, weights), solutions);163 var extremePoint = Utility.ArgMin(s => ASF(s.NormalizedObjectives, weights), firstFront); 145 164 extremePoints.Add(extremePoint); 146 165 } 147 166 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; 153 271 } 154 272 … … 159 277 for (int i = 0; i < numberOfObjectives; i++) 160 278 { 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]); 167 282 } 168 283 else 169 284 { 170 solution. ConvertedFitness[i] = solution.ConvertedFitness[i] / EPSILON;285 solution.NormalizedObjectives[i] = solution.NormalizedObjectives[i] / 10e-10; 171 286 } 172 287 } … … 182 297 // find reference point for which the perpendicular distance to the current 183 298 // 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); 185 300 // associated reference point 186 301 var arp = rpAndDist.Item1; … … 190 305 if (f + 1 != fronts.Count) 191 306 { 192 // Todo: Add member for reference point on index min_rp193 307 arp.NumberOfAssociatedSolutions++; 194 308 } 195 309 else 196 310 { 197 // Todo: Add potential member for reference point on index min_rp198 311 arp.AddPotentialAssociatedSolution(solution, dist); 199 312 } 200 313 } 201 314 } 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); 202 334 } 203 335 … … 230 362 int minNumber = Utility.Min(rp => rp.NumberOfAssociatedSolutions, referencePoints); 231 363 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)]; 248 367 } 249 368 … … 260 379 return chosen; 261 380 } 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 original294 // 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 hyperplane310 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 intercepts324 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 }391 381 } 392 382 } -
branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/ReferencePoint.cs
r17724 r17727 227 227 } 228 228 229 internalSolution FindClosestMember()229 public Solution FindClosestMember() 230 230 { 231 231 if (!potentialAssociatedSolutions.Any()) … … 235 235 } 236 236 237 internalSolution RandomMember()237 public Solution RandomMember() 238 238 { 239 239 if (!potentialAssociatedSolutions.Any()) -
branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/SimulatedBinaryCrossover.cs
r17657 r17727 11 11 * 12 12 * 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. 14 15 */ 15 16 … … 18 19 private const double EPSILON = 10e-6; // a tiny number that is greater than 0 19 20 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) 21 22 { 22 23 var child1 = new RealVector(parent1); … … 33 34 double y2 = Math.Max(parent1[i], parent2[i]); 34 35 35 // todo: is this correct? test it with Encoding.Length != Number of objectives36 36 double lb; 37 37 double ub; -
branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/Solution.cs
r17724 r17727 15 15 // actual fitness of solution as given by Problem 16 16 [Storable] 17 public double[] Fitness { get; set; }17 public double[] Objectives { get; set; } 18 18 19 19 // normalized fitness used in selection process (in order to not overwrite the original Fitness) 20 20 [Storable] 21 public double[] ConvertedFitness { get; set; }21 public double[] NormalizedObjectives { get; set; } 22 22 23 23 [StorableConstructor] … … 32 32 { 33 33 Chromosome = cloner.Clone(solution.Chromosome); 34 if (solution. Fitness != null)34 if (solution.Objectives != null) 35 35 { 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); 38 38 } 39 if (solution. ConvertedFitness != null)39 if (solution.NormalizedObjectives != null) 40 40 { 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); 43 43 } 44 44 } -
branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/Utility.cs
r17724 r17727 69 69 { 70 70 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]; 78 76 } 79 77 return a; … … 91 89 { 92 90 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++) 95 93 { 96 data[i][j] = solution. Fitness[j];94 data[i][j] = solution.Objectives[j]; 97 95 } 98 96 }
Note: See TracChangeset
for help on using the changeset viewer.