Example #1
0
        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);
        }
Example #3
0
        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);
        }