torchsolve 0.0.1__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.
- torchsolve-0.0.1/.gitattributes +11 -0
- torchsolve-0.0.1/.github/ISSUE_TEMPLATE/bug_report.yml +42 -0
- torchsolve-0.0.1/.github/ISSUE_TEMPLATE/config.yml +8 -0
- torchsolve-0.0.1/.github/ISSUE_TEMPLATE/feature_request.yml +31 -0
- torchsolve-0.0.1/.github/PULL_REQUEST_TEMPLATE.md +24 -0
- torchsolve-0.0.1/.github/dependabot.yml +39 -0
- torchsolve-0.0.1/.github/workflows/codeql.yml +31 -0
- torchsolve-0.0.1/.github/workflows/style.yml +40 -0
- torchsolve-0.0.1/.github/workflows/tags-release.yml +68 -0
- torchsolve-0.0.1/.github/workflows/test-ci.yml +75 -0
- torchsolve-0.0.1/.gitignore +28 -0
- torchsolve-0.0.1/.pre-commit-config.yaml +27 -0
- torchsolve-0.0.1/AGENTS.md +72 -0
- torchsolve-0.0.1/CLAUDE.md +74 -0
- torchsolve-0.0.1/CODE_OF_CONDUCT.md +42 -0
- torchsolve-0.0.1/CONTRIBUTING.md +45 -0
- torchsolve-0.0.1/GEMINI.md +74 -0
- torchsolve-0.0.1/LICENSE +21 -0
- torchsolve-0.0.1/PKG-INFO +223 -0
- torchsolve-0.0.1/README.md +193 -0
- torchsolve-0.0.1/SECURITY.md +33 -0
- torchsolve-0.0.1/codecov.yml +24 -0
- torchsolve-0.0.1/examples/.gitignore +2 -0
- torchsolve-0.0.1/examples/01-regularised_solve.ipynb +265 -0
- torchsolve-0.0.1/examples/01-regularised_solve.py +119 -0
- torchsolve-0.0.1/examples/02-preconditioning.ipynb +244 -0
- torchsolve-0.0.1/examples/02-preconditioning.py +119 -0
- torchsolve-0.0.1/examples/03-differentiable_weight.ipynb +251 -0
- torchsolve-0.0.1/examples/03-differentiable_weight.py +113 -0
- torchsolve-0.0.1/examples/04-irgnm.ipynb +342 -0
- torchsolve-0.0.1/examples/04-irgnm.py +151 -0
- torchsolve-0.0.1/examples/README.md +28 -0
- torchsolve-0.0.1/examples/figures/differentiable_weight.png +0 -0
- torchsolve-0.0.1/examples/figures/irgnm.png +0 -0
- torchsolve-0.0.1/examples/figures/make_showcase.py +158 -0
- torchsolve-0.0.1/examples/figures/preconditioning.png +0 -0
- torchsolve-0.0.1/examples/figures/regularised_solve.png +0 -0
- torchsolve-0.0.1/examples/figures/showcase.png +0 -0
- torchsolve-0.0.1/pyproject.toml +113 -0
- torchsolve-0.0.1/scripts/build_examples.sh +40 -0
- torchsolve-0.0.1/scripts/format_and_lint.sh +21 -0
- torchsolve-0.0.1/scripts/sync_agent_docs.sh +29 -0
- torchsolve-0.0.1/setup.cfg +4 -0
- torchsolve-0.0.1/setup.py +5 -0
- torchsolve-0.0.1/src/torchsolve/__init__.py +41 -0
- torchsolve-0.0.1/src/torchsolve/_cg.py +556 -0
- torchsolve-0.0.1/src/torchsolve/_irgnm.py +270 -0
- torchsolve-0.0.1/src/torchsolve/_problem.py +89 -0
- torchsolve-0.0.1/src/torchsolve/_solvers.py +304 -0
- torchsolve-0.0.1/src/torchsolve.egg-info/PKG-INFO +223 -0
- torchsolve-0.0.1/src/torchsolve.egg-info/SOURCES.txt +59 -0
- torchsolve-0.0.1/src/torchsolve.egg-info/dependency_links.txt +1 -0
- torchsolve-0.0.1/src/torchsolve.egg-info/requires.txt +9 -0
- torchsolve-0.0.1/src/torchsolve.egg-info/scm_file_list.json +56 -0
- torchsolve-0.0.1/src/torchsolve.egg-info/scm_version.json +8 -0
- torchsolve-0.0.1/src/torchsolve.egg-info/top_level.txt +1 -0
- torchsolve-0.0.1/tests/conftest.py +32 -0
- torchsolve-0.0.1/tests/test_cg.py +426 -0
- torchsolve-0.0.1/tests/test_docstrings.py +41 -0
- torchsolve-0.0.1/tests/test_irgnm.py +368 -0
- torchsolve-0.0.1/tests/test_smoke.py +8 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something behaves differently from what it says it does.
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what-happened
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened
|
|
9
|
+
description: What did you expect, and what did you get instead?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: reproduce
|
|
15
|
+
attributes:
|
|
16
|
+
label: Smallest reproduction
|
|
17
|
+
description: >
|
|
18
|
+
Code we can run. Prefer synthetic arrays over a data file; if the shape
|
|
19
|
+
of real data matters, give the shapes and dtypes.
|
|
20
|
+
render: python
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
|
|
24
|
+
- type: textarea
|
|
25
|
+
id: environment
|
|
26
|
+
attributes:
|
|
27
|
+
label: Environment
|
|
28
|
+
description: >
|
|
29
|
+
Output of `python -c "import torchsolve, sys, torch;
|
|
30
|
+
print(torchsolve.__version__, sys.version, torch.__version__,
|
|
31
|
+
torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'cpu')"`
|
|
32
|
+
render: shell
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
35
|
+
|
|
36
|
+
- type: dropdown
|
|
37
|
+
id: device
|
|
38
|
+
attributes:
|
|
39
|
+
label: Where it happens
|
|
40
|
+
options: ["CPU only", "CUDA only", "Both"]
|
|
41
|
+
validations:
|
|
42
|
+
required: true
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Question or idea
|
|
4
|
+
url: https://github.com/FiRMLAB-Pisa/torchsolve/discussions
|
|
5
|
+
about: Ask about usage, or propose something before it is a bug report.
|
|
6
|
+
- name: Security vulnerability
|
|
7
|
+
url: https://github.com/FiRMLAB-Pisa/torchsolve/security/advisories/new
|
|
8
|
+
about: Report privately. Please do not open a public issue.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Something this package should be able to do and cannot.
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: The problem
|
|
9
|
+
description: What are you trying to do, and where does it stop?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: proposal
|
|
15
|
+
attributes:
|
|
16
|
+
label: What you have in mind
|
|
17
|
+
description: >
|
|
18
|
+
A sketch of the API, if you have one. If there is a paper or another
|
|
19
|
+
implementation that does this, name it — that is usually the fastest
|
|
20
|
+
way to agree on what is wanted.
|
|
21
|
+
validations:
|
|
22
|
+
required: true
|
|
23
|
+
|
|
24
|
+
- type: textarea
|
|
25
|
+
id: layer
|
|
26
|
+
attributes:
|
|
27
|
+
label: Which layer this belongs to
|
|
28
|
+
description: >
|
|
29
|
+
This package is one of a family with a strict layering (`mrutils` at the
|
|
30
|
+
base, `deepmr` at the top). If the feature needs something from a
|
|
31
|
+
sibling package, say which — that usually means it belongs elsewhere.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. What behaviour is different afterwards? -->
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
<!-- The problem this solves. Link the issue if there is one. -->
|
|
8
|
+
|
|
9
|
+
## How it was verified
|
|
10
|
+
|
|
11
|
+
<!-- The commands you ran and what they said. Paste the output, don't
|
|
12
|
+
summarise it. "Tests pass" is not verification. -->
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Checklist
|
|
18
|
+
|
|
19
|
+
- [ ] `bash scripts/format_and_lint.sh` is clean
|
|
20
|
+
- [ ] `pytest -q` passes, and new behaviour has a test whose name states the
|
|
21
|
+
invariant it protects
|
|
22
|
+
- [ ] Anything numerical is exercised on CPU and CUDA, or the CUDA leg is
|
|
23
|
+
marked `@pytest.mark.cuda` and skips cleanly
|
|
24
|
+
- [ ] No comment or docstring describes the code's history
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# The Actions in .github/workflows pin third-party code that runs with
|
|
4
|
+
# repository credentials, so these are the updates worth having weekly.
|
|
5
|
+
- package-ecosystem: github-actions
|
|
6
|
+
directory: "/"
|
|
7
|
+
schedule:
|
|
8
|
+
interval: weekly
|
|
9
|
+
day: monday
|
|
10
|
+
labels: ["dependencies", "ci"]
|
|
11
|
+
commit-message:
|
|
12
|
+
prefix: "ci"
|
|
13
|
+
groups:
|
|
14
|
+
actions:
|
|
15
|
+
patterns: ["*"]
|
|
16
|
+
|
|
17
|
+
# Grouped so the numerical stack arrives as one pull request that can be
|
|
18
|
+
# tested together rather than as several that each need a full suite run.
|
|
19
|
+
- package-ecosystem: pip
|
|
20
|
+
directory: "/"
|
|
21
|
+
schedule:
|
|
22
|
+
interval: weekly
|
|
23
|
+
day: monday
|
|
24
|
+
open-pull-requests-limit: 5
|
|
25
|
+
labels: ["dependencies", "python"]
|
|
26
|
+
commit-message:
|
|
27
|
+
prefix: "deps"
|
|
28
|
+
groups:
|
|
29
|
+
numerical:
|
|
30
|
+
patterns: ["numpy", "scipy", "torch*", "triton", "mri-nufft", "finufft", "cufinufft"]
|
|
31
|
+
mr-stack:
|
|
32
|
+
patterns: ["mrutils", "mrtoeplitz", "mrllr", "mrmotion", "mrdistortion", "torchsolve", "deepinv", "SimpleITK"]
|
|
33
|
+
dev-tooling:
|
|
34
|
+
patterns: ["pytest*", "coverage", "ruff", "pre-commit", "build", "sphinx*"]
|
|
35
|
+
ignore:
|
|
36
|
+
# Torch major bumps move the CUDA runtime under the whole family, so they
|
|
37
|
+
# are a deliberate decision rather than a routine update.
|
|
38
|
+
- dependency-name: "torch"
|
|
39
|
+
update-types: ["version-update:semver-major"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
analyze:
|
|
11
|
+
name: Analyze Python
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
# Code scanning on a private repository needs GitHub Advanced Security,
|
|
14
|
+
# and uploading results without it is a hard error rather than a warning.
|
|
15
|
+
# The job stands down while the repository is private and starts working
|
|
16
|
+
# on its own once it is made public.
|
|
17
|
+
if: github.event.repository.visibility == 'public'
|
|
18
|
+
permissions:
|
|
19
|
+
security-events: write
|
|
20
|
+
packages: read
|
|
21
|
+
actions: read
|
|
22
|
+
contents: read
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v7
|
|
25
|
+
- uses: github/codeql-action/init@v4
|
|
26
|
+
with:
|
|
27
|
+
languages: python
|
|
28
|
+
build-mode: none
|
|
29
|
+
- uses: github/codeql-action/analyze@v4
|
|
30
|
+
with:
|
|
31
|
+
category: "/language:python"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Style
|
|
2
|
+
|
|
3
|
+
# Runs the same script pre-commit runs, in --check mode: nothing is rewritten
|
|
4
|
+
# and any file that would change fails the job.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
pull_request:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
format-and-lint:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- uses: actions/setup-python@v7
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.11"
|
|
23
|
+
|
|
24
|
+
# The linter only, taken from the same `dev` extra a contributor's
|
|
25
|
+
# pre-commit installs, so both apply one ruff. Installing the extra whole
|
|
26
|
+
# would download the runtime for a job that never imports it.
|
|
27
|
+
- name: Install ruff
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
python - <<'PY' > "$RUNNER_TEMP/lint-requirements.txt"
|
|
31
|
+
import tomllib
|
|
32
|
+
|
|
33
|
+
with open("pyproject.toml", "rb") as pyproject:
|
|
34
|
+
dev = tomllib.load(pyproject)["project"]["optional-dependencies"]["dev"]
|
|
35
|
+
print("\n".join(line for line in dev if line.startswith("ruff")))
|
|
36
|
+
PY
|
|
37
|
+
python -m pip install -r "$RUNNER_TEMP/lint-requirements.txt"
|
|
38
|
+
|
|
39
|
+
- name: Format and lint (check only)
|
|
40
|
+
run: bash scripts/format_and_lint.sh --check
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes a tagged version: sdist and wheel, then PyPI and a signed GitHub
|
|
4
|
+
# release. The version comes from the tag via setuptools_scm.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags:
|
|
9
|
+
- "v[0-9]+.[0-9]+.[0-9]+"
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
- uses: actions/setup-python@v7
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.11"
|
|
21
|
+
- run: |
|
|
22
|
+
python -m pip install --upgrade pip build
|
|
23
|
+
python -m build
|
|
24
|
+
- uses: actions/upload-artifact@v7
|
|
25
|
+
with:
|
|
26
|
+
name: dist
|
|
27
|
+
path: dist/
|
|
28
|
+
if-no-files-found: error
|
|
29
|
+
|
|
30
|
+
publish-to-pypi:
|
|
31
|
+
needs: [build]
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
environment:
|
|
34
|
+
name: pypi
|
|
35
|
+
url: https://pypi.org/p/torchsolve
|
|
36
|
+
permissions:
|
|
37
|
+
id-token: write # trusted publishing (OIDC)
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/download-artifact@v8
|
|
40
|
+
with:
|
|
41
|
+
name: dist
|
|
42
|
+
path: dist
|
|
43
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
44
|
+
|
|
45
|
+
github-release:
|
|
46
|
+
needs: [publish-to-pypi]
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
permissions:
|
|
49
|
+
contents: write # create the release
|
|
50
|
+
id-token: write # sigstore
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/download-artifact@v8
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist
|
|
56
|
+
- uses: sigstore/gh-action-sigstore-python@v3.5.0
|
|
57
|
+
with:
|
|
58
|
+
inputs: |
|
|
59
|
+
./dist/*.tar.gz
|
|
60
|
+
./dist/*.whl
|
|
61
|
+
- env:
|
|
62
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
63
|
+
run: |
|
|
64
|
+
gh release create '${{ github.ref_name }}' \
|
|
65
|
+
--repo '${{ github.repository }}' \
|
|
66
|
+
--title '${{ github.ref_name }}' \
|
|
67
|
+
--generate-notes
|
|
68
|
+
gh release upload '${{ github.ref_name }}' dist/** --repo '${{ github.repository }}'
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Python ${{ matrix.python-version }}
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
# The floor and the ceiling of the supported band: an intermediate
|
|
20
|
+
# release that fails on neither is not a plausible failure.
|
|
21
|
+
python-version: ["3.10", "3.13"]
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0 # setuptools_scm reads the tags
|
|
26
|
+
|
|
27
|
+
- uses: actions/setup-python@v7
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
cache: pip
|
|
31
|
+
|
|
32
|
+
- name: Install
|
|
33
|
+
run: |
|
|
34
|
+
python -m pip install --upgrade pip
|
|
35
|
+
# Torch's default Linux wheel bundles the CUDA runtime: gigabytes the
|
|
36
|
+
# runner has no disk for and no device to use. Installing the CPU
|
|
37
|
+
# build first is what the rest resolves against.
|
|
38
|
+
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
|
|
39
|
+
python -m pip install .[dev]
|
|
40
|
+
|
|
41
|
+
- name: Run the tests
|
|
42
|
+
run: pytest -q --cov --cov-report=xml
|
|
43
|
+
|
|
44
|
+
- uses: codecov/codecov-action@v7
|
|
45
|
+
with:
|
|
46
|
+
fail_ci_if_error: false
|
|
47
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
48
|
+
slug: FiRMLAB-Pisa/torchsolve
|
|
49
|
+
|
|
50
|
+
# Proves the claim the dependency layout rests on: with no CUDA extra and no
|
|
51
|
+
# device, nothing errors -- the GPU tests skip.
|
|
52
|
+
gpu-tests-skip-cleanly:
|
|
53
|
+
name: GPU tests skip without a GPU
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v7
|
|
57
|
+
with:
|
|
58
|
+
fetch-depth: 0
|
|
59
|
+
- uses: actions/setup-python@v7
|
|
60
|
+
with:
|
|
61
|
+
python-version: "3.11"
|
|
62
|
+
cache: pip
|
|
63
|
+
- run: |
|
|
64
|
+
python -m pip install --upgrade pip
|
|
65
|
+
# Torch's default Linux wheel bundles the CUDA runtime: gigabytes the
|
|
66
|
+
# runner has no disk for and no device to use. Installing the CPU
|
|
67
|
+
# build first is what the rest resolves against.
|
|
68
|
+
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
|
|
69
|
+
python -m pip install .[dev]
|
|
70
|
+
# Exit 5 is "nothing matched", which is also a clean outcome here: the
|
|
71
|
+
# point is that no CUDA-marked test errors on a machine without a device.
|
|
72
|
+
- run: |
|
|
73
|
+
status=0
|
|
74
|
+
pytest -q -rs -m cuda || status=$?
|
|
75
|
+
[ "$status" -eq 0 ] || [ "$status" -eq 5 ]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.so
|
|
4
|
+
.Python
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
wheelhouse/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
.eggs/
|
|
10
|
+
|
|
11
|
+
.venv/
|
|
12
|
+
venv/
|
|
13
|
+
.env
|
|
14
|
+
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
.coverage.*
|
|
20
|
+
coverage.xml
|
|
21
|
+
htmlcov/
|
|
22
|
+
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
.DS_Store
|
|
26
|
+
|
|
27
|
+
# Benchmark inputs are fetched, never committed.
|
|
28
|
+
data/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# The rules live in scripts/format_and_lint.sh, which the Style workflow also
|
|
2
|
+
# runs (there with --check). One entry point means a commit cannot pass locally
|
|
3
|
+
# and fail in CI on style.
|
|
4
|
+
repos:
|
|
5
|
+
- repo: local
|
|
6
|
+
hooks:
|
|
7
|
+
- id: format-and-lint
|
|
8
|
+
name: format and lint
|
|
9
|
+
entry: bash scripts/format_and_lint.sh
|
|
10
|
+
language: system
|
|
11
|
+
pass_filenames: false
|
|
12
|
+
types_or: [python, markdown]
|
|
13
|
+
|
|
14
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
15
|
+
rev: v6.0.0
|
|
16
|
+
hooks:
|
|
17
|
+
- id: check-merge-conflict
|
|
18
|
+
- id: end-of-file-fixer
|
|
19
|
+
- id: trailing-whitespace
|
|
20
|
+
- id: check-yaml
|
|
21
|
+
- id: check-toml
|
|
22
|
+
- id: check-added-large-files
|
|
23
|
+
args: [--maxkb=1024]
|
|
24
|
+
- id: check-symlinks
|
|
25
|
+
- id: destroyed-symlinks
|
|
26
|
+
- id: mixed-line-ending
|
|
27
|
+
args: [--fix=lf]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# torchsolve — agent instructions
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
This file is the SOURCE. CLAUDE.md and GEMINI.md are generated from it by
|
|
5
|
+
scripts/sync_agent_docs.sh, which pre-commit runs. Edit this file, never those.
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
## What this package is
|
|
9
|
+
|
|
10
|
+
Memory-lean iterative solvers for inverse problems in PyTorch: preconditioned CG with arbitrary regularisation, differentiable by implicit differentiation.
|
|
11
|
+
|
|
12
|
+
It is one of a family of small, single-purpose MRI packages. The layering is
|
|
13
|
+
strict: `mrutils` is the base; `torchsolve`, `mrtoeplitz`, `mrllr`, `mrmotion`
|
|
14
|
+
and `mrdistortion` sit on it and never import each other; `deepmr` sits on all
|
|
15
|
+
of them. If you find yourself wanting a sibling's code, the answer is either to
|
|
16
|
+
move it down into `mrutils` or to move the caller up into `deepmr`.
|
|
17
|
+
|
|
18
|
+
**deepinv is a `deepmr`-only dependency.** Everything below it is plain Torch
|
|
19
|
+
with duck-typed operators (`A`, `A_adjoint`, `shape`). Do not import deepinv
|
|
20
|
+
here unless this package is `deepmr`.
|
|
21
|
+
|
|
22
|
+
## Build and test
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install -e .[dev]
|
|
26
|
+
bash scripts/format_and_lint.sh # rewrites in place; --check to verify only
|
|
27
|
+
pytest -q
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Build and test steps are mandatory before reporting a change complete. Run them
|
|
31
|
+
and report the exact output; do not assume success.
|
|
32
|
+
|
|
33
|
+
## Tests
|
|
34
|
+
|
|
35
|
+
pytest with plain functions and fixtures — never `unittest.TestCase`. A test
|
|
36
|
+
name states the invariant it protects, so a failure reads as a sentence.
|
|
37
|
+
|
|
38
|
+
Anything numerical that can run on CPU and CUDA is parametrised over both, and
|
|
39
|
+
the CUDA leg skips when no device is present. A kernel-layout check that ran on
|
|
40
|
+
CPU only has passed in this codebase while CUDA was 100% wrong.
|
|
41
|
+
|
|
42
|
+
## Comments and docstrings
|
|
43
|
+
|
|
44
|
+
Write for someone reading the code as it is now, who has no memory of any
|
|
45
|
+
earlier version of it. **Never** write text whose subject is the history of the
|
|
46
|
+
code. Banned in comments, docstrings and prose alike:
|
|
47
|
+
|
|
48
|
+
- "used to", "was once", "no longer", "previously", "now that", "this replaces",
|
|
49
|
+
"the old X", "before the fix"
|
|
50
|
+
- justifying the present shape by contrast with a shape that is gone
|
|
51
|
+
- naming a bug that has been fixed, or the session that fixed it
|
|
52
|
+
- restating what the code plainly says
|
|
53
|
+
|
|
54
|
+
A docstring carries what a caller needs: one line of what, Parameters, Returns,
|
|
55
|
+
Raises. A comment earns its place only by explaining a non-obvious algorithm or
|
|
56
|
+
a choice a reader would otherwise undo — and even then, prefer a well-named
|
|
57
|
+
function or a test whose name states the invariant, because those cannot go
|
|
58
|
+
stale silently. When tempted to explain *why not the other way*, write a test.
|
|
59
|
+
|
|
60
|
+
Stale comments are actively harmful. Deleting an outdated comment is always
|
|
61
|
+
correct; rewriting one to describe the change is not.
|
|
62
|
+
|
|
63
|
+
## Documentation style
|
|
64
|
+
|
|
65
|
+
The audience is MR scientists. Write in the vocabulary of pulse sequences and
|
|
66
|
+
physics, not of software architecture. Never justify a design by describing the
|
|
67
|
+
design it replaced.
|
|
68
|
+
|
|
69
|
+
Do not print a measured constant that is not guaranteed across releases or
|
|
70
|
+
hardware. Name the symbol and where it comes from, and let the build supply the
|
|
71
|
+
number. Benchmark tables in the README are regenerated by the benchmark script,
|
|
72
|
+
not typed in.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<!-- Generated from AGENTS.md by scripts/sync_agent_docs.sh. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
# torchsolve — agent instructions
|
|
4
|
+
|
|
5
|
+
<!--
|
|
6
|
+
This file is the SOURCE. CLAUDE.md and GEMINI.md are generated from it by
|
|
7
|
+
scripts/sync_agent_docs.sh, which pre-commit runs. Edit this file, never those.
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
## What this package is
|
|
11
|
+
|
|
12
|
+
Memory-lean iterative solvers for inverse problems in PyTorch: preconditioned CG with arbitrary regularisation, differentiable by implicit differentiation.
|
|
13
|
+
|
|
14
|
+
It is one of a family of small, single-purpose MRI packages. The layering is
|
|
15
|
+
strict: `mrutils` is the base; `torchsolve`, `mrtoeplitz`, `mrllr`, `mrmotion`
|
|
16
|
+
and `mrdistortion` sit on it and never import each other; `deepmr` sits on all
|
|
17
|
+
of them. If you find yourself wanting a sibling's code, the answer is either to
|
|
18
|
+
move it down into `mrutils` or to move the caller up into `deepmr`.
|
|
19
|
+
|
|
20
|
+
**deepinv is a `deepmr`-only dependency.** Everything below it is plain Torch
|
|
21
|
+
with duck-typed operators (`A`, `A_adjoint`, `shape`). Do not import deepinv
|
|
22
|
+
here unless this package is `deepmr`.
|
|
23
|
+
|
|
24
|
+
## Build and test
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install -e .[dev]
|
|
28
|
+
bash scripts/format_and_lint.sh # rewrites in place; --check to verify only
|
|
29
|
+
pytest -q
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Build and test steps are mandatory before reporting a change complete. Run them
|
|
33
|
+
and report the exact output; do not assume success.
|
|
34
|
+
|
|
35
|
+
## Tests
|
|
36
|
+
|
|
37
|
+
pytest with plain functions and fixtures — never `unittest.TestCase`. A test
|
|
38
|
+
name states the invariant it protects, so a failure reads as a sentence.
|
|
39
|
+
|
|
40
|
+
Anything numerical that can run on CPU and CUDA is parametrised over both, and
|
|
41
|
+
the CUDA leg skips when no device is present. A kernel-layout check that ran on
|
|
42
|
+
CPU only has passed in this codebase while CUDA was 100% wrong.
|
|
43
|
+
|
|
44
|
+
## Comments and docstrings
|
|
45
|
+
|
|
46
|
+
Write for someone reading the code as it is now, who has no memory of any
|
|
47
|
+
earlier version of it. **Never** write text whose subject is the history of the
|
|
48
|
+
code. Banned in comments, docstrings and prose alike:
|
|
49
|
+
|
|
50
|
+
- "used to", "was once", "no longer", "previously", "now that", "this replaces",
|
|
51
|
+
"the old X", "before the fix"
|
|
52
|
+
- justifying the present shape by contrast with a shape that is gone
|
|
53
|
+
- naming a bug that has been fixed, or the session that fixed it
|
|
54
|
+
- restating what the code plainly says
|
|
55
|
+
|
|
56
|
+
A docstring carries what a caller needs: one line of what, Parameters, Returns,
|
|
57
|
+
Raises. A comment earns its place only by explaining a non-obvious algorithm or
|
|
58
|
+
a choice a reader would otherwise undo — and even then, prefer a well-named
|
|
59
|
+
function or a test whose name states the invariant, because those cannot go
|
|
60
|
+
stale silently. When tempted to explain *why not the other way*, write a test.
|
|
61
|
+
|
|
62
|
+
Stale comments are actively harmful. Deleting an outdated comment is always
|
|
63
|
+
correct; rewriting one to describe the change is not.
|
|
64
|
+
|
|
65
|
+
## Documentation style
|
|
66
|
+
|
|
67
|
+
The audience is MR scientists. Write in the vocabulary of pulse sequences and
|
|
68
|
+
physics, not of software architecture. Never justify a design by describing the
|
|
69
|
+
design it replaced.
|
|
70
|
+
|
|
71
|
+
Do not print a measured constant that is not guaranteed across releases or
|
|
72
|
+
hardware. Name the symbol and where it comes from, and let the build supply the
|
|
73
|
+
number. Benchmark tables in the README are regenerated by the benchmark script,
|
|
74
|
+
not typed in.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Code of conduct
|
|
2
|
+
|
|
3
|
+
## Our pledge
|
|
4
|
+
|
|
5
|
+
We pledge to make participation in this project a harassment-free experience
|
|
6
|
+
for everyone, regardless of age, body size, visible or invisible disability,
|
|
7
|
+
ethnicity, sex characteristics, gender identity and expression, level of
|
|
8
|
+
experience, education, socio-economic status, nationality, personal
|
|
9
|
+
appearance, race, religion, or sexual identity and orientation.
|
|
10
|
+
|
|
11
|
+
## Our standards
|
|
12
|
+
|
|
13
|
+
Behaviour that helps:
|
|
14
|
+
|
|
15
|
+
- showing empathy and kindness toward other people
|
|
16
|
+
- respecting differing opinions, viewpoints, and experiences
|
|
17
|
+
- giving and gracefully accepting constructive feedback
|
|
18
|
+
- accepting responsibility, apologising to those affected by our mistakes,
|
|
19
|
+
and learning from the experience
|
|
20
|
+
|
|
21
|
+
Behaviour that is not acceptable:
|
|
22
|
+
|
|
23
|
+
- sexualised language or imagery, and sexual attention or advances of any kind
|
|
24
|
+
- trolling, insulting or derogatory comments, and personal or political attacks
|
|
25
|
+
- public or private harassment
|
|
26
|
+
- publishing others' private information, such as a physical or email address,
|
|
27
|
+
without their explicit permission
|
|
28
|
+
|
|
29
|
+
## Enforcement
|
|
30
|
+
|
|
31
|
+
Report abusive, harassing, or otherwise unacceptable behaviour to
|
|
32
|
+
matteo.cencini@gmail.com. All complaints will be reviewed and investigated
|
|
33
|
+
promptly and fairly. The maintainers will respect the privacy and security of
|
|
34
|
+
the reporter of any incident.
|
|
35
|
+
|
|
36
|
+
Maintainers who do not follow or enforce this code in good faith may face
|
|
37
|
+
temporary or permanent repercussions as determined by other maintainers.
|
|
38
|
+
|
|
39
|
+
## Attribution
|
|
40
|
+
|
|
41
|
+
Adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
|
|
42
|
+
version 2.1.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Contributing to torchsolve
|
|
2
|
+
|
|
3
|
+
## Getting set up
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone https://github.com/FiRMLAB-Pisa/torchsolve.git
|
|
7
|
+
cd torchsolve
|
|
8
|
+
python -m venv .venv && source .venv/bin/activate
|
|
9
|
+
pip install -e .[dev]
|
|
10
|
+
pre-commit install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Before you open a pull request
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bash scripts/format_and_lint.sh # rewrites in place
|
|
17
|
+
pytest -q
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
CI runs the same script with `--check`, so anything that passes locally passes
|
|
21
|
+
there. If `pre-commit` rewrites a file, stage it and commit again.
|
|
22
|
+
|
|
23
|
+
## What the tests expect
|
|
24
|
+
|
|
25
|
+
- pytest with plain functions and fixtures. No `unittest.TestCase` subclasses.
|
|
26
|
+
- A test name states the invariant it protects, so a failure reads as a
|
|
27
|
+
sentence: `test_a_double_precision_basis_does_not_reach_the_kernel`.
|
|
28
|
+
- Anything that can run on both CPU and CUDA is parametrised over both, and
|
|
29
|
+
the CUDA leg skips cleanly when no device is present. A numerical check that
|
|
30
|
+
only ever ran on CPU has, in this codebase's history, passed while the CUDA
|
|
31
|
+
path was completely wrong.
|
|
32
|
+
|
|
33
|
+
## Comments and documentation
|
|
34
|
+
|
|
35
|
+
Write for someone reading the code as it is now, with no memory of an earlier
|
|
36
|
+
version. Do not write text whose subject is the history of the code — no "used
|
|
37
|
+
to", "previously", "this replaces", no naming a bug that is fixed. A comment
|
|
38
|
+
earns its place by explaining a non-obvious algorithm or a choice a reader
|
|
39
|
+
would otherwise undo; prefer a well-named function, or a test whose name states
|
|
40
|
+
the invariant, because those cannot go stale silently.
|
|
41
|
+
|
|
42
|
+
## Releasing
|
|
43
|
+
|
|
44
|
+
Versions come from git tags via `setuptools_scm`. Push a tag matching
|
|
45
|
+
`v[0-9]+.[0-9]+.[0-9]+` and the release workflow builds, signs and publishes it.
|