Skip to content

ImCoh is documented signed but returns |Im|; ccorr and accorr use opposite sign conventions #302

Description

@Ramdam17

Two related sign-convention problems.

1. ImCoh documented signed, implemented as absolute value.

hypyp/sync/imaginary_coh.py:39 and hypyp/analyses.py:504 both write ImCoh = Im(⟨XY*⟩) / √(⟨|X|²⟩⟨|Y|²⟩), with no absolute value. hypyp/sync/README.md likewise. The code takes the magnitude — hypyp/sync/imaginary_coh.py:92:

con = np.abs(np.imag(dphi)) / np.sqrt(...)

Same in numba (:174), torch (:138) and CUDA (cuda_amplitude.py:95, fabs(im)). Measured: no negative value is ever produced.

This discards information. In Nolte et al. 2004 the sign of the imaginary part of coherency carries the lead/lag direction of the interaction; folding it to a magnitude removes the directionality that is a large part of why one reaches for ImCoh in the first place.

2. ccorr and accorr disagree on sign, although presented as variants of the same quantity.

Measured off-diagonal ranges on the same input:

  ccorr    min=+0.001457 max=+0.113029 any_negative=False
  accorr   min=-0.082383 max=+0.078357 any_negative=True
  imcoh    min=+0.001452 max=+0.121609 any_negative=False
  envcorr  min=-0.107288 max=+0.110752 any_negative=True

ccorr takes the absolute value in every backend (numpy ccorr.py:99, numba :236, torch :157, CUDA fabs), while accorr is signed (accorr.py:183, num = r_minus - r_plus with no abs). Both are internally consistent across backends, so neither is a backend bug — but a user comparing ccorr against accorr on the same dataset is comparing a magnitude to a signed quantity.

This is worth resolving deliberately given that ACCorr's reference paper (Zimmermann et al. 2024, Imaging Neuroscience) is specifically about arbitrary methodological decisions skewing inter-brain synchrony estimates.

Suggested fix: decide the intended convention per metric, apply it uniformly across the five backends, and document it explicitly in each class docstring and in sync/README.md. Preserving the sign and letting callers take abs() is the more informative default.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions