run-length encoding wins
This commit is contained in:
parent
e4f7249f1e
commit
38ee2e4eb5
|
@ -0,0 +1,189 @@
|
||||||
|
using Logging;
|
||||||
|
using NuGet.Frameworks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Numerics;
|
||||||
|
using Utils;
|
||||||
|
|
||||||
|
namespace FrameworkTests.Utils
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class IndexEncodingTests
|
||||||
|
{
|
||||||
|
private readonly Random random = new Random();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IndexRanging()
|
||||||
|
{
|
||||||
|
var log = new FileLog(Path.Combine(Environment.CurrentDirectory, nameof(IndexRanging) + ".log"));
|
||||||
|
|
||||||
|
var reruns = 1;
|
||||||
|
var tests = CreateTests().ToArray();
|
||||||
|
log.Log($"Tests: {tests.Length}");
|
||||||
|
foreach (var test in tests)
|
||||||
|
{
|
||||||
|
log.Log($"Running {test.GetName()}");
|
||||||
|
Parallel.For(0, reruns, i =>
|
||||||
|
{
|
||||||
|
RunTest(log, test);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Log("Results:");
|
||||||
|
foreach (var test in tests)
|
||||||
|
{
|
||||||
|
test.PrintResult(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunTest(FileLog log, IndexTest test)
|
||||||
|
{
|
||||||
|
var blockPresence = new BlockPresence(log, test.NumIndices, test.PresenceFactor);
|
||||||
|
var presentIndices = blockPresence.Present.ToArray();
|
||||||
|
|
||||||
|
//Stopwatch.Measure(log, nameof(RunLengthEncode), () =>
|
||||||
|
//{
|
||||||
|
var run = RunLengthEncode(presentIndices);
|
||||||
|
test.RunLengthEncodingLengths.Add(run.Length);
|
||||||
|
//});
|
||||||
|
|
||||||
|
//Stopwatch.Measure(log, nameof(FlipMapEncode), () =>
|
||||||
|
//{
|
||||||
|
var flipMap = FlipMapEncode(presentIndices, test.NumIndices);
|
||||||
|
test.FlipMapLengths.Add(flipMap.Length);
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] RunLengthEncode(int[] indices)
|
||||||
|
{
|
||||||
|
var result = new List<int>();
|
||||||
|
if (indices.Length == 0) return result.ToArray();
|
||||||
|
|
||||||
|
var runValue = indices[0];
|
||||||
|
var runStart = runValue;
|
||||||
|
var runLength = 1;
|
||||||
|
for (var i = 1; i < indices.Length; i++)
|
||||||
|
{
|
||||||
|
if (i >= indices.Length)
|
||||||
|
{
|
||||||
|
result.Add(runStart);
|
||||||
|
result.Add(runLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var nextValue = indices[i];
|
||||||
|
if (nextValue == runValue + 1)
|
||||||
|
{
|
||||||
|
runLength++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Add(runStart);
|
||||||
|
result.Add(runLength);
|
||||||
|
|
||||||
|
runLength = 1;
|
||||||
|
runStart = nextValue;
|
||||||
|
runValue = nextValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] FlipMapEncode(int[] presentIndices, int numIndices)
|
||||||
|
{
|
||||||
|
var flips = new List<int>();
|
||||||
|
if (presentIndices.Length == 0) return flips.ToArray();
|
||||||
|
|
||||||
|
var current = false;
|
||||||
|
for (var i = 0; i < numIndices; i++)
|
||||||
|
{
|
||||||
|
var isPresent = presentIndices.Contains(i);
|
||||||
|
if (current != isPresent)
|
||||||
|
{
|
||||||
|
flips.Add(i);
|
||||||
|
current = isPresent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return flips.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<IndexTest> CreateTests()
|
||||||
|
{
|
||||||
|
//// 10,000,000 indices * 64k = 610 GB dataset
|
||||||
|
//for (var numIndices = 1000; numIndices < 10000000; numIndices *= 100)
|
||||||
|
//{
|
||||||
|
// for (float factor = 0.0f; factor < 1.0f; factor += 0.1f)
|
||||||
|
// {
|
||||||
|
// yield return new IndexTest(numIndices, factor);
|
||||||
|
// }
|
||||||
|
// yield return new IndexTest(numIndices, 1.0f);
|
||||||
|
//}
|
||||||
|
|
||||||
|
yield return new IndexTest(100000, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IndexTest
|
||||||
|
{
|
||||||
|
public IndexTest(int numIndices, float presenceFactor)
|
||||||
|
{
|
||||||
|
NumIndices = numIndices;
|
||||||
|
PresenceFactor = presenceFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int NumIndices { get; }
|
||||||
|
public float PresenceFactor { get; }
|
||||||
|
|
||||||
|
public int BitMapLength => Convert.ToInt32(Math.Ceiling(NumIndices / 8.0));
|
||||||
|
public int PresenceArrayLength => Convert.ToInt32(Math.Ceiling(NumIndices * PresenceFactor));
|
||||||
|
public ConcurrentBag<int> RunLengthEncodingLengths { get; } = new ConcurrentBag<int>();
|
||||||
|
public ConcurrentBag<int> FlipMapLengths { get; } = new ConcurrentBag<int>();
|
||||||
|
|
||||||
|
public void PrintResult(ILog log)
|
||||||
|
{
|
||||||
|
log.Log(GetName());
|
||||||
|
log.Log($"BitmapLength: {BitMapLength}");
|
||||||
|
log.Log($"PresenceArrayLength: {PresenceArrayLength}");
|
||||||
|
log.Log($"RunLength: {RunLengthEncodingLengths.Average()}");
|
||||||
|
log.Log($"FlipMap: {FlipMapLengths.Average()}");
|
||||||
|
log.Log("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetName()
|
||||||
|
{
|
||||||
|
return $"Test: {NumIndices} indices, {PresenceFactor * 100.0f}% present.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BlockPresence
|
||||||
|
{
|
||||||
|
public BlockPresence(ILog log, int length, float factor)
|
||||||
|
{
|
||||||
|
//Stopwatch.Measure(log, "Factoring", () =>
|
||||||
|
//{
|
||||||
|
var all = Enumerable.Range(0, length).ToList();
|
||||||
|
|
||||||
|
float l = length;
|
||||||
|
var numPresent = Convert.ToInt32(Math.Round(l * factor));
|
||||||
|
if (numPresent >= length)
|
||||||
|
{
|
||||||
|
Present = all.ToArray();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var present = new List<int>();
|
||||||
|
while (present.Count < numPresent)
|
||||||
|
{
|
||||||
|
present.Add(all.PickOneRandom());
|
||||||
|
}
|
||||||
|
present.Sort();
|
||||||
|
Present = present.ToArray();
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] Present { get; private set; } = Array.Empty<int>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue