using System; using System.Drawing; using System.IO; using System.Linq; using ZeroLevel.HNSW; namespace HNSWDemo.Tests { public class HistogramTest : ITest { private static int Count = 3000; private static int Dimensionality = 128; private static int Width = 2440; private static int Height = 1920; public void Run() { Create(Dimensionality, @"D:\hist"); // Process.Start("explorer", $"D:\\hist{Dimensionality.ToString("D3")}.jpg"); /* for (int i = 12; i < 512; i++) { Create(i, @"D:\hist"); }*/ } private void Create(int dim, string output) { var vectors = VectorUtils.RandomVectors(dim, Count); var world = SmallWorld.CreateWorld(NSWOptions.Create(8, 16, 200, 200, Metrics.L2Euclidean)); world.AddItems(vectors); var distance = new Func((id1, id2) => Metrics.L2Euclidean(world.GetVector(id1), world.GetVector(id2))); var weights = world.GetLinks().SelectMany(pair => pair.Value.Select(id => distance(pair.Key, id))); var histogram = new Histogram(HistogramMode.SQRT, weights); histogram.Smooth(); int threshold = histogram.CuttOff(); var min = histogram.Bounds[threshold - 1]; var max = histogram.Bounds[threshold]; var R = (max + min) / 2; DrawHistogram(histogram, Path.Combine(output, $"hist{dim.ToString("D3")}.jpg")); } static void DrawHistogram(Histogram histogram, string filename) { var wb = Width / histogram.Values.Length; var k = ((float)Height) / (float)histogram.Values.Max(); var maxes = histogram.GetMaximums().ToDictionary(m => m.Index, m => m); int threshold = histogram.CuttOff(); using (var bmp = new Bitmap(Width, Height)) { using (var g = Graphics.FromImage(bmp)) { for (int i = 0; i < histogram.Values.Length; i++) { var height = (int)(histogram.Values[i] * k); if (maxes.ContainsKey(i)) { g.DrawRectangle(Pens.Red, i * wb, bmp.Height - height, wb, height); g.DrawRectangle(Pens.Red, i * wb + 1, bmp.Height - height, wb - 1, height); } else { g.DrawRectangle(Pens.Blue, i * wb, bmp.Height - height, wb, height); } if (i == threshold) { g.DrawLine(Pens.Green, i * wb + wb / 2, 0, i * wb + wb / 2, bmp.Height); } } } bmp.Save(filename); } } } }