Example #1
0
 /// <summary>
 /// Returns the value x such that GetProbLessThan(x) == probability.
 /// </summary>
 /// <param name="probability">A real number in [0,1].</param>
 /// <returns></returns>
 public double GetQuantile(double probability)
 {
     if (probability < 0)
     {
         throw new ArgumentOutOfRangeException("probability < 0");
     }
     if (probability > 1)
     {
         throw new ArgumentOutOfRangeException("probability > 1");
     }
     if (this.IsPointMass)
     {
         return((probability == 1.0) ? MMath.NextDouble(this.Point) : this.Point);
     }
     else if (!IsProper())
     {
         throw new ImproperDistributionException(this);
     }
     else if (Shape == 1)
     {
         // cdf is 1 - exp(-x*rate)
         return(-Math.Log(1 - probability) / Rate);
     }
     else
     {
         throw new NotImplementedException("Shape != 1 is not implemented");
     }
 }
Example #2
0
        public void QuantileEstimator_AllEqualTest()
        {
            double middle = 3.4;
            double next   = MMath.NextDouble(middle);

            double[] x     = { middle, middle, middle };
            var      outer = new OuterQuantiles(x);

            Assert.Equal(0.0, outer.GetProbLessThan(middle));
            Assert.Equal(middle, outer.GetQuantile(0.0));
            Assert.Equal(middle, outer.GetQuantile(0.75));
            Assert.Equal(1.0, outer.GetProbLessThan(next));
            Assert.Equal(next, outer.GetQuantile(1.0));
            foreach (int weight in new[] { 1, 2, 3 })
            {
                var est = new QuantileEstimator(0.01);
                foreach (var item in x)
                {
                    est.Add(item, weight);
                }
                Assert.Equal(0.0, est.GetProbLessThan(middle));
                Assert.Equal(middle, est.GetQuantile(0.0));
                Assert.Equal(1.0, est.GetProbLessThan(next));
                Assert.Equal(next, est.GetQuantile(1.0));
            }
        }
Example #3
0
        public void QuantileEstimator_DoubleDuplicationTest()
        {
            double first   = 1;
            double second  = 2;
            double between = (first + second) / 2;
            double next    = MMath.NextDouble(second);

            double[] x = { first, first, second, second };
            // quantiles are 0, 1/3, 2/3, 1
            var outer = new OuterQuantiles(x);

            Assert.Equal(0.0, outer.GetProbLessThan(first));
            Assert.Equal(first, outer.GetQuantile(0.0));
            Assert.Equal(0.5, outer.GetProbLessThan(between));
            Assert.Equal(between, outer.GetQuantile(0.5));
            Assert.Equal(2.0 / 3, outer.GetProbLessThan(second));
            Assert.Equal(second, outer.GetQuantile(2.0 / 3));
            Assert.Equal(1.0, outer.GetProbLessThan(next));
            Assert.Equal(next, outer.GetQuantile(1.0));
            CheckGetQuantile(outer, outer);
            var inner = InnerQuantiles.FromDistribution(5, outer);

            CheckGetQuantile(inner, inner, (int)Math.Ceiling(100.0 / 6), (int)Math.Floor(100.0 * 5 / 6));
            var est = new QuantileEstimator(0.01);

            est.Add(first, 2);
            est.Add(second, 2);
            Assert.Equal(0.0, est.GetProbLessThan(first));
            Assert.Equal(first, est.GetQuantile(0.0));
            Assert.Equal(0.5, est.GetProbLessThan(between));
            Assert.Equal(second, est.GetQuantile(2.0 / 3));
            Assert.Equal(1.0, est.GetProbLessThan(next));
            Assert.Equal(next, est.GetQuantile(1.0));
            CheckGetQuantile(est, est);
        }
Example #4
0
 /// <summary>
 /// Returns the value x such that GetProbLessThan(x) == probability.
 /// </summary>
 /// <param name="probability">A real number in [0,1].</param>
 /// <returns></returns>
 public double GetQuantile(double probability)
 {
     if (probability < 0)
     {
         throw new ArgumentOutOfRangeException("probability < 0");
     }
     if (probability > 1)
     {
         throw new ArgumentOutOfRangeException("probability > 1");
     }
     if (this.IsPointMass)
     {
         return((probability == 1.0) ? MMath.NextDouble(this.Point) : this.Point);
     }
     else if (Precision <= 0.0)
     {
         throw new ImproperDistributionException(this);
     }
     else
     {
         double mean     = MeanTimesPrecision / Precision;
         double sqrtPrec = Math.Sqrt(Precision);
         return(MMath.NormalCdfInv(probability) / sqrtPrec + mean);
     }
 }
