using System.Collections;
using System.Collections.Generic;
namespace Combinatorics.Collections
public enum GenerateOption
namespace Combinatorics.Collections
internal static class SmallPrimeUtility
public static List<int> Factor(int i)
var prime = PrimeTable[primeIndex];
var factors = new List<int>();
var remainder = i % prime;
var divResult = remainder == 0 ? i / prime : 0;
var divResult = Math.DivRem(i, prime, out var remainder);
prime = PrimeTable[primeIndex];
public static List<int> DividePrimeFactors(IEnumerable<int> numerator, IEnumerable<int> denominator)
_ = numerator ?? throw new ArgumentNullException(nameof(numerator));
_ = denominator ?? throw new ArgumentNullException(nameof(denominator));
var product = numerator.ToList();
foreach (var prime in denominator)
public static BigInteger EvaluatePrimeFactors(IEnumerable<int> value)
_ = value ?? throw new ArgumentNullException(nameof(value));
foreach (var prime in value)
static SmallPrimeUtility()
PrimeTable = CalculatePrimes();
private static IReadOnlyList<int> CalculatePrimes()
var sieve = new BitArray(65536, true);
for (var possiblePrime = 2; possiblePrime <= 256; ++possiblePrime)
if (!sieve[possiblePrime])
for (var nonPrime = 2 * possiblePrime; nonPrime < 65536; nonPrime += possiblePrime)
var primes = new List<int>();
for (var i = 2; i < 65536; ++i)
public static IReadOnlyList<int> PrimeTable { get; }
namespace Combinatorics.Collections
public sealed class Variations<T> : IEnumerable<IReadOnlyList<T>>
public Variations(IEnumerable<T> values, int lowerIndex) : this(values, lowerIndex, GenerateOption.WithoutRepetition)
public Variations(IEnumerable<T> values, int lowerIndex, GenerateOption type)
_myValues = values.ToList();
if (type != GenerateOption.WithoutRepetition)
var myMap = new List<int>(_myValues.Count);
for (var i = 0; i < _myValues.Count; ++i)
myMap.Add(i >= _myValues.Count - LowerIndex ? index++ : int.MaxValue);
_myPermutations = new Permutations<int>(myMap);
public IEnumerator<IReadOnlyList<T>> GetEnumerator() => Type == GenerateOption.WithRepetition ? (IEnumerator<IReadOnlyList<T>>)new EnumeratorWithRepetition(this) : new EnumeratorWithoutRepetition(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public sealed class EnumeratorWithRepetition : IEnumerator<IReadOnlyList<T>>
public EnumeratorWithRepetition(Variations<T> source)
void IEnumerator.Reset() => throw new NotSupportedException();
if (_myListIndexes == null)
_myListIndexes = new List<int>(_myParent.LowerIndex);
for (var i = 0; i < _myParent.LowerIndex; ++i)
for (var i = _myListIndexes.Count - 1; i >= 0 && carry > 0; --i)
_myListIndexes[i] += carry;
if (_myListIndexes[i] < _myParent.UpperIndex)
public IReadOnlyList<T> Current
object IEnumerator.Current => Current;
private void ComputeCurrent()
if (_myCurrentList != null)
_ = _myListIndexes ?? throw new InvalidOperationException($"Cannot call {nameof(Current)} before calling {nameof(MoveNext)}.");
_myCurrentList = new List<T>(_myListIndexes.Count);
foreach (var index in _myListIndexes)
_myCurrentList.Add(_myParent._myValues[index]);
private readonly Variations<T> _myParent;
private List<T>? _myCurrentList;
private List<int>? _myListIndexes;
public sealed class EnumeratorWithoutRepetition : IEnumerator<IReadOnlyList<T>>
public EnumeratorWithoutRepetition(Variations<T> source)
_myPermutationsEnumerator = (Permutations<int>.Enumerator)_myParent._myPermutations!.GetEnumerator();
void IEnumerator.Reset() => throw new NotSupportedException();
var ret = _myPermutationsEnumerator.MoveNext();
public IReadOnlyList<T> Current
object IEnumerator.Current => Current;
public void Dispose() => _myPermutationsEnumerator.Dispose();
private void ComputeCurrent()
if (_myCurrentList != null)
_myCurrentList = new List<T>(_myParent.LowerIndex);
var currentPermutation = _myPermutationsEnumerator.Current;
for (var i = 0; i < _myParent.LowerIndex; ++i)
_myCurrentList.Add(_myParent._myValues[0]);
foreach (var position in currentPermutation)
if (position != int.MaxValue)
_myCurrentList[position] = _myParent._myValues[index];
if (_myParent.Type == GenerateOption.WithoutRepetition)
private readonly Variations<T> _myParent;
private List<T>? _myCurrentList;
private readonly Permutations<int>.Enumerator _myPermutationsEnumerator;
public BigInteger Count => Type == GenerateOption.WithoutRepetition ? _myPermutations!.Count : BigInteger.Pow(UpperIndex, LowerIndex);
public GenerateOption Type { get; }
public int UpperIndex => _myValues.Count;
public int LowerIndex { get; }
private readonly List<T> _myValues;
private readonly Permutations<int>? _myPermutations;
namespace Combinatorics.Collections
public sealed class Permutations<T> : IEnumerable<IReadOnlyList<T>>
public Permutations(IEnumerable<T> values) : this(values, GenerateOption.WithoutRepetition, null)
public Permutations(IEnumerable<T> values, GenerateOption type) : this(values, type, null)
public Permutations(IEnumerable<T> values, IComparer<T>? comparer) : this(values, GenerateOption.WithoutRepetition, comparer)
public Permutations(IEnumerable<T> values, GenerateOption type, IComparer<T>? comparer)
_ = values ?? throw new ArgumentNullException(nameof(values));
_myValues = values.ToList();
_myLexicographicOrders = new int[_myValues.Count];
if (type == GenerateOption.WithRepetition)
for (var i = 0; i < _myLexicographicOrders.Length; ++i)
_myLexicographicOrders[i] = i;
comparer ??= Comparer<T>.Default;
_myValues.Sort(comparer);
if (_myLexicographicOrders.Length > 0)
_myLexicographicOrders[0] = j;
for (var i = 1; i < _myLexicographicOrders.Length; ++i)
if (comparer.Compare(_myValues[i - 1], _myValues[i]) != 0)
_myLexicographicOrders[i] = j;
public IEnumerator<IReadOnlyList<T>> GetEnumerator() => new Enumerator(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public sealed class Enumerator : IEnumerator<IReadOnlyList<T>>
public Enumerator(Permutations<T> source)
_ = source ?? throw new ArgumentNullException(nameof(source));
_myLexicographicalOrders = new int[source._myLexicographicOrders.Length];
_myValues = new List<T>(source._myValues.Count);
source._myLexicographicOrders.CopyTo(_myLexicographicalOrders, 0);
_myPosition = Position.BeforeFirst;
void IEnumerator.Reset() => throw new NotSupportedException();
case Position.BeforeFirst:
_myValues.AddRange(_myParent._myValues);
_myPosition = Position.InSet;
_myPosition = Position.AfterLast;
else if (!NextPermutation())
_myPosition = Position.AfterLast;
throw new ArgumentOutOfRangeException();
return _myPosition != Position.AfterLast;
object IEnumerator.Current => Current;
public IReadOnlyList<T> Current
if (_myPosition == Position.InSet)
return new List<T>(_myValues);
throw new InvalidOperationException();
private bool NextPermutation()
var i = _myLexicographicalOrders.Length - 1;
while (_myLexicographicalOrders[i - 1] >= _myLexicographicalOrders[i])
var j = _myLexicographicalOrders.Length;
while (_myLexicographicalOrders[j - 1] <= _myLexicographicalOrders[i - 1])
j = _myLexicographicalOrders.Length;
private void Swap(int i, int j)
_myValues[i] = _myValues[j];
_myKviTemp = _myLexicographicalOrders[i];
_myLexicographicalOrders[i] = _myLexicographicalOrders[j];
_myLexicographicalOrders[j] = _myKviTemp;
private Position _myPosition = Position.BeforeFirst;
private readonly int[] _myLexicographicalOrders;
private readonly List<T> _myValues;
private readonly Permutations<T> _myParent;
public BigInteger Count { get; }
public GenerateOption Type { get; }
public int UpperIndex => _myValues.Count;
public int LowerIndex => _myValues.Count;
private BigInteger GetCount()
var divisors = Enumerable.Empty<int>();
var numerators = Enumerable.Empty<int>();
for (var i = 1; i < _myLexicographicOrders.Length; ++i)
numerators = numerators.Concat(SmallPrimeUtility.Factor(i + 1));
if (_myLexicographicOrders[i] == _myLexicographicOrders[i - 1])
for (var f = 2; f <= runCount; ++f)
divisors = divisors.Concat(SmallPrimeUtility.Factor(f));
for (var f = 2; f <= runCount; ++f)
divisors = divisors.Concat(SmallPrimeUtility.Factor(f));
return SmallPrimeUtility.EvaluatePrimeFactors(SmallPrimeUtility.DividePrimeFactors(numerators, divisors));
private readonly List<T> _myValues;
private readonly int[] _myLexicographicOrders;
namespace Combinatorics.Collections
public sealed class Combinations<T> : IEnumerable<IReadOnlyList<T>>
public Combinations(IEnumerable<T> values, int lowerIndex) : this(values, lowerIndex, GenerateOption.WithoutRepetition)
public Combinations(IEnumerable<T> values, int lowerIndex, GenerateOption type)
_ = values ?? throw new ArgumentNullException(nameof(values));
_myValues = values.ToList();
if (type == GenerateOption.WithoutRepetition)
myMap = new List<bool>(_myValues.Count);
myMap.AddRange(_myValues.Select((t, i) => i < _myValues.Count - LowerIndex));
myMap = new List<bool>(_myValues.Count + LowerIndex - 1);
for (var i = 0; i < _myValues.Count - 1; ++i)
for (var i = 0; i < LowerIndex; ++i)
_myPermutations = new Permutations<bool>(myMap);
public IEnumerator<IReadOnlyList<T>> GetEnumerator() => new Enumerator(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public sealed class Enumerator : IEnumerator<IReadOnlyList<T>>
public Enumerator(Combinations<T> source)
_myPermutationsEnumerator = (Permutations<bool>.Enumerator)_myParent._myPermutations.GetEnumerator();
void IEnumerator.Reset() => throw new NotSupportedException();
var ret = _myPermutationsEnumerator.MoveNext();
public IReadOnlyList<T> Current
object IEnumerator.Current => Current;
public void Dispose() => _myPermutationsEnumerator.Dispose();
private void ComputeCurrent()
if (_myCurrentList != null)
_myCurrentList = new List<T>(_myParent.LowerIndex);
var currentPermutation = _myPermutationsEnumerator.Current;
foreach (var p in currentPermutation)
_myCurrentList.Add(_myParent._myValues[index]);
if (_myParent.Type == GenerateOption.WithoutRepetition)
private readonly Combinations<T> _myParent;
private List<T>? _myCurrentList;
private readonly Permutations<bool>.Enumerator _myPermutationsEnumerator;
public BigInteger Count => _myPermutations.Count;
public GenerateOption Type { get; }
public int UpperIndex => _myValues.Count;
public int LowerIndex { get; }
private readonly List<T> _myValues;
private readonly Permutations<bool> _myPermutations;
public static string replaceAt(this string str, int index, int length, string replace)
return str.Remove(index, Math.Min(length, str.Length - index)).Insert(index, replace);
static void Main(string[] args)
string[] inputSet = {"U", "D", "L", "R", "S", "s", "A", "B"};
Combinatorics.Collections.Combinations<string> combinations = new Combinatorics.Collections.Combinations<string>(inputSet, size);
string cformat = $"Combinations of {{A B C D}} choose {size}: size = {combinations.Count}";
Console.WriteLine(cformat);
List<string> allInput = new List<string>();
foreach (IList<string> c in combinations)
for (int i = 0; i < size; i++)
xx = replaceAt(xx, Array.IndexOf(inputSet, c[i]), 1, c[i]);
Combinatorics.Collections.Combinations<string> combinations2 = new Combinatorics.Collections.Combinations<string>(allInput, size2, Combinatorics.Collections.GenerateOption.WithRepetition);
IEnumerator allGood = combinations2.GetEnumerator();
List<string> nana = (List<string>)allGood.Current;
$"{((List<string>)allGood.Current)[2]}");