private void CalcRank() { int isUsed = 0; int toGo = Choices; rank = 0; foreach (int e1 in this.data) { isUsed |= 1 << e1; int digit = 0; for (int e2 = 0; e2 < e1; ++e2) { if ((isUsed & 1 << e2) == 0) { ++digit; } } rank += digit * Combinatoric.Factorial(--toGo); } if (toGo != 0) { rank /= Combinatoric.Factorial(toGo); } }
/// <summary> /// Initializes a new multicombination from elements supplied in <em>source</em> picked /// from the supplied number of <em>choices</em>. /// </summary> /// <param name="choices">Number of values to pick from.</param> /// <param name="source">Array of integers.</param> /// <remarks> /// Supplying a value for <em>choices</em> that is greater than the number of elements in <em>source</em> /// will instantiate a <em>k</em>-multicombination also known as a <em>k</em>-combination with repetition. /// </remarks> /// <example><code source="..\Examples\Multicombination\McExample04\McExample04.cs" lang="cs"/></example> /// <exception cref="ArgumentNullException">When <em>source</em> is <b>null</b>.</exception> /// <exception cref="ArgumentOutOfRangeException">When <em>source</em> contains invalid data; when <em>choices</em> is 0 and <em>source</em> is not empty.</exception> public Multicombination(int choices, int[] source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (choices < 0) { throw new ArgumentOutOfRangeException(nameof(choices), "Value is less than zero."); } if (choices == 0 && source.Length > 0) { throw new ArgumentOutOfRangeException(nameof(choices), "Value is zero and picks is nonzero."); } this.data = new int[source.Length]; source.CopyTo(this.data, 0); Array.Sort(this.data); this.choices = choices; CalcRowCount(); foreach (int element in this.data) { if (element < 0 || element >= choices) { throw new ArgumentOutOfRangeException(nameof(source), "Element is out of range."); } } // // Perform ranking: // this.rank = 0; if (RowCount == 0) { return; } int comboElement = this[0]; int ji = 0; for (int ki = 0;;) { for (; ji < comboElement; ++ji) { this.rank += Combinatoric.BinomialCoefficient(Choices + Picks - ji - 2, Picks - ki - 1); } ++ki; if (ki >= Picks) { break; } ji = comboElement + 1; comboElement = this[ki] - this[ki - 1] + ji; } }
/// <summary> /// Initializes a new combination from elements supplied in <em>source</em> picked /// from the supplied number of <em>choices</em>. /// </summary> /// <param name="choices">Number of values to pick from.</param> /// <param name="source">Array of integers.</param> /// <remarks> /// Supplying a value for <em>choices</em> that is greater than the number of elements in <em>source</em> /// will instantiate a <em>k</em>-combination also known as a pick-combination. /// </remarks> /// <example><code source="..\Examples\Combination\CnExample04\CnExample04.cs" lang="cs"/></example> /// <exception cref="ArgumentNullException">When <em>source</em> is <b>null</b>.</exception> /// <exception cref="ArgumentOutOfRangeException"> /// When length of <em>source</em> is greater than <em>picks</em>; when <em>source</em> contains invalid data. /// </exception> public Combination(int choices, int[] source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (choices < 0) { throw new ArgumentOutOfRangeException(nameof(choices), "Value is less than zero."); } if (choices < source.Length) { throw new ArgumentOutOfRangeException(nameof(choices), "Value is less than picks."); } this.data = new int[source.Length]; source.CopyTo(this.data, 0); Array.Sort(this.data); this.choices = choices; CalcRowCount(); for (int ki = 0; ki < Picks; ++ki) { if (this[ki] < 0 || this[ki] >= choices) { throw new ArgumentOutOfRangeException(nameof(source), "Element is out of range."); } else if (ki > 0 && this[ki] == this[ki - 1]) { throw new ArgumentOutOfRangeException(nameof(source), "Elements must be unique."); } } // // Perform ranking: // this.rank = 0; int ji = 0; for (int ki = 0; ki < Picks; ++ki) { for (; ji < this[ki]; ++ji) { this.rank += Combinatoric.BinomialCoefficient(Choices - ji - 1, Picks - ki - 1); } ji = this[ki] + 1; } }
private void CalcRowCount() { if (Picks == 0) { rowCount = 0; } else { rowCount = Combinatoric.Factorial(Choices); if (Choices != Picks) { rowCount /= Combinatoric.Factorial(Choices - Picks); } } }
// On entry: elements allocated for choices. // On exit: result will be in elements. private static void CalcPlainUnrank(int[] elements, long plainRank) { elements[0] = 0; for (int ei = 1; ei < elements.Length; ++ei) { int yd = (int)(Combinatoric.Factorial(elements.Length) / Combinatoric.Factorial(ei + 1)); int yi = (int)((plainRank / yd) % ((ei + 1) * 2)); int ip = yi <= ei ? ei - yi : yi - ei - 1; for (int si = ei; si > ip; --si) { elements[si] = elements[si - 1]; } elements[ip] = ei; } }
/// <summary>Initializes a new permutation of <see cref="Rank"/> 0 with the supplied number of elements.</summary> /// <param name="choices">Number of elements in the sequence.</param> /// <example><code source="..\Examples\Permutation\PnExample01\PnExample01.cs" lang="cs"/></example> /// <exception cref="ArgumentOutOfRangeException">When <em>choices</em> is less than 0 or greater than 20.</exception> public Permutation(int choices) { if (choices < 0) { throw new ArgumentOutOfRangeException(nameof(choices), "Value is less than zero."); } if (choices > MaxChoices) { throw new ArgumentOutOfRangeException(nameof(choices), "Value is greater than maximum allowed."); } this.data = new int[choices]; for (int ei = 0; ei < choices; ++ei) { this[ei] = ei; } this.choices = choices; this.rowCount = choices == 0 ? 0 : Combinatoric.Factorial(choices); this.rank = 0; }
private void CalcRowCount() => rowCount = Picks == 0 ? 0 : Combinatoric.BinomialCoefficient(Choices, Picks);