// returns the distance between this cluster and another one // we use a complete link approach for hierarchical clustering, // so this is the maximum distance between two members of each // cluster public float Distance(CandidateCluster other, bool useBestPosition) { // get leaf nodes of this cluster List <CLCandidate> leaves = GetCandidatesInCluster(); // get leaf nodes of other cluster List <CLCandidate> otherLeaves = other.GetCandidatesInCluster(); // compute max distance float distance = 0.0f; foreach (CLCandidate c1 in leaves) { foreach (CLCandidate c2 in otherLeaves) { float d = c1.Distance(c2, useBestPosition); if (d > distance) { distance = d; } } } return(distance); }
/// <summary> /// Initializes a new instance of the <see cref="CandidatesClustering"/> class and performs clusterng /// </summary> /// <param name="solver">Solver, whose found solutions we want to cluster</param> /// <param name="minSat">Minimum sat. We will exclude solutions that do not reach this sat.</param> /// <param name="maxDistance">Max distance.</param> /// <param name="maxClusters">Max clusters. Maximum number of clusters to build</param> public HierarchicalClustering(CLSolver solver, float minSat, bool useBestPosition) { List <CandidateCluster> clusters = new List <CandidateCluster> (); // select only candidates with sat >= minSat and assign each candidate to a cluster for (int i = 0; i < solver.numberOfCandidates; i++) { if (solver.candidates[i].bestEvaluation >= minSat) { clusters.Add(new CandidateCluster(solver.candidates[i])); } } Debug.Log("found " + clusters.Count + " candidates with min sat"); // now, loop until |clusters| = 1 while (clusters.Count > 1) { // compute distances matrix float[,] distances = ComputeDistanceMatrix(clusters, useBestPosition); // find closest clusters int cluster1 = 0; int cluster2 = 0; float minDistance = Mathf.Infinity; for (int i = 0; i < clusters.Count; i++) { for (int j = 0; j < clusters.Count; j++) { if (i > j) // we need to compute distance { if (distances[i, j] < minDistance) { cluster1 = i; cluster2 = j; minDistance = distances[i, j]; } } } } float value1, value2; // select representative if (useBestPosition) { value1 = clusters[cluster1].bestCandidate.bestEvaluation; value2 = clusters[cluster2].bestCandidate.bestEvaluation; } else { value1 = clusters[cluster1].bestCandidate.evaluation; value2 = clusters[cluster2].bestCandidate.evaluation; } int best = (value1 > value2)? cluster1:cluster2; CandidateCluster newCluster = new CandidateCluster(clusters[best].bestCandidate); newCluster.maxDistance = distances[cluster1, cluster2]; newCluster.children.Add(clusters[cluster1]); newCluster.children.Add(clusters[cluster2]); clusters[cluster1].parent = newCluster; clusters[cluster2].parent = newCluster; clusters.Add(newCluster); // remove clusters cluster1 and cluster2 clusters.RemoveAt(cluster1); clusters.RemoveAt(cluster2); } if (clusters.Count > 0) { clustering = clusters [0]; } }