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 @@
 [![GitHub release (latest by 
date)](https://img.shields.io/github/v/release/scikit-sparse/scikit-sparse)](https://github.com/scikit-sparse/scikit-sparse/releases/latest)
 
[![PyPI](https://img.shields.io/pypi/v/scikit-sparse)](https://pypi.org/project/scikit-sparse/)
-[![GitHub Workflow Status 
(event)](https://img.shields.io/github/workflow/status/scikit-sparse/scikit-sparse/CI%20targets?label=CI%20Tests)](https://github.com/scikit-sparse/scikit-sparse/actions/workflows/ci_test.yml)
 
-[![Python 
Versions](https://img.shields.io/badge/python-3.6%2C%203.7%2C%203.8%2C%203.9-blue.svg)]()
+[![Conda 
Version](https://img.shields.io/conda/vn/conda-forge/scikit-sparse.svg)](https://anaconda.org/conda-forge/scikit-sparse)
+[![GitHub Workflow Status 
(event)](https://img.shields.io/github/workflow/status/scikit-sparse/scikit-sparse/CI%20targets?label=CI%20Tests)](https://github.com/scikit-sparse/scikit-sparse/actions/workflows/ci_test.yml)
+[![Python 
Versions](https://img.shields.io/badge/python-3.6%2C%203.7%2C%203.8%2C%203.9%2C%203.10-blue.svg)]()
 [![GitHub 
license](https://img.shields.io/github/license/scikit-sparse/scikit-sparse)](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:

Reply via email to