Logic
The logic nodes compute Boolean functions of Boolean variables. A model uses them to build a probabilistic circuit, such as z ~ AND(x, y) in RxInfer's syntax. Each variable carries a Bernoulli belief, the probability that it is true.
The nodes are deterministic: their clusters are out and the joint over the inputs, whatever the factorisation. Every rule is therefore exact belief propagation over Bernoulli messages. The message towards out is the probability that the function is true, given independent inputs. The message towards an input weighs each of its two values by the message on out at the function's output, averaged over the message on the other input. The nodes run under DefaultAlgorithm.
| node | function | interfaces |
|---|---|---|
AND | $\mathrm{out} = \mathrm{in}_1 \wedge \mathrm{in}_2$ | out, in1, in2 |
OR | $\mathrm{out} = \mathrm{in}_1 \vee \mathrm{in}_2$ | out, in1, in2 |
NOT | $\mathrm{out} = \neg \mathrm{in}$ | out, in |
IMPLY | $\mathrm{out} = \mathrm{in}_1 \Rightarrow \mathrm{in}_2$ | out, in1, in2 |
The message towards out has log scale zero. A message towards an input is normalised, and it declares the log of its normaliser as its log scale. The joint marginal of two inputs is a Contingency table, with rows for in1 and columns for in2, false first. None of the nodes has an average energy of its own.
Example
Two fair coins, combined by OR, are true with probability 3/4. An implication that is true, with a true premise, forces its conclusion to be true:
julia> using StandardMessagePassingRules, MessagePassingRulesBase, Distributions
julia> message = getresult(@call_message_update_rule(node = OR, target = :out, m = (in1 = Bernoulli(0.5), in2 = Bernoulli(0.5))));
julia> mean(message) ≈ 0.75
true
julia> result = @call_message_update_rule(node = IMPLY, target = :in2, m = (out = Bernoulli(1.0), in1 = Bernoulli(1.0)));
julia> mean(getresult(result)) ≈ 1.0
trueAND
MessagePassingRulesBase.nodespec(AND)| interface | aliases | |
|---|---|---|
out | ||
in1 | ||
in2 |
| default algorithm | MessagePassingRulesBase.DefaultAlgorithm() |
|---|---|
| static inputs | none |
| defined | nodes/logic.jl:85 |
MessagePassingRulesBase.rule_coverage(AND)| DefaultAlgorithm | |
|---|---|
| → out | ✓ |
| → in1 | ✓ |
| → in2 | ✓ |
| q(in1, in2) | ✓ |
The message towards out multiplies the probabilities of the inputs:
@call_message_update_rule(node = AND, target = :out, m = (in1 = Bernoulli(0.5), in2 = Bernoulli(0.8)))Result
| value | Distributions.Bernoulli{Float64}(p=0.4) |
|---|---|
| type | Distributions.Bernoulli{Float64} |
| log scale | 0 (declared) |
Inputs
| edge | value |
|---|
Rule
| declared inputs | m[:in1]::Distributions.Bernoulli, m[:in2]::Distributions.Bernoulli |
|---|---|
| algorithm | DefaultAlgorithm() |
| log scale | 0 |
| defined | and/rules.jl:1 |
| body | args->Bernoulli(mean(args.m[:in1]) * mean(args.m[:in2])) |
StandardMessagePassingRules.AND — Type
ANDThe conjunction node, out = in1 ∧ in2, with interfaces out, in1 and in2. The message towards out is Bernoulli(p₁ p₂) for inputs Bernoulli(p₁) and Bernoulli(p₂).
Rules. Every message is a Bernoulli, the probability of true, and every rule is belief propagation over the other interfaces' messages: a deterministic node's clusters are always out and the joint over its inputs, whatever the factorisation. The rules towards out have log scale zero; those towards an input declare the log of their normaliser. The node runs under DefaultAlgorithm and has no average energy of its own.
The joint marginal of the inputs, q(in1, in2), is a Contingency table over {false, true}², rows in1 and columns in2, false first.
Examples
julia> message = getresult(@call_message_update_rule(node = AND, target = :out, m = (in1 = Bernoulli(0.5), in2 = Bernoulli(0.2))));
julia> mean(message) ≈ 0.1
trueOR
MessagePassingRulesBase.rule_coverage(OR)| DefaultAlgorithm | |
|---|---|
| → out | ✓ |
| → in1 | ✓ |
| → in2 | ✓ |
| q(in1, in2) | ✓ |
StandardMessagePassingRules.OR — Type
ORThe disjunction node, out = in1 ∨ in2, with interfaces out, in1 and in2. The message towards out is Bernoulli(p₁ + p₂ - p₁ p₂) for inputs Bernoulli(p₁) and Bernoulli(p₂).
Rules. Every message is a Bernoulli, the probability of true, and every rule is belief propagation over the other interfaces' messages: a deterministic node's clusters are always out and the joint over its inputs, whatever the factorisation. The rules towards out have log scale zero; those towards an input declare the log of their normaliser. The node runs under DefaultAlgorithm and has no average energy of its own.
The joint marginal of the inputs, q(in1, in2), is a Contingency table over {false, true}², rows in1 and columns in2, false first.
NOT
MessagePassingRulesBase.rule_coverage(NOT)| DefaultAlgorithm | |
|---|---|
| → out | ✓ |
| → in | ✓ |
StandardMessagePassingRules.NOT — Type
NOTThe negation node, out = ¬in, with interfaces out and in. Each message is the other interface's flipped: Bernoulli(1 - p) for Bernoulli(p), both ways.
Rules. Every message is a Bernoulli, the probability of true, and every rule is belief propagation over the other interfaces' messages: a deterministic node's clusters are always out and the joint over its inputs, whatever the factorisation. The rules towards out have log scale zero; those towards an input declare the log of their normaliser. The node runs under DefaultAlgorithm and has no average energy of its own. With a single input there is no joint marginal rule.
IMPLY
MessagePassingRulesBase.rule_coverage(IMPLY)| DefaultAlgorithm | |
|---|---|
| → out | ✓ |
| → in1 | ✓ |
| → in2 | ✓ |
| q(in1, in2) | ✓ |
StandardMessagePassingRules.IMPLY — Type
IMPLYThe implication node, out = in1 → in2, with interfaces out, in1 and in2: false only when in1 is true and in2 false. The message towards out is Bernoulli(1 - p₁ + p₁ p₂) for inputs Bernoulli(p₁) and Bernoulli(p₂).
Rules. Every message is a Bernoulli, the probability of true, and every rule is belief propagation over the other interfaces' messages: a deterministic node's clusters are always out and the joint over its inputs, whatever the factorisation. The rules towards out have log scale zero; those towards an input declare the log of their normaliser. The node runs under DefaultAlgorithm and has no average energy of its own.
The joint marginal of the inputs, q(in1, in2), is a Contingency table over {false, true}², rows in1 and columns in2, false first.