Skip to content

Nodes

Index

Types

EnhancedBayesianNetworks.DiscreteNode Type
julia
DiscreteNode(name, parents=Symbol[], parameters=[], results=nothing)
DiscreteNode(cpt::ScenariosTable, parameters=[], results=nothing)

A discrete-state node. Holds a conditional probability table (cpt) over its parents' state combinations and its own states. Optional per-state parameters (used when it feeds a functional node) and optional stored results when a FunctionalNode is evaluated into a DiscreteNode. Entries may be precise (Real) or imprecise/credal (Interval). Build by name and fill with node[parent1 => sₚ1, ..., name => sₙ] = p.

Examples

julia
W = DiscreteNode(:W)                     # root node
W[:W => :sunny]  = 0.5
W[:W => :cloudy] = 0.5

# a node can carry per-state `parameters` (consumed when it feeds a functional node);
# each of its own states maps to a vector of `Parameter`s and is set at construction:
S = DiscreteNode(:S, [:W], [:on => [Parameter(0.5, :S)], :off => [Parameter(0.0, :S)]])
S[:W => :sunny,  :S => :on]  = 0.9
S[:W => :sunny,  :S => :off] = 0.1
S[:W => :cloudy, :S => :on]  = 0.2
S[:W => :cloudy, :S => :off] = 0.8

# credal (imprecise) entries use an Interval instead of a Real:
S[:W => :sunny, :S => :on] = Interval(0.8, 0.95)
source
EnhancedBayesianNetworks.ContinuousNode Type
julia
ContinuousNode(name, parents=Symbol[], discretization=ExactDiscretization(), results=nothing)
ContinuousNode(name, dist::ContinuousProbability)
ContinuousNode(name, dist::ContinuousProbability, discretization::ExactDiscretization)

A continuous-valued node. Its table (cpt) maps each parent-state combination to a continuous probability, either precise (a UnivariateDistribution) or imprecise/credal (an Interval or a ProbabilityBox). The discretization field controls how the node is turned into discrete bins during inference: a root node carries an ExactDiscretization (explicit interval edges), a child node an ApproximatedDiscretization (chosen automatically when parents are given).

Build a root either with the ContinuousNode(name, dist) shortcut or by assigning node[] = dist; build a child by naming its parents and filling one distribution per parent state with node[parent => state] = dist.

Examples

julia
# root node from a single distribution:
T = ContinuousNode(:T, Normal())                     # root node

# root node with explicit discretization edges (used later during inference):
Td = ContinuousNode(:T, Normal(), ExactDiscretization([-2.0, 0.0, 2.0]))

# child node: one distribution per parent state (discretization is set to Approximated automatically):
C = ContinuousNode(:C, [:W])
C[:W => :sunny]  = Normal()
C[:W => :cloudy] = Normal(2, 1)

# imprecise (credal) entries use an Interval instead of a distribution:
C[:W => :sunny] = Interval(0.1, 0.5)
source
EnhancedBayesianNetworks.ContinuousFunctionalNode Type
julia
ContinuousFunctionalNode(name, models, simulation, discretization=ApproximatedDiscretization(), nbins=0)
ContinuousFunctionalNode(name, ancestors::Vector{Symbol}, models, discretization=ApproximatedDiscretization(), nbins=0)

A continuous node whose value is computed from its ancestors by one or more UncertaintyQuantification models, instead of being stored as a table. When the node is evaluated, simulation (e.g. MonteCarlo) propagates the parents' uncertainty through the models to produce output samples; these samples are then turned back into a continuous distribution by fitting an EmpiricalDistribution with nbins bins. Separately, discretization (an ApproximatedDiscretization) holds the interval edges used to discretize that continuous node into discrete states for downstream discrete inference. The node is evaluated once per combination of its discrete ancestors, so its uncertainty comes only from its direct parents while the discrete ancestors form the scenario grid the simulation is repeated over. A functional node is never a root; its parents are the inputs referenced by the models, or may be listed explicitly in the second form.

Examples

julia
model = Model(df -> df.x .^ 2, :y)                 # y is computed from parent x

# propagate x's uncertainty through the model with a Monte Carlo simulation:
CF = ContinuousFunctionalNode(:CF, [model], MonteCarlo(1000))

# use 10 bins when refitting the output's EmpiricalDistribution from the samples:
CFb = ContinuousFunctionalNode(:CF, [model], MonteCarlo(1000), 10)
source
EnhancedBayesianNetworks.DiscreteFunctionalNode Type
julia
DiscreteFunctionalNode(name, models, performance, simulation, parameters=[])
DiscreteFunctionalNode(name, ancestors::Vector{Symbol}, models, performance, parameters=[])

A discrete node whose two states — :<name>_safe and :<name>_failed — come from a reliability analysis rather than a table. When the node is evaluated, simulation (e.g. MonteCarlo) propagates the parents' uncertainty through the models, and the performance function maps the models' output to a limit state: the node is failed where performance < 0 and safe otherwise. The estimated failure probability is stored on :<name>_failed and its complement on :<name>_safe. The node is evaluated once per combination of its discrete ancestors, so its uncertainty comes only from its direct parents while the discrete ancestors form the scenario grid the simulation is repeated over. Optional per-state parameters behave as in DiscreteNode: they are forwarded to descendants when this node feeds a further functional node. A functional node is never a root; its parents are the inputs referenced by the models, or may be listed explicitly in the second form.

Examples

julia
model = Model(df -> df.x .^ 2, :y)
performance = df -> df.y .- 1.0                    # failed when y < 1

DF = DiscreteFunctionalNode(:DF, [model], performance, MonteCarlo(1000))
states(DF)                                         # [:DF_safe, :DF_failed]

# optional per-state parameters, keyed by the two derived states:
DFp = DiscreteFunctionalNode(:DF, [model], performance, MonteCarlo(1000),
    [:DF_safe => [Parameter(1.0, :DF)], :DF_failed => [Parameter(0.0, :DF)]])
source
EnhancedBayesianNetworks.ExactDiscretization Type
julia
ExactDiscretization(intervals=Real[])

Discretization strategy for a continuous root node, allowing evidence to be observed on it. The node's distribution support is partitioned exactly at the sorted intervals edges, turning the continuous root into discrete bins. The default (empty intervals) leaves the node continuous, i.e. no discretization is applied. The edges must be sorted.

Examples

julia
# discretize a root node's support at the edges -2, 0, 2:
disc = ExactDiscretization([-2.0, 0.0, 2.0])
T = ContinuousNode(:T, Normal(), disc)

ExactDiscretization()            # empty: the root stays continuous
source
EnhancedBayesianNetworks.ApproximatedDiscretization Type
julia
ApproximatedDiscretization(intervals=Real[], sigma=0)

Discretization strategy for a continuous non-root (child) node, allowing evidence to be observed on it. The sorted intervals edges partition the support into discrete bins, while sigma is the spread of the normal distribution used to approximate the original continuous distribution's tails when a discrete state is mapped back to a continuous range. sigma must be non-negative; a value above 2 is accepted but warns, as it tends to give an unrealistic tail approximation.

Examples

julia
# discretize a child node at edges -1, 0, 1, approximating tails with spread 1.5:
disc = ApproximatedDiscretization([-1.0, 0.0, 1.0], 1.5)
C = ContinuousNode(:C, [:W], disc)
source

Methods

EnhancedBayesianNetworks.states Function
julia
states(node)

Return the vector of discrete states a node can take. Defined for discrete-type nodes: a DiscreteNode returns its own states, a DiscreteFunctionalNode returns its two derived states :<name>_safe and :<name>_failed. Continuous nodes have no discrete states, so calling states on them is a MethodError.

Examples

julia
W = DiscreteNode(:W); W[:W => :sunny] = 0.5; W[:W => :cloudy] = 0.5
states(W)                                   # [:sunny, :cloudy]

m = Model(df -> df.x .^ 2, :y)
DF = DiscreteFunctionalNode(:DF, [:x], m, df -> 1 .- df.y)
states(DF)                                  # [:DF_safe, :DF_failed]
source
EnhancedBayesianNetworks.scenarios Function
julia
scenarios(node)

List every row of the node's CPT as a vector of parent => state pairs. For a DiscreteNode each scenario also carries the node's own state; for a ContinuousNode only the parent-state combinations are returned (a continuous node has no discrete state of its own). A root node yields a single empty scenario. Not defined for functional nodes.

Examples

julia
S = DiscreteNode(:S, [:W])
S[:W => :sunny,  :S => :on]  = 0.9; S[:W => :sunny,  :S => :off] = 0.1
S[:W => :cloudy, :S => :on]  = 0.2; S[:W => :cloudy, :S => :off] = 0.8
scenarios(S)   # [[:W=>:sunny,:S=>:on], [:W=>:sunny,:S=>:off], [:W=>:cloudy,:S=>:on], [:W=>:cloudy,:S=>:off]]

C = ContinuousNode(:C, [:W]); C[:W => :sunny] = Normal(); C[:W => :cloudy] = Normal(2, 1)
scenarios(C)   # [[:W => :sunny], [:W => :cloudy]]
source
EnhancedBayesianNetworks.parents Function
julia
parents(node)
parents(net, name::Symbol)
parents(net, node)

Return the parent names of a node as a Vector{Symbol} (empty for a root). The single-argument form reads the parents off the node's own table (DiscreteNode/ContinuousNode); the network forms look up the parents of name (or node) within net's topology and work for every node type, including functional nodes.

Examples

julia
W = DiscreteNode(:W); W[:W => :sunny] = 0.5; W[:W => :cloudy] = 0.5
S = DiscreteNode(:S, [:W])
parents(W)                                  # Symbol[]
parents(S)                                  # [:W]

bn = BayesianNetwork([W, S]); add_child!(bn, :W, :S); order!(bn)
parents(bn, :S)                             # [:W]
source
EnhancedBayesianNetworks.isroot Function
julia
isroot(node)

Return true if the node has no parents (a root of the network). A FunctionalNode is never a root (false always), since it is defined by models over its ancestors.

Examples

julia
W = DiscreteNode(:W); W[:W => :sunny] = 0.5; W[:W => :cloudy] = 0.5
isroot(W)                                   # true

S = DiscreteNode(:S, [:W]);  isroot(S)      # false
T = ContinuousNode(:T, Normal());  isroot(T)  # true
source
EnhancedBayesianNetworks.isprecise Function
julia
isprecise(node)

Return true if every entry in the node's CPT is precise, false if any is imprecise/credal. For a DiscreteNode precise means every probability is a Real (imprecise entries are Intervals); for a ContinuousNode precise means every entry is a UnivariateDistribution (imprecise entries are Interval/ProbabilityBox).

Examples

julia
S = DiscreteNode(:S, [:W])
S[:W => :sunny,  :S => :on] = 0.9; S[:W => :sunny,  :S => :off] = 0.1
S[:W => :cloudy, :S => :on] = 0.2; S[:W => :cloudy, :S => :off] = 0.8
isprecise(S)                                # true

S[:W => :sunny, :S => :on] = Interval(0.8, 0.95)   # a credal entry
isprecise(S)                                # false

T = ContinuousNode(:T, Normal());  isprecise(T)     # true
source
EnhancedBayesianNetworks.sample Function
julia
sample(node::DiscreteNode, evidence::Evidence)
sample(bn::BayesianNetwork, n::Int=1)

Draw discrete samples. Given a DiscreteNode and an Evidence fixing its parents (and, optionally, the node itself), return one sampled state of the node; sampling a node whose entries are imprecise raises an error. Given a BayesianNetwork, perform ancestral sampling of n joint draws (ordering the network first) and return them as a DataFrame with one column per node.

Examples

julia
W = DiscreteNode(:W); W[:W => :sunny] = 0.5; W[:W => :cloudy] = 0.5
S = DiscreteNode(:S, [:W])
S[:W => :sunny,  :S => :on] = 0.9; S[:W => :sunny,  :S => :off] = 0.1
S[:W => :cloudy, :S => :on] = 0.2; S[:W => :cloudy, :S => :off] = 0.8

sample(S, Evidence(:W => :sunny))           # e.g. :on

bn = BayesianNetwork([W, S]); add_child!(bn, :W, :S); order!(bn)
sample(bn, 3)                               # 3×2 DataFrame with columns :W, :S
source