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.
Files changed (61) hide show
  1. torchsolve-0.0.1/.gitattributes +11 -0
  2. torchsolve-0.0.1/.github/ISSUE_TEMPLATE/bug_report.yml +42 -0
  3. torchsolve-0.0.1/.github/ISSUE_TEMPLATE/config.yml +8 -0
  4. torchsolve-0.0.1/.github/ISSUE_TEMPLATE/feature_request.yml +31 -0
  5. torchsolve-0.0.1/.github/PULL_REQUEST_TEMPLATE.md +24 -0
  6. torchsolve-0.0.1/.github/dependabot.yml +39 -0
  7. torchsolve-0.0.1/.github/workflows/codeql.yml +31 -0
  8. torchsolve-0.0.1/.github/workflows/style.yml +40 -0
  9. torchsolve-0.0.1/.github/workflows/tags-release.yml +68 -0
  10. torchsolve-0.0.1/.github/workflows/test-ci.yml +75 -0
  11. torchsolve-0.0.1/.gitignore +28 -0
  12. torchsolve-0.0.1/.pre-commit-config.yaml +27 -0
  13. torchsolve-0.0.1/AGENTS.md +72 -0
  14. torchsolve-0.0.1/CLAUDE.md +74 -0
  15. torchsolve-0.0.1/CODE_OF_CONDUCT.md +42 -0
  16. torchsolve-0.0.1/CONTRIBUTING.md +45 -0
  17. torchsolve-0.0.1/GEMINI.md +74 -0
  18. torchsolve-0.0.1/LICENSE +21 -0
  19. torchsolve-0.0.1/PKG-INFO +223 -0
  20. torchsolve-0.0.1/README.md +193 -0
  21. torchsolve-0.0.1/SECURITY.md +33 -0
  22. torchsolve-0.0.1/codecov.yml +24 -0
  23. torchsolve-0.0.1/examples/.gitignore +2 -0
  24. torchsolve-0.0.1/examples/01-regularised_solve.ipynb +265 -0
  25. torchsolve-0.0.1/examples/01-regularised_solve.py +119 -0
  26. torchsolve-0.0.1/examples/02-preconditioning.ipynb +244 -0
  27. torchsolve-0.0.1/examples/02-preconditioning.py +119 -0
  28. torchsolve-0.0.1/examples/03-differentiable_weight.ipynb +251 -0
  29. torchsolve-0.0.1/examples/03-differentiable_weight.py +113 -0
  30. torchsolve-0.0.1/examples/04-irgnm.ipynb +342 -0
  31. torchsolve-0.0.1/examples/04-irgnm.py +151 -0
  32. torchsolve-0.0.1/examples/README.md +28 -0
  33. torchsolve-0.0.1/examples/figures/differentiable_weight.png +0 -0
  34. torchsolve-0.0.1/examples/figures/irgnm.png +0 -0
  35. torchsolve-0.0.1/examples/figures/make_showcase.py +158 -0
  36. torchsolve-0.0.1/examples/figures/preconditioning.png +0 -0
  37. torchsolve-0.0.1/examples/figures/regularised_solve.png +0 -0
  38. torchsolve-0.0.1/examples/figures/showcase.png +0 -0
  39. torchsolve-0.0.1/pyproject.toml +113 -0
  40. torchsolve-0.0.1/scripts/build_examples.sh +40 -0
  41. torchsolve-0.0.1/scripts/format_and_lint.sh +21 -0
  42. torchsolve-0.0.1/scripts/sync_agent_docs.sh +29 -0
  43. torchsolve-0.0.1/setup.cfg +4 -0
  44. torchsolve-0.0.1/setup.py +5 -0
  45. torchsolve-0.0.1/src/torchsolve/__init__.py +41 -0
  46. torchsolve-0.0.1/src/torchsolve/_cg.py +556 -0
  47. torchsolve-0.0.1/src/torchsolve/_irgnm.py +270 -0
  48. torchsolve-0.0.1/src/torchsolve/_problem.py +89 -0
  49. torchsolve-0.0.1/src/torchsolve/_solvers.py +304 -0
  50. torchsolve-0.0.1/src/torchsolve.egg-info/PKG-INFO +223 -0
  51. torchsolve-0.0.1/src/torchsolve.egg-info/SOURCES.txt +59 -0
  52. torchsolve-0.0.1/src/torchsolve.egg-info/dependency_links.txt +1 -0
  53. torchsolve-0.0.1/src/torchsolve.egg-info/requires.txt +9 -0
  54. torchsolve-0.0.1/src/torchsolve.egg-info/scm_file_list.json +56 -0
  55. torchsolve-0.0.1/src/torchsolve.egg-info/scm_version.json +8 -0
  56. torchsolve-0.0.1/src/torchsolve.egg-info/top_level.txt +1 -0
  57. torchsolve-0.0.1/tests/conftest.py +32 -0
  58. torchsolve-0.0.1/tests/test_cg.py +426 -0
  59. torchsolve-0.0.1/tests/test_docstrings.py +41 -0
  60. torchsolve-0.0.1/tests/test_irgnm.py +368 -0
  61. torchsolve-0.0.1/tests/test_smoke.py +8 -0
@@ -0,0 +1,11 @@
1
+ * text=auto eol=lf
2
+
3
+ *.png binary
4
+ *.jpg binary
5
+ *.npy binary
6
+ *.npz binary
7
+ *.mat binary
8
+ *.h5 binary
9
+
10
+ # Generated: keep them out of diffs and out of the language statistics.
11
+ *.ipynb linguist-documentation=true
@@ -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.