blocksolver 0.8.3__cp310-cp310-macosx_10_9_universal2.whl

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,439 @@
1
+ Metadata-Version: 2.1
2
+ Name: blocksolver
3
+ Version: 0.8.3
4
+ Summary: Block Quasi-Minimal-Residual sparse linear solver
5
+ Home-page: https://blit.sourceforge.net
6
+ Author: Qianqian Fang
7
+ Author-email: Qianqian Fang <q.fang@neu.edu>
8
+ License: BSD-3-Clause OR LGPL-3.0-or-later OR GPL-3.0-or-later
9
+ Project-URL: Homepage, https://blit.sourceforge.net
10
+ Project-URL: Repository, https://github.com/fangq/blocksolver
11
+ Project-URL: Documentation, https://blit.sourceforge.net
12
+ Project-URL: Bug Tracker, https://github.com/fangq/blocksolver/issues
13
+ Keywords: sparse,linear-algebra,iterative-solver,qmr,fortran,umfpack
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
18
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Operating System :: POSIX :: Linux
21
+ Classifier: Operating System :: MacOS
22
+ Classifier: Operating System :: Microsoft :: Windows
23
+ Classifier: Programming Language :: Fortran
24
+ Classifier: Programming Language :: Python :: 3
25
+ Classifier: Programming Language :: Python :: 3.8
26
+ Classifier: Programming Language :: Python :: 3.9
27
+ Classifier: Programming Language :: Python :: 3.10
28
+ Classifier: Programming Language :: Python :: 3.11
29
+ Classifier: Programming Language :: Python :: 3.12
30
+ Classifier: Programming Language :: Python :: 3.13
31
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
32
+ Requires-Python: >=3.8
33
+ Description-Content-Type: text/markdown
34
+ Requires-Dist: numpy>=1.20
35
+ Requires-Dist: scipy>=1.0
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest>=6.0; extra == "dev"
38
+ Requires-Dist: build; extra == "dev"
39
+ Requires-Dist: twine; extra == "dev"
40
+ Provides-Extra: fast
41
+ Requires-Dist: numba>=0.50; extra == "fast"
42
+ Provides-Extra: test
43
+ Requires-Dist: pytest>=6.0; extra == "test"
44
+
45
+ # BlockSolver - Block Quasi-Minimal Residual (BLQMR) Sparse Linear Solver
46
+
47
+ **BlockSolver** is a Python package for solving large sparse linear systems using the Block Quasi-Minimal Residual (BLQMR) algorithm. It provides both a high-performance Fortran backend and a pure Python/NumPy implementation for maximum portability.
48
+
49
+ ## Features
50
+
51
+ - **Block QMR Algorithm**: Efficiently solves multiple right-hand sides simultaneously
52
+ - **Complex Symmetric Support**: Designed for complex symmetric matrices (A = Aᵀ, not A = A†)
53
+ - **Dual Backend**: Fortran extension for speed, Python fallback for portability
54
+ - **ILU Preconditioning**: Built-in incomplete LU preconditioner for faster convergence
55
+ - **SciPy Integration**: Works seamlessly with SciPy sparse matrices
56
+ - **Optional Numba Acceleration**: JIT-compiled kernels for the Python backend
57
+
58
+ ## Algorithm
59
+
60
+ ### Block Quasi-Minimal Residual (BLQMR)
61
+
62
+ The BLQMR algorithm is an iterative Krylov subspace method specifically designed for:
63
+
64
+ 1. **Complex symmetric systems**: Unlike standard methods that assume Hermitian (A = A†) or general matrices, BLQMR exploits complex symmetry (A = Aᵀ) which arises in electromagnetics, acoustics, and diffuse optical tomography.
65
+
66
+ 2. **Multiple right-hand sides**: Instead of solving each system independently, BLQMR processes all right-hand sides together in a block fashion, sharing Krylov subspace information and reducing total computation.
67
+
68
+ 3. **Quasi-minimal residual**: The algorithm minimizes a quasi-residual norm at each iteration, providing smooth convergence without the erratic behavior of some Krylov methods.
69
+
70
+ ### Key Components
71
+
72
+ - **Quasi-QR Decomposition**: A modified Gram-Schmidt process using the quasi inner product ⟨x,y⟩ = Σ xₖyₖ (without conjugation) for complex symmetric systems.
73
+
74
+ - **Three-term Lanczos Recurrence**: Builds an orthonormal basis for the Krylov subspace with short recurrences, minimizing memory usage.
75
+
76
+ - **Block Updates**: Processes m right-hand sides simultaneously, with typical block sizes of 1-16.
77
+
78
+ ### When to Use BLQMR
79
+
80
+ | Use Case | Recommendation |
81
+ |----------|----------------|
82
+ | Complex symmetric matrix (A = Aᵀ) | ✅ Ideal |
83
+ | Multiple right-hand sides | ✅ Ideal |
84
+ | Real symmetric positive definite | Consider CG first |
85
+ | General non-symmetric | Consider GMRES or BiCGSTAB |
86
+ | Very large systems (>10⁶ unknowns) | ✅ Good with preconditioning |
87
+
88
+ ## Installation
89
+
90
+ ### From PyPI
91
+
92
+ ```bash
93
+ pip install blocksolver
94
+ ```
95
+
96
+ ### From Source
97
+
98
+ Prerequisites:
99
+ - Python ≥ 3.8
100
+ - NumPy ≥ 1.20
101
+ - SciPy ≥ 1.0
102
+ - (Optional) Fortran compiler + UMFPACK for the accelerated backend
103
+ - (Optional) Numba for accelerated Python backend
104
+
105
+ ```bash
106
+ # Ubuntu/Debian
107
+ sudo apt install gfortran libsuitesparse-dev libblas-dev liblapack-dev
108
+
109
+ # macOS
110
+ brew install gcc suite-sparse openblas
111
+
112
+ # Install
113
+ cd python
114
+ pip install .
115
+ ```
116
+
117
+ ## Quick Start
118
+
119
+ ```python
120
+ import numpy as np
121
+ from scipy.sparse import csc_matrix
122
+ from blocksolver import blqmr
123
+
124
+ # Create a sparse matrix
125
+ A = csc_matrix([
126
+ [4, 1, 0, 0],
127
+ [1, 4, 1, 0],
128
+ [0, 1, 4, 1],
129
+ [0, 0, 1, 4]
130
+ ], dtype=float)
131
+
132
+ b = np.array([1., 2., 3., 4.])
133
+
134
+ # Solve Ax = b
135
+ result = blqmr(A, b, tol=1e-10)
136
+
137
+ print(f"Solution: {result.x}")
138
+ print(f"Converged: {result.converged}")
139
+ print(f"Iterations: {result.iter}")
140
+ print(f"Relative residual: {result.relres:.2e}")
141
+ ```
142
+
143
+ ## Usage
144
+
145
+ ### Main Interface: `blqmr()`
146
+
147
+ The primary function `blqmr()` automatically selects the best available backend (Fortran if available, otherwise Python).
148
+
149
+ ```python
150
+ from blocksolver import blqmr, BLQMR_EXT
151
+
152
+ # Check which backend is active
153
+ print(f"Using Fortran backend: {BLQMR_EXT}")
154
+
155
+ # Basic usage
156
+ result = blqmr(A, b)
157
+
158
+ # With options
159
+ result = blqmr(A, b,
160
+ tol=1e-8, # Convergence tolerance
161
+ maxiter=1000, # Maximum iterations
162
+ use_precond=True, # Use ILU preconditioning
163
+ )
164
+ ```
165
+
166
+ ### Multiple Right-Hand Sides
167
+
168
+ BLQMR excels when solving the same system with multiple right-hand sides:
169
+
170
+ ```python
171
+ import numpy as np
172
+ from blocksolver import blqmr
173
+
174
+ # 100 different right-hand sides
175
+ B = np.random.randn(n, 100)
176
+
177
+ # Solve all systems at once (much faster than solving individually)
178
+ result = blqmr(A, B, tol=1e-8)
179
+
180
+ # result.x has shape (n, 100)
181
+ ```
182
+
183
+ ### Complex Symmetric Systems
184
+
185
+ BLQMR is specifically designed for complex symmetric matrices (common in frequency-domain wave problems):
186
+
187
+ ```python
188
+ import numpy as np
189
+ from blocksolver import blqmr
190
+
191
+ # Complex symmetric matrix (A = A.T, NOT A.conj().T)
192
+ A = create_helmholtz_matrix(frequency=1000) # Your application
193
+ b = np.complex128(source_term)
194
+
195
+ result = blqmr(A, b, tol=1e-8)
196
+ ```
197
+
198
+ ### Custom Preconditioning
199
+
200
+ For the Python backend, you can provide custom preconditioners:
201
+
202
+ ```python
203
+ from blocksolver import blqmr, make_preconditioner
204
+
205
+ # Create ILU preconditioner
206
+ M1 = make_preconditioner(A, 'ilu')
207
+
208
+ # Or diagonal (Jacobi) preconditioner
209
+ M1 = make_preconditioner(A, 'diag')
210
+
211
+ # Solve with custom preconditioner
212
+ result = blqmr(A, b, M1=M1, use_precond=False)
213
+ ```
214
+
215
+ ### SciPy-Compatible Interface
216
+
217
+ For drop-in replacement in existing code:
218
+
219
+ ```python
220
+ from blocksolver import blqmr_scipy
221
+
222
+ # Returns (x, flag) like scipy.sparse.linalg solvers
223
+ x, flag = blqmr_scipy(A, b, tol=1e-10)
224
+ ```
225
+
226
+ ### Low-Level CSC Interface
227
+
228
+ For maximum control, use the CSC component interface:
229
+
230
+ ```python
231
+ from blocksolver import blqmr_solve
232
+
233
+ # CSC format components (0-based indexing)
234
+ Ap = np.array([0, 2, 5, 9, 10, 12], dtype=np.int32) # Column pointers
235
+ Ai = np.array([0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4], dtype=np.int32) # Row indices
236
+ Ax = np.array([2., 3., 3., -1., 4., 4., -3., 1., 2., 2., 6., 1.]) # Values
237
+ b = np.array([8., 45., -3., 3., 19.])
238
+
239
+ result = blqmr_solve(Ap, Ai, Ax, b,
240
+ tol=1e-8,
241
+ droptol=0.001, # ILU drop tolerance (Fortran only)
242
+ use_precond=True,
243
+ zero_based=True, # 0-based indexing (default)
244
+ )
245
+ ```
246
+
247
+ ## API Reference
248
+
249
+ ### `blqmr(A, B, **kwargs) -> BLQMRResult`
250
+
251
+ Main solver interface.
252
+
253
+ **Parameters:**
254
+ | Parameter | Type | Default | Description |
255
+ |-----------|------|---------|-------------|
256
+ | `A` | sparse matrix or ndarray | required | System matrix (n × n) |
257
+ | `B` | ndarray | required | Right-hand side (n,) or (n × m) |
258
+ | `tol` | float | 1e-6 | Convergence tolerance |
259
+ | `maxiter` | int | n | Maximum iterations |
260
+ | `M1`, `M2` | preconditioner | None | Custom preconditioners (Python backend) |
261
+ | `x0` | ndarray | None | Initial guess |
262
+ | `use_precond` | bool | True | Use ILU preconditioning |
263
+ | `droptol` | float | 0.001 | ILU drop tolerance (Fortran backend) |
264
+ | `residual` | bool | False | Use true residual for convergence (Python) |
265
+ | `workspace` | BLQMRWorkspace | None | Pre-allocated workspace (Python) |
266
+
267
+ **Returns:** `BLQMRResult` object with:
268
+ | Attribute | Type | Description |
269
+ |-----------|------|-------------|
270
+ | `x` | ndarray | Solution vector(s) |
271
+ | `flag` | int | 0=converged, 1=maxiter, 2=precond fail, 3=stagnation |
272
+ | `iter` | int | Iterations performed |
273
+ | `relres` | float | Final relative residual |
274
+ | `converged` | bool | True if flag == 0 |
275
+ | `resv` | ndarray | Residual history (Python backend only) |
276
+
277
+ ### `blqmr_solve(Ap, Ai, Ax, b, **kwargs) -> BLQMRResult`
278
+
279
+ Low-level CSC interface.
280
+
281
+ ### `blqmr_solve_multi(Ap, Ai, Ax, B, **kwargs) -> BLQMRResult`
282
+
283
+ Multiple right-hand sides with CSC input.
284
+
285
+ ### `blqmr_scipy(A, b, **kwargs) -> Tuple[ndarray, int]`
286
+
287
+ SciPy-compatible interface returning `(x, flag)`.
288
+
289
+ ### `make_preconditioner(A, type) -> Preconditioner`
290
+
291
+ Create a preconditioner for the Python backend.
292
+
293
+ **Types:** `'diag'`/`'jacobi'`, `'ilu'`/`'ilu0'`, `'ssor'`
294
+
295
+ ### Utility Functions
296
+
297
+ ```python
298
+ from blocksolver import (
299
+ BLQMR_EXT, # True if Fortran backend available
300
+ HAS_NUMBA, # True if Numba acceleration available
301
+ get_backend_info, # Returns dict with backend details
302
+ test, # Run built-in tests
303
+ )
304
+ ```
305
+
306
+ ## Performance Tips
307
+
308
+ 1. **Use the Fortran backend** when available (10-100× faster than Python)
309
+
310
+ 2. **Enable preconditioning** for ill-conditioned systems:
311
+ ```python
312
+ result = blqmr(A, b, use_precond=True)
313
+ ```
314
+
315
+ 3. **Batch multiple right-hand sides** instead of solving one at a time:
316
+ ```python
317
+ # Fast: single call with all RHS
318
+ result = blqmr(A, B_matrix)
319
+
320
+ # Slow: multiple calls
321
+ for b in B_columns:
322
+ result = blqmr(A, b)
323
+ ```
324
+
325
+ 4. **Install Numba** for faster Python backend:
326
+ ```bash
327
+ pip install numba
328
+ ```
329
+
330
+ 5. **Reuse workspace** for repeated solves with the same dimensions:
331
+ ```python
332
+ from blocksolver import BLQMRWorkspace
333
+ ws = BLQMRWorkspace(n, m)
334
+ for b in many_rhs:
335
+ result = blqmr(A, b, workspace=ws)
336
+ ```
337
+
338
+ ## Examples
339
+
340
+ ### Diffuse Optical Tomography
341
+
342
+ ```python
343
+ import numpy as np
344
+ from scipy.sparse import diags, kron, eye
345
+ from blocksolver import blqmr
346
+
347
+ def create_diffusion_matrix(nx, ny, D=1.0, mu_a=0.01, omega=1e9):
348
+ """Create 2D diffusion matrix for DOT."""
349
+ n = nx * ny
350
+ h = 1.0 / nx
351
+
352
+ # Laplacian
353
+ Lx = diags([-1, 2, -1], [-1, 0, 1], shape=(nx, nx)) / h**2
354
+ Ly = diags([-1, 2, -1], [-1, 0, 1], shape=(ny, ny)) / h**2
355
+ L = kron(eye(ny), Lx) + kron(Ly, eye(nx))
356
+
357
+ # Diffusion equation: (-D∇² + μ_a + iω/c) φ = q
358
+ c = 3e10 # speed of light in tissue (cm/s)
359
+ A = -D * L + mu_a * eye(n) + 1j * omega / c * eye(n)
360
+
361
+ return A.tocsc()
362
+
363
+ # Setup problem
364
+ A = create_diffusion_matrix(100, 100, omega=2*np.pi*100e6)
365
+ sources = np.random.randn(10000, 16) # 16 source positions
366
+
367
+ # Solve for all sources at once
368
+ result = blqmr(A, sources, tol=1e-8)
369
+ print(f"Solved {sources.shape[1]} systems in {result.iter} iterations")
370
+ ```
371
+
372
+ ### Frequency-Domain Acoustics
373
+
374
+ ```python
375
+ import numpy as np
376
+ from blocksolver import blqmr
377
+
378
+ # Helmholtz equation: (∇² + k²)p = f
379
+ # Results in complex symmetric matrix
380
+
381
+ def solve_helmholtz(K, M, f, frequencies):
382
+ """Solve Helmholtz at multiple frequencies."""
383
+ solutions = []
384
+ for omega in frequencies:
385
+ # A = K - ω²M (complex symmetric if K, M are symmetric)
386
+ A = K - omega**2 * M
387
+ result = blqmr(A, f, tol=1e-10)
388
+ solutions.append(result.x)
389
+ return np.array(solutions)
390
+ ```
391
+
392
+ ## Troubleshooting
393
+
394
+ ### "No Fortran backend available"
395
+
396
+ Install the package with Fortran support:
397
+ ```bash
398
+ # Install dependencies first
399
+ sudo apt install gfortran libsuitesparse-dev # Linux
400
+ brew install gcc suite-sparse # macOS
401
+
402
+ # Reinstall blocksolver
403
+ pip install --no-cache-dir blocksolver
404
+ ```
405
+
406
+ ### Slow convergence
407
+
408
+ 1. Enable preconditioning: `use_precond=True`
409
+ 2. Reduce ILU drop tolerance: `droptol=1e-4` (Fortran backend)
410
+ 3. Check matrix conditioning with `np.linalg.cond(A.toarray())`
411
+
412
+ ### Memory issues with large systems
413
+
414
+ 1. Use the Fortran backend (more memory efficient)
415
+ 2. Reduce block size for multiple RHS
416
+ 3. Use iterative refinement instead of tighter tolerance
417
+
418
+ ## License
419
+
420
+ BSD-3-Clause / LGPL-3.0+ / GPL-3.0+ (tri-licensed)
421
+
422
+ ## Citation
423
+
424
+ If you use BlockSolver in your research, please cite:
425
+
426
+ ```bibtex
427
+ @software{blocksolver,
428
+ author = {Qianqian Fang},
429
+ title = {BlockSolver: Block Quasi-Minimal Residual Sparse Linear Solver},
430
+ url = {https://github.com/fangq/blit},
431
+ year = {2024}
432
+ }
433
+ ```
434
+
435
+ ## See Also
436
+
437
+ - [BLIT](https://github.com/fangq/blit) - The underlying Fortran library
438
+ - [SciPy sparse.linalg](https://docs.scipy.org/doc/scipy/reference/sparse.linalg.html) - Other iterative solvers
439
+ - [PyAMG](https://github.com/pyamg/pyamg) - Algebraic multigrid solvers
@@ -0,0 +1,7 @@
1
+ blocksolver/__init__.py,sha256=uiwFH4fykkobMnkGeFrumVpE5uBaBqcRlc0uZd4SXF8,1899
2
+ blocksolver/_blqmr.cpython-310-darwin.so,sha256=2wmCNtO1yrkAViaRDrtguja15igZh6QVSm-LCwAcwyc,275144
3
+ blocksolver/blqmr.py,sha256=b2xJ3MiB7UKyMDLG1Y90B_73nSm7sGxdCSqjBNZF6Y8,39741
4
+ blocksolver-0.8.3.dist-info/METADATA,sha256=opJXFW5M7J6wCQUl0X70BA_O2ac73VphxMCu8HJX6mo,13327
5
+ blocksolver-0.8.3.dist-info/WHEEL,sha256=3IGgna_5_UzxI4nXCLe9aGeZGoCAumx1Qyv-zIiuJ1c,115
6
+ blocksolver-0.8.3.dist-info/top_level.txt,sha256=R5OAf1b8tkdMHqg8VgcfGMg6vbYt25p9JNq2Pk_VlbA,12
7
+ blocksolver-0.8.3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.46.3)
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-cp310-macosx_10_9_universal2
5
+
@@ -0,0 +1 @@
1
+ blocksolver