Example #1
0
        /// <summary>
        /// Make a new <see cref="Combination"/> from the supplied
        /// <em>choices</em> and <em>picks</em> of <see cref="Rank"/> 0.
        /// </summary>
        /// <param name="choices">Number of values to pick from.</param>
        /// <param name="picks">Number of elements in the sequence.</param>
        /// <example>
        /// <code source="Examples\Combination\CnExample01\CnExample01.cs" lang="cs" />
        /// </example>
        /// <exception cref="ArgumentOutOfRangeException">
        /// When negative value supplied; when <em>picks</em> greater than <em>choices</em>.
        /// </exception>
        /// <exception cref="OverflowException">When the numbers are just too big.</exception>
        public Combination(int choices, int picks)
        {
            if (choices < 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is less than zero.");
            }

            if (picks < 0)
            {
                throw new ArgumentOutOfRangeException("picks", "Value is less than zero.");
            }

            if (picks > choices)
            {
                throw new ArgumentOutOfRangeException("picks", "Value is greater than choices.");
            }

            _data = new int[picks];
            for (var ki = 0; ki < picks; ++ki)
            {
                _data[ki] = ki;
            }

            _choices  = choices;
            _rowCount = picks == 0 ? 0 : Combinatoric.BinomialCoefficient(choices, picks);
            _rank     = 0;
        }
Example #2
0
        /// <summary>
        /// Iterate thru all rows of all <see cref="Combination"/> tables for every
        /// pick in the range (1..<see cref="Picks"/>).
        /// </summary>
        /// <returns>An iterator for a series of <see cref="Combination"/> tables.</returns>
        /// <example>
        /// <code source="Examples\Combination\CnExample02\CnExample02.cs" lang="cs" />
        /// </example>
        public IEnumerable <Combination> GetRowsForAllPicks()
        {
            for (var k = 1; k <= Picks; ++k)
            {
                var current = (Combination)MemberwiseClone();

                current._data = new int[k];
                for (var ei = 0; ei < current._data.Length; ++ei)
                {
                    current._data[ei] = ei;
                }
                current._rowCount = Combinatoric.BinomialCoefficient(_choices, k);
                current._rank     = 0;

                for (;;)
                {
                    yield return(current);

                    current.Rank = current.Rank + 1;
                    if (current.Rank == 0)
                    {
                        break;
                    }
                }
            }
        }
Example #3
0
        // On entry: elements & choices assumed valid, picks = elements.Length.
        private static long CalcRank(int[] elements, int choices)
        {
            long result = 0;
            var  isUsed = new bool[choices];

            //
            // Perform ranking:
            //

            for (var ei1 = 0; ei1 < elements.Length; ++ei1)
            {
                isUsed[elements[ei1]] = true;

                var digit = 0;
                for (var ei2 = 0; ei2 < elements[ei1]; ++ei2)
                {
                    if (!isUsed[ei2])
                    {
                        ++digit;
                    }
                }

                result += digit * Combinatoric.Factorial(choices - ei1 - 1);
            }

            if (elements.Length < choices)
            {
                result = result / Combinatoric.Factorial(choices - elements.Length);
            }

            return(result);
        }
Example #4
0
        /// <summary>
        /// Make a new <see cref="Combination"/> from the supplied elements.
        /// </summary>
        /// <param name="choices">Number of values to pick from.</param>
        /// <param name="source">Array of integers.</param>
        /// <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("source");
            }

            if (choices < 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is less than zero.");
            }

            if (choices < source.Length)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is less than picks.");
            }

            _data = new int[source.Length];
            source.CopyTo(_data, 0);
            Array.Sort(_data);

            _choices  = choices;
            _rowCount = Picks == 0 ? 0 : Combinatoric.BinomialCoefficient(choices, Picks);

            for (var ki = 0; ki < Picks; ++ki)
            {
                if (_data[ki] < 0 || _data[ki] >= choices)
                {
                    throw new ArgumentOutOfRangeException("source", "Element is out of range.");
                }

                if (ki > 0)
                {
                    if (_data[ki] == _data[ki - 1])
                    {
                        throw new ArgumentOutOfRangeException("source", "Elements must be unique.");
                    }
                }
            }

            //
            // Perform ranking:
            //

            _rank = 0;
            var ji = 0;

            for (var ki = 0; ki < Picks; ++ki)
            {
                for (; ji < _data[ki]; ++ji)
                {
                    _rank += Combinatoric.BinomialCoefficient(Choices - ji - 1, Picks - ki - 1);
                }

                ji = _data[ki] + 1;
            }
        }
