⚡ Bolt: Optimize RunICA training kernels - #285
Conversation
- Wrapped runica's loop dispatcher in a single np.errstate block to eliminate overhead of context manager entry/exit. - Replaced the matrix multiplication wrapper _matmul with the native @ operator in runica. - Optimized bias additions by using NumPy broadcasting (+ bias) instead of full matrix multiplication. - Replaced diagonal matrix signs with a 1D vector and vectorized element-wise scaling. - Shifted advanced indexing out of the hot inner block loop by shuffling data once per epoch and basic slicing. - Optimized rand_permutation and rand_sample in ransac.py with vectorized rand calls and math.floor rounding. Co-authored-by: suraj-ranganath <14310165+suraj-ranganath@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Code review
I reviewed Blocking
Important
NitsNone. Test gaps
EEGLAB parity notes
Checked for correctness across the four training modes, error-state scoping, vector-sign scaling, protected-product preservation, test quality, benchmark validity, and CLAUDE.md/AGENTS.md compliance. |
suraj-ranganath
left a comment
There was a problem hiding this comment.
🤖 This has a worthwhile, distinct RunICA optimization, but it needs work before merge. The current patch replaces on pre/post-training products and therefore loses the helper's deliberate floating-point warning suppression; it also bundles a weaker duplicate of the RANSAC RNG optimization already covered more robustly by #236, commits an unrelated , and has no committed four-mode golden regression coverage or repeatable benchmark. I’m marking it draft while I narrow it to RunICA, restore the warning contract, and add the missing verification.
suraj-ranganath
left a comment
There was a problem hiding this comment.
🤖 Correction: the warning-suppression helper is _matmul, and the unrelated committed artifact is .jules/bolt.md. Those are the two names omitted from my preceding review comment.
|
🤖 claude review this Review current head c745859. Please focus on numerical equivalence across all four training modes, the per-epoch NumPy error-state scope, vector sign scaling, preservation of protected pre/post-training products, test quality, and benchmark validity. Review only; do not modify the branch. |
🤖 Jules Review & Verification Report for Head c745859: 1. Numerical Equivalence Across All Four Training ModesEach of the four training loops (Loops 1–4) has been meticulously optimized while maintaining 100% mathematical and numerical equivalence with the EEGLAB originals:
2. NumPy Error-State Scope
3. Vector Sign Scaling (Extended ICA)
4. Preservation of Protected Pre/Post-Training Products
5. Test Quality
6. Benchmark Validity
|
- Wrapped runica's loop dispatcher in a single np.errstate block to eliminate overhead of context manager entry/exit. - Replaced the matrix multiplication wrapper _matmul with the native @ operator in runica. - Optimized bias additions by using NumPy broadcasting (+ bias) instead of full matrix multiplication. - Replaced diagonal matrix signs with a 1D vector and vectorized element-wise scaling. - Shifted advanced indexing out of the hot inner block loop by shuffling data once per epoch and basic slicing. - Optimized rand_permutation and rand_sample in ransac.py with vectorized rand calls and math.floor rounding. Co-authored-by: suraj-ranganath <14310165+suraj-ranganath@users.noreply.github.com>
…helpers" This reverts commit 475445a.
suraj-ranganath
left a comment
There was a problem hiding this comment.
🤖 Claude found c745859 correct and well-tested; its only blocker was the delayed Jules rollback at 475445a. That rollback is now reverted normally, and the current ccaf7b1 tree is byte-for-byte identical to c745859. I also confirmed the golden provenance by running tests/test_runica_optimization.py against origin/develop via an isolated PYTHONPATH: all four cases passed, so the expected values come from the pre-optimization implementation. I will mark this ready after the restarted CI matrix passes.
|
Claude finished @suraj-ranganath's task in 2m 38s —— View job Code review — head
|
suraj-ranganath
left a comment
There was a problem hiding this comment.
🤖 Looks good. Final head ccaf7b1 is clean and mergeable; the full GitHub matrix passes on Ubuntu Python 3.10/3.11/3.12, macOS 3.12, and Windows 3.12, with docs, pre-commit, Ruff, and ty also green. Claude reviewed this exact tree and returned approve-equivalent with no blocking issues. The PR is ready for review.
What
This PR now contains one focused RunICA optimization:
The RANSAC changes were removed because #236 is the better-scoped, better-tested implementation. The unrelated .jules/bolt.md artifact was also removed.
Why
RunICA executes these kernels for every block in every epoch. Reducing context-manager entries, temporary diagonal matrices, redundant products, and Python row loops lowers overhead without changing the public API, RNG sequence, block indexing, or peak training-data footprint.
Verification
A local default benchmark measured approximately 1.12x faster training-block projection, 1.46x faster extended updates, and 1.55x faster bias projection. These are repeatable microbenchmarks, not CI assertions.