/// <summary>EP message to <c>sample</c>.</summary>
        /// <param name="choice">Incoming message from <c>choice</c>.</param>
        /// <param name="probTrue0">Constant value for <c>probTrue0</c>.</param>
        /// <param name="probTrue1">Constant value for <c>probTrue1</c>.</param>
        /// <returns>The outgoing EP message to the <c>sample</c> argument.</returns>
        /// <remarks>
        ///   <para>The outgoing message is a distribution matching the moments of <c>sample</c> as the random arguments are varied. The formula is <c>proj[p(sample) sum_(choice) p(choice) factor(sample,choice,probTrue0,probTrue1)]/p(sample)</c>.</para>
        /// </remarks>
        public static Bernoulli SampleAverageConditional(Bernoulli choice, double probTrue0, double probTrue1)
        {
            Bernoulli result = new Bernoulli();

            if (choice.IsPointMass)
            {
                return(SampleConditional(choice.Point, probTrue0, probTrue1));
            }
#if FAST
            result.SetProbTrue(choice.GetProbFalse() * probTrue0 + choice.GetProbTrue() * probTrue1);
#else
            // This method is more numerically stable but slower.
            // let oX = log(p(X)/(1-p(X))
            // let oY = log(p(Y)/(1-p(Y))
            // oX = log( (TT*sigma(oY) + TF*sigma(-oY))/(FT*sigma(oY) + FF*sigma(-oY)) )
            //    = log( (TT*exp(oY) + TF)/(FT*exp(oY) + FF) )
            //    = log( (exp(oY) + TF/TT)/(exp(oY) + FF/FT) ) + log(TT/FT)
            // ay = log(TF/TT)
            // by = log(FF/FT)
            // offset = log(TT/FT)
            if (probTrue0 == 0 || probTrue1 == 0)
            {
                throw new ArgumentException("probTrue is zero");
            }
            double ay     = Math.Log(probTrue0 / probTrue1);
            double by     = Math.Log((1 - probTrue0) / (1 - probTrue1));
            double offset = MMath.Logit(probTrue1);
            result.LogOdds = MMath.DiffLogSumExp(choice.LogOdds, ay, by) + offset;
#endif
            return(result);
        }
        /// <summary>EP message to <c>choice</c>.</summary>
        /// <param name="sample">Incoming message from <c>sample</c>. Must be a proper distribution. If uniform, the result will be uniform.</param>
        /// <param name="probTrue0">Constant value for <c>probTrue0</c>.</param>
        /// <param name="probTrue1">Constant value for <c>probTrue1</c>.</param>
        /// <returns>The outgoing EP message to the <c>choice</c> argument.</returns>
        /// <remarks>
        ///   <para>The outgoing message is a distribution matching the moments of <c>choice</c> as the random arguments are varied. The formula is <c>proj[p(choice) sum_(sample) p(sample) factor(sample,choice,probTrue0,probTrue1)]/p(choice)</c>.</para>
        /// </remarks>
        /// <exception cref="ImproperMessageException">
        ///   <paramref name="sample" /> is not a proper distribution.</exception>
        public static Bernoulli ChoiceAverageConditional([SkipIfUniform] Bernoulli sample, double probTrue0, double probTrue1)
        {
            Bernoulli result = new Bernoulli();

            if (sample.IsPointMass)
            {
                return(ChoiceConditional(sample.Point, probTrue0, probTrue1));
            }
#if FAST
            double p1  = sample.GetProbFalse() * (1 - probTrue1) + sample.GetProbTrue() * probTrue1;
            double p0  = sample.GetProbFalse() * (1 - probTrue0) + sample.GetProbTrue() * probTrue0;
            double sum = p0 + p1;
            if (sum == 0.0)
            {
                throw new AllZeroException();
            }
            else
            {
                result.SetProbTrue(p1 / sum);
            }
#else
            // This method is more numerically stable but slower.
            // ax = log(FT/TT)
            // bx = log(FF/TF)
            // offset = log(TT/TF)
            if (probTrue0 == 0 || probTrue1 == 0)
            {
                throw new ArgumentException("probTrue is zero");
            }
            double ax     = -MMath.Logit(probTrue1);
            double bx     = -MMath.Logit(probTrue0);
            double offset = Math.Log(probTrue1 / probTrue0);
            result.LogOdds = MMath.DiffLogSumExp(sample.LogOdds, ax, bx) + offset;
#endif
            return(result);
        }