/// <summary>
        /// Compose an enumerable that encompasses a range of points starting at the given point and running for the given length.
        /// If the point is too close to the end of the list in sorted order, fewer items than rangeLength may be returned.
        /// </summary>
        /// <param name="p">Point where range starts.</param>
        /// <param name="rangeLength">Range length.</param>
        public IEnumerable <HilbertPoint> Range(HilbertPoint p, int rangeLength)
        {
            var position   = SortedPosition(p);
            var rangeStart = Math.Min(Math.Max(0, position - rangeLength / 2), Count - rangeLength);

            return(SortedPoints.Skip(rangeStart).Take(rangeLength));
        }
        /// <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>
        /// Find the points adjacent to the given point in the Hilbert ordering, then sort them by the cartesian distance, from nearest to farthest.
        /// </summary>
        /// <param name="point">Reference point to seek in the index.</param>
        /// <param name="rangeLength">Number of points to retrieve from the index. Half of these points will precede and half succeed the given point
        /// in the index, unless we are near the beginning or end of the index, in which case the range will be shifted.</param>
        /// <param name="includePointItself">If false, the reference point will not be present in the results.
        /// If true, the point will be present in the results.</param>
        /// <returns>The points nearest to the reference point in both Hilbert and Cartesian ordering, sorted from nearest to farthest.</returns>
        public IEnumerable <HilbertPoint> NearestFromRange(HilbertPoint point, int rangeLength, bool includePointItself = false)
        {
            rangeLength = includePointItself ? rangeLength : rangeLength + 1;
            var middlePosition = SortedPosition(point);
            var rangeStart     = Math.Max(0, middlePosition - rangeLength / 2);

            return(SortedPoints
                   .Skip(rangeStart)
                   .Take(rangeLength)
                   .Where(p => includePointItself || !p.Equals(point))
                   .OrderBy(p => p.Measure(point)));
        }
示例#4
0
 private void InitIndexing()
 {
     Index = new Dictionary <UnsignedPoint, Position>();
     foreach (var pointWithIndex in UnsortedPoints.Select((p, i) => new { Point = p, OriginalPosition = i }))
     {
         Index[pointWithIndex.Point] = new Position(pointWithIndex.OriginalPosition, -1);
     }
     foreach (var pointWithIndex in SortedPoints.Select((p, i) => new { Point = p, SortedPosition = i }))
     {
         Index[pointWithIndex.Point].Sorted = pointWithIndex.SortedPosition;
     }
     IdsToPoints = new Dictionary <int, UnsignedPoint>();
     foreach (var p in UnsortedPoints)
     {
         IdsToPoints[p.UniqueId] = p;
     }
 }
        /// <summary>
        /// Check if the ids in the points in the Clusters match the ids in the SortedPoints.
        /// </summary>s
        private void ValidateIds()
        {
            if (SortedPoints.Count != Clusters.NumPoints)
            {
                throw new InvalidOperationException("Clusters holds more points than SortedPoints");
            }

            var idRangeClusters = Clusters.Points().Aggregate(
                new     { Min = int.MaxValue, Max = int.MinValue },
                (accumulator, o) => new
            {
                Min = Math.Min(o.UniqueId, accumulator.Min),
                Max = Math.Max(o.UniqueId, accumulator.Max)
            }
                );
            var idRangeSortedPoints = SortedPoints.Aggregate(
                new { Min = int.MaxValue, Max = int.MinValue },
                (accumulator, o) => new
            {
                Min = Math.Min(o.UniqueId, accumulator.Min),
                Max = Math.Max(o.UniqueId, accumulator.Max)
            }
                );

            if (idRangeClusters.Min != idRangeSortedPoints.Min)
            {
                throw new InvalidOperationException("The lowest Id among the points in SortedPoints and Clusters is not the same");
            }
            if (idRangeClusters.Max != idRangeSortedPoints.Max)
            {
                throw new InvalidOperationException("The highest Id among the points in SortedPoints and Clusters is not the same");
            }

            /*
             * // Exhaustive comparison of all ids. More costly.
             * var idsInClusters = new HashSet<int>();
             * foreach (var point in Clusters.Points())
             *      idsInClusters.Add(point.UniqueId);
             *
             * foreach (var point in SortedPoints)
             * {
             *      if (!idsInClusters.Contains(point.UniqueId))
             *              throw new InvalidOperationException("SortedPoints has a point whose Id does not match a point in Clusters");
             * }
             */
        }
 /// <summary>
 /// Find the K-nearest neighbors of a given point according to the cartesian distance between the point and its neighbors.
 ///
 /// NOTE: This compares the point to all other points, hence is more costly than NearestFromRange but is guaranteed
 /// to find all near neighbors.
 /// </summary>
 /// <param name="point">Reference point whose neighbors are sought.</param>
 /// <param name="k">Number of nearest neighbors to find.</param>
 /// <param name="includePointItself">If false, the point is not considered its own neighbor and will not be present in the results.
 /// If true, the point is considered its own neighbor and will be present in the results,
 /// unless all the nearest neighbors are zero distance from this point, in which case it might not make the cut.</param>
 /// <returns>The nearest neighbors of the given point, sorted from nearest to farthest.</returns>
 public IEnumerable <HilbertPoint> Nearest(HilbertPoint point, int k, bool includePointItself = false)
 {
     return(SortedPoints
            .Where(p => includePointItself || !p.Equals(point))
            .BottomN <HilbertPoint, long>(point, k));
 }