Example #5
0
File: Gamma.cs Project: 0xCM/arrows
 /// <summary>
 /// Returns the value x such that GetProbLessThan(x) == probability.
 /// </summary>
 /// <param name="probability">A real number in [0,1].</param>
 /// <returns></returns>
 public double GetQuantile(double probability)
 {
     if (probability < 0)
     {
         throw new ArgumentOutOfRangeException("probability < 0");
     }
     if (probability > 1)
     {
         throw new ArgumentOutOfRangeException("probability > 1");
     }
     if (this.IsPointMass)
     {
         return((probability == 1.0) ? MMath.NextDouble(this.Point) : this.Point);
     }
     else if (!IsProper())
     {
         throw new ImproperDistributionException(this);
     }
     else if (MMath.AreEqual(probability, 0))
     {
         return(0);
     }
     else if (MMath.AreEqual(probability, 1))
     {
         return(double.PositiveInfinity);
     }
     else if (Shape == 1)
     {
         // cdf is 1 - exp(-x*rate)
         return(-Math.Log(1 - probability) / Rate);
     }
     else
     {
         // Binary search
         double lowerBound = 0;
         double upperBound = double.MaxValue;
         while (lowerBound < upperBound)
         {
             double average = MMath.Average(lowerBound, upperBound);
             double p       = GetProbLessThan(average);
             if (p == probability)
             {
                 return(average);
             }
             else if (p < probability)
             {
                 lowerBound = MMath.NextDouble(average);
             }
             else
             {
                 upperBound = MMath.PreviousDouble(average);
             }
         }
         return(lowerBound);
     }
 }
Example #6
0
 internal void CheckGetQuantile(CanGetQuantile canGetQuantile, CanGetProbLessThan canGetProbLessThan, int minPercent = 0, int maxPercent = 100)
 {
     for (int i = minPercent; i < maxPercent; i++)
     {
         // probability = 1.0 is excluded
         double probability   = i / 100.0;
         double x             = canGetQuantile.GetQuantile(probability);
         double probLessThanX = canGetProbLessThan.GetProbLessThan(x);
         Assert.True(probLessThanX <= probability);
         double next             = MMath.NextDouble(x);
         double probLessThanNext = canGetProbLessThan.GetProbLessThan(next);
         Assert.True(probLessThanNext > probability);
     }
 }
Example #7
0
        /// <summary>
        /// Returns the largest value x such that GetProbLessThan(x) &lt;= probability.
        /// </summary>
        /// <param name="probability">A real number in [0,1].</param>
        /// <param name="quantiles">Numbers in increasing order corresponding to the quantiles for probabilities (0,...,n-1)/(n-1).</param>
        /// <returns></returns>
        public static double GetQuantile(double probability, double[] quantiles)
        {
            if (probability < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability < 0");
            }
            if (probability > 1.0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability > 1.0");
            }
            int n = quantiles.Length;

            if (quantiles == null)
            {
                throw new ArgumentNullException(nameof(quantiles));
            }
            if (n == 0)
            {
                throw new ArgumentException("quantiles array is empty", nameof(quantiles));
            }
            if (probability == 1.0)
            {
                return(MMath.NextDouble(quantiles[n - 1]));
            }
            if (n == 1)
            {
                return(quantiles[0]);
            }
            double pos   = MMath.LargestDoubleProduct(n - 1, probability);
            int    lower = (int)Math.Floor(pos);
            int    upper = (int)Math.Ceiling(pos);

            if (upper == lower)
            {
                upper = lower + 1;
            }
            return(GetQuantile(probability, lower, quantiles[lower], quantiles[upper], n));
        }
