/// <summary> /// Finds exactly the cluster closest to the cluster whose label matches color1 and the points /// in each cluster that are closest, along with the square distance between them. /// </summary> /// <param name="color1">Label of the cluster whose nearest neighbor is being sought.</param> /// <returns>A point in the cluster corresponding to color1, the closest point to it /// from another cluster, the square distance between the points, and the label of the other cluster. /// NOTE: ClosestPair.Color1 will equal color1. /// </returns> public ClosestPair FindClusterExhaustively(TLabel color1) { var shortest = new ClosestPair(); foreach (var p1 in Clusters.PointsInClass(color1)) { foreach (var pc in Clusters.Points() .Select(p => new { Point = p, Color = Clusters.GetClassLabel(p) }) .Where(pc => !color1.Equals(pc.Color))) { var d = p1.Measure(pc.Point); if (d < shortest.SquareDistance) { shortest.SquareDistance = d; shortest.Color1 = color1; shortest.Point1 = p1; shortest.Color2 = pc.Color; shortest.Point2 = pc.Point; } } } //TODO: If there is only one cluster, the if statement above will not be triggered and shortest will // be ill-defined and cause a Null Pointer exception in Swap. return(shortest.Swap(color1)); }
/// <summary> /// Finds an approximately closest pair of points (one of each color) by using the ordering found in SortedPoints. /// /// This compares points in two of the clusters, ignoring points in all other clusters. /// /// NOTE: This was a good idea, but yields results too poor to be used. /// </summary> /// <param name="color1">Label of the first cluster.</param> /// <param name="color2">Label of the second cluster.</param> /// <returns>The point with Color1, the point with Color2 and the square distance between them. /// </returns> public ClosestPair FindPairApproximately(TLabel color1, TLabel color2) { var shortest = new ClosestPair(); UnsignedPoint prevP = null; TLabel prevColor = default(TLabel); foreach (var pc in SortedPoints .Select(p => new { Point = p, Color = Clusters.GetClassLabel(p) }) .Where(pc => pc.Color.Equals(color1) || pc.Color.Equals(color2))) { if (prevP != null && !prevColor.Equals(pc.Color)) { var d = pc.Point.Measure(prevP); if (d < shortest.SquareDistance) { shortest.SquareDistance = d; shortest.Color1 = prevColor; shortest.Point1 = prevP; shortest.Color2 = pc.Color; shortest.Point2 = pc.Point; } } prevP = pc.Point; prevColor = pc.Color; } return(shortest.Swap(color1)); }
/// <summary> /// Approximates the closest distance between every cluster and every other cluster. /// /// If there are currently K clusters, this will return at most K(K-1)/2 ClosestPairs, unsorted. /// If an upper limit on the square distance is supplied, fewer may be returned. /// </summary> /// <param name="maxSquareDistance">If omitted, no restriction on distance is applied. /// If supplied, no measurement of the closest distance between two colors will /// be returned if those two colors are farther apart than this distance. /// </param> /// <returns>ClosestPairs for every pair of colors, unsorted. /// If a distance is returned for colors "A" and "B", one will not be returned for colors "B" and "A", /// since the distance is symmetric.</returns> public IEnumerable <ClosestPair> FindAllClustersApproximately(long maxSquareDistance = long.MaxValue) { var colors = Clusters.ClassLabels().ToArray(); for (var i = 0; i < colors.Length; i++) { for (var j = i + 1; j < colors.Length; j++) { var closest = NearestPointFinder.FindNearestWithLabel(colors[i], colors[j]); var shortest = new ClosestPair(closest.SearchLabel, closest.SearchPoint, closest.NearLabel, closest.NearPoint, closest.Measure); yield return(shortest.Swap(colors[i])); } } }
/// <summary> /// Finds approximately the cluster nearest to the given cluster. /// </summary> /// <param name="color1">Identifies the cluster being queried.</param> /// <returns>The closest cluster and the points from each cluster that were closest.</returns> public ClosestPair FindClusterApproximately(TLabel color1) { if (EqualityComparer <TLabel> .Default.Equals(color1, default(TLabel))) { throw new ArgumentNullException(nameof(color1)); } // A contiguous segment of points that are not color1 is sandwiched between // two points that are color1, except possibly at the beginning and end of the list of SortedPoints. // If multiple points from the same second color are found in the segment, // only compare the nearest point in sequence to each end of the segment. // For example, if the sequence of colors (1,2,3) for points A thru J is this: // Points: A B C D E F G H I J // Colors: 1 2 2 2 3 3 3 2 2 1 // We will compare the distances between A & B, A & E, G & J, and I & J, // because they are likeliest to be the closest points to one or the other endpoints (A & J). // Thus at most one point of each color found in the segment will be compared to the // first point of color1, and at most one point of each color will be compared to the last // point of color1. var closest = this.NearestPointFinder.FindNearest(color1); var shortest = new ClosestPair(closest.SearchLabel, closest.SearchPoint, closest.NearLabel, closest.NearPoint, closest.Measure); return(shortest.Swap(color1)); }