Skip to content

test(3d morphology): assert the five PCA axis features against MIRP, and two MATLAB rows nothing checked - #434

Open
darkclad wants to merge 2 commits into
PolusAI:mainfrom
darkclad:main-vet-3d-morphology
Open

test(3d morphology): assert the five PCA axis features against MIRP, and two MATLAB rows nothing checked#434
darkclad wants to merge 2 commits into
PolusAI:mainfrom
darkclad:main-vet-3d-morphology

Conversation

@darkclad

Copy link
Copy Markdown

Closes the five 3D morphology rows that read status=vetted, oracle=mirp with no in-tree oracle assertion, plus two more the family plan did not count.

The five axis features

3MAJOR_AXIS_LEN, 3MINOR_AXIS_LEN, 3LEAST_AXIS_LEN, 3ELONGATION and 3FLATNESS carried a mirp verdict from an offline harness run (source=tracker) with target_test naming a _regression file. Nothing in the tree compared them against MIRP; the only thing touching them was the coverage sweep, which pins Nyxus' own output as a snapshot.

gen_morphology3d_mirp.py now runs MIRP 2.6.0 against the segmented phantom and test_3d_morphology_mirp.h asserts all five. Same definition on both sides - 4*sqrt of the mask covariance eigenvalues, and their ratios - so the agreement is exact to double precision:

3MAJOR_AXIS_LEN 104.70681271508683 rel 0
3MINOR_AXIS_LEN 88.30145986864228 rel 0
3LEAST_AXIS_LEN 71.51449974198198 rel 2.0e-16
3ELONGATION 0.8433210559938976 rel 0
3FLATNESS 0.6829975804590384 rel 1.6e-16

Asserted at rel=1e-9, far tighter than SPEC 7's rel=1e-3 same-definition tier, because that is what the measurement supports.

The generator checks the identities the old defect broke -------------------------------------------------------- This family carried an eigenvalue-ordering defect that produced 3LEAST_AXIS_LEN > 3MAJOR_AXIS_LEN and 3FLATNESS > 1, both structurally impossible. It is fixed in 3d_surface.cpp and these are the corrected values. The generator now asserts, on MIRP's own output, that MAJOR >= MINOR >= LEAST > 0, that ELONGATION and FLATNESS lie in [0,1], and that each equals its defining ratio - so a misconfigured oracle run is caught before anything is pinned. No _invariant file is added: the five oracle pins fix the exact values on this fixture and are strictly stronger than the bounds would be there.

Two rows the plan did not count

3VOXEL_VOLUME and 3VOLUME_CONVEXHULL read status=vetted, oracle=matlab and had a MATLAB golden and a stated band in morphology_3d_matlab_ref_vals/_ref_tols - but no oracle-named test asserted them. test_3d_morphology_matlab.h registered exactly one function, for 3MESH_VOLUME. The only thing comparing the other two against MATLAB was the parameterized sweep in test_3d_morphology_coverage.h, whose case names carry no oracle token, so the claim rested on a test that does not say what it checks (SPEC 6.2). The report generator misses this the same way it missed two rows in 2D morphology: a feature name in an oracle file counts as coverage whether an assertion reads it or only a table does. Both now have an assertion through the existing helper, goldens and bands. Both pass.

MATLAB cannot be re-run, so MIRP cross-checks it

Three rows claim oracle=matlab and revet step 3 says to run every claimed oracle. Not possible here - no licence, and Octave's image package has no regionprops3 - and the goldens have no in-repo generator (not_covered.md C). The generator prints the corresponding MIRP quantities instead, unpinned:

voxel volume MIRP 274432.0 MATLAB 274432.0 exact
convex-hull volume MIRP 496958.32 MATLAB 497824.0 0.17%

Both MATLAB goldens are independently corroborated, which also relocates the disagreement: Nyxus' 3VOLUME_CONVEXHULL of 478516 is 3.6% from MATLAB and 3.7% from MIRP while the two tools sit 0.17% apart, so the difference is Nyxus' discrete voxel hull against two triangulated ones - which is what the existing 5% band documents, now with a second measurement behind it.

The surface-area convention gap stays open

3AREA counts exposed voxel faces (59992) where MIRP integrates a marching-cubes mesh (46739), a 28% convention difference that no tolerance turns into an agreement. 3AREA and the five features derived from it stay status=regression, with the reason recorded per row rather than left as a bare absence. Settling it changes six public feature values and belongs on its own branch.

Test file cleanup

test_3d_morphology_common.h carried a dead #if 0 block - a superseded copy of the whole fixture, ending in a line of asterisks that is not valid C++ and only compiled because it was disabled. Removed. It also included test_ref_vals.h while declaring no reference table. Include hygiene across the family: _common.h relied transitively on , , and helpers/fsystem.h; _matlab.h named Pixel3 and Nyxus::calc_eigvals without including features/pixel.h or helpers/helpers.h, and used std::abs/std::vector without /; _regression.h relied on . All now direct. Three headers carried "Migrated from test_3d_shape.h (Wave 8)" history, which belongs in the audit report.

Registry

All 14 rows get a real config_recipe id (three new: morphology3d.mirp_ibsi, morphology3d.matlab_regionprops3, morphology3d.regression_ut_phantom - one fixture, three benchmarks, so unusually they ARE comparable to each other, which is what makes the MIRP cross-check meaningful), a real tolerance, target_test cleared, source moved off tracker, and current_test synced to the files that actually cover each feature.

Verified: runAllTests 780/780 on Windows and under ASan+UBSan on Linux; pytest tests/python/ full directory (92 passed, 1 skipped); check_coverage.py --check, check_test_names.py --check and audit/scan_morphology3d_coverage.py --check all clean; gen_morphology3d_mirp.py re-verifies all five goldens and all four structural identities against a fresh MIRP 2.6.0 run.

