Skip to content

FIX: Make confound expansion column order deterministic#1045

Open
lobennett wants to merge 1 commit into
nipreps:masterfrom
lobennett:fix/parse-formula-determinism
Open

FIX: Make confound expansion column order deterministic#1045
lobennett wants to merge 1 commit into
nipreps:masterfrom
lobennett:fix/parse-formula-determinism

Conversation

@lobennett

Copy link
Copy Markdown

Closes nipreps/fmriprep#3501.

Changes

  • parse_formula: replace list(set(reduce(...))) with list(dict.fromkeys(reduce(...))) to preserve insertion order while deduplicating.
  • _expand_shorthand: build the others substitution with an ordered generator over variables rather than set(variables) - set(formula_variables).
  • temporal_derivatives / exponential_terms: wrap set(order) - {0|1} in sorted() so multi-order expansions iterate in ascending order.

Why

Each of those set() iterations depends on Python's hash seed, so the same fMRIPrep run could produce columns in different order between executions. The user reported this in nipreps/fmriprep#3501 with --skull-strip-fixed-seed --omp-nthreads 1 --random-seed N set, expecting bit-identical output across runs.

Testing

Added test_expansion_column_order_deterministic asserting the exact expected column order for (dd1(a + b + c))^^2 + others against the existing test fixture. Empirically:

  • Under the unpatched code, the test fails on all six PYTHONHASHSEED values I tried (1, 2, 3, 42, 100, 9999).
  • Under the fix, the test passes on all six.
  • Existing test_expansion_* tests continue to pass (they assert column sets, not order, so they were unaffected).

ruff check, ruff format --check, and codespell pass on both modified files.

parse_formula and its helpers in interfaces/confounds.py used set()-based
iteration in three places, so columns of desc-confounds_timeseries.tsv
could shuffle between otherwise-identical fMRIPrep runs even with
--skull-strip-fixed-seed and --random-seed set. Replace with
order-preserving alternatives: dict.fromkeys for the parse_formula
deduplication, an ordered generator for the _expand_shorthand 'others'
substitution, and sorted() around the set arithmetic in
temporal_derivatives and exponential_terms.

Closes nipreps/fmriprep#3501.
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.

Changing order of columns in confounds tsv when trying to generate identical output

1 participant