/// <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");
            }
            int n = quantiles.Length;

            if (probability < 1.0 / (n + 1.0))
            {
                return(lowerGaussian.GetQuantile(probability));
            }
            if (probability > n / (n + 1.0))
            {
                return(upperGaussian.GetQuantile(probability));
            }
            if (n == 1)
            {
                return(quantiles[0]);        // probability must be 0.5
            }
            double pos   = MMath.LargestDoubleProduct(n + 1, probability) - 1;
            int    lower = (int)Math.Floor(pos);

            if (lower == n - 1)
            {
                return(quantiles[lower]);
            }
            return(OuterQuantiles.GetQuantile(probability, lower + 1, quantiles[lower], quantiles[lower + 1], n + 2));
        }
Beispiel #2
0
 public IrregularQuantiles(double[] probabilities, double[] quantiles)
 {
     AssertIncreasing(probabilities, nameof(probabilities));
     AssertInRange(probabilities, nameof(probabilities));
     OuterQuantiles.AssertNondecreasing(quantiles, nameof(quantiles));
     OuterQuantiles.AssertFinite(quantiles, nameof(quantiles));
     this.probabilities = probabilities;
     this.quantiles     = quantiles;
 }
        public double GetQuantile(double probability)
        {
            int n = quantiles.Length;

            if (probability < 1.0 / (n + 1.0))
            {
                // find the next quantile
                int i = 1;
                while (i < n && quantiles[i] == quantiles[0])
                {
                    i++;
                }
                if (i == n)
                {
                    // all quantiles are equal
                    return(quantiles[0]);
                }
                double p0 = 1.0 / (n + 1);
                double p1 = (i + 1.0) / (n + 1);
                return(GetGaussianQuantile(probability, quantiles[0], p0, quantiles[i], p1));
            }
            if (probability > n / (n + 1.0))
            {
                // find the previous quantile
                int i = n - 2;
                while (i >= 0 && quantiles[i] == quantiles[n - 1])
                {
                    i--;
                }
                if (i < 0)
                {
                    // all quantiles are equal
                    return(quantiles[n - 1]);
                }
                double p0 = n / (n + 1.0);
                double p1 = (i + 1.0) / (n + 1.0);
                return(GetGaussianQuantile(probability, quantiles[n - 1], p0, quantiles[i], p1));
            }
            double pos   = probability * (quantiles.Length + 1) - 1;
            int    lower = (int)Math.Floor(pos);
            int    upper = (int)Math.Ceiling(pos);

            if (upper == lower)
            {
                upper = lower + 1;
            }
            return(OuterQuantiles.GetQuantile(probability, lower + 1, quantiles[lower], quantiles[upper], quantiles.Length + 2));
        }
Beispiel #4
0
 public InnerQuantiles(double[] quantiles)
 {
     if (quantiles == null)
     {
         throw new ArgumentNullException(nameof(quantiles));
     }
     if (quantiles.Length == 0)
     {
         throw new ArgumentException("quantiles array is empty", nameof(quantiles));
     }
     OuterQuantiles.AssertFinite(quantiles, nameof(quantiles));
     OuterQuantiles.AssertNondecreasing(quantiles, nameof(quantiles));
     this.quantiles = quantiles;
     lowerGaussian  = GetLowerGaussian(quantiles);
     upperGaussian  = GetUpperGaussian(quantiles);
 }
Beispiel #5
0
        public double GetQuantile(double probability)
        {
            int n = quantiles.Length;

            if (probability < 1.0 / (n + 1.0))
            {
                return(lowerGaussian.GetQuantile(probability));
            }
            if (probability > n / (n + 1.0))
            {
                return(upperGaussian.GetQuantile(probability));
            }
            double pos   = probability * (quantiles.Length + 1) - 1;
            int    lower = (int)Math.Floor(pos);
            int    upper = (int)Math.Ceiling(pos);

            if (upper == lower)
            {
                upper = lower + 1;
            }
            return(OuterQuantiles.GetQuantile(probability, lower + 1, quantiles[lower], quantiles[upper], quantiles.Length + 2));
        }
Beispiel #6
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));
                    }
                }
            }
        }
        /// <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(upperBound + MMath.Ulp(upperBound));
            }
            if (double.IsPositiveInfinity(lowerBound))
            {
                throw new Exception("QuantileEstimator has no data");
            }
            // 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 = probability * (itemCount - 1);
                // 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));
                }
            }
        }