Ejemplo n.º 1
0
        /// <summary>
        /// Returns the largest quantile such that ((quantile - lowerItem)/(upperItem - lowerItem) + lowerIndex)/(n-1) &lt;= probability.
        /// </summary>
        /// <param name="probability">A number between 0 and 1.</param>
        /// <param name="lowerIndex"></param>
        /// <param name="lowerItem">Must be finite.</param>
        /// <param name="upperItem">Must be finite and at least lowerItem.</param>
        /// <param name="n">Must be greater than 1</param>
        /// <returns></returns>
        internal static double GetQuantile(double probability, double lowerIndex, double lowerItem, double upperItem, long n)
        {
            if (probability < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), probability, $"{nameof(probability)} < 0");
            }
            if (probability > 1)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), probability, $"{nameof(probability)} > 1");
            }
            if (n <= 1)
            {
                throw new ArgumentOutOfRangeException(nameof(n), n, "n <= 1");
            }
            double pos  = MMath.LargestDoubleProduct(probability, n - 1);
            double frac = MMath.LargestDoubleSum(-lowerIndex, pos);

            if (upperItem < lowerItem)
            {
                throw new ArgumentOutOfRangeException(nameof(upperItem), upperItem, $"{nameof(upperItem)} ({upperItem}) < {nameof(lowerItem)} ({lowerItem})");
            }
            if (upperItem == lowerItem)
            {
                return(lowerItem);
            }
            // The above check ensures diff > 0
            double diff   = upperItem - lowerItem;
            double offset = MMath.LargestDoubleProduct(frac, diff);

            return(MMath.LargestDoubleSum(lowerItem, offset));
        }
Ejemplo n.º 2
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");
            }
            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));
        }
Ejemplo n.º 3
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");
            }
            // The zero-based index of item in the sorted List<T>, if item is found;
            // otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item
            // or, if there is no larger element, the bitwise complement of Count.
            int index = Array.BinarySearch(probabilities, probability);

            if (index >= 0)
            {
                return(quantiles[index]);
            }
            else
            {
                // Linear interpolation
                int largerIndex = ~index;
                if (largerIndex == 0)
                {
                    return(quantiles[largerIndex]);
                }
                int smallerIndex = largerIndex - 1;
                if (largerIndex == probabilities.Length)
                {
                    return(quantiles[smallerIndex]);
                }
                double upperItem = quantiles[largerIndex];
                double lowerItem = quantiles[smallerIndex];
                double diff      = upperItem - lowerItem;
                if (diff > double.MaxValue)
                {
                    double scale = System.Math.Max(System.Math.Abs(upperItem), System.Math.Abs(lowerItem));
                    double lowerItemOverScale = lowerItem / scale;
                    diff = upperItem / scale - lowerItemOverScale;
                    double slope  = diff / (probabilities[largerIndex] - probabilities[smallerIndex]);
                    double frac   = MMath.LargestDoubleSum(-probabilities[smallerIndex], probability);
                    double offset = MMath.LargestDoubleProduct(frac, slope);
                    return(MMath.LargestDoubleSum(lowerItemOverScale, offset) * scale);
                }
                else
                {
                    double slope = diff / (probabilities[largerIndex] - probabilities[smallerIndex]);
                    // Solve for the largest x such that probabilities[smallerIndex] + (x - quantiles[smallerIndex]) / slope <= probability.
                    double frac   = MMath.LargestDoubleSum(-probabilities[smallerIndex], probability);
                    double offset = MMath.LargestDoubleProduct(frac, slope);
                    return(MMath.LargestDoubleSum(lowerItem, offset));
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Returns the largest quantile such that ((quantile - lowerItem)/(upperItem - lowerItem) + lowerIndex)/(n-1) &lt;= probability.
        /// </summary>
        /// <param name="probability"></param>
        /// <param name="lowerIndex"></param>
        /// <param name="lowerItem"></param>
        /// <param name="upperItem"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        internal static double GetQuantile(double probability, long lowerIndex, double lowerItem, double upperItem, long n)
        {
            if (n == 1)
            {
                throw new ArgumentOutOfRangeException("n == 1");
            }
            double pos  = MMath.LargestDoubleProduct(n - 1, probability);
            double frac = MMath.LargestDoubleSum(-lowerIndex, pos);
            double diff = upperItem - lowerItem;

            if (diff == 0)
            {
                return(lowerItem);
            }
            double offset = MMath.LargestDoubleProduct(diff, frac);

            return(MMath.LargestDoubleSum(lowerItem, offset));
        }
Ejemplo n.º 5
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");
            }
            // The zero-based index of item in the sorted List<T>, if item is found;
            // otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item
            // or, if there is no larger element, the bitwise complement of Count.
            int index = Array.BinarySearch(probabilities, probability);

            if (index >= 0)
            {
                return(quantiles[index]);
            }
            else
            {
                // Linear interpolation
                int largerIndex = ~index;
                if (largerIndex == 0)
                {
                    return(quantiles[largerIndex]);
                }
                int smallerIndex = largerIndex - 1;
                if (largerIndex == probabilities.Length)
                {
                    return(quantiles[smallerIndex]);
                }
                double slope = (quantiles[largerIndex] - quantiles[smallerIndex]) / (probabilities[largerIndex] - probabilities[smallerIndex]);
                // Solve for the largest x such that probabilities[smallerIndex] + (x - quantiles[smallerIndex]) / slope <= probability.
                double frac   = MMath.LargestDoubleSum(-probabilities[smallerIndex], probability);
                double offset = MMath.LargestDoubleProduct(slope, frac);
                return(MMath.LargestDoubleSum(quantiles[smallerIndex], offset));
            }
        }
Ejemplo n.º 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>
        /// <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));
        }
Ejemplo n.º 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>
        /// <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));
                    }
                }
            }
        }
Ejemplo n.º 8
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));
                }
            }
        }