-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Ensure n_fft, n_overlap and n_per_seg are integers #11334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
mne/time_frequency/psd.py
Outdated
| if n_per_seg is not None: | ||
| _validate_type(n_per_seg, "int", "n_per_seg") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if n_per_seg is not None: | |
| _validate_type(n_per_seg, "int", "n_per_seg") | |
| _validate_type(n_per_seg, ("int", None), "n_per_seg") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it does not support multiple types if one of them is "int"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lines 517 to 519 in 063a3e8
| if types == "int": | |
| _ensure_int(item, name=item_name, extra=extra) | |
| return # terminate prematurely |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure? To me it’s mostly to speed up the check but it should still work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, the function fails with a KeyError for "int" a bit further, so I guess the early exit is also due to this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks like correct/useful behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... @mscheltienne I think we are digressing a bit here. In MNE-Python we try to use _ensure_int when we want to ensure a user is passing an int-ike, e.g.:
$ git grep " = _ensure_int"
mne/_ola.py: n_pts = _ensure_int(n_pts, 'n_pts')
mne/_ola.py: n_samples = _ensure_int(n_samples, 'n_samples')
mne/_ola.py: n_overlap = _ensure_int(n_overlap, 'n_overlap')
mne/_ola.py: n_total = _ensure_int(n_total, 'n_total')
mne/bem.py: threshold = _ensure_int(threshold, 'threshold')
mne/filter.py: filter_length = _ensure_int(filter_length, 'filter_length')
mne/io/pick.py: info = _ensure_int(info, 'info', 'an int or Info')
...
It sounds like that is your goal here, yes? If so, I think we should continue using _ensure_int here, and @mscheltienne if you are still opposed to this function / don't see the point / think it's useless, we should debate its merits in a separate issue that addresses that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not opposed in the slightest, especially on a minor point like this one, since both functions fulfill the same role. I am however curious, am I missing something about _ensure_int? _validate_type calls it internally, and the casting seems to occur only from int to int (otherwise it raises).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the casting seems to occur only from int to int
Based on this phrasing perhaps what you miss is that more specifically "the casting occurs from any int-like that we want to support, to a native Python int".
Why is this useful? Well here is one problematic example case:
>>> _validate_type(np.uint32(1), 'int')
>>> np.uint32(1) - np.uint32(2)
<stdin>:1: RuntimeWarning: overflow encountered in uint_scalars
4294967295
>>> _ensure_int(np.uint32(1)) - np.uint32(2)
-1
This may seem contrived, but once users start working with / saving data to different formats (and we use I/O internally, too, internally), this sort of stuff can happen, and motivated implementing this function. So can this:
>>> type(np.array(1))
<class 'numpy.ndarray'>
>>> type(_ensure_int(np.array(1)))
<class 'int'>
I can't remember offhand why having this 0-d ndarray was problematic downstream, but I think it was at some point...
And even for less problematic cases (e.g., np.int32 vs np.int64 for small values), having different variants of int-like variables being passed can end up being inefficient. For example, if you write a numba function that consumes it, numba will now have to JIT-compile a new variant for every dtype (or raise if it doesn't know how to handle the inputs).
So anything that requires, is made safer, or is made more consistent by knowing that what you work with is a native Python int will benefit from this function. And given that it's hard to see ahead of time how potential failures will come up and account for them, it's useful to use it most times you need an int.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the details, I'll think about it and about how to include this in my future codes. I did not realize this difference between ints could cause issues.
Co-authored-by: Alexandre Gramfort <alexandre.gramfort@m4x.org>
This reverts commit 843d579.
agramfort
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@larsoner merge if you think it is the expected fix
|
Thanks @mscheltienne ! |
Improvement to make sure the arguments
n_fft,n_overlapandn_per_segare integers in Welch's method, to avoid this crpytic traceback when a float is provided (which is common if you doduration * raw.info["sfreq"]and forget to convert to int):From the forum post https://mne.discourse.group/t/set-window-size-for-welch-via-compute-psd/5958/6