Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2825-NSGA3/HeuristicLab.Algorithms.NSGA3/3.3/ReferencePoint.cs @ 17958

Last change on this file since 17958 was 17727, checked in by dleko, 4 years ago

#2825 Refactoring.

File size: 9.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using HEAL.Attic;
5using HeuristicLab.Common;
6using HeuristicLab.Core;
7
8namespace HeuristicLab.Algorithms.NSGA3
9{
10    [StorableType("5026513A-F3C7-4A85-95D6-82B5B376E900")]
11    public class ReferencePoint : IDeepCloneable
12    {
13        #region Properties
14
15        // The potentially associated solutions to this reference point and the distance to that solution
16        private Dictionary<Solution, double> potentialAssociatedSolutions = new Dictionary<Solution, double>();
17
18        [Storable]
19        private IRandom random;
20
21        [Storable]
22        public double[] Values { get; set; }
23
24        [Storable]
25        public int NumberOfAssociatedSolutions { get; set; } = 0;
26
27        #endregion Properties
28
29        #region Constructors
30
31        [StorableConstructor]
32        public ReferencePoint(StorableConstructorFlag _) { }
33
34        public ReferencePoint(IRandom random, int obj)
35        {
36            this.random = random;
37            Values = new double[obj];
38        }
39
40        public ReferencePoint(ReferencePoint other, Cloner cloner)
41        {
42            random = cloner.Clone(other.random);
43            Values = new double[other.Values.Length];
44            Array.Copy(other.Values, Values, Values.Length);
45        }
46
47        public ReferencePoint(ReferencePoint other)
48        {
49            random = other.random;
50            Values = new double[other.Values.Length];
51            Array.Copy(other.Values, Values, Values.Length);
52        }
53
54        public IDeepCloneable Clone(Cloner cloner)
55        {
56            return new ReferencePoint(this, cloner);
57        }
58
59        public object Clone()
60        {
61            return new Cloner().Clone(this);
62        }
63
64        #endregion Constructors
65
66        #region Static methods
67
68        public static Tuple<int, int> GetDivisions(int obj)
69        {
70            switch (obj)
71            {
72                case 3:
73                    return Tuple.Create(12, 0);
74
75                case 5:
76                    return Tuple.Create(6, 0);
77
78                case 8:
79                    return Tuple.Create(3, 2);
80
81                case 10:
82                    return Tuple.Create(3, 2);
83
84                case 15:
85                    return Tuple.Create(2, 1);
86
87                default:
88                    return null;
89            }
90        }
91
92        /// <summary>
93        /// Returns the number of reference points that would be created when using <see
94        /// cref="GenerateReferencePoints(IRandom, int)" />.
95        /// </summary>
96        /// <param name="obj"></param>
97        /// <returns></returns>
98        public static int GetNumberOfGeneratedReferencePoints(int obj)
99        {
100            Tuple<int, int> division = GetDivisions(obj);
101            if (division == null) return -1;
102
103            return GetNumberOfGeneratedReferencePoints(obj, division.Item1, division.Item2);
104        }
105
106        public static int GetNumberOfGeneratedReferencePoints(int obj, int outerDiv, int innerDiv = 0)
107        {
108            int outerPoints = Utility.NCR(obj + outerDiv - 1, outerDiv);
109            int innerPoints = innerDiv == 0 ? 0 : Utility.NCR(obj + innerDiv - 1, innerDiv);
110            return outerPoints + innerPoints;
111        }
112
113        public static int GetPopulationSizeForReferencePoints(int referencePoints)
114        {
115            return (referencePoints + 3) / 4 * 4;
116        }
117
118        /// <summary>
119        /// Generate reference points that are evenly distributed over a hyperplane with dimensions
120        /// <paramref name="obj" /> - 1 with the sum of the values in all dimensions being equal to
121        /// 1 for each reference point. <paramref name="obj" /> may only be one of {3, 5, 8, 10, 15}
122        /// -&gt; The number of inner divisions and outer divisions are determined based on the
123        /// values provided in the NSGA-III paper, chapter V: Results. If different dimensions are
124        /// given, a NotSupportedException is thrown.
125        /// </summary>
126        /// <param name="random">
127        /// The <see cref="IRandom" /> to give as a parameter to the ReferencePoint constructors.
128        /// </param>
129        /// <param name="obj">The dimensionality of the Reference Points</param>
130        /// <returns></returns>
131        public static List<ReferencePoint> GenerateReferencePoints(IRandom random, int obj)
132        {
133            Tuple<int, int> divisions = GetDivisions(obj);
134
135            if (divisions == null) return null;
136            return GenerateReferencePoints(random, obj, divisions.Item1, divisions.Item2);
137        }
138
139        /*
140         * This method is based on Tsung-Che Chiang's NSGA-III implementation (version 1.20)
141         * http://web.ntnu.edu.tw/~tcchiang/publications/nsga3cpp/nsga3cpp.htm
142         */
143
144        /// <summary>
145        /// Generate reference points that are evenly distributed over a hyperplane with dimensions
146        /// <paramref name="obj" /> - 1 with the sum of the values in all dimensions being equal to
147        /// 1 for each reference point.
148        /// </summary>
149        /// <param name="obj">The number of dimensions for the reference points.</param>
150        /// <param name="outerDiv">The number of divisions for the outer reference points</param>
151        /// <returns>The generated reference points (Check Fig. 4 in NSGA-III paper).</returns>
152        /// <param name="innerDiv">The number of divisions for the inner reference points</param>
153        /// <returns>
154        /// The generated reference points (Check Fig. 4 in NSGA-III paper). Set to 0, in order to
155        /// not have inner reference points
156        /// </returns>
157        public static List<ReferencePoint> GenerateReferencePoints(IRandom random, int obj, int outerDiv, int innerDiv = 0)
158        {
159            if (obj <= 0) throw new ArgumentException("obj must be greater than 0");
160            if (outerDiv <= 1) throw new ArgumentException("outerDiv must be greater than 1");
161
162            List<ReferencePoint> referencePoints = new List<ReferencePoint>();
163            ReferencePoint refPoint = new ReferencePoint(random, obj);
164            GenerateRecursive(referencePoints, refPoint, obj, outerDiv, outerDiv, 0);
165
166            if (innerDiv > 0)
167            {
168                List<ReferencePoint> insideReferencePoints = new List<ReferencePoint>();
169                GenerateRecursive(insideReferencePoints, refPoint, obj, innerDiv, innerDiv, 0);
170
171                double center = 1.0 / obj;
172
173                for (int i = 0; i < insideReferencePoints.Count; i++)
174                {
175                    for (int j = 0; j < insideReferencePoints[i].Values.Length; j++)
176                    {
177                        insideReferencePoints[i].Values[j] = (center + insideReferencePoints[i].Values[j]) / 2;
178                    }
179                    referencePoints.Add(insideReferencePoints[i]);
180                }
181            }
182
183            return referencePoints;
184        }
185
186        /*
187         * This method is based on Tsung-Che Chiang's NSGA-III implementation (version 1.20)
188         * http://web.ntnu.edu.tw/~tcchiang/publications/nsga3cpp/nsga3cpp.htm
189         */
190
191        private static void GenerateRecursive(List<ReferencePoint> referencePoints, ReferencePoint refPoint, int numberOfObjectives, int left, int total, int element)
192        {
193            if (element == numberOfObjectives - 1)
194            {
195                refPoint.Values[element] = ((double)left) / total;
196                var newRefPoint = (ReferencePoint)refPoint.Clone();
197                referencePoints.Add(newRefPoint);
198            }
199            else
200            {
201                for (int i = 0; i <= left; i++)
202                {
203                    refPoint.Values[element] = (double)i / total;
204                    GenerateRecursive(referencePoints, refPoint, numberOfObjectives, left - i, total, element + 1);
205                }
206            }
207        }
208
209        #endregion Static methods
210
211        public void AddPotentialAssociatedSolution(Solution s, double distance)
212        {
213            if (potentialAssociatedSolutions.ContainsKey(s))
214                throw new InvalidOperationException("Given solution was already added as a potential solution");
215
216            potentialAssociatedSolutions.Add(s, distance);
217        }
218
219        public void RemovePotentialAssociatedSolution(Solution s)
220        {
221            potentialAssociatedSolutions.Remove(s);
222        }
223
224        public bool HasPotentialMember()
225        {
226            return potentialAssociatedSolutions.Any();
227        }
228
229        public Solution FindClosestMember()
230        {
231            if (!potentialAssociatedSolutions.Any())
232                throw new InvalidOperationException("No potential members exist");
233
234            return Utility.ArgMin(pair => pair.Value, potentialAssociatedSolutions).Key;
235        }
236
237        public Solution RandomMember()
238        {
239            if (!potentialAssociatedSolutions.Any())
240                throw new InvalidOperationException("No potential members exist");
241
242            return potentialAssociatedSolutions.Keys.ElementAt(random.Next(potentialAssociatedSolutions.Count));
243        }
244    }
245}
Note: See TracBrowser for help on using the repository browser.