mixle.experimental.active_causal module¶
P15 (experimental) – active causal discovery: buying the interventions that matter.
A chain X0->X1->X2, the reverse X2->X1->X0, and the fork X0<-X1->X2 share the skeleton
0-1-2 (one Markov equivalence class). They are parameterized as factorizations of the same
observational joint Gaussian, so observation cannot orient them.
Interventions break the tie decisively – do(X1) moves X2 under the chain, X0 under the
reverse, and both under the fork. This module chooses which intervention to run by expected
information gain (EIG) over a posterior on candidate causal structures, and identifies the true
structure with fewer experiments than random or observation-only selection.
Everything is exact linear-Gaussian, so the structure likelihood is closed form and the synthetic ground truth is known – active causal discovery can be graded exactly, which the field mostly cannot do.
Exploratory mixle.experimental code (P15 card).
- class LinearGaussianSCM(name, n_nodes, parents, weight=0.9, noise=1.0, edge_weights=None, noise_scales=None)[source]
Bases:
objectA linear-Gaussian structural causal model over
n_nodesvariables.parents[j]lists nodej’s parents; each contributesweighttoj’s mean. Nodes with no parents are exogenousN(0, noise^2).- Parameters:
- log_likelihood(x, intervention=None)[source]
Total log-density of rows
xunder this SCM given the intervention regime.
- class StructurePosterior(candidates, log_w=None)[source]
Bases:
objectPosterior over a fixed list of candidate SCMs, updated by experiment likelihoods.
- expected_information_gain(posterior, regime, *, n_batch, rng, n_outcomes=6)[source]
EIG of running
regimeonce: current entropy minus the expected posterior entropy.Outcomes are simulated from each candidate weighted by the current posterior (the posterior-predictive), so no ground truth leaks into the design.
- default_regimes(n_nodes, value=2.0)[source]
Observation plus
do(node = value)for each node.
- class DiscoveryResult(identified: 'int', correct: 'bool', n_experiments: 'int', final_probs: 'list[float]')[source]
Bases:
object
- active_discovery(true_scm, candidates, *, strategy='eig', n_batch=8, threshold=0.95, max_experiments=40, seed=0, value=2.0)[source]
Run the act-observe-update loop until the posterior concentrates or the budget runs out.
strategy="eig"picks the max-EIG regime each step;"random"picks uniformly;"obs"only ever observes. Returns which structure was identified and how many experiments it took.