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.
Two related sign-convention problems.
1. ImCoh documented signed, implemented as absolute value.
hypyp/sync/imaginary_coh.py:39andhypyp/analyses.py:504both writeImCoh = Im(⟨XY*⟩) / √(⟨|X|²⟩⟨|Y|²⟩), with no absolute value.hypyp/sync/README.mdlikewise. The code takes the magnitude —hypyp/sync/imaginary_coh.py:92: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.
ccorrandaccorrdisagree on sign, although presented as variants of the same quantity.Measured off-diagonal ranges on the same input:
ccorrtakes the absolute value in every backend (numpyccorr.py:99, numba:236, torch:157, CUDAfabs), whileaccorris signed (accorr.py:183,num = r_minus - r_pluswith noabs). Both are internally consistent across backends, so neither is a backend bug — but a user comparingccorragainstaccorron 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 takeabs()is the more informative default.