torchsparsegradutils 0.2.2__tar.gz → 0.2.3__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.
- {torchsparsegradutils-0.2.2/torchsparsegradutils.egg-info → torchsparsegradutils-0.2.3}/PKG-INFO +1 -1
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/docs/source/conf.py +2 -2
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/pyproject.toml +1 -1
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/sparse_solve.py +9 -2
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_jax_bindings.py +1 -5
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_sparse_solve.py +222 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3/torchsparsegradutils.egg-info}/PKG-INFO +1 -1
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/LICENSE +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/MANIFEST.in +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/README.md +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/setup.cfg +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/setup.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/batched_sparse_mm_rand.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/benchmark_suite.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/benchmark_utils.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/sparse_generic_solve_rand.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/sparse_generic_solve_suite.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/sparse_mm_rand.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/sparse_mm_suite.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/sparse_triangular_solve_rand.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/sparse_triangular_solve_suitesparse.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/benchmarks/visualize_benchmark_results.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/cupy/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/cupy/cupy_bindings.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/cupy/cupy_sparse_solve.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/distributions/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/distributions/constraints.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/distributions/sparse_multivariate_normal.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/encoders/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/encoders/pairwise_encoder.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/encoders/pairwise_voxel_encoder.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/indexed_matmul.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/jax/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/jax/jax_bindings.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/jax/jax_sparse_solve.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/sparse_lstsq.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/sparse_matmul.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/conftest.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_bicgstab.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_config.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_cupy_bindings.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_cupy_sparse_solve.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_dist_stats_helpers.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_distributions.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_doctests.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_encoders.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_indexed_matmul.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_integration_pairwise_sparse_mvn.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_jax_sparse_solve.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_linear_cg.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_lsmr.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_minres.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_params/czyx_shifts.yaml +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_params/pairwise_coo_indices.yaml +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_params/xyz_coords.yaml +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_quickstart_guide.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_random.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_sparse_lstsq.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_sparse_matmul.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_sparse_triangular_solve.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_utils.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/__init__.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/bicgstab.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/dist_stats_helpers.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/linear_cg.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/lsmr.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/minres.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/random_sparse.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/utils.py +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/SOURCES.txt +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/dependency_links.txt +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/not-zip-safe +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/requires.txt +0 -0
- {torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/top_level.txt +0 -0
|
@@ -15,8 +15,8 @@ sys.path.insert(0, os.path.abspath("../../"))
|
|
|
15
15
|
project = "torchsparsegradutils"
|
|
16
16
|
copyright = "2026, CAI4CAI research group"
|
|
17
17
|
author = "CAI4CAI research group"
|
|
18
|
-
release = "0.2.
|
|
19
|
-
version = "0.2.
|
|
18
|
+
release = "0.2.3"
|
|
19
|
+
version = "0.2.3"
|
|
20
20
|
|
|
21
21
|
# -- General configuration ---------------------------------------------------
|
|
22
22
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/sparse_solve.py
RENAMED
|
@@ -438,6 +438,7 @@ class SparseGenericSolve(torch.autograd.Function):
|
|
|
438
438
|
@staticmethod
|
|
439
439
|
def forward(ctx, A, B, solve, transpose_solve, kwargs):
|
|
440
440
|
grad_flag = A.requires_grad or B.requires_grad
|
|
441
|
+
ctx.solve = solve
|
|
441
442
|
ctx.transpose_solve = transpose_solve
|
|
442
443
|
ctx.kwargs = kwargs # Store kwargs for backward pass
|
|
443
444
|
|
|
@@ -449,7 +450,7 @@ class SparseGenericSolve(torch.autograd.Function):
|
|
|
449
450
|
|
|
450
451
|
x.requires_grad = grad_flag
|
|
451
452
|
|
|
452
|
-
ctx.save_for_backward(A, x
|
|
453
|
+
ctx.save_for_backward(A, x)
|
|
453
454
|
return x
|
|
454
455
|
|
|
455
456
|
@staticmethod
|
|
@@ -463,7 +464,13 @@ class SparseGenericSolve(torch.autograd.Function):
|
|
|
463
464
|
grad = grad.unsqueeze(-1)
|
|
464
465
|
|
|
465
466
|
# Backprop rule: gradB = A^{-T} grad
|
|
466
|
-
gradB =
|
|
467
|
+
gradB = sparse_generic_solve(
|
|
468
|
+
A,
|
|
469
|
+
grad,
|
|
470
|
+
solve=ctx.transpose_solve,
|
|
471
|
+
transpose_solve=ctx.solve,
|
|
472
|
+
**ctx.kwargs,
|
|
473
|
+
)
|
|
467
474
|
|
|
468
475
|
# Ensure gradient dtype matches input dtype
|
|
469
476
|
if gradB.dtype != A.dtype:
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
import jax
|
|
2
1
|
import numpy as np
|
|
3
2
|
import pytest
|
|
4
3
|
import torch
|
|
5
4
|
from test_config import DEVICES
|
|
6
5
|
|
|
7
|
-
import torchsparsegradutils as tsgu
|
|
8
6
|
import torchsparsegradutils.jax as tsgujax
|
|
9
7
|
|
|
10
8
|
# skip if JAX unavailable
|
|
11
|
-
pytest.importorskip("jax")
|
|
9
|
+
jax = pytest.importorskip("jax")
|
|
12
10
|
if not tsgujax.have_jax:
|
|
13
11
|
pytest.skip("JAX bindings unavailable, skipping jax tests", allow_module_level=True)
|
|
14
12
|
|
|
15
|
-
import jax.numpy as jnp
|
|
16
|
-
|
|
17
13
|
|
|
18
14
|
def _id_device(d):
|
|
19
15
|
return str(d)
|
|
@@ -42,6 +42,132 @@ def solve_id(solve):
|
|
|
42
42
|
return "default"
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
def _make_differentiable_tridiag_spd(theta, layout):
|
|
46
|
+
"""Create a small sparse SPD matrix with fixed sparsity and differentiable values."""
|
|
47
|
+
n = theta.numel()
|
|
48
|
+
device = theta.device
|
|
49
|
+
|
|
50
|
+
diag = theta.square() + 2.0
|
|
51
|
+
off = -0.1 * torch.sigmoid(theta[:-1])
|
|
52
|
+
|
|
53
|
+
rows = torch.cat(
|
|
54
|
+
[
|
|
55
|
+
torch.arange(n, device=device),
|
|
56
|
+
torch.arange(n - 1, device=device),
|
|
57
|
+
torch.arange(1, n, device=device),
|
|
58
|
+
]
|
|
59
|
+
)
|
|
60
|
+
cols = torch.cat(
|
|
61
|
+
[
|
|
62
|
+
torch.arange(n, device=device),
|
|
63
|
+
torch.arange(1, n, device=device),
|
|
64
|
+
torch.arange(n - 1, device=device),
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
values = torch.cat([diag, off, off])
|
|
68
|
+
|
|
69
|
+
A = torch.sparse_coo_tensor(torch.stack([rows, cols]), values, (n, n)).coalesce()
|
|
70
|
+
if layout == torch.sparse_csr:
|
|
71
|
+
A = A.to_sparse_csr()
|
|
72
|
+
return A, A.to_dense()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _make_differentiable_nonsymmetric_tridiag(theta, layout):
|
|
76
|
+
"""Create a small fixed-sparsity non-symmetric diagonally dominant matrix."""
|
|
77
|
+
n = 6
|
|
78
|
+
device = theta.device
|
|
79
|
+
dtype = theta.dtype
|
|
80
|
+
|
|
81
|
+
if theta.numel() != 3 * n - 2:
|
|
82
|
+
raise ValueError(f"theta should have length {3 * n - 2}, got {theta.numel()}")
|
|
83
|
+
|
|
84
|
+
diag_theta = theta[:n]
|
|
85
|
+
upper_theta = theta[n : n + n - 1]
|
|
86
|
+
lower_theta = theta[n + n - 1 :]
|
|
87
|
+
|
|
88
|
+
diag = diag_theta.square() + 3.0
|
|
89
|
+
upper = 0.05 * torch.tanh(upper_theta)
|
|
90
|
+
lower = -0.08 * torch.sigmoid(lower_theta)
|
|
91
|
+
|
|
92
|
+
rows = torch.cat(
|
|
93
|
+
[
|
|
94
|
+
torch.arange(n, device=device),
|
|
95
|
+
torch.arange(n - 1, device=device),
|
|
96
|
+
torch.arange(1, n, device=device),
|
|
97
|
+
]
|
|
98
|
+
)
|
|
99
|
+
cols = torch.cat(
|
|
100
|
+
[
|
|
101
|
+
torch.arange(n, device=device),
|
|
102
|
+
torch.arange(1, n, device=device),
|
|
103
|
+
torch.arange(n - 1, device=device),
|
|
104
|
+
]
|
|
105
|
+
)
|
|
106
|
+
values = torch.cat([diag, upper, lower]).to(dtype=dtype)
|
|
107
|
+
|
|
108
|
+
A = torch.sparse_coo_tensor(torch.stack([rows, cols]), values, (n, n)).coalesce()
|
|
109
|
+
if layout == torch.sparse_csr:
|
|
110
|
+
A = A.to_sparse_csr()
|
|
111
|
+
return A, A.to_dense()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _bicgstab_transpose(A, B, **kwargs):
|
|
115
|
+
"""Solve A.T X = B using BiCGSTAB."""
|
|
116
|
+
if A.layout == torch.sparse_csr:
|
|
117
|
+
# A.T currently triggers aten::as_strided for sparse CSR tensors in PyTorch,
|
|
118
|
+
# so use transpose(...).to_sparse_csr() for the CSR test case.
|
|
119
|
+
# A.transpose(0, 1) for csr will return csc, hence the to_sparse_csr() call.
|
|
120
|
+
return bicgstab(A.transpose(0, 1).to_sparse_csr(), B, **kwargs)
|
|
121
|
+
return bicgstab(A.T, B, **kwargs)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _bicgstab_higher_order_kwargs(value_dtype):
|
|
125
|
+
from torchsparsegradutils.utils.bicgstab import BICGSTABSettings
|
|
126
|
+
|
|
127
|
+
if value_dtype == torch.float32:
|
|
128
|
+
return {"settings": BICGSTABSettings(reltol=1e-6, abstol=1e-6, matvec_max=1000)}
|
|
129
|
+
return {"settings": BICGSTABSettings(reltol=1e-12, abstol=1e-12, matvec_max=1000)}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _higher_order_bicgstab_tolerances(value_dtype):
|
|
133
|
+
if value_dtype == torch.float32:
|
|
134
|
+
return {
|
|
135
|
+
"output": (1e-5, 1e-5),
|
|
136
|
+
"grad": (5e-5, 5e-5),
|
|
137
|
+
"hess": (5e-3, 5e-3),
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
"output": (1e-8, 1e-8),
|
|
141
|
+
"grad": (1e-6, 1e-6),
|
|
142
|
+
"hess": (5e-5, 5e-5),
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _settings_for_higher_order_solve(solve, value_dtype):
|
|
147
|
+
if solve is linear_cg:
|
|
148
|
+
from torchsparsegradutils.utils.linear_cg import LinearCGSettings
|
|
149
|
+
|
|
150
|
+
return {"settings": LinearCGSettings(cg_tolerance=1e-5, max_cg_iterations=1000)}
|
|
151
|
+
if solve is minres:
|
|
152
|
+
from torchsparsegradutils.utils.minres import MINRESSettings
|
|
153
|
+
|
|
154
|
+
tolerance = 1e-6 if value_dtype == torch.float32 else 1e-10
|
|
155
|
+
return {"settings": MINRESSettings(minres_tolerance=tolerance, max_cg_iterations=1000)}
|
|
156
|
+
return {}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _higher_order_spd_tolerances(value_dtype):
|
|
160
|
+
if value_dtype == torch.float32:
|
|
161
|
+
return {
|
|
162
|
+
"grad": (1e-3, 1e-3),
|
|
163
|
+
"hess": (5e-2, 5e-2),
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
"grad": (1e-5, 1e-5),
|
|
167
|
+
"hess": (5e-4, 5e-4),
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
45
171
|
# Define Fixtures
|
|
46
172
|
|
|
47
173
|
|
|
@@ -260,3 +386,99 @@ def test_kwargs_with_different_solvers_same_matrix():
|
|
|
260
386
|
# All solutions should be close to each other
|
|
261
387
|
assert torch.allclose(X_cg, X_minres, atol=atol, rtol=rtol)
|
|
262
388
|
assert torch.allclose(X_bicgstab, X_minres, atol=atol, rtol=rtol)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
@pytest.mark.parametrize("base_solve", [linear_cg, minres], ids=[solve_id(linear_cg), solve_id(minres)])
|
|
392
|
+
def test_sparse_generic_solve_higher_order_create_graph_no_out_error(layout, base_solve, device, value_dtype):
|
|
393
|
+
torch.manual_seed(0)
|
|
394
|
+
|
|
395
|
+
theta = torch.randn(8, dtype=value_dtype, device=device, requires_grad=True)
|
|
396
|
+
A, _ = _make_differentiable_tridiag_spd(theta, layout)
|
|
397
|
+
B = torch.randn(8, 2, dtype=value_dtype, device=device)
|
|
398
|
+
|
|
399
|
+
kwargs = _settings_for_higher_order_solve(base_solve, value_dtype)
|
|
400
|
+
loss = sparse_generic_solve(A, B, solve=base_solve, transpose_solve=base_solve, **kwargs).sum()
|
|
401
|
+
|
|
402
|
+
grad_theta = torch.autograd.grad(loss, theta, create_graph=True)[0]
|
|
403
|
+
|
|
404
|
+
assert grad_theta.requires_grad
|
|
405
|
+
assert torch.isfinite(grad_theta).all()
|
|
406
|
+
|
|
407
|
+
second = torch.autograd.grad(grad_theta.sum(), theta)[0]
|
|
408
|
+
assert torch.isfinite(second).all()
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@pytest.mark.parametrize("base_solve", [linear_cg, minres], ids=[solve_id(linear_cg), solve_id(minres)])
|
|
412
|
+
def test_sparse_generic_solve_higher_order_matches_dense_reference(layout, base_solve, device, value_dtype):
|
|
413
|
+
torch.manual_seed(1)
|
|
414
|
+
|
|
415
|
+
theta_sparse = torch.randn(6, dtype=value_dtype, device=device, requires_grad=True)
|
|
416
|
+
theta_dense = theta_sparse.detach().clone().requires_grad_()
|
|
417
|
+
|
|
418
|
+
B = torch.randn(6, 2, dtype=value_dtype, device=device)
|
|
419
|
+
|
|
420
|
+
A_sparse, _ = _make_differentiable_tridiag_spd(theta_sparse, layout)
|
|
421
|
+
_, A_dense = _make_differentiable_tridiag_spd(theta_dense, torch.sparse_coo)
|
|
422
|
+
|
|
423
|
+
kwargs = _settings_for_higher_order_solve(base_solve, value_dtype)
|
|
424
|
+
tolerances = _higher_order_spd_tolerances(value_dtype)
|
|
425
|
+
|
|
426
|
+
out_sparse = sparse_generic_solve(A_sparse, B, solve=base_solve, transpose_solve=base_solve, **kwargs)
|
|
427
|
+
out_dense = torch.linalg.solve(A_dense, B)
|
|
428
|
+
|
|
429
|
+
loss_sparse = out_sparse.square().sum()
|
|
430
|
+
loss_dense = out_dense.square().sum()
|
|
431
|
+
|
|
432
|
+
grad_sparse = torch.autograd.grad(loss_sparse, theta_sparse, create_graph=True)[0]
|
|
433
|
+
grad_dense = torch.autograd.grad(loss_dense, theta_dense, create_graph=True)[0]
|
|
434
|
+
|
|
435
|
+
hess_vec_sparse = torch.autograd.grad(grad_sparse.sum(), theta_sparse)[0]
|
|
436
|
+
hess_vec_dense = torch.autograd.grad(grad_dense.sum(), theta_dense)[0]
|
|
437
|
+
|
|
438
|
+
grad_atol, grad_rtol = tolerances["grad"]
|
|
439
|
+
hess_atol, hess_rtol = tolerances["hess"]
|
|
440
|
+
assert torch.allclose(grad_sparse, grad_dense, atol=grad_atol, rtol=grad_rtol)
|
|
441
|
+
assert torch.allclose(hess_vec_sparse, hess_vec_dense, atol=hess_atol, rtol=hess_rtol)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def test_sparse_generic_solve_higher_order_nonsymmetric_bicgstab_matches_dense_reference(layout, device, value_dtype):
|
|
445
|
+
torch.manual_seed(2)
|
|
446
|
+
|
|
447
|
+
n = 6
|
|
448
|
+
theta_sparse = torch.randn(3 * n - 2, dtype=value_dtype, device=device, requires_grad=True)
|
|
449
|
+
theta_dense = theta_sparse.detach().clone().requires_grad_()
|
|
450
|
+
|
|
451
|
+
B = torch.randn(n, 2, dtype=value_dtype, device=device)
|
|
452
|
+
|
|
453
|
+
A_sparse, _ = _make_differentiable_nonsymmetric_tridiag(theta_sparse, layout)
|
|
454
|
+
_, A_dense = _make_differentiable_nonsymmetric_tridiag(theta_dense, torch.sparse_coo)
|
|
455
|
+
assert not torch.allclose(A_dense, A_dense.T)
|
|
456
|
+
|
|
457
|
+
kwargs = _bicgstab_higher_order_kwargs(value_dtype)
|
|
458
|
+
tolerances = _higher_order_bicgstab_tolerances(value_dtype)
|
|
459
|
+
|
|
460
|
+
out_sparse = sparse_generic_solve(
|
|
461
|
+
A_sparse,
|
|
462
|
+
B,
|
|
463
|
+
solve=bicgstab,
|
|
464
|
+
transpose_solve=_bicgstab_transpose,
|
|
465
|
+
**kwargs,
|
|
466
|
+
)
|
|
467
|
+
out_dense = torch.linalg.solve(A_dense, B)
|
|
468
|
+
output_atol, output_rtol = tolerances["output"]
|
|
469
|
+
assert torch.allclose(A_dense @ out_sparse, B, atol=output_atol, rtol=output_rtol)
|
|
470
|
+
|
|
471
|
+
loss_sparse = out_sparse.square().sum()
|
|
472
|
+
loss_dense = out_dense.square().sum()
|
|
473
|
+
|
|
474
|
+
grad_sparse = torch.autograd.grad(loss_sparse, theta_sparse, create_graph=True)[0]
|
|
475
|
+
grad_dense = torch.autograd.grad(loss_dense, theta_dense, create_graph=True)[0]
|
|
476
|
+
|
|
477
|
+
hess_vec_sparse = torch.autograd.grad(grad_sparse.sum(), theta_sparse)[0]
|
|
478
|
+
hess_vec_dense = torch.autograd.grad(grad_dense.sum(), theta_dense)[0]
|
|
479
|
+
|
|
480
|
+
grad_atol, grad_rtol = tolerances["grad"]
|
|
481
|
+
hess_atol, hess_rtol = tolerances["hess"]
|
|
482
|
+
assert torch.allclose(out_sparse, out_dense, atol=output_atol, rtol=output_rtol)
|
|
483
|
+
assert torch.allclose(grad_sparse, grad_dense, atol=grad_atol, rtol=grad_rtol)
|
|
484
|
+
assert torch.allclose(hess_vec_sparse, hess_vec_dense, atol=hess_atol, rtol=hess_rtol)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/cupy/__init__.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/cupy/cupy_bindings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/encoders/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/indexed_matmul.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/jax/__init__.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/jax/jax_bindings.py
RENAMED
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/sparse_lstsq.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/sparse_matmul.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/__init__.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/conftest.py
RENAMED
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_lsmr.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_minres.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_random.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/tests/test_utils.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/__init__.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/bicgstab.py
RENAMED
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/linear_cg.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/lsmr.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/minres.py
RENAMED
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils/utils/utils.py
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{torchsparsegradutils-0.2.2 → torchsparsegradutils-0.2.3}/torchsparsegradutils.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|