Example #8
0
        /// <summary>
        /// Used to tune MMath.NormalCdfLn.  The best tuning minimizes the number of messages printed.
        /// </summary>
        internal void NormalCdf2Test2()
        {
            // Call both routines now to speed up later calls.
            MMath.NormalCdf(-2, -2, -0.5);
            NormalCdf_Quadrature(-2, -2, -0.5);
            Stopwatch watch = new Stopwatch();
            double    xmin  = 0.1;
            double    xmax  = 0.1;
            double    n     = 20;
            double    xinc  = (xmax - xmin) / (n - 1);

            for (int xi = 0; xi < n; xi++)
            {
                if (xinc == 0 && xi > 0)
                {
                    break;
                }
                double x    = xmin + xi * xinc;
                double ymin = -System.Math.Abs(x) * 10;
                double ymax = -ymin;
                double yinc = (ymax - ymin) / (n - 1);
                for (int yi = 0; yi < n; yi++)
                {
                    double y    = ymin + yi * yinc;
                    double rmin = -0.999999;
                    double rmax = -0.000001;
                    rmin = MMath.NextDouble(-1);
                    rmax = -1 + 1e-6;
                    //rmax = -0.5;
                    //rmax = 0.1;
                    //rmax = -0.58;
                    //rmax = -0.9;
                    //rmin = -0.5;
                    rmax = 1;
                    double rinc = (rmax - rmin) / (n - 1);
                    for (int ri = 0; ri < n; ri++)
                    {
                        double r    = rmin + ri * rinc;
                        string good = "good";
                        watch.Restart();
                        double result1 = double.NaN;
                        try
                        {
                            result1 = MMath.NormalCdfIntegral(x, y, r);
                        }
                        catch
                        {
                            good = "bad";
                            //throw;
                        }
                        watch.Stop();
                        long ticks = watch.ElapsedTicks;
                        watch.Restart();
                        double result2 = double.NaN;
                        try
                        {
                            result2 = NormalCdfLn_Quadrature(x, y, r);
                        }
                        catch
                        {
                        }
                        long ticks2   = watch.ElapsedTicks;
                        bool overtime = ticks > 10 * ticks2;
                        if (double.IsNaN(result1) /*|| overtime*/)
                        {
                            Trace.WriteLine($"({x:g17},{y:g17},{r:g17},{x - r * y}): {good} {ticks} {ticks2} {result1} {result2}");
                        }
                    }
                }
            }
        }
