diff --git a/src/Numerics/Combinatorics.cs b/src/Numerics/Combinatorics.cs index f7178aaf..b3ae25b9 100644 --- a/src/Numerics/Combinatorics.cs +++ b/src/Numerics/Combinatorics.cs @@ -36,7 +36,8 @@ namespace MathNet.Numerics public static class Combinatorics { /// - /// Computes the number of variations without repetition. The order matters and each object can be chosen only once. + /// Computes the number of variations without repetition. + /// The order matters and each object can be chosen only once. /// /// Number of elements in the set. /// Number of elements to choose from the set. Each element is chosen at most once. @@ -48,11 +49,15 @@ namespace MathNet.Numerics return 0; } - return Math.Floor(0.5 + Math.Exp(SpecialFunctions.FactorialLn(n) - SpecialFunctions.FactorialLn(n - k))); + return Math.Floor( + 0.5 + Math.Exp( + SpecialFunctions.FactorialLn(n) + - SpecialFunctions.FactorialLn(n - k))); } /// - /// Computes the number of variations with repetition. The order matters and each object can be chosen more than once. + /// Computes the number of variations with repetition. + /// The order matters and each object can be chosen more than once. /// /// Number of elements in the set. /// Number of elements to choose from the set. Each element is chosen 0, 1 or multiple times. @@ -66,5 +71,43 @@ namespace MathNet.Numerics return Math.Pow(n, k); } + + /// + /// Computes the number of combinations without repetition. + /// The order does not matter and each object can be chosen only once. + /// + /// Number of elements in the set. + /// Number of elements to choose from the set. Each element is chosen at most once. + /// Maximum number of combinations. + public static double Combinations(int n, int k) + { + return SpecialFunctions.Binomial(n, k); + } + + /// + /// Computes the number of combinations with repetition. + /// The order does not matter and an object can be chosen more than once. + /// + /// Number of elements in the set. + /// Number of elements to choose from the set. Each element is chosen 0, 1 or multiple times. + /// Maximum number of combinations with repetition. + public static double CombinationsWithRepetition(int n, int k) + { + if (k < 0 || n < 0 || (n == 0 && k > 0)) + { + return 0; + } + + if (n == 0 && k == 0) + { + return 1; + } + + return Math.Floor( + 0.5 + Math.Exp( + SpecialFunctions.FactorialLn(n + k - 1) + - SpecialFunctions.FactorialLn(k) + - SpecialFunctions.FactorialLn(n - 1))); + } } } \ No newline at end of file diff --git a/src/UnitTests/CombinatoricsTests/CombinatoricsCountingTest.cs b/src/UnitTests/CombinatoricsTests/CombinatoricsCountingTest.cs index 9733646b..7b196bf0 100644 --- a/src/UnitTests/CombinatoricsTests/CombinatoricsCountingTest.cs +++ b/src/UnitTests/CombinatoricsTests/CombinatoricsCountingTest.cs @@ -96,5 +96,69 @@ namespace MathNet.Numerics.UnitTests.CombinatoricsTests Combinatorics.VariationsWithRepetition(n, k), "The number of variations with repetition but out of the range must be 0."); } + + [Test] + [Row(0, 0, 1)] + [Row(1, 0, 1)] + [Row(10, 0, 1)] + [Row(10, 2, 45)] + [Row(10, 4, 210)] + [Row(10, 6, 210)] + [Row(10, 9, 10)] + [Row(10, 10, 1)] + public void CanCountCombinations(int n, int k, long expected) + { + Assert.AreEqual( + expected, + Combinatorics.Combinations(n, k), + "Count the number of combinations without repetition"); + } + + [Test] + [Row(0, 1)] + [Row(10, 11)] + [Row(0, -1)] + [Row(1, -1)] + [Row(-1, 0)] + [Row(-1, 1)] + public void OutOfRangeCombinationsMustCountToZero(int n, int k) + { + Assert.AreEqual( + 0, + Combinatorics.Combinations(n, k), + "The number of combinations without repetition but out of the range must be 0."); + } + + [Test] + [Row(0, 0, 1)] + [Row(1, 0, 1)] + [Row(10, 0, 1)] + [Row(10, 2, 55)] + [Row(10, 4, 715)] + [Row(10, 6, 5005)] + [Row(10, 9, 48620)] + [Row(10, 10, 92378)] + [Row(10, 11, 167960)] + public void CanCountCombinationsWithRepetition(int n, int k, long expected) + { + Assert.AreEqual( + expected, + Combinatorics.CombinationsWithRepetition(n, k), + "Count the number of combinations with repetition"); + } + + [Test] + [Row(0, 1)] + [Row(0, -1)] + [Row(1, -1)] + [Row(-1, 0)] + [Row(-1, 1)] + public void OutOfRangeCombinationsWithRepetitionMustCountToZero(int n, int k) + { + Assert.AreEqual( + 0, + Combinatorics.CombinationsWithRepetition(n, k), + "The number of combinations with repetition but out of the range must be 0."); + } } } \ No newline at end of file