/// <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));
        }