Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions csharp/Platform.Collections.Benchmarks/BitStringBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ public void Setup()
}
}

[Benchmark]
public BitString CreateWithRandomBitsOld()
{
var bitString = new BitString(N);
bitString.SetRandomBits();
return bitString;
}

[Benchmark]
public BitString CreateWithRandomBitsNew() => BitStringExtensions.CreateWithRandomBits(N);

[Benchmark]
public BitString Not() => new BitString(_left).Not();

Expand Down
34 changes: 34 additions & 0 deletions csharp/Platform.Collections.Tests/BitStringTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ public static void BitGetSetTest()
}
}

[Fact]
public static void BitStringArrayConstructorTest()
{
const int n = 128;
var array = new long[] { unchecked((long)0x1234567890ABCDEF), unchecked((long)0xFEDCBA0987654321) };
var bitString = new BitString(array, n);

var normalBitString = new BitString(n);
for (var i = 0L; i < BitString.GetWordsCountFromIndex(n); i++)
{
for (var j = 0; j < 64 && (i * 64 + j) < n; j++)
{
var bitIndex = i * 64 + j;
var expectedValue = (array[i] & (1L << j)) != 0;
normalBitString.Set(bitIndex, expectedValue);
Assert.Equal(expectedValue, bitString.Get(bitIndex));
}
}

Assert.Equal(normalBitString.CountSetBits(), bitString.CountSetBits());
}

[Fact]
public static void CreateWithRandomBitsTest()
{
const int n = 1000;
var bitString1 = BitStringExtensions.CreateWithRandomBits(n);
var bitString2 = BitStringExtensions.CreateWithRandomBits(n);

Assert.Equal(n, bitString1.Length);
Assert.Equal(n, bitString2.Length);
Assert.False(bitString1.Equals(bitString2));
}

[Fact]
public static void BitVectorNotTest()
{
Expand Down
60 changes: 60 additions & 0 deletions csharp/Platform.Collections.Tests/PerformanceComparisonTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Diagnostics;
using Xunit;
using Xunit.Abstractions;

namespace Platform.Collections.Tests
{
public class PerformanceComparisonTest
{
private readonly ITestOutputHelper _output;

public PerformanceComparisonTest(ITestOutputHelper output)
{
_output = output;
}

[Fact]
public void BitStringInitializationPerformanceComparison()
{
const int iterations = 100;
const long bitStringLength = 10000;

_output.WriteLine($"Testing BitString initialization performance with {iterations} iterations for length {bitStringLength}");

// Test old method (SetRandomBits)
var sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
var bitString = new BitString(bitStringLength);
bitString.SetRandomBits();
}
sw.Stop();
var oldMethodTime = sw.ElapsedMilliseconds;
_output.WriteLine($"Old method (SetRandomBits): {oldMethodTime} ms");

// Test new method (array constructor)
sw.Restart();
for (int i = 0; i < iterations; i++)
{
var bitString = BitStringExtensions.CreateWithRandomBits(bitStringLength);
}
sw.Stop();
var newMethodTime = sw.ElapsedMilliseconds;
_output.WriteLine($"New method (CreateWithRandomBits): {newMethodTime} ms");

if (oldMethodTime > 0 && newMethodTime > 0)
{
var improvement = (double)oldMethodTime / newMethodTime;
_output.WriteLine($"Performance improvement: {improvement:F2}x faster");

// Assert that the new method is faster or at least not significantly slower
Assert.True(newMethodTime <= oldMethodTime, $"New method should be faster or equal. Old: {oldMethodTime}ms, New: {newMethodTime}ms");
}
else
{
_output.WriteLine("Performance test completed, but times were too small to measure accurately");
}
}
}
}
57 changes: 57 additions & 0 deletions csharp/Platform.Collections/BitString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,36 @@ public BitString(long length, bool defaultValue)
}
}

/// <summary>
/// <para>
/// Initializes a new <see cref="BitString"/> instance.
/// </para>
/// <para></para>
/// </summary>
/// <param name="array">
/// <para>An array of integers to initialize the bit string with.</para>
/// <para></para>
/// </param>
/// <param name="length">
/// <para>A length.</para>
/// <para></para>
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BitString(long[] array, long length)
{
Ensure.Always.ArgumentNotNull(array, nameof(array));
Ensure.Always.ArgumentInRange(length, GetValidLengthRange(), nameof(length));
var wordsCount = GetWordsCountFromIndex(length);
if (array.LongLength < wordsCount)
{
throw new ArgumentException($"Array must have at least {wordsCount} elements for length {length}.", nameof(array));
}
_length = length;
_array = new long[wordsCount];
Array.Copy(array, _array, wordsCount);
SetBordersFromArray();
}

#endregion

/// <summary>
Expand Down Expand Up @@ -1533,6 +1563,33 @@ private void EnsureBitStringHasTheSameSize(BitString other, string argumentName)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MarkBordersAsAllBitsSet() => SetBorders(0, _array.LongLength - 1);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetBordersFromArray()
{
long minPositiveWord = _array.LongLength - 1;
long maxPositiveWord = 0;
var hasPositiveBits = false;
for (var i = 0L; i < _array.LongLength; i++)
{
if (_array[i] != 0)
{
if (!hasPositiveBits)
{
minPositiveWord = i;
hasPositiveBits = true;
}
maxPositiveWord = i;
}
}
if (!hasPositiveBits)
{
MarkBordersAsAllBitsReset();
}
else
{
SetBorders(minPositiveWord, maxPositiveWord);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void GetBorders(out long from, out long to)
{
from = _minPositiveWord;
Expand Down
26 changes: 26 additions & 0 deletions csharp/Platform.Collections/BitStringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,31 @@ public static void SetRandomBits(this BitString @string)
@string.Set(i, value);
}
}

/// <summary>
/// <para>
/// Creates a new BitString with random bits using the efficient constructor.
/// </para>
/// <para></para>
/// </summary>
/// <param name="length">
/// <para>The length of the bit string.</para>
/// <para></para>
/// </param>
/// <returns>
/// <para>A new BitString with random bits.</para>
/// <para></para>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BitString CreateWithRandomBits(long length)
{
var wordsCount = BitString.GetWordsCountFromIndex(length);
var randomArray = new long[wordsCount];
for (var i = 0L; i < wordsCount; i++)
{
randomArray[i] = RandomHelpers.Default.NextInt64();
}
return new BitString(randomArray, length);
}
}
}
Loading