Uploaded using `kernel-builder`.
#1
by phanerozoic - opened
- build/torch213-cxx11-cu130-aarch64-linux/__init__.py +265 -0
- build/torch213-cxx11-cu130-aarch64-linux/_exact_solve_cuda_31a8fa7_dirty.abi3.so +3 -0
- build/torch213-cxx11-cu130-aarch64-linux/_exact_solve_recon.py +45 -0
- build/torch213-cxx11-cu130-aarch64-linux/_ops.py +9 -0
- build/torch213-cxx11-cu130-aarch64-linux/exact_solve/__init__.py +26 -0
- build/torch213-cxx11-cu130-aarch64-linux/metadata.json +39 -0
build/torch213-cxx11-cu130-aarch64-linux/__init__.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""exact-solve: exact rational linear-system solver on INT8 tensor cores.
|
| 2 |
+
|
| 3 |
+
Solves ``A x = b`` exactly over the rationals for integer ``A`` (``[n, n]``) and
|
| 4 |
+
integer ``b`` (``[n, c]``) by high-order Dixon p-adic lifting on the residue
|
| 5 |
+
(CRT) engine, and returns the exact solution as ``fractions.Fraction``.
|
| 6 |
+
|
| 7 |
+
The lift uses a squarefree modulus ``P = prod(q_j)`` over primes ``q_j < 256``:
|
| 8 |
+
each step's ``A^{-1} mod q_j`` matmuls are native INT8 tensor-core GEMMs (one per
|
| 9 |
+
prime), CRT-reconstructed into a wide base-``P`` digit; the single-limb residual
|
| 10 |
+
update is ``(r - A x_i) * P^{-1} mod 2^64`` (``P`` odd), which needs only
|
| 11 |
+
``A x_i mod 2^64``. The batched modular inverse and the lift run on the GPU; the
|
| 12 |
+
final rational reconstruction runs on the CPU (accelerated by ``gmpy2`` and a
|
| 13 |
+
process pool, ``fork`` or ``spawn``, when available).
|
| 14 |
+
|
| 15 |
+
solve(A, b) -> [n][c] list of fractions.Fraction (exact)
|
| 16 |
+
|
| 17 |
+
Reference: Dixon, "Exact solution of linear equations using p-adic expansions"
|
| 18 |
+
(Numerische Mathematik 40, 1982).
|
| 19 |
+
"""
|
| 20 |
+
import math
|
| 21 |
+
import os
|
| 22 |
+
import sys
|
| 23 |
+
from fractions import Fraction
|
| 24 |
+
|
| 25 |
+
import torch
|
| 26 |
+
|
| 27 |
+
from ._ops import ops
|
| 28 |
+
|
| 29 |
+
# odd primes < 256 (descending); 2 is excluded so P is odd and invertible mod 2^64
|
| 30 |
+
_ODD_PRIMES = [251, 241, 239, 233, 229, 227, 223, 211, 199, 197, 193, 191, 181,
|
| 31 |
+
179, 173, 167, 163, 157, 151, 149, 139, 137, 131, 127, 113, 109,
|
| 32 |
+
107, 103, 101, 97, 89, 83, 79, 73, 71, 67, 61, 59, 53, 47, 43, 41,
|
| 33 |
+
37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3]
|
| 34 |
+
_LMAX = 4
|
| 35 |
+
_STRIDE = 2 * _LMAX + 1
|
| 36 |
+
_M64 = (1 << 64) - 1
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
# ---------------------------------------------------------------- tables / ops
|
| 40 |
+
|
| 41 |
+
def _crt_tables(primes, device):
|
| 42 |
+
P = len(primes)
|
| 43 |
+
inv = [0] * (P * P)
|
| 44 |
+
for a in range(P):
|
| 45 |
+
for b in range(a + 1, P):
|
| 46 |
+
inv[a * P + b] = pow(primes[a] % primes[b], -1, primes[b])
|
| 47 |
+
mu = [(1 << 62) // p for p in primes]
|
| 48 |
+
pow32 = [0] * (P * _STRIDE)
|
| 49 |
+
for pi, p in enumerate(primes):
|
| 50 |
+
for k in range(_STRIDE):
|
| 51 |
+
pow32[pi * _STRIDE + k] = pow(2, 32 * k, p)
|
| 52 |
+
return (torch.tensor(primes, dtype=torch.int32, device=device),
|
| 53 |
+
torch.tensor(inv, dtype=torch.int32, device=device),
|
| 54 |
+
torch.tensor(mu, dtype=torch.int64, device=device),
|
| 55 |
+
torch.tensor(pow32, dtype=torch.int32, device=device))
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def _pad8(x):
|
| 59 |
+
return max(24, ((x + 7) // 8) * 8)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def _extract(Xi64, rows_pad, cols_pad, primes, mu, pow32):
|
| 63 |
+
rows, cols = Xi64.shape
|
| 64 |
+
if rows == rows_pad and cols == cols_pad:
|
| 65 |
+
Y = Xi64.contiguous()
|
| 66 |
+
else:
|
| 67 |
+
Y = torch.zeros(rows_pad, cols_pad, dtype=torch.int64, device=Xi64.device)
|
| 68 |
+
Y[:rows, :cols] = Xi64
|
| 69 |
+
planes = torch.empty(primes.numel(), rows_pad, cols_pad, dtype=torch.int8, device=Xi64.device)
|
| 70 |
+
ops.exact_solve_extract(planes, Y.unsqueeze(0).contiguous(), primes, mu, pow32)
|
| 71 |
+
return planes
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def _matmul(A_planes, B_planes, Lc, primes, inv, mu):
|
| 75 |
+
C = torch.empty(Lc, A_planes.size(1), B_planes.size(1), dtype=torch.int64, device=A_planes.device)
|
| 76 |
+
ops.exact_solve_matmul(C, A_planes, B_planes, primes, inv, mu)
|
| 77 |
+
return C
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def _batched_modinv(A, primes):
|
| 81 |
+
n = A.size(0)
|
| 82 |
+
E = primes.numel()
|
| 83 |
+
Bout = torch.empty(E, n, n, dtype=torch.int8, device=A.device)
|
| 84 |
+
work = torch.empty((int)(E) * n * 2 * n, dtype=torch.int32, device=A.device)
|
| 85 |
+
singular = torch.zeros(E, dtype=torch.int32, device=A.device)
|
| 86 |
+
ops.exact_solve_batched_modinv(Bout, A, primes, work, singular)
|
| 87 |
+
return Bout, singular
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def _i64_matmul(A, X):
|
| 91 |
+
out = torch.empty(A.size(0), X.size(1), dtype=torch.int64, device=A.device)
|
| 92 |
+
ops.exact_solve_i64_matmul(out, A, X)
|
| 93 |
+
return out
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def _padic(r, axlow, Pinv64):
|
| 97 |
+
out = torch.empty_like(r)
|
| 98 |
+
ops.exact_solve_padic_residual(out, r, axlow, Pinv64)
|
| 99 |
+
return out
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def _gpu_recon(digits, Pl, Pm, Rr, Pmhalf, dl, LO):
|
| 103 |
+
out = torch.empty(LO, digits.size(2), dtype=torch.int64, device=digits.device)
|
| 104 |
+
ops.exact_solve_gpu_recon(out, digits, Pl, Pm, Rr, Pmhalf, dl)
|
| 105 |
+
return out
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def _s64(u):
|
| 109 |
+
return u - (1 << 64) if u >> 63 else u
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def _to_limbs(x, L):
|
| 113 |
+
return torch.tensor([_s64((x >> (64 * i)) & _M64) for i in range(L)], dtype=torch.int64)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def _from_limbs(col, LO):
|
| 117 |
+
u = 0
|
| 118 |
+
for i in range(LO):
|
| 119 |
+
u |= (int(col[i]) & _M64) << (64 * i)
|
| 120 |
+
return u - (1 << (64 * LO)) if u >> (64 * LO - 1) else u
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
# ---------------------------------------------------------------- reconstruction
|
| 124 |
+
# Reconstruction lives in the torch-free _exact_solve_recon module (imported
|
| 125 |
+
# top-level, its dir on sys.path) so spawn-pool workers load it without torch.
|
| 126 |
+
|
| 127 |
+
_RECON = None
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def _recon():
|
| 131 |
+
global _RECON
|
| 132 |
+
if _RECON is None:
|
| 133 |
+
import importlib
|
| 134 |
+
d = os.path.dirname(os.path.abspath(__file__))
|
| 135 |
+
if d not in sys.path:
|
| 136 |
+
sys.path.append(d)
|
| 137 |
+
_RECON = importlib.import_module("_exact_solve_recon")
|
| 138 |
+
return _RECON
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
_POOL = None
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def _pool():
|
| 145 |
+
global _POOL
|
| 146 |
+
if _POOL is None:
|
| 147 |
+
import multiprocessing as mp
|
| 148 |
+
from concurrent.futures import ProcessPoolExecutor
|
| 149 |
+
_recon() # place the backend dir on sys.path before any worker spawns
|
| 150 |
+
ctx = mp.get_context("fork" if hasattr(os, "fork") else "spawn")
|
| 151 |
+
_POOL = ProcessPoolExecutor(max_workers=min(int(os.cpu_count() or 8), 32), mp_context=ctx)
|
| 152 |
+
return _POOL
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def _hadamard_bits(A, B):
|
| 156 |
+
n = len(A)
|
| 157 |
+
col_sq = [sum(int(A[i][j]) ** 2 for i in range(n)) for j in range(n)]
|
| 158 |
+
logcol = [0.5 * math.log2(max(s, 1)) for s in col_sq]
|
| 159 |
+
logden = sum(logcol)
|
| 160 |
+
b_sq_max = max(sum(int(B[i][k]) ** 2 for i in range(n)) for k in range(len(B[0])))
|
| 161 |
+
lognum = sum(logcol) - min(logcol) + 0.5 * math.log2(max(b_sq_max, 1))
|
| 162 |
+
return lognum, logden
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
def _to_int_lists(T, rows, cols):
|
| 166 |
+
if isinstance(T, torch.Tensor):
|
| 167 |
+
t = T.detach().cpu().tolist()
|
| 168 |
+
else:
|
| 169 |
+
t = [list(r) for r in T]
|
| 170 |
+
return [[int(t[i][j]) for j in range(cols)] for i in range(rows)]
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
# ---------------------------------------------------------------- public solve
|
| 174 |
+
|
| 175 |
+
def solve(A, b, parallel=True):
|
| 176 |
+
"""Exact rational solution of ``A x = b``.
|
| 177 |
+
|
| 178 |
+
Args:
|
| 179 |
+
A: ``[n, n]`` integer matrix (torch int tensor, list, or numpy array).
|
| 180 |
+
b: ``[n, c]`` integer right-hand side(s). A 1-D ``[n]`` vector is
|
| 181 |
+
treated as a single column.
|
| 182 |
+
parallel: use a process pool (fork or spawn) for reconstruction when
|
| 183 |
+
available.
|
| 184 |
+
|
| 185 |
+
Returns:
|
| 186 |
+
``[n][c]`` list of ``fractions.Fraction`` (the exact solution), or
|
| 187 |
+
``None`` if ``A`` is singular over the rationals.
|
| 188 |
+
|
| 189 |
+
Requires a CUDA device; entries with ``n * max|A_ij| < 2^63``.
|
| 190 |
+
"""
|
| 191 |
+
import numpy as np
|
| 192 |
+
dev = A.device if isinstance(A, torch.Tensor) else torch.device("cuda")
|
| 193 |
+
if isinstance(b, torch.Tensor) and b.dim() == 1:
|
| 194 |
+
b = b.unsqueeze(1)
|
| 195 |
+
n = A.shape[0] if isinstance(A, torch.Tensor) else len(A)
|
| 196 |
+
c = (b.shape[1] if isinstance(b, torch.Tensor) else len(b[0]))
|
| 197 |
+
A_list = _to_int_lists(A, n, n)
|
| 198 |
+
b_list = _to_int_lists(b, n, c)
|
| 199 |
+
lognum, logden = _hadamard_bits(A_list, b_list)
|
| 200 |
+
margin = 48
|
| 201 |
+
|
| 202 |
+
A_t = torch.tensor(A_list, dtype=torch.int64, device=dev)
|
| 203 |
+
primes_all = torch.tensor(_ODD_PRIMES, dtype=torch.int32, device=dev)
|
| 204 |
+
Bout_all, singular = _batched_modinv(A_t, primes_all)
|
| 205 |
+
good = [i for i in range(len(_ODD_PRIMES)) if int(singular[i]) == 0]
|
| 206 |
+
if not good:
|
| 207 |
+
return None
|
| 208 |
+
Q = [_ODD_PRIMES[i] for i in good]
|
| 209 |
+
P = 1
|
| 210 |
+
for q in Q:
|
| 211 |
+
P *= q
|
| 212 |
+
Pinv = pow(P, -1, 1 << 64)
|
| 213 |
+
Pinv_s = Pinv - (1 << 64) if Pinv >> 63 else Pinv
|
| 214 |
+
Lx = 1
|
| 215 |
+
while (1 << (64 * Lx - 1)) <= P:
|
| 216 |
+
Lx += 1
|
| 217 |
+
m = int(math.ceil((1.0 + lognum + logden + margin) / math.log2(P)))
|
| 218 |
+
Mmod = P ** m
|
| 219 |
+
Nb = 1 << int(math.ceil(lognum + margin / 2))
|
| 220 |
+
Db = 1 << int(math.ceil(logden + margin / 2))
|
| 221 |
+
primes, inv, mu, pow32 = _crt_tables(Q, dev)
|
| 222 |
+
Ecnt = len(Q)
|
| 223 |
+
Mp, Kp, Cp = max(n, 17), _pad8(n), max(8, ((c + 7) // 8) * 8) # narrow RHS pad for small c
|
| 224 |
+
Blift = Bout_all[torch.tensor(good, device=dev)].contiguous()
|
| 225 |
+
Blift_p = torch.zeros(Ecnt, Mp, Kp, dtype=torch.int8, device=dev)
|
| 226 |
+
Blift_p[:, :n, :n] = Blift
|
| 227 |
+
|
| 228 |
+
r = torch.tensor(b_list, dtype=torch.int64, device=dev)
|
| 229 |
+
digits = torch.empty(m, Lx, n, c, dtype=torch.int64, device=dev)
|
| 230 |
+
for it in range(m):
|
| 231 |
+
rT = r.t().contiguous()
|
| 232 |
+
rT_planes = _extract(rT, Cp, Kp, primes, mu, pow32)
|
| 233 |
+
xi = _matmul(Blift_p, rT_planes, Lx, primes, inv, mu)[:, :n, :c].contiguous()
|
| 234 |
+
digits[it] = xi
|
| 235 |
+
r = _padic(r, _i64_matmul(A_t, xi[0].contiguous()), Pinv_s)
|
| 236 |
+
|
| 237 |
+
NC = n * c
|
| 238 |
+
D3 = np.ascontiguousarray(digits.permute(0, 2, 3, 1).reshape(m, NC, Lx).cpu().numpy())
|
| 239 |
+
|
| 240 |
+
# Reconstruct every entry independently to its exact (num, den). The bounds
|
| 241 |
+
# give Nb*Db <= Mmod/2, so rational reconstruction is unique and correct per
|
| 242 |
+
# entry; no shared common-denominator estimate is involved. Parallelize the
|
| 243 |
+
# per-entry Euclid across cores for large grids (fork or spawn pool).
|
| 244 |
+
rb = _recon()
|
| 245 |
+
use_pool = parallel and NC >= 256
|
| 246 |
+
pairs = None
|
| 247 |
+
if use_pool:
|
| 248 |
+
try:
|
| 249 |
+
nch = min(NC, min(int(os.cpu_count() or 8), 32) * 3)
|
| 250 |
+
bnd = [round(x * NC / nch) for x in range(nch + 1)]
|
| 251 |
+
tasks = [(D3[:, bnd[i]:bnd[i + 1], :].copy(), m, P, Mmod, Nb, Db)
|
| 252 |
+
for i in range(nch) if bnd[i + 1] > bnd[i]]
|
| 253 |
+
pairs = []
|
| 254 |
+
for res in _pool().map(rb._recon_chunk, tasks):
|
| 255 |
+
pairs.extend(res)
|
| 256 |
+
except Exception:
|
| 257 |
+
pairs = None
|
| 258 |
+
if pairs is None:
|
| 259 |
+
pairs = rb._recon_chunk((D3, m, P, Mmod, Nb, Db))
|
| 260 |
+
if any(p is None for p in pairs):
|
| 261 |
+
return None
|
| 262 |
+
return [[Fraction(pairs[i * c + j][0], pairs[i * c + j][1]) for j in range(c)] for i in range(n)]
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
__all__ = ["solve"]
|
build/torch213-cxx11-cu130-aarch64-linux/_exact_solve_cuda_31a8fa7_dirty.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ab909fca772b391348b267060579307c2f63977d5cf3d1c8c2e1542d25dcf740
|
| 3 |
+
size 1496576
|
build/torch213-cxx11-cu130-aarch64-linux/_exact_solve_recon.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Torch-free rational reconstruction (Horner + extended-Euclid) for exact-solve;
|
| 2 |
+
imported by the reconstruction process-pool workers (gmpy2/numpy only, no torch)."""
|
| 3 |
+
import math
|
| 4 |
+
|
| 5 |
+
try:
|
| 6 |
+
import gmpy2
|
| 7 |
+
from gmpy2 import mpz
|
| 8 |
+
_HAVE_GMP = True
|
| 9 |
+
except Exception: # pragma: no cover - optional acceleration
|
| 10 |
+
_HAVE_GMP = False
|
| 11 |
+
|
| 12 |
+
def mpz(x):
|
| 13 |
+
return int(x)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def _rat_recon(X, M, N, D):
|
| 17 |
+
"""Rational reconstruction: a/b with a == b X (mod M), |a|<=N, 0<b<=D."""
|
| 18 |
+
r0, r1 = mpz(M), mpz(X) % mpz(M)
|
| 19 |
+
t0, t1 = mpz(0), mpz(1)
|
| 20 |
+
while r1 > N:
|
| 21 |
+
q = r0 // r1
|
| 22 |
+
r0, r1 = r1, r0 - q * r1
|
| 23 |
+
t0, t1 = t1, t0 - q * t1
|
| 24 |
+
a, b = r1, t1
|
| 25 |
+
if b < 0:
|
| 26 |
+
a, b = -a, -b
|
| 27 |
+
if b == 0 or b > D:
|
| 28 |
+
return None
|
| 29 |
+
g = math.gcd(int(abs(a)), int(b)) if not _HAVE_GMP else gmpy2.gcd(abs(a), b)
|
| 30 |
+
a, b = a // g, b // g
|
| 31 |
+
return (int(a), int(b)) if b <= D else None
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _recon_chunk(args):
|
| 35 |
+
"""Reconstruct every entry in the chunk: Horner the p-adic digits into X, then
|
| 36 |
+
extended-Euclid X (mod M) into an exact (num, den) pair, each independently."""
|
| 37 |
+
D3chunk, m, P, Mmod, Nb, Db = args
|
| 38 |
+
Pm = mpz(P); Mmz = mpz(Mmod)
|
| 39 |
+
out = []
|
| 40 |
+
for k in range(D3chunk.shape[1]):
|
| 41 |
+
X = mpz(0)
|
| 42 |
+
for it in range(m - 1, -1, -1):
|
| 43 |
+
X = X * Pm + int.from_bytes(D3chunk[it, k].tobytes(), "little", signed=True)
|
| 44 |
+
out.append(_rat_recon(X % Mmz, Mmz, Nb, Db))
|
| 45 |
+
return out
|
build/torch213-cxx11-cu130-aarch64-linux/_ops.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from . import _exact_solve_cuda_31a8fa7_dirty
|
| 3 |
+
ops = torch.ops._exact_solve_cuda_31a8fa7_dirty
|
| 4 |
+
|
| 5 |
+
def add_op_namespace_prefix(op_name: str):
|
| 6 |
+
"""
|
| 7 |
+
Prefix op by namespace.
|
| 8 |
+
"""
|
| 9 |
+
return f"_exact_solve_cuda_31a8fa7_dirty::{op_name}"
|
build/torch213-cxx11-cu130-aarch64-linux/exact_solve/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ctypes
|
| 2 |
+
import importlib.util
|
| 3 |
+
import sys
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from types import ModuleType
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def _import_from_path(file_path: Path) -> ModuleType:
|
| 9 |
+
# We cannot use the module name as-is, after adding it to `sys.modules`,
|
| 10 |
+
# it would also be used for other imports. So, we make a module name that
|
| 11 |
+
# depends on the path for it to be unique using the hex-encoded hash of
|
| 12 |
+
# the path.
|
| 13 |
+
path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
|
| 14 |
+
module_name = path_hash
|
| 15 |
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
| 16 |
+
if spec is None:
|
| 17 |
+
raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
|
| 18 |
+
module = importlib.util.module_from_spec(spec)
|
| 19 |
+
if module is None:
|
| 20 |
+
raise ImportError(f"Cannot load module {module_name} from spec")
|
| 21 |
+
sys.modules[module_name] = module
|
| 22 |
+
spec.loader.exec_module(module) # type: ignore
|
| 23 |
+
return module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
|
build/torch213-cxx11-cu130-aarch64-linux/metadata.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "exact-solve",
|
| 3 |
+
"id": "_exact_solve_cuda_31a8fa7_dirty",
|
| 4 |
+
"version": 1,
|
| 5 |
+
"license": "Apache-2.0",
|
| 6 |
+
"python-depends": [],
|
| 7 |
+
"backend": {
|
| 8 |
+
"type": "cuda",
|
| 9 |
+
"archs": [
|
| 10 |
+
"10.0",
|
| 11 |
+
"12.0",
|
| 12 |
+
"8.0",
|
| 13 |
+
"8.6",
|
| 14 |
+
"8.9",
|
| 15 |
+
"9.0"
|
| 16 |
+
]
|
| 17 |
+
},
|
| 18 |
+
"digest": {
|
| 19 |
+
"algorithm": "sha256",
|
| 20 |
+
"files": {
|
| 21 |
+
"__init__.py": "ZG5Z4fcpkB0UCWfChZwPg4dTmNtHpTxDCEvKPLJc9PI=",
|
| 22 |
+
"_exact_solve_cuda_31a8fa7_dirty.abi3.so": "q5CfyncrORNIsmcGBXkwfC9jl31c89HIwuFULSXc90A=",
|
| 23 |
+
"_exact_solve_recon.py": "gU5Ywz+UPfUeXS2dyzJ8NOOxgj7pgUcbFV9uAOAVIzU=",
|
| 24 |
+
"_ops.py": "1ujza9fF0nYcw94Evi6lqaZ8wNTrVB+GsP8zCO4FVj8=",
|
| 25 |
+
"exact_solve/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY="
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"provenance": {
|
| 29 |
+
"kernel-builder": {
|
| 30 |
+
"version": "0.17.0-dev0",
|
| 31 |
+
"sha": "19aaa6421e674e9fecc352bbae6eab81d19a6bf4",
|
| 32 |
+
"dirty": false
|
| 33 |
+
},
|
| 34 |
+
"kernel": {
|
| 35 |
+
"sha": "31a8fa724c4e4c412e04efba7ee534c01afb61cd",
|
| 36 |
+
"dirty": true
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
}
|