/// <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); }