Exemple #1
0
        private void Test67Choose33()
        {
            // This function tests out the long binomial coefficien class for the case 67 choose 33.
            // This produces one of the largest number of combinations that will fit within a ulong:
            // 14,226,520,737,620,288,370
            //
            // Test out the unsigned long version of GetBinCoeff.  The int version overflows.
            int    n = 67;
            int    k = 33;
            string s;
            bool   overflow;

            // Create the BinCoeff object that will be used for all the tests for the 50 choose 25 case.
            BCL = new BinCoeffL(n, k);
            // ulong numCombos50Choose25 = BCL.TotalCombos;
            if (BCL.TotalCombos != 14226520737620288370)
            {
                s = $"Test67Choose33: Error calculating # of combos - {BCL.TotalCombos}.";
                DisplayMsg(s);
                throw new ApplicationException(s);
            }
            uint  loop;
            ulong rank = 0, highRank = BCL.TotalCombos - 1, rank2;

            int[] kIndexes = new int[k];
            // Try getting the first and last 5 combinations and ranks for this case.
            try
            {
                for (loop = 0; loop < 5; loop++)
                {
                    BCL.GetCombFromRank(rank, kIndexes);
                    rank2 = BCL.GetRank(true, kIndexes, out overflow);
                    if (rank != rank2)
                    {
                        s = $"Test67Choose33: Either rank or combos was not calculated correctly. rank = {rank}, rank2 = {rank2}";
                        DisplayMsg(s);
                        throw new ApplicationException(s);
                    }
                    BCL.GetCombFromRank(highRank, kIndexes);
                    rank2 = BCL.GetRank(true, kIndexes, out overflow);
                    if (highRank != rank2)
                    {
                        s = $"Test67Choose33: Either rank or combos was not calculated correctly. highRank = {highRank}, rank2 = {rank2}";
                        DisplayMsg(s);
                        throw new ApplicationException(s);
                    }
                    rank++;
                    highRank--;
                }
            }
            catch (Exception e)
            {
                DisplayMsg($"Test67Choose33: Exception = {e.Message}.");
                return;
            }
            DisplayMsg("Test67Choose33: completed successfully.");
        }
Exemple #2
0
        private bool TestRankComboulong(int numItems, int groupSize)
        {
            // This method tests getting the rank and combination for the specified case.
            // If the test failed, then false is returned. Otherwise true is returned.
            string s;
            bool   overflow;
            int    n = numItems, k = groupSize;
            // Create the bin coeff object required to get all the combos for this n choose k combination.
            BinCoeffL bcl = new BinCoeffL(n, k);

            // The Kindexes array specifies the indexes for a combination.
            int[] kIndexes = new int[k];
            ulong numCombos = bcl.TotalCombos, rankLoop;

            bcl.GetCombFromRank(numCombos - 1, kIndexes);
            uint numCombos2 = (uint)BinCoeffBase.GetRankAlt(kIndexes, n, k, out overflow) + 1;

            if (numCombos != numCombos2)
            {
                s = $"TestRankComboLong: {n} choose {k}: # of combos not the same with alternate method - {numCombos} .vs. {numCombos2}";
                Console.WriteLine(s);
                return(false);
            }
            ulong rank, offset = 1;

            // Loop thru all the combinations for this n choose k case if # of combos <= 1000000.
            // Otherwise, choose a random rank between 100 & 200.
            if (numCombos > 1000000)
            {
                Random rand = new Random(-12345);
                offset = (ulong)rand.Next(100, 200);
            }
            for (rankLoop = 0; rankLoop < numCombos; rankLoop += offset)
            {
                // Get the k-indexes for this combination.
                bcl.GetCombFromRank(rankLoop, kIndexes);
                // Verify that the Kindexes returned can be used to retrieve the rank of the combination.
                rank = bcl.GetRank(true, kIndexes, out overflow, groupSize);
                if (rank != rankLoop)
                {
                    s = $"TestRankComboLong: {n} choose {k}: GetRank or GetCombFromRank failed - value of {rank} != rank at {rankLoop}";
                    Console.WriteLine(s);
                    return(false);
                }
            }
            s = $"TestRankComboLong: {n} choose {k} completed successfully.";
            Console.WriteLine(s);
            return(true);
        }
Exemple #3
0
        private void Test100Choose95SubCases()
        {
            // This method tests out the new int functionality of specifying a lower n choose k case without having to
            // create a new version of Pascal's Triangle to handle it. This version checks the 100 choose 95 case.
            //
            string    s;
            bool      overflow;
            int       n = 100, k = 95, kLoop;
            BinCoeffL bcl = new BinCoeffL(n, k);
            ulong     numCombos, numCombos2, rank, highRank;
            uint      rankLoop;

            int[] kIndexes = new int[k];

            // Test all subcases of 100 choose 95.
            for (kLoop = k; kLoop > 0; kLoop--)
            {
                numCombos  = bcl.GetNumCombos(n, kLoop);
                numCombos2 = BinCoeffBase.GetCombosCount(n, kLoop);
                if (numCombos != numCombos2)
                {
                    s = $"Test100Choose95SubCases: Error - {n} choose {k}: # of combos does not match.";
                    Console.WriteLine(s);
                    return;
                }
                // Test the lowest 10 ranks and the highest 10 ranks for each subcase test case.
                for (rankLoop = 1; rankLoop <= 10; rankLoop++)
                {
                    bcl.GetCombFromRank(rankLoop, kIndexes, n, kLoop);
                    rank = bcl.GetRank(true, kIndexes, out overflow, kLoop);
                    if (rank != rankLoop)
                    {
                        s = $"Test100Choose95SubCases: Error - {n} choose {kLoop}: rank or combo is wrong.";
                        Console.WriteLine(s);
                        return;
                    }
                    highRank = numCombos - rankLoop;
                    bcl.GetCombFromRank(highRank, kIndexes, n, kLoop);
                    rank = bcl.GetRank(true, kIndexes, out overflow, kLoop);
                    if (rank != highRank)
                    {
                        s = $"Test100Choose95SubCases: Error - {n} choose {kLoop}: high rank or combo is wrong.";
                        Console.WriteLine(s);
                        return;
                    }
                }
            }
        }
        private ulong BenchmarkBCRankAlt(int n, int k, out long ticks)
        {
            // This method benchmarks obtaining the rank for this n choose k case
            // using the Combination.GetRank method.
            //
            ulong rank;

            GC.Collect();
            // Get the combination for a mid in kIndexes.
            var bc = new BinCoeffL(n, k);

            int[] kIndexes = new int[k];
            bc.GetCombFromRank(bc.TotalCombos / 2, kIndexes);
            Stopwatch sw = Stopwatch.StartNew();

            rank = Combination.GetRank(kIndexes, out bool overflow, n, k);
            // Some cases overflow. So, use big integer.
            if (rank == 0)
            {
                rank = (ulong)Combination.GetRankBigInt(kIndexes, n, k);
            }
            sw.Stop();
            ticks = sw.ElapsedTicks;
            return(rank);
        }
        private int[] BenchmarkBCGetComboFromRank(int n, int k, out long ticks)
        {
            // This method benchmarks obtaining the rank for this n choose k case.
            //
            GC.Collect();
            var bc = new BinCoeffL(n, k);

            int[]     kIndexes = new int[k];
            ulong     rank     = bc.TotalCombos / 2;
            Stopwatch sw       = Stopwatch.StartNew();

            bc.GetCombFromRank(rank, kIndexes);
            sw.Stop();
            ticks = sw.ElapsedTicks;
            return(kIndexes);
        }
        private ulong BenchmarkBCRank(int n, int k, out long ticks)
        {
            // This method benchmarks obtaining the rank for this n choose k case.
            //
            ulong rank;

            GC.Collect();
            var bc = new BinCoeffL(n, k);

            int[] kIndexes = new int[k];
            bc.GetCombFromRank(bc.TotalCombos / 2, kIndexes);
            Stopwatch sw = Stopwatch.StartNew();

            rank = bc.GetRank(true, kIndexes, out bool overflow);
            sw.Stop();
            ticks = sw.ElapsedTicks;
            return(rank);
        }
        private void BenchmarkBinCoeffMultiple(int[] numElemArray, int[] numGroupArray)
        {
            // This method benchmarks the n choose k tests for many subcases & ranks, and compares the performance against the Combination class methods.
            // The first benchmark compares the performance of single methods. This one attempts a more "real-life" analysis and calls GetRank and
            // GetComboFromRank 1,000 times for all the subcases for each test case.
            //
            int numItems, groupSize, caseLoop;

            int[]     kIndexes = new int[40];
            ulong     rankSum  = 0;
            int       kLoop;
            bool      overflow;
            BinCoeffL bcl;
            long      ticks, ticksAlt, ticksSum = 0, ticksSumAlt = 0;
            ulong     numCombos, rank, startRank, endRank, rankCount = 1000, rankLoop;
            double    d;
            Stopwatch sw;

            // Benchmark all the subcases.
            for (caseLoop = 0; caseLoop < numElemArray.Length; caseLoop++)
            {
                GC.Collect();
                sw        = Stopwatch.StartNew();
                numItems  = numElemArray[caseLoop];
                groupSize = numGroupArray[caseLoop];
                bcl       = new BinCoeffL(numItems, groupSize);
                for (kLoop = groupSize; kLoop > 0; kLoop--)
                {
                    numCombos = bcl.GetNumCombos(numItems, kLoop);
                    rankSum  += numCombos;
                    startRank = (numCombos / 2) - 500;
                    endRank   = startRank + rankCount;
                    for (rankLoop = startRank; rankLoop < endRank; rankLoop++)
                    {
                        bcl.GetCombFromRank(rankLoop, kIndexes, numItems, kLoop);
                        rank     = bcl.GetRank(true, kIndexes, out overflow, kLoop);
                        rankSum += rank;
                    }
                }
                sw.Stop();
                // Looking at the sum of the return values makes sure that the compiler does not optimize the code away.
                if (rankSum == 0)
                {
                    Console.WriteLine("Error - rankSum = 0?");
                }
                ticks = sw.ElapsedTicks;
                //
                // Benchmark the uint BinCoeff class subcases for 30 choose 15.
                rankSum = 0;
                sw      = Stopwatch.StartNew();
                for (kLoop = groupSize; kLoop > 4; kLoop--)
                {
                    numCombos = Combination.GetNumCombos(numItems, kLoop);
                    rankSum  += numCombos;
                    startRank = (numCombos / 2) - 500;
                    endRank   = startRank + rankCount;
                    for (rankLoop = startRank; rankLoop < endRank; rankLoop++)
                    {
                        Combination.GetCombFromRankLong(rankLoop, kIndexes, numItems, kLoop);
                        rank     = Combination.GetRank(kIndexes, out overflow, numItems, kLoop);
                        rankSum += rank;
                    }
                }
                sw.Stop();
                ticksAlt = sw.ElapsedTicks;
                // Display the results.
                d = (double)ticksAlt / (double)ticks;
                d = Math.Round(d, 2);
                Console.WriteLine($"Multiple methods benchmark for {numItems} choose {groupSize} & subcases .vs. Combination class ratio = {d} to 1.");
                ticksSum    += ticks;
                ticksSumAlt += ticksAlt;
            }
            d = (double)ticksSumAlt / (double)ticksSum;
            d = Math.Round(d, 2);
            Console.WriteLine($"Average for all n choose k cases & subcases .vs. Combination class ratio = {d} to 1.");
            Console.WriteLine();
            // Looking at the sum of the return values makes sure that the compiler does not optimize the code away.
            if (rankSum == 0)
            {
                Console.WriteLine("Error - rankSum = 0?");
            }
        }
Exemple #8
0
        private void VerifyTranslastion50Choose25()
        {
            // This test function verifies that the BinCoeff class has been created correctly and that each
            // combination translates properly to the correct index in the sorted binomial coefficient table.
            // Testing for translating between the index and the KIndexes is also done here.
            //
            int k = 25;

            int[] kIndexes = new int[k];
            int[,] verKIndexes = new int[5, 4] {
                { 24, 23, 22, 21 }, { 25, 23, 22, 21 }, { 25, 24, 22, 21 },
                { 25, 24, 23, 21 }, { 25, 24, 23, 22 }
            };
            uint  verLoop;
            ulong loop, rank, rank2;

            // There are 126,410,606,437,752 unique combinations in this test case, far too many to go thru them all.
            // So, just check out the first 5 and the last 5.
            for (loop = 0; loop < 5; loop++)
            {
                BCL.GetCombFromRank(loop, kIndexes);
                // Verify that the KIndexes can be translated back to the proper index.
                rank = BCL.GetRank(true, kIndexes, out bool overflow);
                if (rank != loop)
                {
                    DisplayMsg("BinCoeffL.GetKindex did not calculate the correct index.");
                    return;
                }
                // Verify that the KIndexes were returned correctly.
                for (verLoop = 0; verLoop < k; verLoop++)
                {
                    if (verLoop < 4)
                    {
                        if (kIndexes[verLoop] != verKIndexes[loop, verLoop])
                        {
                            DisplayMsg("BinCoeffL.GetKindexes did not calculate the correct KIndexes.");
                            return;
                        }
                    }
                    else
                    {
                        if (kIndexes[verLoop] != k - 1 - verLoop)
                        {
                            DisplayMsg("BinCoeffL.GetKindexes did not calculate the correct last index in KIndexes.");
                            return;
                        }
                    }
                }
                rank = 126410606437747 + loop;
                BCL.GetCombFromRank(rank, kIndexes);
                // Verify that the KIndexes can be translated back to the proper index.
                rank2 = BCL.GetRank(true, kIndexes, out overflow);
                if (overflow)
                {
                    DisplayMsg("BinCoeffL.GetRank overflowed.");
                    return;
                }
                if (rank != rank2)
                {
                    DisplayMsg("BinCoeffL.GetRank did not calculate the correct index.");
                    return;
                }
                for (verLoop = 0; verLoop < k; verLoop++)
                {
                    if (verLoop != k - 1)
                    {
                        if (kIndexes[verLoop] != 49 - verLoop)
                        {
                            DisplayMsg("BinCoeffL.GetKindexes did not calculate the correct KIndexes.");
                            return;
                        }
                    }
                    else
                    {
                        if ((uint)kIndexes[verLoop] != 45 - verLoop + loop)
                        {
                            DisplayMsg("BinCoeffL.GetKindexes did not calculate the correct last index in KIndexes.");
                            return;
                        }
                    }
                }
            }
        }
