--- name: 20261023-andrey-0-9-0 description: "Andrey 0.9.0, our biggest speed breakthrough: BOSS up to 8.1x faster, exact search 5.2x, and FCI 3.1x, with exactly the same graphs." meta: type: post blogpost: true date: 2026-10-23 author: Shu Wan tags: [Release, Speed] version: 0.9.0 cover: rocket --- # Acceleration Andrey was already the fastest causal discovery package. 0.9.0 is our biggest speed breakthrough yet, the fastest causal discovery we have ever shipped: BOSS runs up to 8.1x faster than before, exact search 5.2x, and FCI and GFCI 3.1x, and every graph is exactly the same. Every release so far added methods or data; this one is all speed. This post is the first of two. Here the rocket lifts off. The next release, 0.10.0, follows it up to the boundary: how far each method now goes before it stops finishing, or stops being accurate. ## TL;DR - The fastest Andrey ever. Speedups over 0.8.0, at the best of the sizes we measured: - Permutation-based: BOSS up to 8.1x, GRaSP 3.8x. - Score-based: exact search 5.2x, GES and XGES 1.7x. - Constraint-based: FCI and GFCI 3.1x, PC 1.8x, CD-NOD 1.6x. - LiNGAM, pairwise, and temporal: LPCMCI 2.8x, PNL 2.2x, DirectLiNGAM and MultiGroupDirectLiNGAM 1.9x. - Exactly the same answers: in all 1,216 identity checks, 27 methods in five column orders with one worker and four, 0.9.0 returns exactly 0.8.0's output. - PC, FCI, GFCI, and CD-NOD spread their largest skeleton passes over worker processes: with four workers, CD-NOD runs up to 4.6x faster than 0.8.0 and PC 2.6x. `andrey calibrate` measures when the workers pay off on your machine. ## Where the time went A causal discovery method spends its time on three jobs: tests or scores, the bookkeeping of the graph it searches, and the memory that holds them. The [Why Andrey is fast](20261008-why-andrey-is-fast.md) post shows the ideas we started from. 0.9.0 applies them further, without changing a single result. **Ask in stacks.** PC, FCI, GFCI, and CD-NOD test whether two variables are independent given a set of others. 0.9.0 hands the test all of a pair's conditioning sets at once, together with those of the pairs next to it, so one array operation answers what took many. Exact search does the same for its scores: it solves the equations of up to 4,096 parent sets in one call. **Use every core.** With more than one worker, the largest passes of the PC, FCI, GFCI, and CD-NOD skeleton search run in worker processes. Small passes stay in one process, where starting workers would cost more than it saves. `andrey calibrate` measures that cutoff on your machine. **Copy less.** A search tries many changes to its graph and keeps few. XGES now copies only the part of the graph a branch changes. After each move, GES updates only the edges the move can reach instead of rebuilding the whole graph, and keeps each reach set until a move can change it. BOSS and GRaSP keep one tuple of candidate parents, and the set of allowed parents, instead of building them again on every step. **Build once.** FCI computes one reach set per variable for its possible-d-separation step, and builds its neighbor lists and reach sets once for each version of the graph; GFCI builds each node's neighbor list once. LPCMCI keeps each node's neighbors and paths for each version of the graph instead of building them for every query. Exact search looks up each variable's best parent set in a table built once per fit. DirectLiNGAM and the methods built on it compute each pair's residual entropy once per step instead of twice. PNL builds each variable's kernel once and can run its independence tests on a CUDA GPU. **Hold less.** The first pass of PC, FCI, GFCI, and CD-NOD builds its queries one stack at a time instead of listing every pair's conditioning sets first, which on a complete graph of 1,000 variables held gigabytes. ANM and the KCI test build their kernels in blocks, in one reused matrix. ## An example The answer does not depend on how many workers you use. We fit GES on 200 variables with one worker and with four, and compare the graphs. ```{literalinclude} 0.9.0/example.py :language: python :caption: example.py ``` ```{literalinclude} 0.9.0/example-output.txt :language: text :caption: example.py ``` ## How much faster We timed each method in 0.9.0 against Andrey 0.8.0 on the same datasets, side by side on the same machine. ```{raw} html :file: 0.9.0/ranges.html ``` The gains grow with the problem: BOSS is 2.9x faster at 200 variables and 8.1x at 400, and GFCI 2.2x at 200 and 3.1x at 400, because the work we removed, copies and repeated bookkeeping, grows faster than the tests and scores themselves. Every one of these fits returned exactly 0.8.0's output. GES now also runs 1.6x to 5.4x faster than pcalg's, whose GES is written in C++, with the same or fewer errors at every size. The [0.9.0 release card](../docs/benchmarks/0.9.0.md) gives every size, the conditions, and the comparison with pcalg. ## Limits - **Measured speedups.** A speedup depends on the data, the settings, and the machine. Methods without speed work in 0.9.0 run as fast as in 0.8.0; the release card names them. - **Same answers.** In the identity checks, the LiNGAM methods return 0.8.0's output exactly. Their internal scores can differ in the last bits, which could change a causal order only at an exact tie between two candidates. With one worker, PNL lets its linear algebra use every core, so on a machine with several cores its result can differ in the last digits from that with several workers. - **Workers.** Worker processes repay their start-up cost only on large passes. On a small problem, one worker is as fast. ## Try it ```{code-block} shell :class: window pip install -U andrey-core ``` ## Help us build it Andrey is in alpha. The API may change between releases. When you try it on your own data, [tell us what breaks](https://github.com/Abel-ai-lab/andrey/issues/new) or which method you need. We also welcome pull requests. The [contributing guide](https://github.com/Abel-ai-lab/andrey/blob/main/CONTRIBUTING.md) explains how you can set up the development environment. --- - [Getting started](../docs/guides/getting-started.md) - [Configuration](../docs/configuration.md) - [Release cards](../docs/benchmarks.md) - [Changelog](../docs/changelog.md) - [GitHub](https://github.com/Abel-ai-lab/andrey)