public int GetIndex(bool sorted, int[] kIndexes) { // This function returns the proper index to an entry in the sorted binomial coefficient table from // the underlying values in KIndexes. For example, for the 13 chooose 5 example which // corresponds to 5 card poker hand ranks, then AKQJT (which is the greatest hand in the table) would // be passed as value 12, 11, 10, 9, and 8, and the return value would be 1286, which is the highest // element. Note that if the Sorted flag is false, then the values in KIndexes will be put into sorted // order and returned that way. The sorted flag must be set to false if KIndexes is not in descending order. // // Handle the N choose 1 case. if (GroupSize == 1) { return(kIndexes[0]); } int LoopIndex, n, Index = 0; int[] IndexArray; if (!sorted) { ArraySorter <int> .SortDescending(kIndexes); } for (LoopIndex = 0; LoopIndex < GroupSize - 1; LoopIndex++) { IndexArray = Indexes[LoopIndex]; n = kIndexes[LoopIndex]; Index += IndexArray[n]; } Index += kIndexes[GroupSize - 1]; return(Index); }
public BigInteger GetRank(bool sorted, int[] kIndexes, int groupSize = -1) { // This method returns the rank of the combination in kIndexes. For example, with the 13 chooose 5 case which // corresponds to 5 card poker hand ranks, then AKQJT (which is the greatest hand in the table) would // be passed as value 12, 11, 10, 9, and 8, and the return value would be 1286, which is the highest // element. Note that if the Sorted flag is false, then the values in KIndexes will be put into sorted // descending order and returned that way. The sorted flag must be set to false if KIndexes is not in descending order. // // If the optional argument groupSize is specified, then it must be <= to the GroupSize used to create the instance. // groupSize = (groupSize == -1) ? GroupSize : groupSize; // Handle the n choose 1 case. if (groupSize == 1) { return(kIndexes[0]); } // Handle the n choose n case. if (groupSize == NumItems) { return(0); } int loopIndex, n; // The times that Pascal's triangle may not have been legitimately created are handled above. // So, if it has not been created, then throw an exception. if (PasTri == null) { string s = "BinCoeffBigInt:GetNumCombos: Error - Pascal's Triangle has not been created."; ApplicationException ae = new ApplicationException(s); throw ae; } BigInteger rank = 0; BigInteger[] indexArray; if (!sorted) { ArraySorter <int> .SortDescending(kIndexes); } int startIndex = GroupSize - groupSize; int kIndex = 0; for (loopIndex = startIndex; loopIndex < GroupSizeM1; loopIndex++) { indexArray = PasTri[loopIndex]; n = kIndexes[kIndex++]; rank += indexArray[n]; } rank += kIndexes[groupSize - 1]; return(rank); }
public uint GetRank(bool sorted, int[] kIndexes, out bool overflow, int groupSize = -1) { // This method returns the rank of the combination in kIndexes. For example, with the 13 chooose 5 case which // corresponds to 5 card poker hand ranks, then AKQJT (which is the greatest hand in the table) would // be passed as value 12, 11, 10, 9, and 8, and the return value would be 1286, which is the highest // element. Note that if the Sorted flag is false, then the values in KIndexes will be put into sorted // order and returned that way. The sorted flag must be set to false if KIndexes is not in descending order. // // If the optional argument groupSize is specified, then it must be <= to the GroupSize used to create the instance. // string s; overflow = false; groupSize = (groupSize == -1) ? GroupSize : groupSize; if (groupSize == 0) { s = "BinCoeffL:GetNumCombos: groupSize equals zero. This is not allowed."; ApplicationException ae = new ApplicationException(s); throw ae; } // Handle the n choose 1 case. if (groupSize == 1) { return((uint)kIndexes[0]); } // Handle the n choose n case. if (groupSize == NumItems) { return(0); } int loopIndex, n; // The times that Pascal's triangle may not have been legitimately created are handled above. // So, if it has not been created, then throw an exception. if (PasTri == null) { s = "BinCoeffL:GetNumCombos: Error - Pascal's Triangle has not been created. "; ApplicationException ae = new ApplicationException(s); throw ae; } uint rank = 0; uint[] indexArray; if (!sorted) { ArraySorter <int> .SortDescending(kIndexes); } int startIndex = GroupSize - groupSize; int kIndex = 0; // for (LoopIndex = 0; LoopIndex < GroupSize - 1; LoopIndex++) for (loopIndex = startIndex; loopIndex < GroupSizeM1; loopIndex++) { indexArray = PasTri[loopIndex]; n = kIndexes[kIndex++]; // Check for overflow first. if ((indexArray.Length > n) && (rank <= uint.MaxValue - indexArray[n])) { rank += indexArray[n]; } else { overflow = true; return(0); } } if (rank <= uint.MaxValue - (ulong)kIndexes[groupSize - 1]) { rank += (uint)kIndexes[groupSize - 1]; } else { overflow = true; return(0); } return(rank); }
public ulong GetRank(int numItems, int groupSize, bool sorted, int[] kIndexes) { // This function returns the proper index to an entry in the sorted binomial coefficient table from // the underlying values in KIndexes. For example, for the 13 chooose 5 example which // corresponds to 5 card poker hand ranks, then AKQJT (which is the greatest hand in the table) would // be passed as value 12, 11, 10, 9, and 8, and the return value would be 1286, which is the highest // element. Note that if the Sorted flag is false, then the values in KIndexes will be put longo sorted // order and returned that way. The sorted flag must be set to false if KIndexes is not in descending order. // // Notes: 13 choose 4 = 715. Start at 2nd index array. Examples: // 13 choose 4 = 495 + 165 + 45 + 9 = 714 -> add one since these numbers start from zero -> 715. // 13 choose 3 = 220 + 55 + 10 = 285 (+ 1) = 286. // Both of the above cases are correct. // 12 choose 5 = 792. Start at 1st index array, 2nd entry. Examples: // 12 choose 5 = 462 + 210 + 84 + 28 + 7 = 791 (+ 1) = 792. // 11 choose 5 = 256 + 126 + 56 + 21 + 6 = 461 (+ 1) = 462. // Both of the above cases are correct. // 12 choose 4 = 495. Start at 2nd index and start off at 2nd entry in array. // 12 choose 4 = 494 (+ 1) = 495. // 9 choose 3 = 83 (+ 1) = 84. Start at 3rd index, // 9 choose 3 = 56 + 21 + 6 = 83 ( + 1) = 84. // 8 choose 2 = 27 ( + 1)= 28. Start at // // Proof that C(n, k) = C(n, n-k): // N! / K! (N - K)! = N! / (N - K) ! (N - (N - K))! // K! (N - K)! = (N - K)! (N - (N - K))! // K! = (N - (N - K))! // K! = K! // Benchmark of dynamic -> 18 times slower than static types: // https://dev.to/mokenyon/benchmarking-and-exploring-c-s-dynamic-keyword-1l5i#:~:text=You%20can%20see%20that%20the,18x%20slower%20and%20allocated%20memory. // http://ghcimdm4u.weebly.com/uploads/1/3/5/8/13589538/5.4.pdf - Proof of each binomial coefficient can be obtained from N choose K. // https://www.mathsisfun.com/algebra/binomial-theorem.html#coefficients - shows how Pascal's triangle is composed of binomial coefficients. // https://math.libretexts.org/Bookshelves/Mathematical_Logic_and_Proof/Book%3A_Book_of_Proof_(Hammack)/03%3A_Counting/3.06%3A_Pascal%E2%80%99s_Triangle_and_the_Binomial_Theorem // The above link has a good explanation on Pascal's Triangle and the Binomial Theorem. // https://math.stackexchange.com/questions/453843/why-does-pascals-triangle-give-the-binomial-coefficients - Why does Pascal's Triangle give the Binomial Coefficients? // https://en.wikipedia.org/wiki/Combinatorial_number_system - Combinatorial number system (Ordering Combinations). // https://www.developertyrone.com/blog/generating-the-mth-lexicographical-element-of-a-mathematical-combination/ - Generating the mth Lexicographical Element of a Mathematical Combination // https://stackoverflow.com/questions/29010699/can-i-add-two-generic-values-in-java - indicates that Java has same issue as C# when adding generic variables. // https://arxiv.org/pdf/1601.05794.pdf proof of n choose k = rank = c1 choose k + c2 choose (k - 1) + ... + cn choose 1, // where c1, c2, ... ck are one of the kIndexes and k is groupSize. PROOF OF BIJECTION FOR COMBINATORIAL NUMBER SYSTEM. // // 2 ^ 32 = 4,294,967,296 // 34 C 17 = 2,333,606,220 // 35 C 16 = 4,059,928,950 // 35 C 17 = 4,537,567,650 // 50 C 25 = 126,410,606,437,752 // 2 ^ 64 = 18,446,744,073,709,551,616 // 67 C 33 = 14,226,520,737,620,288,370 // Calling BinCoeffBase.GetNumCombos(67, 33, out bool overflow) overflows. // 68 C 33 = 27,640,097,433,090,845,976 // // 100 C 50 = 100,891,344,545,564,193,334,812,497,256 // 200 C 100 = 90,548,514,656,103,281,165,404,177,077,484,163,874,504,589,675,413,336,841,320 // 1000 C 500 = 27028824094543656951561469362597527549615200844654828700739287510662542870552219389861248392450237016536260608502154610480220975 // 00506799175498942196995184754236654842637517333561624640797378873443645741611194976045710449857562878805146009942194267523669158 // 56603136862602484428109296905863799821216320 if ((numItems > NumItems) || (groupSize > GroupSize)) { ApplicationException ae = new ApplicationException("BinCoeffL:GetRank: Input parameter(s) greater than expected."); throw ae; } int loopIndex; long n; ulong rank = 0; ulong[] indexArray; if (!sorted) { ArraySorter <int> .SortDescending(kIndexes); } int groupOffset = GroupSize - groupSize; int startIndex = NumItems - numItems; for (loopIndex = startIndex; loopIndex < GroupSize - 1; loopIndex++) { indexArray = PasTri[loopIndex]; n = kIndexes[loopIndex + groupOffset]; rank += indexArray[n]; } rank += (ulong)kIndexes[GroupSize - 1]; return(rank); }
public ulong GetRank(bool sorted, int[] kIndexes, out bool overflow, int groupSize = -1) { // This function returns the proper index to an entry in the sorted binomial coefficient table from // the underlying values in KIndexes. For example, for the 13 chooose 5 example which // corresponds to 5 card poker hand ranks, then AKQJT (which is the greatest hand in the table) would // be passed as value 12, 11, 10, 9, and 8, and the return value would be 1286, which is the highest // element. Note that if the Sorted flag is false, then the values in KIndexes will be put into descending // order and returned that way. The sorted flag must be set to false if KIndexes needs to be sorted. // overflow is set to true if the operation overflows. // overflow = false; groupSize = (groupSize == -1) ? GroupSize : groupSize; // Handle the n choose n case. if (groupSize == NumItems) { return(0); } // Handle the n choose 1 case. if (groupSize == 1) { return((ulong)kIndexes[0]); } // The times that Pascal's triangle may not have been legitimately created are handled above. // So, if it has not been created, then throw an exception. if (PasTri == null) { string s = "BinCoeffL:GetNumCombos: Pascal's Triangle has not been created." + "This could occur if the instance is created with 5 choose 5 and then 5 choose 3 is tried."; ApplicationException ae = new ApplicationException(s); throw ae; } ulong rank = 0; int loopIndex; long n; ulong[] indexArray; if (!sorted) { ArraySorter <int> .SortDescending(kIndexes); } int startIndex = GroupSize - groupSize; int kIndex = 0; for (loopIndex = startIndex; loopIndex < GroupSizeM1; loopIndex++) { indexArray = PasTri[loopIndex]; n = kIndexes[kIndex++]; // Check for overflow first. if ((indexArray.Length > n) && (rank <= ulong.MaxValue - indexArray[n])) { rank += indexArray[n]; } else { overflow = true; return(0); } } if (rank <= ulong.MaxValue - (ulong)kIndexes[groupSize - 1]) { rank += (ulong)kIndexes[groupSize - 1]; } else { overflow = true; return(0); } return(rank); }