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