private static void Run <T>(IIndex <int, TRectangle, TPoint> index, IList <Tuple <int, T> > data, BuildSmallUpdates <T> makeSmallUpdate, BuildLargeUpdates <T> makeLargeUpdate, AddEntries <T> addEntries, DoUpdate <T> doUpdate) { // Get new randomizer. var random = new MersenneTwister(Seed); // Get stop watch for profiling. var watch = new Stopwatch(); // Also allocate the ids to look up in advance. var rangeQueries = new List <Tuple <TPoint, float> >(Operations); var areaQueries = new List <TRectangle>(Operations); // And updates. var smallUpdates = new List <Tuple <int, T> >(Operations); var largeUpdates = new List <Tuple <int, T> >(Operations); var addTime = new DoubleSampling(Iterations); var rangeQueryTime = new DoubleSampling(Iterations); var areaQueryTime = new DoubleSampling(Iterations); var smallUpdateTime = new DoubleSampling(Iterations); var largeUpdateTime = new DoubleSampling(Iterations); var highLoadRemoveTime = new DoubleSampling(Iterations); var mediumLoadRemoveTime = new DoubleSampling(Iterations); var lowLoadRemoveTime = new DoubleSampling(Iterations); Console.Write("Doing {0} iterations... ", Iterations); for (var i = 0; i < Iterations; i++) { Console.Write("{0}. ", i + 1); // Clear the index. index.Clear(); // Generate look up ids in advance. rangeQueries.Clear(); for (var j = 0; j < Operations; j++) { rangeQueries.Add(Tuple.Create(random.NextVector(Area), MinQueryRange + (MaxQueryRange - MinQueryRange) * (float)random.NextDouble())); } areaQueries.Clear(); for (var j = 0; j < Operations; j++) { areaQueries.Add(random.NextRectangle(Area, MinQueryRange * 2, MaxQueryRange * 2)); } // Generate position updates. smallUpdates.Clear(); largeUpdates.Clear(); for (var j = 0; j < Operations; j++) { // High chance it remains in the same cell. makeSmallUpdate(smallUpdates, data, random, j); } for (var j = 0; j < Operations; j++) { // High chance it will be outside the original cell. makeLargeUpdate(largeUpdates, data, random, j); } // Test time to add. try { watch.Reset(); watch.Start(); addEntries(index, data); watch.Stop(); addTime.Put(watch.ElapsedMilliseconds / (double)NumberOfObjects); } catch (NotSupportedException) { } // Test update time. try { watch.Reset(); watch.Start(); foreach (var update in smallUpdates) { doUpdate(index, update); } watch.Stop(); smallUpdateTime.Put(watch.ElapsedMilliseconds / (double)smallUpdates.Count); } catch (NotSupportedException) { } try { watch.Reset(); watch.Start(); foreach (var update in largeUpdates) { doUpdate(index, update); } watch.Stop(); largeUpdateTime.Put(watch.ElapsedMilliseconds / (double)largeUpdates.Count); } catch (NotSupportedException) { } // Test look up time. try { watch.Reset(); watch.Start(); for (var j = 0; j < Operations; j++) { #if USE_CALLBACK index.Find(rangeQueries[j].Item1, rangeQueries[j].Item2, value => true); #else index.Find(rangeQueries[j].Item1, rangeQueries[j].Item2, ref DummyCollection <int> .Instance); #endif } watch.Stop(); rangeQueryTime.Put(watch.ElapsedMilliseconds / (double)Operations); } catch (NotSupportedException) { } try { watch.Reset(); watch.Start(); for (var j = 0; j < Operations; j++) { var rect = areaQueries[j]; #if USE_CALLBACK index.Find(rect, value => true); #else index.Find(rect, ref DummyCollection <int> .Instance); #endif } watch.Stop(); areaQueryTime.Put(watch.ElapsedMilliseconds / (double)Operations); } catch (NotSupportedException) { } // Test removal time. try { watch.Reset(); watch.Start(); for (var j = 0; j < NumberOfObjects / 3; j++) { index.Remove(data[j].Item1); } watch.Stop(); highLoadRemoveTime.Put(watch.ElapsedMilliseconds / (double)(NumberOfObjects / 3)); } catch (NotSupportedException) { } try { watch.Reset(); watch.Start(); for (var j = NumberOfObjects / 3; j < NumberOfObjects * 2 / 3; j++) { index.Remove(data[j].Item1); } watch.Stop(); mediumLoadRemoveTime.Put(watch.ElapsedMilliseconds / (double)(NumberOfObjects / 3)); } catch (NotSupportedException) { } try { watch.Reset(); watch.Start(); for (var j = NumberOfObjects * 2 / 3; j < NumberOfObjects; j++) { index.Remove(data[j].Item1); } watch.Stop(); lowLoadRemoveTime.Put(watch.ElapsedMilliseconds / (double)(NumberOfObjects / 3)); } catch (NotSupportedException) { } } Console.WriteLine("Done!"); Console.WriteLine("Operation | Mean | Std.dev.\n" + "Add: | {0:0.00000}ms | {1:0.00000}ms\n" + "Range query: | {2:0.00000}ms | {3:0.00000}ms\n" + "Area query: | {4:0.00000}ms | {5:0.00000}ms\n" + "Update (small): | {6:0.00000}ms | {7:0.00000}ms\n" + "Update (large): | {8:0.00000}ms | {9:0.00000}ms\n" + "Remove (high load): | {10:0.00000}ms | {11:0.00000}ms\n" + "Remove (med. load): | {12:0.00000}ms | {13:0.00000}ms\n" + "Remove (low load): | {14:0.00000}ms | {15:0.00000}ms", addTime.Mean(), addTime.StandardDeviation(), rangeQueryTime.Mean(), rangeQueryTime.StandardDeviation(), areaQueryTime.Mean(), areaQueryTime.StandardDeviation(), smallUpdateTime.Mean(), smallUpdateTime.StandardDeviation(), largeUpdateTime.Mean(), largeUpdateTime.StandardDeviation(), highLoadRemoveTime.Mean(), highLoadRemoveTime.StandardDeviation(), mediumLoadRemoveTime.Mean(), mediumLoadRemoveTime.StandardDeviation(), lowLoadRemoveTime.Mean(), lowLoadRemoveTime.StandardDeviation()); }