private static void InteractiveDemo()
        {
            Console.WriteLine("Entering interactive mode...");
            Console.WriteLine("Which feature do you want to use? (Input an integer.)");
            Console.WriteLine("[1]         Color moment");
            Console.WriteLine("[2 - 6]     RGB Histgram, with dim 2,3,4,5,6 in each channel");
            Console.WriteLine("[7 - 11]    HSL Histgram, with dim 2,3,4,5,6 in each channel");
            Console.WriteLine("[12]        4x4 Binary density");
            var strategy = int.Parse(Console.ReadLine() ?? throw new Exception());

            Console.WriteLine("Building R Tree...");
            const int minEntry = 12;
            const int maxEntry = 30;

            var featurePath = StrategyMap[strategy].Item1;
            var featureDim  = StrategyMap[strategy].Item2;

            var tree = new RTree <string>(maxEntry, minEntry);

            var featureLines = File.ReadAllLines(featurePath);
            var points       = featureLines.Select(s =>
            {
                var slices = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                return(new Point(featureDim, slices.Select(double.Parse).ToList()));
            }).ToList();

            var imageNames = File.ReadAllLines(ImageFilePath);

            for (var i = 0; i < NumImages; i++)
            {
                tree.AddRecord(new Rectangle(featureDim, points[i], points[i]), imageNames[i]);
            }

            var imagePointMap = new Dictionary <string, Point>();

            for (var i = 0; i < NumImages; i++)
            {
                imagePointMap.Add(imageNames[i], points[i]);
            }

            while (true)
            {
                Console.WriteLine(
                    "Please choose a image by file name (e.g. \"n01613177_3.JPEG\", quotation mark is not needed) :");
                var imageName = Console.ReadLine();
                if (imageName == null)
                {
                    throw new Exception();
                }
                Console.WriteLine("How many items do you want to retrievel?");
                var topK = int.Parse(Console.ReadLine() ?? throw new Exception());

                var results = tree.GetKNearestItems(imagePointMap[imageName], topK);
                results.ForEach(res =>
                {
                    Console.WriteLine($"{res}     {string.Join(" ", imagePointMap[res].Coordinate)}");
                });
            }
        }
        private static int GetNumDiskAccess(int rtreeSize, int strategy, int minEntry, int maxEntry)
        {
            var featurePath = StrategyMap[strategy].Item1;
            var featureDim  = StrategyMap[strategy].Item2;

            var nums = Enumerable.Range(0, NumImages).ToList();

            nums.Shuffle();

            var tree = new RTree <string>(maxEntry, minEntry);

            var featureLines = File.ReadAllLines(featurePath);
            var points       = featureLines.Select(s =>
            {
                var slices = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                return(new Point(featureDim, slices.Select(double.Parse).ToList()));
            }).ToList();

            var imageNames = File.ReadAllLines(ImageFilePath);

            for (var i = 0; i < rtreeSize; i++)
            {
                tree.AddRecord(new Rectangle(featureDim, points[nums[i]], points[nums[i]]), imageNames[nums[i]]);
            }

            var mbr   = tree.GetRootMbr();
            var ratio = Math.Pow(1d / 2, 1d / featureDim);

            const int queryTimes = 1024;
            var       countSum   = 0;

            for (var i = 0; i < queryTimes; i++)
            {
                var queryMinBound = Enumerable.Repeat(0d, featureDim).ToList();
                var queryMaxBound = Enumerable.Repeat(0d, featureDim).ToList();

                for (var dim = 0; dim < featureDim; dim++)
                {
                    var length     = mbr.MaxBoundries[dim] - mbr.MinBoundries[dim];
                    var sideLength = length * ratio;
                    var start      = mbr.MinBoundries[dim] + new Random(DateTime.Now.Millisecond).NextDouble() *
                                     (mbr.MaxBoundries[dim] - sideLength - mbr.MinBoundries[dim]);
                    var end = start + sideLength;
                    queryMinBound[dim] = start;
                    queryMaxBound[dim] = end;
                }

                var queryRect = new Rectangle(featureDim, queryMinBound, queryMaxBound);
                tree.GetContainedItems(queryRect, out var count);
                countSum += count;
            }

            return(countSum / queryTimes);
        }
        private static double GetAccuracy(int strategy, int numTopK)
        {
            const int minEntry = 12;
            const int maxEntry = 30;

            var featurePath = StrategyMap[strategy].Item1;
            var featureDim  = StrategyMap[strategy].Item2;

            var tree = new RTree <string>(maxEntry, minEntry);

            var featureLines = File.ReadAllLines(featurePath);
            var points       = featureLines.Select(s =>
            {
                var slices = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                return(new Point(featureDim, slices.Select(double.Parse).ToList()));
            }).ToList();

            var imageNames = File.ReadAllLines(ImageFilePath);

            for (var i = 0; i < NumImages; i++)
            {
                tree.AddRecord(new Rectangle(featureDim, points[i], points[i]), imageNames[i]);
            }

            var totalAccuracy = 0d;

            for (var i = 0; i < NumImages; i++)
            {
                var results = tree.GetKNearestItems(points[i], numTopK);
                results.Remove(imageNames[i]);
                var total = results.Count;
                var count = 0;
                foreach (var result in results)
                {
                    if (result.Split('_')[0] == imageNames[i].Split('_')[0])
                    {
                        count++;
                    }
                }

                var accuracy = (double)count / total;
                totalAccuracy += accuracy;
            }

            return(totalAccuracy / NumImages);
        }
        private static int GetSplitCountOfBuilding(int rtreeSize, int strategy, int minEntry, int maxEntry)
        {
            var tree = new RTree <string>(maxEntry, minEntry);

            var featurePath  = StrategyMap[strategy].Item1;
            var featureDim   = StrategyMap[strategy].Item2;
            var featureLines = File.ReadAllLines(featurePath);
            var points       = featureLines.Select(s =>
            {
                var slices = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                return(new Point(featureDim, slices.Select(double.Parse).ToList()));
            }).ToList();

            var imageNames = File.ReadAllLines(ImageFilePath);

            for (var i = 0; i < NumImages; i++)
            {
                tree.AddRecord(new Rectangle(featureDim, points[i], points[i]), imageNames[i]);
            }

            return(tree.SplitCount);
        }
        private static double GetRecall(int strategy)
        {
            const int minEntry = 12;
            const int maxEntry = 30;
            var       tree     = new RTree <string>(maxEntry, minEntry);

            var featurePath = StrategyMap[strategy].Item1;
            var featureDim  = StrategyMap[strategy].Item2;

            var featureLines = File.ReadAllLines(featurePath);
            var points       = featureLines.Select(s =>
            {
                var slices = s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                return(new Point(featureDim, slices.Select(double.Parse).ToList()));
            }).ToList();

            var imageNames = File.ReadAllLines(ImageFilePath);

            for (var i = 0; i < NumImages; i++)
            {
                tree.AddRecord(new Rectangle(featureDim, points[i], points[i]), imageNames[i]);
            }

            var dict = new Dictionary <string, int>();

            for (var i = 0; i < NumImages; i++)
            {
                var category = imageNames[i].Split('_')[0];
                if (dict.Keys.Contains(category))
                {
                    dict[category]++;
                }
                else
                {
                    dict[category] = 1;
                }
            }

            var totalRecall = 0d;

            for (var i = 0; i < NumImages; i++)
            {
                var category = imageNames[i].Split('_')[0];
                var results  = tree.GetKNearestItems(points[i], dict[category]);
                var count    = 0;
                foreach (var result in results)
                {
                    if (result.Split('_')[0] == category)
                    {
                        count++;
                    }
                }

                var recall = (double)count / dict[category];
                totalRecall += recall;

                if (i % 100 == 0)
                {
                    Console.Error.WriteLine(i);
                }
            }

            return(totalRecall / NumImages);
        }