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_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 (SimonAB fork under CDCS packages/CausalInference.jl).
Arguments
g: A directed acyclic graph (DiGraph)X: Source node or set of nodesY: Target node or set of nodesZ: Conditioning set (vector, set, or single node)
Returns
trueif X and Y are d-separated by Z,falseotherwise
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 graphnodes: 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}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 graphnodes: 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}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 graphnodes: 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}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 graphnodes: 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}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 graphY: 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}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 graphX: Source nodeY: Target nodemax_paths: Cap on enumerated paths (raises if exceeded)
Returns
- Vector of backdoor paths (each path is a vector of nodes)
CausalDynamics.find_directed_paths — Function
find_directed_paths(g, X, Y; max_paths=10_000)Find all directed paths from X to Y (forward edges only).
Prefer nodes_on_directed_paths or has_path when only membership / existence is needed — full enumeration is exponential on dense DAGs.
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.
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 graphsource::Int: Source nodetarget::Int: Target node
Returns
Bool:trueif a directed path exists,falseotherwise
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
falseif source == target (no self-loops) - Uses BFS reachability (not path enumeration)
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:trueif g is a DAG,falseotherwise
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) # falseNotes
- Uses topological sort to detect cycles
- Returns
falseif 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
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:trueif 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 ArgumentErrorNotes
- 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)
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) tuplesDict{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 DAGis_dag: Check if a graph is acyclic