예제 #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));
        }
예제 #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");
            }
            // 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));
                }
            }
        }
예제 #3
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));
        }
예제 #4
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));
            }
        }
예제 #5
0
파일: PlusGamma.cs 프로젝트: shhyder/infer
 /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PlusGammaOp"]/message_doc[@name="SumAverageConditional(GammaPower, double)"]/*'/>
 public static GammaPower SumAverageConditional([SkipIfUniform] GammaPower a, double b)
 {
     if (double.IsInfinity(b) || double.IsNaN(b))
     {
         throw new ArgumentOutOfRangeException(nameof(b), b, $"Argument is outside the range of supported values.");
     }
     if (a.IsUniform() || b == 0)
     {
         return(a);
     }
     else if (a.Power == 0)
     {
         throw new ArgumentException($"Cannot add {b} to {a}");
     }
     else if (a.IsPointMass)
     {
         return(GammaPower.PointMass(a.Point + b, a.Power));
     }
     else if (a.Power < 0)
     {
         if (a.Shape <= a.Power)
         {
             return(a);                    // mode is at zero
         }
         // The mode is ((Shape - Power)/Rate)^Power
         // We want to shift the mode by b, preserving the Shape and Power.
         // This implies ((Shape - Power)/newRate)^Power = newMode
         // newRate = (Shape - Power)/newMode^(1/Power)
         //         = (a.Shape - a.Power) * Math.Pow(a.GetMode() + b, -1 / a.Power);
         //double logMode = a.Power * (Math.Log(Math.Max(0, a.Shape - a.Power)) - Math.Log(a.Rate));
         //if (logMode > double.MaxValue) return a; // mode is at infinity
         double logShapeMinusPower = Math.Log(a.Shape - a.Power);
         double mode = a.GetMode();
         if (mode > double.MaxValue)
         {
             return(a);                        // mode is at infinity
         }
         double newMode    = Math.Max(0, mode + b);
         double newLogMode = Math.Log(newMode);
         // Find newLogRate to satisfy a.Power*(logShapeMinusPower - newLogRate) <= newLogMode
         // logShapeMinusPower - newLogRate >= newLogMode/a.Power
         // newLogRate - logShapeMinusPower <= -newLogMode/a.Power
         double newLogModeOverPower = MMath.LargestDoubleRatio(newLogMode, -a.Power);
         double newLogRate          = MMath.LargestDoubleSum(logShapeMinusPower, newLogModeOverPower);
         if ((double)((logShapeMinusPower - newLogRate) * a.Power) > newLogMode)
         {
             throw new Exception();
         }
         // Ideally this would find largest newRate such that log(newRate) <= newLogRate
         double newRate = Math.Exp(newLogRate);
         if (logShapeMinusPower == newLogRate)
         {
             newRate = a.Shape - a.Power;
         }
         if (a.Rate > 0)
         {
             newRate = Math.Max(double.Epsilon, newRate);
         }
         if (!double.IsPositiveInfinity(a.Rate))
         {
             newRate = Math.Min(double.MaxValue, newRate);
         }
         return(GammaPower.FromShapeAndRate(a.Shape, newRate, a.Power));
     }
     else if (!a.IsProper())
     {
         return(a);
     }
     else
     {
         // The mean is Math.Exp(Power * (MMath.RisingFactorialLnOverN(Shape, Power) - Math.Log(Rate)))
         // We want to shift the mean by b, preserving the Shape and Power.
         // This implies log(newRate) = MMath.RisingFactorialLnOverN(Shape, Power) - log(newMean)/Power
         double logShape = MMath.RisingFactorialLnOverN(a.Shape, a.Power);
         //double logMean = a.GetLogMeanPower(1);
         //double newLogMean = (b > 0) ?
         //    MMath.LogSumExp(logMean, Math.Log(b)) :
         //    MMath.LogDifferenceOfExp(logMean, Math.Log(-b));
         double newMean    = Math.Max(0, a.GetMean() + b);
         double newLogMean = Math.Log(newMean);
         // If logShape is big, this difference can lose accuracy
         // Find newLogRate to satisfy logShape - newLogRate <= newLogMean/a.Power
         double newLogMeanOverPower = MMath.LargestDoubleRatio(newLogMean, a.Power);
         double newLogRate          = -MMath.LargestDoubleSum(-logShape, newLogMeanOverPower);
         // check: (logShape - newLogRate)*a.Power <= newLogMean
         if ((double)((logShape - newLogRate) * a.Power) > newLogMean)
         {
             throw new Exception();
         }
         double newRate = Math.Exp(newLogRate);
         newRate = Math.Max(double.Epsilon, newRate);
         if (!double.IsPositiveInfinity(a.Rate))
         {
             newRate = Math.Min(double.MaxValue, newRate);
         }
         return(GammaPower.FromShapeAndRate(a.Shape, newRate, a.Power));
     }
 }