feat: Horn parallel analysis for component retention (paran oracle) - #224
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds Horn (1965) / Glorfeld (1995) parallel analysis for PCA component retention to mlsirm-core, exposes it via the PyO3 extension and a thin Python validation/marshaling wrapper, and adds Rust + Python fixture-based tests plus changelog documentation.
Changes:
- Implement
mlsirm_core::parallel::parallel_analysis(correlation → Jacobi eigenvalues → paran-style bias/adjustment → retention scan). - Add Python API
fast_mlsirm.parallel_analysis(...) -> ParallelAnalysisResultbacked by the compiled Rust core and re-export it fromfast_mlsirm. - Add deterministic fixtures and degenerate-input rejection tests in both Rust and Python; document the feature in
CHANGELOG.md.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
crates/mlsirm-core/src/parallel.rs |
New Rust implementation of Horn/Glorfeld parallel analysis (PCA path) with deterministic RNG and input guards. |
crates/mlsirm-core/src/lib.rs |
Exposes the new parallel module. |
crates/fast-mlsirm-py/src/lib.rs |
Adds PyO3 binding for parallel_analysis and registers it in the extension module. |
python/fast_mlsirm/parallel_analysis.py |
New Python wrapper: validates inputs, calls the Rust core, returns a dataclass result. |
python/fast_mlsirm/__init__.py |
Re-exports the new API (but currently drops ClassificationResult and omits ParallelAnalysisResult from __all__). |
tests/unit/parallel_tests.rs |
New Rust unit tests with pinned NumPy-derived fixtures, mutation anchors, and regression cases. |
tests/test_paper_features.py |
New Python-level parity/guard tests through the wrapper/binding. |
CHANGELOG.md |
Documents the new parallel analysis feature and its deliberate divergences from the R oracle. |
Comments suppressed due to low confidence (1)
python/fast_mlsirm/init.py:178
ParallelAnalysisResultis imported and part of the public surface, but it isn't included in__all__alongside other*Resultexports. This makesfrom fast_mlsirm import *omit the new result type and is inconsistent with existing exports likeDetectResult/ClassificationResult.
"rudner_classification",
"lee_classification",
"parallel_analysis",
"ClassificationResult",
"DetectResult",
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot Fix the code for all comments in this review thread. When a review comment includes a suggested change, apply the suggestion exactly. Do not make changes beyond what is described in the linked review thread. |
Both issues fixed in commit
|
7ef3bd5 to
4e47e5a
Compare
603c583 to
1dbe283
Compare
4e47e5a to
fb50514
Compare
1dbe283 to
d4c5c73
Compare
fb50514 to
eee3e09
Compare
d4c5c73 to
636027c
Compare
ab8dc8a to
090a2df
Compare
Rebased onto main after #223 squash merge; keeps only parallel-analysis feature files. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
636027c to
f70f44d
Compare
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rebased onto main after #224 squash merge; keeps only reliability feature files. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rebased onto main after #224 squash merge; include shared parallel helpers required by reliability. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Iteration 7 of the autonomous paper-implementation loop. Stacked on #223 (base
seonghobae-classification-accuracy).Horn (1965) parallel analysis — Glorfeld (1995) centile variant
Oracle: Dinno's CRAN paran 1.5.6 R sources, read line by line (Horn 1965 and Glorfeld 1995 themselves are paywalled; cited as-implemented-by/as-cited-in paran — divergences documented in the module docs).
Contract (PCA path only): eigenvalues of the observed Pearson correlation matrix (cyclic Jacobi, Err on non-convergence) adjusted by sampling bias
random_eigenvalue - 1fromn_iterationsstandard-normal same-shape datasets (single deterministic LCG stream);centile=0= mean benchmark,1..=99= R type-7 quantile; retention = paran's left-to-right scan stopping at firstadjusted <= 1(resurgence does not count).Deliberate divergences (module docs): PCA only (paran
cfa/ginv path out of scope); single crate-LCG stream — paran-inspired, not bit-identical to any R run (paran.R line 35 references loop varkbefore definition, so the oracle does not faithfully implement its own seeding claim either); narrowed guards; wrapper supplies paran's30 * n_itemsdefault.Evidence
n_iterations * n_items), 1 MINOR (wrapper ValueError for negative scalars)