diff --git a/src/Numerics/Combinatorics.cs b/src/Numerics/Combinatorics.cs
index 131f78a5..5ceb8476 100644
--- a/src/Numerics/Combinatorics.cs
+++ b/src/Numerics/Combinatorics.cs
@@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
-// Copyright (c) 2009-2010 Math.NET
+// Copyright (c) 2009-2015 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -28,17 +28,21 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MathNet.Numerics.Properties;
+using MathNet.Numerics.Random;
+
namespace MathNet.Numerics
{
- using System;
-
///
/// Enumerative Combinatorics and Counting.
///
public static class Combinatorics
{
///
- /// Counts the number of possible variations without repetition.
+ /// Count the number of possible variations without repetition.
/// The order matters and each object can be chosen only once.
///
/// Number of elements in the set.
@@ -53,12 +57,12 @@ namespace MathNet.Numerics
return Math.Floor(
0.5 + Math.Exp(
- SpecialFunctions.FactorialLn(n)
- - SpecialFunctions.FactorialLn(n - k)));
+ SpecialFunctions.FactorialLn(n)
+ - SpecialFunctions.FactorialLn(n - k)));
}
///
- /// Counts the number of possible variations with repetition.
+ /// Count the number of possible variations with repetition.
/// The order matters and each object can be chosen more than once.
///
/// Number of elements in the set.
@@ -75,7 +79,7 @@ namespace MathNet.Numerics
}
///
- /// Counts the number of possible combinations without repetition.
+ /// Count the number of possible combinations without repetition.
/// The order does not matter and each object can be chosen only once.
///
/// Number of elements in the set.
@@ -87,7 +91,7 @@ namespace MathNet.Numerics
}
///
- /// Counts the number of possible combinations with repetition.
+ /// Count the number of possible combinations with repetition.
/// The order does not matter and an object can be chosen more than once.
///
/// Number of elements in the set.
@@ -107,13 +111,13 @@ namespace MathNet.Numerics
return Math.Floor(
0.5 + Math.Exp(
- SpecialFunctions.FactorialLn(n + k - 1)
- - SpecialFunctions.FactorialLn(k)
- - SpecialFunctions.FactorialLn(n - 1)));
+ SpecialFunctions.FactorialLn(n + k - 1)
+ - SpecialFunctions.FactorialLn(k)
+ - SpecialFunctions.FactorialLn(n - 1)));
}
///
- /// Counts the number of possible permutations (without repetition).
+ /// Count the number of possible permutations (without repetition).
///
/// Number of (distinguishable) elements in the set.
/// Maximum number of permutations without repetition.
@@ -121,5 +125,299 @@ namespace MathNet.Numerics
{
return SpecialFunctions.Factorial(n);
}
+
+ ///
+ /// Generate a random permutation, without repetition, by generating the index numbers 0 to N-1 and shuffle them randomly.
+ /// Implemented using Fisher-Yates Shuffling.
+ ///
+ /// An array of length N that contains (in any order) the integers of the interval [0, N).
+ /// Number of (distinguishable) elements in the set.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ public static int[] GeneratePermutation(int n, System.Random randomSource = null)
+ {
+ if (n < 0) throw new ArgumentOutOfRangeException("n", n, Resources.ArgumentNotNegative);
+
+ int[] indices = new int[n];
+ for (int i = 0; i < indices.Length; i++)
+ {
+ indices[i] = i;
+ }
+
+ SelectPermutationInplace(indices, randomSource);
+ return indices;
+ }
+
+ ///
+ /// Select a random permutation, without repetition, from a data array by reordering the provided array in-place.
+ /// Implemented using Fisher-Yates Shuffling. The provided data array will be modified.
+ ///
+ /// The data array to be reordered. The array will be modified by this routine.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ public static void SelectPermutationInplace(T[] data, System.Random randomSource = null)
+ {
+ var random = randomSource ?? SystemRandomSource.Default;
+
+ // Fisher-Yates Shuffling
+ for (int i = data.Length - 1; i > 0; i--)
+ {
+ int swapIndex = random.Next(i + 1);
+ T swap = data[i];
+ data[i] = data[swapIndex];
+ data[swapIndex] = swap;
+ }
+ }
+
+ ///
+ /// Select a random permutation from a data sequence by returning the provided data in random order.
+ /// Implemented using Fisher-Yates Shuffling.
+ ///
+ /// The data elements to be reordered.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ public static IEnumerable SelectPermutation(this IEnumerable data, System.Random randomSource = null)
+ {
+ var random = randomSource ?? SystemRandomSource.Default;
+ T[] array = data.ToArray();
+
+ // Fisher-Yates Shuffling
+ for (int i = array.Length - 1; i >= 0; i--)
+ {
+ int k = random.Next(i + 1);
+ yield return array[k];
+ array[k] = array[i];
+ }
+ }
+
+ ///
+ /// Generate a random combination, without repetition, by randomly selecting some of N elements.
+ ///
+ /// Number of elements in the set.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// Boolean mask array of length N, for each item true if it is selected.
+ public static bool[] GenerateCombination(int n, System.Random randomSource = null)
+ {
+ if (n < 0) throw new ArgumentOutOfRangeException("n", n, Resources.ArgumentNotNegative);
+
+ var random = randomSource ?? SystemRandomSource.Default;
+
+ bool[] mask = new bool[n];
+ for (int i = 0; i < mask.Length; i++)
+ {
+ mask[i] = random.NextBoolean();
+ }
+
+ return mask;
+ }
+
+ ///
+ /// Generate a random combination, without repetition, by randomly selecting k of N elements.
+ ///
+ /// Number of elements in the set.
+ /// Number of elements to choose from the set. Each element is chosen at most once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// Boolean mask array of length N, for each item true if it is selected.
+ public static bool[] GenerateCombination(int n, int k, System.Random randomSource = null)
+ {
+ if (n < 0) throw new ArgumentOutOfRangeException("n", n, Resources.ArgumentNotNegative);
+ if (k < 0) throw new ArgumentOutOfRangeException("k", k, Resources.ArgumentNotNegative);
+ if (k > n) throw new ArgumentOutOfRangeException("k", k, string.Format(Resources.ArgumentOutOfRangeSmallerEqual, "k", "n"));
+
+ var random = randomSource ?? SystemRandomSource.Default;
+
+ bool[] mask = new bool[n];
+ if (k*3 < n)
+ {
+ // just pick and try
+ int selectionCount = 0;
+ while (selectionCount < k)
+ {
+ int index = random.Next(n);
+ if (!mask[index])
+ {
+ mask[index] = true;
+ selectionCount++;
+ }
+ }
+
+ return mask;
+ }
+
+ // based on permutation
+ int[] permutation = GeneratePermutation(n, random);
+ for (int i = 0; i < k; i++)
+ {
+ mask[permutation[i]] = true;
+ }
+
+ return mask;
+ }
+
+ ///
+ /// Select a random combination, without repetition, from a data sequence by selecting k elements in original order.
+ ///
+ /// The data source to choose from.
+ /// Number of elements (k) to choose from the data set. Each element is chosen at most once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// The chosen combination, in the original order.
+ public static IEnumerable SelectCombination(this IEnumerable data, int elementsToChoose, System.Random randomSource = null)
+ {
+ T[] array = data as T[] ?? data.ToArray();
+
+ if (elementsToChoose < 0) throw new ArgumentOutOfRangeException("elementsToChoose", elementsToChoose, Resources.ArgumentNotNegative);
+ if (elementsToChoose > array.Length) throw new ArgumentOutOfRangeException("elementsToChoose", elementsToChoose, string.Format(Resources.ArgumentOutOfRangeSmallerEqual, "elementsToChoose", "data.Count"));
+
+ bool[] mask = GenerateCombination(array.Length, elementsToChoose, randomSource);
+
+ for (int i = 0; i < mask.Length; i++)
+ {
+ if (mask[i])
+ {
+ yield return array[i];
+ }
+ }
+ }
+
+ ///
+ /// Generates a random combination, with repetition, by randomly selecting k of N elements.
+ ///
+ /// Number of elements in the set.
+ /// Number of elements to choose from the set. Elements can be chosen more than once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// Integer mask array of length N, for each item the number of times it was selected.
+ public static int[] GenerateCombinationWithRepetition(int n, int k, System.Random randomSource = null)
+ {
+ if (n < 0) throw new ArgumentOutOfRangeException("n", n, Resources.ArgumentNotNegative);
+ if (k < 0) throw new ArgumentOutOfRangeException("k", k, Resources.ArgumentNotNegative);
+
+ var random = randomSource ?? SystemRandomSource.Default;
+
+ int[] mask = new int[n];
+ for (int i = 0; i < k; i++)
+ {
+ mask[random.Next(n)]++;
+ }
+
+ return mask;
+ }
+
+ ///
+ /// Select a random combination, with repetition, from a data sequence by selecting k elements in original order.
+ ///
+ /// The data source to choose from.
+ /// Number of elements (k) to choose from the data set. Elements can be chosen more than once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// The chosen combination with repetition, in the original order.
+ public static IEnumerable SelectCombinationWithRepetition(this IEnumerable data, int elementsToChoose, System.Random randomSource = null)
+ {
+ if (elementsToChoose < 0) throw new ArgumentOutOfRangeException("elementsToChoose", elementsToChoose, Resources.ArgumentNotNegative);
+
+ T[] array = data as T[] ?? data.ToArray();
+ int[] mask = GenerateCombinationWithRepetition(array.Length, elementsToChoose, randomSource);
+
+ for (int i = 0; i < mask.Length; i++)
+ {
+ for (int j = 0; j < mask[i]; j++)
+ {
+ yield return array[i];
+ }
+ }
+ }
+
+ ///
+ /// Generate a random variation, without repetition, by randomly selecting k of n elements with order.
+ /// Implemented using partial Fisher-Yates Shuffling.
+ ///
+ /// Number of elements in the set.
+ /// Number of elements to choose from the set. Each element is chosen at most once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// An array of length K that contains the indices of the selections as integers of the interval [0, N).
+ public static int[] GenerateVariation(int n, int k, System.Random randomSource = null)
+ {
+ if (n < 0) throw new ArgumentOutOfRangeException("n", n, Resources.ArgumentNotNegative);
+ if (k < 0) throw new ArgumentOutOfRangeException("k", k, Resources.ArgumentNotNegative);
+ if (k > n) throw new ArgumentOutOfRangeException("k", k, string.Format(Resources.ArgumentOutOfRangeSmallerEqual, "k", "n"));
+
+ var random = randomSource ?? SystemRandomSource.Default;
+
+ int[] indices = new int[n];
+ for (int i = 0; i < indices.Length; i++)
+ {
+ indices[i] = i;
+ }
+
+ // Partial Fisher-Yates Shuffling
+ int[] selection = new int[k];
+ for (int i = 0, j = indices.Length - 1; i < selection.Length; i++, j--)
+ {
+ int swapIndex = random.Next(j + 1);
+ selection[i] = indices[swapIndex];
+ indices[swapIndex] = indices[j];
+ }
+
+ return selection;
+ }
+
+ ///
+ /// Select a random variation, without repetition, from a data sequence by randomly selecting k elements in random order.
+ /// Implemented using partial Fisher-Yates Shuffling.
+ ///
+ /// The data source to choose from.
+ /// Number of elements (k) to choose from the set. Each element is chosen at most once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// The chosen variation, in random order.
+ public static IEnumerable SelectVariation(this IEnumerable data, int elementsToChoose, System.Random randomSource = null)
+ {
+ var random = randomSource ?? SystemRandomSource.Default;
+ T[] array = data.ToArray();
+
+ if (elementsToChoose < 0) throw new ArgumentOutOfRangeException("elementsToChoose", elementsToChoose, Resources.ArgumentNotNegative);
+ if (elementsToChoose > array.Length) throw new ArgumentOutOfRangeException("elementsToChoose", elementsToChoose, string.Format(Resources.ArgumentOutOfRangeSmallerEqual, "elementsToChoose", "data.Count"));
+
+ // Partial Fisher-Yates Shuffling
+ for (int i = array.Length - 1; i >= array.Length - elementsToChoose; i--)
+ {
+ int swapIndex = random.Next(i + 1);
+ yield return array[swapIndex];
+ array[swapIndex] = array[i];
+ }
+ }
+
+ ///
+ /// Generate a random variation, with repetition, by randomly selecting k of n elements with order.
+ ///
+ /// Number of elements in the set.
+ /// Number of elements to choose from the set. Elements can be chosen more than once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// An array of length K that contains the indices of the selections as integers of the interval [0, N).
+ public static int[] GenerateVariationWithRepetition(int n, int k, System.Random randomSource = null)
+ {
+ if (n < 0) throw new ArgumentOutOfRangeException("n", n, Resources.ArgumentNotNegative);
+ if (k < 0) throw new ArgumentOutOfRangeException("k", k, Resources.ArgumentNotNegative);
+
+ var random = randomSource ?? SystemRandomSource.Default;
+
+ int[] ret = new int[k];
+ random.NextInt32s(ret, 0, n);
+ return ret;
+ }
+
+ ///
+ /// Select a random variation, with repetition, from a data sequence by randomly selecting k elements in random order.
+ ///
+ /// The data source to choose from.
+ /// Number of elements (k) to choose from the data set. Elements can be chosen more than once.
+ /// The random number generator to use. Optional; the default random source will be used if null.
+ /// The chosen variation with repetition, in random order.
+ public static IEnumerable SelectVariationWithRepetition(this IEnumerable data, int elementsToChoose, System.Random randomSource = null)
+ {
+ if (elementsToChoose < 0) throw new ArgumentOutOfRangeException("elementsToChoose", elementsToChoose, Resources.ArgumentNotNegative);
+
+ T[] array = data as T[] ?? data.ToArray();
+ int[] indices = GenerateVariationWithRepetition(array.Length, elementsToChoose, randomSource);
+
+ for (int i = 0; i < indices.Length; i++)
+ {
+ yield return array[indices[i]];
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/Numerics/Properties/Resources.Designer.cs b/src/Numerics/Properties/Resources.Designer.cs
index 996bcedc..301c0a64 100644
--- a/src/Numerics/Properties/Resources.Designer.cs
+++ b/src/Numerics/Properties/Resources.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
-// Runtime Version:4.0.30319.34014
+// Runtime Version:4.0.30319.34209
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -386,6 +386,24 @@ namespace MathNet.Numerics.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to {0} must be smaller than {1}..
+ ///
+ public static string ArgumentOutOfRangeSmaller {
+ get {
+ return ResourceManager.GetString("ArgumentOutOfRangeSmaller", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} must be smaller than or equal to {1}..
+ ///
+ public static string ArgumentOutOfRangeSmallerEqual {
+ get {
+ return ResourceManager.GetString("ArgumentOutOfRangeSmallerEqual", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The chosen parameter set is invalid (probably some value is out of range)..
///
diff --git a/src/Numerics/Properties/Resources.resx b/src/Numerics/Properties/Resources.resx
index e1360503..6713e906 100644
--- a/src/Numerics/Properties/Resources.resx
+++ b/src/Numerics/Properties/Resources.resx
@@ -183,6 +183,12 @@
{0} must be greater than or equal to {1}.
+
+ {0} must be smaller than {1}.
+
+
+ {0} must be smaller than or equal to {1}.
+
The chosen parameter set is invalid (probably some value is out of range).
diff --git a/src/Numerics/Random/RandomSource.cs b/src/Numerics/Random/RandomSource.cs
index 601ddf9f..f40ab8ee 100644
--- a/src/Numerics/Random/RandomSource.cs
+++ b/src/Numerics/Random/RandomSource.cs
@@ -3,9 +3,9 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
-//
+//
// Copyright (c) 2009-2013 Math.NET
-//
+//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
@@ -14,10 +14,10 @@
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
-//
+//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
-//
+//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND