/// <summary> /// Returns the largest quantile such that ((quantile - lowerItem)/(upperItem - lowerItem) + lowerIndex)/(n-1) <= 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)); }
/// <summary> /// Returns the largest 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(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)); } } }
/// <summary> /// Returns the largest quantile such that ((quantile - lowerItem)/(upperItem - lowerItem) + lowerIndex)/(n-1) <= 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)); }
/// <summary> /// Returns the largest 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(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)); } }
/// <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)); } }