Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ stages:
PYTHONIOENCODING: 'utf-8'
AZURE_CI_WINDOWS: 'true'
PYTHON_ARCH: 'x64'
MNE_CI_KIND: $(TEST_MODE)
timeoutInMinutes: 95
strategy:
maxParallel: 4
Expand Down
55 changes: 49 additions & 6 deletions mne/utils/linalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,61 @@ def _get_lapack_funcs(dtype, names):
###############################################################################
# linalg.svd and linalg.pinv2

# TODO VERSION these can be removed once we use SciPy 1.18+ with batched processing
# (otherwise call overhead for `lwork` is too high). Can't use NumPy because
# it doesn't provide an interface to GESVD (only uses GESDD, which can be buggy).


# Vendored from scipy: _compute_lwork and _check_work_float


def _compute_lwork(routine, *args, **kwargs): # pragma: no cover
dtype = getattr(routine, "dtype", None)
int_dtype = getattr(routine, "int_dtype", None)
ret = routine(*args, **kwargs)
if ret[-1] != 0:
raise ValueError(f"Internal work array size computation failed: {ret[-1]}")
if len(ret) == 2:
return _check_work_float(ret[0].real, dtype, int_dtype)
else:
return tuple(_check_work_float(x.real, dtype, int_dtype) for x in ret[:-1])


_int32_max = np.iinfo(np.int32).max
_int64_max = np.iinfo(np.int64).max


def _check_work_float(value, dtype, int_dtype): # pragma: no cover
if dtype == np.float32 or dtype == np.complex64:
# Single-precision routine -- take next fp value to work
# around possible truncation in LAPACK code
value = np.nextafter(value, np.inf, dtype=np.float32)

value = int(value)
if int_dtype.itemsize == 4:
if value < 0 or value > _int32_max:
raise ValueError(
"Too large work array required -- computation "
"cannot be performed with standard 32-bit"
" LAPACK."
)
elif int_dtype.itemsize == 8:
if value < 0 or value > _int64_max:
raise ValueError(
"Too large work array required -- computation"
" cannot be performed with standard 64-bit"
" LAPACK."
)
return value


def _svd_lwork(shape, dtype=np.float64):
"""Set up SVD calculations on identical-shape float64/complex128 arrays."""
try:
ds = linalg._decomp_svd
except AttributeError: # < 1.8.0
ds = linalg.decomp_svd
gesdd_lwork, gesvd_lwork = _get_lapack_funcs(dtype, ("gesdd_lwork", "gesvd_lwork"))
sdd_lwork = ds._compute_lwork(
sdd_lwork = _compute_lwork(
gesdd_lwork, *shape, compute_uv=True, full_matrices=False
)
svd_lwork = ds._compute_lwork(
svd_lwork = _compute_lwork(
gesvd_lwork, *shape, compute_uv=True, full_matrices=False
)
return sdd_lwork, svd_lwork
Expand Down
6 changes: 6 additions & 0 deletions mne/viz/tests/test_raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ def test_scale_bar(browser_backend):
def test_plot_raw_selection(raw, browser_backend):
"""Test selection mode of plot_raw()."""
ismpl = browser_backend.name == "matplotlib"
if ismpl and os.getenv("MNE_CI_KIND") == "pip-pre":
# TODO VERSION FIX SOON AFTER 2026/01/26!
pytest.xfail("Needs mpl gh-31031")
with raw.info._unlock():
raw.info["lowpass"] = 10.0 # allow heavy decim during plotting
browser_backend._close_all() # ensure all are closed
Expand Down Expand Up @@ -765,6 +768,9 @@ def test_plot_misc_auto(browser_backend):
def test_plot_annotations(raw, browser_backend):
"""Test annotation mode of the plotter."""
ismpl = browser_backend.name == "matplotlib"
if ismpl and os.getenv("MNE_CI_KIND") == "pip-pre":
# TODO VERSION FIX SOON AFTER 2026/01/26!
pytest.xfail("Needs mpl gh-31031")
with raw.info._unlock():
raw.info["lowpass"] = 10.0
_annotation_helper(raw, browser_backend)
Expand Down