/// <summary> /// Starts the clustering. /// </summary> /// <param name="elements"></param> /// <param name="fusion"></param> /// <param name="metric"></param> /// <returns></returns> protected internal Cluster[] Cluster(List<Element> elements, Fusion fusion, IDistanceMetric metric) { HashSet<Cluster> clusters = new HashSet<Cluster>(); ClusterPairs pairs = new ClusterPairs(); // 1. Initialize each element as a cluster foreach (Element el in elements) { Cluster cl = new Cluster(fusion); cl.AddElement(el); clusters.Add(cl); } // 2. a) Calculate the distances of all clusters to all other clusters foreach (Cluster cl1 in clusters) { foreach (Cluster cl2 in clusters) { if (cl1 == cl2) continue; ClusterPair pair = new ClusterPair(cl1, cl2, cl1.CalculateDistance(cl2)); pairs.AddPair(pair); } } // 2. b) Initialize the pair with the lowest distance to each other. ClusterPair lowestDistancePair = pairs.LowestDistancePair; // 3. Merge clusters to new clusters and recalculate distances in a loop until there are only countCluster clusters while (!isFinished(clusters, lowestDistancePair)) { // a) Merge: Create a new cluster and add the elements of the two old clusters lowestDistancePair = pairs.LowestDistancePair; Cluster newCluster = new Cluster(fusion); newCluster.AddElements(lowestDistancePair.Cluster1.GetElements()); newCluster.AddElements(lowestDistancePair.Cluster2.GetElements()); // b)Remove the two old clusters from clusters clusters.Remove(lowestDistancePair.Cluster1); clusters.Remove(lowestDistancePair.Cluster2); // c) Remove the two old clusters from pairs pairs.RemovePairsByOldClusters(lowestDistancePair.Cluster1, lowestDistancePair.Cluster2); // d) Calculate the distance of the new cluster to all other clusters and save each as pair foreach (Cluster cluster in clusters) { ClusterPair pair = new ClusterPair(cluster, newCluster, cluster.CalculateDistance(newCluster)); pairs.AddPair(pair); } // e) Add the new cluster to clusters clusters.Add(newCluster); } return clusters.ToArray<Cluster>(); }
internal void RemovePairsByOldClusters(Cluster cluster1, Cluster cluster2) { List<ClusterPair> toRemove = new List<ClusterPair>(); foreach(ClusterPair pair in pairs) { if (pair.HasCluster(cluster1) || pair.HasCluster(cluster2)) { toRemove.Add(pair); } } foreach (ClusterPair pair in toRemove) { pairs.Remove(pair); } }
internal bool HasCluster(Cluster cluster) { return cluster1 == cluster || cluster2 == cluster; }
internal float CalculateDistance(Cluster otherCluster) { return fusion.CalculateDistance(this, otherCluster); }
public ClusterPair(Cluster cluster1, Cluster cluster2, float distance) { this.cluster1 = cluster1; this.cluster2 = cluster2; this.distance = distance; }