Graph Operations

Names also exported by DAGMakie (find_backdoor_paths, find_directed_paths, is_dag) are written fully qualified so the docs build resolves them unambiguously when the plotting extension is loaded.

Paths and ancestry

CausalDynamics.d_separated — Function
d_separated(g, X, Y, Z)

Check if nodes X and Y are d-separated by set Z in directed acyclic graph g.

Delegates to CausalInference.dsep.

Arguments

  • g: A directed acyclic graph (DiGraph)
  • X: Source node or set of nodes
  • Y: Target node or set of nodes
  • Z: Conditioning set (vector, set, or single node)

Returns

  • true if X and Y are d-separated by Z, false otherwise
source
CausalDynamics.get_ancestors — Function
get_ancestors(g, nodes)

Get the set of all ancestors of the given nodes.

An ancestor of node X is any node that has a directed path to X.

Arguments

  • g: Directed acyclic graph
  • nodes: Node or set of nodes

Returns

  • Set of ancestor nodes

Examples

using CausalDynamics, Graphs

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

ancestors = get_ancestors(g, 4)  # {1, 2, 3}
source
CausalDynamics.get_descendants — Function
get_descendants(g, nodes)

Get the set of all descendants of the given nodes.

A descendant of node X is any node that has a directed path from X.

Arguments

  • g: Directed acyclic graph
  • nodes: Node or set of nodes

Returns

  • Set of descendant nodes

Examples

using CausalDynamics, Graphs

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

descendants = get_descendants(g, 1)  # {2, 3, 4}
source
CausalDynamics.get_parents — Function
get_parents(g, nodes)

Get the set of parents of the given nodes.

A parent of node X is a node with a direct edge pointing into X.

Arguments

  • g::AbstractGraph: Directed acyclic graph
  • nodes: Node (Int) or collection of nodes (Vector/Set)

Returns

  • Set{Int}: Set of parent nodes

Examples

using CausalDynamics, Graphs

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

parents = get_parents(g, 3)  # {1, 2}
source
CausalDynamics.get_children — Function
get_children(g, nodes)

Get the set of children of the given nodes.

A child of node X is a node with a direct edge pointing from X.

Arguments

  • g::AbstractGraph: Directed acyclic graph
  • nodes: Node (Int) or collection of nodes (Vector/Set)

Returns

  • Set{Int}: Set of child nodes

Examples

using CausalDynamics, Graphs

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

children = get_children(g, 1)  # {2, 3}
source
CausalDynamics.markov_boundary — Function
markov_boundary(g, Y)

Compute the Markov boundary of node Y.

The Markov boundary of Y is the minimal set that d-separates Y from all other nodes. It consists of: parents of Y, children of Y, and parents of children of Y.

Arguments

  • g: Directed acyclic graph
  • Y: Target node

Returns

  • Set of nodes in the Markov boundary

Examples

using CausalDynamics, Graphs

g = DiGraph(4)
add_edge!(g, 1, 2)  # X → Y
add_edge!(g, 3, 2)  # Z → Y
add_edge!(g, 2, 4)  # Y → W
add_edge!(g, 5, 4)  # V → W

mb = markov_boundary(g, 2)  # {1, 3, 4, 5}
# Parents: {1, 3}
# Children: {4}
# Parents of children: {5}
source
CausalDynamics.find_backdoor_paths — Function
find_backdoor_paths(g, X, Y; max_paths=10_000)

Find all backdoor paths from X to Y.

A backdoor path is a path that starts with an edge pointing into X.

Arguments

  • g: Directed acyclic graph
  • X: Source node
  • Y: Target node
  • max_paths: Cap on enumerated paths (raises if exceeded)

Returns

  • Vector of backdoor paths (each path is a vector of nodes)
source
CausalDynamics.nodes_on_directed_paths — Function
nodes_on_directed_paths(g, X, Y) -> Set{Int}

Nodes that lie on at least one directed path from X to Y (including endpoints).

On a DAG this is ({X} ∪ descendants(X)) ∩ ({Y} ∪ ancestors(Y)) restricted to nodes reachable from X toward Y — computed via BFS, not path enumeration.

