/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="GammaPowerProductOp_Laplace"]/message_doc[@name="LogAverageFactor(GammaPower, GammaPower, GammaPower, Gamma)"]/*'/>
        public static double LogAverageFactor(GammaPower product, GammaPower A, GammaPower B, Gamma q)
        {
            if (B.Shape < A.Shape)
            {
                return(LogAverageFactor(product, B, A, q));
            }
            if (B.IsPointMass)
            {
                return(GammaProductOp.LogAverageFactor(product, A, B.Point));
            }
            if (A.IsPointMass)
            {
                return(GammaProductOp.LogAverageFactor(product, A.Point, B));
            }
            double qPoint = q.GetMean();
            double logf;

            if (product.IsPointMass)
            {
                // Ga(y/q; s, r)/q
                if (qPoint == 0)
                {
                    if (product.Point == 0)
                    {
                        logf = A.GetLogProb(0);
                    }
                    else
                    {
                        logf = double.NegativeInfinity;
                    }
                }
                else
                {
                    logf = A.GetLogProb(product.Point / qPoint) - Math.Log(qPoint);
                }
            }
            else
            {
                // int Ga^y_p(a^pa b^pb; y_s, y_r) Ga(a; s, r) da = q^(y_s-y_p) / (r + q y_r)^(y_s + s-pa)  Gamma(y_s+s-pa)
                double shape  = product.Shape - product.Power;
                double shape2 = GammaFromShapeAndRateOp_Slow.AddShapesMinus1(product.Shape, A.Shape) + (1 - A.Power);
                if (IsProper(product) && product.Shape > A.Shape)
                {
                    // same as below but product.GetLogNormalizer() is inlined and combined with other terms
                    double AShapeMinusPower = A.Shape - A.Power;
                    logf = shape * Math.Log(qPoint)
                           - Gamma.FromShapeAndRate(A.Shape, A.Rate).GetLogNormalizer()
                           - product.Shape * Math.Log(A.Rate / product.Rate + qPoint)
                           - Math.Log(Math.Abs(product.Power));
                    if (AShapeMinusPower != 0)
                    {
                        logf += AShapeMinusPower * (MMath.RisingFactorialLnOverN(product.Shape, AShapeMinusPower) - Math.Log(A.Rate + qPoint * product.Rate));
                    }
                }
                else
                {
                    logf = shape * Math.Log(qPoint)
                           - shape2 * Math.Log(A.Rate + qPoint * product.Rate)
                           + MMath.GammaLn(shape2)
                           - Gamma.FromShapeAndRate(A.Shape, A.Rate).GetLogNormalizer()
                           - product.GetLogNormalizer();
                    // normalizer is -MMath.GammaLn(Shape) + Shape * Math.Log(Rate) - Math.Log(Math.Abs(Power))
                }
            }
            double logz = logf + Gamma.FromShapeAndRate(B.Shape, B.Rate).GetLogProb(qPoint) - q.GetLogProb(qPoint);

            return(logz);
        }