/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="DoublePlusOp"]/message_doc[@name="AAverageConditional(Gaussian, Gaussian)"]/*'/> public static Gaussian AAverageConditional([SkipIfUniform] Gaussian Sum, [SkipIfUniform] Gaussian b) { if (Sum.IsPointMass) { return(AAverageConditional(Sum.Point, b)); } if (b.IsPointMass) { return(AAverageConditional(Sum, b.Point)); } if (Sum.IsUniform() || b.IsUniform()) { return(Gaussian.Uniform()); } if (Sum.Precision == b.Precision) { // This formula works even when Precision == 0 return(Gaussian.FromNatural(MMath.Average(Sum.MeanTimesPrecision, -b.MeanTimesPrecision), Sum.Precision / 2)); } double prec = Sum.Precision + b.Precision; if (prec == 0) { throw new ImproperDistributionException(Sum.IsProper() ? b : Sum); } return(Gaussian.FromNatural((Sum.MeanTimesPrecision * b.Precision - b.MeanTimesPrecision * Sum.Precision) / prec, Sum.Precision * b.Precision / prec)); }
/// <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); } }
public void WeightedAverageTest() { Assert.Equal(Environment.Is64BitProcess ? 3.86361619394904E-311 : 3.86361619394162E-311, MMath.WeightedAverage(0.82912896852490248, 2.5484859206000203E-311, 3.50752234977395E-313, 31.087830618727477)); Assert.Equal(MMath.WeightedAverage(0.1, double.MinValue, 0.01, double.MinValue), double.MinValue); Assert.Equal(MMath.WeightedAverage(0.1, -double.Epsilon, double.MaxValue, -double.Epsilon), -double.Epsilon); Assert.Equal(MMath.WeightedAverage(1e-100, 2e-250, 1e-100, 4e-250), MMath.Average(2e-250, 4e-250)); Assert.Equal(MMath.WeightedAverage(1e100, 2e250, 1e100, 4e250), MMath.Average(2e250, 4e250)); Assert.Equal(MMath.WeightedAverage(0, 0, 0.1, -double.Epsilon), -double.Epsilon); Assert.Equal(MMath.WeightedAverage(0.1, -double.Epsilon, 0, double.NegativeInfinity), -double.Epsilon); Assert.False(double.IsNaN(MMath.WeightedAverage(1.7976931348623157E+308, double.NegativeInfinity, 4.94065645841247E-324, double.NegativeInfinity))); Assert.False(double.IsNaN(MMath.WeightedAverage(0.01, double.NegativeInfinity, double.MaxValue, double.MaxValue))); Assert.False(double.IsNaN(MMath.WeightedAverage(0.01, double.NegativeInfinity, double.Epsilon, double.NegativeInfinity))); Assert.Equal(double.MaxValue, MMath.WeightedAverage(double.MaxValue, double.MaxValue, double.MaxValue, double.MaxValue)); const int limit = 2_000_000; int count = 0; Parallel.ForEach(OperatorTests.DoublesAtLeastZero(), wa => { Parallel.ForEach(OperatorTests.DoublesAtLeastZero(), wb => { if (count > limit) { return; } Trace.WriteLine($"wa = {wa}, wb = {wb}"); foreach (var a in OperatorTests.Doubles()) { if (count > limit) { break; } foreach (var b in OperatorTests.Doubles()) { if (count > limit) { break; } if (double.IsNaN(a + b)) { continue; } double midpoint = MMath.WeightedAverage(wa, a, wb, b); Assert.True(midpoint >= System.Math.Min(a, b), $"Failed assertion: MMath.WeightedAverage({wa:r}, {a:r}, {wb:r}, {b:r}) {midpoint} >= {System.Math.Min(a, b)}"); Assert.True(midpoint <= System.Math.Max(a, b), $"Failed assertion: MMath.WeightedAverage({wa:r}, {a:r}, {wb:r}, {b:r}) {midpoint} <= {System.Math.Max(a, b)}"); if (wa == wb) { Assert.Equal(MMath.Average(a, b), midpoint); } Interlocked.Add(ref count, 1); } } }); }); }
public void WeightedAverageTest() { Assert.Equal(MMath.WeightedAverage(0.1, double.MinValue, 0.01, double.MinValue), double.MinValue); Assert.Equal(MMath.WeightedAverage(0.1, -double.Epsilon, double.MaxValue, -double.Epsilon), -double.Epsilon); Assert.Equal(MMath.WeightedAverage(1e-100, 2e-250, 1e-100, 4e-250), MMath.Average(2e-250, 4e-250)); Assert.Equal(MMath.WeightedAverage(1e100, 2e250, 1e100, 4e250), MMath.Average(2e250, 4e250)); Assert.Equal(MMath.WeightedAverage(0, 0, 0.1, -double.Epsilon), -double.Epsilon); Assert.Equal(MMath.WeightedAverage(0.1, -double.Epsilon, 0, double.NegativeInfinity), -double.Epsilon); Assert.False(double.IsNaN(MMath.WeightedAverage(1.7976931348623157E+308, double.NegativeInfinity, 4.94065645841247E-324, double.NegativeInfinity))); Assert.False(double.IsNaN(MMath.WeightedAverage(0.01, double.NegativeInfinity, double.MaxValue, double.MaxValue))); Assert.False(double.IsNaN(MMath.WeightedAverage(0.01, double.NegativeInfinity, double.Epsilon, double.NegativeInfinity))); Assert.Equal(double.MaxValue, MMath.WeightedAverage(double.MaxValue, double.MaxValue, double.MaxValue, double.MaxValue)); const int limit = 2_000_000; int count = 0; Parallel.ForEach(OperatorTests.DoublesAtLeastZero(), wa => { Parallel.ForEach(OperatorTests.DoublesAtLeastZero(), wb => { if (count > limit) { return; } Trace.WriteLine($"wa = {wa}, wb = {wb}"); foreach (var a in OperatorTests.Doubles()) { if (count > limit) { break; } foreach (var b in OperatorTests.Doubles()) { if (count > limit) { break; } if (double.IsNaN(a + b)) { continue; } double midpoint = MMath.WeightedAverage(wa, a, wb, b); Assert.True(midpoint >= System.Math.Min(a, b), $"Failed assertion: {midpoint} >= {System.Math.Min(a, b)}, wa={wa:r}, a={a:r}, wb={wb:r}, b={b:r}"); Assert.True(midpoint <= System.Math.Max(a, b), $"Failed assertion: {midpoint} <= {System.Math.Max(a, b)}, wa={wa:r}, a={a:r}, wb={wb:r}, b={b:r}"); if (wa == wb) { Assert.Equal(MMath.Average(a, b), midpoint); } Interlocked.Add(ref count, 1); } } }); }); }
public static double GetMidpoint(double lower, double upper) { double midpoint; if (double.IsNegativeInfinity(lower)) { if (double.IsPositiveInfinity(upper)) { midpoint = 0.0; } else if (upper > 0) { midpoint = -upper; } else if (upper < 0) { midpoint = 2 * upper; } else { midpoint = -1; } } else if (double.IsPositiveInfinity(upper)) { if (lower > 0) { midpoint = 2 * lower; } else if (lower < 0) { midpoint = -lower; } else { midpoint = 1; } } else { midpoint = MMath.Average(lower, upper); } return(midpoint); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="DoublePlusOp"]/message_doc[@name="AAverageConditional(Gaussian, Gaussian)"]/*'/> public static Gaussian AAverageConditional([SkipIfUniform] Gaussian Sum, [SkipIfUniform] Gaussian b) { if (Sum.IsPointMass) { return(AAverageConditional(Sum.Point, b)); } if (b.IsPointMass) { return(AAverageConditional(Sum, b.Point)); } if (Sum.IsUniform() || b.IsUniform()) { return(Gaussian.Uniform()); } if (Sum.Precision == b.Precision) { // This formula works even when Precision == 0 return(Gaussian.FromNatural(MMath.Average(Sum.MeanTimesPrecision, -b.MeanTimesPrecision), Sum.Precision / 2)); } double meanTimesPrec, prec; if (Sum.Precision >= b.Precision) { double precOverSumPrec = 1 + b.Precision / Sum.Precision; // can overflow if b.Precision > Sum.Precision if (precOverSumPrec == 0) { throw new ImproperDistributionException(Sum.IsProper() ? b : Sum); } meanTimesPrec = (Sum.MeanTimesPrecision / Sum.Precision * b.Precision - b.MeanTimesPrecision) / precOverSumPrec; prec = b.Precision / precOverSumPrec; } else // Sum.Precision < b.Precision { double precOverbPrec = Sum.Precision / b.Precision + 1; // can overflow if Sum.Precision > b.Precision if (precOverbPrec == 0) { throw new ImproperDistributionException(Sum.IsProper() ? b : Sum); } meanTimesPrec = (Sum.MeanTimesPrecision - b.MeanTimesPrecision / b.Precision * Sum.Precision) / precOverbPrec; prec = Sum.Precision / precOverbPrec; } return(Gaussian.FromNatural(meanTimesPrec, prec)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="DoublePlusOp"]/message_doc[@name="SumAverageConditional(Gaussian, Gaussian)"]/*'/> public static Gaussian SumAverageConditional([SkipIfUniform] Gaussian a, [SkipIfUniform] Gaussian b) { if (a.IsPointMass) { return(SumAverageConditional(a.Point, b)); } if (b.IsPointMass) { return(SumAverageConditional(a, b.Point)); } if (a.IsUniform() || b.IsUniform()) { return(Gaussian.Uniform()); } if (a.Precision == b.Precision) { // This formula works even when Precision == 0 return(Gaussian.FromNatural(MMath.Average(a.MeanTimesPrecision, b.MeanTimesPrecision), a.Precision / 2)); } double meanTimesPrec, prec; if (a.Precision >= b.Precision) { double precOverAPrec = 1 + b.Precision / a.Precision; if (precOverAPrec == 0) { throw new ImproperDistributionException(a.IsProper() ? b : a); } meanTimesPrec = (a.MeanTimesPrecision / a.Precision * b.Precision + b.MeanTimesPrecision) / precOverAPrec; prec = b.Precision / precOverAPrec; } else { double precOverBPrec = a.Precision / b.Precision + 1; if (precOverBPrec == 0) { throw new ImproperDistributionException(a.IsProper() ? b : a); } meanTimesPrec = (a.MeanTimesPrecision + b.MeanTimesPrecision / b.Precision * a.Precision) / precOverBPrec; prec = a.Precision / precOverBPrec; } return(Gaussian.FromNatural(meanTimesPrec, prec)); }
/// <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"); } // 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)); } } } }