source
CausalDynamics.has_path — Function
has_path(g, source, target)

Check if there exists a directed path from source to target.

A directed path follows edges in their forward direction only.

Arguments

  • g::AbstractGraph: Directed acyclic graph
  • source::Int: Source node
  • target::Int: Target node

Returns

  • Bool: true if a directed path exists, false otherwise

Examples

using CausalDynamics, Graphs

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

has_path(g, 1, 3)  # true (path: 1 → 2 → 3)
has_path(g, 3, 1)  # false (no reverse path)

Notes

  • Returns false if source == target (no self-loops)
  • Uses BFS reachability (not path enumeration)
source
CausalDynamics.is_dag — Function
is_dag(g)

Check if graph g is a directed acyclic graph (DAG).

A DAG is a directed graph with no cycles (no path from a node back to itself).

Arguments

  • g::AbstractGraph: Directed graph to test

Returns

  • Bool: true if g is a DAG, false otherwise

Examples

using CausalDynamics, Graphs

# Valid DAG
g1 = DiGraph(3)
add_edge!(g1, 1, 2)
add_edge!(g1, 2, 3)
is_dag(g1)  # true

# Contains cycle
g2 = DiGraph(3)
add_edge!(g2, 1, 2)
add_edge!(g2, 2, 3)
add_edge!(g2, 3, 1)  # Cycle: 1 → 2 → 3 → 1
is_dag(g2)  # false

Notes

  • Uses topological sort to detect cycles
  • Returns false if topological sort fails (indicates cycle)
  • Causal graphs must be DAGs (no causal loops)

See Also

  • validate_causal_graph: Validate and throw error if not DAG
source
CausalDynamics.validate_causal_graph — Function
validate_causal_graph(g)

Validate that graph g is a valid causal graph (DAG).

Causal graphs must be directed acyclic graphs (DAGs) to represent well-defined causal relationships without circular dependencies.

Arguments

  • g::AbstractGraph: Directed graph to validate

Returns

  • Bool: true if valid (always returns true, throws on error)

Throws

  • ArgumentError: If graph is not a DAG (contains cycles)

Examples

using CausalDynamics, Graphs

# Valid DAG
g1 = DiGraph(3)
add_edge!(g1, 1, 2)
add_edge!(g1, 2, 3)
validate_causal_graph(g1)  # true

# Invalid: contains cycle
g2 = DiGraph(3)
add_edge!(g2, 1, 2)
add_edge!(g2, 2, 3)
add_edge!(g2, 3, 1)
validate_causal_graph(g2)  # throws ArgumentError

Notes

  • Used internally by identification functions to ensure graph validity
  • Causal models require DAGs to avoid circular causal dependencies
  • Throws error rather than returning false for clearer error messages

See Also

  • is_dag: Check if graph is DAG (returns boolean)
source
CausalDynamics.create_causal_graph — Function
create_causal_graph(edges)

Create a causal graph from a list of edges.

Convenience function to create a validated DAG from edge specifications. Automatically determines graph size and validates that the result is a DAG.

Arguments

  • edges: Edge specification, either:
    • Vector{Tuple{Int, Int}}: List of (source, target) tuples
    • Dict{Int, Vector{Int}}: Dictionary mapping source nodes to vectors of target nodes

Returns

  • DiGraph: Validated directed acyclic graph

Examples

using CausalDynamics

# From edge list: Z → X, Z → Y, X → Y
edges = [(1, 2), (1, 3), (2, 3)]
g = create_causal_graph(edges)

# From dictionary (same graph)
edge_dict = Dict(
    1 => [2, 3],  # Z → X, Z → Y
    2 => [3]      # X → Y
)
g = create_causal_graph(edge_dict)

Throws

  • ArgumentError: If the resulting graph is not a DAG (contains cycles)

Notes

  • Automatically determines number of nodes from edge specifications
  • Validates that graph is acyclic before returning
  • Node indices start at 1

See Also

  • validate_causal_graph: Validate that a graph is a DAG
  • is_dag: Check if a graph is acyclic
source

CausalGraph metadata

Optional property bag and attached data on a causal graph wrapper.

