Skip to content

Speed up Wobble peak search with a linear maximum filter - #4782

Open
JESUSROYETH wants to merge 1 commit into
SpikeInterface:mainfrom
JESUSROYETH:perf-wobble-linear-peak-search
Open

JESUSROYETH wants to merge 1 commit into
SpikeInterface:mainfrom
JESUSROYETH:perf-wobble-linear-peak-search

Conversation

@JESUSROYETH

Copy link
Copy Markdown
Contributor

Wobble calls argrelmax with order=num_samples - 1 during chunked matching. When candidates remain, SciPy rescans the objective for each offset. So this uses two directional maximum_filter1d passes while preserving strict maxima; arrays with NaN keep the original path.

Five measured alternating baseline/candidate pairs on generated recordings; the VM harness discarded one setup run:

Public path Fixture Result
Matching 384 channels, 192 templates 17.932 → 15.581 s (13.11%)
Cold Lupin sort 180 s, 64 channels, 20 units; Intel Cascade Lake VM 120.448 → 106.845 s (11.29%)

The baseline spent 14.76% of matching time in 308 argrelmax calls.

The matching pairs were stable (+11.01–14.45%) and returned the same 28,043 spikes byte for byte. The full-sort pairs were also stable (+10.48–13.11%).

Final-code validation: 700 differential cases; ten byte-identical fixed-template runs; 9 focused tests; the public Wobble test; and formatting. Diff: 88 additions, 5 deletions.

The cold-sort result is corroborating, not equal-workload, because clustering is non-deterministic. The 384-channel full sort remains unvalidated: both arms failed during clustering, before matching, with an unknown singular-matrix cause. No captured recording was benchmarked.

@yger

yger commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Looks great and promising ! Actually, the same argrelmax() should be also in place in circus.py for the OMP peeler, used in a similar manner. Maybe worth also optimizing to be consistent?

@JESUSROYETH

Copy link
Copy Markdown
Contributor Author

Thanks @yger, good point on consistency... checking circus.py, the OMP loop doesn't use argrelmax, the peak selection there is already linear with maximum_filter:

result = ndimage.maximum_filter(products[0], size=self.vicinity, mode="constant", cval=0)
cond_2 = np.abs(products[0] - result) < 1e-9

The only argrelmax call in src/ is the one in wobble.py.

One detail: the criteria are not the same. On a flat plateau Circus can keep several tied samples, while this helper keeps the strict argrelmax behaviour exactly, so reusing it in Circus would change its results. The idea would be to keep this PR only for Wobble, and if aligning both makes sense, do it in a separate PR. What do you think?

@yger

yger commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Ok my bad, I wasn't in front of a computer. I'll check the other matching engines, but yes, let's only change if they use argrelmax. I'll read everything more carefully later, thanks a lot !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants