From adfa6c4837c808f96daa501330151198c504e415 Mon Sep 17 00:00:00 2001 From: Daniel Sword Date: Mon, 19 Nov 2018 20:02:15 -0800 Subject: [PATCH] Combinatorics: add method for lexicographic generation of all permutations of a set. --- src/Numerics/Combinatorics.cs | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/Numerics/Combinatorics.cs b/src/Numerics/Combinatorics.cs index fe0503d8..ff62df10 100644 --- a/src/Numerics/Combinatorics.cs +++ b/src/Numerics/Combinatorics.cs @@ -160,6 +160,43 @@ namespace MathNet.Numerics return result; } + /// + /// Lazily generates all permutations lexicographically. + /// Note that the same array is yielded on each iteration, + /// so care is needed when converting to a collection. + /// + /// Number of (distinguishable) elements in the set. + /// A lazy enumeration of all unique permutations of the set. + public static IEnumerable GenerateAllPermutations(int n) + { + // This method follows Algorithm L found in + // Knuth, "Combinatorial Algorithms" The Art of Computer Science vol. 4A, 7.2.1.2 + + if (n < 0) throw new ArgumentOutOfRangeException(nameof(n), Resources.ArgumentNotNegative); + + // We'll repeatedly yield the following array as we generate the permutations. + // The first entry is just the items in lexicographical order. + var a = Enumerable.Range(0, n).ToArray(); + int j, l, swap; + while (true) + { + yield return a; + j = n - 1; + // Following Knuth's notation, the entry a_j is found at position a[j-1]. + while (j > 0 && a[j - 1] >= a[j]) + j--; + if (j == 0) break; // Terminates the algorithm. + l = n; + while (a[j - 1] >= a[l - 1]) + l--; + // Swap aj and al + swap = a[j - 1]; + a[j - 1] = a[l - 1]; + a[l - 1] = swap; + Array.Reverse(a, j, n - j); + } + } + /// /// 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.