Inference in k-TBNs
Inference in a k-TBN computes P(target[t] | observations, interventions) for every declared target at every time slice, under any mix of soft/hard observations and Pearl-style do-interventions – without ever unrolling the model. aGrUM/pyAgrum implements one exact algorithm, a generalization of Murphy’s interface algorithm to order k.
class pyagrum.ktbn.KTBNInference(ktbn)
Section titled “class pyagrum.ktbn.KTBNInference(ktbn)”KTBNInference answers exact queries on a pyagrum.ktbn.KTBN under any mix
of observations (soft or hard evidence) and hard interventions
(Pearl’s do-operator), returning P(target[t] | obs, do(…)) for every declared
target at every time slice, without ever unrolling the model.
An observation is conditioning: it revises the whole network, ancestors included. An intervention do(V[t]=v) is surgery: V[t] is cut from its causes and forced to v, so the effect only reaches its descendants. Both may be combined, and a node may carry both.
Warning
The k-TBN is referenced, not copied: it must outlive the inference engine.
Examples
>>> import pyagrum.ktbn as ktbn>>> ie = ktbn.KTBNInference(model)>>> ie.addObservation("Y", 3, 1) # observe Y[3] = 1>>> ie.addIntervention("X", 2, 1) # do(X[2] = 1)>>> ie.addTarget("X") # want the whole P(X[t] | ...) series>>> ie.makeInference(10) # compute slices 0..9>>> p3 = ie.posterior("X", 3)>>> px = ie.posteriors("X")>>> logpe = ie.logObservationProbability()KTBNInference(ktbn) -> KTBNInference : Parameters: : - ktbn (pyagrum.ktbn.KTBN) – the k-TBN to reason about (referenced, not copied)
- Raises: pyagrum.InvalidArgument – if ktbn is None
- Parameters:
ktbn (
KTBN)
ATEMPORAL = -1
Section titled “ATEMPORAL = -1”addIntervention(*args)
Section titled “addIntervention(*args)”Record a hard intervention do(base[slice] = value). Recorded only; applied at
makeInference(). Re-intervening on the same node overwrites.
The batch form takes a dict {node: value}, node keyed by an engine name (e.g.
"X[5]") or a (base, slice) tuple, all-or-nothing validated before
anything is recorded.
Examples
>>> ie.addIntervention("X", 5, 0) # by (base, slice), index>>> ie.addIntervention("X", 5, "high") # by (base, slice), label>>> ie.addIntervention("X[5]", 0) # by engine name>>> ie.addIntervention({"X[5]": 0, ("Z", 2): "high"}) # batch- Parameters:
- base (str) – base name of the target (used together with slice)
- slice (int) – slice of the target (
pyagrum.ktbn.KTBN.ATEMPORALfor a static node) - node_name (str) – alternatively, the target’s engine name
- value (int or str) – the forced modality, as an index or a label
- interventions (dict) – for the batch form, one node -> value entry per intervention
- Raises:
- pyagrum.NotFound – if the node is unknown, or value is not a legal modality
- pyagrum.InvalidArgument – if the slice is invalid for the node’s kind
- pyagrum.OutOfBounds – if a modality index is out of range
- Return type:
None
addObservation(*args)
Section titled “addObservation(*args)”Record an observation on base[slice]: a hard observation base[slice]=value
(conditioning: revises the whole network, ancestors included), or a soft
(likelihood) observation via a list of per-modality likelihoods (a one-hot
vector is equivalent to a hard observation). Recorded only; applied at
makeInference(). Re-observing the same node overwrites.
The batch form (addObservations) takes a dict {node: value} of hard
observations only, node keyed by an engine name or a (base, slice) tuple,
all-or-nothing validated before anything is recorded.
Examples
>>> ie.addObservation("X", 5, 0) # hard, by index>>> ie.addObservation("X", 5, "high") # hard, by label>>> ie.addObservation("X", 5, [0.1, 0.9]) # soft (likelihoods)>>> ie.addObservations({"X[5]": 0, ("Z", 2): 1}) # batch, hard only- Parameters:
- base (str) – base name of the target (used together with slice)
- slice (int) – slice of the target (
pyagrum.ktbn.KTBN.ATEMPORALfor a static node) - node_name (str) – alternatively, the target’s engine name
- value (int or str) – for a hard observation, the observed modality (index or label)
- likelihood (list *[*float ]) – for a soft observation, one non-negative, not-all-zero weight per modality
- observations (dict) – for the batch form, one node -> value entry per hard observation
- Raises:
- pyagrum.NotFound – if the node is unknown, or value is not a legal modality
- pyagrum.InvalidArgument – if the slice is invalid, or likelihood has the wrong length, a negative entry, or is all zeros
- Return type:
None
addObservations(*args)
Section titled “addObservations(*args)”- Return type:
None
addTarget(base)
Section titled “addTarget(base)”Declare base as a target: a base variable whose marginals are wanted. The first
declared target switches the engine out of default-all-targets mode (with no
target declared, every base is a target). Recorded only; applied at
makeInference().
- Parameters:
base (
str) – a temporal or atemporal base variable of the k-TBN - Raises: pyagrum.NotFound – if base is neither a temporal nor an atemporal variable of the k-TBN
- Return type:
None
clearInterventions()
Section titled “clearInterventions()”Remove all recorded interventions.
- Return type:
None
clearObservation()
Section titled “clearObservation()”Remove all recorded observations.
- Return type:
None
clearTargets()
Section titled “clearTargets()”Remove all targets (restores default-all-targets mode).
- Return type:
None
eraseIntervention(*args)
Section titled “eraseIntervention(*args)”Remove a recorded intervention (silent no-op if absent).
- Parameters:
- base (str) – base name of the node (used together with slice)
- slice (int) – slice of the node
- node_name (str) – alternatively, the node’s engine name
- Return type:
None
eraseObservation(*args)
Section titled “eraseObservation(*args)”Remove a recorded observation (silent no-op if absent).
- Parameters:
- base (str) – base name of the node (used together with slice)
- slice (int) – slice of the node
- node_name (str) – alternatively, the node’s engine name
- Return type:
None
eraseTarget(base)
Section titled “eraseTarget(base)”Remove a target; when the last one is removed, default-all-targets mode is restored.
- Parameters:
base (
str) – the base variable to un-target - Return type:
None
hasIntervention(*args)
Section titled “hasIntervention(*args)”- Parameters:
- base (str) – base name of the node (used together with slice)
- slice (int) – slice of the node
- node_name (str) – alternatively, the node’s engine name
- Returns: True if the node carries an intervention
- Return type:
bool
hasObservation(*args)
Section titled “hasObservation(*args)”With no argument, tells whether any observation at all is recorded (when False,
makeInference() needs no backward pass and runs in horizon-independent
memory).
- Parameters:
- base (str , optional) – base name of the node (used together with slice)
- slice (int , optional) – slice of the node
- node_name (str , optional) – alternatively, the node’s engine name
- Returns: True if the node (or, with no argument, any node) carries an observation
- Return type:
bool
interfaceSize()
Section titled “interfaceSize()”Introspection only: the size of the forward interface of the repeating window, i.e. how many node occurrences have to cross each slice boundary.
- Returns: the interface size
- Return type:
int
isInTargetMode()
Section titled “isInTargetMode()”- Returns: True iff at least one explicit target has been declared; when False, every base is a target
- Return type:
bool
isTarget(base)
Section titled “isTarget(base)”- Parameters:
base (
str) – a base variable - Returns: True if base is a target of the next inference
- Return type:
bool
ktbn()
Section titled “ktbn()”- Returns: the k-TBN this engine reasons about
- Return type:
KTBN
logObservationProbability()
Section titled “logObservationProbability()”Return log2 P(obs | do(…)) for the last run: the log-likelihood of the
recorded observations under the (possibly mutilated) model. 0 when nothing is
observed. Lazily (re)runs makeInference() if the cache is out of date.
- Returns: the log2-probability of the observations
- Return type:
float - Raises: pyagrum.OperationNotAllowed – if makeInference has never been run
makeInference(nbTimeSlices)
Section titled “makeInference(nbTimeSlices)”Run the interface algorithm over nbTimeSlices slices (0..nbTimeSlices-1) and
cache, for every targeted base, its marginal at every slice. Idempotent, and
called lazily by posterior()/posteriors() (with the last horizon)
whenever their cache is out of date.
- Parameters:
nbTimeSlices (
int) – the horizon: number of time slices to compute - Raises:
- pyagrum.InvalidArgument – if nbTimeSlices is 0
- pyagrum.FatalError – if the recorded observations have probability 0 under the model
- Return type:
None
observationProbability()
Section titled “observationProbability()”Return P(obs | do(…)), i.e. 2 raised to logObservationProbability().
Prefer the log form on long horizons, where this one underflows to 0.
- Returns: the probability of the observations
- Return type:
float
posterior(*args)
Section titled “posterior(*args)”Return P(base[slice] | obs, do(…)). Lazily (re)runs makeInference() with
the last horizon if the cache is out of date. The returned reference is owned
by the engine and invalidated by the next makeInference() call: copy it to
keep it.
- Parameters:
- base (str) – base name of the queried node (used together with slice)
- slice (int) – slice of the queried node (
pyagrum.ktbn.KTBN.ATEMPORALfor a static node) - node_name (str) – alternatively, the node’s engine name
- Returns: the posterior distribution
- Return type:
Tensor - Raises:
- pyagrum.OperationNotAllowed – if makeInference has never been run
- pyagrum.UndefinedElement – if base is not a target
- pyagrum.OutOfBounds – if slice was not computed (>= the horizon)
posteriors(base)
Section titled “posteriors(base)”The whole marginal time-series of a targeted base variable.
- Parameters:
base (
str) – the base name of a temporal process or an atemporal variable - Returns: one Tensor per slice (a single-element list for an atemporal base)
- Return type:
list
toString()
Section titled “toString()”- Returns: a human-readable summary of the engine’s state
- Return type:
str
windowJunctionTree()
Section titled “windowJunctionTree()”Introspection only: the junction tree of the repeating window, compiled once from the k-slice template and re-entered at every step from slice k-1 on.
- Returns: the window’s junction tree
- Return type: pyagrum.JunctionTree