Skip to content
Merged
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
37 changes: 37 additions & 0 deletions Utilities.Tests/Extensions/DictionaryExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using FluentAssertions;
using NUnit.Framework;
using Utilities.Extensions;

namespace Utilities.Tests.Extensions
{
public class DictionaryExtensionsTests
{
[Test]
public void AddMany_ShouldThrowArgumentException_WhenKeyAlreadyExists()
{
var dictionary = new Dictionary<string, int> { ["one"] = 1 };
var enumerable = new[] { ("one", 1), ("two", 2) };

var action = () => dictionary.AddMany(enumerable);

action.Should().Throw<ArgumentException>();
}

[Test]
public void AddMany_ShouldAddAllKeyValuePairs()
{
var dictionary = new Dictionary<string, int> { ["one"] = 1 };
var enumerable = new[] { ("two", 2), ("three", 3) };

dictionary.AddMany(enumerable);

dictionary.Should().HaveCount(3);

dictionary.Should().ContainKey("one").WhichValue.Should().Be(1);
dictionary.Should().ContainKey("two").WhichValue.Should().Be(2);
dictionary.Should().ContainKey("three").WhichValue.Should().Be(3);
}
}
}
28 changes: 28 additions & 0 deletions Utilities.Tests/Extensions/MatrixExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,5 +179,33 @@ public void Subtract_ShouldCalculateSubtractionResult(
double[,] operand,
double[,] result) =>
source.Subtract(operand).Should().BeEquivalentTo(result);

[Test]
public void RoundToNextInt_ShouldReturnRoundedMatrix()
{
var source = new[,]
{
{ -1.9, 1.9 },
{ -1.5, 1.5 },
{ -1.1, 1.1 },
{ -0.9, 0.9 },
{ -0.5, 0.5 },
{ -0.1, 0.1 },
};

var result = new double[,]
{
{ -2, 2 },
{ -2, 2 },
{ -1, 1 },
{ -1, 1 },
{ 0, 0 },
{ 0, 0 },
};

var actualResult = source.RoundToNextInt();

actualResult.Should().BeEquivalentTo(result);
}
}
}
21 changes: 21 additions & 0 deletions Utilities.Tests/Extensions/RandomExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using FluentAssertions;
using NUnit.Framework;
using Utilities.Extensions;

namespace Utilities.Tests.Extensions
{
public class RandomExtensionsTests
{
[Test]
public void NextVector_ShouldReturnNormalizedVector()
{
var random = new Random(0);

var result = random.NextVector(10);

result.Length.Should().Be(10);
result.Magnitude().Should().BeApproximately(1.0, 1e-6);
}
}
}
137 changes: 137 additions & 0 deletions Utilities.Tests/Extensions/VectorExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using System;
using FluentAssertions;
using NUnit.Framework;
using Utilities.Extensions;

namespace Utilities.Tests.Extensions
{
public class VectorExtensionsTests
{
[Test]
public void Copy_ShouldReturnCopyOfVector()
{
var vector = new double[] { 0, 1, 2, 3 };

var vectorCopy = vector.Copy();

vectorCopy.Should().BeEquivalentTo(vector);
vectorCopy.Should().NotBeSameAs(vector);
}

[Test]
public void OuterProduct_ShouldCalculateOuterProduct()
{
var lhs = new double[] { -2, -1, 0, 1, 2 };
var rhs = new double[] { 1, 2, 3 };

var result = new double[,]
{
{ -2, -4, -6 },
{ -1, -2, -3 },
{ 0, 0, 0 },
{ 1, 2, 3 },
{ 2, 4, 6 },
};

var actualResult = lhs.OuterProduct(rhs);

actualResult.Should().BeEquivalentTo(result);
}

[Test]
public void Dot_ShouldThrowArgumentException_WhenDimensionsDoNotMatch()
{
var lhs = new double[] { 1, 2, 3 };
var rhs = new double[] { 1, 2, 3, 4 };

var func = () => lhs.Dot(rhs);

func.Should().Throw<ArgumentException>()
.WithMessage("Dot product arguments must have same dimension");
}

[Test]
public void Dot_ShouldCalculateDotProduct()
{
var lhs = new double[] { 1, 2, 3 };
var rhs = new double[] { 4, 5, 6 };

var actualResult = lhs.Dot(rhs);

actualResult.Should().Be(32);
}

[Test]
public void Magnitude_ShouldCalculateMagnitude()
{
var vector = new double[] { -3, 4 };

var actualResult = vector.Magnitude();

actualResult.Should().BeApproximately(5.0, 0.0001);
}

[Test]
public void Scale_ShouldCalculateScale()
{
var vector = new double[] { -1, 0, 1 };
var factor = 2;

var result = new double[] { -2, 0, 2 };

var actualResult = vector.Scale(factor);

actualResult.Should().BeEquivalentTo(result);
}

[Test]
public void ToColumnVector_ShouldReturnColumnVector()
{
var vector = new double[] { 1, 2, 3, 4 };
var result = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } };

var actualResult = vector.ToColumnVector();

actualResult.Should().BeEquivalentTo(result);
}

[Test]
public void ToRowVector_ShouldThrowInvalidOperationException_WhenSourceIsNotAColumnVector()
{
var source = new double[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } };

var func = () => source.ToRowVector();

func.Should().Throw<InvalidOperationException>()
.WithMessage("The column vector should have only 1 element in width.");
}

[Test]
public void ToRowVector_ShouldReturnRowVector()
{
var source = new double[,] { { 1 }, { 2 }, { 3 }, { 4 } };
var result = new double[] { 1, 2, 3, 4 };

var actualResult = source.ToRowVector();

actualResult.Should().BeEquivalentTo(result);
}

[Test]
public void ToDiagonalMatrix_ShouldReturnDiagonalMatrix()
{
var source = new double[] { 1, 2, 3, 4 };
var result = new double[,]
{
{ 1, 0, 0, 0 },
{ 0, 2, 0, 0 },
{ 0, 0, 3, 0 },
{ 0, 0, 0, 4 },
};

var actualResult = source.ToDiagonalMatrix();

actualResult.Should().BeEquivalentTo(result);
}
}
}
13 changes: 12 additions & 1 deletion Utilities/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;

namespace Utilities.Extensions
{
public static class DictionaryExtensions
{
/// <summary>
/// Adds the specified key value tuples to the dictionary.
/// </summary>
/// <param name="keys">The dictionary.</param>
/// <param name="enumerable">The collection of key value tuples to add.</param>
/// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
/// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
/// <exception cref="ArgumentException">
/// A key from the <paramref name="enumerable"/> already exists in <paramref name="keys"/>.
/// </exception>
public static void AddMany<TKey, TValue>(
this Dictionary<TKey, TValue> keys,
IEnumerable<(TKey, TValue)> enumerable) where TKey : notnull
Expand Down
6 changes: 6 additions & 0 deletions Utilities/Extensions/RandomExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ namespace Utilities.Extensions
{
public static class RandomExtensions
{
/// <summary>
/// Returns a random normalized vector of the specified size.
/// </summary>
/// <param name="rand">The random number generator.</param>
/// <param name="size">The size of the vector to return.</param>
/// <returns>A random normalized vector.</returns>
public static double[] NextVector(this Random rand, int size)
{
var vector = Enumerable.Range(0, size)
Expand Down