Skip to content
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

MAINT: next round of 1.9.0 backports #16420

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/linux_meson.yml
Expand Up @@ -101,6 +101,7 @@ jobs:
- name: Test SciPy
run: |
export OMP_NUM_THREADS=2
export SCIPY_USE_PROPACK=1
python dev.py -n -j 2

test_venv_install:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/macos_meson.yml
Expand Up @@ -112,6 +112,7 @@ jobs:
run: |
conda activate scipy-dev
export OMP_NUM_THREADS=2
export SCIPY_USE_PROPACK=1
python dev.py -n -j 2

- name: Ccache statistics
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/windows.yml
Expand Up @@ -79,6 +79,7 @@ jobs:
- name: prep-test
run: |
echo "PYTHONPATH=${env:installed_path}" >> $env:GITHUB_ENV
echo "SCIPY_USE_PROPACK=1" >> $env:GITHUB_ENV
- name: test
run: |
mkdir tmp
Expand Down
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Expand Up @@ -182,7 +182,7 @@ stages:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
python3.8 get-pip.py && \
pip3 --version && \
pip3 install setuptools==59.6.0 wheel numpy==1.18.5 cython==0.29.21 pybind11 pytest pytest-timeout pytest-xdist pytest-env pytest-cov Pillow mpmath pythran==0.10.0 && \
pip3 install setuptools==59.6.0 wheel numpy==1.18.5 cython==0.29.21 pybind11 pytest pytest-timeout pytest-xdist pytest-env pytest-cov Pillow mpmath pythran==0.11.0 && \
apt-get -y install gcc-5 g++-5 gfortran-8 wget && \
cd .. && \
mkdir openblas && cd openblas && \
Expand Down Expand Up @@ -295,7 +295,7 @@ stages:
numpy==1.21.4
Pillow
pybind11
pythran==0.10.0
pythran==0.11.0
pytest
pytest-cov
pytest-env
Expand Down
76 changes: 70 additions & 6 deletions doc/release/1.9.0-notes.rst

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions doc/source/_static/scipy.css
Expand Up @@ -38,18 +38,21 @@ Nat Methods 8, 441 (2011). https://doi.org/10.1038/nmeth.1618
#version_switcher_button[data-active-version-name*="dev"] {
background-color: #E69F00;
border-color: #E69F00;
color: white;
}

/* green for `stable` */
#version_switcher_button[data-active-version-name*="stable"] {
background-color: #009E73;
border-color: #009E73;
color: white;
}

/* red for `old` */
#version_switcher_button:not([data-active-version-name*="stable"]):not([data-active-version-name*="dev"]):not([data-active-version-name*="pull"]) {
background-color: #980F0F;
border-color: #980F0F;
color: white;
}

/* Taken from NumPy */
Expand Down Expand Up @@ -159,3 +162,40 @@ h3 {
margin-bottom: 0rem;
color: #484848;
}


/* Dark theme tweaking

Matplotlib images are in png and inverted while other output
types are assumed to be normal images.

*/
html[data-theme=dark] img[src*='.png'] {
filter: invert(0.82) brightness(0.8) contrast(1.2);
}

html[data-theme=dark] .MathJax_SVG * {
fill: var(--pst-color-text-base);
}

/* Main index page overview cards */
html[data-theme=dark] .shadow {
box-shadow: 0 .5rem 1rem rgba(250, 250, 250, .6) !important
}

html[data-theme=dark] .intro-card .card-header {
background-color:var(--pst-color-background);
color: #150458 !important;
}

html[data-theme=dark] .intro-card .card-footer {
background-color:var(--pst-color-background);
}

html[data-theme=dark] h1 {
color: var(--pst-color-primary);
}

html[data-theme=dark] h3 {
color: #0a6774;
}
4 changes: 2 additions & 2 deletions doc/source/conf.py
Expand Up @@ -185,9 +185,9 @@
html_favicon = '_static/favicon.ico'

