Skip to content

feat: Horn parallel analysis for component retention (paran oracle) - #224

Merged
seonghobae merged 2 commits into
mainfrom
seonghobae-parallel-analysis
Jul 25, 2026
Merged

seonghobae merged 2 commits into
mainfrom
seonghobae-parallel-analysis

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

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 - 1 from n_iterations standard-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 first adjusted <= 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 var k before definition, so the oracle does not faithfully implement its own seeding claim either); narrowed guards; wrapper supplies paran's 30 * n_items default.

Evidence

Check Result
Fixture parity vs independent NumPy replication (mirrors crate LCG with np.uint64) 1e-9, first run
Mutation spot-checks 5/5 killed & restored (uncentered corr, no-interpolation quantile, bias w/o −1, count-vs-scan, no sort)
500-rep Monte Carlo (#[ignore], 2-factor n=200 p=10) 100% retained==2 (threshold 90%)
Adversarial spec-verify GO-WITH-FIXES, 11 defects applied pre-implementation
Adversarial impl-review 2 MAJOR fixed + regressions (overflow-safe correlation guards, checked n_iterations * n_items), 1 MINOR (wrapper ValueError for negative scalars)
mlsirm-core suite 477 passed
Python wrapper tests 3 passed (fixture parity through binding, degenerate-input rejections, impl-review regressions)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(...) -> ParallelAnalysisResult backed by the compiled Rust core and re-export it from fast_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

  • ParallelAnalysisResult is imported and part of the public surface, but it isn't included in __all__ alongside other *Result exports. This makes from fast_mlsirm import * omit the new result type and is inconsistent with existing exports like DetectResult/ClassificationResult.
    "rudner_classification",
    "lee_classification",
    "parallel_analysis",
    "ClassificationResult",
    "DetectResult",

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread python/fast_mlsirm/__init__.py
Comment thread crates/mlsirm-core/src/parallel.rs
@seonghobae

Copy link
Copy Markdown
Contributor Author

@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.

Copilot AI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested ch...

Both issues fixed in commit fix: add ClassificationResult import and optimize parallel.rs mean-path memory:

  1. __init__.py — ClassificationResult added to the from .classification import (...) block so it is actually importable and consistent with __all__ (lines 45-49 now include it).

  2. parallel.rs — The centile == 0 (mean) path now uses a single-pass running-sum accumulator per item position, avoiding the O(n_iterations × n_items) intermediate sim buffer entirely. The quantile path (centile != 0) is unchanged and still stores the full buffer for sorting.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread crates/mlsirm-core/src/parallel.rs
Comment thread python/fast_mlsirm/__init__.py
Comment thread python/fast_mlsirm/parallel_analysis.py
@seonghobae
seonghobae force-pushed the seonghobae-classification-accuracy branch from 7ef3bd5 to 4e47e5a Compare July 25, 2026 09:29
@seonghobae
seonghobae force-pushed the seonghobae-parallel-analysis branch from 603c583 to 1dbe283 Compare July 25, 2026 09:29
@seonghobae
seonghobae force-pushed the seonghobae-classification-accuracy branch from 4e47e5a to fb50514 Compare July 25, 2026 10:03
@seonghobae
seonghobae force-pushed the seonghobae-parallel-analysis branch from 1dbe283 to d4c5c73 Compare July 25, 2026 10:04
@seonghobae
seonghobae force-pushed the seonghobae-classification-accuracy branch from fb50514 to eee3e09 Compare July 25, 2026 10:14
@seonghobae
seonghobae force-pushed the seonghobae-parallel-analysis branch from d4c5c73 to 636027c Compare July 25, 2026 10:14
@seonghobae
seonghobae force-pushed the seonghobae-classification-accuracy branch 2 times, most recently from ab8dc8a to 090a2df Compare July 25, 2026 10:29
Base automatically changed from seonghobae-classification-accuracy to main July 25, 2026 10:36
Rebased onto main after #223 squash merge; keeps only parallel-analysis feature files.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@seonghobae
seonghobae force-pushed the seonghobae-parallel-analysis branch from 636027c to f70f44d Compare July 25, 2026 10:45
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@seonghobae
seonghobae merged commit 50de0ad into main Jul 25, 2026
31 of 32 checks passed
@seonghobae
seonghobae deleted the seonghobae-parallel-analysis branch July 25, 2026 11:11
seonghobae added a commit that referenced this pull request Jul 25, 2026
Rebased onto main after #224 squash merge; keeps only reliability feature files.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
seonghobae added a commit that referenced this pull request Jul 25, 2026
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>
seonghobae added a commit that referenced this pull request Jul 25, 2026
…#225)

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>
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.

3 participants