CausalDynamics.CausalGraph — Type
CausalGraph

Directed graph with optional node / edge / graph properties (names, attached data).

Wraps DiGraph and delegates Graphs.jl operations. Prefer SimpleDiGraph for identification when you do not need properties; use CausalGraph when integrating with TMLE / PPL façades that attach metadata.

Fields

  • graph::DiGraph
  • node_props::Dict{Int, Dict{Symbol, Any}}
  • edge_props::Dict{Tuple{Int, Int}, Dict{Symbol, Any}}
  • graph_props::Dict{Symbol, Any}

See also: set_node_prop!, get_node_prop, attach_data!.

source
CausalDynamics.attach_data! — Function
attach_data!(g, data; node_names=nothing, check_columns=true)

Attach data to a causal graph with optional column name checking.

Designed for integration with statistical estimation packages:

  • TMLE.jl: Uses DataFrames with named columns
  • Turing.jl: Uses DataFrames or NamedTuples
  • RxInfer.jl: Uses various table formats

Arguments

  • g::CausalGraph: The causal graph
  • data: Data to attach (DataFrame, NamedTuple, or other table format)
  • node_names::Union{Dict{Int, Symbol}, Nothing}: Optional mapping from node indices to column names. If not provided, uses get_node_names(g).
  • check_columns::Bool: If true, verify that data columns match node names (default: true)

Returns

  • CausalGraph: The graph with data attached (for method chaining)

Notes

  • Data is stored in graph property :data
  • Node names are used to map graph nodes to data columns
  • Column checking ensures data columns match expected node names
  • Compatible with probabilistic programming packages (Turing, RxInfer)

See Also

  • get_data: Get attached data
  • has_data: Check if data is attached
  • get_node_names: Get node names
source
CausalDynamics.get_data — Function
get_data(g)

Get the attached data from a causal graph.

Arguments

  • g::CausalGraph: The causal graph

Returns

  • Attached data (DataFrame, NamedTuple, or other), or nothing if no data attached

See Also

  • attach_data!: Attach data to graph
  • has_data: Check if data is attached
source
CausalDynamics.has_data — Function
has_data(g)

Check if data is attached to a causal graph.

Arguments

  • g::CausalGraph: The causal graph

Returns

  • Bool: true if data is attached, false otherwise

See Also

  • get_data: Get attached data
  • attach_data!: Attach data to graph
source
CausalDynamics.get_node_names — Function
get_node_names(g)

Get node names as a dictionary mapping node indices to symbols.

Arguments

  • g::CausalGraph: The causal graph

Returns

  • Dict{Int, Symbol}: Mapping from node indices to names, or empty dict if no names set

See Also

  • set_node_prop!: Set node name
  • get_node_name: Get name for single node
source
CausalDynamics.get_node_name — Function
get_node_name(g, node, default=nothing)

Get the name for a specific node.

Arguments

  • g::CausalGraph: The causal graph
  • node::Int: Node index
  • default: Default value if name not set (default: nothing)

Returns

  • Symbol: Node name, or default if not set

See Also

  • get_node_names: Get all node names
  • set_node_prop!: Set node name
source
CausalDynamics.get_prop — Function
get_prop(g, key, default=nothing)

Get a graph-level property.

Arguments

  • g::CausalGraph: The causal graph
  • key::Symbol: Property key
  • default: Default value if property doesn't exist (default: nothing)

Returns

  • Property value, or default if not found

See Also

  • set_prop!: Set graph-level property
  • has_prop: Check if property exists
source
CausalDynamics.set_prop! — Function
set_prop!(g, key, value)

Set a graph-level property.

Arguments

  • g::CausalGraph: The causal graph
  • key::Symbol: Property key
  • value: Property value (any type)

See Also

  • get_prop: Get graph-level property
  • has_prop: Check if property exists
source
CausalDynamics.has_prop — Function
has_prop(g, key)

Check if a graph-level property exists.

Arguments

  • g::CausalGraph: The causal graph
  • key::Symbol: Property key

Returns

  • Bool: true if property exists, false otherwise

See Also

  • set_prop!: Set graph-level property
  • get_prop: Get graph-level property