Exemple #9
0
        private TestResult TestLongSubCases(int n, int k)
        {
            // This method tests out the new int functionality of specifying a lower n choose k case without having to
            // create a new version of Pascal's Triangle to handle it. n & k specifies the main n choose k case.
            //
            string    s;
            int       nLoop, kLoop;
            BinCoeffL bcl = new BinCoeffL(n, k);
            ulong     numCombos, numCombos2, rank, rankHigh, rank2, rankLoop;

            int[] kIndexes = new int[k];
            // If the # of combos overflowed, then don't try this case with uint.
            if (bcl.TotalCombos == 0)
            {
                return(TestResult.IntOverflow);
            }
            // Try getting the rank and combination for all subcases of n choose k.
            for (kLoop = k; kLoop > 0; kLoop--)
            {
                for (nLoop = n; nLoop >= kLoop; nLoop--)
                {
                    numCombos  = bcl.GetNumCombos(nLoop, kLoop);
                    numCombos2 = (uint)BinCoeffBase.GetCombosCount(nLoop, kLoop);
                    if (numCombos != numCombos2)
                    {
                        s = $"TestIntSubCases: Error - {n} choose {k}: # of combos does not match.";
                        Console.WriteLine(s);
                        return(TestResult.Failed);
                    }
                    ulong comboCount = numCombos;
                    // Loop thru all the combinations for this n choose k case if # of combos <= 1000.
                    // Otherwise, just do the lowest ranked 500 and the highest ranked 500.
                    if (numCombos > 1000)
                    {
                        comboCount = 500;
                    }
                    // Loop thru the combinations for this n choose k case.
                    for (rankLoop = 0; rankLoop < comboCount; rankLoop++)
                    {
                        bcl.GetCombFromRank(rankLoop, kIndexes, nLoop, kLoop);
                        rank = bcl.GetRank(true, kIndexes, out bool overflow, kLoop);
                        if (rank != rankLoop)
                        {
                            s = $"TestIntSubCases: Error - {n} choose {k}: rank or combo is wrong.";
                            Console.WriteLine(s);
                            return(TestResult.Failed);
                        }
                        // If not doing all the combinations, then process the high ranks.
                        if (numCombos > comboCount)
                        {
                            rankHigh = numCombos - rankLoop - 1;
                            // Get the k-indexes for this combination.
                            bcl.GetCombFromRank(rankHigh, kIndexes, nLoop, kLoop);
                            // Verify that the Kindexes returned can be used to retrieve the rank of the combination.
                            rank2 = bcl.GetRank(true, kIndexes, out overflow, kLoop);
                            if (rank2 != rankHigh)
                            {
                                s = $"TestIntSubCases: Error - {n} choose {k}: GetRank or GetCombFromRank failed - {rank2} != rankHigh at {rankLoop}";
                                Console.WriteLine(s);
                                return(TestResult.Failed);
                            }
                        }
                    }
                }
            }
            return(TestResult.Passed);
        }