Skip to content

[v0.2.2] perm_entropy improvements; better doc/doctest#51

Merged
raphaelvallat merged 12 commits intomasterfrom
fast_perm_entropy
Apr 1, 2026
Merged

[v0.2.2] perm_entropy improvements; better doc/doctest#51
raphaelvallat merged 12 commits intomasterfrom
fast_perm_entropy

Conversation

@raphaelvallat
Copy link
Copy Markdown
Owner

@raphaelvallat raphaelvallat commented Mar 29, 2026

What's new

  • 2D support: perm_entropy now accepts arrays of shape (n_epochs, n_times) for order=3 and order=4, computing entropy for all epochs in one call instead of looping with np.apply_along_axis.
  • Major speed-up: 1.3–4.9× faster for 1D signals, 2–6× faster for 2D signals, compared to the previous implementation.
  • Deterministic results: the previous implementation used an unstable sort, giving platform-dependent results on signals with tied values. All code paths now use a stable sort, so results are identical across operating systems, NumPy versions, and hardware.
# Before: manual loop required
pe = np.array([ant.perm_entropy(epoch) for epoch in x])

# After: native 2D support
pe = ant.perm_entropy(x)  # x has shape (n_epochs, n_times)

How it works

For order=3 and order=4 (the two most common settings), argsort is replaced by a small lookup table indexed by pairwise comparisons between delayed columns. Pattern counts are accumulated in a single vectorised np.bincount call across all epochs simultaneously.

For order > 4, the existing argsort-based path is retained (1D only) with two minor improvements: a zero-copy window view (as_strided) and a BLAS @ product for hashing.

Note

Ties (exact duplicate values within a window) are broken by position across all inputs and all orders — earlier position ranks lower, matching stable argsort. This covers integer arrays, quantized float signals, zero-padded epochs, and any other signal with duplicate values.

Benchmarks

Three implementations are compared:

  • Original — previous antropy implementation (unstable sort, no 2D support)
  • General — improved fallback for order > 4 (stable sort, 1D only)
  • Fast path — new implementation for order=3/4 (stable, 1D and 2D)

1D — single time series

Order Length Fast path (µs) General (µs) Original (µs) Fast vs General Fast vs Original
3 1,000 26.4 35.6 46.7 1.3× 1.8×
3 5,000 50.6 123.4 189.2 2.4× 3.7×
3 10,000 98.9 241.3 356.2 2.4× 3.6×
4 1,000 28.0 43.2 56.6 1.5× 2.0×
4 5,000 55.4 159.1 238.7 2.9× 4.3×
4 10,000 91.5 307.5 447.5 3.4× 4.9×

2D — multi-epoch data (n_epochs × n_times)

Compared against np.apply_along_axis with the original implementation.

Order Epochs Length Fast path (ms) Original loop (ms) Speed-up
3 5 1,000 0.05 0.25 4.7×
3 5 10,000 0.38 1.82 4.8×
3 50 1,000 0.40 2.41 6.1×
3 50 10,000 5.63 19.61 3.5×
3 500 1,000 6.00 24.30 4.1×
3 500 10,000 60.93 211.76 3.5×
4 5 5,000 0.24 1.51 6.3×
4 50 5,000 2.97 13.58 4.6×
4 500 5,000 32.11 130.49 4.1×

Tests

  • test_perm_entropy_fast_path — fast path matches the reference within atol=1e-12 for order=3/4, across multiple delays and normalize settings.
  • test_perm_entropy_2d — 2D output matches apply_along_axis of the reference row-by-row.
  • test_perm_entropy_ties — signals with ties (integer arrays, float arrays, zero-padded, quantized) agree with a stable-sort reference for all orders and both dtypes.

perm_entropy now uses a lookup-table fast path for order=3/4 (2–6× faster for 1D, 3–7× for 2D) and accepts 2D arrays (n_epochs, n_times) for those orders, removing the need for apply_along_axis. The general
  path (order > 4) gains a zero-copy as_strided window view and a BLAS @ hash product (~1.4× faster). Integer-dtype signals get positional epsilon jitter to match argsort tie-breaking. Includes new tests
  (fast_path, 2d, ties), updated docstring with 2D examples, and a three-way benchmark script.
- Added deterministic results as a third bullet in "What's new", explaining that the previous unstable sort gave platform-dependent results on tied signals.
  - Updated the benchmark table descriptions to label the original as "unstable sort, no 2D support" and the new paths as "stable".
  - The [!NOTE] on ties now mentions "all inputs and all orders" to cover the general path change.
  - Updated test_perm_entropy_ties description to reflect it now covers float arrays and both dtypes.
  - Refreshed all benchmark numbers.
@raphaelvallat raphaelvallat changed the title Add fast path for perm_entropy + support for 2D arrays with order 3 or 4 perm_entropy: add support for 2D arrays with order 3 or 4; speed improvements; deterministic on signals with tied values Mar 29, 2026
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (ac5ec11) to head (d4e46ab).

Additional details and impacted files
@@            Coverage Diff            @@
##            master       #51   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         4           
  Lines          312       370   +58     
  Branches        52        62   +10     
=========================================
+ Hits           312       370   +58     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@raphaelvallat raphaelvallat added this to the v0.2.2 milestone Apr 1, 2026
@raphaelvallat raphaelvallat changed the title perm_entropy: add support for 2D arrays with order 3 or 4; speed improvements; deterministic on signals with tied values [v0.2.2] perm_entropy improvements; better doc/doctest Apr 1, 2026
@raphaelvallat raphaelvallat self-assigned this Apr 1, 2026
@raphaelvallat raphaelvallat merged commit dfbe688 into master Apr 1, 2026
18 checks passed
@raphaelvallat raphaelvallat deleted the fast_perm_entropy branch April 1, 2026 21:26
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