Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.VRPEnhancements/HeuristicLab.Problems.VehicleRouting/3.4/Encodings/Potvin/Creators/Cluster.cs @ 14431

Last change on this file since 14431 was 14431, checked in by jzenisek, 7 years ago

#2707 updated clustering: implemented a quite generic version

File size: 8.4 KB
Line 
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using HeuristicLab.Core;
5using HeuristicLab.Problems.VehicleRouting.Interfaces;
6
7namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
8
9  public class ClusterAlgorithm<C,CO> where C : Cluster<CO> where CO : ClusterElement {
10
11    public static List<C> KMeans(IRandom random, List<CO> clusterElements, int k, double changeThreshold, bool minimizeImpact) {
12      HashSet<int> initMeans = new HashSet<int>();
13      int nextMean = -1;
14
15      List<C> clusters = CreateCList();
16
17      // (1) initialize each cluster with a random element as mean
18      for (int i = 0; i < k && i < clusterElements.Count; i++) {
19        C cluster = (C)Activator.CreateInstance(typeof(C));
20        cluster.Id = i;
21
22        do {
23          nextMean = random.Next(0, clusterElements.Count);
24        } while (initMeans.Contains(nextMean));
25        initMeans.Add(nextMean);
26        cluster.SetMean(clusterElements[nextMean]);
27        clusters.Add(cluster);
28      }
29
30      // (2) repeat clustering until change rate is below threshold
31      double changeRate = 0.0;
32
33      do {
34        int changes = KMeansRun(clusters, clusterElements, minimizeImpact);
35        changeRate = (double)changes / clusterElements.Count;
36      } while (changeRate > changeThreshold);
37
38
39      // remove empty clusters
40      clusters.RemoveAll(c => c.Elements.Count.Equals(0));
41
42      return clusters;
43    }
44
45    private static int KMeansRun(List<C> clusters, List<CO> clusterElements, bool minimizeImpact) {
46      int changes = 0;
47
48      // clear clusters from previous assigned elements
49      foreach (var c in clusters) {
50        c.Elements.Clear();
51      }
52
53      // assign elements to currently most suitable clusters
54      foreach (var e in clusterElements) {
55        int optClusterIdx = 0;
56        double optImpact = clusters[optClusterIdx].CalculateImpact(e);
57        for (int i = 1; i < clusters.Count; i++) {
58          double impact = clusters[i].CalculateImpact(e);
59          if (
60            // optimal impact: max variance decrease (biggest negative or smallest positive value)
61            (minimizeImpact && impact < optImpact) ||
62            // optimal impact: min variance increase, if no increase possible: min decrease (smallest negative or positive value)
63            //(!minimizeImpact && ((optImpact > 0 && impact < optImpact) || (optImpact < 0 && impact > optImpact)))) {
64            (!minimizeImpact && impact > optImpact)
65            ) {
66
67            optImpact = impact;
68            optClusterIdx = i;
69          }
70        }
71        if (clusters[optClusterIdx].AddObject(e)) {
72          changes++;
73        }
74      }
75
76      // update mean and variance
77      foreach (var c in clusters) {
78        c.CalculateMean();
79        c.CalculateVariance();
80      }
81
82      return changes;
83    }
84
85    private static List<C> CreateCList() {
86      var listType = typeof(List<>);
87      var constructedListType = listType.MakeGenericType(typeof(C));
88      return (List<C>)Activator.CreateInstance(constructedListType);
89    }
90  }
91
92  #region Cluster
93  public interface ICluster<T> where T : ClusterElement {
94    void SetMean(T o);
95    bool AddObject(T o);
96    void CalculateMean();
97    void CalculateVariance();
98    double CalculateImpact(T e);
99    double CalculateDistance(T e1, T e2);
100
101  }
102  public abstract class Cluster<T> : ICluster<T> where T : ClusterElement {
103    public int Id;
104
105    public List<T> Elements { get; private set; }
106
107    public T Mean { get; set; }
108
109    public double Variance { get; set; }
110
111    protected Cluster() {
112      Elements = new List<T>();
113    }
114
115    protected Cluster(int id) {
116      Id = id;
117      Elements = new List<T>();
118
119    }
120
121    public bool AddObject(T e) {
122      Elements.Add(e);
123
124      bool clusterChanged = e.ClusterId != Id;
125      e.ClusterId = Id;
126      return clusterChanged;
127    }
128
129    public void SetMean(T e) {
130      Mean = e;
131      Mean.ClusterId = Id;
132    }
133
134    public abstract void CalculateMean();
135
136    public abstract double CalculateDistance(T e1, T e2);
137
138    public virtual void CalculateVariance() {
139      if (Mean == null)
140        CalculateMean();
141
142      Variance = 0.0;
143      foreach (T e in Elements) {
144        Variance += Math.Pow(CalculateDistance(Mean, e), 2);
145      }
146      Variance /= Elements.Count;
147    }
148
149    public virtual double CalculateImpact(T e) {
150      if (Mean == null)
151        CalculateMean();
152
153      double newVariance = (Variance * Elements.Count + Math.Pow(CalculateDistance(Mean, e), 2)) / (Elements.Count + 1);
154      return newVariance - Variance;
155    }
156
157  }
158  public class SpatialDistanceCluster : Cluster<SpatialDistanceClusterElement> {
159    public SpatialDistanceCluster() : base() {
160    }
161
162    public SpatialDistanceCluster(int id) : base(id) {
163    }
164
165    public override void CalculateMean() {
166      int dimensions = (Mean != null) ? Mean.Coordinates.Length : (Elements.Count > 0) ? Elements[0].Coordinates.Length : 0;
167      SpatialDistanceClusterElement mean = new SpatialDistanceClusterElement(-1, dimensions, Id);
168      foreach (SpatialDistanceClusterElement e in Elements) {
169        for (int i = 0; i < Mean.Coordinates.Length; i++) {
170          mean.Coordinates[i] += (e.Coordinates[i] / Elements.Count);
171        }
172      }
173      Mean = mean;
174    }
175
176    public override double CalculateDistance(SpatialDistanceClusterElement e1, SpatialDistanceClusterElement e2) {
177      if (!e1.Coordinates.Length.Equals(e2.Coordinates.Length)) {
178        throw new ArgumentException("Distance could not be calculated since number of dimensions is unequal.");
179      }
180
181      double distance = 0.0;
182      for (int i = 0; i < e1.Coordinates.Length; i++) {
183        distance += Math.Pow(e1.Coordinates[i] - e2.Coordinates[i], 2);
184      }
185
186      return Math.Sqrt(distance);
187    }
188  }
189
190  public class TemporalDistanceCluster : Cluster<TemporalDistanceClusterElement> {
191    public TemporalDistanceCluster() : base() {
192    }
193
194    public TemporalDistanceCluster(int id) : base(id) {
195    }
196
197    public override void CalculateMean() {
198      TemporalDistanceClusterElement mean = new TemporalDistanceClusterElement(-1, Id);
199      foreach (TemporalDistanceClusterElement e in Elements) {
200        mean.ReadyTime += e.ReadyTime/Elements.Count;
201        mean.DueTime += e.DueTime/Elements.Count;
202      }
203      Mean = mean;
204    }
205
206    public override double CalculateDistance(TemporalDistanceClusterElement e1, TemporalDistanceClusterElement e2) {
207      double distance = 0.0;
208      distance += Math.Abs(e1.ReadyTime - e2.ReadyTime);
209      distance += Math.Abs(e1.DueTime - e2.DueTime);
210
211      return distance;
212      //return euklid(e1, e2);
213    }
214
215    private double euklid(TemporalDistanceClusterElement e1, TemporalDistanceClusterElement e2) {
216      double distance = 0.0;
217      distance += Math.Pow(e1.ReadyTime - e2.ReadyTime + e1.DueTime - e2.DueTime, 2);
218
219      return Math.Sqrt(distance);
220    }
221  }
222
223  #endregion Cluster
224
225  #region ClusterElement
226  public abstract class ClusterElement {
227    public int Id { get; set; }
228    public int ClusterId { get; set; }
229
230    protected ClusterElement() {
231      ClusterId = -1;
232    }
233
234    public ClusterElement(int id, int clusterId = -1) {
235      Id = id;
236      ClusterId = clusterId;
237    }
238  }
239  public class SpatialDistanceClusterElement : ClusterElement {
240
241    public double[] Coordinates { get; set; }
242
243    public SpatialDistanceClusterElement() : base() {
244    }
245
246    public SpatialDistanceClusterElement(int id, int clusterId = -1) : base(id, clusterId) {
247    }
248
249    public SpatialDistanceClusterElement(int id, double[] coordinates, int clusterId = -1) : base(id, clusterId) {
250      Coordinates = coordinates;
251    }
252
253    public SpatialDistanceClusterElement(int id, int dimensions, int clusterId = -1) : base(id, clusterId) {
254      Coordinates = new double[dimensions];
255    }
256
257  }
258
259  public class TemporalDistanceClusterElement : ClusterElement {
260    public double ReadyTime { get; set; }
261    public double DueTime { get; set; }
262
263    public TemporalDistanceClusterElement() : base() {
264    }
265
266    public TemporalDistanceClusterElement(int id, int clusterId = -1) : base(id, clusterId) {
267    }
268
269    public TemporalDistanceClusterElement(int id, double readyTime, double dueTime, int clusterId = -1) : base(id, clusterId) {
270      ReadyTime = readyTime;
271      DueTime = dueTime;
272    }
273  }
274
275  #endregion ClusterElement
276}
Note: See TracBrowser for help on using the repository browser.