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.

CausalDynamics.d_separatedFunction
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 (SimonAB fork under CDCS packages/CausalInference.jl).

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_ancestorsFunction
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_descendantsFunction
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_parentsFunction
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_childrenFunction
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_boundaryFunction
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_pathsFunction
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_pathsFunction
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_pathFunction
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_dagFunction
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_graphFunction
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_graphFunction
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