Identification Algorithms

Queries and certificates

CausalDynamics.TotalEffectQueryType
TotalEffectQuery(treatment, outcome)

Backdoor-identifiable total effect of treatment on outcome. Node labels may be Int indices or Symbol names (with a node_names map).

source
CausalDynamics.MediationQueryType
MediationQuery(treatment, outcome, mediators)

Interventional mediation decomposition (NDE / NIE / TE) via mediators on directed paths.

source
CausalDynamics.InterventionalPolicyQueryType
InterventionalPolicyQuery(treatment, outcome; shift=nothing)

Modified treatment policy / stochastic intervention contrast on treatment. shift is an application-defined policy descriptor (estimators interpret it).

source
CausalDynamics.identifyFunction
identify(g, query::TotalEffectQuery; node_names=nothing) -> IdentificationResult
source
identify(g, query::MediationQuery; node_names=nothing) -> IdentificationResult
source
identify(g, query::InterventionalPolicyQuery; node_names=nothing) -> IdentificationResult

Policy contrasts reduce to total-effect identification on the same (treatment, outcome) pair.

source
identify(unrolling::TemporalUnrolling, query::TemporalEffectQuery) -> IdentificationResult
source
identify(g, query::CausalQuery; kwargs...) -> IdentificationResult
source
CausalDynamics.identification_reportFunction
identification_report(g, treatment, outcome; node_names=nothing) -> Vector{NamedTuple}

Enumerate candidate adjustment sets and mark which satisfy the backdoor criterion. Returns a vector of named tuples (no DataFrames dependency).

source

Adjustment and instruments

CausalDynamics.backdoor_adjustment_setFunction
backdoor_adjustment_set(g, X, Y)

Find a valid backdoor adjustment set for estimating the causal effect of X on Y.

Delegates to CausalInference.find_min_backdoor_adjustment. Returns nothing if no valid set exists (false from CausalInference).

Arguments

  • g: Directed acyclic graph
  • X: Treatment node
  • Y: Outcome node

Returns

  • Set{Int} of adjustment nodes (possibly empty if no backdoors), or nothing
source
CausalDynamics.frontdoor_adjustment_setFunction
frontdoor_adjustment_set(g, X, Y, M)

Check if M is a valid frontdoor adjustment set for estimating the causal effect of X on Y.

The frontdoor criterion states that a set M is a valid frontdoor adjustment set if:

  1. M blocks all directed paths from X to Y
  2. There are no backdoor paths from X to M
  3. All backdoor paths from M to Y are blocked by X

Uses reachability (BFS), not path enumeration — safe on dense DAGs.

Arguments

  • g: Directed acyclic graph
  • X: Treatment node
  • Y: Outcome node
  • M: Potential mediator set

Returns

  • true if M is a valid frontdoor adjustment set, false otherwise
source
CausalDynamics.find_path_mediatorsFunction
find_path_mediators(g, treatment, outcome) -> Set{Int}

Structural mediator candidates between treatment and outcome: nodes that lie on at least one proper directed path treatment → ⋯ → outcome (excluding the endpoints).

On a DAG this is

intersect(get_descendants(g, treatment), get_ancestors(g, outcome))

This is not the frontdoor criterion. For single-node sets that satisfy the frontdoor criterion, use find_frontdoor_mediators.

Arguments

  • g: Directed acyclic graph
  • treatment: Treatment node index
  • outcome: Outcome node index

Returns

  • Set{Int} of mediator candidate indices

Examples

using CausalDynamics, Graphs

# Nodes: A=1, M1=2, M2=3, M3=4, Y=5, C=6, D=7
# A → M1 → M2 → Y; A → M3 → Y; C → A; C → Y; A → D
g = DiGraph(7)
add_edge!(g, 1, 2); add_edge!(g, 2, 3); add_edge!(g, 3, 5)
add_edge!(g, 1, 4); add_edge!(g, 4, 5)
add_edge!(g, 6, 1); add_edge!(g, 6, 5)
add_edge!(g, 1, 7)

find_path_mediators(g, 1, 5)  # Set([2, 3, 4]) == {M1, M2, M3}
source
find_path_mediators(g, treatment, outcome; node_names) -> Set

As find_path_mediators with Int indices, but treatment / outcome may be Symbols when node_names maps indices to names (same conventions as identify).

Returns a Set{Symbol} when node_names is provided, otherwise Set{Int}.

source
CausalDynamics.find_minimal_mediator_setsFunction
find_minimal_mediator_sets(g, treatment, outcome; max_candidates=20) -> MinimalMediatorSets{Int}

Inclusion-minimal sets of mediators that intercept every directed path treatment → ⋯ → outcome.

A set $S$ intercepts all directed paths when intercepts_all_directed_paths (g, treatment, outcome, S) is true. Equivalently, $S$ is a hitting set for the intermediate nodes of every directed path.

Returns a MinimalMediatorSets with:

  • sets: all inclusion-minimal cuts, sorted by (length, sorted members)
  • status: :ok, :no_path, :uncuttable_direct_edge, or :uncuttable