Demian Vladi added 2 commits August 14, 2026 14:21
…and two MATLAB rows nothing checked

Closes the five 3D morphology rows that read status=vetted, oracle=mirp with no in-tree oracle
assertion, plus two more the family plan did not count.

The five axis features
----------------------
3MAJOR_AXIS_LEN, 3MINOR_AXIS_LEN, 3LEAST_AXIS_LEN, 3ELONGATION and 3FLATNESS carried a mirp verdict
from an offline harness run (source=tracker) with target_test naming a _regression file. Nothing in
the tree compared them against MIRP; the only thing touching them was the coverage sweep, which pins
Nyxus' own output as a snapshot.

gen_morphology3d_mirp.py now runs MIRP 2.6.0 against the segmented phantom and
test_3d_morphology_mirp.h asserts all five. Same definition on both sides - 4*sqrt of the mask
covariance eigenvalues, and their ratios - so the agreement is exact to double precision:

  3MAJOR_AXIS_LEN   104.70681271508683   rel 0
  3MINOR_AXIS_LEN    88.30145986864228   rel 0
  3LEAST_AXIS_LEN    71.51449974198198   rel 2.0e-16
  3ELONGATION         0.8433210559938976 rel 0
  3FLATNESS           0.6829975804590384 rel 1.6e-16

Asserted at rel=1e-9, far tighter than SPEC 7's rel=1e-3 same-definition tier, because that is what
the measurement supports.

The generator checks the identities the old defect broke
--------------------------------------------------------
This family carried an eigenvalue-ordering defect that produced 3LEAST_AXIS_LEN > 3MAJOR_AXIS_LEN and
3FLATNESS > 1, both structurally impossible. It is fixed in 3d_surface.cpp and these are the corrected
values. The generator now asserts, on MIRP's own output, that MAJOR >= MINOR >= LEAST > 0, that
ELONGATION and FLATNESS lie in [0,1], and that each equals its defining ratio - so a misconfigured
oracle run is caught before anything is pinned. No _invariant file is added: the five oracle pins fix
the exact values on this fixture and are strictly stronger than the bounds would be there.

Two rows the plan did not count
-------------------------------
3VOXEL_VOLUME and 3VOLUME_CONVEXHULL read status=vetted, oracle=matlab and had a MATLAB golden and a
stated band in morphology_3d_matlab_ref_vals/_ref_tols - but no oracle-named test asserted them.
test_3d_morphology_matlab.h registered exactly one function, for 3MESH_VOLUME. The only thing
comparing the other two against MATLAB was the parameterized sweep in test_3d_morphology_coverage.h,
whose case names carry no oracle token, so the claim rested on a test that does not say what it
checks (SPEC 6.2). The report generator misses this the same way it missed two rows in 2D morphology:
a feature name in an oracle file counts as coverage whether an assertion reads it or only a table
does. Both now have an assertion through the existing helper, goldens and bands. Both pass.

MATLAB cannot be re-run, so MIRP cross-checks it
------------------------------------------------
Three rows claim oracle=matlab and revet step 3 says to run every claimed oracle. Not possible here -
no licence, and Octave's image package has no regionprops3 - and the goldens have no in-repo generator
(not_covered.md C). The generator prints the corresponding MIRP quantities instead, unpinned:

  voxel volume        MIRP 274432.0   MATLAB 274432.0   exact
  convex-hull volume  MIRP 496958.32  MATLAB 497824.0   0.17%

Both MATLAB goldens are independently corroborated, which also relocates the disagreement: Nyxus'
3VOLUME_CONVEXHULL of 478516 is 3.6% from MATLAB and 3.7% from MIRP while the two tools sit 0.17%
apart, so the difference is Nyxus' discrete voxel hull against two triangulated ones - which is what
the existing 5% band documents, now with a second measurement behind it.

The surface-area convention gap stays open
------------------------------------------
3AREA counts exposed voxel faces (59992) where MIRP integrates a marching-cubes mesh (46739), a 28%
convention difference that no tolerance turns into an agreement. 3AREA and the five features derived
from it stay status=regression, with the reason recorded per row rather than left as a bare absence.
Settling it changes six public feature values and belongs on its own branch.

Test file cleanup
-----------------
test_3d_morphology_common.h carried a dead #if 0 block - a superseded copy of the whole fixture,
ending in a line of asterisks that is not valid C++ and only compiled because it was disabled.
Removed. It also included test_ref_vals.h while declaring no reference table. Include hygiene across
the family: _common.h relied transitively on <string>, <tuple>, <vector> and helpers/fsystem.h;
_matlab.h named Pixel3 and Nyxus::calc_eigvals without including features/pixel.h or
helpers/helpers.h, and used std::abs/std::vector without <cmath>/<vector>; _regression.h relied on
<string>. All now direct. Three headers carried "Migrated from test_3d_shape.h (Wave 8)" history,
which belongs in the audit report.

Registry
--------
All 14 rows get a real config_recipe id (three new: morphology3d.mirp_ibsi,
morphology3d.matlab_regionprops3, morphology3d.regression_ut_phantom - one fixture, three benchmarks,
so unusually they ARE comparable to each other, which is what makes the MIRP cross-check meaningful),
a real tolerance, target_test cleared, source moved off tracker, and current_test synced to the files
that actually cover each feature.

Verified: runAllTests 780/780 on Windows and under ASan+UBSan on Linux; pytest tests/python/ full
directory (92 passed, 1 skipped); check_coverage.py --check, check_test_names.py --check and
audit/scan_morphology3d_coverage.py --check all clean; gen_morphology3d_mirp.py re-verifies all five
goldens and all four structural identities against a fresh MIRP 2.6.0 run.
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.

1 participant