Metadata-Version: 2.4
Name: rslab
Version: 0.26.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Requires-Dist: numpy>=1.21
Requires-Dist: scipy>=1.7
Summary: Pure-Rust sparse direct solver (symmetric LDLᵀ + unsymmetric LU) and preconditioner, with NumPy/SciPy bindings.
Keywords: sparse,solver,linear-algebra,ldlt,lu,preconditioner,pardiso,scipy
Author: Milan Rother
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/milanofthe/rslab
Project-URL: Repository, https://github.com/milanofthe/rslab

# rslab (Python bindings)

NumPy/SciPy bindings for [RSLAB](https://github.com/milanofthe/rslab), a
pure-Rust sparse direct solver and preconditioner: complex/real symmetric LDLᵀ
(Bunch-Kaufman) plus unsymmetric LU. A thin wrapper, all numeric work happens in
Rust.

## Install

```bash
pip install rslab
```

## Usage

```python
import numpy as np
import scipy.sparse as sp
import rslab

# Symmetric system (real or complex; the dtype selects the path).
A = sp.random(5000, 5000, density=1e-3, format="csc") + sp.eye(5000) * 10
A = A + A.T
b = np.random.rand(5000)

# One-shot solve.
x = rslab.spsolve(A, b)

# Factor once, solve many right-hand sides.
f = rslab.ldlt(A)
x1 = f.solve(b)
X = f.solve_many(np.random.rand(5000, 8))   # n x nrhs

print(f.n, f.factor_nnz, f.inertia, f.dtype)
```

Complex-symmetric matrices (EM/FEM, PARDISO `mtype 6`) work identically:

```python
A = A.astype(np.complex128); A.data += 1j * 0.3 * A.data.real
x = rslab.ldlt(A).solve(np.ones(A.shape[0], dtype=np.complex128))
```

Unsymmetric matrices use the LU path:

```python
f = rslab.lu(A_general)
x = f.solve(b)
```

Circuit-shaped matrices (MNA / SPICE-class: very sparse, unsymmetric,
near-triangularizable) use the KLU path, bit-deterministic, with a
numeric-only `refactor` for fixed-pattern sweeps:

```python
f = rslab.klu(A_circuit)
x = f.solve(b)
A_circuit.data *= 1.5            # frequency sweep: same pattern, new values
f.refactor(A_circuit.data)       # no symbolic work, no pivot search
x2 = f.solve(b)
y = f.solve_transpose(b)         # A.T @ y = b on the same factors (adjoint)
```

`solve_transpose` is the plain transpose; for the conjugate-transpose adjoint
use `f.solve_transpose(b.conj()).conj()`.

### Preconditioner mode

Never-fail static pivoting plus iterative refinement for hard/indefinite
systems:

```python
f = rslab.ldlt(A, preconditioner=1e-4)
x = f.solve(b, refine=20)        # refine against the original A
```

## Configuration (keyword arguments)

By default `ldlt`, `lu` and `spsolve` use RSLAB's deterministic heuristic
pick, the adaptive ordering plus an exact nested-dissection bakeoff on large
systems (adopted only on a clear predicted win with no fill/memory
regression). A one-time `rslab.install_diagnose()` measures this machine's
throughput and speedup curve and caches it; afterwards the default also picks
its worker count from the calibration (until then the conservative capped
default applies). Keyword arguments override the pick:

| kwarg            | default          | meaning                                                        |
|------------------|------------------|----------------------------------------------------------------|
| `threads`        | `None` (auto)    | `None` = calibrated/structural per-matrix pick; int = fixed (`0` = all) |
| `preconditioner` | `None`           | static-pivot floor (e.g. `1e-4`); never-fail, refine to solve  |
| `drop_tol`       | `None`           | incomplete-factor threshold (preconditioner)                   |
| `method`         | `"left_looking"` | `"left_looking"` or `"multifrontal"`                           |
| `memory`         | `"low"`          | `"low"` or `"eager"` factor emit strategy                      |
| `force_accept`   | `False`          | accept tiny pivots in exact mode instead of failing            |

`klu` accepts:

| kwarg         | default | meaning                                                          |
|---------------|---------|------------------------------------------------------------------|
| `pivot_tol`   | `1e-3`  | diagonal-preference threshold; `1.0` = plain partial pivoting    |
| `row_scaling` | `True`  | divide each row by its max-magnitude entry before factoring      |
| `btf`         | `True`  | permute to block upper triangular form first (keep it on)       |

Supported dtypes: `float64`, `float32`, `complex128`, `complex64`.

## License

MIT.

