Beispiel #1
0
        // 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));
            }
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
 /// <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));
 }
Beispiel #5
0
 /// <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));
 }
Beispiel #6
0
        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));
        }
Beispiel #7
0
        /// <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));
        }
Beispiel #8
0
        // 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));
            }
        }
Beispiel #9
0
 /// <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));
 }
Beispiel #10
0
 /// <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));
 }
Beispiel #11
0
 /// <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));
 }
Beispiel #12
0
        /// <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);
        }
Beispiel #14
0
        /// <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);
        }
Beispiel #15
0
        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);
        }
Beispiel #19
0
 /// <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));
     }
 }
Beispiel #20
0
        // 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));
        }
Beispiel #21
0
        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));
            }
        }
Beispiel #22
0
        /// <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));
        }
Beispiel #23
0
        // 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));
        }
Beispiel #24
0
 public static GammaPower InvGammaFromShapeAndMeanInverse(double shape, double meanInverse)
 {
     return(GammaPower.FromShapeAndRate(shape, shape / meanInverse, -1));
 }