Example #9
0
        /// <summary>
        /// Returns the largest value x such that GetProbLessThan(x) &lt;= probability.
        /// </summary>
        /// <param name="probability">A real number in [0,1].</param>
        /// <returns></returns>
        public double GetQuantile(double probability)
        {
            if (probability < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability < 0");
            }
            if (probability > 1.0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability > 1.0");
            }
            // compute the min and max of the retained items
            double lowerBound = double.PositiveInfinity, upperBound = double.NegativeInfinity;

            for (int bufferIndex = 0; bufferIndex < buffers.Length; bufferIndex++)
            {
                double[] buffer = buffers[bufferIndex];
                int      count  = countInBuffer[bufferIndex];
                for (int i = 0; i < count; i++)
                {
                    double item = buffer[i];
                    if (item < lowerBound)
                    {
                        lowerBound = item;
                    }
                    if (item > upperBound)
                    {
                        upperBound = item;
                    }
                }
            }
            if (probability == 1.0)
            {
                return(MMath.NextDouble(upperBound));
            }
            if (probability == 0.0)
            {
                return(lowerBound);
            }
            if (double.IsPositiveInfinity(lowerBound))
            {
                throw new Exception("QuantileEstimator has no data");
            }
            if (lowerBound == upperBound)
            {
                return(upperBound);
            }
            // use bisection
            while (true)
            {
                double x = MMath.Average(lowerBound, upperBound);
                double lowerItem;
                double upperItem;
                long   lowerRank;
                long   lowerWeight, minLowerWeight, upperWeight, minUpperWeight;
                long   itemCount;
                GetAdjacentItems(x, out lowerItem, out upperItem, out lowerRank, out lowerWeight, out upperWeight, out minLowerWeight, out minUpperWeight, out itemCount);
                if (InterpolationType == 0)
                {
                    double probabilityLessThanLowerItem = (double)(lowerRank - lowerWeight) / itemCount;
                    if (probability < probabilityLessThanLowerItem)
                    {
                        upperBound = MMath.PreviousDouble(lowerItem);
                    }
                    else
                    {
                        double probabilityLessThanUpperItem = (double)lowerRank / itemCount;
                        if (probability < probabilityLessThanUpperItem)
                        {
                            return(lowerItem);
                        }
                        double probabilityLessThanOrEqualUpperItem = (double)(lowerRank + upperWeight) / itemCount;
                        if (probability < probabilityLessThanOrEqualUpperItem)
                        {
                            return(upperItem);
                        }
                        lowerBound = MMath.NextDouble(upperItem);
                    }
                }
                else if (InterpolationType == 1)
                {
                    // Find frac such that (lowerRank - 0.5 + frac) / itemCount == probability
                    double scaledProbability = MMath.LargestDoubleProduct(itemCount, probability);
                    if (scaledProbability < 0.5)
                    {
                        return(lowerBound);
                    }
                    if (scaledProbability >= itemCount - 0.5)
                    {
                        return(upperBound);
                    }
                    // probability of lowerItem ranges from (lowerRank-lowerWeight+0.5) / itemCount
                    // to (lowerRank - 0.5) / itemCount
                    //if (scaledProbability == lowerRank - lowerWeight + 0.5) return lowerItem;
                    if ((scaledProbability > lowerRank - lowerWeight + 0.5) && (scaledProbability < lowerRank - 0.5))
                    {
                        return(lowerItem);
                    }
                    // probability of upperItem ranges from (lowerRank + 0.5) / itemCount
                    // to (lowerRank + upperWeight - 0.5) / itemCount
                    if (scaledProbability == lowerRank + 0.5)
                    {
                        return(upperItem);
                    }
                    if ((scaledProbability > lowerRank + 0.5) && (scaledProbability < lowerRank + upperWeight - 0.5))
                    {
                        return(upperItem);
                    }
                    double frac = scaledProbability - (lowerRank - 0.5);
                    if (frac < 0)
                    {
                        upperBound = MMath.PreviousDouble(x);
                    }
                    else if (frac > 1)
                    {
                        lowerBound = MMath.NextDouble(x);
                    }
                    else
                    {
                        return(OuterQuantiles.GetQuantile(probability, lowerRank - 0.5, lowerItem, upperItem, itemCount + 1));
                    }
                }
                else
                {
                    double scaledProbability = MMath.LargestDoubleProduct(itemCount - 1, probability);
                    // probability of lowerItem ranges from (lowerRank-lowerWeight) / (itemCount - 1)
                    // to (lowerRank - 1) / (itemCount - 1).
                    if (scaledProbability == lowerRank - lowerWeight)
                    {
                        return(lowerItem);
                    }
                    if ((scaledProbability > lowerRank - lowerWeight) && (scaledProbability < lowerRank - 1))
                    {
                        return(lowerItem);
                    }
                    // probability of upperItem ranges from lowerRank / (itemCount - 1)
                    // to (lowerRank + upperWeight-1) / (itemCount - 1)
                    if (scaledProbability == lowerRank)
                    {
                        return(upperItem);
                    }
                    if ((scaledProbability > lowerRank) && (scaledProbability < lowerRank + upperWeight - 1))
                    {
                        return(upperItem);
                    }
                    // solve for frac in (lowerRank-1 + frac) / (itemCount - 1) == probability
                    double frac = scaledProbability - (lowerRank - 1);
                    if (frac < 0)
                    {
                        upperBound = MMath.PreviousDouble(x);
                    }
                    else if (frac > 1)
                    {
                        lowerBound = MMath.NextDouble(x);
                    }
                    else
                    {
                        return(OuterQuantiles.GetQuantile(probability, lowerRank - 1, lowerItem, upperItem, itemCount));
                    }
                }
            }
        }