Example #5
0
        /// <summary>
        /// Make a new <see cref="Multicombination"/> from the supplied
        /// <em>choices</em> of the same <em>Picks</em>.
        /// </summary>
        /// <param name="choices">Number of elements in the sequence.</param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// When <em>choices</em> less than 0.
        /// </exception>
        public Multicombination(int choices)
        {
            if (choices < 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is less than zero.");
            }

            _data     = new int[choices];
            _choices  = choices;
            _rowCount = choices == 0 ? 0 : Combinatoric.BinomialCoefficient(Picks + choices - 1, Picks);
            _rank     = 0;
        }
Example #6
0
        // 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 (var ei = 1; ei < elements.Length; ++ei)
            {
                var yd = (int)(Combinatoric.Factorial(elements.Length) / Combinatoric.Factorial(ei + 1));
                var yi = (int)((plainRank / yd) % ((ei + 1) * 2));
                var ip = yi <= ei ? ei - yi : yi - ei - 1;

                for (var si = ei; si > ip; --si)
                {
                    elements[si] = elements[si - 1];
                }
                elements[ip] = ei;
            }
        }
Example #7
0
        // On entry: choices, picks assumed valid.
        private static long CalcCount(int choices, int picks)
        {
            if (picks == 0)
            {
                return(0);
            }

            var result = Combinatoric.Factorial(choices);

            if (picks < choices)
            {
                result = result / Combinatoric.Factorial(choices - picks);
            }

            return(result);
        }
Example #8
0
        /// <summary>
        /// Make a new <see cref="Combination"/> from the supplied
        /// <em>choices</em> and <em>picks</em> of the supplied <em>rank</em>.
        /// </summary>
        /// <remarks>
        /// If the supplied <em>rank</em> is out of the range (0..<see cref="RowCount"/>-1),
        /// it will be normalized to the valid range. For example, a value of -1 will
        /// produce the last row in the ordered table.
        /// </remarks>
        /// <param name="choices">Number of values to pick from.</param>
        /// <param name="picks">Number of elements in the sequence.</param>
        /// <param name="rank">Initial row index in the ordered <see cref="Combination"/> table.</param>
        /// <example>
        /// <code source="Examples\Combination\CnExample05\CnExample05.cs" lang="cs" />
        /// </example>
        /// <exception cref="ArgumentOutOfRangeException">
        /// When negative value supplied; when <em>picks</em> greater than <em>choices</em>.
        /// </exception>
        /// <exception cref="OverflowException">When too many <em>choices</em>.</exception>
        public Combination(int choices, int picks, long rank)
        {
            if (choices < 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is less than zero.");
            }

            if (picks < 0)
            {
                throw new ArgumentOutOfRangeException("picks", "Value is less than zero.");
            }

            if (picks > choices)
            {
                throw new ArgumentOutOfRangeException("picks", "Value is greater than choices.");
            }

            _data     = new int[picks];
            _choices  = choices;
            _rowCount = picks == 0 ? 0 : Combinatoric.BinomialCoefficient(choices, picks);
            Rank      = rank;
        }
