/// <summary>
        ///   Prepares parameters for <see cref="TRandom"/>.
        /// </summary>
        /// <param name="weightsCount">The number of weights.</param>
        /// <param name="weights">Weights, or null.</param>
        /// <param name="cdf">The output cdf.</param>
        /// <remarks>
        ///   Also remember to change <see cref="UpdateHelpers"/> when changing this method.
        /// </remarks>
        internal static void SetUp(int weightsCount, IEnumerable <double> weights, out double[] cdf)
        {
            var weightsList = (weights == null) ? Ones(weightsCount) : weights.ToList();
            var weightsSum  = weightsList.Sum(); // It will store the sum of all UNNORMALIZED weights.

            cdf = new double[weightsList.Count]; // It will store NORMALIZED cdf.
            var maxW = 0.0;                      // It will store max weight (all weights are positive).

            // Let's normalize all weights, if necessary.
            if (!TMath.AreEqual(weightsSum, 1.0))
            {
                for (var i = 0; i < weightsList.Count; ++i)
                {
                    weightsList[i] /= weightsSum;
                }
                Debug.Assert(TMath.AreEqual(weightsList.Sum(), 1.0));
            }

            weightsSum = 0.0; // Reset weight sum to use it for cdf.

            // One big loop to compute all helpers needed by this distribution.
            for (var i = 0; i < weightsList.Count; ++i)
            {
                var w = weightsList[i];
                weightsSum += w;
                cdf[i]      = weightsSum;
                if (w > maxW)
                {
                    maxW = w;
                }
            }
        }
 /// <summary>
 ///   Initializes a new instance of the <see cref="BinomialDistribution"/> class, using a
 ///   <see cref="XorShift128Generator"/> with the specified seed value.
 /// </summary>
 /// <param name="seed">
 ///   An unsigned number used to calculate a starting value for the pseudo-random number sequence.
 /// </param>
 /// <param name="valueCount">
 ///   The parameter valueCount which is used for generation of binomial distributed random
 ///   numbers by setting the number of equi-distributed "weights" the distribution will have.
 /// </param>
 /// <exception cref="ArgumentOutOfRangeException">
 ///   <paramref name="valueCount"/> is less than or equal to zero.
 /// </exception>
 public CategoricalDistribution(uint seed, int valueCount) : this(new XorShift128Generator(seed), valueCount)
 {
     Debug.Assert(Generator is XorShift128Generator);
     Debug.Assert(Generator.Seed == seed);
     Debug.Assert(Equals(Weights.Count, valueCount));
     Debug.Assert(Weights.All(w => TMath.AreEqual(w, 1.0 / valueCount)));
 }
示例#3
0
        public void Doubles_MaxValue_SameOutputAsNextDouble()
        {
            var max      = Rand.Next() + 1; // To avoid zero
            var otherGen = GetGenerator(_generator.Seed);

            Assert.True(_generator.Doubles(max).Take(Iterations).All(x => TMath.AreEqual(x, otherGen.NextDouble(max))));
        }
        /// <summary>
        ///   Computes the unnormalized cumulative distribution function and other attributes for the
        ///   distribution (like mean, variance, and so on).
        /// </summary>
        /// <remarks>
        ///   Also remember to change <see cref="SetUp(int, IEnumerable{double}, out double[])"/>
        ///   when changing this method.
        /// </remarks>
        private void UpdateHelpers()
        {
            var weightsSum = _weights.Sum();             // It will store the sum of all UNNORMALIZED weights.
            var cdf        = new double[_weights.Count]; // It will store NORMALIZED cdf.
            var tmpMean    = 0.0;
            var maxW       = 0.0;                        // It will store max weight (all weights are positive).
            var maxI       = 0;                          // It will store max weight index.

            // Let's normalize all weights, if necessary.
            if (!TMath.AreEqual(weightsSum, 1.0))
            {
                for (var i = 0; i < _weights.Count; ++i)
                {
                    _weights[i] /= weightsSum;
                }
                Debug.Assert(TMath.AreEqual(_weights.Sum(), 1.0));
            }

            weightsSum = 0.0; // Reset weight sum to use it for cdf.

            // One big loop to compute all helpers needed by this distribution.
            for (var i = 0; i < _weights.Count; ++i)
            {
                var w = _weights[i];
                weightsSum += w;
                cdf[i]      = weightsSum;
                tmpMean    += w * (i + 1.0); // Plus one because it is zero-based.
                if (w > maxW)
                {
                    maxW = w;
                    maxI = i;
                }
            }

            // Finalize some results...
            _cdf = cdf;
            Mean = tmpMean - 1.0; // Minus one to make it zero-based.
            Mode = new double[] { maxI };

            var halfWeightsSum = weightsSum / 2.0;
            var tmpMedian      = double.NaN;
            var tmpVar         = 0.0;

            // We still need another loop to compute variance; as for the mean, the plus/minus one is needed.
            for (var i = 0; i < _weights.Count; ++i)
            {
                if (double.IsNaN(tmpMedian) && _cdf[i] >= halfWeightsSum)
                {
                    tmpMedian = i;
                }
                tmpVar += _weights[i] * TMath.Square(i + 1 - Mean);
            }

            // Finalize last results...
            Median   = tmpMedian;
            Variance = tmpVar - 1.0;
        }
示例#5
0
        public void Doubles_SameOutputAsNextDouble_AfterReset()
        {
            var otherGen = GetGenerator(_generator.Seed);

            Assert.True(_generator.Doubles().Take(Iterations).All(x => TMath.AreEqual(x, otherGen.NextDouble())));
            _generator.Reset();
            otherGen.Reset();
            Assert.True(_generator.Doubles().Take(Iterations).All(x => TMath.AreEqual(x, otherGen.NextDouble())));
        }
        /// <summary>
        ///   Returns a floating point random number within the specified range.
        /// </summary>
        /// <param name="minValue">The inclusive lower bound of the random number to be generated.</param>
        /// <param name="maxValue">The exclusive upper bound of the random number to be generated.</param>
        /// <returns>
        ///   A double-precision floating point number greater than or equal to
        ///   <paramref name="minValue"/>, and less than <paramref name="maxValue"/>; that is, the
        ///   range of return values includes <paramref name="minValue"/> but not <paramref name="maxValue"/>.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///   The difference between <paramref name="maxValue"/> and <paramref name="minValue"/>
        ///   cannot be <see cref="double.PositiveInfinity"/>.
        /// </exception>
        public double NextDouble(double minValue, double maxValue)
        {
            // Preconditions
            if (minValue > maxValue)
            {
                throw new ArgumentOutOfRangeException(nameof(minValue), ErrorMessages.MinValueGreaterThanMaxValue);
            }
            if (double.IsPositiveInfinity(maxValue - minValue))
            {
                throw new ArgumentException(ErrorMessages.InfiniteMaxValueMinusMinValue, nameof(minValue));
            }

            var result = minValue + NextDouble() * (maxValue - minValue);

            // Postconditions
            Debug.Assert((TMath.AreEqual(result, minValue) && TMath.AreEqual(minValue, maxValue)) || (result >= minValue && result < maxValue));
            return(result);
        }
 /// <summary>
 ///   Initializes a new instance of the <see cref="CategoricalDistribution"/> class, using
 ///   the specified <see cref="IGenerator"/> as underlying random number generator.
 /// </summary>
 /// <param name="generator">An <see cref="IGenerator"/> object.</param>
 /// <exception cref="ArgumentNullException"><paramref name="generator"/> is <see langword="null"/>.</exception>
 public CategoricalDistribution(IGenerator generator) : this(generator, DefaultValueCount)
 {
     Debug.Assert(ReferenceEquals(Generator, generator));
     Debug.Assert(Equals(Weights.Count, DefaultValueCount));
     Debug.Assert(Weights.All(w => TMath.AreEqual(w, 1.0 / DefaultValueCount)));
 }
 /// <summary>
 ///   Initializes a new instance of the <see cref="BinomialDistribution"/> class, using a
 ///   <see cref="XorShift128Generator"/> as underlying random number generator.
 /// </summary>
 public CategoricalDistribution() : this(new XorShift128Generator(), DefaultValueCount)
 {
     Debug.Assert(Generator is XorShift128Generator);
     Debug.Assert(Equals(Weights.Count, DefaultValueCount));
     Debug.Assert(Weights.All(w => TMath.AreEqual(w, 1.0 / DefaultValueCount)));
 }