Example #10
0
 /// <summary>
 /// Get the mean and variance after truncation.
 /// </summary>
 /// <param name="mean"></param>
 /// <param name="variance"></param>
 public void GetMeanAndVariance(out double mean, out double variance)
 {
     if (this.Gamma.IsPointMass)
     {
         mean     = this.Gamma.Point;
         variance = 0.0;
     }
     else if (!IsProper())
     {
         throw new ImproperDistributionException(this);
     }
     else
     {
         // Apply the recurrence GammaUpper(s+1,x,false) = s*GammaUpper(s,x,false) + x^s*exp(-x)
         // Z = GammaUpper(s,r*l,false) - GammaUpper(s,r*u,false)
         // E[x] = (GammaUpper(s+1,r*l,false) - GammaUpper(s+1,r*u,false))/r/Z
         //      = (s + ((r*l)^s*exp(-r*l) - (r*u)^s*exp(-r*u))/Z)/r
         double rl = this.Gamma.Rate * LowerBound;
         double ru = this.Gamma.Rate * UpperBound;
         double m = this.Gamma.Shape / this.Gamma.Rate;
         double offset, offset2;
         if (ru > double.MaxValue)
         {
             double logZ = GetLogNormalizer();
             if (logZ < double.MinValue)
             {
                 mean     = GetMode();
                 variance = 0.0;
                 return;
             }
             offset  = Math.Exp(MMath.GammaUpperLogScale(this.Gamma.Shape, rl) - logZ);
             offset2 = (rl - this.Gamma.Shape) / this.Gamma.Rate * offset;
         }
         else
         {
             // This fails when GammaUpperScale underflows to 0
             double Z = GetNormalizer();
             if (Z == 0)
             {
                 mean     = GetMode();
                 variance = 0.0;
                 return;
             }
             double gammaUpperScaleLower = MMath.GammaUpperScale(this.Gamma.Shape, rl);
             double gammaUpperScaleUpper = MMath.GammaUpperScale(this.Gamma.Shape, ru);
             offset  = (gammaUpperScaleLower - gammaUpperScaleUpper) / Z;
             offset2 = ((rl - this.Gamma.Shape) / this.Gamma.Rate * gammaUpperScaleLower - (ru - this.Gamma.Shape) / this.Gamma.Rate * gammaUpperScaleUpper) / Z;
         }
         if (rl == this.Gamma.Shape)
         {
             mean = LowerBound + offset / this.Gamma.Rate;
         }
         else
         {
             mean = (this.Gamma.Shape + offset) / this.Gamma.Rate;
             if (mean < LowerBound)
             {
                 mean = MMath.NextDouble(mean);
             }
             if (mean < LowerBound)
             {
                 mean = MMath.NextDouble(mean);
             }
         }
         if (mean > double.MaxValue)
         {
             variance = mean;
         }
         else
         {
             variance = (m + offset2 + (1 - offset) * offset / this.Gamma.Rate) / this.Gamma.Rate;
         }
     }
 }
Example #11
0
        /// <summary>
        /// Returns the largest value x such that GetProbLessThan(x) &lt;= probability.
        /// </summary>
        /// <param name="probability">A real number in [0,1].</param>
        /// <returns></returns>
        public double GetQuantile(double probability)
        {
            if (probability < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability < 0");
            }
            if (probability > 1.0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability > 1.0");
            }
            // compute the min and max of the retained items
            double lowerBound = double.PositiveInfinity, upperBound = double.NegativeInfinity;

            for (int bufferIndex = 0; bufferIndex < buffers.Length; bufferIndex++)
            {
                double[] buffer = buffers[bufferIndex];
                int      count  = countInBuffer[bufferIndex];
                for (int i = 0; i < count; i++)
                {
                    double item = buffer[i];
                    if (item < lowerBound)
                    {
                        lowerBound = item;
                    }
                    if (item > upperBound)
                    {
                        upperBound = item;
                    }
                }
            }
            if (probability == 1.0)
            {
                return(MMath.NextDouble(upperBound));
            }
            if (double.IsPositiveInfinity(lowerBound))
            {
                throw new Exception("QuantileEstimator has no data");
            }
            if (lowerBound == upperBound)
            {
                return(upperBound);
            }
            // use bisection
            while (true)
            {
                double x = (lowerBound + upperBound) / 2;
                double lowerItem;
                double upperItem;
                long   lowerIndex;
                long   lowerWeight, minLowerWeight, upperWeight, minUpperWeight;
                long   itemCount;
                GetAdjacentItems(x, out lowerItem, out upperItem, out lowerIndex, out lowerWeight, out upperWeight, out minLowerWeight, out minUpperWeight, out itemCount);
                double scaledProbability = MMath.LargestDoubleProduct(itemCount - 1, probability);
                // probability of lowerItem ranges from (lowerIndex - lowerWeight + 1) / (itemCount - 1)
                // to lowerIndex / (itemCount - 1).
                if ((scaledProbability >= lowerIndex - lowerWeight + 1) && (scaledProbability < lowerIndex))
                {
                    return(lowerItem);
                }
                // probability of upperItem ranges from (lowerIndex + 1) / (itemCount - 1)
                // to (lowerIndex + upperWeight) / (itemCount - 1)
                if ((scaledProbability >= lowerIndex + 1) && (scaledProbability <= lowerIndex + upperWeight))
                {
                    return(upperItem);
                }
                // solve for frac in (lowerIndex + frac) / (itemCount - 1) == probability
                double frac = scaledProbability - lowerIndex;
                if (frac < 0)
                {
                    upperBound = x;
                }
                else if (frac > 1)
                {
                    lowerBound = x;
                }
                else
                {
                    return(OuterQuantiles.GetQuantile(probability, lowerIndex, lowerItem, upperItem, itemCount));
                }
            }
        }