sparseqr 1.2.1__tar.gz → 1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ *.pyc
2
+ *.pyo
3
+ _spqr.*
@@ -0,0 +1,53 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [v1.4] - 2025-01-28
10
+ ### Fixed
11
+ - Modernized the build system (`pyproject.toml`).
12
+ - Changed the way suite-sparse is found to be more robust.
13
+
14
+ ## [v1.3] - 2025-01-09
15
+ ### Added
16
+ - Bindings for `qr_factorize` and `qmult` (thanks to jkrokowski)
17
+
18
+ ### Fixed
19
+ - Compatibility with more environments (more search paths, newer numpy, setuptools dependency)
20
+ - Readme example uses `spsolve_triangular`.
21
+
22
+ ## [v1.2.1] - 2023-04-12
23
+ ### Fixed
24
+ - Fixed a memory leak in `qr()` and `rz()`.
25
+ ### Changed
26
+ - Bumped minimal Python version to 3.8.
27
+ - `rz()` is called by the test script. Its output is ignored.
28
+
29
+ ## [v1.2] - 2022-05-27
30
+ ### Added
31
+ - Added support for partial "economy" decompositions. (Christoph Hansknecht <c.hansknecht@tu-braunschweig.de>): 'The "economy" option can be used in SPQR to compute a QR factorization of a (m x n) matrix with m < n consisting of blocks Q_1, and Q_2, where Q_1 has as shape of (m x n) and Q_2 of (m x k - n). For k = n we get the reduced form, for k = m the full one. For k in between m and n, SPQR yields a block that spans part of the kernel of A. This patch adds this functionality to PySPQR.'
32
+ - Added support for macOS on arm64.
33
+
34
+ ## [v1.1.2] - 2021-08-09
35
+ ### Added
36
+ - Added rz recomposition (thanks to Ben Smith <bsmith@apl.washington.edu>)
37
+ - Added support for "economy" decomposition. (Jeffrey Bouas <ignirtoq@gmail.com>)
38
+ ### Changed
39
+ - Supports conda environments (thanks to Ben Smith <bsmith@apl.washington.edu> and Sterling Baird <sterling.baird@icloud.com>)
40
+
41
+ ## [v1.0.0] - 2017-08-31
42
+ ### Added
43
+ - Installation and packaging using `setuptools`
44
+ ### Changed
45
+ - Rename module `spqr` to `sparseqr`
46
+ - Clean up public API: `qr`, `solve`, `permutation_vector_to_matrix`
47
+
48
+ ## [v1.0.0] - 2017-08-31
49
+ ### Added
50
+ - Installation and packaging using `setuptools` (thanks to Juha Jeronen <juha.jeronen@tut.fi>)
51
+ ### Changed
52
+ - Rename module `spqr` to `sparseqr`
53
+ - Clean up public API: `qr`, `solve`, `permutation_vector_to_matrix`
sparseqr-1.4/PKG-INFO ADDED
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.3
2
+ Name: sparseqr
3
+ Version: 1.4
4
+ Summary: Python wrapper for SuiteSparseQR
5
+ Keywords: suitesparse,bindings,wrapper,scipy,numpy,qr-decomposition,qr-factorisation,sparse-matrix,sparse-linear-system,sparse-linear-solver
6
+ Author-email: Yotam Gingold <yotam@yotamgingold.com>
7
+ Requires-Python: >= 3.8
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: numpy >1.2
10
+ Requires-Dist: scipy >= 1.0
11
+ Requires-Dist: cffi >= 1.0
12
+ Requires-Dist: setuptools >35
13
+ Project-URL: homepage, https://github.com/yig/PySPQR
14
+ Project-URL: source, https://github.com/yig/PySPQR
15
+
16
+ # Python wrapper for SuiteSparseQR
17
+
18
+ This module wraps the [SuiteSparseQR](http://faculty.cse.tamu.edu/davis/suitesparse.html)
19
+ decomposition function for use with [SciPy](http://www.scipy.org).
20
+ This is Matlab's sparse `[Q,R,E] = qr()`.
21
+ For some reason, no one ever wrapped that function of SuiteSparseQR for Python.
22
+
23
+ Also wrapped are the SuiteSparseQR solvers for ``A x = b`` for the cases with sparse `A` and dense or sparse `b`.
24
+ This is especially useful for solving sparse overdetermined linear systems in the least-squares sense.
25
+ Here `A` is of size m-by-n and `b` is m-by-k (storing `k` different right-hand side vectors, each considered separately).
26
+
27
+ # Usage
28
+
29
+ ```python
30
+ import numpy
31
+ import scipy.sparse.linalg
32
+ import sparseqr
33
+
34
+ # QR decompose a sparse matrix M such that Q R = M E
35
+ #
36
+ M = scipy.sparse.rand( 10, 10, density = 0.1 )
37
+ Q, R, E, rank = sparseqr.qr( M )
38
+ print( "Should be approximately zero:", abs( Q*R - M*sparseqr.permutation_vector_to_matrix(E) ).sum() )
39
+
40
+ # Solve many linear systems "M x = b for b in columns(B)"
41
+ #
42
+ B = scipy.sparse.rand( 10, 5, density = 0.1 ) # many RHS, sparse (could also have just one RHS with shape (10,))
43
+ x = sparseqr.solve( M, B, tolerance = 0 )
44
+
45
+ # Solve an overdetermined linear system A x = b in the least-squares sense
46
+ #
47
+ # The same routine also works for the usual non-overdetermined case.
48
+ #
49
+ A = scipy.sparse.rand( 20, 10, density = 0.1 ) # 20 equations, 10 unknowns
50
+ b = numpy.random.random(20) # one RHS, dense, but could also have many (in shape (20,k))
51
+ x = sparseqr.solve( A, b, tolerance = 0 )
52
+ ## Call `rz()`:
53
+ sparseqr.rz( A, b, tolerance = 0 )
54
+
55
+ # Solve a linear system M x = B via QR decomposition
56
+ #
57
+ # This approach is slow due to the explicit construction of Q, but may be
58
+ # useful if a large number of systems need to be solved with the same M.
59
+ #
60
+ M = scipy.sparse.rand( 10, 10, density = 0.1 )
61
+ Q, R, E, rank = sparseqr.qr( M )
62
+ r = rank # r could be min(M.shape) if M is full-rank
63
+
64
+ # The system is only solvable if the lower part of Q.T @ B is all zero:
65
+ print( "System is solvable if this is zero (unlikely for a random matrix):", abs( (( Q.tocsc()[:,r:] ).T ).dot( B ) ).sum() )
66
+
67
+ # Systems with large non-square matrices can benefit from "economy" decomposition.
68
+ M = scipy.sparse.rand( 20, 5, density=0.1 )
69
+ B = scipy.sparse.rand( 20, 5, density = 0.1 )
70
+ Q, R, E, rank = sparseqr.qr( M )
71
+ print("Q shape (should be 20x20):", Q.shape)
72
+ print("R shape (should be 20x5):", R.shape)
73
+ Q, R, E, rank = sparseqr.qr( M, economy=True )
74
+ print("Q shape (should be 20x5):", Q.shape)
75
+ print("R shape (should be 5x5):", R.shape)
76
+
77
+
78
+ R = R.tocsr()[:r,:r] #for best performance, spsolve_triangular() wants the Matrix to be in CSR format.
79
+ Q = Q.tocsc()[:,:r] # Use CSC format for fast indexing of columns.
80
+ QB = (Q.T).dot(B).todense() # spsolve_triangular() need the RHS in array format.
81
+ result = scipy.sparse.linalg.spsolve_triangular(R, QB, lower=False)
82
+
83
+ # Recover a solution (as a dense array):
84
+ x = numpy.zeros( ( M.shape[1], B.shape[1] ), dtype = result.dtype )
85
+ x[:r] = result
86
+ x[E] = x.copy()
87
+
88
+ # Recover a solution (as a sparse matrix):
89
+ x = scipy.sparse.vstack( ( result, scipy.sparse.coo_matrix( ( M.shape[1] - rank, B.shape[1] ), dtype = result.dtype ) ) )
90
+ x.row = E[ x.row ]
91
+ ```
92
+
93
+ # Installation
94
+
95
+ Before installing this module, you must first install [SuiteSparseQR](http://faculty.cse.tamu.edu/davis/suitesparse.html). You can do that via conda (`conda install suitesparse`) or your system's package manager (macOS: `brew install suitesparse`; debian/ubuntu linux: `apt-get install libsuitesparse-dev`).
96
+
97
+ Now you are ready to install this module.
98
+
99
+ ## Via `pip`
100
+
101
+ From PyPI:
102
+
103
+ ```bash
104
+ pip install sparseqr
105
+ ```
106
+
107
+ From GitHub:
108
+
109
+ ```bash
110
+ pip install git+https://github.com/yig/PySPQR.git
111
+ ```
112
+
113
+ ## Directly
114
+
115
+ Copy the three `sparseqr/*.py` files next to your source code,
116
+ or leave them in their directory and call it as a module.
117
+
118
+
119
+ # Deploy
120
+
121
+ 1. Change the version in:
122
+
123
+ ```
124
+ sparseqr/__init__.py
125
+ pyproject.toml
126
+ ```
127
+
128
+ 2. Update `CHANGELOG.md`
129
+
130
+ 3. Run:
131
+
132
+ ```
133
+ flit publish --format sdist
134
+ ```
135
+
136
+ We don't publish binary wheels, because it must be compiled against suite-sparse as a system dependency. We could publish a `none-any` wheel, which would cause compilation to happen the first time the module is imported rather than when it is installed. Is there a point to that?
137
+
138
+ # Known issues
139
+
140
+ `pip uninstall sparseqr` won't remove the generated libraries. It will list them with a warning.
141
+
142
+ # Tested on
143
+
144
+ - Python 3.9, 3.13.
145
+ - Conda and not conda.
146
+ - macOS, Ubuntu Linux, and Linux Mint.
147
+
148
+ PYTHONPATH='.:$PYTHONPATH' python3 test/test.py
149
+
150
+ # Dependencies
151
+
152
+ These are installed via pip:
153
+
154
+ * [SciPy/NumPy](http://www.scipy.org)
155
+ * [cffi](http://cffi.readthedocs.io/)
156
+
157
+ These must be installed manually:
158
+
159
+ * [SuiteSparseQR](http://faculty.cse.tamu.edu/davis/suitesparse.html) (macOS: `brew install suitesparse`; debian/ubuntu linux: `apt-get install libsuitesparse-dev`)
160
+
161
+ # License
162
+
163
+ Public Domain [CC0](http://creativecommons.org/publicdomain/zero/1.0/)
164
+
@@ -59,24 +59,28 @@ Q, R, E, rank = sparseqr.qr( M, economy=True )
59
59
  print("Q shape (should be 20x5):", Q.shape)
60
60
  print("R shape (should be 5x5):", R.shape)
61
61
 
62
- # Use CSC format for fast indexing of columns.
63
- R = R.tocsc()[:r,:r]
64
- Q = Q.tocsc()[:,:r]
65
- QB = (Q.T).dot(B).tocsc() # for best performance, spsolve() wants the RHS to be in CSC format.
66
- result = scipy.sparse.linalg.spsolve(R, QB)
62
+
63
+ R = R.tocsr()[:r,:r] #for best performance, spsolve_triangular() wants the Matrix to be in CSR format.
64
+ Q = Q.tocsc()[:,:r] # Use CSC format for fast indexing of columns.
65
+ QB = (Q.T).dot(B).todense() # spsolve_triangular() need the RHS in array format.
66
+ result = scipy.sparse.linalg.spsolve_triangular(R, QB, lower=False)
67
67
 
68
68
  # Recover a solution (as a dense array):
69
69
  x = numpy.zeros( ( M.shape[1], B.shape[1] ), dtype = result.dtype )
70
- x[:r] = result.todense()
70
+ x[:r] = result
71
71
  x[E] = x.copy()
72
72
 
73
73
  # Recover a solution (as a sparse matrix):
74
- x = scipy.sparse.vstack( ( result.tocoo(), scipy.sparse.coo_matrix( ( M.shape[1] - rank, B.shape[1] ), dtype = result.dtype ) ) )
74
+ x = scipy.sparse.vstack( ( result, scipy.sparse.coo_matrix( ( M.shape[1] - rank, B.shape[1] ), dtype = result.dtype ) ) )
75
75
  x.row = E[ x.row ]
76
76
  ```
77
77
 
78
78
  # Installation
79
79
 
80
+ Before installing this module, you must first install [SuiteSparseQR](http://faculty.cse.tamu.edu/davis/suitesparse.html). You can do that via conda (`conda install suitesparse`) or your system's package manager (macOS: `brew install suitesparse`; debian/ubuntu linux: `apt-get install libsuitesparse-dev`).
81
+
82
+ Now you are ready to install this module.
83
+
80
84
  ## Via `pip`
81
85
 
82
86
  From PyPI:
@@ -91,22 +95,6 @@ From GitHub:
91
95
  pip install git+https://github.com/yig/PySPQR.git
92
96
  ```
93
97
 
94
- ## Manually from GitHub
95
-
96
- As user:
97
-
98
- ```bash
99
- git clone https://github.com/yig/PySPQR.git
100
- cd PySPQR
101
- python setup.py install --user
102
- ```
103
-
104
- As admin, change the last command to
105
-
106
- ```bash
107
- sudo python setup.py install
108
- ```
109
-
110
98
  ## Directly
111
99
 
112
100
  Copy the three `sparseqr/*.py` files next to your source code,
@@ -119,7 +107,6 @@ or leave them in their directory and call it as a module.
119
107
 
120
108
  ```
121
109
  sparseqr/__init__.py
122
- setup.py
123
110
  pyproject.toml
124
111
  ```
125
112
 
@@ -128,27 +115,33 @@ or leave them in their directory and call it as a module.
128
115
  3. Run:
129
116
 
130
117
  ```
131
- poetry build -f sdist
132
- poetry publish
118
+ flit publish --format sdist
133
119
  ```
134
120
 
121
+ We don't publish binary wheels, because it must be compiled against suite-sparse as a system dependency. We could publish a `none-any` wheel, which would cause compilation to happen the first time the module is imported rather than when it is installed. Is there a point to that?
122
+
135
123
  # Known issues
136
124
 
137
125
  `pip uninstall sparseqr` won't remove the generated libraries. It will list them with a warning.
138
126
 
139
127
  # Tested on
140
128
 
141
- - Python 2.7, 3.4, 3.5, and 3.9.
129
+ - Python 3.9, 3.13.
142
130
  - Conda and not conda.
143
- - Mac OS X, Ubuntu Linux and Linux Mint.
131
+ - macOS, Ubuntu Linux, and Linux Mint.
144
132
 
145
133
  PYTHONPATH='.:$PYTHONPATH' python3 test/test.py
146
134
 
147
135
  # Dependencies
148
136
 
137
+ These are installed via pip:
138
+
149
139
  * [SciPy/NumPy](http://www.scipy.org)
140
+ * [cffi](http://cffi.readthedocs.io/)
141
+
142
+ These must be installed manually:
143
+
150
144
  * [SuiteSparseQR](http://faculty.cse.tamu.edu/davis/suitesparse.html) (macOS: `brew install suitesparse`; debian/ubuntu linux: `apt-get install libsuitesparse-dev`)
151
- * [cffi](http://cffi.readthedocs.io/) (`pip install cffi`)
152
145
 
153
146
  # License
154
147
 
@@ -0,0 +1,29 @@
1
+ [project]
2
+ name = "sparseqr"
3
+ version = "1.4"
4
+ description = "Python wrapper for SuiteSparseQR"
5
+ authors = [{name = "Yotam Gingold", email = "yotam@yotamgingold.com"}]
6
+ license = {text = "Public Domain CC0"}
7
+ readme = "README.md"
8
+ keywords = ["suitesparse", "bindings", "wrapper", "scipy", "numpy", "qr-decomposition", "qr-factorisation", "sparse-matrix", "sparse-linear-system", "sparse-linear-solver"]
9
+
10
+ requires-python = ">= 3.8"
11
+
12
+ dependencies = [
13
+ "numpy >1.2",
14
+ "scipy >= 1.0",
15
+ "cffi >= 1.0",
16
+ "setuptools >35",
17
+ ]
18
+
19
+ [project.urls]
20
+ homepage = "https://github.com/yig/PySPQR"
21
+ source = "https://github.com/yig/PySPQR"
22
+
23
+ [build-system]
24
+ requires = ["setuptools>=61"]
25
+ build-backend = "setuptools.build_meta"
26
+
27
+ #[tool.setuptools.packages.find]
28
+ # include = ["test/*.py", "README.md", "LICENSE.md"]
29
+ #exclude = ["sparseqr/_sparseqr*"]
sparseqr-1.4/setup.py ADDED
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ from __future__ import division, print_function, absolute_import
4
+
5
+ from setuptools import setup #, dist
6
+ import os
7
+
8
+ setup(
9
+ # See
10
+ # http://setuptools.readthedocs.io/en/latest/setuptools.html
11
+ #
12
+ setup_requires = ["cffi>=1.0.0"],
13
+ cffi_modules = ["sparseqr/sparseqr_gen.py:ffibuilder"],
14
+ install_requires = ["cffi>=1.0.0"],
15
+ )
@@ -17,8 +17,8 @@ See the docstrings of the individual functions for details.
17
17
 
18
18
  from __future__ import absolute_import
19
19
 
20
- __version__ = '1.2.1'
20
+ __version__ = '1.4'
21
21
 
22
22
  # import the important things into the package's top-level namespace.
23
- from .sparseqr import qr, rz, solve, permutation_vector_to_matrix
23
+ from .sparseqr import qr, rz, solve, permutation_vector_to_matrix, qr_factorize,qmult
24
24
 
@@ -351,6 +351,77 @@ def qr( A, tolerance = None, economy = None ):
351
351
  return scipy_Q, scipy_R, E, rank
352
352
 
353
353
 
354
+ def qr_factorize( A, tolerance = None):
355
+ '''
356
+ Given a sparse matrix A,
357
+ returns a QR factorization in householder form
358
+
359
+ If optional `tolerance` parameter is negative, it has the following meanings:
360
+ #define SPQR_DEFAULT_TOL ... /* if tol <= -2, the default tol is used */
361
+ #define SPQR_NO_TOL ... /* if -2 < tol < 0, then no tol is used */
362
+
363
+ For A an m-by-n matrix, Q will be m-by-m and R will be m-by-n.
364
+
365
+ The performance-optimal format for A is scipy.sparse.coo_matrix.
366
+
367
+ '''
368
+
369
+ chol_A = scipy2cholmodsparse( A )
370
+
371
+ if tolerance is None: tolerance = lib.SPQR_DEFAULT_TOL
372
+
373
+ QR = lib.SuiteSparseQR_C_factorize(
374
+ ## Input
375
+ lib.SPQR_ORDERING_DEFAULT,
376
+ tolerance,
377
+ chol_A,
378
+ cc
379
+ )
380
+
381
+ cholmod_free_sparse( chol_A )
382
+ ## Apparently we don't need to do this. (I get a malloc error.)
383
+ # lib.cholmod_l_free( A.shape[1], ffi.sizeof("SuiteSparse_long"), chol_E, cc )
384
+
385
+ return QR
386
+
387
+
388
+ def qmult( QR, X, method=1):
389
+ '''
390
+ Given a QR factorization struct
391
+ a dense matrix
392
+ returns Q applied to X in a dense matrix
393
+
394
+ From the suitesparse documentation:
395
+ /*
396
+ Applies Q in Householder form (as stored in the QR factorization object
397
+ returned by SuiteSparseQR_C_factorize) to a dense matrix X.
398
+
399
+ method SPQR_QTX (0): Y = Q'*X
400
+ method SPQR_QX (1): Y = Q*X
401
+ method SPQR_XQT (2): Y = X*Q'
402
+ method SPQR_XQ (3): Y = X*Q
403
+ */
404
+
405
+ '''
406
+
407
+ chol_X = numpy2cholmoddense( X )
408
+
409
+ chol_Y = lib.SuiteSparseQR_C_qmult(
410
+ ## Input
411
+ method,
412
+ QR,
413
+ chol_X,
414
+ cc
415
+ )
416
+ numpy_Y = cholmoddense2numpy( chol_Y )
417
+
418
+ ## Free cholmod stuff
419
+ cholmod_free_dense( chol_X )
420
+ cholmod_free_dense( chol_Y )
421
+
422
+ return numpy_Y
423
+
424
+
354
425
  def solve( A, b, tolerance = None ):
355
426
  '''
356
427
  Given a sparse m-by-n matrix A, and dense or sparse m-by-k matrix (storing k RHS vectors) b,
@@ -4,9 +4,7 @@ License: Public Domain [CC0](http://creativecommons.org/publicdomain/zero/1.0/)
4
4
  Description: Wrapper for SuiteSparse qr() and solve() functions. Matlab and Julia have it, Python should have it, too.
5
5
  '''
6
6
 
7
- from __future__ import print_function, division, absolute_import
8
7
  import os
9
- from os.path import join, expanduser
10
8
  import platform
11
9
 
12
10
  from cffi import FFI
@@ -15,20 +13,21 @@ include_dirs = []
15
13
  library_dirs = []
16
14
  libraries = ['spqr']
17
15
 
18
- if platform.system() == 'Windows':
19
- include_dirs.append( join('C:', 'Program Files', 'Python', 'suitesparse') )
16
+ ## If we're using conda, use the conda paths
17
+ if 'CONDA_PREFIX' in os.environ:
18
+ include_dirs.append( os.path.join(os.environ['CONDA_PREFIX'], 'include', 'suitesparse') )
19
+ library_dirs.append( os.path.join(os.environ['CONDA_PREFIX'], 'lib') )
20
+
21
+ ## Otherwise, add common system-wide directories
20
22
  else:
21
- include_dirs.append( '/usr/include/suitesparse' )
22
- ## Homebrew on macOS arm64 puts headers and libraries
23
- ## in `/opt/homebrew`. That's not on the default path, so add them:
24
- include_dirs.append( '/opt/homebrew/include' )
25
- library_dirs.append( '/opt/homebrew/lib' )
26
-
27
- # for compatibility with conda envs
28
- if 'CONDA_DEFAULT_ENV' in os.environ:
29
- homedir = expanduser("~")
30
- include_dirs.append( join(homedir, 'anaconda3', 'envs', os.environ['CONDA_DEFAULT_ENV'], 'Library', 'include', 'suitesparse') )
31
- include_dirs.append( join(homedir, 'miniconda3', 'envs', os.environ['CONDA_DEFAULT_ENV'], 'Library', 'include', 'suitesparse') )
23
+ if platform.system() == 'Windows':
24
+ include_dirs.append( join('C:', 'Program Files', 'Python', 'suitesparse') )
25
+ else:
26
+ include_dirs.append( '/usr/include/suitesparse' )
27
+ ## Homebrew on macOS arm64 puts headers and libraries
28
+ ## in `/opt/homebrew`. That's not on the default path, so add them:
29
+ include_dirs.append( '/opt/homebrew/include/suitesparse' )
30
+ library_dirs.append( '/opt/homebrew/lib' )
32
31
 
33
32
  if platform.system() == 'Windows':
34
33
  # https://github.com/yig/PySPQR/issues/6
@@ -37,6 +36,11 @@ if platform.system() == 'Windows':
37
36
 
38
37
  ffibuilder = FFI()
39
38
 
39
+ ## Uncomment this and install with `pip install -v` to see the arguments to `set_source`.
40
+ # print( "cffi include_dirs:", include_dirs )
41
+ # print( "cffi library_dirs:", library_dirs )
42
+ # print( "cffi libraries:", libraries )
43
+
40
44
  ffibuilder.set_source( "sparseqr._sparseqr",
41
45
  """#include <SuiteSparseQR_C.h>
42
46
  """,
@@ -362,6 +366,105 @@ cholmod_sparse *SuiteSparseQR_C_backslash_sparse /* returns X, or NULL */
362
366
  cholmod_common *cc /* workspace and parameters */
363
367
  ) ;
364
368
 
369
+ /* ========================================================================== */
370
+ /* === SuiteSparseQR_C_factorization ======================================== */
371
+ /* ========================================================================== */
372
+
373
+ /* A real or complex QR factorization, computed by SuiteSparseQR_C_factorize */
374
+ typedef struct SuiteSparseQR_C_factorization_struct
375
+ {
376
+ int xtype ; /* CHOLMOD_REAL or CHOLMOD_COMPLEX */
377
+ void *factors ; /* from SuiteSparseQR_factorize <double> or
378
+ SuiteSparseQR_factorize <Complex> */
379
+
380
+ } SuiteSparseQR_C_factorization ;
381
+
382
+ /* ========================================================================== */
383
+ /* === SuiteSparseQR_C_factorize ============================================ */
384
+ /* ========================================================================== */
385
+
386
+ SuiteSparseQR_C_factorization *SuiteSparseQR_C_factorize
387
+ (
388
+ /* inputs: */
389
+ int ordering, /* all, except 3:given treated as 0:fixed */
390
+ double tol, /* columns with 2-norm <= tol treated as 0 */
391
+ cholmod_sparse *A, /* m-by-n sparse matrix */
392
+ cholmod_common *cc /* workspace and parameters */
393
+ ) ;
394
+
395
+ /* ========================================================================== */
396
+ /* === SuiteSparseQR_C_symbolic ============================================= */
397
+ /* ========================================================================== */
398
+
399
+ SuiteSparseQR_C_factorization *SuiteSparseQR_C_symbolic
400
+ (
401
+ /* inputs: */
402
+ int ordering, /* all, except 3:given treated as 0:fixed */
403
+ int allow_tol, /* if TRUE allow tol for rank detection */
404
+ cholmod_sparse *A, /* m-by-n sparse matrix, A->x ignored */
405
+ cholmod_common *cc /* workspace and parameters */
406
+ ) ;
407
+
408
+ /* ========================================================================== */
409
+ /* === SuiteSparseQR_C_numeric ============================================== */
410
+ /* ========================================================================== */
411
+
412
+ int SuiteSparseQR_C_numeric
413
+ (
414
+ /* inputs: */
415
+ double tol, /* treat columns with 2-norm <= tol as zero */
416
+ cholmod_sparse *A, /* sparse matrix to factorize */
417
+ /* input/output: */
418
+ SuiteSparseQR_C_factorization *QR,
419
+ cholmod_common *cc /* workspace and parameters */
420
+ ) ;
421
+
422
+ /* ========================================================================== */
423
+ /* === SuiteSparseQR_C_free ================================================= */
424
+ /* ========================================================================== */
425
+
426
+ /* Free the QR factors computed by SuiteSparseQR_C_factorize */
427
+ int SuiteSparseQR_C_free /* returns TRUE (1) if OK, FALSE (0) otherwise*/
428
+ (
429
+ SuiteSparseQR_C_factorization **QR,
430
+ cholmod_common *cc /* workspace and parameters */
431
+ ) ;
432
+
433
+ /* ========================================================================== */
434
+ /* === SuiteSparseQR_C_solve ================================================ */
435
+ /* ========================================================================== */
436
+
437
+ cholmod_dense* SuiteSparseQR_C_solve /* returnx X, or NULL if failure */
438
+ (
439
+ int system, /* which system to solve */
440
+ SuiteSparseQR_C_factorization *QR, /* of an m-by-n sparse matrix A */
441
+ cholmod_dense *B, /* right-hand-side, m-by-k or n-by-k */
442
+ cholmod_common *cc /* workspace and parameters */
443
+ ) ;
444
+
445
+ /* ========================================================================== */
446
+ /* === SuiteSparseQR_C_qmult ================================================ */
447
+ /* ========================================================================== */
448
+
449
+ /*
450
+ Applies Q in Householder form (as stored in the QR factorization object
451
+ returned by SuiteSparseQR_C_factorize) to a dense matrix X.
452
+
453
+ method SPQR_QTX (0): Y = Q'*X
454
+ method SPQR_QX (1): Y = Q*X
455
+ method SPQR_XQT (2): Y = X*Q'
456
+ method SPQR_XQ (3): Y = X*Q
457
+ */
458
+
459
+ cholmod_dense *SuiteSparseQR_C_qmult /* returns Y, or NULL on failure */
460
+ (
461
+ /* inputs: */
462
+ int method, /* 0,1,2,3 */
463
+ SuiteSparseQR_C_factorization *QR, /* of an m-by-n sparse matrix A */
464
+ cholmod_dense *X, /* size m-by-n with leading dimension ldx */
465
+ cholmod_common *cc /* workspace and parameters */
466
+ ) ;
467
+
365
468
  #define SPQR_ORDERING_FIXED ...
366
469
  #define SPQR_ORDERING_NATURAL ...
367
470
  #define SPQR_ORDERING_COLAMD ...
@@ -64,3 +64,16 @@ x[E] = x.copy()
64
64
  # Recover a solution (as a sparse matrix):
65
65
  x = scipy.sparse.vstack( ( result.tocoo(), scipy.sparse.coo_matrix( ( M.shape[1] - rank, B.shape[1] ), dtype = result.dtype ) ) )
66
66
  x.row = E[ x.row ]
67
+
68
+ #initialize QR Factorization object
69
+ M = scipy.sparse.rand( 100, 100, density=0.05 )
70
+
71
+ #perform QR factorization, but store in Householder form
72
+ QR= sparseqr.qr_factorize( M )
73
+ X = numpy.zeros((M.shape[0],1))
74
+ #change last entry of the first column to a 1
75
+ # this allows us to construct only the first column of Q
76
+ X[-1,0]=1
77
+
78
+ Y = sparseqr.qmult(QR,X)
79
+ print("Y shape (should be 100x1):",Y.shape)
sparseqr-1.2.1/PKG-INFO DELETED
@@ -1,17 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: sparseqr
3
- Version: 1.2.1
4
- Summary: Python wrapper for SuiteSparseQR
5
- License: Public Domain CC0
6
- Author: Yotam Gingold
7
- Author-email: yotam@yotamgingold.com
8
- Requires-Python: >=3.8,<4.0
9
- Classifier: License :: Other/Proprietary License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.8
12
- Classifier: Programming Language :: Python :: 3.9
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Requires-Dist: cffi (>=1.0,<2.0)
16
- Requires-Dist: numpy (>=1.21,<2.0)
17
- Requires-Dist: scipy (>=1.0,<2.0)
@@ -1,21 +0,0 @@
1
- [tool.poetry]
2
- name = "sparseqr"
3
- version = "1.2.1"
4
- description = "Python wrapper for SuiteSparseQR"
5
- authors = ["Yotam Gingold <yotam@yotamgingold.com>"]
6
- license = "Public Domain CC0"
7
-
8
- include = ["test/*.py", "README.md", "LICENSE.md"]
9
- exclude = ["sparseqr/_sparseqr*"]
10
-
11
- [tool.poetry.dependencies]
12
- python = "^3.8"
13
- numpy = "^1.21"
14
- scipy = "^1.0"
15
- cffi = "^1.0"
16
-
17
- [tool.poetry.dev-dependencies]
18
-
19
- [build-system]
20
- requires = ["poetry-core>=1.0.0"]
21
- build-backend = "poetry.core.masonry.api"
File without changes