/// <summary> /// EP message to 'array'. /// </summary> /// <param name="allTrue">Incoming message from 'allTrue'. Must be a proper distribution. If uniform, the result will be uniform.</param> /// <param name="array">Incoming message from 'array'.</param> /// <param name="result">Modified to contain the outgoing message.</param> /// <returns><paramref name="result"/></returns> /// <remarks><para> /// The outgoing message is a distribution matching the moments of 'array' as the random arguments are varied. /// The formula is <c>proj[p(array) sum_(allTrue) p(allTrue) factor(allTrue,array)]/p(array)</c>. /// </para></remarks> /// <exception cref="ImproperMessageException"><paramref name="allTrue"/> is not a proper distribution</exception> public static BernoulliList ArrayAverageConditional <BernoulliList>([SkipIfUniform] Bernoulli allTrue, IList <Bernoulli> array, BernoulliList result) where BernoulliList : IList <Bernoulli> { if (result.Count == 0) { } else if (result.Count == 1) { result[0] = allTrue; } else if (result.Count == 2) { result[0] = BooleanAndOp.AAverageConditional(allTrue, array[1]); result[1] = BooleanAndOp.BAverageConditional(allTrue, array[0]); } else // result.Count >= 3 { double notallTruePrevious = Double.NegativeInfinity; double[] notallTrueNext = new double[result.Count]; notallTrueNext[notallTrueNext.Length - 1] = Double.NegativeInfinity; for (int i = notallTrueNext.Length - 2; i >= 0; i--) { notallTrueNext[i] = Bernoulli.Or(-array[i + 1].LogOdds, notallTrueNext[i + 1]); } for (int i = 0; i < result.Count; i++) { double notallTrueExcept = Bernoulli.Or(notallTruePrevious, notallTrueNext[i]); result[i] = Bernoulli.FromLogOdds(-Bernoulli.Gate(-allTrue.LogOdds, notallTrueExcept)); notallTruePrevious = Bernoulli.Or(notallTruePrevious, -array[i].LogOdds); } } return(result); }
/// <summary>EP message to <c>array</c>.</summary> /// <param name="allTrue">Incoming message from <c>allTrue</c>. Must be a proper distribution. If uniform, the result will be uniform.</param> /// <param name="array">Constant value for <c>array</c>.</param> /// <param name="result">Modified to contain the outgoing message.</param> /// <returns> /// <paramref name="result" /> /// </returns> /// <remarks> /// <para>The outgoing message is a distribution matching the moments of <c>array</c> as the random arguments are varied. The formula is <c>proj[p(array) sum_(allTrue) p(allTrue) factor(allTrue,array)]/p(array)</c>.</para> /// </remarks> /// <exception cref="ImproperMessageException"> /// <paramref name="allTrue" /> is not a proper distribution.</exception> /// <typeparam name="BernoulliList">The type of the resulting array.</typeparam> public static BernoulliList ArrayAverageConditional <BernoulliList>([SkipIfUniform] Bernoulli allTrue, IList <bool> array, BernoulliList result) where BernoulliList : IList <Bernoulli> { if (result.Count == 0) { } else if (result.Count == 1) { result[0] = allTrue; } else if (result.Count == 2) { result[0] = BooleanAndOp.AAverageConditional(allTrue, array[1]); result[1] = BooleanAndOp.BAverageConditional(allTrue, array[0]); } else { // result.Count >= 3 int trueCount = 0; int firstFalseIndex = -1; for (int i = 0; i < array.Count; i++) { if (array[i]) { trueCount++; } else if (firstFalseIndex < 0) { firstFalseIndex = i; } } if (trueCount == array.Count) { for (int i = 0; i < result.Count; i++) { result[i] = BooleanAndOp.AAverageConditional(allTrue, true); } } else { for (int i = 0; i < result.Count; i++) { result[i] = BooleanAndOp.AAverageConditional(allTrue, false); } if (trueCount == result.Count - 1) { result[firstFalseIndex] = BooleanAndOp.AAverageConditional(allTrue, true); } } } return(result); }