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 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
CausalGraph metadata
Optional property bag and attached data on a causal graph wrapper.
CausalDynamics.CausalGraph — Type
CausalGraphDirected 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::DiGraphnode_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!.
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 graphdata: 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, usesget_node_names(g).check_columns::Bool: Iftrue, 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 datahas_data: Check if data is attachedget_node_names: Get node names
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
nothingif no data attached
See Also
attach_data!: Attach data to graphhas_data: Check if data is attached
CausalDynamics.has_data — Function
has_data(g)Check if data is attached to a causal graph.
Arguments
g::CausalGraph: The causal graph
Returns
Bool:trueif data is attached,falseotherwise
See Also
get_data: Get attached dataattach_data!: Attach data to graph
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 nameget_node_name: Get name for single node
CausalDynamics.get_node_name — Function
get_node_name(g, node, default=nothing)Get the name for a specific node.
Arguments
g::CausalGraph: The causal graphnode::Int: Node indexdefault: Default value if name not set (default:nothing)
Returns
Symbol: Node name, ordefaultif not set
See Also
get_node_names: Get all node namesset_node_prop!: Set node name
CausalDynamics.get_prop — Function
get_prop(g, key, default=nothing)Get a graph-level property.
Arguments
g::CausalGraph: The causal graphkey::Symbol: Property keydefault: Default value if property doesn't exist (default:nothing)
Returns
- Property value, or
defaultif not found
See Also
set_prop!: Set graph-level propertyhas_prop: Check if property exists
CausalDynamics.set_prop! — Function
set_prop!(g, key, value)Set a graph-level property.
Arguments
g::CausalGraph: The causal graphkey::Symbol: Property keyvalue: Property value (any type)
See Also
get_prop: Get graph-level propertyhas_prop: Check if property exists
CausalDynamics.has_prop — Function
has_prop(g, key)Check if a graph-level property exists.
Arguments
g::CausalGraph: The causal graphkey::Symbol: Property key
Returns
Bool:trueif property exists,falseotherwise
See Also
set_prop!: Set graph-level propertyget_prop: Get graph-level property
CausalDynamics.delete_prop! — Function
delete_prop!(g, key)Delete a graph-level property.
Arguments
g::CausalGraph: The causal graphkey::Symbol: Property key to delete
Returns
CausalGraph: The graph (for method chaining)
See Also
set_prop!: Set graph-level propertyget_prop: Get graph-level property
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 graphnode::Int: Node indexkey::Symbol: Property keydefault: Default value if property doesn't exist (default:nothing)
Returns
- Property value, or
defaultif not found
See Also
set_node_prop!: Set node propertyhas_node_prop: Check if node property exists
CausalDynamics.set_node_prop! — Function
set_node_prop!(g, node, key, value)Set a property for a specific node.
Arguments
g::CausalGraph: The causal graphnode::Int: Node indexkey::Symbol: Property keyvalue: Property value (any type)
Throws
ArgumentError: If node index is out of range
See Also
get_node_prop: Get node propertyhas_node_prop: Check if node property existsdelete_node_prop!: Delete node property
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 graphnode::Int: Node indexkey::Symbol: Property key
Returns
Bool:trueif property exists,falseotherwise
See Also
set_node_prop!: Set node propertyget_node_prop: Get node property
CausalDynamics.delete_node_prop! — Function
delete_node_prop!(g, node, key)Delete a property for a specific node.
Arguments
g::CausalGraph: The causal graphnode::Int: Node indexkey::Symbol: Property key to delete
Returns
CausalGraph: The graph (for method chaining)
See Also
set_node_prop!: Set node propertyget_node_prop: Get node property
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 graphsrc::Int: Source node indexdst::Int: Destination node indexkey::Symbol: Property keydefault: Default value if property doesn't exist (default:nothing)
Returns
- Property value, or
defaultif not found
See Also
set_edge_prop!: Set edge propertyhas_edge_prop: Check if edge property exists
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 graphsrc::Int: Source node indexdst::Int: Destination node indexkey::Symbol: Property keyvalue: Property value (any type)
Throws
ArgumentError: If edge doesn't exist in the graph
See Also
get_edge_prop: Get edge propertyhas_edge_prop: Check if edge property existsdelete_edge_prop!: Delete edge property
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 graphsrc::Int: Source node indexdst::Int: Destination node indexkey::Symbol: Property key
Returns
Bool:trueif property exists,falseotherwise
See Also
set_edge_prop!: Set edge propertyget_edge_prop: Get edge property
CausalDynamics.delete_edge_prop! — Function
delete_edge_prop!(g, src, dst, key)Delete a property for a specific edge.
Arguments
g::CausalGraph: The causal graphsrc::Int: Source node indexdst::Int: Destination node indexkey::Symbol: Property key to delete
Returns
CausalGraph: The graph (for method chaining)
See Also
set_edge_prop!: Set edge propertyget_edge_prop: Get edge property
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.