// GammaPower = TruncatedGamma ^ y ///////////////////////////////////////////////////////// public static GammaPower PowAverageConditional([SkipIfUniform] TruncatedGamma x, double y, GammaPower result) { if (result.Power == -1) { y = -y; } else if (result.Power != 1) { throw new ArgumentException($"result.Power ({result.Power}) is not 1 or -1", nameof(result)); } double mean = x.GetMeanPower(y); if (x.LowerBound > 0) { double meanInverse = x.GetMeanPower(-y); Gamma result1 = GammaFromMeanAndMeanInverse(mean, meanInverse); return(GammaPower.FromShapeAndRate(result1.Shape, result1.Rate, result.Power)); } else { double variance = x.GetMeanPower(2 * y) - mean * mean; Gamma result1 = Gamma.FromMeanAndVariance(mean, variance); return(GammaPower.FromShapeAndRate(result1.Shape, result1.Rate, result.Power)); } }
public void ExpOpGammaPowerTest() { Assert.True(!double.IsNaN(ExpOp.ExpAverageConditional(GammaPower.Uniform(-1), Gaussian.FromNatural(0.046634157098979417, 0.00078302234897204242), Gaussian.Uniform()).Rate)); Assert.True(!double.IsNaN(ExpOp.ExpAverageConditional(GammaPower.Uniform(-1), Gaussian.FromNatural(0.36153121930654075, 0.0005524890062312658), Gaussian.Uniform()).Rate)); Assert.True(ExpOp.DAverageConditional(GammaPower.PointMass(0, -1), new Gaussian(0, 1), Gaussian.Uniform()).Point < double.MinValue); ExpOp.ExpAverageConditional(GammaPower.FromShapeAndRate(-1, 283.673, -1), Gaussian.FromNatural(0.004859823703146038, 6.6322755562737905E-06), Gaussian.FromNatural(0.00075506803981220758, 8.24487022054953E-07)); GammaPower exp = GammaPower.FromShapeAndRate(0, 0, -1); Gaussian[] ds = new[] { Gaussian.FromNatural(-1.6171314269768655E+308, 4.8976001759138024), Gaussian.FromNatural(-0.037020622891705768, 0.00034989765084474117), Gaussian.PointMass(double.NegativeInfinity), }; foreach (var d in ds) { Gaussian to_d = ExpOp.DAverageConditional(exp, d, Gaussian.Uniform()); Gaussian to_d_slow = ExpOp_Slow.DAverageConditional(exp, d); Assert.True(to_d_slow.MaxDiff(to_d) < 1e-10); to_d = Gaussian.FromNatural(1, 0); GammaPower to_exp = ExpOp.ExpAverageConditional(exp, d, to_d); //Trace.WriteLine($"{to_exp}"); } ExpOp.ExpAverageConditional(GammaPower.FromShapeAndRate(-1, 883.22399999999993, -1), Gaussian.FromNatural(0.0072160312702854888, 8.1788482512051846E-06), Gaussian.FromNatural(0.00057861649495666474, 5.6316164560235272E-07)); }
public static GammaPower InvGammaFromMeanAndMeanInverse(double mean, double meanInverse) { double shape = 1 / (1 - 1 / mean / meanInverse); double rate = mean * (shape - 1); return(GammaPower.FromShapeAndRate(shape, rate, -1)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaRatioOp"]/message_doc[@name="RatioAverageConditional(double, Gamma)"]/*'/> public static GammaPower RatioAverageConditional(double A, Gamma B) { if (B.IsPointMass) { return(GammaPower.PointMass(A / B.Point, -1)); } return(GammaPower.FromShapeAndRate(B.Shape, B.Rate * A, -1)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaRatioOp"]/message_doc[@name="BAverageConditional(Gamma, double)"]/*'/> public static GammaPower BAverageConditional([SkipIfUniform] Gamma ratio, double A) { if (ratio.IsPointMass) { return(GammaPower.PointMass(BAverageConditional(ratio.Point, A).Point, -1)); } // Ga(a/b; y_s, y_r) =propto b^(-y_s+1) exp(-a/b y_r) return(GammaPower.FromShapeAndRate(ratio.Shape - 2, ratio.Rate * A, -1)); }
public static GammaPower XAverageConditional([SkipIfUniform] GammaPower pow, double y, GammaPower result) { double power = pow.Power / y; if (power != result.Power) { throw new NotSupportedException("Outgoing message power (" + power + ") does not match the desired power (" + result.Power + ")"); } return(GammaPower.FromShapeAndRate(pow.Shape, pow.Rate, pow.Power / y)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PlusGammaVmpOp"]/message_doc[@name="AAverageLogarithm(GammaPower, GammaPower, GammaPower)"]/*'/> public static GammaPower AAverageLogarithm([SkipIfUniform] GammaPower sum, [Proper] GammaPower a, [Proper] GammaPower b, GammaPower to_a, GammaPower to_b) { // f = int_sum sum^(ss/c -1)*exp(-sr*sum^(1/c))*delta(sum = a+b) dsum // = (a+b)^(ss/c -1)*exp(-sr*(a+b)^(1/c)) // log(f) = (ss/c -1)*log(a+b) - sr*(a+b)^(1/c) // apply a lower bound: // log(a+b) >= p*log(a) + (1-p)*log(b) - p*log(p) - (1-p)*log(1-p) // optimal p = exp(a)/(exp(a)+exp(b)) if (a,b) are fixed // optimal p = exp(E[log(a)])/(exp(E[log(a)])+exp(E[log(b)])) if (a,b) are random // This generalizes the bound used by Cemgil (2008). // (a+b)^(1/c) = (a*q/q + b*(1-q)/(1-q))^(1/c) // <= q*(a/q)^(1/c) + (1-q)*(b/(1-q))^(1/c) if c < 0 // = q^(1-1/c)*a^(1/c) + (1-q)^(1-1/c)*b^(1/c) // d/dq = (1-1/c)*(q^(-1/c)*a^(1/c) - (1-q)^(-1/c)*b^(1/c)) // optimal q = a/(a + b) if (a,b) are fixed // optimal q = E[a^(1/c)]^c/(E[a^(1/c)]^c + E[b^(1/c)]^c) if (a,b) are random // The message to A has shape (ss-c)*p + c and rate sr*q^(1-1/c). // If sum is a point mass, then the message to A is pointmass(s*p^c*q^(1-c)) if (a.Power != sum.Power) { throw new NotSupportedException($"a.Power ({a.Power}) != sum.Power ({sum.Power})"); } double x = sum.Shape - sum.Power; GammaPower aPost = a * to_a; if (aPost.IsUniform()) { return(sum); } GammaPower bPost = b * to_b; if (bPost.IsUniform()) { if (sum.IsPointMass) { return(sum); } return(GammaPower.FromShapeAndRate(sum.Power, sum.Rate, sum.Power)); } double ma = Math.Exp(aPost.GetMeanLog()); double mb = Math.Exp(bPost.GetMeanLog()); double denom = ma + mb; double p = (denom == 0) ? 0.5 : ma / (ma + mb); double m = x * p; double mac = Math.Exp(a.Power * aPost.GetLogMeanPower(1 / a.Power)); double mbc = Math.Exp(b.Power * bPost.GetLogMeanPower(1 / b.Power)); double denom2 = mac + mbc; double q = (denom2 == 0) ? 0.5 : mac / (mac + mbc); if (sum.IsPointMass) { return(GammaPower.PointMass(sum.Point * Math.Pow(p / q, sum.Power) * q, sum.Power)); } return(GammaPower.FromShapeAndRate(m + sum.Power, sum.Rate * Math.Pow(q, 1 - 1 / sum.Power), sum.Power)); }
// GammaPower = Gamma ^ y ////////////////////////////////////////////////////////////// /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PowerOp"]/message_doc[@name="PowAverageConditional(Gamma, double)"]/*'/> public static GammaPower PowAverageConditional([SkipIfUniform] Gamma x, double y) { if (x.IsPointMass) { return(GammaPower.PointMass(System.Math.Pow(x.Point, y), y)); } else { return(GammaPower.FromShapeAndRate(x.Shape, x.Rate, y)); } }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaProductVmpOp"]/message_doc[@name="ProductAverageLogarithm(double, Gamma)"]/*'/> public static GammaPower ProductAverageLogarithm(double A, [SkipIfUniform] GammaPower B) { if (B.IsPointMass) { return(GammaPower.PointMass(A * B.Point, B.Power)); } if (A == 0) { return(GammaPower.PointMass(0, B.Power)); } return(GammaPower.FromShapeAndRate(B.Shape, B.Rate * Math.Pow(A, -1 / B.Power), B.Power)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaProductOp"]/message_doc[@name="AAverageConditional(double, Gamma)"]/*'/> public static GammaPower AAverageConditional(double product, Gamma B) { if (B.IsPointMass) { return(GammaPower.PointMass(B.Point / product, -1)); } // b' = ab, db' = a db // int delta(y - ab) Ga(b; b_s, b_r) db // = int delta(y - b') Ga(b'/a; b_s, b_r)/a db' // = Ga(y/a; b_s, b_r)/a // =propto a^(-b_s) exp(-yb_r/a) return(GammaPower.FromShapeAndRate(B.Shape - 1, product * B.Rate, -1)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaProductOp"]/message_doc[@name="AAverageConditional(GammaPower, double, GammaPower)"]/*'/> public static GammaPower AAverageConditional([SkipIfUniform] GammaPower Product, double B, GammaPower result) { if (Product.IsPointMass) { return(AAverageConditional(Product.Point, B, result)); } if (B == 0) { result.SetToUniform(); return(result); } // (ab)^(shape/power-1) exp(-rate*(ab)^(1/power)) return(GammaPower.FromShapeAndRate(Product.Shape, Product.Rate * Math.Pow(B, 1 / result.Power), result.Power)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PowerOp"]/message_doc[@name="PowAverageConditional(GammaPower, double, GammaPower)"]/*'/> public static GammaPower PowAverageConditional([SkipIfUniform] GammaPower x, double y, GammaPower result) { GammaPower message; if (x.IsPointMass) { message = GammaPower.PointMass(System.Math.Pow(x.Point, y), y * x.Power); } else { message = GammaPower.FromShapeAndRate(x.Shape, x.Rate, y * x.Power); } return(GammaPowerFromDifferentPower(message, result.Power)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaPowerProductOp_Laplace"]/message_doc[@name="BAverageConditional(GammaPower, GammaPower, GammaPower, Gamma, GammaPower)"]/*'/> public static GammaPower BAverageConditional([SkipIfUniform] GammaPower product, [Proper] GammaPower A, [Proper] GammaPower B, Gamma q, GammaPower result) { if (B.Shape < A.Shape) { return(AAverageConditional(product, B, A, q, result)); } if (A.IsPointMass) { return(GammaProductOp.BAverageConditional(product, A.Point, result)); } if (B.IsPointMass) { return(GammaPower.Uniform(result.Power)); // TODO } if (product.IsUniform()) { return(product); } if (q.IsUniform()) { q = Q(product, A, B); } double qPoint = q.GetMean(); GammaPower bMarginal; // threshold ensures 6/qPoint^4 does not overflow double threshold = Math.Sqrt(Math.Sqrt(6 / double.MaxValue)); if (result.Power < 0 && qPoint > threshold) { double iqMean, iqVariance; GetIQMoments(product, A, q, qPoint, out iqMean, out iqVariance); GammaPower iqMarginal = GammaPower.FromMeanAndVariance(iqMean, iqVariance, -1); bMarginal = GammaPower.FromShapeAndRate(iqMarginal.Shape, iqMarginal.Rate, result.Power); } else { // B.Shape >= A.Shape therefore Q is the approximate distribution of B^(1/B.Power). // We compute the approximate moments of q = b^(1/b.Power) to get a Gamma distribution and then raise to B.Power. double qMean, qVariance; GetQMoments(product, A, q, qPoint, out qMean, out qVariance); bMarginal = GammaPower.FromGamma(Gamma.FromMeanAndVariance(qMean, qVariance), result.Power); } result.SetToRatio(bMarginal, B, GammaProductOp_Laplace.ForceProper); return(result); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PowerOp"]/message_doc[@name="XAverageConditional(GammaPower, GammaPower, double, GammaPower)"]/*'/> public static GammaPower XAverageConditional([SkipIfUniform] GammaPower pow, GammaPower x, double y, GammaPower result) { // message computed below should be uniform when pow is uniform, but may not due to roundoff error. if (pow.IsUniform()) { return(GammaPower.Uniform(result.Power)); } // Factor is (x^y)^(pow.Shape/pow.Power - 1) * exp(-pow.Rate*(x^y)^1/pow.Power) // =propto x^(pow.Shape/(pow.Power/y) - y) * exp(-pow.Rate*x^y/pow.Power) // newShape/(pow.Power/y) - 1 = pow.Shape/(pow.Power/y) - y // newShape = pow.Shape + (1-y)*(pow.Power/y) double power = pow.Power / y; var toPow = PowAverageConditional(x, y, pow); GammaPower powMarginal = pow * toPow; // xMarginal2 is the exact distribution of pow^(1/y) where pow has distribution powMarginal GammaPower xMarginal2 = GammaPower.FromShapeAndRate(powMarginal.Shape, powMarginal.Rate, power); GammaPower xMarginal = GammaPowerFromDifferentPower(xMarginal2, result.Power); result.SetToRatio(xMarginal, x, GammaProductOp_Laplace.ForceProper); return(result); }
public static GammaPower GammaPowerFromDerivLogZ(GammaPower a, double dlogZ, double ddlogZ) { bool method1 = false; if (method1) { GetPosteriorMeanAndVariance(Gamma.FromShapeAndRate(a.Shape, a.Rate), dlogZ, ddlogZ, out double iaMean, out double iaVariance); Gamma ia = Gamma.FromMeanAndVariance(iaMean, iaVariance); return(GammaPower.FromShapeAndRate(ia.Shape, ia.Rate, a.Power) / a); } else { double alpha = -a.Rate * dlogZ; // dalpha/dr = -dlogZ - r*ddlogZ // beta = -r * dalpha/dr double beta = a.Rate * dlogZ + a.Rate * a.Rate * ddlogZ; Gamma prior = Gamma.FromShapeAndRate(a.Shape, a.Rate); // ia is the marginal of a^(1/a.Power) Gamma ia = GaussianOp.GammaFromAlphaBeta(prior, alpha, beta, true) * prior; return(GammaPower.FromShapeAndRate(ia.Shape, ia.Rate, a.Power) / a); } }
private static GammaPower InverseGammaFromMeanAndVarianceOverMeanSquared(double mean, double varianceOverMeanSquared) { double shape = 1 / varianceOverMeanSquared + 2; return(GammaPower.FromShapeAndRate(shape, mean * (shape - 1), -1)); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaPowerProductOp_Laplace"]/message_doc[@name="AAverageConditional(GammaPower, GammaPower, GammaPower, Gamma, GammaPower)"]/*'/> public static GammaPower AAverageConditional([SkipIfUniform] GammaPower product, GammaPower A, [SkipIfUniform] GammaPower B, Gamma q, GammaPower result) { if (B.Shape < A.Shape) { return(BAverageConditional(product, B, A, q, result)); } if (B.IsPointMass) { return(GammaProductOp.AAverageConditional(product, B.Point, result)); } if (A.IsPointMass) { return(GammaPower.Uniform(A.Power)); // TODO } if (product.IsUniform()) { return(product); } double qPoint = q.GetMean(); GammaPower aMarginal; if (product.IsPointMass) { // Z = int Ga(y/q; s, r)/q Ga(q; q_s, q_r) dq // E[a] = E[product/q] // E[a^2] = E[product^2/q^2] // aVariance = E[a^2] - aMean^2 double productPoint = product.Point; if (productPoint == 0) { aMarginal = GammaPower.PointMass(0, result.Power); } else { double iqMean, iqVariance; GetIQMoments(product, A, q, qPoint, out iqMean, out iqVariance); double aMean = productPoint * iqMean; double aVariance = productPoint * productPoint * iqVariance; aMarginal = GammaPower.FromGamma(Gamma.FromMeanAndVariance(aMean, aVariance), result.Power); } } else { if (double.IsPositiveInfinity(product.Rate)) { return(GammaPower.PointMass(0, result.Power)); } if (A.Power != product.Power) { throw new NotSupportedException($"A.Power ({A.Power}) != product.Power ({product.Power})"); } if (B.Power != product.Power) { throw new NotSupportedException($"B.Power ({B.Power}) != product.Power ({product.Power})"); } double r = product.Rate; double g = 1 / (qPoint * r + A.Rate); double g2 = g * g; double shape2 = GammaFromShapeAndRateOp_Slow.AddShapesMinus1(product.Shape, A.Shape) + (1 - A.Power); // From above: // a^(y_s-pa + a_s-1) exp(-(y_r b + a_r)*a) if (shape2 > 2) { // Compute the moments of a^(-1/a.Power) // Here q = b^(1/b.Power) // E[a^(-1/a.Power)] = E[(q r + a_r)/(shape2-1)] // var(a^(-1/a.Power)) = E[(q r + a_r)^2/(shape2-1)/(shape2-2)] - E[a^(-1/a.Power)]^2 // = (var(q r + a_r) + E[(q r + a_r)]^2)/(shape2-1)/(shape2-2) - E[(q r + a_r)]^2/(shape2-1)^2 // = var(q r + a_r)/(shape2-1)/(shape2-2) + E[(q r + a_r)/(shape2-1)]^2/(shape2-2) // TODO: share this computation with BAverageConditional double qMean, qVariance; GetQMoments(product, A, q, qPoint, out qMean, out qVariance); double iaMean = (qMean * r + A.Rate) / (shape2 - 1); //double iaVariance = (qVariance * r2 / (shape2 - 1) + iaMean * iaMean) / (shape2 - 2); // shape = mean^2/variance + 2 //double iaVarianceOverMeanSquared = (qVariance / (shape2 - 1) * r / iaMean * r / iaMean + 1) / (shape2 - 2); double iaVarianceOverMeanSquared = (qVariance * (shape2 - 1) / (qMean + A.Rate / r) / (qMean + A.Rate / r) + 1) / (shape2 - 2); //GammaPower iaMarginal = GammaPower.FromMeanAndVariance(iaMean, iaVariance, -1); GammaPower iaMarginal = InverseGammaFromMeanAndVarianceOverMeanSquared(iaMean, iaVarianceOverMeanSquared); if (iaMarginal.IsUniform()) { if (result.Power > 0) { return(GammaPower.PointMass(0, result.Power)); } else { return(GammaPower.Uniform(result.Power)); } } else { aMarginal = GammaPower.FromShapeAndRate(iaMarginal.Shape, iaMarginal.Rate, result.Power); } bool check = false; if (check) { // Importance sampling MeanVarianceAccumulator mvaB = new MeanVarianceAccumulator(); MeanVarianceAccumulator mvaInvA = new MeanVarianceAccumulator(); Gamma bPrior = Gamma.FromShapeAndRate(B.Shape, B.Rate); q = bPrior; double shift = (product.Shape - product.Power) * Math.Log(qPoint) - shape2 * Math.Log(A.Rate + qPoint * r) + bPrior.GetLogProb(qPoint) - q.GetLogProb(qPoint); for (int i = 0; i < 1000000; i++) { double bSample = q.Sample(); // logf = (y_s-y_p)*log(b) - (s+y_s-pa)*log(r + b*y_r) double logf = (product.Shape - product.Power) * Math.Log(bSample) - shape2 * Math.Log(A.Rate + bSample * r) + bPrior.GetLogProb(bSample) - q.GetLogProb(bSample); double weight = Math.Exp(logf - shift); mvaB.Add(bSample, weight); double invA = (bSample * r + A.Rate) / (shape2 - 1); mvaInvA.Add(invA, weight); } Trace.WriteLine($"b = {mvaB}, {qMean}, {qVariance}"); Trace.WriteLine($"invA = {mvaInvA} {mvaInvA.Variance * (shape2 - 1) / (shape2 - 2) + mvaInvA.Mean * mvaInvA.Mean / (shape2 - 2)}, {iaMean}, {iaVarianceOverMeanSquared * iaMean * iaMean}"); Trace.WriteLine($"aMarginal = {aMarginal}"); } } else { // Compute the moments of a^(1/a.Power) // aMean = shape2/(b y_r + a_r) // aVariance = E[shape2*(shape2+1)/(b y_r + a_r)^2] - aMean^2 = var(shape2/(b y_r + a_r)) + E[shape2/(b y_r + a_r)^2] // = shape2^2*var(1/(b y_r + a_r)) + shape2*(var(1/(b y_r + a_r)) + (aMean/shape2)^2) double r2 = r * r; double[] gDerivatives = new double[] { g, -r * g2, 2 * g2 * g * r2, -6 * g2 * g2 * r2 * r }; double gMean, gVariance; GaussianOp_Laplace.LaplaceMoments(q, gDerivatives, dlogfs(qPoint, product, A), out gMean, out gVariance); double aMean = shape2 * gMean; double aVariance = shape2 * shape2 * gVariance + shape2 * (gVariance + gMean * gMean); aMarginal = GammaPower.FromGamma(Gamma.FromMeanAndVariance(aMean, aVariance), result.Power); } } result.SetToRatio(aMarginal, A, GammaProductOp_Laplace.ForceProper); if (double.IsNaN(result.Shape) || double.IsNaN(result.Rate)) { throw new InferRuntimeException("result is nan"); } return(result); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaPowerProductOp_Laplace"]/message_doc[@name="ProductAverageConditional(GammaPower, GammaPower, GammaPower, Gamma, GammaPower)"]/*'/> public static GammaPower ProductAverageConditional(GammaPower product, [Proper] GammaPower A, [SkipIfUniform] GammaPower B, Gamma q, GammaPower result) { if (B.Shape < A.Shape) { return(ProductAverageConditional(product, B, A, q, result)); } if (B.IsPointMass) { return(GammaProductOp.ProductAverageConditional(A, B.Point)); } if (B.IsUniform()) { return(GammaPower.Uniform(result.Power)); } if (A.IsPointMass) { return(GammaProductOp.ProductAverageConditional(A.Point, B)); } if (product.IsPointMass) { return(GammaPower.Uniform(result.Power)); // TODO } if (A.Power != product.Power) { throw new NotSupportedException($"A.Power ({A.Power}) != product.Power ({product.Power})"); } if (B.Power != product.Power) { throw new NotSupportedException($"B.Power ({B.Power}) != product.Power ({product.Power})"); } if (A.Rate == 0) { if (B.Rate == 0) { return(GammaPower.FromShapeAndRate(Math.Min(A.Shape, B.Shape), 0, result.Power)); } else { return(A); } } if (B.Rate == 0) { return(B); } double qPoint = q.GetMean(); double r = product.Rate; double shape2 = GammaFromShapeAndRateOp_Slow.AddShapesMinus1(product.Shape, A.Shape) + (1 - A.Power); GammaPower productMarginal; // threshold ensures 6/qPoint^4 does not overflow double threshold = Math.Sqrt(Math.Sqrt(6 / double.MaxValue)); if (shape2 > 2 && result.Power < 0 && qPoint > threshold) { // Compute the moments of product^(-1/product.Power) // Here q = b^(1/b.Power) // E[a^(-1/a.Power) b^(-1/b.Power)] = E[(q r + a_r)/(shape2-1)/q] // var(a^(-1/a.Power) b^(-1/b.Power)) = E[(q r + a_r)^2/(shape2-1)/(shape2-2)/q^2] - E[a^(-1/a.Power) b^(-1/b.Power)]^2 // = (var((q r + a_r)/q) + E[(q r + a_r)/q]^2)/(shape2-1)/(shape2-2) - E[(q r + a_r)/q]^2/(shape2-1)^2 // = var((q r + a_r)/q)/(shape2-1)/(shape2-2) + E[(q r + a_r)/(shape2-1)/q]^2/(shape2-2) double iqMean, iqVariance; GetIQMoments(product, A, q, qPoint, out iqMean, out iqVariance); double ipMean = (r + A.Rate * iqMean) / (shape2 - 1); double ipVariance = (iqVariance * A.Rate * A.Rate / (shape2 - 1) + ipMean * ipMean) / (shape2 - 2); // TODO: use ipVarianceOverMeanSquared GammaPower ipMarginal = GammaPower.FromMeanAndVariance(ipMean, ipVariance, -1); if (ipMarginal.IsUniform()) { return(GammaPower.Uniform(result.Power)); } else { productMarginal = GammaPower.FromShapeAndRate(ipMarginal.Shape, ipMarginal.Rate, result.Power); } bool check = false; if (check) { // Importance sampling MeanVarianceAccumulator mvaInvQ = new MeanVarianceAccumulator(); MeanVarianceAccumulator mvaInvProduct = new MeanVarianceAccumulator(); Gamma qPrior = Gamma.FromShapeAndRate(B.Shape, B.Rate); double shift = (product.Shape - product.Power) * Math.Log(qPoint) - shape2 * Math.Log(A.Rate + qPoint * r) + qPrior.GetLogProb(qPoint) - q.GetLogProb(qPoint); for (int i = 0; i < 1000000; i++) { double qSample = q.Sample(); // logf = (y_s-y_p)*log(b) - (s+y_s-pa)*log(r + b*y_r) double logf = (product.Shape - product.Power) * Math.Log(qSample) - shape2 * Math.Log(A.Rate + qSample * r) + qPrior.GetLogProb(qSample) - q.GetLogProb(qSample); double weight = Math.Exp(logf - shift); mvaInvQ.Add(1 / qSample, weight); double invProduct = (r + A.Rate / qSample) / (shape2 - 1); mvaInvProduct.Add(invProduct, weight); } Trace.WriteLine($"invQ = {mvaInvQ}, {iqMean}, {iqVariance}"); Trace.WriteLine($"invProduct = {mvaInvProduct}"); Trace.WriteLine($"invA = {mvaInvProduct.Variance * (shape2 - 1) / (shape2 - 2) + mvaInvProduct.Mean * mvaInvProduct.Mean / (shape2 - 2)}, {ipMean}, {ipVariance}"); Trace.WriteLine($"productMarginal = {productMarginal}"); } } else { // Compute the moments of y = product^(1/product.Power) // yMean = E[shape2*b/(b y_r + a_r)] // yVariance = E[shape2*(shape2+1)*b^2/(b y_r + a_r)^2] - yMean^2 // = var(shape2*b/(b y_r + a_r)) + E[shape2*b^2/(b y_r + a_r)^2] // = shape2^2*var(b/(b y_r + a_r)) + shape2*(var(b/(b y_r + a_r)) + (yMean/shape2)^2) // Let g = b/(b y_r + a_r) double denom = qPoint * r + A.Rate; double denom2 = denom * denom; double rOverDenom = r / denom; double[] gDerivatives = (denom == 0) ? new double[] { 0, 0, 0, 0 } : new double[] { qPoint / denom, A.Rate / denom2, -2 * A.Rate / denom2 * rOverDenom, 6 * A.Rate / denom2 * rOverDenom * rOverDenom }; double gMean, gVariance; GaussianOp_Laplace.LaplaceMoments(q, gDerivatives, dlogfs(qPoint, product, A), out gMean, out gVariance); double yMean = shape2 * gMean; double yVariance = shape2 * shape2 * gVariance + shape2 * (gVariance + gMean * gMean); productMarginal = GammaPower.FromGamma(Gamma.FromMeanAndVariance(yMean, yVariance), result.Power); } result.SetToRatio(productMarginal, product, GammaProductOp_Laplace.ForceProper); if (double.IsNaN(result.Shape) || double.IsNaN(result.Rate)) { throw new InferRuntimeException("result is nan"); } return(result); }
/// <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)); } }
// GammaPower = Gamma ^ y ////////////////////////////////////////////////////////////// /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PowerOp"]/message_doc[@name="PowAverageConditional(Gamma, double)"]/*'/> public static GammaPower PowAverageConditional([SkipIfUniform] Gamma x, double y) { return(GammaPower.FromShapeAndRate(x.Shape, x.Rate, y)); }
public static GammaPower GammaPowerFromDifferentPower(GammaPower message, double newPower) { if (message.Power == newPower) { return(message); // same as below, but faster } if (message.IsUniform()) { return(GammaPower.Uniform(newPower)); } // Making two hops ensures that the desired mean powers are finite. if (message.Power > 0 && newPower < 0 && newPower != -1) { return(GammaPowerFromDifferentPower(GammaPowerFromDifferentPower(message, -1), newPower)); } if (message.Power < 0 && newPower > 0 && newPower != 1) { return(GammaPowerFromDifferentPower(GammaPowerFromDifferentPower(message, 1), newPower)); } // Project the message onto the desired power if (newPower == 1 || newPower == -1 || newPower == 2) { message.GetMeanAndVariance(out double mean, out double variance); if (!double.IsPositiveInfinity(mean)) { return(GammaPower.FromMeanAndVariance(mean, variance, newPower)); } // Fall through } bool useMean = false; if (useMean) { // Constraints: // mean = Gamma(Shape + newPower)/Gamma(Shape)/Rate^newPower =approx (Shape/Rate)^newPower // mean2 = Gamma(Shape + 2*newPower)/Gamma(Shape)/Rate^(2*newPower) =approx ((Shape + newPower)/Rate)^newPower * (Shape/Rate)^newPower // mean2/mean^2 = Gamma(Shape + 2*newPower)*Gamma(Shape)/Gamma(Shape + newPower)^2 =approx ((Shape + newPower)/Shape)^newPower // Shape =approx newPower/((mean2/mean^2)^(1/newPower) - 1) // Rate = Shape/mean^(1/newPower) message.GetMeanAndVariance(out double mean, out double variance); double meanp = System.Math.Pow(mean, 1 / newPower); double mean2p = System.Math.Pow(variance + mean * mean, 1 / newPower); double shape = newPower / (mean2p / meanp / meanp - 1); if (double.IsInfinity(shape)) { return(GammaPower.PointMass(mean, newPower)); } double rate = shape / meanp; return(GammaPower.FromShapeAndRate(shape, rate, newPower)); } else { // Compute the mean and variance of x^1/newPower double mean = message.GetMeanPower(1 / newPower); double mean2 = message.GetMeanPower(2 / newPower); double variance = System.Math.Max(0, mean2 - mean * mean); if (double.IsPositiveInfinity(mean * mean)) { variance = mean; } return(GammaPower.FromGamma(Gamma.FromMeanAndVariance(mean, variance), newPower)); } }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PowerOp"]/message_doc[@name="PowAverageConditional(GammaPower, double, GammaPower)"]/*'/> public static GammaPower PowAverageConditional([SkipIfUniform] GammaPower x, double y, GammaPower result) { GammaPower message = GammaPower.FromShapeAndRate(x.Shape, x.Rate, y * x.Power); return(GammaPowerFromDifferentPower(message, result.Power)); }
// Gamma = Gamma ^ y ///////////////////////////////////////////////////////// /// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="PowerOp"]/message_doc[@name="PowAverageConditional(Gamma, double, Gamma)"]/*'/> public static Gamma PowAverageConditional([SkipIfUniform] Gamma x, double y, Gamma result) { GammaPower message = GammaPower.FromShapeAndRate(x.Shape, x.Rate, y); return(GammaFromGammaPower(message)); }
public static GammaPower InvGammaFromShapeAndMeanInverse(double shape, double meanInverse) { return(GammaPower.FromShapeAndRate(shape, shape / meanInverse, -1)); }