Example #9
0
        /// <summary>
        /// Make a new <see cref="Multicombination"/> from the supplied
        /// <em>choices</em> and <em>picks</em> of the supplied <em>rank</em>.
        /// </summary>
        /// <remarks>
        /// If the supplied <em>rank</em> is out of the range (0..<see cref="RowCount"/>-1),
        /// it will be normalized to the valid range. For example, a value of -1 will
        /// produce the last row in the ordered table.
        /// </remarks>
        /// <param name="choices">Number of values to pick from.</param>
        /// <param name="picks">Number of elements in the sequence.</param>
        /// <param name="rank">Initial row index in the ordered <see cref="Multicombination"/> table.</param>
        /// <example>
        /// <code source="Examples\Multicombination\McExample05\McExample05.cs" lang="cs" />
        /// </example>
        /// <exception cref="ArgumentOutOfRangeException">
        /// When negative value supplied; when <em>choices</em> is 0 and <em>picks</em> is not 0.
        /// </exception>
        /// <exception cref="OverflowException">When too many <em>choices</em>.</exception>
        public Multicombination(int choices, int picks, long rank)
        {
            if (choices < 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is less than zero.");
            }

            if (picks < 0)
            {
                throw new ArgumentOutOfRangeException("picks", "Value is less than zero.");
            }

            if (choices == 0 && picks > 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is zero and picks is nonzero.");
            }

            _data     = new int[picks];
            _choices  = choices;
            _rowCount = picks == 0 ? 0 : Combinatoric.BinomialCoefficient(picks + choices - 1, picks);
            Rank      = rank;
        }
Example #10
0
        /// <summary>
        /// Iterate thru all rows of all <see cref="Multicombination"/> tables for every
        /// pick in the range (<em>startPicks</em>..<em>stopPicks</em>).
        /// </summary>
        /// <returns>An iterator for a series of <see cref="Multicombination"/> tables.</returns>
        /// <remarks>
        /// Unlike <see cref="Picks"/>, <see cref="Choices"/> may exceed <see cref="Choices"/>.
        /// </remarks>
        /// <param name="startPicks">Number of picks for first table.</param>
        /// <param name="stopPicks">Number of picks for last table.</param>
        /// <example>
        /// <code source="Examples\Multicombination\McExample02\McExample02.cs" lang="cs" />
        /// </example>
        /// <exception cref="Combination">
        /// When <em>startPicks</em> is less than 0 or greater than <em>stopPicks</em>.
        /// </exception>
        public IEnumerable <Multicombination> GetRowsForPicks(int startPicks, int stopPicks)
        {
            if (startPicks < 0 || startPicks > stopPicks)
            {
                throw new ArgumentOutOfRangeException("startPicks", "Pick range is not valid.");
            }

            if (Choices == 0)
            {
                yield break;
            }

            if (startPicks == 0)
            {
                startPicks = 1;
            }

            for (var k = startPicks; k <= stopPicks; ++k)
            {
                var current = (Multicombination)MemberwiseClone();
                current._data     = new int[k];
                current._rowCount = Combinatoric.BinomialCoefficient(k + _choices - 1, k);
                current._rank     = 0;

                for (;;)
                {
                    yield return(current);

                    current.Rank = current.Rank + 1;
                    if (current.Rank == 0)
                    {
                        break;
                    }
                }
            }
        }
Example #11
0
        /// <summary>
        /// Make a new <see cref="Multicombination"/> from the supplied elements.
        /// </summary>
        /// <param name="choices">Number of values to pick from.</param>
        /// <param name="source">Array of integers.</param>
        /// <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("source");
            }

            if (choices < 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is less than zero.");
            }

            if (choices == 0 && source.Length > 0)
            {
                throw new ArgumentOutOfRangeException("choices", "Value is zero and picks is nonzero.");
            }

            _data = new int[source.Length];
            source.CopyTo(_data, 0);
            Array.Sort(_data);

            _choices  = choices;
            _rowCount = Picks == 0 ? 0 : Combinatoric.BinomialCoefficient(Picks + choices - 1, Picks);

            for (var ki = 0; ki < Picks; ++ki)
            {
                if (_data[ki] < 0 || _data[ki] >= choices)
                {
                    throw new ArgumentOutOfRangeException("source", "Element is out of range.");
                }
            }

            //
            // Perform ranking:
            //

            _rank = 0;
            if (RowCount == 0)
            {
                return;
            }

            var comboElement = _data[0];
            var ji           = 0;

            for (var ki = 0;;)
            {
                for (; ji < comboElement; ++ji)
                {
                    _rank += Combinatoric.BinomialCoefficient(Choices + Picks - ji - 2, Picks - ki - 1);
                }

                ++ki;
                if (ki >= Picks)
                {
                    break;
                }

                ji           = comboElement + 1;
                comboElement = _data[ki] - _data[ki - 1] + ji;
            }
        }