How we got toSPARC-fast
SPARC-fast is the third version of our causal discovery engine in fourteen months. This is how we got there: the score CausalACO had to lose, the model we chose not to train, and how SPARC-fast won the speed back.
- versions of the engine in fourteen months, on one 69-dataset benchmark
- 3
- skeleton F1, from 0.552 for CausalACO to 0.740
- +34%
- directed error, down from 155.9 for CausalACO
- 51.8
- on the largest datasets, after SPARC's 30 minutes
- 48 s
Last week we published the results for SPARC-fast, our production causal discovery engine. On 69 ground-truth datasets it recovers more true structure than any method we compared it with, and at scale it finishes in under a minute. SPARC-fast is the third version of our discovery engine in fourteen months, and this post covers the two versions before it and one approach we decided not to build. Every version was measured on the same 69-dataset benchmark, and each replaced the one before because of what that benchmark showed.
Three versions on one benchmark#
Across the three versions, skeleton F1 (higher is better) rose from 0.552 to 0.740, and directed structural error (lower is better) fell from 155.9 to 51.8, a drop of about two-thirds (Figure 1). Runtime on the largest datasets took a different path: 46 seconds for CausalACO, about thirty minutes for SPARC and 48 seconds for SPARC-fast (Figure 2).
Figure 1 · Three versions · all 69 datasets
Skeleton F1 up 34%, directed error down by two-thirds
Skeleton F1 rose from 0.552 to 0.674 to 0.740 across the three versions, up 34%.
Skeleton F1 asks: did it find the right cause-and-effect links at all, whichever way the arrows point?
Figure 2 · Runtime · largest datasets
SPARC bought accuracy with speed, and SPARC-fast won the speed back
CausalACO took 46 seconds. Dropping the global score made SPARC more accurate and about 40 times slower, at about 30 minutes. SPARC-fast brought it back to 48 seconds.
CausalACO: a fast search over the wrong objective#
CausalACO, finished in March 2025, searched the space of graphs with ant colony optimization. Conditional independence tests supplied the evidence, and a fitness function over complete graphs decided which candidates the colony moved toward.
A standard algorithm treats a test as a verdict on one edge. CausalACO treated a test as evidence about a pathway. Take three variables where A and C are dependent but become independent once you condition on B. That is the signature of mediation, A → B → C. Read as a verdict, the result removes the edge between A and C. Read as evidence, the same result supports A → B and B → C, counts against a direct A → C because the chain already explains the association, and changes how plausible every other edge touching B looks (Figure 3). Confounding and collider bias have their own signatures, and each updates the pathway it belongs to. We called this the path heuristic.
Because one informative test moved many hypotheses at once, the search converged in fewer iterations. Because an edge that belonged to a coherent explanation counted for more than an edge with the same test statistic and nothing around it, the search was more robust to any single noisy test. With the heuristic switched off, the engine needed substantially more iterations and finished further from the true graph, and the gap was widest on dense graphs, where the space of candidate structures is largest.
CausalACO was also fast, because it read the data only once. Standard libraries such as pcalg and causal-learn return to the raw data for every independence test they run, so their cost is the size of the search multiplied by the size of the data. CausalACO read the data once, up front, to build an index of the statistics its tests needed, and then ran the entire search against that index.
The index was a hierarchy of tests in increasing order of cost. Distance correlation1, which detects nonlinear dependence and makes no assumption about the distribution, screened every pair, and pairs with negligible dependence were dropped before anything expensive ran. The survivors went to partial distance correlation2, computed with rank-one updates so that each additional conditioning variable cost a fraction of a full recomputation. Checks for cycles ran against statistics that were updated incrementally as edges were added, so adding an edge cost about the same however dense the graph had become.
Profiling across dataset sizes N and variable counts V gave two separate power laws:
Tindex ≈ 2.41 × 10−7 · V2.15 N1.15
Tsearch ≈ 7.07 × 10−4 · V1.90 N0.05
Building the index grows slightly faster than linearly in rows and slightly faster than quadratically in variables. The search barely depends on rows: with an exponent of 0.05, a hundredfold increase in data makes it about 26% slower (Figure 4). Once the index exists, the cost of exploring graph space is set by the number of variables, and grows a little slower than their square. The staged screening in SPARC and SPARC-fast, cheap tests across everything and expensive tests only on survivors, descends from this index.
Figure 4 · CausalACO scaling · fitted exponents
Building the index grows with the data; the search barely notices it
At ten times the rows, building the index costs about 14 times as much; the search costs about 12% more.
On the largest datasets CausalACO took 46 seconds where the classical baselines took 10 to 14 hours, and it completed all 69 datasets when several baselines could not. It reliably found high-scoring graphs. It also stopped at 0.552 skeleton F1, and every improvement we made to the search reached that same number faster. The graphs it returned were the best available under the fitness function, and the fitness function was wrong often enough that the best graph under it was frequently not the true one. We spent months treating that as a search problem before accepting that it was a problem with the score.
Score-based methods such as greedy equivalence search (GES)3 and hill climbing typically use a likelihood minus a penalty for complexity. Choosing a score commits you to a family of relationships: linear with Gaussian noise, additive with a particular error term, or multinomial with a Dirichlet prior. Figure 5 switches between them. Inside that family, the highest-scoring graph tends to be the true graph. Outside it, the score's maximum sits somewhere else, and a better search finds that wrong answer more reliably.
GES has a well-known guarantee: given faithfulness and unlimited data, it finds the true graph, but only if the score correctly describes the process that produced the data. You never have unlimited data, and on real tables the score rarely describes the process.
It follows that no single score will find the true graph across every kind of data, so looking for one is a poor use of research time. What you can do is raise a score's number on a particular benchmark by tuning it to that benchmark. We did, and the gain disappeared on the next class of problem. In early 2026 we stopped tuning the score. That left two ways forward: train a model to learn the assumptions from a corpus, or choose them from the data in front of us.
Could we have trained a model instead?#
There is no ImageNet for causality. Training a model to output causal graphs, known as amortized causal discovery, needs a large corpus of datasets whose true graphs are known, and for real systems those barely exist. The protein-signaling network from Sachs et al.4 is close to the only real-world graph in wide use, and expert-drawn networks such as alarm and munin cover a handful of domains. Everything else in every published benchmark, ours included, is synthetic. So the training corpus has to be generated, and a model trained on generated data learns the habits of the generator.
The idea is to learn the mapping from data to graph instead of specifying it: train a model on many datasets with known graphs, have it output structure directly, and pay the cost once at training time. The literature is substantial, from kernel-embedding classifiers5 through equivariant architectures6, time-series variants7, ENCO8, AVICI9 and the CSIvA transformer10, to recent work extending it from structure to mechanisms. It is sometimes pitched as a foundation model for causal discovery, and the appeal is real: inference is fast, the architecture is familiar, and nobody has to state an assumption.
The authors of AVICI name the central challenge themselves: generalizing out of distribution, because no simulated distribution is likely to cover the shifts real data presents. Montagna et al.11 tested this across roughly a million runs and found that the training data acts as a hidden prior on the test data. A trained network identifies the class of models it saw in training, and does well when the test data falls inside that class. On mechanisms it had not seen, its structural error approaches that of a coin flip, and a network trained on a family that is not identifiable in the first place stays at a coin flip everywhere. They also point out that out-of-distribution tests of this kind are largely missing from the earlier literature, which is part of why the approach can look more general than it is. The assumption has not gone away; it has moved into the choice of training data.
We measured the same thing. We reproduced the first- and third-place solutions from the 2024 ADIA Lab Causal Discovery Challenge12, trained both on the 23,500-graph ADIA corpus, and ran them unchanged on our benchmark (Figure 6).
Figure 6 · The supervised route · balanced accuracy, role task
Both challenge winners fall to 0.26 on our benchmark
On a held-out split of their own corpus the reproductions score 0.69 (1st) and 0.60 (3rd). On our benchmark both fall to 0.26.
On held-out data from their own corpus they scored 0.69 and 0.60 balanced accuracy on the challenge's task of classifying each variable's role relative to a treatment and an outcome. On our benchmark both fell to 0.26. The launch post scored the same models on recovering links, on the 40 small datasets they can run on, and found about 0.65 skeleton F1 with roughly twice SPARC-fast's directed error. They recover a reasonable skeleton and get the directions and roles wrong, because the corpus taught them a shape rather than a mechanism. Retrained on our benchmark they would score higher on it, and that would measure the same thing the drop to 0.26 already shows: how closely a model's training corpus matches the data it is given.
The natural response is that this is a data problem, and data problems are solved with more data. That is what happened with language. It does not carry over, for two reasons.
Language models train on the distribution they are deployed on. Internet text comes from the same process that produces the prompts, so coverage is a matter of volume, and the volume existed. Causal discovery would need observational data with verified structure, and verifying structure means intervening on the system, so that data is scarce by nature.
Even with unlimited generated data, you have to know what you are covering. For language, the taxonomy is mature enough for coverage to mean something: topics, languages, formats, registers. For causal discovery, coverage has to span the combinations of mechanism, noise distribution, confounding structure and sampling regime, and those cannot be listed. Montagna et al. find that mixing mechanism types in training helps a great deal, because there are only a few families of mechanism and you can name them. Noise is different: they note that covering every possible noise distribution in training data is practically impossible, because the space is effectively infinite. Identifiability depends on how the two interact, so a corpus can be enormous and still leave the dataset in front of you outside it (Figure 7).
Language models have the same out-of-distribution problem, with two differences. It happens far more often here, because enterprise tables are not drawn from anyone's simulator. And nothing in the output tells you it has happened: a wrong graph comes back with the same confidence as a right one. A stated assumption can be checked against the data in front of you, and you can decline to trust the result when the check fails. A learned prior gives you no way to tell which edges came from the data and which came from the generator (Figure 8).
SPARC: choosing the test per relationship#
We chose the second. SPARC, released in March 2026, chooses its assumptions per relationship instead of committing to one set for the whole table. Before it tests whether two variables are connected, it works out what kind of relationship it is looking at and picks a test suited to that kind. Cheap, safe statistics run across every pair first, the expensive tests run only on pairs that survive, and the assumptions that remain are local and checkable.
The reason is a result from Shah and Peters13. They proved that conditional independence cannot be tested in general: a test that stays valid across every distribution where the null holds has no power against any alternative. Every usable test gets its power by restricting the kinds of data it will be right about, so choosing a test requires knowing something about the problem. The result is stated for tests, and the same applies to scores. The space of possible relationships between variables is infinite-dimensional, reparameterizing it does not make it smaller, and only an assumption shrinks it to something a fixed criterion can search. No fixed test or score is right for every kind of data, so something has to choose. We decided the choosing should be automated, and done per relationship.
A theorem about the general case does not say how much this matters on real data, so we checked it on our benchmark. GES uses a single Bayesian-Dirichlet score, which describes categorical data well. On the 22 discrete datasets GES reaches 0.869 skeleton F1, ahead of SPARC-fast's 0.792. On continuous data it drops to 0.616, and on mixed-type data to 0.549 (Figure 9). The algorithm is the same on all three; only the match between its score and the data changes.
Figure 9 · GES by data type · skeleton F1
The same GES scores 0.869 where its score fits the data and 0.549 where it does not
GES reaches 0.869 on discrete data, which its score describes well, and drops to 0.616 on continuous and 0.549 on mixed-type data.
Dropping the global score took skeleton F1 from 0.552 to 0.674 in one version. It also made the engine much slower: SPARC took about thirty minutes on the largest datasets, against CausalACO's 46 seconds.
SPARC-fast: getting the speed back#
SPARC-fast, released in May 2026, keeps SPARC's approach and recovers the speed. It uses functional-form detection to shrink the search space, runs its core in parallel across CPU cores or a GPU, and uses randomized low-rank approximations for the most expensive tests. On the largest datasets it takes 48 seconds, level with CausalACO, and it raises skeleton F1 to 0.740. The launch post covers how it works.
What comes next#
Our current work is on the screening stages. Our ablations show that once the skeleton is correct, orienting the edges is close to solved on this suite, so the remaining gap is in finding the right links in the first place. We will write about that, and about the conditional independence tests underneath it, in future posts.
References#
- 1Székely, G. J., Rizzo, M. L. and Bakirov, N. K. (2007). Measuring and testing dependence by correlation of distances. Annals of Statistics, 35(6), 2769–2794.↩︎ Back
- 2Székely, G. J. and Rizzo, M. L. (2014). Partial distance correlation with methods for dissimilarities. Annals of Statistics, 42(6), 2382–2412.↩︎ Back
- 3Chickering, D. M. (2002). Optimal structure identification with greedy search. Journal of Machine Learning Research, 3, 507–554. jmlr.org↩︎ Back
- 4Sachs, K., Perez, O., Pe’er, D., Lauffenburger, D. A. and Nolan, G. P. (2005). Causal protein-signaling networks derived from multiparameter single-cell data. Science, 308(5721), 523–529. doi.org/10.1126/science.1105809↩︎ Back
- 5Lopez-Paz, D., Muandet, K., Schölkopf, B. and Tolstikhin, I. (2015). Towards a learning theory of cause-effect inference. ICML.↩︎ Back
- 6Li, H., Xiao, Q. and Tian, J. (2020). Supervised whole DAG causal discovery. arXiv:2006.04697↩︎ Back
- 7Lowe, S., Madras, D., Zemel, R. and Welling, M. (2020). Amortized causal discovery: learning to infer causal graphs from time-series data. CLeaR.↩︎ Back
- 8Lippe, P., Cohen, T. and Gavves, E. (2022). Efficient neural causal discovery without acyclicity constraints. ICLR.↩︎ Back
- 9Lorch, L., Sussex, S., Rothfuss, J., Krause, A. and Schölkopf, B. (2022). Amortized inference for causal structure learning. NeurIPS.↩︎ Back
- 10Ke, N. R. et al. (2023). Learning to induce causal structure. ICLR.↩︎ Back
- 11Montagna, F., Cairney-Leeming, M., Sridhar, D. and Locatello, F. (2024). Demystifying amortized causal discovery with transformers. Transactions on Machine Learning Research. arXiv:2405.16924↩︎ Back
- 12ADIA Lab Causal Discovery Challenge (2024), hosted by CrunchDAO. hub.crunchdao.com↩︎ Back
- 13Shah, R. D. and Peters, J. (2018). The hardness of conditional independence testing and the generalised covariance measure. arXiv:1804.07203↩︎ Back