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
28 changes: 28 additions & 0 deletions Algorithms.Tests/LinearAlgebra/Distances/MinkowskiTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using NUnit.Framework;
using Algorithms.LinearAlgebra.Distances;
using FluentAssertions;
using System;

namespace Algorithms.Tests.LinearAlgebra.Distances;

public class MinkowskiTests
{
[TestCase(new[] { 2.0, 3.0 }, new[] { -1.0, 5.0 }, 1, 5.0)] // Simulate Manhattan condition
[TestCase(new[] { 7.0, 4.0, 3.0 }, new[] { 17.0, 6.0, 2.0 }, 2, 10.247)] // Simulate Euclidean condition
[TestCase(new[] { 1.0, 2.0, 3.0, 4.0 }, new[] { 1.75, 2.25, -3.0, 0.5 }, 20, 6.0)] // Simulate Chebyshev condition
[TestCase(new[] { 1.0, 1.0, 9.0 }, new[] { 2.0, 2.0, -5.2 }, 3, 14.2)]
[TestCase(new[] { 1.0, 2.0, 3.0 }, new[] { 1.0, 2.0, 3.0 }, 5, 0.0)]
public void DistanceTest(double[] point1, double[] point2, int order, double expectedDistance)
{
Minkowski.Distance(point1, point2, order).Should().BeApproximately(expectedDistance, 0.01);
}

[TestCase(new[] { 2.0, 3.0 }, new[] { -1.0 }, 2)]
[TestCase(new[] { 1.0 }, new[] { 1.0, 2.0, 3.0 }, 1)]
[TestCase(new[] { 1.0, 1.0 }, new[] { 2.0, 2.0 }, 0)]
public void DistanceThrowsArgumentExceptionOnInvalidInput(double[] point1, double[] point2, int order)
{
Action action = () => Minkowski.Distance(point1, point2, order);
action.Should().Throw<ArgumentException>();
}
}
37 changes: 37 additions & 0 deletions Algorithms/LinearAlgebra/Distances/Minkowski.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Linq;

namespace Algorithms.LinearAlgebra.Distances;

/// <summary>
/// Implementation of Minkowski distance.
/// It is the sum of the lengths of the projections of the line segment between the points onto the
/// coordinate axes, raised to the power of the order and then taking the p-th root.
/// For the case of order = 1, the Minkowski distance degenerates to the Manhattan distance,
/// for order = 2, the usual Euclidean distance is obtained and for order = infinity, the Chebyshev distance is obtained.
/// </summary>
public static class Minkowski
{
/// <summary>
/// Calculate Minkowski distance for two N-Dimensional points.
/// </summary>
/// <param name="point1">First N-Dimensional point.</param>
/// <param name="point2">Second N-Dimensional point.</param>
/// <param name="order">Order of the Minkowski distance.</param>
/// <returns>Calculated Minkowski distance.</returns>
public static double Distance(double[] point1, double[] point2, int order)
{
if (order < 1)
{
throw new ArgumentException("The order must be greater than or equal to 1.");
}

if (point1.Length != point2.Length)
{
throw new ArgumentException("Both points should have the same dimensionality");
}

// distance = (|x1-y1|^p + |x2-y2|^p + ... + |xn-yn|^p)^(1/p)
return Math.Pow(point1.Zip(point2, (x1, x2) => Math.Pow(Math.Abs(x1 - x2), order)).Sum(), 1.0 / order);
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ find more than one implementation for the same objective but using different alg
* [Chebyshev](./Algorithms/LinearAlgebra/Distances/Chebyshev.cs)
* [Euclidean](./Algorithms/LinearAlgebra/Distances/Euclidean.cs)
* [Manhattan](./Algorithms/LinearAlgebra/Distances/Manhattan.cs)
* [Minkowski](./Algorithms/LinearAlgebra/Distances/Minkowski.cs)
* [Eigenvalue](./Algorithms/LinearAlgebra/Eigenvalue)
* [Power Iteration](./Algorithms/LinearAlgebra/Eigenvalue/PowerIteration.cs)
* [Modular Arithmetic](./Algorithms/ModularArithmetic)
Expand Down
Loading