html_theme_options = {
"logo_link": "index",
"github_url": "https://github.com/scipy/scipy",
"navbar_end": ["version-switcher", "navbar-icon-links"],
"twitter_url": "https://twitter.com/SciPy_team",
"navbar_end": ["theme-switcher", "version-switcher", "navbar-icon-links"],
"switcher": {
"json_url": "https://scipy.github.io/devdocs/_static/version_switcher.json",
"version_match": version,
Expand Down
4 changes: 2 additions & 2 deletions doc_requirements.txt
@@ -1,7 +1,7 @@
# Note: this should disappear at some point. For now, please keep it
# in sync with the doc dependencies in pyproject.toml
Sphinx!=3.1.0, !=4.1.0
pydata-sphinx-theme>=0.8.1
Sphinx!=4.1.0
pydata-sphinx-theme>=0.9.0
sphinx-panels>=0.5.2
sphinx-tabs
numpydoc
Expand Down
4 changes: 2 additions & 2 deletions environment.yml
Expand Up @@ -18,7 +18,7 @@ dependencies:
- pkg-config # note: not available on Windows
- libblas=*=*openblas # helps avoid pulling in MKL
- pybind11
- pythran>=0.9.12
- pythran>=0.11.0
# For testing and benchmarking
- pytest
- pytest-cov
Expand All @@ -32,7 +32,7 @@ dependencies:
- numpydoc
- ipython
- matplotlib
- pydata-sphinx-theme>=0.8.1
- pydata-sphinx-theme>=0.9.0
- sphinx-panels
- sphinx-tabs
# For linting
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Expand Up @@ -13,7 +13,7 @@ requires = [
"meson-python>=0.5.0",
"Cython>=0.29.21",
"pybind11>=2.4.3",
"pythran>=0.9.12",
"pythran>=0.11.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty sure this will create a merge conflict, but that's all being dealt with in gh-16353 anyway, where the caps are added.

# `wheel` is needed for non-isolated builds, given that `meson-python`
# doesn't list it as a runtime requirement (at least in 0.5.0)
"wheel",
Expand Down Expand Up @@ -101,8 +101,8 @@ test = [
"scikit-umfpack",
]
doc = [
"sphinx!=3.1.0, !=4.1.0",
"pydata-sphinx-theme>=0.8.1",
"sphinx!=4.1.0",
"pydata-sphinx-theme>=0.9.0",
"sphinx-panels>=0.5.2",
"matplotlib>2",
"numpydoc",
Expand Down
2 changes: 1 addition & 1 deletion scipy/_lib/boost
5 changes: 5 additions & 0 deletions scipy/optimize/tests/test_linprog.py
Expand Up @@ -2,6 +2,7 @@
Unit test for Linear Programming
"""
import sys
import platform

import numpy as np
from numpy.testing import (assert_, assert_allclose, assert_equal,
Expand Down Expand Up @@ -2199,6 +2200,10 @@ class TestLinprogHiGHSMIP():
method = "highs"
options = {}

@pytest.mark.xfail(condition=(sys.maxsize < 2 ** 32 and
platform.system() == "Linux"),
run=False,
reason="gh-16347")
def test_mip1(self):
# solve non-relaxed magic square problem (finally!)
# also check that values are all integers - they don't always
Expand Down
4 changes: 3 additions & 1 deletion scipy/optimize/tests/test_milp.py
Expand Up @@ -57,8 +57,10 @@ def test_milp_iv():
milp([1, 2, 3], bounds=([1, 2, 3], [set(), 4, 5]))


@pytest.mark.xfail(strict=True, reason="Needs to be fixed in `_highs_wrapper`")
@pytest.mark.xfail(run=False,
reason="Needs to be fixed in `_highs_wrapper`")
def test_milp_options(capsys):
# run=False now because of gh-16347
message = "Unrecognized options detected: {'ekki'}..."
options = {'ekki': True}
with pytest.warns(RuntimeWarning, match=message):
Expand Down
13 changes: 12 additions & 1 deletion scipy/sparse/linalg/_eigen/_svds.py
@@ -1,3 +1,4 @@
import os
import numpy as np

from .arpack import _arpack # type: ignore[attr-defined]
Expand All @@ -6,7 +7,11 @@
from scipy._lib._util import check_random_state
from scipy.sparse.linalg._interface import LinearOperator, aslinearoperator
from scipy.sparse.linalg._eigen.lobpcg import lobpcg # type: ignore[no-redef]
from scipy.sparse.linalg._svdp import _svdp
if os.environ.get("SCIPY_USE_PROPACK"):
from scipy.sparse.linalg._svdp import _svdp
HAS_PROPACK = True
else:
HAS_PROPACK = False
from scipy.linalg import svd

arpack_int = _arpack.timing.nbx.dtype
Expand Down Expand Up @@ -297,6 +302,12 @@ def matmat_XH_X(x):
eigvec, _ = np.linalg.qr(eigvec)

elif solver == 'propack':
if not HAS_PROPACK:
raise ValueError("`solver='propack'` is opt-in due "
"to potential issues on Windows, "
"it can be enabled by setting the "
"`SCIPY_USE_PROPACK` environment "
"variable before importing scipy")
jobu = return_singular_vectors in {True, 'u'}
jobv = return_singular_vectors in {True, 'vh'}
irl_mode = (which == 'SM')
Expand Down
45 changes: 45 additions & 0 deletions scipy/sparse/linalg/_eigen/tests/test_svds.py
@@ -1,3 +1,4 @@
import os
import re
import copy
import numpy as np
Expand All @@ -8,6 +9,10 @@
from scipy.linalg import hilbert, svd, null_space
from scipy.sparse import csc_matrix, isspmatrix, spdiags, random
from scipy.sparse.linalg import LinearOperator, aslinearoperator
if os.environ.get("SCIPY_USE_PROPACK"):
has_propack = True
else:
has_propack = False
from scipy.sparse.linalg import svds
from scipy.sparse.linalg._eigen.arpack import ArpackNoConvergence

Expand Down Expand Up @@ -157,6 +162,8 @@ def test_svds_input_validation_k_1(self, k):

# propack can do complete SVD
if self.solver == 'propack' and k == 3:
if not has_propack:
pytest.skip("PROPACK not enabled")
res = svds(A, k=k, solver=self.solver)
_check_svds(A, k, *res, check_usvh_A=True, check_svd=True)
return
Expand Down Expand Up @@ -257,6 +264,9 @@ def test_svds_input_validation_return_singular_vectors(self, rsv):
@pytest.mark.parametrize("k", [3, 5])
@pytest.mark.parametrize("which", ["LM", "SM"])
def test_svds_parameter_k_which(self, k, which):
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")
# check that the `k` parameter sets the number of eigenvalues/
# eigenvectors returned.
# Also check that the `which` parameter sets whether the largest or
Expand All @@ -274,6 +284,9 @@ def test_svds_parameter_k_which(self, k, which):

# loop instead of parametrize for simplicity
def test_svds_parameter_tol(self):
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")
return # TODO: needs work, disabling for now
# check the effect of the `tol` parameter on solver accuracy by solving
# the same problem with varying `tol` and comparing the eigenvalues
Expand Down Expand Up @@ -315,6 +328,9 @@ def err(tol):
assert error > accuracy/10

def test_svd_v0(self):
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")
# check that the `v0` parameter affects the solution
n = 100
k = 1
Expand Down Expand Up @@ -347,6 +363,9 @@ def test_svd_v0(self):
assert_equal(res1a, res1b)

def test_svd_random_state(self):
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")
# check that the `random_state` parameter affects the solution
# Admittedly, `n` and `k` are chosen so that all solver pass all
# these checks. That's a tall order, since LOBPCG doesn't want to
Expand Down Expand Up @@ -379,6 +398,10 @@ def test_svd_random_state(self):
np.random.RandomState(0),
np.random.default_rng(0)))
def test_svd_random_state_2(self, random_state):
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")

n = 100
k = 1

Expand All @@ -397,6 +420,10 @@ def test_svd_random_state_2(self, random_state):
np.random.RandomState(0),
np.random.default_rng(0)))
def test_svd_random_state_3(self, random_state):
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")

n = 100
k = 5

Expand All @@ -417,6 +444,9 @@ def test_svd_random_state_3(self, random_state):
def test_svd_maxiter(self):
# check that maxiter works as expected: should not return accurate
# solution after 1 iteration, but should with default `maxiter`
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")
A = hilbert(6)
k = 1
u, s, vh = sorted_svd(A, k)
Expand All @@ -443,6 +473,10 @@ def test_svd_maxiter(self):
@pytest.mark.parametrize("shape", ((5, 7), (6, 6), (7, 5)))
def test_svd_return_singular_vectors(self, rsv, shape):
# check that the return_singular_vectors parameter works as expected
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")

rng = np.random.default_rng(0)
A = rng.random(shape)
k = 2
Expand Down Expand Up @@ -521,6 +555,10 @@ def test_svd_return_singular_vectors(self, rsv, shape):
aslinearoperator))
def test_svd_simple(self, A, k, real, transpose, lo_type):

if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")

A = np.asarray(A)
A = np.real(A) if real else A
A = A.T if transpose else A
Expand All @@ -547,6 +585,9 @@ def test_svd_simple(self, A, k, real, transpose, lo_type):

def test_svd_linop(self):
solver = self.solver
if self.solver == 'propack':
if not has_propack:
pytest.skip("PROPACK not available")

nmks = [(6, 7, 3),
(9, 5, 4),
Expand Down Expand Up @@ -720,6 +761,8 @@ def test_svd_LM_zeros_matrix(self, shape, dtype):
# ARPACK supports only dtype float, complex, or np.float32
@pytest.mark.parametrize("dtype", (float, complex, np.float32))
def test_small_sigma(self, shape, dtype):
if not has_propack:
pytest.skip("PROPACK not enabled")
# https://github.com/scipy/scipy/pull/11829
if dtype == complex and self.solver == 'propack':
pytest.skip("PROPACK unsupported for complex dtype")
Expand All @@ -743,6 +786,8 @@ def test_small_sigma(self, shape, dtype):
@pytest.mark.filterwarnings("ignore:The problem size")
@pytest.mark.parametrize("dtype", (float, complex, np.float32))
def test_small_sigma2(self, dtype):
if not has_propack:
pytest.skip("PROPACK not enabled")
# https://github.com/scipy/scipy/issues/11406
if dtype == complex and self.solver == 'propack':
pytest.skip("PROPACK unsupported for complex dtype")
Expand Down
5 changes: 3 additions & 2 deletions scipy/spatial/_qhull.pyx
Expand Up @@ -2822,8 +2822,9 @@ class HalfspaceIntersection(_QhullUser):

# Run qhull
mode_option = "H"
qhull = _Qhull(mode_option.encode(), halfspaces, qhull_options, required_options=None,
incremental=incremental, interior_point=interior_point)
qhull = _Qhull(mode_option.encode(), halfspaces, qhull_options,
required_options=None, incremental=incremental,
interior_point=self.interior_point)

_QhullUser.__init__(self, qhull, incremental=incremental)

Expand Down