Uses directed reachability (BFS with forbidden nodes), not full path enumeration. Candidate nodes are find_path_mediators. Enumeration of subsets is exponential in the number of candidates; max_candidates caps that search.

This is not the frontdoor criterion — see find_frontdoor_mediators. Nor does it choose mediators for MediationQuery; pass a chosen set explicitly after inspecting .sets.

Examples

using CausalDynamics, Graphs

# Sequential: A → M1 → M2 → Y
g = DiGraph(4)
add_edge!(g, 1, 2); add_edge!(g, 2, 3); add_edge!(g, 3, 4)
r = find_minimal_mediator_sets(g, 1, 4)
r.status  # :ok
r.sets    # [Set([2]), Set([3])]

# Parallel: A → M1 → Y and A → M2 → Y
g = DiGraph(4)
add_edge!(g, 1, 2); add_edge!(g, 2, 4)
add_edge!(g, 1, 3); add_edge!(g, 3, 4)
find_minimal_mediator_sets(g, 1, 4).sets  # [Set([2, 3])]

# Mixed: A → M1 → M3 → Y and A → M2 → M3 → Y
g = DiGraph(5)
add_edge!(g, 1, 2); add_edge!(g, 2, 4); add_edge!(g, 4, 5)
add_edge!(g, 1, 3); add_edge!(g, 3, 4)
find_minimal_mediator_sets(g, 1, 5).sets  # [Set([4]), Set([2, 3])]
source
find_minimal_mediator_sets(g, treatment, outcome; node_names, max_candidates=20)

As find_minimal_mediator_sets with Int indices. With node_names, returns MinimalMediatorSets{Symbol}.

source
CausalDynamics.MinimalMediatorSetsType
MinimalMediatorSets{T}

Result of find_minimal_mediator_sets.

Fields

  • sets: Inclusion-minimal mediator sets, sorted by (length, sorted members)
  • status:
    • :oksets holds the cuts (possibly empty only in degenerate cases)
    • :no_path — no directed path from treatment to outcome
    • :uncuttable_direct_edge — a direct treatment→outcome edge cannot be cut by mediators
    • :uncuttable — a residual directed path avoids every path-mediator candidate

Iterates over sets (so collect(result) and Set(result) still work).

source
CausalDynamics.find_instrumentsFunction
find_instruments(g, X, Y)

Find instrumental variables for estimating the causal effect of X on Y.

An instrumental variable Z must satisfy:

  1. Z has a causal effect on X
  2. Z affects Y only through X (exclusion restriction)
  3. Z is independent of confounders of X and Y (independence)

Arguments

  • g: Directed acyclic graph
  • X: Treatment node
  • Y: Outcome node

Returns

  • Vector of potential instrumental variables

Examples

using CausalDynamics, Graphs

# IV example
g = DiGraph(4)
add_edge!(g, 1, 2)  # Z → X
add_edge!(g, 2, 3)  # X → Y
add_edge!(g, 4, 2)  # U → X
add_edge!(g, 4, 3)  # U → Y

# Z is a valid instrument
instruments = find_instruments(g, 2, 3)  # [1]

References

  • Angrist, J. D., & Pischke, J. S. (2009). Mostly Harmless Econometrics
source
CausalDynamics.is_valid_instrumentFunction
is_valid_instrument(g, Z, X, Y)

Check if Z is a valid instrumental variable for X → Y.

An instrument Z must satisfy three conditions:

  1. Relevance: Z has a causal effect on X (directed path Z → X)
  2. Exclusion restriction: Z affects Y only through X (all paths Z → Y go through X)
  3. Independence: Z is independent of confounders (no backdoor paths Z → Y)

Arguments

  • g::AbstractGraph: Directed acyclic graph
  • Z::Int: Potential instrument node
  • X::Int: Treatment node
  • Y::Int: Outcome node

Returns

  • Bool: true if Z is a valid instrument, false otherwise

Examples

using CausalDynamics, Graphs

# Valid instrument
g = DiGraph(4)
add_edge!(g, 1, 2)  # Z → X
add_edge!(g, 2, 3)  # X → Y
add_edge!(g, 4, 2)  # U → X
add_edge!(g, 4, 3)  # U → Y

is_valid_instrument(g, 1, 2, 3)  # true

# Invalid: Z has direct path to Y
g2 = DiGraph(3)
add_edge!(g2, 1, 2)  # Z → X
add_edge!(g2, 1, 3)  # Z → Y (violates exclusion)
add_edge!(g2, 2, 3)  # X → Y

is_valid_instrument(g2, 1, 2, 3)  # false

Notes

  • The independence condition (3) is checked conservatively: if any backdoor paths exist, returns false
  • In practice, independence may hold even with backdoor paths if they are blocked

References

  • Angrist, J. D., & Pischke, J. S. (2009). Mostly Harmless Econometrics, Chapter 4
source

Column resolvers

Map graph node labels to data columns after identification.