CausalIQ Analysis Merge¶
This module provides functions for merging multiple graphs (DAG, PDAG, PDG) into a single Probabilistic Dependency Graph (PDG) with weighted edge probabilities.
Core Functions¶
merge_graphs
¶
merge_graphs(
graphs: List[Union[DAG, PDAG, PDG]],
weights: Optional[List[float]] = None,
cpdag: bool = False,
strategy: str = "average",
) -> PDG
Merge multiple graphs into a single PDG with edge probabilities.
Combines DAGs, PDAGs, and/or PDGs into a single probabilistic graph using the specified merge strategy.
Parameters:
-
(graphs¶List[Union[DAG, PDAG, PDG]]) –List of graphs to merge. Must all have identical node sets.
-
(weights¶Optional[List[float]], default:None) –Optional weights for each graph. Must sum to 1.0 if provided. If None, uniform weights (1/n) are used.
-
(cpdag¶bool, default:False) –If True, convert DAGs to their CPDAG (equivalence class) before merging.
-
(strategy¶str, default:'average') –Merge strategy. 'average' for weighted average of probability vectors (default). 'noisy_or' for noisy-OR existence with weighted orientation. 'max' to select the most confident source per edge.
Returns:
-
PDG–PDG with combined edge probabilities.
Raises:
-
TypeError–If graphs or weights have invalid types.
-
ValueError–If graphs list is empty, nodes differ, weights don't match graph count, weights don't sum to 1.0, or strategy is invalid.
Example
from causaliq_core.graph import DAG, PDAG dag1 = DAG(["A", "B"], [("A", "->", "B")]) dag2 = DAG(["A", "B"], [("B", "->", "A")]) pdg = merge_graphs([dag1, dag2]) probs = pdg.get_probabilities("A", "B") probs.forward # P(A -> B) 0.5
Merge multiple graphs into a single PDG with weighted average edge probabilities.
Overview¶
Graph Merging¶
The merge_graphs function combines multiple learned causal graphs into a
single Probabilistic Dependency Graph (PDG) that captures structural
uncertainty. This is useful when you have graphs from:
- Different random seeds
- Different sample sizes
- Different algorithms
- Bootstrap resampling experiments
- Heterogeneous sources (e.g., LLM priors and structure-learning results)
Merge Strategies¶
Three strategies control how edge probabilities are combined:
| Strategy | Description |
|---|---|
average |
Weighted average of probability vectors (default). Treats absence as evidence against existence. |
noisy_or |
Noisy-OR for existence + weighted orientation. An edge exists if any source supports it. Best for fusing heterogeneous sources. |
max |
Picks the most confident source per edge. Simple baseline. |
Input Graph Types¶
The function accepts any combination of:
| Type | Treatment |
|---|---|
| DAG | Edges treated as probability 1.0 for their direction |
| PDAG | Edges treated as probability 1.0 for their type |
| PDG | Edge probabilities used directly |
All input graphs must have identical node sets.
CPDAG Conversion¶
When cpdag=True, DAGs are converted to their CPDAG (Completed Partially
Directed Acyclic Graph) before merging. This averages over Markov
equivalence classes rather than specific DAG orientations, which is often
more appropriate for comparing structure learning results.
Weighting¶
By default, uniform weights (1/n) are applied. Custom weights can be provided to give different graphs more or less influence on the final result. Weights must:
- Have one value per input graph
- Sum to 1.0
- Be non-negative
Usage Examples¶
Basic Merging¶
from causaliq_analysis import merge_graphs
from causaliq_core.graph import DAG
# Create sample graphs from different experiments
dag1 = DAG(["A", "B", "C"], [("A", "->", "B"), ("B", "->", "C")])
dag2 = DAG(["A", "B", "C"], [("A", "->", "B"), ("C", "->", "B")])
dag3 = DAG(["A", "B", "C"], [("B", "->", "A"), ("B", "->", "C")])
# Merge with uniform weights
pdg = merge_graphs([dag1, dag2, dag3])
# Inspect edge probabilities
probs = pdg.get_probabilities("A", "B")
print(f"P(A → B): {probs.forward:.3f}")
print(f"P(B → A): {probs.backward:.3f}")
print(f"P(A — B): {probs.undirected:.3f}")
print(f"P(no edge): {probs.none:.3f}")
Custom Weights¶
# Weight first graph more heavily (e.g., larger sample size)
pdg = merge_graphs([dag1, dag2, dag3], weights=[0.5, 0.25, 0.25])
CPDAG Conversion¶
# Convert DAGs to CPDAGs before merging
# This averages over equivalence classes
pdg = merge_graphs([dag1, dag2, dag3], cpdag=True)
Merging PDGs¶
from causaliq_core.graph import PDG
# PDGs can be merged with DAGs/PDAGs
# Their edge probabilities are used directly
pdg_combined = merge_graphs([pdg1, dag1, pdag1])
Noisy-OR Strategy¶
# Noisy-OR: edges exist if any source supports them
# Orientation is a weighted blend from contributing sources
pdg = merge_graphs([dag1, dag2, dag3], strategy="noisy_or")
# With custom weights
pdg = merge_graphs(
[llm_graph, fges_graph],
weights=[0.6, 0.4],
strategy="noisy_or",
)
Max Strategy¶
See Also¶
- Graph Merging User Guide — Detailed usage including CLI and workflow action
- Summarisation Paradigm — Architecture for aggregation operations