solvax 0.1.0__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.
- solvax-0.1.0/.github/workflows/docs.yml +19 -0
- solvax-0.1.0/.github/workflows/publish.yml +32 -0
- solvax-0.1.0/.github/workflows/tests.yml +30 -0
- solvax-0.1.0/.gitignore +9 -0
- solvax-0.1.0/.readthedocs.yaml +16 -0
- solvax-0.1.0/CITATION.cff +10 -0
- solvax-0.1.0/LICENSE +21 -0
- solvax-0.1.0/PKG-INFO +115 -0
- solvax-0.1.0/README.md +80 -0
- solvax-0.1.0/codecov.yml +11 -0
- solvax-0.1.0/docs/api.md +65 -0
- solvax-0.1.0/docs/conf.py +35 -0
- solvax-0.1.0/docs/index.md +51 -0
- solvax-0.1.0/docs/references.bib +85 -0
- solvax-0.1.0/examples/01_block_tridiagonal_kinetic.py +49 -0
- solvax-0.1.0/examples/02_advection_preconditioning.py +57 -0
- solvax-0.1.0/examples/03_recycled_continuation.py +41 -0
- solvax-0.1.0/pyproject.toml +60 -0
- solvax-0.1.0/src/solvax/__init__.py +89 -0
- solvax-0.1.0/src/solvax/banded.py +385 -0
- solvax-0.1.0/src/solvax/direct.py +344 -0
- solvax-0.1.0/src/solvax/implicit.py +149 -0
- solvax-0.1.0/src/solvax/krylov.py +431 -0
- solvax-0.1.0/src/solvax/native.py +119 -0
- solvax-0.1.0/src/solvax/operators.py +460 -0
- solvax-0.1.0/src/solvax/precond.py +416 -0
- solvax-0.1.0/src/solvax/refine.py +111 -0
- solvax-0.1.0/tests/test_banded.py +206 -0
- solvax-0.1.0/tests/test_direct.py +166 -0
- solvax-0.1.0/tests/test_implicit.py +194 -0
- solvax-0.1.0/tests/test_krylov.py +178 -0
- solvax-0.1.0/tests/test_native.py +67 -0
- solvax-0.1.0/tests/test_operators.py +320 -0
- solvax-0.1.0/tests/test_precond.py +425 -0
- solvax-0.1.0/tests/test_refine.py +80 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
timeout-minutes: 10
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
cache: pip
|
|
18
|
+
- run: pip install -e '.[docs]'
|
|
19
|
+
- run: python -m sphinx -W -b html docs docs/_build
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-python@v5
|
|
13
|
+
with:
|
|
14
|
+
python-version: "3.12"
|
|
15
|
+
- run: pipx run build
|
|
16
|
+
- uses: actions/upload-artifact@v4
|
|
17
|
+
with:
|
|
18
|
+
name: dist
|
|
19
|
+
path: dist/
|
|
20
|
+
|
|
21
|
+
publish:
|
|
22
|
+
needs: build
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
environment: pypi
|
|
25
|
+
permissions:
|
|
26
|
+
id-token: write
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/download-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: dist
|
|
31
|
+
path: dist/
|
|
32
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-latest, macos-latest]
|
|
17
|
+
runs-on: ${{ matrix.os }}
|
|
18
|
+
timeout-minutes: 15
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
cache: pip
|
|
25
|
+
- run: pip install -e '.[dev]'
|
|
26
|
+
- run: pytest -n auto --cov --cov-report=xml
|
|
27
|
+
- uses: codecov/codecov-action@v4
|
|
28
|
+
if: matrix.os == 'ubuntu-latest'
|
|
29
|
+
with:
|
|
30
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
solvax-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use solvax in your research, please cite it as below."
|
|
3
|
+
title: "solvax: differentiable structured linear solvers in JAX"
|
|
4
|
+
authors:
|
|
5
|
+
- family-names: Jorge
|
|
6
|
+
given-names: Rogerio
|
|
7
|
+
email: rogerio.jorge@wisc.edu
|
|
8
|
+
affiliation: University of Wisconsin-Madison
|
|
9
|
+
repository-code: "https://github.com/uwplasma/SOLVAX"
|
|
10
|
+
license: MIT
|
solvax-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UW Plasma group, University of Wisconsin-Madison
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
solvax-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: solvax
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Differentiable structured linear solvers, preconditioners and matrix-free methods in JAX
|
|
5
|
+
Project-URL: Homepage, https://github.com/uwplasma/SOLVAX
|
|
6
|
+
Project-URL: Documentation, https://solvax.readthedocs.io
|
|
7
|
+
Author-email: UW Plasma <rogerio.jorge@wisc.edu>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: equinox
|
|
18
|
+
Requires-Dist: jax
|
|
19
|
+
Requires-Dist: lineax
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: numpy; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-xdist; extra == 'dev'
|
|
25
|
+
Requires-Dist: scipy; extra == 'dev'
|
|
26
|
+
Provides-Extra: docs
|
|
27
|
+
Requires-Dist: furo; extra == 'docs'
|
|
28
|
+
Requires-Dist: myst-parser; extra == 'docs'
|
|
29
|
+
Requires-Dist: sphinx; extra == 'docs'
|
|
30
|
+
Requires-Dist: sphinx-copybutton; extra == 'docs'
|
|
31
|
+
Requires-Dist: sphinxcontrib-bibtex; extra == 'docs'
|
|
32
|
+
Provides-Extra: native
|
|
33
|
+
Requires-Dist: scipy; extra == 'native'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# SOLVAX
|
|
37
|
+
|
|
38
|
+
[](https://github.com/uwplasma/SOLVAX/actions/workflows/tests.yml)
|
|
39
|
+
[](https://codecov.io/gh/uwplasma/SOLVAX)
|
|
40
|
+
[](https://pypi.org/project/solvax/)
|
|
41
|
+
[](https://solvax.readthedocs.io)
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
|
|
44
|
+
**Differentiable structured linear solvers, preconditioners and matrix-free methods in JAX.**
|
|
45
|
+
|
|
46
|
+
`solvax` provides the solver infrastructure that kinetic and PDE codes keep
|
|
47
|
+
re-implementing: structured direct solves (batched dense LU, block-tridiagonal
|
|
48
|
+
Schur elimination with truncated storage), preconditioned and recycled Krylov
|
|
49
|
+
methods, physics-agnostic preconditioners (coarse-operator LU, p-multigrid,
|
|
50
|
+
Kronecker approximations, line smoothers), mixed-precision iterative
|
|
51
|
+
refinement, and implicit differentiation of every solve — all
|
|
52
|
+
jit/vmap/grad-transparent, on CPU and GPU.
|
|
53
|
+
|
|
54
|
+
It fills a gap in the JAX ecosystem: [lineax](https://github.com/patrick-kidger/lineax)
|
|
55
|
+
offers general linear-operator abstractions and standard solvers, but not
|
|
56
|
+
block-structured direct elimination, coarse-operator/multigrid
|
|
57
|
+
preconditioning, or Krylov subspace recycling for parameter continuation.
|
|
58
|
+
`solvax` builds on lineax's operator interface and adds exactly that layer.
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install solvax
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quickstart
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import jax.numpy as jnp
|
|
70
|
+
import solvax as sx
|
|
71
|
+
|
|
72
|
+
# Solve a block-tridiagonal system L_k x_{k-1} + D_k x_k + U_k x_{k+1} = b_k
|
|
73
|
+
x = sx.block_thomas(lower, diag, upper, rhs)
|
|
74
|
+
|
|
75
|
+
# Reuse one elimination across many right-hand sides
|
|
76
|
+
factors = sx.block_thomas_factor(lower, diag, upper)
|
|
77
|
+
x1 = sx.block_thomas_solve(factors, rhs1)
|
|
78
|
+
x2 = sx.block_thomas_solve(factors, rhs2)
|
|
79
|
+
|
|
80
|
+
# Memory-truncated mode: rhs nonzero only in the lowest K blocks and only the
|
|
81
|
+
# lowest K solution blocks needed -> O(K m^2) memory, independent of N.
|
|
82
|
+
x_low = sx.block_thomas_truncated(lower, diag, upper, rhs[:3], keep_lowest=3)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Everything is differentiable (`jax.grad` through the solve) and batchable
|
|
86
|
+
(`jax.vmap` over stacked systems).
|
|
87
|
+
|
|
88
|
+
## What's in the box
|
|
89
|
+
|
|
90
|
+
| Module | Contents |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `solvax.operators` | Matrix-free, sum, Kronecker, block-tridiagonal and bordered (constraint-row) operator containers with closed-form transposes |
|
|
93
|
+
| `solvax.precond` | Jacobi/block-Jacobi, coarse-operator LU, alternating-direction line smoothers, p-multigrid V-cycles, nearest-Kronecker, mixed-precision wrappers |
|
|
94
|
+
| `solvax.direct` | Block-tridiagonal Schur elimination (block Thomas): full, factor/solve split, truncated-storage mode |
|
|
95
|
+
| `solvax.banded` | Non-pivoted banded LU with row equilibration + static pivoting; periodic variant via the Woodbury capacitance trick |
|
|
96
|
+
| `solvax.krylov` | Flexible restarted GMRES (CGS2 + Givens) and GCROT-style Krylov subspace recycling for parameter continuation |
|
|
97
|
+
| `solvax.implicit` | Implicit-function-theorem `linear_solve` and `root_solve` — gradients cost one extra (transposed) solve |
|
|
98
|
+
| `solvax.refine` | Mixed-precision iterative refinement (float32 factor, float64 residuals) |
|
|
99
|
+
| `solvax.native` | Host-side SuperLU bridge (non-differentiable, import-guarded) |
|
|
100
|
+
|
|
101
|
+
Roadmap to v0.2: harmonic-Ritz recycle selection, pytree operands, complex
|
|
102
|
+
dtypes, GPU batched-LU benchmarks.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# Preconditioned, recycled Krylov across a parameter scan:
|
|
106
|
+
sol = sx.gcrot(matvec, b, precond=coarse_inverse, m=50, k=10)
|
|
107
|
+
sol2 = sx.gcrot(matvec2, b2, precond=coarse_inverse, recycle=sol.recycle)
|
|
108
|
+
|
|
109
|
+
# Differentiable solve wrapping any solver:
|
|
110
|
+
x = sx.linear_solve(matvec, b, solver=lambda mv, rhs: sx.gmres(mv, rhs).x)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT. Developed by the [UW Plasma group](https://github.com/uwplasma).
|
solvax-0.1.0/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# SOLVAX
|
|
2
|
+
|
|
3
|
+
[](https://github.com/uwplasma/SOLVAX/actions/workflows/tests.yml)
|
|
4
|
+
[](https://codecov.io/gh/uwplasma/SOLVAX)
|
|
5
|
+
[](https://pypi.org/project/solvax/)
|
|
6
|
+
[](https://solvax.readthedocs.io)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
**Differentiable structured linear solvers, preconditioners and matrix-free methods in JAX.**
|
|
10
|
+
|
|
11
|
+
`solvax` provides the solver infrastructure that kinetic and PDE codes keep
|
|
12
|
+
re-implementing: structured direct solves (batched dense LU, block-tridiagonal
|
|
13
|
+
Schur elimination with truncated storage), preconditioned and recycled Krylov
|
|
14
|
+
methods, physics-agnostic preconditioners (coarse-operator LU, p-multigrid,
|
|
15
|
+
Kronecker approximations, line smoothers), mixed-precision iterative
|
|
16
|
+
refinement, and implicit differentiation of every solve — all
|
|
17
|
+
jit/vmap/grad-transparent, on CPU and GPU.
|
|
18
|
+
|
|
19
|
+
It fills a gap in the JAX ecosystem: [lineax](https://github.com/patrick-kidger/lineax)
|
|
20
|
+
offers general linear-operator abstractions and standard solvers, but not
|
|
21
|
+
block-structured direct elimination, coarse-operator/multigrid
|
|
22
|
+
preconditioning, or Krylov subspace recycling for parameter continuation.
|
|
23
|
+
`solvax` builds on lineax's operator interface and adds exactly that layer.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install solvax
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quickstart
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
import jax.numpy as jnp
|
|
35
|
+
import solvax as sx
|
|
36
|
+
|
|
37
|
+
# Solve a block-tridiagonal system L_k x_{k-1} + D_k x_k + U_k x_{k+1} = b_k
|
|
38
|
+
x = sx.block_thomas(lower, diag, upper, rhs)
|
|
39
|
+
|
|
40
|
+
# Reuse one elimination across many right-hand sides
|
|
41
|
+
factors = sx.block_thomas_factor(lower, diag, upper)
|
|
42
|
+
x1 = sx.block_thomas_solve(factors, rhs1)
|
|
43
|
+
x2 = sx.block_thomas_solve(factors, rhs2)
|
|
44
|
+
|
|
45
|
+
# Memory-truncated mode: rhs nonzero only in the lowest K blocks and only the
|
|
46
|
+
# lowest K solution blocks needed -> O(K m^2) memory, independent of N.
|
|
47
|
+
x_low = sx.block_thomas_truncated(lower, diag, upper, rhs[:3], keep_lowest=3)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Everything is differentiable (`jax.grad` through the solve) and batchable
|
|
51
|
+
(`jax.vmap` over stacked systems).
|
|
52
|
+
|
|
53
|
+
## What's in the box
|
|
54
|
+
|
|
55
|
+
| Module | Contents |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `solvax.operators` | Matrix-free, sum, Kronecker, block-tridiagonal and bordered (constraint-row) operator containers with closed-form transposes |
|
|
58
|
+
| `solvax.precond` | Jacobi/block-Jacobi, coarse-operator LU, alternating-direction line smoothers, p-multigrid V-cycles, nearest-Kronecker, mixed-precision wrappers |
|
|
59
|
+
| `solvax.direct` | Block-tridiagonal Schur elimination (block Thomas): full, factor/solve split, truncated-storage mode |
|
|
60
|
+
| `solvax.banded` | Non-pivoted banded LU with row equilibration + static pivoting; periodic variant via the Woodbury capacitance trick |
|
|
61
|
+
| `solvax.krylov` | Flexible restarted GMRES (CGS2 + Givens) and GCROT-style Krylov subspace recycling for parameter continuation |
|
|
62
|
+
| `solvax.implicit` | Implicit-function-theorem `linear_solve` and `root_solve` — gradients cost one extra (transposed) solve |
|
|
63
|
+
| `solvax.refine` | Mixed-precision iterative refinement (float32 factor, float64 residuals) |
|
|
64
|
+
| `solvax.native` | Host-side SuperLU bridge (non-differentiable, import-guarded) |
|
|
65
|
+
|
|
66
|
+
Roadmap to v0.2: harmonic-Ritz recycle selection, pytree operands, complex
|
|
67
|
+
dtypes, GPU batched-LU benchmarks.
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
# Preconditioned, recycled Krylov across a parameter scan:
|
|
71
|
+
sol = sx.gcrot(matvec, b, precond=coarse_inverse, m=50, k=10)
|
|
72
|
+
sol2 = sx.gcrot(matvec2, b2, precond=coarse_inverse, recycle=sol.recycle)
|
|
73
|
+
|
|
74
|
+
# Differentiable solve wrapping any solver:
|
|
75
|
+
x = sx.linear_solve(matvec, b, solver=lambda mv, rhs: sx.gmres(mv, rhs).x)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT. Developed by the [UW Plasma group](https://github.com/uwplasma).
|
solvax-0.1.0/codecov.yml
ADDED
solvax-0.1.0/docs/api.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# API reference
|
|
2
|
+
|
|
3
|
+
## Linear operators
|
|
4
|
+
|
|
5
|
+
```{eval-rst}
|
|
6
|
+
.. automodule:: solvax.operators
|
|
7
|
+
:members:
|
|
8
|
+
:member-order: bysource
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Preconditioners
|
|
12
|
+
|
|
13
|
+
```{eval-rst}
|
|
14
|
+
.. automodule:: solvax.precond
|
|
15
|
+
:members:
|
|
16
|
+
:member-order: bysource
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Structured direct solvers
|
|
20
|
+
|
|
21
|
+
```{eval-rst}
|
|
22
|
+
.. automodule:: solvax.direct
|
|
23
|
+
:members:
|
|
24
|
+
:member-order: bysource
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Banded and periodic-banded LU
|
|
28
|
+
|
|
29
|
+
```{eval-rst}
|
|
30
|
+
.. automodule:: solvax.banded
|
|
31
|
+
:members:
|
|
32
|
+
:member-order: bysource
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Krylov methods
|
|
36
|
+
|
|
37
|
+
```{eval-rst}
|
|
38
|
+
.. automodule:: solvax.krylov
|
|
39
|
+
:members:
|
|
40
|
+
:member-order: bysource
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Implicit differentiation
|
|
44
|
+
|
|
45
|
+
```{eval-rst}
|
|
46
|
+
.. automodule:: solvax.implicit
|
|
47
|
+
:members:
|
|
48
|
+
:member-order: bysource
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Mixed-precision refinement
|
|
52
|
+
|
|
53
|
+
```{eval-rst}
|
|
54
|
+
.. automodule:: solvax.refine
|
|
55
|
+
:members:
|
|
56
|
+
:member-order: bysource
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Native host bridges
|
|
60
|
+
|
|
61
|
+
```{eval-rst}
|
|
62
|
+
.. automodule:: solvax.native
|
|
63
|
+
:members:
|
|
64
|
+
:member-order: bysource
|
|
65
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Sphinx configuration for the solvax documentation."""
|
|
2
|
+
|
|
3
|
+
import solvax
|
|
4
|
+
|
|
5
|
+
project = "solvax"
|
|
6
|
+
copyright = "2026, UW Plasma group"
|
|
7
|
+
author = "UW Plasma group"
|
|
8
|
+
release = solvax.__version__
|
|
9
|
+
|
|
10
|
+
extensions = [
|
|
11
|
+
"sphinx.ext.autodoc",
|
|
12
|
+
"sphinx.ext.napoleon",
|
|
13
|
+
"sphinx.ext.mathjax",
|
|
14
|
+
"sphinx.ext.intersphinx",
|
|
15
|
+
"myst_parser",
|
|
16
|
+
"sphinx_copybutton",
|
|
17
|
+
"sphinxcontrib.bibtex",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
bibtex_bibfiles = ["references.bib"]
|
|
21
|
+
myst_enable_extensions = ["dollarmath", "amsmath"]
|
|
22
|
+
|
|
23
|
+
html_theme = "furo"
|
|
24
|
+
html_title = "solvax"
|
|
25
|
+
|
|
26
|
+
intersphinx_mapping = {
|
|
27
|
+
"jax": ("https://docs.jax.dev/en/latest/", None),
|
|
28
|
+
"python": ("https://docs.python.org/3", None),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
autodoc_typehints = "description"
|
|
32
|
+
napoleon_google_docstring = True
|
|
33
|
+
# NamedTuple fields are already documented via napoleon Attributes sections;
|
|
34
|
+
# ivar rendering avoids duplicate autodoc entries for the same objects.
|
|
35
|
+
napoleon_use_ivar = True
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# solvax
|
|
2
|
+
|
|
3
|
+
**Differentiable structured linear solvers, preconditioners and matrix-free
|
|
4
|
+
methods in JAX.**
|
|
5
|
+
|
|
6
|
+
`solvax` is the solver layer that kinetic and PDE codes keep re-implementing,
|
|
7
|
+
factored out once: structured direct solves, preconditioned and recycled
|
|
8
|
+
Krylov methods, physics-agnostic preconditioners, mixed-precision refinement,
|
|
9
|
+
and implicit differentiation — all jit/vmap/grad-transparent on CPU and GPU.
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import solvax as sx
|
|
15
|
+
|
|
16
|
+
# Block-tridiagonal system: L_k x_{k-1} + D_k x_k + U_k x_{k+1} = b_k
|
|
17
|
+
x = sx.block_thomas(lower, diag, upper, rhs)
|
|
18
|
+
|
|
19
|
+
# Reuse one elimination across right-hand sides
|
|
20
|
+
factors = sx.block_thomas_factor(lower, diag, upper)
|
|
21
|
+
x1 = sx.block_thomas_solve(factors, rhs1)
|
|
22
|
+
x2 = sx.block_thomas_solve(factors, rhs2)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## The block-tridiagonal kernel
|
|
26
|
+
|
|
27
|
+
For blocks $L_k x_{k-1} + D_k x_k + U_k x_{k+1} = b_k$, a Schur-complement
|
|
28
|
+
sweep from the last block down,
|
|
29
|
+
|
|
30
|
+
$$\Delta_{N-1} = D_{N-1}, \qquad
|
|
31
|
+
\Delta_k = D_k - U_k \Delta_{k+1}^{-1} L_{k+1}, \qquad
|
|
32
|
+
\sigma_k = b_k - U_k \Delta_{k+1}^{-1} \sigma_{k+1},$$
|
|
33
|
+
|
|
34
|
+
followed by substitution upward from block 0, solves the system exactly with
|
|
35
|
+
one dense LU and one matrix product per block {cite}`golub2013,demmel1995`.
|
|
36
|
+
When the right-hand side vanishes above block $K$ and only the lowest $K$
|
|
37
|
+
solution blocks are needed — the typical situation for spectral kinetic
|
|
38
|
+
equations, where sources and velocity moments involve only the first few
|
|
39
|
+
modes — storage above $K$ can be discarded on the fly, giving memory
|
|
40
|
+
$O(K m^2)$ independent of $N$ {cite}`escoto2025`.
|
|
41
|
+
|
|
42
|
+
```{toctree}
|
|
43
|
+
:maxdepth: 1
|
|
44
|
+
|
|
45
|
+
api
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## References
|
|
49
|
+
|
|
50
|
+
```{bibliography}
|
|
51
|
+
```
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
@book{golub2013,
|
|
2
|
+
author = {Golub, Gene H. and Van Loan, Charles F.},
|
|
3
|
+
title = {Matrix Computations},
|
|
4
|
+
edition = {4},
|
|
5
|
+
publisher = {Johns Hopkins University Press},
|
|
6
|
+
year = {2013},
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@article{demmel1995,
|
|
10
|
+
author = {Demmel, James W. and Higham, Nicholas J. and Schreiber, Robert S.},
|
|
11
|
+
title = {Stability of block {LU} factorization},
|
|
12
|
+
journal = {Numerical Linear Algebra with Applications},
|
|
13
|
+
volume = {2},
|
|
14
|
+
pages = {173--190},
|
|
15
|
+
year = {1995},
|
|
16
|
+
doi = {10.1002/nla.1680020208},
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@phdthesis{escoto2025,
|
|
20
|
+
author = {Escoto, F. Javier},
|
|
21
|
+
title = {Fast and accurate calculation of the bootstrap current and radial
|
|
22
|
+
neoclassical transport in low collisionality stellarator plasmas},
|
|
23
|
+
school = {Universidad Carlos III de Madrid},
|
|
24
|
+
year = {2025},
|
|
25
|
+
url = {https://arxiv.org/abs/2510.27513},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@article{morgan2002,
|
|
29
|
+
author = {Morgan, Ronald B.},
|
|
30
|
+
title = {{GMRES} with deflated restarting},
|
|
31
|
+
journal = {SIAM Journal on Scientific Computing},
|
|
32
|
+
volume = {24},
|
|
33
|
+
pages = {20--37},
|
|
34
|
+
year = {2002},
|
|
35
|
+
doi = {10.1137/S1064827599364659},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@article{parks2006,
|
|
39
|
+
author = {Parks, Michael L. and de Sturler, Eric and Mackey, Greg and
|
|
40
|
+
Johnson, Duane D. and Maiti, Spandan},
|
|
41
|
+
title = {Recycling {Krylov} subspaces for sequences of linear systems},
|
|
42
|
+
journal = {SIAM Journal on Scientific Computing},
|
|
43
|
+
volume = {28},
|
|
44
|
+
pages = {1651--1674},
|
|
45
|
+
year = {2006},
|
|
46
|
+
doi = {10.1137/040607277},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@article{carson2018,
|
|
50
|
+
author = {Carson, Erin and Higham, Nicholas J.},
|
|
51
|
+
title = {Accelerating the solution of linear systems by iterative
|
|
52
|
+
refinement in three precisions},
|
|
53
|
+
journal = {SIAM Journal on Scientific Computing},
|
|
54
|
+
volume = {40},
|
|
55
|
+
pages = {A817--A847},
|
|
56
|
+
year = {2018},
|
|
57
|
+
doi = {10.1137/17M1140819},
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@inproceedings{blondel2022,
|
|
61
|
+
author = {Blondel, Mathieu and Berthet, Quentin and Cuturi, Marco and
|
|
62
|
+
Frostig, Roy and Hoyer, Stephan and Llinares-L{\'o}pez, Felipe
|
|
63
|
+
and Pedregosa, Fabian and Vert, Jean-Philippe},
|
|
64
|
+
title = {Efficient and modular implicit differentiation},
|
|
65
|
+
booktitle = {Advances in Neural Information Processing Systems},
|
|
66
|
+
year = {2022},
|
|
67
|
+
url = {https://arxiv.org/abs/2105.15183},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@article{skene2026,
|
|
71
|
+
author = {Skene, Calum S. and Burns, Keaton J.},
|
|
72
|
+
title = {Fast automated adjoints for spectral {PDE} solvers},
|
|
73
|
+
journal = {Proceedings of the National Academy of Sciences},
|
|
74
|
+
year = {2026},
|
|
75
|
+
url = {https://arxiv.org/abs/2506.14792},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@incollection{vanloan1993,
|
|
79
|
+
author = {Van Loan, Charles F. and Pitsianis, Nikos},
|
|
80
|
+
title = {Approximation with {Kronecker} products},
|
|
81
|
+
booktitle = {Linear Algebra for Large Scale and Real-Time Applications},
|
|
82
|
+
publisher = {Springer},
|
|
83
|
+
year = {1993},
|
|
84
|
+
doi = {10.1007/978-94-015-8196-7_17},
|
|
85
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Solve a kinetic-style block-tridiagonal system with truncated storage.
|
|
2
|
+
|
|
3
|
+
Spectral discretizations of kinetic equations (e.g. a Legendre expansion in
|
|
4
|
+
pitch angle) couple only neighbouring modes l-1, l, l+1, giving a
|
|
5
|
+
block-tridiagonal system whose right-hand side lives in the lowest few modes
|
|
6
|
+
and whose observables (density, flow, pressure moments) touch only those same
|
|
7
|
+
modes. `block_thomas_truncated` exploits both facts: memory O(K m^2)
|
|
8
|
+
independent of the number of modes.
|
|
9
|
+
|
|
10
|
+
Expected runtime: a few seconds on a laptop CPU.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import jax
|
|
14
|
+
import jax.numpy as jnp
|
|
15
|
+
|
|
16
|
+
import solvax as sx
|
|
17
|
+
|
|
18
|
+
jax.config.update("jax_enable_x64", True)
|
|
19
|
+
|
|
20
|
+
n_modes, m = 64, 100 # Legendre-like modes x flux-surface grid points
|
|
21
|
+
key = jax.random.PRNGKey(0)
|
|
22
|
+
k1, k2, k3, k4 = jax.random.split(key, 4)
|
|
23
|
+
|
|
24
|
+
# Streaming-like off-diagonal coupling and a collisional diagonal ~ l(l+1).
|
|
25
|
+
lower = 0.3 * jax.random.normal(k1, (n_modes, m, m))
|
|
26
|
+
upper = 0.3 * jax.random.normal(k2, (n_modes, m, m))
|
|
27
|
+
nu = 0.5 * jnp.arange(n_modes) * (jnp.arange(n_modes) + 1) + 5.0
|
|
28
|
+
diag = jax.random.normal(k3, (n_modes, m, m)) + nu[:, None, None] * jnp.eye(m)
|
|
29
|
+
|
|
30
|
+
# Two drives (radial + parallel), nonzero only in modes 0..2 — solved together.
|
|
31
|
+
rhs_low = jax.random.normal(k4, (3, m, 2))
|
|
32
|
+
|
|
33
|
+
x_low = sx.block_thomas_truncated(lower, diag, upper, rhs_low, keep_lowest=3)
|
|
34
|
+
print("lowest-mode solution block shape:", x_low.shape)
|
|
35
|
+
|
|
36
|
+
# Cross-check against the full solve.
|
|
37
|
+
rhs_full = jnp.zeros((n_modes, m, 2)).at[:3].set(rhs_low)
|
|
38
|
+
x_full = sx.block_thomas(lower, diag, upper, rhs_full)
|
|
39
|
+
err = jnp.max(jnp.abs(x_low - x_full[:3]))
|
|
40
|
+
print(f"max |truncated - full| = {err:.2e}")
|
|
41
|
+
|
|
42
|
+
# The whole solve is differentiable: gradient of a "flux" moment w.r.t. nu.
|
|
43
|
+
def flux(nu_vec):
|
|
44
|
+
d = jax.random.normal(k3, (n_modes, m, m)) + nu_vec[:, None, None] * jnp.eye(m)
|
|
45
|
+
x = sx.block_thomas_truncated(lower, d, upper, rhs_low, keep_lowest=3)
|
|
46
|
+
return jnp.sum(x[1] ** 2) # mode-1 moment ~ parallel flow
|
|
47
|
+
|
|
48
|
+
g = jax.grad(flux)(nu)
|
|
49
|
+
print("d(flux)/d(nu_0) =", float(g[0]))
|