diff --git a/.gitignore b/.gitignore
index 096e60a44..3ee4d94fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,3 +76,6 @@ docs/content/Contributing.md
docs/content/Contributors.md
docs/content/ReleaseNotes.md
docs/content/ReleaseNotes-*.md
+
+NUnitTests.csproj
+NUnitTests/
\ No newline at end of file
diff --git a/.paket/Paket.Restore.targets b/.paket/Paket.Restore.targets
index d93abfef9..52f41c608 100644
--- a/.paket/Paket.Restore.targets
+++ b/.paket/Paket.Restore.targets
@@ -17,23 +17,43 @@
native
/Library/Frameworks/Mono.framework/Commands/mono
mono
-
- $(PaketToolsPath)paket
- $(PaketRootPath)paket.exe
- $(PaketToolsPath)paket.exe
- $(PaketToolsPath)paket.exe
- $(PaketToolsPath)paket
+
+ $(PaketRootPath)paket.bootstrapper.exe
+ $(PaketToolsPath)paket.bootstrapper.exe
+ $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\
+
+
+
+
+ $(PaketRootPath)paket.exe
+ $(PaketToolsPath)paket.exe
+ $(PaketToolsPath)paket.exe
+ $(_PaketBootStrapperExeDir)paket.exe
+ paket.exe
+
+
+ $(PaketRootPath)paket
+ $(PaketToolsPath)paket
+ $(PaketToolsPath)paket
+
+
+ $(PaketRootPath)paket.exe
+ $(PaketToolsPath)paket.exe
+
+
+ $(PaketBootStrapperExeDir)paket.exe
+
+
+ paket
<_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))
dotnet "$(PaketExePath)"
- "$(PaketExePath)"
$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
- "$(PaketExePath)"
+ "$(PaketExePath)"
+
- $(PaketRootPath)paket.bootstrapper.exe
- $(PaketToolsPath)paket.bootstrapper.exe
"$(PaketBootStrapperExePath)"
$(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)"
@@ -42,6 +62,9 @@
true
true
+
+
+ True
@@ -82,7 +105,11 @@
true
-
+
+
true
@@ -163,6 +190,7 @@
runtime
runtime
true
+ true
diff --git a/MathNet.Numerics.sln b/MathNet.Numerics.sln
index 357c7c3c1..b19c6969d 100644
--- a/MathNet.Numerics.sln
+++ b/MathNet.Numerics.sln
@@ -18,9 +18,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Readme", "Readme", "{C2F374
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numerics", "src\Numerics\Numerics.csproj", "{B7CAE5F4-A23F-4438-B5BE-41226618B695}"
EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp", "src\FSharp\FSharp.fsproj", "{37E8E802-A354-4114-BFC1-6E1357DA605B}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp", "src\FSharp\FSharp.fsproj", "{37E8E802-A354-4114-BFC1-6E1357DA605B}"
EndProject
-Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Tests", "src\FSharp.Tests\FSharp.Tests.fsproj", "{F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}"
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Tests", "src\FSharp.Tests\FSharp.Tests.fsproj", "{F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numerics.Tests", "src\Numerics.Tests\Numerics.Tests.csproj", "{DAF07AA8-C5C9-4963-98F7-2C3285064DAD}"
EndProject
diff --git a/src/FSharp/FSharp.fsproj b/src/FSharp/FSharp.fsproj
index 3bf79fe91..7d625d566 100644
--- a/src/FSharp/FSharp.fsproj
+++ b/src/FSharp/FSharp.fsproj
@@ -57,4 +57,4 @@ Linear Algebra: optimized range checking in vectors and matrices
-
+
\ No newline at end of file
diff --git a/src/Numerics.Tests/CombinatoricsTests/CombinatoricsCountingTest.cs b/src/Numerics.Tests/CombinatoricsTests/CombinatoricsCountingTest.cs
index 592416f77..2968a7f4f 100644
--- a/src/Numerics.Tests/CombinatoricsTests/CombinatoricsCountingTest.cs
+++ b/src/Numerics.Tests/CombinatoricsTests/CombinatoricsCountingTest.cs
@@ -28,6 +28,7 @@
//
using NUnit.Framework;
+using MathNet.Numerics;
namespace MathNet.Numerics.UnitTests.CombinatoricsTests
{
diff --git a/src/Numerics.Tests/CombinatoricsTests/CombinatoricsTest.cs b/src/Numerics.Tests/CombinatoricsTests/CombinatoricsTest.cs
new file mode 100644
index 000000000..069914946
--- /dev/null
+++ b/src/Numerics.Tests/CombinatoricsTests/CombinatoricsTest.cs
@@ -0,0 +1,103 @@
+using MathNet.Numerics.Combinations;
+using NUnit.Framework;
+using System;
+
+namespace NUnitTests
+{
+ ///
+ /// Permutation tests.
+ ///
+ [TestFixture()]
+ public class CombinatoricsTest
+ {
+ ///
+ /// Can create permutation from int array.
+ ///
+ /// Permutations index set.
+ [TestCase(new[] { -1 })]
+ [TestCase(new[] { 0 })]
+ [TestCase(new[] { 0, 1, 2, 3, 4, 5 })]
+ [TestCase(new[] { 0, 1, 2, 3, 4, 4 })]
+ [TestCase(new[] { 5, 4, 3, 2, 1, 0 })]
+ [TestCase(new[] { 0, 4, 3, 2, 1, 5 })]
+ [TestCase(new[] { 0, 3, 2, 1, 4, 5 })]
+ [TestCase(new[] { 5, 4, 3, 2, 1, 7 })]
+ public void CanCreateIntegerPermutation(int[] idx)
+ {
+ GC.KeepAlive(new Permutations(idx));
+ }
+
+ ///
+ /// Can create permutation from char array.
+ ///
+ /// Permutations index set.
+ [TestCase(new[] { 'A' })]
+ [TestCase(new[] { 'A', 'A', 'B', 'C', 'D', 'E' })]
+ [TestCase(new[] { 'A', 'B', 'C', 'D', 'E', 'F' })]
+ [TestCase(new[] { 'D', 'E', 'F', 'A', 'B', 'C' })]
+ public void CanCreateCharPermutation(char[] idx)
+ {
+ GC.KeepAlive(new Permutations(idx));
+ }
+
+ ///
+ /// Can create permutation from int array.
+ ///
+ /// Permutations index set.
+ [TestCase(new[] { -1 })]
+ [TestCase(new[] { 0 })]
+ [TestCase(new[] { 0, 1, 2, 3, 4, 5 })]
+ [TestCase(new[] { 0, 1, 2, 3, 4, 4 })]
+ [TestCase(new[] { 5, 4, 3, 2, 1, 0 })]
+ [TestCase(new[] { 0, 4, 3, 2, 1, 5 })]
+ [TestCase(new[] { 0, 3, 2, 1, 4, 5 })]
+ [TestCase(new[] { 5, 4, 3, 2, 1, 7 })]
+ public void CanCreateIntegerCombination(int[] idx)
+ {
+ GC.KeepAlive(new Combinations(idx, 3));
+ }
+
+ ///
+ /// Can create permutation from char array.
+ ///
+ /// Permutations index set.
+ [TestCase(new[] { 'A' })]
+ [TestCase(new[] { 'A', 'A', 'B', 'C', 'D', 'E' })]
+ [TestCase(new[] { 'A', 'B', 'C', 'D', 'E', 'F' })]
+ [TestCase(new[] { 'D', 'E', 'F', 'A', 'B', 'C' })]
+ public void CanCreateCharCombination(char[] idx)
+ {
+ GC.KeepAlive(new Combinations(idx, 3));
+ }
+
+ ///
+ /// Can create permutation from int array.
+ ///
+ /// Permutations index set.
+ [TestCase(new[] { -1 })]
+ [TestCase(new[] { 0 })]
+ [TestCase(new[] { 0, 1, 2, 3, 4, 5 })]
+ [TestCase(new[] { 0, 1, 2, 3, 4, 4 })]
+ [TestCase(new[] { 5, 4, 3, 2, 1, 0 })]
+ [TestCase(new[] { 0, 4, 3, 2, 1, 5 })]
+ [TestCase(new[] { 0, 3, 2, 1, 4, 5 })]
+ [TestCase(new[] { 5, 4, 3, 2, 1, 7 })]
+ public void CanCreateIntegerVariation(int[] idx)
+ {
+ GC.KeepAlive(new Variations(idx, 3));
+ }
+
+ ///
+ /// Can create permutation from char array.
+ ///
+ /// Permutations index set.
+ [TestCase(new[] { 'A' })]
+ [TestCase(new[] { 'A', 'A', 'B', 'C', 'D', 'E' })]
+ [TestCase(new[] { 'A', 'B', 'C', 'D', 'E', 'F' })]
+ [TestCase(new[] { 'D', 'E', 'F', 'A', 'B', 'C' })]
+ public void CanCreateCharVariation(char[] idx)
+ {
+ GC.KeepAlive(new Variations(idx, 3));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Numerics/Combinatorics.cs b/src/Numerics/Combinatorics.cs
index 63e66c9d9..c49a3424f 100644
--- a/src/Numerics/Combinatorics.cs
+++ b/src/Numerics/Combinatorics.cs
@@ -418,5 +418,73 @@ public static IEnumerable SelectVariationWithRepetition(this IEnumerable
+ /// Test if two lists are equal
+ ///
+ /// true, if equal was unordereded, false otherwise.
+ /// The first list to compare.
+ /// The second list to compare.
+ /// The 1st type parameter.
+ public static bool UnorderedEqual(ICollection a, ICollection b)
+ {
+ // Require that the counts are equal
+ if (a.Count != b.Count)
+ {
+ return false;
+ }
+
+ // Initialize new Dictionary of the type
+ Dictionary d = new Dictionary();
+
+ // Add each key's frequency from collection A to the Dictionary
+ foreach (T item in a)
+ {
+ int c;
+ if (d.TryGetValue(item, out c))
+ {
+ d[item] = c + 1;
+ }
+ else
+ {
+ d.Add(item, 1);
+ }
+ }
+
+ // Add each key's frequency from collection B to the Dictionary
+ // Return early if we detect a mismatch
+ foreach (T item in b)
+ {
+ int c;
+ if (d.TryGetValue(item, out c))
+ {
+ if (c == 0)
+ {
+ return false;
+ }
+ else
+ {
+ d[item] = c - 1;
+ }
+ }
+ else
+ {
+ // Not in dictionary
+ return false;
+ }
+ }
+
+ // Verify that all frequencies are zero
+ foreach (int v in d.Values)
+ {
+ if (v != 0)
+ {
+ return false;
+ }
+ }
+
+ // We know the collections are equal
+ return true;
+ }
}
}
diff --git a/src/Numerics/Combinatorics/Combinations.cs b/src/Numerics/Combinatorics/Combinations.cs
new file mode 100755
index 000000000..98c1f3250
--- /dev/null
+++ b/src/Numerics/Combinatorics/Combinations.cs
@@ -0,0 +1,348 @@
+// Copyright 2008 Adrian Akison
+// Distributed under license terms of CPOL http://www.codeproject.com/info/cpol10.aspx
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MathNet.Numerics.Combinations
+{
+ ///
+ /// Combinations defines a meta-collection, typically a list of lists, of all possible
+ /// subsets of a particular size from the set of values. This list is enumerable and
+ /// allows the scanning of all possible combinations using a simple foreach() loop.
+ /// Within the returned set, there is no prescribed order. This follows the mathematical
+ /// concept of choose. For example, put 10 dominoes in a hat and pick 5. The number of possible
+ /// combinations is defined as "10 choose 5", which is calculated as (10!) / ((10 - 5)! * 5!).
+ ///
+ ///
+ /// The MetaCollectionType parameter of the constructor allows for the creation of
+ /// two types of sets, those with and without repetition in the output set when
+ /// presented with repetition in the input set.
+ ///
+ /// When given a input collect {A B C} and lower index of 2, the following sets are generated:
+ /// MetaCollectionType.WithRepetition =>
+ /// {A A}, {A B}, {A C}, {B B}, {B C}, {C C}
+ /// MetaCollectionType.WithoutRepetition =>
+ /// {A B}, {A C}, {B C}
+ ///
+ /// Input sets with multiple equal values will generate redundant combinations in proprotion
+ /// to the likelyhood of outcome. For example, {A A B B} and a lower index of 3 will generate:
+ /// {A A B} {A A B} {A B B} {A B B}
+ ///
+ /// The type of the values within the list.
+ public class Combinations : IMetaCollection {
+ #region Constructors
+
+ ///
+ /// No default constructor, must provided a list of values and size.
+ ///
+ protected Combinations() {
+ ;
+ }
+
+ ///
+ /// Create a combination set from the provided list of values.
+ /// The upper index is calculated as values.Count, the lower index is specified.
+ /// Collection type defaults to MetaCollectionType.WithoutRepetition
+ ///
+ /// List of values to select combinations from.
+ /// The size of each combination set to return.
+ public Combinations(IList values, int lowerIndex) {
+ Initialize(values, lowerIndex, GenerateOption.WithoutRepetition);
+ }
+
+ ///
+ /// Create a combination set from the provided list of values.
+ /// The upper index is calculated as values.Count, the lower index is specified.
+ ///
+ /// List of values to select combinations from.
+ /// The size of each combination set to return.
+ /// The type of Combinations set to generate.
+ public Combinations(IList values, int lowerIndex, GenerateOption type) {
+ Initialize(values, lowerIndex, type);
+ }
+
+ #endregion
+
+ #region IEnumerable Interface
+
+ ///
+ /// Gets an enumerator for collecting the list of combinations.
+ ///
+ /// The enumerator.
+ public IEnumerator> GetEnumerator() {
+ return new Enumerator(this);
+ }
+
+ ///
+ /// Gets an enumerator for collecting the list of combinations.
+ ///
+ /// The enumerator.
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return new Enumerator(this);
+ }
+
+ #endregion
+
+ #region Enumerator Inner Class
+
+ ///
+ /// The enumerator that enumerates each meta-collection of the enclosing Combinations class.
+ ///
+ public class Enumerator : IEnumerator> {
+
+ #region Constructors
+
+ ///
+ /// Construct a enumerator with the parent object.
+ ///
+ /// The source combinations object.
+ public Enumerator(Combinations source) {
+ myParent = source;
+ myPermutationsEnumerator = (Permutations.Enumerator)myParent.myPermutations.GetEnumerator();
+ }
+
+ #endregion
+
+ #region IEnumerator interface
+ ///
+ /// Resets the combinations enumerator to the first combination.
+ ///
+ public void Reset() {
+ myPermutationsEnumerator.Reset();
+ }
+
+ ///
+ /// Advances to the next combination of items from the set.
+ ///
+ /// True if successfully moved to next combination, False if no more unique combinations exist.
+ ///
+ /// The heavy lifting is done by the permutations object, the combination is generated
+ /// by creating a new list of those items that have a true in the permutation parrellel array.
+ ///
+ public bool MoveNext() {
+ bool ret = myPermutationsEnumerator.MoveNext();
+ myCurrentList = null;
+ return ret;
+ }
+
+ ///
+ /// The current combination
+ ///
+ public IList Current {
+ get {
+ ComputeCurrent();
+ return myCurrentList;
+ }
+ }
+
+ ///
+ /// The current combination
+ ///
+ object System.Collections.IEnumerator.Current {
+ get {
+ ComputeCurrent();
+ return myCurrentList;
+ }
+ }
+
+ ///
+ /// Cleans up non-managed resources, of which there are none used here.
+ ///
+ public void Dispose() {
+ ;
+ }
+
+ #endregion
+
+ #region Heavy Lifting Members
+
+ ///
+ /// The only complex function of this entire wrapper, ComputeCurrent() creates
+ /// a list of original values from the bool permutation provided.
+ /// The exception for accessing current (InvalidOperationException) is generated
+ /// by the call to .Current on the underlying enumeration.
+ ///
+ ///
+ /// To compute the current list of values, the underlying permutation object
+ /// which moves with this enumerator, is scanned differently based on the type.
+ /// The items have only two values, true and false, which have different meanings:
+ ///
+ /// For type WithoutRepetition, the output is a straightforward subset of the input array.
+ /// E.g. 6 choose 3 without repetition
+ /// Input array: {A B C D E F}
+ /// Permutations: {0 1 0 0 1 1}
+ /// Generates set: {A C D }
+ /// Note: size of permutation is equal to upper index.
+ ///
+ /// For type WithRepetition, the output is defined by runs of characters and when to
+ /// move to the next element.
+ /// E.g. 6 choose 5 with repetition
+ /// Input array: {A B C D E F}
+ /// Permutations: {0 1 0 0 1 1 0 0 1 1}
+ /// Generates set: {A B B D D }
+ /// Note: size of permutation is equal to upper index - 1 + lower index.
+ ///
+ private void ComputeCurrent() {
+ if(myCurrentList == null) {
+ myCurrentList = new List();
+ int index = 0;
+ IList currentPermutation = (IList)myPermutationsEnumerator.Current;
+ for(int i = 0; i < currentPermutation.Count; ++i) {
+ if(currentPermutation[i] == false) {
+ myCurrentList.Add(myParent.myValues[index]);
+ if(myParent.Type == GenerateOption.WithoutRepetition) {
+ ++index;
+ }
+ }
+ else {
+ ++index;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Data
+
+ ///
+ /// Parent object this is an enumerator for.
+ ///
+ private Combinations myParent;
+
+ ///
+ /// The current list of values, this is lazy evaluated by the Current property.
+ ///
+ private List myCurrentList;
+
+ ///
+ /// An enumertor of the parents list of lexicographic orderings.
+ ///
+ private Permutations.Enumerator myPermutationsEnumerator;
+
+ #endregion
+ }
+ #endregion
+
+ #region IMetaList Interface
+
+ ///
+ /// The number of unique combinations that are defined in this meta-collection.
+ /// This value is mathematically defined as Choose(M, N) where M is the set size
+ /// and N is the subset size. This is M! / (N! * (M-N)!).
+ ///
+ public long Count {
+ get {
+ return myPermutations.Count;
+ }
+ }
+
+ ///
+ /// The type of Combinations set that is generated.
+ ///
+ public GenerateOption Type {
+ get {
+ return myMetaCollectionType;
+ }
+ }
+
+ ///
+ /// The upper index of the meta-collection, equal to the number of items in the initial set.
+ ///
+ public int UpperIndex {
+ get {
+ return myValues.Count;
+ }
+ }
+
+ ///
+ /// The lower index of the meta-collection, equal to the number of items returned each iteration.
+ ///
+ public int LowerIndex {
+ get {
+ return myLowerIndex;
+ }
+ }
+
+ #endregion
+
+ #region Heavy Lifting Members
+
+ ///
+ /// Initialize the combinations by settings a copy of the values from the
+ ///
+ /// List of values to select combinations from.
+ /// The size of each combination set to return.
+ /// The type of Combinations set to generate.
+ ///
+ /// Copies the array and parameters and then creates a map of booleans that will
+ /// be used by a permutations object to refence the subset. This map is slightly
+ /// different based on whether the type is with or without repetition.
+ ///
+ /// When the type is WithoutRepetition, then a map of upper index elements is
+ /// created with lower index false's.
+ /// E.g. 8 choose 3 generates:
+ /// Map: {1 1 1 1 1 0 0 0}
+ /// Note: For sorting reasons, false denotes inclusion in output.
+ ///
+ /// When the type is WithRepetition, then a map of upper index - 1 + lower index
+ /// elements is created with the falses indicating that the 'current' element should
+ /// be included and the trues meaning to advance the 'current' element by one.
+ /// E.g. 8 choose 3 generates:
+ /// Map: {1 1 1 1 1 1 1 1 0 0 0} (7 trues, 3 falses).
+ ///
+ private void Initialize(IList values, int lowerIndex, GenerateOption type) {
+ myMetaCollectionType = type;
+ myLowerIndex = lowerIndex;
+ myValues = new List();
+ myValues.AddRange(values);
+ List myMap = new List();
+ if(type == GenerateOption.WithoutRepetition) {
+ for(int i = 0; i < myValues.Count; ++i) {
+ if(i >= myValues.Count - myLowerIndex) {
+ myMap.Add(false);
+ }
+ else {
+ myMap.Add(true);
+ }
+ }
+ }
+ else {
+ for(int i = 0; i < values.Count - 1; ++i) {
+ myMap.Add(true);
+ }
+ for(int i = 0; i < myLowerIndex; ++i) {
+ myMap.Add(false);
+ }
+ }
+ myPermutations = new Permutations(myMap);
+ }
+
+ #endregion
+
+ #region Data
+
+ ///
+ /// Copy of values object is intialized with, required for enumerator reset.
+ ///
+ private List myValues;
+
+ ///
+ /// Permutations object that handles permutations on booleans for combination inclusion.
+ ///
+ private Permutations myPermutations;
+
+ ///
+ /// The type of the combination collection.
+ ///
+ private GenerateOption myMetaCollectionType;
+
+ ///
+ /// The lower index defined in the constructor.
+ ///
+ private int myLowerIndex;
+
+ #endregion
+ }
+}
diff --git a/src/Numerics/Combinatorics/GenerateOption.cs b/src/Numerics/Combinatorics/GenerateOption.cs
new file mode 100755
index 000000000..776abe04b
--- /dev/null
+++ b/src/Numerics/Combinatorics/GenerateOption.cs
@@ -0,0 +1,23 @@
+// Copyright 2008 Adrian Akison
+// Distributed under license terms of CPOL http://www.codeproject.com/info/cpol10.aspx
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MathNet.Numerics.Combinations
+{
+ ///
+ /// Indicates whether a Permutation, Combination or Variation meta-collections
+ /// generate repetition sets.
+ ///
+ public enum GenerateOption {
+ ///
+ /// Do not generate additional sets, typical implementation.
+ ///
+ WithoutRepetition,
+ ///
+ /// Generate additional sets even if repetition is required.
+ ///
+ WithRepetition
+ }
+}
diff --git a/src/Numerics/Combinatorics/IMetaCollection.cs b/src/Numerics/Combinatorics/IMetaCollection.cs
new file mode 100755
index 000000000..75e0afb1e
--- /dev/null
+++ b/src/Numerics/Combinatorics/IMetaCollection.cs
@@ -0,0 +1,39 @@
+// Copyright 2008 Adrian Akison
+// Distributed under license terms of CPOL http://www.codeproject.com/info/cpol10.aspx
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MathNet.Numerics.Combinations
+{
+ ///
+ /// Interface for Permutations, Combinations and any other classes that present
+ /// a collection of collections based on an input collection. The enumerators that
+ /// this class inherits defines the mechanism for enumerating through the collections.
+ ///
+ /// The of the elements in the collection, not the type of the collection.
+ interface IMetaCollection : IEnumerable> {
+ ///
+ /// The count of items in the collection. This is not inherited from
+ /// ICollection since this meta-collection cannot be extended by users.
+ ///
+ long Count { get; }
+
+ ///
+ /// The type of the meta-collection, determining how the collections are
+ /// determined from the inputs.
+ ///
+ GenerateOption Type { get; }
+
+ ///
+ /// The upper index of the meta-collection, which is the size of the input collection.
+ ///
+ int UpperIndex { get; }
+
+ ///
+ /// The lower index of the meta-collection, which is the size of each output collection.
+ ///
+ int LowerIndex { get; }
+ }
+
+}
diff --git a/src/Numerics/Combinatorics/Permutations.cs b/src/Numerics/Combinatorics/Permutations.cs
new file mode 100755
index 000000000..00e4bad52
--- /dev/null
+++ b/src/Numerics/Combinatorics/Permutations.cs
@@ -0,0 +1,457 @@
+// Copyright 2008 Adrian Akison
+// Distributed under license terms of CPOL http://www.codeproject.com/info/cpol10.aspx
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace MathNet.Numerics.Combinations
+{
+ ///
+ /// Permutations defines a meta-collection, typically a list of lists, of all
+ /// possible orderings of a set of values. This list is enumerable and allows
+ /// the scanning of all possible permutations using a simple foreach() loop.
+ /// The MetaCollectionType parameter of the constructor allows for the creation of
+ /// two types of sets, those with and without repetition in the output set when
+ /// presented with repetition in the input set.
+ ///
+ ///
+ /// When given a input collect {A A B}, the following sets are generated:
+ /// MetaCollectionType.WithRepetition =>
+ /// {A A B}, {A B A}, {A A B}, {A B A}, {B A A}, {B A A}
+ /// MetaCollectionType.WithoutRepetition =>
+ /// {A A B}, {A B A}, {B A A}
+ ///
+ /// When generating non-repetition sets, ordering is based on the lexicographic
+ /// ordering of the lists based on the provided Comparer.
+ /// If no comparer is provided, then T must be IComparable on T.
+ ///
+ /// When generating repetition sets, no comparisions are performed and therefore
+ /// no comparer is required and T does not need to be IComparable.
+ ///
+ /// The type of the values within the list.
+ public class Permutations : IMetaCollection {
+
+ #region Constructors
+
+ ///
+ /// No default constructor, must at least provided a list of values.
+ ///
+ protected Permutations() {
+ ;
+ }
+
+ ///
+ /// Create a permutation set from the provided list of values.
+ /// The values (T) must implement IComparable.
+ /// If T does not implement IComparable use a constructor with an explict IComparer.
+ /// The repetition type defaults to MetaCollectionType.WithholdRepetitionSets
+ ///
+ /// List of values to permute.
+ public Permutations(IList values) {
+ Initialize(values, GenerateOption.WithoutRepetition, null);
+ }
+
+ ///
+ /// Create a permutation set from the provided list of values.
+ /// If type is MetaCollectionType.WithholdRepetitionSets, then values (T) must implement IComparable.
+ /// If T does not implement IComparable use a constructor with an explict IComparer.
+ ///
+ /// List of values to permute.
+ /// The type of permutation set to calculate.
+ public Permutations(IList values, GenerateOption type) {
+ Initialize(values, type, null);
+ }
+
+ ///
+ /// Create a permutation set from the provided list of values.
+ /// The values will be compared using the supplied IComparer.
+ /// The repetition type defaults to MetaCollectionType.WithholdRepetitionSets
+ ///
+ /// List of values to permute.
+ /// Comparer used for defining the lexigraphic order.
+ public Permutations(IList values, IComparer comparer) {
+ Initialize(values, GenerateOption.WithoutRepetition, comparer);
+ }
+
+ #endregion
+
+ #region IEnumerable Interface
+
+ ///
+ /// Gets an enumerator for collecting the list of permutations.
+ ///
+ /// The enumerator.
+ public virtual IEnumerator GetEnumerator() {
+ return new Enumerator(this);
+ }
+
+ ///
+ /// Gets an enumerator for collecting the list of permutations.
+ ///
+ /// The enumerator.
+ IEnumerator> IEnumerable>.GetEnumerator() {
+ return new Enumerator(this);
+ }
+
+ #endregion
+
+ #region Enumerator Inner-Class
+
+ ///
+ /// The enumerator that enumerates each meta-collection of the enclosing Permutations class.
+ ///
+ public class Enumerator : IEnumerator> {
+
+ #region Constructors
+
+ ///
+ /// Construct a enumerator with the parent object.
+ ///
+ /// The source Permutations object.
+ public Enumerator(Permutations source) {
+ myParent = source;
+ myLexicographicalOrders = new int[source.myLexicographicOrders.Length];
+ source.myLexicographicOrders.CopyTo(myLexicographicalOrders, 0);
+ Reset();
+ }
+
+ #endregion
+
+ #region IEnumerator Interface
+
+ ///
+ /// Resets the permutations enumerator to the first permutation.
+ /// This will be the first lexicographically order permutation.
+ ///
+ public void Reset() {
+ myPosition = Position.BeforeFirst;
+ }
+
+ ///
+ /// Advances to the next permutation.
+ ///
+ /// True if successfully moved to next permutation, False if no more permutations exist.
+ ///
+ /// Continuation was tried (i.e. yield return) by was not nearly as efficient.
+ /// Performance is further increased by using value types and removing generics, that is, the LexicographicOrder parellel array.
+ /// This is a issue with the .NET CLR not optimizing as well as it could in this infrequently used scenario.
+ ///
+ public bool MoveNext() {
+ if(myPosition == Position.BeforeFirst) {
+ myValues = new List(myParent.myValues.Count);
+ myValues.AddRange(myParent.myValues);
+ Array.Sort(myLexicographicalOrders);
+ myPosition = Position.InSet;
+ } else if(myPosition == Position.InSet) {
+ if(myValues.Count < 2) {
+ myPosition = Position.AfterLast;
+ }
+ else if(NextPermutation() == false) {
+ myPosition = Position.AfterLast;
+ }
+ }
+ return myPosition != Position.AfterLast;
+ }
+
+ ///
+ /// The current permutation.
+ ///
+ public object Current {
+ get {
+ if(myPosition == Position.InSet) {
+ return new List(myValues);
+ }
+ else {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+
+ ///
+ /// The current permutation.
+ ///
+ IList IEnumerator>.Current {
+ get {
+ if(myPosition == Position.InSet) {
+ return new List(myValues);
+ }
+ else {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+
+ ///
+ /// Cleans up non-managed resources, of which there are none used here.
+ ///
+ public virtual void Dispose() {
+ ;
+ }
+
+ #endregion
+
+ #region Heavy Lifting Methods
+
+ ///
+ /// Calculates the next lexicographical permutation of the set.
+ /// This is a permutation with repetition where values that compare as equal will not
+ /// swap positions to create a new permutation.
+ /// http://www.cut-the-knot.org/do_you_know/AllPerm.shtml
+ /// E. W. Dijkstra, A Discipline of Programming, Prentice-Hall, 1997
+ ///
+ /// True if a new permutation has been returned, false if not.
+ ///
+ /// This uses the integers of the lexicographical order of the values so that any
+ /// comparison of values are only performed during initialization.
+ ///
+ private bool NextPermutation() {
+ int i = myLexicographicalOrders.Length - 1;
+ while(myLexicographicalOrders[i - 1] >= myLexicographicalOrders[i]) {
+ --i;
+ if(i == 0) {
+ return false;
+ }
+ }
+ int j = myLexicographicalOrders.Length;
+ while(myLexicographicalOrders[j - 1] <= myLexicographicalOrders[i - 1]) {
+ --j;
+ }
+ Swap(i - 1, j - 1);
+ ++i;
+ j = myLexicographicalOrders.Length;
+ while(i < j) {
+ Swap(i - 1, j - 1);
+ ++i;
+ --j;
+ }
+ return true;
+ }
+
+ ///
+ /// Helper function for swapping two elements within the internal collection.
+ /// This swaps both the lexicographical order and the values, maintaining the parallel array.
+ ///
+ private void Swap(int i, int j) {
+ myTemp = myValues[i];
+ myValues[i] = myValues[j];
+ myValues[j] = myTemp;
+ myKviTemp = myLexicographicalOrders[i];
+ myLexicographicalOrders[i] = myLexicographicalOrders[j];
+ myLexicographicalOrders[j] = myKviTemp;
+ }
+
+ #endregion
+
+ #region Data and Internal Members
+ ///
+ /// Single instance of swap variable for T, small performance improvement over declaring in Swap function scope.
+ ///
+ private T myTemp;
+
+ ///
+ /// Single instance of swap variable for int, small performance improvement over declaring in Swap function scope.
+ ///
+ private int myKviTemp;
+
+ ///
+ /// Flag indicating the position of the enumerator.
+ ///
+ private Position myPosition = Position.BeforeFirst;
+
+ ///
+ /// Parrellel array of integers that represent the location of items in the myValues array.
+ /// This is generated at Initialization and is used as a performance speed up rather that
+ /// comparing T each time, much faster to let the CLR optimize around integers.
+ ///
+ private int[] myLexicographicalOrders;
+
+ ///
+ /// The list of values that are current to the enumerator.
+ ///
+ private List myValues;
+
+ ///
+ /// The set of permuations that this enumerator enumerates.
+ ///
+ private Permutations myParent;
+
+ ///
+ /// Internal position type for tracking enumertor position.
+ ///
+ private enum Position {
+ BeforeFirst,
+ InSet,
+ AfterLast
+ }
+
+ #endregion
+
+ }
+
+ #endregion
+
+ #region IMetaList Interface
+
+ ///
+ /// The count of all permutations that will be returned.
+ /// If type is MetaCollectionType.WithholdGeneratedSets, then this does not double count permutations with multiple identical values.
+ /// I.e. count of permutations of "AAB" will be 3 instead of 6.
+ /// If type is MetaCollectionType.WithRepetition, then this is all combinations and is therefore N!, where N is the number of values.
+ ///
+ public long Count {
+ get {
+ return myCount;
+ }
+ }
+
+ ///
+ /// The type of Permutations set that is generated.
+ ///
+ public GenerateOption Type {
+ get {
+ return myMetaCollectionType;
+ }
+ }
+
+ ///
+ /// The upper index of the meta-collection, equal to the number of items in the initial set.
+ ///
+ public int UpperIndex {
+ get {
+ return myValues.Count;
+ }
+ }
+
+ ///
+ /// The lower index of the meta-collection, equal to the number of items returned each iteration.
+ /// For Permutation, this is always equal to the UpperIndex.
+ ///
+ public int LowerIndex {
+ get {
+ return myValues.Count;
+ }
+ }
+
+ #endregion
+
+ #region Heavy Lifting Members
+
+ ///
+ /// Common intializer used by the multiple flavors of constructors.
+ ///
+ ///
+ /// Copies information provided and then creates a parellel int array of lexicographic
+ /// orders that will be used for the actual permutation algorithm.
+ /// The input array is first sorted as required for WithoutRepetition and always just for consistency.
+ /// This array is constructed one of two way depending on the type of the collection.
+ ///
+ /// When type is MetaCollectionType.WithRepetition, then all N! permutations are returned
+ /// and the lexicographic orders are simply generated as 1, 2, ... N.
+ /// E.g.
+ /// Input array: {A A B C D E E}
+ /// Lexicograhpic Orders: {1 2 3 4 5 6 7}
+ ///
+ /// When type is MetaCollectionType.WithoutRepetition, then fewer are generated, with each
+ /// identical element in the input array not repeated. The lexicographic sort algorithm
+ /// handles this natively as long as the repetition is repeated.
+ /// E.g.
+ /// Input array: {A A B C D E E}
+ /// Lexicograhpic Orders: {1 1 2 3 4 5 5}
+ ///
+ private void Initialize(IList values, GenerateOption type, IComparer comparer) {
+ myMetaCollectionType = type;
+ myValues = new List(values.Count);
+ myValues.AddRange(values);
+ myLexicographicOrders = new int[values.Count];
+ if(type == GenerateOption.WithRepetition) {
+ for(int i = 0; i < myLexicographicOrders.Length; ++i) {
+ myLexicographicOrders[i] = i;
+ }
+ }
+ else {
+ if(comparer == null) {
+ comparer = new SelfComparer();
+ }
+ myValues.Sort(comparer);
+ int j = 1;
+ if(myLexicographicOrders.Length > 0) {
+ myLexicographicOrders[0] = j;
+ }
+ for(int i = 1; i < myLexicographicOrders.Length; ++i) {
+ if(comparer.Compare(myValues[i - 1], myValues[i]) != 0) {
+ ++j;
+ }
+ myLexicographicOrders[i] = j;
+ }
+ }
+ myCount = GetCount();
+ }
+
+ ///
+ /// Calculates the total number of permutations that will be returned.
+ /// As this can grow very large, extra effort is taken to avoid overflowing the accumulator.
+ /// While the algorithm looks complex, it really is just collecting numerator and denominator terms
+ /// and cancelling out all of the denominator terms before taking the product of the numerator terms.
+ ///
+ /// The number of permutations.
+ private long GetCount() {
+ int runCount = 1;
+ List divisors = new List();
+ List numerators = new List();
+ for(int i = 1; i < myLexicographicOrders.Length; ++i) {
+ numerators.AddRange(SmallPrimeUtility.Factor(i + 1));
+ if(myLexicographicOrders[i] == myLexicographicOrders[i - 1]) {
+ ++runCount;
+ }
+ else {
+ for(int f = 2; f <= runCount; ++f) {
+ divisors.AddRange(SmallPrimeUtility.Factor(f));
+ }
+ runCount = 1;
+ }
+ }
+ for(int f = 2; f <= runCount; ++f) {
+ divisors.AddRange(SmallPrimeUtility.Factor(f));
+ }
+ return SmallPrimeUtility.EvaluatePrimeFactors(SmallPrimeUtility.DividePrimeFactors(numerators, divisors));
+ }
+
+ #endregion
+
+ #region Data and Internal Members
+
+ ///
+ /// A list of T that represents the order of elements as originally provided, used for Reset.
+ ///
+ private List myValues;
+
+ ///
+ /// Parrellel array of integers that represent the location of items in the myValues array.
+ /// This is generated at Initialization and is used as a performance speed up rather that
+ /// comparing T each time, much faster to let the CLR optimize around integers.
+ ///
+ private int[] myLexicographicOrders;
+
+ ///
+ /// Inner class that wraps an IComparer around a type T when it is IComparable
+ ///
+ private class SelfComparer : IComparer {
+ public int Compare(U x, U y) {
+ return ((IComparable)x).CompareTo(y);
+ }
+ }
+
+ ///
+ /// The count of all permutations. Calculated at Initialization and returned by Count property.
+ ///
+ private long myCount;
+
+ ///
+ /// The type of Permutations that this was intialized from.
+ ///
+ private GenerateOption myMetaCollectionType;
+
+ #endregion
+
+ }
+}
diff --git a/src/Numerics/Combinatorics/SmallPrimeUtility.cs b/src/Numerics/Combinatorics/SmallPrimeUtility.cs
new file mode 100755
index 000000000..baaa514f6
--- /dev/null
+++ b/src/Numerics/Combinatorics/SmallPrimeUtility.cs
@@ -0,0 +1,151 @@
+// Copyright 2008 Adrian Akison
+// Distributed under license terms of CPOL http://www.codeproject.com/info/cpol10.aspx
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Collections;
+
+namespace MathNet.Numerics.Combinations
+{
+ ///
+ /// Utility class that maintains a small table of prime numbers and provides
+ /// simple implementations of Prime Factorization algorithms.
+ /// This is a quick and dirty utility class to support calculations of permutation
+ /// sets with indexes under 2^31.
+ /// The prime table contains all primes up to Sqrt(2^31) which are all of the primes
+ /// requires to factorize any Int32 positive integer.
+ ///
+ public class SmallPrimeUtility {
+ ///
+ /// Utility class, no instances allowed.
+ ///
+ private SmallPrimeUtility() {
+ ;
+ }
+
+ ///
+ /// Performs a prime factorization of a given integer using the table of primes in PrimeTable.
+ /// Since this will only factor Int32 sized integers, a simple list of factors is returned instead
+ /// of the more scalable, but more difficult to consume, list of primes and associated exponents.
+ ///
+ /// The number to factorize, must be positive.
+ /// A simple list of factors.
+ public static List Factor(int i) {
+ int primeIndex = 0;
+ int prime = PrimeTable[primeIndex];
+ List factors = new List();
+ while(i > 1) {
+ if(i % prime == 0) {
+ factors.Add(prime);
+ i /= prime;
+ }
+ else {
+ ++primeIndex;
+ prime = PrimeTable[primeIndex];
+ }
+ }
+ return factors;
+ }
+
+ ///
+ /// Given two integers expressed as a list of prime factors, multiplies these numbers
+ /// together and returns an integer also expressed as a set of prime factors.
+ /// This allows multiplication to overflow well beyond a Int64 if necessary.
+ ///
+ /// Left Hand Side argument, expressed as list of prime factors.
+ /// Right Hand Side argument, expressed as list of prime factors.
+ /// Product, expressed as list of prime factors.
+ public static List MultiplyPrimeFactors(IList lhs, IList rhs) {
+ List product = new List();
+ foreach(int prime in lhs) {
+ product.Add(prime);
+ }
+ foreach(int prime in rhs) {
+ product.Add(prime);
+ }
+ product.Sort();
+ return product;
+ }
+
+ ///
+ /// Given two integers expressed as a list of prime factors, divides these numbers
+ /// and returns an integer also expressed as a set of prime factors.
+ /// If the result is not a integer, then the result is undefined. That is, 11 / 5
+ /// when divided by this function will not yield a correct result.
+ /// As such, this function is ONLY useful for division with combinatorial results where
+ /// the result is known to be an integer AND the division occurs as the last operation(s).
+ ///
+ /// Numerator argument, expressed as list of prime factors.
+ /// Denominator argument, expressed as list of prime factors.
+ /// Resultant, expressed as list of prime factors.
+ public static List DividePrimeFactors(IList numerator, IList denominator) {
+ List product = new List();
+ foreach(int prime in numerator) {
+ product.Add(prime);
+ }
+ foreach(int prime in denominator) {
+ product.Remove(prime);
+ }
+ return product;
+ }
+
+ ///
+ /// Given a list of prime factors returns the long representation.
+ ///
+ /// Integer, expressed as list of prime factors.
+ /// Standard long representation.
+ public static long EvaluatePrimeFactors(IList value) {
+ long accumulator = 1;
+ foreach(int prime in value) {
+ accumulator *= prime;
+ }
+ return accumulator;
+ }
+
+ ///
+ /// Static initializer, set up prime table.
+ ///
+ static SmallPrimeUtility() {
+ CalculatePrimes();
+ }
+
+ ///
+ /// Calculate all primes up to Sqrt(2^32) = 2^16.
+ /// This table will be large enough for all factorizations for Int32's.
+ /// Small tables are best built using the Sieve Of Eratosthenes,
+ /// Reference: http://primes.utm.edu/glossary/page.php?sort=SieveOfEratosthenes
+ ///
+ private static void CalculatePrimes() {
+ // Build Sieve Of Eratosthenes
+ BitArray sieve = new BitArray(65536, true);
+ for(int possiblePrime = 2; possiblePrime <= 256; ++possiblePrime) {
+ if(sieve[possiblePrime] == true) {
+ // It is prime, so remove all future factors...
+ for(int nonPrime = 2 * possiblePrime; nonPrime < 65536; nonPrime += possiblePrime) {
+ sieve[nonPrime] = false;
+ }
+ }
+ }
+ // Scan sieve for primes...
+ myPrimes = new List();
+ for(int i = 2; i < 65536; ++i) {
+ if(sieve[i] == true) {
+ myPrimes.Add(i);
+ }
+ }
+
+ }
+
+ ///
+ /// A List of all primes from 2 to 2^16.
+ ///
+ public static IList PrimeTable {
+ get {
+ return myPrimes;
+ }
+ }
+
+ private static List myPrimes = new List();
+
+ }
+}
diff --git a/src/Numerics/Combinatorics/Variations.cs b/src/Numerics/Combinatorics/Variations.cs
new file mode 100755
index 000000000..2e3140952
--- /dev/null
+++ b/src/Numerics/Combinatorics/Variations.cs
@@ -0,0 +1,454 @@
+// Copyright 2008 Adrian Akison
+// Distributed under license terms of CPOL http://www.codeproject.com/info/cpol10.aspx
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MathNet.Numerics.Combinations
+{
+ ///
+ /// Variations defines a meta-collection, typically a list of lists, of all possible
+ /// ordered subsets of a particular size from the set of values.
+ /// This list is enumerable and allows the scanning of all possible Variations using a simple
+ /// foreach() loop even though the variations are not all in memory.
+ ///
+ ///
+ /// The MetaCollectionType parameter of the constructor allows for the creation of
+ /// normal Variations and Variations with Repetition.
+ ///
+ /// When given an input collect {A B C} and lower index of 2, the following sets are generated:
+ /// MetaCollectionType.WithoutRepetition generates 6 sets: =>
+ /// {A B}, {A B}, {B A}, {B C}, {C A}, {C B}
+ /// MetaCollectionType.WithRepetition generates 9 sets:
+ /// {A A}, {A B}, {A B}, {B A}, {B B }, {B C}, {C A}, {C B}, {C C}
+ ///
+ /// The equality of multiple inputs is not considered when generating variations.
+ ///
+ /// The type of the values within the list.
+ public class Variations : IMetaCollection {
+ #region Constructors
+
+ ///
+ /// No default constructor, must provided a list of values and size.
+ ///
+ protected Variations() {
+ ;
+ }
+
+ ///
+ /// Create a variation set from the indicated list of values.
+ /// The upper index is calculated as values.Count, the lower index is specified.
+ /// Collection type defaults to MetaCollectionType.WithoutRepetition
+ ///
+ /// List of values to select Variations from.
+ /// The size of each variation set to return.
+ public Variations(IList values, int lowerIndex) {
+ Initialize(values, lowerIndex, GenerateOption.WithoutRepetition);
+ }
+
+ ///
+ /// Create a variation set from the indicated list of values.
+ /// The upper index is calculated as values.Count, the lower index is specified.
+ ///
+ /// List of values to select variations from.
+ /// The size of each vatiation set to return.
+ /// Type indicates whether to use repetition in set generation.
+ public Variations(IList values, int lowerIndex, GenerateOption type) {
+ Initialize(values, lowerIndex, type);
+ }
+
+ #endregion
+
+ #region IEnumerable Interface
+
+ ///
+ /// Gets an enumerator for the collection of Variations.
+ ///
+ /// The enumerator.
+ public IEnumerator> GetEnumerator() {
+ if(Type == GenerateOption.WithRepetition) {
+ return new EnumeratorWithRepetition(this);
+ }
+ else {
+ return new EnumeratorWithoutRepetition(this);
+ }
+ }
+
+ ///
+ /// Gets an enumerator for the collection of Variations.
+ ///
+ /// The enumerator.
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ if(Type == GenerateOption.WithRepetition) {
+ return new EnumeratorWithRepetition(this);
+ }
+ else {
+ return new EnumeratorWithoutRepetition(this);
+ }
+ }
+
+ #endregion
+
+ #region Enumerator Inner Class
+
+ ///
+ /// An enumerator for Variations when the type is set to WithRepetition.
+ ///
+ public class EnumeratorWithRepetition : IEnumerator> {
+
+ #region Constructors
+
+ ///
+ /// Construct a enumerator with the parent object.
+ ///
+ /// The source Variations object.
+ public EnumeratorWithRepetition(Variations source) {
+ myParent = source;
+ Reset();
+ }
+
+ #endregion
+
+ #region IEnumerator interface
+
+ ///
+ /// Resets the Variations enumerator to the first variation.
+ ///
+ public void Reset() {
+ myCurrentList = null;
+ myListIndexes = null;
+ }
+
+ ///
+ /// Advances to the next variation.
+ ///
+ /// True if successfully moved to next variation, False if no more variations exist.
+ ///
+ /// Increments the internal myListIndexes collection by incrementing the last index
+ /// and overflow/carrying into others just like grade-school arithemtic. If the
+ /// finaly carry flag is set, then we would wrap around and are therefore done.
+ ///
+ public bool MoveNext() {
+ int carry = 1;
+ if(myListIndexes == null) {
+ myListIndexes = new List();
+ for(int i = 0; i < myParent.LowerIndex; ++i) {
+ myListIndexes.Add(0);
+ }
+ carry = 0;
+ }
+ else {
+ for(int i = myListIndexes.Count - 1; i >= 0 && carry > 0; --i) {
+ myListIndexes[i] += carry;
+ carry = 0;
+ if(myListIndexes[i] >= myParent.UpperIndex) {
+ myListIndexes[i] = 0;
+ carry = 1;
+ }
+ }
+ }
+ myCurrentList = null;
+ return carry != 1;
+ }
+
+ ///
+ /// The current variation
+ ///
+ public IList Current {
+ get {
+ ComputeCurrent();
+ return myCurrentList;
+ }
+ }
+
+ ///
+ /// The current variation.
+ ///
+ object System.Collections.IEnumerator.Current {
+ get {
+ ComputeCurrent();
+ return myCurrentList;
+ }
+ }
+
+ ///
+ /// Cleans up non-managed resources, of which there are none used here.
+ ///
+ public void Dispose() {
+ ;
+ }
+
+ #endregion
+
+ #region Heavy Lifting Members
+
+ ///
+ /// Computes the current list based on the internal list index.
+ ///
+ private void ComputeCurrent() {
+ if(myCurrentList == null) {
+ myCurrentList = new List();
+ foreach(int index in myListIndexes) {
+ myCurrentList.Add(myParent.myValues[index]);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Data
+
+ ///
+ /// Parent object this is an enumerator for.
+ ///
+ private Variations myParent;
+
+ ///
+ /// The current list of values, this is lazy evaluated by the Current property.
+ ///
+ private List myCurrentList;
+
+ ///
+ /// An enumertor of the parents list of lexicographic orderings.
+ ///
+ private List myListIndexes;
+
+ #endregion
+ }
+
+ ///
+ /// An enumerator for Variations when the type is set to WithoutRepetition.
+ ///
+ public class EnumeratorWithoutRepetition : IEnumerator> {
+
+ #region Constructors
+
+ ///
+ /// Construct a enumerator with the parent object.
+ ///
+ /// The source Variations object.
+ public EnumeratorWithoutRepetition(Variations source) {
+ myParent = source;
+ myPermutationsEnumerator = (Permutations.Enumerator)myParent.myPermutations.GetEnumerator();
+ }
+
+ #endregion
+
+ #region IEnumerator interface
+
+ ///
+ /// Resets the Variations enumerator to the first variation.
+ ///
+ public void Reset() {
+ myPermutationsEnumerator.Reset();
+ }
+
+ ///
+ /// Advances to the next variation.
+ ///
+ /// True if successfully moved to next variation, False if no more variations exist.
+ public bool MoveNext() {
+ bool ret = myPermutationsEnumerator.MoveNext();
+ myCurrentList = null;
+ return ret;
+ }
+
+ ///
+ /// The current variation.
+ ///
+ public IList Current {
+ get {
+ ComputeCurrent();
+ return myCurrentList;
+ }
+ }
+
+ ///
+ /// The current variation.
+ ///
+ object System.Collections.IEnumerator.Current {
+ get {
+ ComputeCurrent();
+ return myCurrentList;
+ }
+ }
+
+ ///
+ /// Cleans up non-managed resources, of which there are none used here.
+ ///
+ public void Dispose() {
+ ;
+ }
+
+ #endregion
+
+ #region Heavy Lifting Members
+
+ ///
+ /// Creates a list of original values from the int permutation provided.
+ /// The exception for accessing current (InvalidOperationException) is generated
+ /// by the call to .Current on the underlying enumeration.
+ ///
+ ///
+ /// To compute the current list of values, the element to use is determined by
+ /// a permutation position with a non-MaxValue value. It is placed at the position in the
+ /// output that the index value indicates.
+ ///
+ /// E.g. Variations of 6 choose 3 without repetition
+ /// Input array: {A B C D E F}
+ /// Permutations: {- 1 - - 3 2} (- is Int32.MaxValue)
+ /// Generates set: {B F E}
+ ///
+ private void ComputeCurrent() {
+ if(myCurrentList == null) {
+ myCurrentList = new List();
+ int index = 0;
+ IList currentPermutation = (IList)myPermutationsEnumerator.Current;
+ for(int i = 0; i < myParent.LowerIndex; ++i) {
+ myCurrentList.Add(myParent.myValues[0]);
+ }
+ for(int i = 0; i < currentPermutation.Count; ++i) {
+ int position = currentPermutation[i];
+ if(position != Int32.MaxValue) {
+ myCurrentList[position] = myParent.myValues[index];
+ if(myParent.Type == GenerateOption.WithoutRepetition) {
+ ++index;
+ }
+ }
+ else {
+ ++index;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Data
+
+ ///
+ /// Parent object this is an enumerator for.
+ ///
+ private Variations myParent;
+
+ ///
+ /// The current list of values, this is lazy evaluated by the Current property.
+ ///
+ private List myCurrentList;
+
+ ///
+ /// An enumertor of the parents list of lexicographic orderings.
+ ///
+ private Permutations.Enumerator myPermutationsEnumerator;
+
+ #endregion
+ }
+ #endregion
+
+ #region IMetaList Interface
+
+ ///
+ /// The number of unique variations that are defined in this meta-collection.
+ ///
+ ///
+ /// Variations with repetitions does not behave like other meta-collections and it's
+ /// count is equal to N^P, where N is the upper index and P is the lower index.
+ ///
+ public long Count {
+ get {
+ if(Type == GenerateOption.WithoutRepetition) {
+ return myPermutations.Count;
+ }
+ else {
+ return (long)Math.Pow(UpperIndex, LowerIndex);
+ }
+ }
+ }
+
+ ///
+ /// The type of Variations set that is generated.
+ ///
+ public GenerateOption Type {
+ get {
+ return myMetaCollectionType;
+ }
+ }
+
+ ///
+ /// The upper index of the meta-collection, equal to the number of items in the initial set.
+ ///
+ public int UpperIndex {
+ get {
+ return myValues.Count;
+ }
+ }
+
+ ///
+ /// The lower index of the meta-collection, equal to the number of items returned each iteration.
+ ///
+ public int LowerIndex {
+ get {
+ return myLowerIndex;
+ }
+ }
+
+ #endregion
+
+ #region Heavy Lifting Members
+
+ ///
+ /// Initialize the variations for constructors.
+ ///
+ /// List of values to select variations from.
+ /// The size of each variation set to return.
+ /// The type of variations set to generate.
+ private void Initialize(IList values, int lowerIndex, GenerateOption type) {
+ myMetaCollectionType = type;
+ myLowerIndex = lowerIndex;
+ myValues = new List();
+ myValues.AddRange(values);
+ if(type == GenerateOption.WithoutRepetition) {
+ List myMap = new List();
+ int index = 0;
+ for(int i = 0; i < myValues.Count; ++i) {
+ if(i >= myValues.Count - myLowerIndex) {
+ myMap.Add(index++);
+ }
+ else {
+ myMap.Add(Int32.MaxValue);
+ }
+ }
+ myPermutations = new Permutations(myMap);
+ }
+ else {
+ ; // myPermutations isn't used.
+ }
+ }
+
+ #endregion
+
+ #region Data
+
+ ///
+ /// Copy of values object is intialized with, required for enumerator reset.
+ ///
+ private List myValues;
+
+ ///
+ /// Permutations object that handles permutations on int for variation inclusion and ordering.
+ ///
+ private Permutations myPermutations;
+
+ ///
+ /// The type of the variation collection.
+ ///
+ private GenerateOption myMetaCollectionType;
+
+ ///
+ /// The lower index defined in the constructor.
+ ///
+ private int myLowerIndex;
+
+ #endregion
+ }
+}
diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index 620bb6f0b..4cc973c96 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -32,7 +32,10 @@ Linear Algebra: optimized range checking in vectors and matricestrue
1701;1702;1705;1591;1573
true
+ net40
+
+