/// <summary>
 /// Load data directly, not via a file.
 /// </summary>
 /// <param name="initialClassification">Initial classification.</param>
 /// <param name="originalOrder">Original order. If omitted, an arbitrary ordering of points will be defined.</param>
 public void LoadData(Classification <UnsignedPoint, string> initialClassification, IList <UnsignedPoint> originalOrder = null)
 {
     InitialClassification = initialClassification;
     if (originalOrder == null)
     {
         InputOrder = InitialClassification.Points().ToList();
     }
     else
     {
         InputOrder = originalOrder.ToList();
     }
     InputDataIds = new Dictionary <UnsignedPoint, string>();
     foreach (var point in InitialClassification.Points())
     {
         InputDataIds[point] = point.UniqueId.ToString();
     }
 }
        /// <summary>
        /// Create a classifier to categorize points further, building on top of an existing classification.
        /// </summary>
        /// <param name="points">Points to categorize.</param>
        /// <param name="bitsPerDimension">Bits per dimension.</param>
        public HilbertClassifier(Classification <UnsignedPoint, string> c, int bitsPerDimension)
        {
            // Steps 1 and 2b (Receive points and classify all points as they are already classified).
            Clusters         = c;
            BitsPerDimension = bitsPerDimension;

            IdsToPoints = new Dictionary <int, UnsignedPoint>();
            foreach (var p in Clusters.Points())
            {
                IdsToPoints[p.UniqueId] = p;
            }
        }
        /// <summary>
        /// Create a classifier to cluster from scratch, with no regard to any previous categorization.
        /// </summary>
        /// <param name="points">Points to categorize.</param>
        /// <param name="bitsPerDimension">Bits per dimension.</param>
        public HilbertClassifier(IEnumerable <UnsignedPoint> points, int bitsPerDimension)
        {
            var labelCounter = 1;

            // Steps 1 and 2a (Receive points and classify all points in separate clusters of size one).
            Clusters         = new Classification <UnsignedPoint, string>(points, p => (labelCounter++).ToString());
            BitsPerDimension = bitsPerDimension;

            IdsToPoints = new Dictionary <int, UnsignedPoint>();
            foreach (var p in Clusters.Points())
            {
                IdsToPoints[p.UniqueId] = p;
            }
        }
        /// <summary>
        /// Create an index of all the points in a Classification, optionally adding a new dimension to each point to hold
        /// that point's classification index.
        /// </summary>
        /// <param name="clusters">Clusters of points, which could be UnsignedPoints or HilbertPoints.</param>
        /// <param name="bitsPerDimension">Bits per dimension to use when transforming UnsignedPoints into HilbertPoints,
        /// should that be necessary.
        /// If a non-positive number, compute the value by studying the data, using the smallest number capable of accommodating
        /// the largest coordinate values.</param>
        /// <param name="addClassificationDimension">If set to <c>true</c> add a classification dimension to the end of each point.
        /// The value will be the index of that point's cluster. Cluster ordering is arbitrary and dependent on the order that
        /// the set Classification.LabelToPoints.Values iterates over them.</param>
        public HilbertIndex(Classification <UnsignedPoint, string> clusters, int bitsPerDimension = 0, bool addClassificationDimension = false)
        {
            if (bitsPerDimension <= 0)
            {
                bitsPerDimension = FindBitsPerDimension(clusters.Points());
            }

            UnsortedPoints = new List <HilbertPoint>();
            foreach (var clusterWithNumber in clusters.LabelToPoints.Values.Select((c, i) => new { Cluster = c, Index = (uint)i }))
            {
                UnsortedPoints.AddRange(
                    clusterWithNumber.Cluster
                    .Select(p => addClassificationDimension ? p.AppendCoordinate(clusterWithNumber.Index) : p)
                    .Select(p => HilbertPoint.CastOrConvert(p, bitsPerDimension, true))
                    );
            }
            InitIndexing();
        }