M4 — pls4all source split: EXTRACTION RECIPE¶
Status: scaffolded — 39 target stub files landed at their final paths.
The actual function-body extraction is deferred to a focused refactor
session because each cut must keep n4m_tests (265/265) green
between commits and the surgery is genuinely 4 days of careful work per
the roadmap budget. This document is the maintenance protocol that
guides that session.
Source plan: docs/merge/M4/SPLIT_PLAN.md (produced by the
Explore agent in parallel with M3).
Pre-flight per-extraction checklist¶
Before any single extraction commit:
n4m_testsis currently green (./build/dev-release/cpp/tests/n4m_testsreports265 run, 0 failures, 0 skipped).Work on the
merge/import-donorbranch.The pls4all CMakeLists at
cpp/src/CMakeLists.txtstill references the source monoliths (core/model.cpp,core/extra_pls.cpp).
Phase 1 — extract helpers FIRST (load-bearing)¶
The agent’s analysis flags four cross-cutting helper blocks that MUST be extracted before any algorithm files, because anonymous-namespace helpers cannot be called across translation units:
Helper block |
Lines in source |
Target file |
Linkage transition |
|---|---|---|---|
model.cpp anon-namespace (L18–L1524, ~1500 lines) — |
model.cpp:18-1524 |
|
anonymous → |
model.cpp PLS-shared helpers ( |
model.cpp:281-1524 selectively |
|
same |
extra_pls.cpp anon-namespace (L18–L306, ~290 lines) — |
extra_pls.cpp:18-306 |
|
same |
Critical: simple_simpls (extra_pls.cpp:97) is called by both
fit_pls_sparse_simpls (model.cpp) AND extra_pls sparse variants. It
MUST be extracted to a shared location accessible to both — the
recommended location is models/pls/_common.{cpp,hpp} (since SIMPLS is
canonically PLS-side).
Phase 1 commit pattern¶
M4 phase 1: extract models/core/_common — N anonymous-namespace helpers
- cpp/src/core/models/core/_common.cpp (+~300 lines)
- cpp/src/core/models/core/_common.hpp (+~80 lines, declarations)
- cpp/src/core/model.cpp (−~300 lines, replaced by include of _common.hpp)
- cpp/src/CMakeLists.txt (+1 entry: core/models/core/_common.cpp)
- Verify: n4m_tests 265/265 still green
Repeat for pls/_common and sparse/_common. After Phase 1 (3
commits), 50 % of model.cpp’s bulk is extracted but no functional
change.
Phase 2 — core PLS solvers (8 commits)¶
In topological order (dependencies first):
Order |
Function |
Source lines |
Target |
Helper deps |
|---|---|---|---|---|
1 |
|
model.cpp:1819-1838 |
|
|
2 |
|
model.cpp:1528-1818 |
|
|
3 |
|
model.cpp:3685-3884 |
|
|
4 |
|
model.cpp:2895-3060 |
|
|
5 |
|
model.cpp:1839-1999 |
|
|
6 |
|
model.cpp:3061-3226 |
|
|
7 |
|
model.cpp:3227-3396 |
|
|
8 |
|
model.cpp:2615-2894 |
|
|
9 |
|
model.cpp:2350-2614 |
|
|
Phase 3 — derived (2 commits)¶
# |
Function |
Source lines |
Target |
|---|---|---|---|
1 |
|
model.cpp:3397-3684 |
|
2 |
|
model.cpp:2000-2349 |
|
Phase 4 — classification (3 commits)¶
# |
Function |
Source lines |
Target |
|---|---|---|---|
1 |
|
model.cpp:3921-4162 |
|
2 |
|
extra_pls.cpp:847-944 |
|
3 |
|
extra_pls.cpp:945-1029 |
|
Phase 5 — sparse (4 commits)¶
# |
Function |
Source lines |
Target |
|---|---|---|---|
1 |
|
model.cpp:4163-4387 |
|
2 |
|
extra_pls.cpp:307-366 |
|
3 |
|
extra_pls.cpp:367-444 |
|
4 |
|
extra_pls.cpp:445-480 |
|
Phase 6 — specialized + ensembles + transfer (12 commits)¶
# |
Function |
Source lines |
Target |
|---|---|---|---|
1 |
|
extra_pls.cpp:481-550 |
|
2 |
|
extra_pls.cpp:551-616 |
|
3 |
|
extra_pls.cpp:617-677 |
|
4 |
|
extra_pls.cpp:678-736 |
|
5 |
|
extra_pls.cpp:737-799 |
|
6 |
|
extra_pls.cpp:1333-1397 |
|
7 |
|
extra_pls.cpp:800-846 |
|
8 |
|
extra_pls.cpp:1243-1332 |
|
9 |
|
extra_pls.cpp:1030-1140 |
|
10 |
|
extra_pls.cpp:1141-1242 |
|
11 |
|
extra_pls.cpp:1477-1647 |
|
Phase 7 — core dispatch (2 commits)¶
# |
Function |
Source lines |
Target |
|---|---|---|---|
1 |
|
model.cpp:3885-3920 and 4388-4541 |
|
2 |
|
extra_pls.cpp:1398-1476 |
|
Final cleanup¶
After all 7 phases land:
cpp/src/core/model.cppreduces to either an empty file (and is deleted) or to a tiny placeholder that just re-includes the new files (for backward-compat).Same for
cpp/src/core/extra_pls.cpp.cpp/src/CMakeLists.txtno longer references the two monoliths; instead it picks upcpp/src/core/models/**/*.cppandcpp/src/core/transfer/*.cpp(still explicit listing, no GLOB).
Per-commit gate¶
Each phase’s individual commit must pass:
cmake --build --preset dev-releasebuilds without errors../build/dev-release/cpp/tests/n4m_testsreports265 run, 0 failures, 0 skipped../build/dev-release/cpp/cli/n4m_cli --selfcheckreportsselfcheck OK.Optional:
objdump -T build/dev-release/cpp/src/libn4m.so.1 | grep ' n4m_' | wc -lreturns the same count as before the extraction (no symbol drop or duplication).
What is in M4 today (this commit)¶
39 stub files at all target paths under
cpp/src/core/models/{pls,opls,pcr,sparse,multiblock,local,ensembles,specialized,classification,glm,core}/andcpp/src/core/transfer/. Each stub carries a structured header naming the origin source, the line range to extract, and the function(s) it will receive.Two reports (
SPLIT_PLAN.mdfrom the Explore agent + thisEXTRACTION_RECIPE.md).No changes to
model.cpp,extra_pls.cpp, orcpp/src/CMakeLists.txt. pls4all builds unchanged,n4m_tests265/265 green.
What is NOT done in M4¶
The actual function-body extraction (Phases 1–7 above). The 28 algorithm extractions plus 3 helper extractions plus the cleanup are roadmap-budgeted at 4 days of careful work. They are deferred to a focused refactor session that can dedicate a build/test cycle per extraction.
Multiblock subcategory has no stubs because all multiblock methods (
mb_pls,n_pls,o2pls,so_pls,on_pls,rosa,multiblock_extensions) live in separatecpp/src/core/*.cppfiles already — they need re-categorisation rather than extraction. Those moves are simpler and can land in M5/M6.
Sequencing within the merge¶
Per MERGE_ROADMAP.md §9 critical path:
M3 → M4 → M5 → M6 → M7 → M8 → ...
The M4 scaffold unblocks M5 (ABI rename) because M5 operates on the monoliths in place. After M5, the post-rename monoliths can be extracted into the M4 stubs as planned here. The execution becomes:
M5 mechanical
n4m_* → n4m_*rename onmodel.cpp,extra_pls.cppin place.M4 Phase 1 (extract helpers) on the renamed monoliths.
M4 Phases 2–7 on each algorithm.
This is the order the agent’s plan implies.