Skip to content

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.

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)

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.ATEMPORAL for 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:
  • Return type: None

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.ATEMPORAL for 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
  • Return type: None

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

Remove all recorded interventions.

  • Return type: None

Remove all recorded observations.

  • Return type: None

Remove all targets (restores default-all-targets mode).

  • Return type: None

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

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

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
  • 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

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

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
  • Returns: True iff at least one explicit target has been declared; when False, every base is a target
  • Return type: bool
  • Parameters: base (str) – a base variable
  • Returns: True if base is a target of the next inference
  • Return type: bool
  • Returns: the k-TBN this engine reasons about
  • Return type: KTBN

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

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:
  • Return type: None

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

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.

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
  • Returns: a human-readable summary of the engine’s state
  • Return type: str

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