source
CausalDynamics.delete_prop! — Function
delete_prop!(g, key)

Delete a graph-level property.

Arguments

  • g::CausalGraph: The causal graph
  • key::Symbol: Property key to delete

Returns

  • CausalGraph: The graph (for method chaining)

See Also

  • set_prop!: Set graph-level property
  • get_prop: Get graph-level property
source
CausalDynamics.get_node_prop — Function
get_node_prop(g, node, key, default=nothing)

Get a property for a specific node.

Arguments

  • g::CausalGraph: The causal graph
  • node::Int: Node index
  • key::Symbol: Property key
  • default: Default value if property doesn't exist (default: nothing)

Returns

  • Property value, or default if not found

See Also

  • set_node_prop!: Set node property
  • has_node_prop: Check if node property exists
source
CausalDynamics.set_node_prop! — Function
set_node_prop!(g, node, key, value)

Set a property for a specific node.

Arguments

  • g::CausalGraph: The causal graph
  • node::Int: Node index
  • key::Symbol: Property key
  • value: Property value (any type)

Throws

  • ArgumentError: If node index is out of range

See Also

  • get_node_prop: Get node property
  • has_node_prop: Check if node property exists
  • delete_node_prop!: Delete node property
source
CausalDynamics.has_node_prop — Function
has_node_prop(g, node, key)

Check if a property exists for a specific node.

Arguments

  • g::CausalGraph: The causal graph
  • node::Int: Node index
  • key::Symbol: Property key

Returns

  • Bool: true if property exists, false otherwise

See Also

  • set_node_prop!: Set node property
  • get_node_prop: Get node property
source
CausalDynamics.delete_node_prop! — Function
delete_node_prop!(g, node, key)

Delete a property for a specific node.

Arguments

  • g::CausalGraph: The causal graph
  • node::Int: Node index
  • key::Symbol: Property key to delete

Returns

  • CausalGraph: The graph (for method chaining)

See Also

  • set_node_prop!: Set node property
  • get_node_prop: Get node property
source
CausalDynamics.get_edge_prop — Function
get_edge_prop(g, src, dst, key, default=nothing)

Get a property for a specific edge.

Arguments

  • g::CausalGraph: The causal graph
  • src::Int: Source node index
  • dst::Int: Destination node index
  • key::Symbol: Property key
  • default: Default value if property doesn't exist (default: nothing)

Returns

  • Property value, or default if not found

See Also

  • set_edge_prop!: Set edge property
  • has_edge_prop: Check if edge property exists
source
CausalDynamics.set_edge_prop! — Function
set_edge_prop!(g, src, dst, key, value)

Set a property for a specific edge.

Arguments

  • g::CausalGraph: The causal graph
  • src::Int: Source node index
  • dst::Int: Destination node index
  • key::Symbol: Property key
  • value: Property value (any type)

Throws

  • ArgumentError: If edge doesn't exist in the graph

See Also

  • get_edge_prop: Get edge property
  • has_edge_prop: Check if edge property exists
  • delete_edge_prop!: Delete edge property
source
CausalDynamics.has_edge_prop — Function
has_edge_prop(g, src, dst, key)

Check if a property exists for a specific edge.

Arguments

  • g::CausalGraph: The causal graph
  • src::Int: Source node index
  • dst::Int: Destination node index
  • key::Symbol: Property key

Returns

  • Bool: true if property exists, false otherwise

See Also

  • set_edge_prop!: Set edge property
  • get_edge_prop: Get edge property
source
CausalDynamics.delete_edge_prop! — Function
delete_edge_prop!(g, src, dst, key)

Delete a property for a specific edge.

Arguments

  • g::CausalGraph: The causal graph
  • src::Int: Source node index
  • dst::Int: Destination node index
  • key::Symbol: Property key to delete

Returns

  • CausalGraph: The graph (for method chaining)

See Also

  • set_edge_prop!: Set edge property
  • get_edge_prop: Get edge property
source

Hypergraphs

Higher-order edges are experimental and not exported. Qualify as CausalDynamics.Hypergraph, CausalDynamics.add_hyperedge!, and related helpers. They are outside the identify / GraphSCM / CDM path.