Skip to content

EEGLAB export writes an asymmetric sphere transposed #336

Description

@neuromechanist

Symptom

write_amicaout, the EEGLAB export shared by the torch, NumPy and MLX backends (write_amica_output), writes a square sphere S in C order, while the Fortran reference writes it column-major and every reader (EEGLAB's loadmodout15.m, pamica's loadmodout) reads it column-major. For the default symmetric (ZCA) sphere this is invisible (2e-17). With do_approx_sphere=False the sphere is not symmetric, and the exported sphere comes back exactly transposed. Measured on the bundled sample (torch, 3 iterations): max|S_loaded - S| = 0.51, max|S_loaded - S.T| = 0.0. EEGLAB would then build icasphere and icaweights from the wrong matrix.

Root cause

pamica/numpy_impl/load.py write_amicaout: the rank-reduced branch pads and writes order="F", but the square branch keeps order="C", on the reasoning that the ZCA sphere is its own transpose and that C order keeps output "byte-identical to the Fortran reference". That reasoning does not hold. The test that backs it (test_square_sphere_bytes_are_unchanged in pamica/tests/test_amicaout_reduced.py) pins C order for a sphere pamica itself computed, not against the reference's bytes. Fortran's layout is column-major, so C order is wrong by the sphere's asymmetry: 2e-17 for ZCA, O(1) otherwise. pamica/numpy_impl/data.py load_results mirrors the writer, reading a square sphere in C order.

Fix

Write S column-major in both branches, read it column-major in load_results, and replace the C-order pin with round-trip tests. For every backend, with do_approx_sphere True and False and with and without pcakeep, loadmodout and load_results must return the fitted sphere bit-exactly, and the raw bytes must equal sphere.ravel(order="F") (after padding). Update the comments and docstrings that claim C order is the byte-identical choice, and add a changelog entry.

Found during epic #324 Phase 6 (#315, PR #332). Part of epic #324.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions