Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-scikit-sparse for openSUSE:Factory checked in at 2023-09-10 13:09:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-scikit-sparse (Old) and /work/SRC/openSUSE:Factory/.python-scikit-sparse.new.1766 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-scikit-sparse" Sun Sep 10 13:09:58 2023 rev:6 rq:1109763 version:0.4.12 Changes: -------- --- /work/SRC/openSUSE:Factory/python-scikit-sparse/python-scikit-sparse.changes 2021-04-24 23:10:54.755544089 +0200 +++ /work/SRC/openSUSE:Factory/.python-scikit-sparse.new.1766/python-scikit-sparse.changes 2023-09-10 13:10:33.715265391 +0200 @@ -1,0 +2,17 @@ +Fri Sep 8 16:56:21 UTC 2023 - Matej Cepl <mc...@suse.com> + +- Clean up the SPEC file. +- Convert from python_{build,install} to + pyproject_{wheel,install} macros. + +------------------------------------------------------------------- +Thu Aug 31 12:37:47 UTC 2023 - Markéta Machová <mmach...@suse.com> + +- Update to 0.4.12 + * Allow suitesparse include/library paths to be passed in to + pip install through environment variables. + * Added support for python 3.11 + * Fix compilation with Cython>=3.0.0 +- Add upstream scipy111.patch + +------------------------------------------------------------------- Old: ---- scikit-sparse-0.4.5.tar.gz New: ---- scikit-sparse-0.4.12.tar.gz scipy111.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-scikit-sparse.spec ++++++ --- /var/tmp/diff_new_pack.gNB3UY/_old 2023-09-10 13:10:34.735301833 +0200 +++ /var/tmp/diff_new_pack.gNB3UY/_new 2023-09-10 13:10:34.739301976 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-scikit-sparse # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,34 +16,34 @@ # -%{?!python_module:%define python_module() python-%{**} python3-%{**}} -%define skip_python2 1 -%define skip_python36 1 -Name: python-scikit-sparse -Version: 0.4.5 -Release: 0 # For license file %define tag c94f8418b6c36c3ff9db4f87e00fc08bd51cfb4b +Name: python-scikit-sparse +Version: 0.4.12 +Release: 0 Summary: Scikits sparse matrix package License: GPL-2.0-or-later AND LGPL-2.1-or-later Group: Development/Languages/Python URL: https://github.com/scikit-sparse/scikit-sparse/ Source: https://files.pythonhosted.org/packages/source/s/scikit-sparse/scikit-sparse-%{version}.tar.gz +#PATCH-FIX-UPSTREAM https://github.com/scikit-sparse/scikit-sparse/pull/102 Fix breaking changes in isspmatrix of scipy >=1.11.0 +Patch0: scipy111.patch BuildRequires: %{python_module Cython} BuildRequires: %{python_module devel} BuildRequires: %{python_module numpy-devel >= 1.13.3} +BuildRequires: %{python_module pip} BuildRequires: %{python_module scipy >= 0.19} BuildRequires: %{python_module setuptools >= 18.0} +BuildRequires: %{python_module wheel} BuildRequires: fdupes BuildRequires: python-rpm-macros BuildRequires: suitesparse-devel -# SECTION test requirements -BuildRequires: %{python_module pytest} -# /SECTION Requires: python-numpy >= 1.12 Requires: python-scipy >= 0.18 ExcludeArch: %{ix86} - +# SECTION test requirements +BuildRequires: %{python_module pytest} +# /SECTION %python_subpackages %description @@ -57,16 +57,14 @@ decomposition. %prep -%setup -q -n scikit-sparse-%{version} -# no need for nose here -- gh#scikit-sparse/pull#66 -sed -i 's/from nose.tools import assert_raises/from pytest import raises as assert_raises/' sksparse/test_cholmod.py +%autosetup -p1 -n scikit-sparse-%{version} %build export CFLAGS="%{optflags}" -%python_build +%pyproject_wheel %install -%python_install +%pyproject_install %python_expand %fdupes %{buildroot}%{$python_sitearch} %check ++++++ scikit-sparse-0.4.5.tar.gz -> scikit-sparse-0.4.12.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/PKG-INFO new/scikit-sparse-0.4.12/PKG-INFO --- old/scikit-sparse-0.4.5/PKG-INFO 2021-04-03 13:32:43.000000000 +0200 +++ new/scikit-sparse-0.4.12/PKG-INFO 2023-07-21 06:59:19.567062900 +0200 @@ -1,21 +1,11 @@ -Metadata-Version: 1.2 +Metadata-Version: 2.1 Name: scikit-sparse -Version: 0.4.5 +Version: 0.4.12 Summary: Scikit sparse matrix package Home-page: https://github.com/scikit-sparse/scikit-sparse Maintainer: Justin Ellis Maintainer-email: justin.elli...@gmail.com License: BSD -Description: Sparse matrix tools. - - This is a home for sparse matrix code in Python that plays well with - scipy.sparse, but that is somehow unsuitable for inclusion in scipy - proper. Usually this will be because it is released under the GPL. - - So far we have a wrapper for the CHOLMOD library for sparse Cholesky - decomposition. Further contributions are welcome! - -Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console Classifier: Intended Audience :: Developers @@ -29,4 +19,16 @@ Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 -Requires-Python: >=3.6, <3.10 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Requires-Python: >=3.6, <3.12 +License-File: LICENSE.txt + +Sparse matrix tools. + +This is a home for sparse matrix code in Python that plays well with +scipy.sparse, but that is somehow unsuitable for inclusion in scipy +proper. Usually this will be because it is released under the GPL. + +So far we have a wrapper for the CHOLMOD library for sparse Cholesky +decomposition. Further contributions are welcome! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/README.md new/scikit-sparse-0.4.12/README.md --- old/scikit-sparse-0.4.5/README.md 2021-04-03 13:32:27.000000000 +0200 +++ new/scikit-sparse-0.4.12/README.md 2023-07-21 06:58:55.000000000 +0200 @@ -1,7 +1,8 @@ [](https://github.com/scikit-sparse/scikit-sparse/releases/latest) [](https://pypi.org/project/scikit-sparse/) -[](https://github.com/scikit-sparse/scikit-sparse/actions/workflows/ci_test.yml) -[]() +[](https://anaconda.org/conda-forge/scikit-sparse) +[](https://github.com/scikit-sparse/scikit-sparse/actions/workflows/ci_test.yml) +[]() [](https://github.com/scikit-sparse/scikit-sparse/blob/master/LICENSE.txt) # scikit-sparse @@ -15,6 +16,8 @@ ## Installation +### With `pip` + For pip installs of `scikit-sparse` depend on the suite-sparse library which can be installed via: ```bash # mac @@ -29,6 +32,48 @@ pip install scikit-sparse ``` +If you suite-sparse library is installed in a non-standard place and you get errors when installing with `pip` you can use the environment +variables: +* `SUITESPARSE_INCLUDE_DIR` +* `SUITESPARSE_LIBRARY_DIR` + +at runtime so the compiler can find them. For example, lets say your suite-sparse installation is in `/opt/local` then you can run +```bash +SUITESPARSE_INCLUDE_DIR=/opt/local/include SUITESPARSE_LIBRARY_DIR=/opt/local/lib pip install scikit-sparse +``` + +### With `conda` +The `conda` package comes with `suite-sparse` packaged as a dependency so all you need to do is: + +```bash +conda install -c conda-forge scikit-sparse +``` + +### Windows installation +This was tested with a Anaconda 3 installation and Python 3.8 + +0. Install requirements + - `conda install -c conda-forge cython` - tested with v0.29.32 + - `conda install -c conda-forge suitesparse` - tested with v5.4.0 + - optional (included in the build dependencies of `scikit-sparse`): + - `conda install -c conda-forge numpy` - tested with v1.23.2 + - `conda install -c conda-forge scipy` - tested with v1.9.1 + +1. Download Microsoft Build Tools for C++ from https://visualstudio.microsoft.com/de/visual-cpp-build-tools/ (tested with 2022, should work with 2015 or newer) + +2. Install Visual Studio Build Tools + 1. Choose Workloads + 2. Check "Desktop development with C++" + 3. Keep standard settings + +3. Run in a Powershell + - `$env:SUITESPARSE_INCLUDE_DIR='C:/Anaconda3/envs/<YOUR ENVIRONMENT NAME HERE>/Library/include/suitesparse'` + - `$env:SUITESPARSE_LIBRARY_DIR='C:/Anaconda3/envs/<YOUR ENVIRONMENT NAME HERE>/Library/lib'` + - `pip install scikit-sparse` + +4. Test `from sksparse.cholmod import cholesky` + + ## License The wrapper code contained in this package is released under a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/pyproject.toml new/scikit-sparse-0.4.12/pyproject.toml --- old/scikit-sparse-0.4.5/pyproject.toml 2021-04-03 13:32:27.000000000 +0200 +++ new/scikit-sparse-0.4.12/pyproject.toml 2023-07-21 06:58:55.000000000 +0200 @@ -1,6 +1,6 @@ [tool.black] line-length = 120 -target_version = ['py36'] +target_version = ['py38'] include = '\.pyi?$' exclude = ''' @@ -23,11 +23,13 @@ [build-system] requires = [ "setuptools>=40.8.0", - "wheel", + "wheel", "Cython>=0.22", 'numpy==1.13.3; python_version=="3.6"', 'numpy==1.14.5; python_version=="3.7"', 'numpy==1.17.3; python_version=="3.8"', 'numpy==1.19.3; python_version=="3.9"', + 'numpy==1.23.1; python_version=="3.10"', + 'numpy==1.23.5; python_version=="3.11"', ] build-backend = "setuptools.build_meta" \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/scikit_sparse.egg-info/PKG-INFO new/scikit-sparse-0.4.12/scikit_sparse.egg-info/PKG-INFO --- old/scikit-sparse-0.4.5/scikit_sparse.egg-info/PKG-INFO 2021-04-03 13:32:43.000000000 +0200 +++ new/scikit-sparse-0.4.12/scikit_sparse.egg-info/PKG-INFO 2023-07-21 06:59:19.000000000 +0200 @@ -1,21 +1,11 @@ -Metadata-Version: 1.2 +Metadata-Version: 2.1 Name: scikit-sparse -Version: 0.4.5 +Version: 0.4.12 Summary: Scikit sparse matrix package Home-page: https://github.com/scikit-sparse/scikit-sparse Maintainer: Justin Ellis Maintainer-email: justin.elli...@gmail.com License: BSD -Description: Sparse matrix tools. - - This is a home for sparse matrix code in Python that plays well with - scipy.sparse, but that is somehow unsuitable for inclusion in scipy - proper. Usually this will be because it is released under the GPL. - - So far we have a wrapper for the CHOLMOD library for sparse Cholesky - decomposition. Further contributions are welcome! - -Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console Classifier: Intended Audience :: Developers @@ -29,4 +19,16 @@ Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 -Requires-Python: >=3.6, <3.10 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Requires-Python: >=3.6, <3.12 +License-File: LICENSE.txt + +Sparse matrix tools. + +This is a home for sparse matrix code in Python that plays well with +scipy.sparse, but that is somehow unsuitable for inclusion in scipy +proper. Usually this will be because it is released under the GPL. + +So far we have a wrapper for the CHOLMOD library for sparse Cholesky +decomposition. Further contributions are welcome! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/scikit_sparse.egg-info/SOURCES.txt new/scikit-sparse-0.4.12/scikit_sparse.egg-info/SOURCES.txt --- old/scikit-sparse-0.4.5/scikit_sparse.egg-info/SOURCES.txt 2021-04-03 13:32:43.000000000 +0200 +++ new/scikit-sparse-0.4.12/scikit_sparse.egg-info/SOURCES.txt 2023-07-21 06:59:19.000000000 +0200 @@ -19,4 +19,5 @@ sksparse/test_data/well1033.mtx.gz sksparse/test_data/well1033_rhs1.mtx.gz sksparse/test_data/well1850.mtx.gz -sksparse/test_data/well1850_rhs1.mtx.gz \ No newline at end of file +sksparse/test_data/well1850_rhs1.mtx.gz +tests/test_cholmod.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/setup.py new/scikit-sparse-0.4.12/setup.py --- old/scikit-sparse-0.4.5/setup.py 2021-04-03 13:32:27.000000000 +0200 +++ new/scikit-sparse-0.4.12/setup.py 2023-07-21 06:58:55.000000000 +0200 @@ -10,7 +10,7 @@ # 2016-2017 Joscha Reimer <j...@informatik.uni-kiel.de> # 2021- Justin Ellis <justin.elli...@gmail.com> -"""Sparse matrix tools. +"""Sparse matrix tools. This is a home for sparse matrix code in Python that plays well with scipy.sparse, but that is somehow unsuitable for inclusion in scipy @@ -20,6 +20,13 @@ decomposition. Further contributions are welcome! """ +import os +import sys + +import numpy as np +from Cython.Build import cythonize +from setuptools import Extension, find_packages, setup + DISTNAME = "scikit-sparse" DESCRIPTION = "Scikit sparse matrix package" LONG_DESCRIPTION = __doc__ @@ -28,21 +35,33 @@ URL = "https://github.com/scikit-sparse/scikit-sparse" LICENSE = "BSD" -import sys -import numpy as np -from Cython.Build import cythonize -from setuptools import Extension, find_packages, setup +INCLUDE_DIRS = [ + np.get_include(), + sys.prefix + "/include", + # Debian's suitesparse-dev installs to + # /usr/include/suitesparse + "/usr/include/suitesparse", +] +LIBRARY_DIRS = [] + +user_include_dir = os.getenv("SUITESPARSE_INCLUDE_DIR") +user_library_dir = os.getenv("SUITESPARSE_LIBRARY_DIR") +if user_include_dir: + INCLUDE_DIRS.append(user_include_dir) + +if user_library_dir: + LIBRARY_DIRS.append(user_library_dir) setup( install_requires=["numpy>=1.13.3", "scipy>=0.19"], - python_requires=">=3.6, <3.10", + python_requires=">=3.6, <3.12", packages=find_packages(), package_data={ "": ["test_data/*.mtx.gz"], }, name=DISTNAME, - version="0.4.5", # remember to update __init__.py + version="0.4.12", # remember to update __init__.py maintainer=MAINTAINER, maintainer_email=MAINTAINER_EMAIL, description=DESCRIPTION, @@ -63,6 +82,8 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ], # You may specify the directory where CHOLMOD is installed using the # library_dirs and include_dirs keywords in the lines below. @@ -70,14 +91,8 @@ Extension( "sksparse.cholmod", ["sksparse/cholmod.pyx"], - include_dirs=[ - np.get_include(), - sys.prefix + "/include", - # Debian's suitesparse-dev installs to - # /usr/include/suitesparse - "/usr/include/suitesparse", - ], - library_dirs=[], + include_dirs=INCLUDE_DIRS, + library_dirs=LIBRARY_DIRS, libraries=["cholmod"], ) ), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/sksparse/__init__.py new/scikit-sparse-0.4.12/sksparse/__init__.py --- old/scikit-sparse-0.4.5/sksparse/__init__.py 2021-04-03 13:32:27.000000000 +0200 +++ new/scikit-sparse-0.4.12/sksparse/__init__.py 2023-07-21 06:58:55.000000000 +0200 @@ -1 +1 @@ -__version__ = "0.4.5" +__version__ = "0.4.12" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/sksparse/cholmod.pyx new/scikit-sparse-0.4.12/sksparse/cholmod.pyx --- old/scikit-sparse-0.4.5/sksparse/cholmod.pyx 2021-04-03 13:32:27.000000000 +0200 +++ new/scikit-sparse-0.4.12/sksparse/cholmod.pyx 2023-07-21 06:58:55.000000000 +0200 @@ -39,6 +39,7 @@ #cython: binding = True #cython: language_level = 3 +#cython: legacy_implicit_noexcept = True cimport numpy as np @@ -624,7 +625,7 @@ def cholesky(self, A, beta=0): """The same as :meth:`cholesky_inplace` except that it first creates - a copy of the current :class:`Factor` and modifes the copy. + a copy of the current :class:`Factor` and modifies the copy. :returns: The new :class:`Factor` object.""" clone = self.copy() @@ -633,7 +634,7 @@ def cholesky_AAt(self, A, beta=0): """The same as :meth:`cholesky_AAt_inplace` except that it first - creates a copy of the current :class:`Factor` and modifes the copy. + creates a copy of the current :class:`Factor` and modifies the copy. :returns: The new :class:`Factor` object.""" clone = self.copy() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/sksparse/test_cholmod.py new/scikit-sparse-0.4.12/sksparse/test_cholmod.py --- old/scikit-sparse-0.4.5/sksparse/test_cholmod.py 2021-04-03 13:32:27.000000000 +0200 +++ new/scikit-sparse-0.4.12/sksparse/test_cholmod.py 2023-07-21 06:58:55.000000000 +0200 @@ -40,7 +40,7 @@ from functools import partial import os.path -from nose.tools import assert_raises +from pytest import raises as assert_raises import numpy as np from numpy.testing import assert_allclose, assert_array_equal from scipy import sparse diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/scikit-sparse-0.4.5/tests/test_cholmod.py new/scikit-sparse-0.4.12/tests/test_cholmod.py --- old/scikit-sparse-0.4.5/tests/test_cholmod.py 1970-01-01 01:00:00.000000000 +0100 +++ new/scikit-sparse-0.4.12/tests/test_cholmod.py 2023-07-21 06:58:55.000000000 +0200 @@ -0,0 +1,286 @@ +# Test code for the scikits.sparse CHOLMOD wrapper. + +# Copyright (C) 2008-2017 The scikit-sparse developers: +# +# 2008 David Cournapeau <courn...@gmail.com> +# 2009-2015 Nathaniel Smith <n...@pobox.com> +# 2010 Dag Sverre Seljebotn <da...@student.matnat.uio.no> +# 2014 Leon Barrett <lbarr...@climate.com> +# 2015 Yuri <y...@tsoft.com> +# 2016-2017 Antony Lee <anntzer....@gmail.com> +# 2016 Alex Grigorievskiy <alex.grigorievs...@gmail.com> +# 2016-2017 Joscha Reimer <j...@informatik.uni-kiel.de> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from functools import partial +import os.path + +from pytest import raises as assert_raises +import numpy as np +from numpy.testing import assert_allclose, assert_array_equal +from scipy import sparse +from sksparse.cholmod import ( + cholesky, + cholesky_AAt, + analyze, + analyze_AAt, + CholmodError, + CholmodNotPositiveDefiniteError, + _modes, + _ordering_methods, +) + +modes = tuple(_modes.keys()) +ordering_methods = tuple(_ordering_methods.keys()) + +# Match defaults of np.allclose, which were used before (and are needed). +assert_allclose = partial(assert_allclose, rtol=1e-5, atol=1e-8) + + +def test_cholesky_smoke_test(): + f = cholesky(sparse.eye(10, 10)) + d = np.arange(20).reshape(10, 2) + print("dense") + assert_allclose(f(d), d) + print("sparse") + s_csc = sparse.csc_matrix(np.eye(10)[:, :2]) + assert sparse.issparse(f(s_csc)) + assert_allclose(f(s_csc).todense(), s_csc.todense()) + print("csr") + s_csr = s_csc.tocsr() + assert sparse.issparse(f(s_csr)) + assert_allclose(f(s_csr).todense(), s_csr.todense()) + print("extract") + assert np.all(f.P() == np.arange(10)) + + +def test_writeability(): + t = cholesky(sparse.eye(10, 10))(np.arange(10)) + assert t.flags["WRITEABLE"] + + +def real_matrix(): + return sparse.csc_matrix([[10, 0, 3, 0], [0, 5, 0, -2], [3, 0, 5, 0], [0, -2, 0, 2]]) + + +def complex_matrix(): + return sparse.csc_matrix([[10, 0, 3 - 1j, 0], [0, 5, 0, -2], [3 + 1j, 0, 5, 0], [0, -2, 0, 2]]) + + +def factor_of(factor, matrix): + return np.allclose( + (factor.L() * factor.L().H).todense(), matrix.todense()[factor.P()[:, np.newaxis], factor.P()[np.newaxis, :]] + ) + + +def convert_matrix_indices_to_long_indices(matrix): + matrix.indices = np.asarray(matrix.indices, dtype=np.int64) + matrix.indptr = np.asarray(matrix.indptr, dtype=np.int64) + return matrix + + +def test_complex(): + c = complex_matrix() + fc = cholesky(c) + r = real_matrix() + fr = cholesky(r) + + assert factor_of(fc, c) + + assert_allclose(fc(np.arange(4))[:, None], c.todense().I * np.arange(4)[:, None]) + assert_allclose(fc(np.arange(4) * 1j)[:, None], c.todense().I * (np.arange(4) * 1j)[:, None]) + assert_allclose(fr(np.arange(4))[:, None], r.todense().I * np.arange(4)[:, None]) + # If we did a real factorization, we can't do solves on complex arrays: + assert_raises(CholmodError, fr, np.arange(4) * 1j) + + +def test_beta(): + for matrix in [real_matrix(), complex_matrix()]: + for beta in [0, 1, 3.4]: + matrix_plus_beta = matrix + beta * sparse.eye(*matrix.shape) + for use_long in [False, True]: + if use_long: + matrix_plus_beta = convert_matrix_indices_to_long_indices(matrix_plus_beta) + for ordering_method in ordering_methods: + for mode in modes: + f = cholesky(matrix, beta=beta, mode=mode, ordering_method=ordering_method) + L = f.L() + assert factor_of(f, matrix_plus_beta) + + +def test_update_downdate(): + m = real_matrix() + f = cholesky(m) + L = f.L()[f.P(), :] + assert factor_of(f, m) + f.update_inplace(L) + assert factor_of(f, 2 * m) + f.update_inplace(L) + assert factor_of(f, 3 * m) + f.update_inplace(L, subtract=True) + assert factor_of(f, 2 * m) + f.update_inplace(L, subtract=True) + assert factor_of(f, m) + + +def test_solve_edge_cases(): + m = real_matrix() + f = cholesky(m) + # sparse matrices give a sparse back: + assert sparse.issparse(f(sparse.eye(*m.shape).tocsc())) + # dense matrices give a dense back: + assert not sparse.issparse(f(np.eye(*m.shape))) + # 1d dense matrices are accepted and a 1d vector is returned (this matches + # the behavior of np.dot): + assert f(np.arange(m.shape[0])).shape == (m.shape[0],) + # 2d dense matrices are also accepted: + assert f(np.arange(m.shape[0])[:, np.newaxis]).shape == (m.shape[0], 1) + # But not if the dimensions are wrong...: + assert_raises(CholmodError, f, np.arange(m.shape[0] + 1)[:, np.newaxis]) + assert_raises(CholmodError, f, np.arange(m.shape[0])[np.newaxis, :]) + assert_raises(CholmodError, f, np.arange(m.shape[0])[:, np.newaxis, np.newaxis]) + # And ditto for the sparse version: + assert_raises(CholmodError, f, sparse.eye(m.shape[0] + 1, m.shape[1]).tocsc()) + + +def mm_matrix(name): + from scipy.io import mmread + + # Supposedly, it is better to use resource_stream and pass the resulting + # open file object to mmread()... but for some reason this fails? + from pkg_resources import resource_filename + + filename = resource_filename(__name__, "test_data/%s.mtx.gz" % name) + matrix = mmread(filename) + if sparse.issparse(matrix): + matrix = matrix.tocsc() + return matrix + + +def test_cholesky_matrix_market(): + for problem in ("well1033", "illc1033", "well1850", "illc1850"): + X = mm_matrix(problem) + y = mm_matrix(problem + "_rhs1") + answer = np.linalg.lstsq(X.todense(), y)[0] + XtX = (X.T * X).tocsc() + Xty = X.T * y + for mode in modes: + assert_allclose(cholesky(XtX, mode=mode)(Xty), answer) + assert_allclose(cholesky_AAt(X.T, mode=mode)(Xty), answer) + assert_allclose(cholesky(XtX, mode=mode).solve_A(Xty), answer) + assert_allclose(cholesky_AAt(X.T, mode=mode).solve_A(Xty), answer) + + f1 = analyze(XtX, mode=mode) + f2 = f1.cholesky(XtX) + assert_allclose(f2(Xty), answer) + assert_raises(CholmodError, f1, Xty) + assert_raises(CholmodError, f1.solve_A, Xty) + assert_raises(CholmodError, f1.solve_LDLt, Xty) + assert_raises(CholmodError, f1.solve_LD, Xty) + assert_raises(CholmodError, f1.solve_DLt, Xty) + assert_raises(CholmodError, f1.solve_L, Xty) + assert_raises(CholmodError, f1.solve_D, Xty) + assert_raises(CholmodError, f1.apply_P, Xty) + assert_raises(CholmodError, f1.apply_Pt, Xty) + f1.P() + assert_raises(CholmodError, f1.L) + assert_raises(CholmodError, f1.LD) + assert_raises(CholmodError, f1.L_D) + assert_raises(CholmodError, f1.L_D) + f1.cholesky_inplace(XtX) + assert_allclose(f1(Xty), answer) + + f3 = analyze_AAt(X.T, mode=mode) + f4 = f3.cholesky(XtX) + assert_allclose(f4(Xty), answer) + assert_raises(CholmodError, f3, Xty) + f3.cholesky_AAt_inplace(X.T) + assert_allclose(f3(Xty), answer) + + print(problem, mode) + for f in (f1, f2, f3, f4): + pXtX = XtX.todense()[f.P()[:, np.newaxis], f.P()[np.newaxis, :]] + assert_allclose(np.prod(f.D()), np.linalg.det(XtX.todense())) + assert_allclose((f.L() * f.L().T).todense(), pXtX) + L, D = f.L_D() + assert_allclose((L * D * L.T).todense(), pXtX) + + b = np.arange(XtX.shape[0])[:, np.newaxis] + assert_allclose(f.solve_A(b), np.dot(XtX.todense().I, b)) + assert_allclose(f(b), np.dot(XtX.todense().I, b)) + assert_allclose(f.solve_LDLt(b), np.dot((L * D * L.T).todense().I, b)) + assert_allclose(f.solve_LD(b), np.dot((L * D).todense().I, b)) + assert_allclose(f.solve_DLt(b), np.dot((D * L.T).todense().I, b)) + assert_allclose(f.solve_L(b), np.dot(L.todense().I, b)) + assert_allclose(f.solve_Lt(b), np.dot(L.T.todense().I, b)) + assert_allclose(f.solve_D(b), np.dot(D.todense().I, b)) + + assert_allclose(f.apply_P(b), b[f.P(), :]) + assert_allclose(f.apply_P(b), b[f.P(), :]) + # Pt is the inverse of P, and argsort inverts permutation + # vectors: + assert_allclose(f.apply_Pt(b), b[np.argsort(f.P()), :]) + assert_allclose(f.apply_Pt(b), b[np.argsort(f.P()), :]) + + +def test_convenience(): + A_dense_seed = np.array([[10, 0, 3, 0], [0, 5, 0, -2], [3, 0, 5, 0], [0, -2, 0, 2]]) + for dtype in (float, complex): + A_dense = np.array(A_dense_seed, dtype=dtype) + A_sp = sparse.csc_matrix(A_dense) + for use_long in [False, True]: + if use_long: + A_sp = convert_matrix_indices_to_long_indices(A_sp) + for ordering_method in ordering_methods: + for mode in modes: + print("----") + print(dtype) + print(A_sp.indices.dtype) + print(use_long) + print(ordering_method) + print(mode) + print("----") + f = cholesky(A_sp, mode=mode, ordering_method=ordering_method) + print(f.D()) + assert_allclose(f.det(), np.linalg.det(A_dense)) + assert_allclose(f.logdet(), np.log(np.linalg.det(A_dense))) + assert_allclose(f.slogdet(), [1, np.log(np.linalg.det(A_dense))]) + assert_allclose((f.inv() * A_sp).todense(), np.eye(4)) + + +def test_CholmodNotPositiveDefiniteError(): + A = -sparse.eye(4).tocsc() + f = cholesky(A) + assert_raises(CholmodNotPositiveDefiniteError, f.L) + + +def test_natural_ordering_method(): + A = real_matrix() + f = cholesky(A, ordering_method="natural") + p = f.P() + assert_array_equal(p, np.arange(len(p))) ++++++ scipy111.patch ++++++ >From 179e69774584163a7827b5ee23f1e0096d7eeec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4ger?= <jae...@mfk.fau.de> Date: Tue, 29 Aug 2023 16:15:42 +0200 Subject: [PATCH] Fix breaking changes in isspmatrix of scipy >=1.11.0, discontinuing compatibility with csc_array Details see https://github.com/scipy/scipy/pull/18528 --- sksparse/cholmod.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sksparse/cholmod.pyx b/sksparse/cholmod.pyx index 861029d..9eceb8c 100644 --- a/sksparse/cholmod.pyx +++ b/sksparse/cholmod.pyx @@ -403,12 +403,12 @@ cdef void _error_handler( warnings.warn(full_msg, CholmodWarning) def _check_for_csc(m): - if not sparse.isspmatrix_csc(m): + if not sparse.isspmatrix_csc(m) or isinstance(m, sparse.csc_array): warnings.warn("converting matrix of class %s to CSC format" % (m.__class__.__name__,), CholmodTypeConversionWarning) m = m.tocsc() - assert sparse.isspmatrix_csc(m) + assert sparse.isspmatrix_csc(m) or isinstance(m, sparse.csc_array) return m cdef class Common: