sparseqr 1.2__tar.gz → 1.3__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.
- {sparseqr-1.2 → sparseqr-1.3}/PKG-INFO +8 -5
- {sparseqr-1.2 → sparseqr-1.3}/README.md +24 -18
- {sparseqr-1.2 → sparseqr-1.3}/pyproject.toml +4 -3
- {sparseqr-1.2 → sparseqr-1.3}/sparseqr/__init__.py +2 -2
- {sparseqr-1.2 → sparseqr-1.3}/sparseqr/sparseqr.py +74 -0
- {sparseqr-1.2 → sparseqr-1.3}/sparseqr/sparseqr_gen.py +107 -2
- {sparseqr-1.2 → sparseqr-1.3}/test/test.py +24 -0
- sparseqr-1.2/setup.py +0 -30
- {sparseqr-1.2 → sparseqr-1.3}/LICENSE.md +0 -0
- {sparseqr-1.2 → sparseqr-1.3}/sparseqr/cffi_asarray.py +0 -0
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sparseqr
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3
|
|
4
4
|
Summary: Python wrapper for SuiteSparseQR
|
|
5
5
|
License: Public Domain CC0
|
|
6
6
|
Author: Yotam Gingold
|
|
7
7
|
Author-email: yotam@yotamgingold.com
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.8,<4.0
|
|
9
9
|
Classifier: License :: Other/Proprietary License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.8
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
17
|
Requires-Dist: cffi (>=1.0,<2.0)
|
|
16
|
-
Requires-Dist: numpy (
|
|
18
|
+
Requires-Dist: numpy (>1.2)
|
|
17
19
|
Requires-Dist: scipy (>=1.0,<2.0)
|
|
20
|
+
Requires-Dist: setuptools (>35)
|
|
@@ -20,7 +20,7 @@ import sparseqr
|
|
|
20
20
|
#
|
|
21
21
|
M = scipy.sparse.rand( 10, 10, density = 0.1 )
|
|
22
22
|
Q, R, E, rank = sparseqr.qr( M )
|
|
23
|
-
print( abs( Q*R - M*sparseqr.permutation_vector_to_matrix(E) ).sum() )
|
|
23
|
+
print( "Should be approximately zero:", abs( Q*R - M*sparseqr.permutation_vector_to_matrix(E) ).sum() )
|
|
24
24
|
|
|
25
25
|
# Solve many linear systems "M x = b for b in columns(B)"
|
|
26
26
|
#
|
|
@@ -34,6 +34,8 @@ x = sparseqr.solve( M, B, tolerance = 0 )
|
|
|
34
34
|
A = scipy.sparse.rand( 20, 10, density = 0.1 ) # 20 equations, 10 unknowns
|
|
35
35
|
b = numpy.random.random(20) # one RHS, dense, but could also have many (in shape (20,k))
|
|
36
36
|
x = sparseqr.solve( A, b, tolerance = 0 )
|
|
37
|
+
## Call `rz()`:
|
|
38
|
+
sparseqr.rz( A, b, tolerance = 0 )
|
|
37
39
|
|
|
38
40
|
# Solve a linear system M x = B via QR decomposition
|
|
39
41
|
#
|
|
@@ -45,31 +47,31 @@ Q, R, E, rank = sparseqr.qr( M )
|
|
|
45
47
|
r = rank # r could be min(M.shape) if M is full-rank
|
|
46
48
|
|
|
47
49
|
# The system is only solvable if the lower part of Q.T @ B is all zero:
|
|
48
|
-
print( "System is solvable if this is zero:", abs( (( Q.tocsc()[:,r:] ).T ).dot( B ) ).sum() )
|
|
50
|
+
print( "System is solvable if this is zero (unlikely for a random matrix):", abs( (( Q.tocsc()[:,r:] ).T ).dot( B ) ).sum() )
|
|
49
51
|
|
|
50
52
|
# Systems with large non-square matrices can benefit from "economy" decomposition.
|
|
51
53
|
M = scipy.sparse.rand( 20, 5, density=0.1 )
|
|
52
54
|
B = scipy.sparse.rand( 20, 5, density = 0.1 )
|
|
53
55
|
Q, R, E, rank = sparseqr.qr( M )
|
|
54
|
-
print("Q shape:", Q.shape)
|
|
55
|
-
print("R shape:", R.shape)
|
|
56
|
+
print("Q shape (should be 20x20):", Q.shape)
|
|
57
|
+
print("R shape (should be 20x5):", R.shape)
|
|
56
58
|
Q, R, E, rank = sparseqr.qr( M, economy=True )
|
|
57
|
-
print("Q shape:", Q.shape)
|
|
58
|
-
print("R shape:", R.shape)
|
|
59
|
+
print("Q shape (should be 20x5):", Q.shape)
|
|
60
|
+
print("R shape (should be 5x5):", R.shape)
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
R = R.
|
|
62
|
-
Q = Q.tocsc()[:,:r]
|
|
63
|
-
QB = (Q.T).dot(B).
|
|
64
|
-
result = scipy.sparse.linalg.
|
|
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)
|
|
65
67
|
|
|
66
68
|
# Recover a solution (as a dense array):
|
|
67
69
|
x = numpy.zeros( ( M.shape[1], B.shape[1] ), dtype = result.dtype )
|
|
68
|
-
x[:r] = result
|
|
70
|
+
x[:r] = result
|
|
69
71
|
x[E] = x.copy()
|
|
70
72
|
|
|
71
73
|
# Recover a solution (as a sparse matrix):
|
|
72
|
-
x = scipy.sparse.vstack( ( result
|
|
74
|
+
x = scipy.sparse.vstack( ( result, scipy.sparse.coo_matrix( ( M.shape[1] - rank, B.shape[1] ), dtype = result.dtype ) ) )
|
|
73
75
|
x.row = E[ x.row ]
|
|
74
76
|
```
|
|
75
77
|
|
|
@@ -115,16 +117,20 @@ or leave them in their directory and call it as a module.
|
|
|
115
117
|
|
|
116
118
|
1. Change the version in:
|
|
117
119
|
|
|
120
|
+
```
|
|
118
121
|
sparseqr/__init__.py
|
|
119
|
-
setup.py
|
|
120
|
-
pyproject.toml
|
|
122
|
+
setup.py
|
|
123
|
+
pyproject.toml
|
|
124
|
+
```
|
|
121
125
|
|
|
122
126
|
2. Update `CHANGELOG.md`
|
|
123
127
|
|
|
124
128
|
3. Run:
|
|
125
129
|
|
|
130
|
+
```
|
|
126
131
|
poetry build -f sdist
|
|
127
132
|
poetry publish
|
|
133
|
+
```
|
|
128
134
|
|
|
129
135
|
# Known issues
|
|
130
136
|
|
|
@@ -132,9 +138,9 @@ or leave them in their directory and call it as a module.
|
|
|
132
138
|
|
|
133
139
|
# Tested on
|
|
134
140
|
|
|
135
|
-
- Python 2.7, 3.4, 3.5,
|
|
141
|
+
- Python 2.7, 3.4, 3.5, 3.9, 3.13.
|
|
136
142
|
- Conda and not conda.
|
|
137
|
-
-
|
|
143
|
+
- macOS, Ubuntu Linux, and Linux Mint.
|
|
138
144
|
|
|
139
145
|
PYTHONPATH='.:$PYTHONPATH' python3 test/test.py
|
|
140
146
|
|
|
@@ -142,7 +148,7 @@ or leave them in their directory and call it as a module.
|
|
|
142
148
|
|
|
143
149
|
* [SciPy/NumPy](http://www.scipy.org)
|
|
144
150
|
* [SuiteSparseQR](http://faculty.cse.tamu.edu/davis/suitesparse.html) (macOS: `brew install suitesparse`; debian/ubuntu linux: `apt-get install libsuitesparse-dev`)
|
|
145
|
-
* [cffi](http://cffi.readthedocs.io/)
|
|
151
|
+
* [cffi](http://cffi.readthedocs.io/)
|
|
146
152
|
|
|
147
153
|
# License
|
|
148
154
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "sparseqr"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.3"
|
|
4
4
|
description = "Python wrapper for SuiteSparseQR"
|
|
5
5
|
authors = ["Yotam Gingold <yotam@yotamgingold.com>"]
|
|
6
6
|
license = "Public Domain CC0"
|
|
@@ -9,10 +9,11 @@ include = ["test/*.py", "README.md", "LICENSE.md"]
|
|
|
9
9
|
exclude = ["sparseqr/_sparseqr*"]
|
|
10
10
|
|
|
11
11
|
[tool.poetry.dependencies]
|
|
12
|
-
python = "^3.
|
|
13
|
-
numpy = "
|
|
12
|
+
python = "^3.8"
|
|
13
|
+
numpy = ">1.2"
|
|
14
14
|
scipy = "^1.0"
|
|
15
15
|
cffi = "^1.0"
|
|
16
|
+
setuptools = ">35"
|
|
16
17
|
|
|
17
18
|
[tool.poetry.dev-dependencies]
|
|
18
19
|
|
|
@@ -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.
|
|
20
|
+
__version__ = '1.3'
|
|
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
|
|
|
@@ -240,6 +240,8 @@ def rz(A, B, tolerance = None):
|
|
|
240
240
|
## Free cholmod stuff
|
|
241
241
|
cholmod_free_dense( chol_Z[0] )
|
|
242
242
|
cholmod_free_sparse( chol_R[0] )
|
|
243
|
+
cholmod_free_sparse( chol_A )
|
|
244
|
+
cholmod_free_dense( chol_b )
|
|
243
245
|
|
|
244
246
|
return scipy_Z, scipy_R, E, rank
|
|
245
247
|
|
|
@@ -342,12 +344,84 @@ def qr( A, tolerance = None, economy = None ):
|
|
|
342
344
|
## Free cholmod stuff
|
|
343
345
|
cholmod_free_sparse( chol_Q[0] )
|
|
344
346
|
cholmod_free_sparse( chol_R[0] )
|
|
347
|
+
cholmod_free_sparse( chol_A )
|
|
345
348
|
## Apparently we don't need to do this. (I get a malloc error.)
|
|
346
349
|
# lib.cholmod_l_free( A.shape[1], ffi.sizeof("SuiteSparse_long"), chol_E, cc )
|
|
347
350
|
|
|
348
351
|
return scipy_Q, scipy_R, E, rank
|
|
349
352
|
|
|
350
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
|
+
|
|
351
425
|
def solve( A, b, tolerance = None ):
|
|
352
426
|
'''
|
|
353
427
|
Given a sparse m-by-n matrix A, and dense or sparse m-by-k matrix (storing k RHS vectors) b,
|
|
@@ -21,14 +21,20 @@ else:
|
|
|
21
21
|
include_dirs.append( '/usr/include/suitesparse' )
|
|
22
22
|
## Homebrew on macOS arm64 puts headers and libraries
|
|
23
23
|
## in `/opt/homebrew`. That's not on the default path, so add them:
|
|
24
|
+
include_dirs.append( '/opt/homebrew/include/suitesparse' )
|
|
25
|
+
# Does this work for anyone? At one point I thought it worked for me, but maybe I didn't test properly.
|
|
24
26
|
include_dirs.append( '/opt/homebrew/include' )
|
|
25
27
|
library_dirs.append( '/opt/homebrew/lib' )
|
|
26
28
|
|
|
27
29
|
# for compatibility with conda envs
|
|
28
30
|
if 'CONDA_DEFAULT_ENV' in os.environ:
|
|
29
31
|
homedir = expanduser("~")
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
|
|
33
|
+
for packager in ['anaconda3','miniconda3','condaforge','miniforge','mambaforge']:
|
|
34
|
+
for sub in ['','Library']:
|
|
35
|
+
thedir=join(homedir, packager, 'envs', os.environ['CONDA_DEFAULT_ENV'], sub, 'include', 'suitesparse')
|
|
36
|
+
if os.path.isdir(thedir):
|
|
37
|
+
include_dirs.append(thedir)
|
|
32
38
|
|
|
33
39
|
if platform.system() == 'Windows':
|
|
34
40
|
# https://github.com/yig/PySPQR/issues/6
|
|
@@ -362,6 +368,105 @@ cholmod_sparse *SuiteSparseQR_C_backslash_sparse /* returns X, or NULL */
|
|
|
362
368
|
cholmod_common *cc /* workspace and parameters */
|
|
363
369
|
) ;
|
|
364
370
|
|
|
371
|
+
/* ========================================================================== */
|
|
372
|
+
/* === SuiteSparseQR_C_factorization ======================================== */
|
|
373
|
+
/* ========================================================================== */
|
|
374
|
+
|
|
375
|
+
/* A real or complex QR factorization, computed by SuiteSparseQR_C_factorize */
|
|
376
|
+
typedef struct SuiteSparseQR_C_factorization_struct
|
|
377
|
+
{
|
|
378
|
+
int xtype ; /* CHOLMOD_REAL or CHOLMOD_COMPLEX */
|
|
379
|
+
void *factors ; /* from SuiteSparseQR_factorize <double> or
|
|
380
|
+
SuiteSparseQR_factorize <Complex> */
|
|
381
|
+
|
|
382
|
+
} SuiteSparseQR_C_factorization ;
|
|
383
|
+
|
|
384
|
+
/* ========================================================================== */
|
|
385
|
+
/* === SuiteSparseQR_C_factorize ============================================ */
|
|
386
|
+
/* ========================================================================== */
|
|
387
|
+
|
|
388
|
+
SuiteSparseQR_C_factorization *SuiteSparseQR_C_factorize
|
|
389
|
+
(
|
|
390
|
+
/* inputs: */
|
|
391
|
+
int ordering, /* all, except 3:given treated as 0:fixed */
|
|
392
|
+
double tol, /* columns with 2-norm <= tol treated as 0 */
|
|
393
|
+
cholmod_sparse *A, /* m-by-n sparse matrix */
|
|
394
|
+
cholmod_common *cc /* workspace and parameters */
|
|
395
|
+
) ;
|
|
396
|
+
|
|
397
|
+
/* ========================================================================== */
|
|
398
|
+
/* === SuiteSparseQR_C_symbolic ============================================= */
|
|
399
|
+
/* ========================================================================== */
|
|
400
|
+
|
|
401
|
+
SuiteSparseQR_C_factorization *SuiteSparseQR_C_symbolic
|
|
402
|
+
(
|
|
403
|
+
/* inputs: */
|
|
404
|
+
int ordering, /* all, except 3:given treated as 0:fixed */
|
|
405
|
+
int allow_tol, /* if TRUE allow tol for rank detection */
|
|
406
|
+
cholmod_sparse *A, /* m-by-n sparse matrix, A->x ignored */
|
|
407
|
+
cholmod_common *cc /* workspace and parameters */
|
|
408
|
+
) ;
|
|
409
|
+
|
|
410
|
+
/* ========================================================================== */
|
|
411
|
+
/* === SuiteSparseQR_C_numeric ============================================== */
|
|
412
|
+
/* ========================================================================== */
|
|
413
|
+
|
|
414
|
+
int SuiteSparseQR_C_numeric
|
|
415
|
+
(
|
|
416
|
+
/* inputs: */
|
|
417
|
+
double tol, /* treat columns with 2-norm <= tol as zero */
|
|
418
|
+
cholmod_sparse *A, /* sparse matrix to factorize */
|
|
419
|
+
/* input/output: */
|
|
420
|
+
SuiteSparseQR_C_factorization *QR,
|
|
421
|
+
cholmod_common *cc /* workspace and parameters */
|
|
422
|
+
) ;
|
|
423
|
+
|
|
424
|
+
/* ========================================================================== */
|
|
425
|
+
/* === SuiteSparseQR_C_free ================================================= */
|
|
426
|
+
/* ========================================================================== */
|
|
427
|
+
|
|
428
|
+
/* Free the QR factors computed by SuiteSparseQR_C_factorize */
|
|
429
|
+
int SuiteSparseQR_C_free /* returns TRUE (1) if OK, FALSE (0) otherwise*/
|
|
430
|
+
(
|
|
431
|
+
SuiteSparseQR_C_factorization **QR,
|
|
432
|
+
cholmod_common *cc /* workspace and parameters */
|
|
433
|
+
) ;
|
|
434
|
+
|
|
435
|
+
/* ========================================================================== */
|
|
436
|
+
/* === SuiteSparseQR_C_solve ================================================ */
|
|
437
|
+
/* ========================================================================== */
|
|
438
|
+
|
|
439
|
+
cholmod_dense* SuiteSparseQR_C_solve /* returnx X, or NULL if failure */
|
|
440
|
+
(
|
|
441
|
+
int system, /* which system to solve */
|
|
442
|
+
SuiteSparseQR_C_factorization *QR, /* of an m-by-n sparse matrix A */
|
|
443
|
+
cholmod_dense *B, /* right-hand-side, m-by-k or n-by-k */
|
|
444
|
+
cholmod_common *cc /* workspace and parameters */
|
|
445
|
+
) ;
|
|
446
|
+
|
|
447
|
+
/* ========================================================================== */
|
|
448
|
+
/* === SuiteSparseQR_C_qmult ================================================ */
|
|
449
|
+
/* ========================================================================== */
|
|
450
|
+
|
|
451
|
+
/*
|
|
452
|
+
Applies Q in Householder form (as stored in the QR factorization object
|
|
453
|
+
returned by SuiteSparseQR_C_factorize) to a dense matrix X.
|
|
454
|
+
|
|
455
|
+
method SPQR_QTX (0): Y = Q'*X
|
|
456
|
+
method SPQR_QX (1): Y = Q*X
|
|
457
|
+
method SPQR_XQT (2): Y = X*Q'
|
|
458
|
+
method SPQR_XQ (3): Y = X*Q
|
|
459
|
+
*/
|
|
460
|
+
|
|
461
|
+
cholmod_dense *SuiteSparseQR_C_qmult /* returns Y, or NULL on failure */
|
|
462
|
+
(
|
|
463
|
+
/* inputs: */
|
|
464
|
+
int method, /* 0,1,2,3 */
|
|
465
|
+
SuiteSparseQR_C_factorization *QR, /* of an m-by-n sparse matrix A */
|
|
466
|
+
cholmod_dense *X, /* size m-by-n with leading dimension ldx */
|
|
467
|
+
cholmod_common *cc /* workspace and parameters */
|
|
468
|
+
) ;
|
|
469
|
+
|
|
365
470
|
#define SPQR_ORDERING_FIXED ...
|
|
366
471
|
#define SPQR_ORDERING_NATURAL ...
|
|
367
472
|
#define SPQR_ORDERING_COLAMD ...
|
|
@@ -25,6 +25,8 @@ x = sparseqr.solve( M, B, tolerance = 0 )
|
|
|
25
25
|
A = scipy.sparse.rand( 20, 10, density = 0.1 ) # 20 equations, 10 unknowns
|
|
26
26
|
b = numpy.random.random(20) # one RHS, dense, but could also have many (in shape (20,k))
|
|
27
27
|
x = sparseqr.solve( A, b, tolerance = 0 )
|
|
28
|
+
## Call `rz()`:
|
|
29
|
+
sparseqr.rz( A, b, tolerance = 0 )
|
|
28
30
|
|
|
29
31
|
# Solve a linear system M x = B via QR decomposition
|
|
30
32
|
#
|
|
@@ -38,6 +40,16 @@ r = rank # r could be min(M.shape) if M is full-rank
|
|
|
38
40
|
# The system is only solvable if the lower part of Q.T @ B is all zero:
|
|
39
41
|
print( "System is solvable if this is zero (unlikely for a random matrix):", abs( (( Q.tocsc()[:,r:] ).T ).dot( B ) ).sum() )
|
|
40
42
|
|
|
43
|
+
# Systems with large non-square matrices can benefit from "economy" decomposition.
|
|
44
|
+
M = scipy.sparse.rand( 20, 5, density=0.1 )
|
|
45
|
+
B = scipy.sparse.rand( 20, 5, density = 0.1 )
|
|
46
|
+
Q, R, E, rank = sparseqr.qr( M )
|
|
47
|
+
print("Q shape (should be 20x20):", Q.shape)
|
|
48
|
+
print("R shape (should be 20x5):", R.shape)
|
|
49
|
+
Q, R, E, rank = sparseqr.qr( M, economy=True )
|
|
50
|
+
print("Q shape (should be 20x5):", Q.shape)
|
|
51
|
+
print("R shape (should be 5x5):", R.shape)
|
|
52
|
+
|
|
41
53
|
# Use CSC format for fast indexing of columns.
|
|
42
54
|
R = R.tocsc()[:r,:r]
|
|
43
55
|
Q = Q.tocsc()[:,:r]
|
|
@@ -53,3 +65,15 @@ x[E] = x.copy()
|
|
|
53
65
|
x = scipy.sparse.vstack( ( result.tocoo(), scipy.sparse.coo_matrix( ( M.shape[1] - rank, B.shape[1] ), dtype = result.dtype ) ) )
|
|
54
66
|
x.row = E[ x.row ]
|
|
55
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/setup.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from setuptools import setup
|
|
3
|
-
|
|
4
|
-
packages = \
|
|
5
|
-
['sparseqr']
|
|
6
|
-
|
|
7
|
-
package_data = \
|
|
8
|
-
{'': ['*']}
|
|
9
|
-
|
|
10
|
-
install_requires = \
|
|
11
|
-
['cffi>=1.0,<2.0', 'numpy>=1.21,<2.0', 'scipy>=1.0,<2.0']
|
|
12
|
-
|
|
13
|
-
setup_kwargs = {
|
|
14
|
-
'name': 'sparseqr',
|
|
15
|
-
'version': '1.2',
|
|
16
|
-
'description': 'Python wrapper for SuiteSparseQR',
|
|
17
|
-
'long_description': None,
|
|
18
|
-
'author': 'Yotam Gingold',
|
|
19
|
-
'author_email': 'yotam@yotamgingold.com',
|
|
20
|
-
'maintainer': None,
|
|
21
|
-
'maintainer_email': None,
|
|
22
|
-
'url': None,
|
|
23
|
-
'packages': packages,
|
|
24
|
-
'package_data': package_data,
|
|
25
|
-
'install_requires': install_requires,
|
|
26
|
-
'python_requires': '>=3.7,<4.0',
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
setup(**setup_kwargs)
|
|
File without changes
|
|
File without changes
|