torch_pfaffian package¶
Subpackages¶
- torch_pfaffian.kernels package
- torch_pfaffian.low_rank package
- Submodules
- torch_pfaffian.low_rank.low_rank_pfaffian module
LowRankPfaffianLowRankPfaffian.add_product()LowRankPfaffian.as_index()LowRankPfaffian.project()LowRankPfaffian.ratio()LowRankPfaffian.ratio_and_inverse()LowRankPfaffian.ratio_and_r_inverse()LowRankPfaffian.ratio_extend()LowRankPfaffian.ratio_extend_and_inverse()LowRankPfaffian.ratio_replace()LowRankPfaffian.ratio_replace_and_inverse()LowRankPfaffian.skew_identity()LowRankPfaffian.skew_identity_pfaffian()
- torch_pfaffian.low_rank.pfaffian_chain module
- torch_pfaffian.low_rank.pfaffian_updater module
PfaffianUpdaterPfaffianUpdater.__init__()PfaffianUpdater.accept()PfaffianUpdater.accept_replace()PfaffianUpdater.delayPfaffianUpdater.from_inverse()PfaffianUpdater.inversePfaffianUpdater.max_delayPfaffianUpdater.merge()PfaffianUpdater.pfaffianPfaffianUpdater.ratio()PfaffianUpdater.ratio_replace()PfaffianUpdater.reset()
- torch_pfaffian.low_rank.skew_gradient module
- Module contents
- torch_pfaffian.strategies package
- Submodules
- torch_pfaffian.strategies.pfaffian_block_det module
- torch_pfaffian.strategies.pfaffian_det module
- torch_pfaffian.strategies.pfaffian_fdbpf module
- torch_pfaffian.strategies.pfaffian_masked_magnitude module
- torch_pfaffian.strategies.pfaffian_parlett_reid module
- torch_pfaffian.strategies.pfaffian_rust_parlett_reid module
- torch_pfaffian.strategies.pfaffian_slog module
- torch_pfaffian.strategies.pfaffian_small module
- torch_pfaffian.strategies.strategy module
PfaffianStrategyPfaffianStrategy.EPSILONPfaffianStrategy.EXACT_SINGULAR_GRADPfaffianStrategy.INVERSE_RESIDUAL_RTOL_EXPONENTPfaffianStrategy.MINOR_CHUNK_ELEMENTSPfaffianStrategy.NAMEPfaffianStrategy.NULL_SPACE_SEPARATION_EXPONENTPfaffianStrategy.SINGULARITY_RTOL_EXPONENTPfaffianStrategy.backward()PfaffianStrategy.forward()PfaffianStrategy.pfaffian_grad_matrix()PfaffianStrategy.setup_context()
- Module contents
Submodules¶
torch_pfaffian.utils module¶
- torch_pfaffian.utils.get_all_subclasses(cls)¶
Module contents¶
TorchPfaffian computes batched, differentiable Pfaffians of skew-symmetric matrices in PyTorch, on CPU and GPU.
- torch_pfaffian.get_pfaffian_function(name: str = 'PfaffianFDBPf') Callable[[Tensor], Tensor]¶
- torch_pfaffian.pfaffian(matrix: Tensor, *, sign: bool = True, check_input: bool = False, check_finite: bool = True, epsilon: float | None = None, mask_roundoff_gradient: bool = False) Tensor¶
Compute the Pfaffian of a skew-symmetric matrix, choosing the strategy from the input.
The matrix has shape
(..., 2n, 2n)and the result has shape(...,), sharing the backend, dtype, and device ofmatrix.Strategy selection:
Condition
Strategy
Reason
mask_roundoff_gradient=TruePfaffianMaskedMagnitudezero gradient at round-off zeros
m <= AUTO_SMALL_MAXPfaffianSmallexact unrolled kernel (all dtypes)
block form, large input (see below)
PfaffianBlockDetone
n x ndeterminantsign=True, Rust built, CPU inputRustPfaffianParlettReidfastest signed path (native Rust)
sign=True, otherwisePfaffianParlettReidGPU-native and pure-Python fallback
sign=False,epsilongivenmagnitude_pfaffianlog-domain magnitude with floor
sign=False, grad neededPfaffianFDBPfmagnitude only; robust backward
sign=False, no gradPfaffianDetcheapest:
sqrt(|det|)onlyMatrices with last dimension
m <= AUTO_SMALL_MAXtake the exact unrolledPfaffianSmallpath first, regardless ofsignand device (|Pf|forsign=False); it is exact for every dtype and differentiable end-to-end. For larger matrices the Rust kernel runs on CPU (in real and complex precisions), so a non-CPU (e.g. CUDA) input is routed toPfaffianParlettReid, which runs natively on the input device and avoids a host round-trip. All signed strategies compute the correct complex signed Pfaffian without discarding the imaginary part and are differentiable end-to-end for real and complex inputs (the complex backward follows PyTorch’s Wirtinger convention).Inputs with
m > AUTO_SMALL_MAXand at leastAUTO_BLOCK_DET_MIN_NUMELentries in total are tested for the block form[[0, B], [-B^T, 0]](both diagonal blocks exactly zero for every batch element). When it holds,PfaffianBlockDetcomputespf = (-1)^{n(n-1)/2} det(B)from then x nblock, forsign=Trueand forsign=Falsewithoutepsilon(where the magnitude is floored atsqrt(PfaffianStrategy.EPSILON)like the determinant paths). The test rejects a general input after reading one entry per matrix, and the gradient matches the general strategies.The supported dtypes are float16, bfloat16, float32, float64, complex32, complex64 and complex128. PyTorch has no LU factorization in
float16,bfloat16andcomplex32, so these inputs are computed infloat32(complex64forcomplex32), with aUserWarning, and the result is cast back: at every size forcomplex32, and forfloat16andbfloat16whenm > AUTO_SMALL_MAX, withmask_roundoff_gradient=True, or when the unrolled kernel’s result is not finite. The gradient flows back through the cast. A result that is finite after the upcast but exceeds the range of the input dtype becomesinf, with aRuntimeWarningwhencheck_finite=True. The round-off criterion ofmask_roundoff_gradientthen uses the precision of the upcast dtype, so a Pfaffian that is zero only up to the round-off of an earlier half-precision computation is not masked.The Pfaffian is only defined for skew-symmetric matrices; the strategies assume this and do not check it. Pass
check_input=Trueto validate the assumption. The chosen strategy is the fastest correct one for the input, so callingpfaffianis all most callers need. For inputs with a wide dynamic range the fast linear-domain path can overflow toinfeven when the true Pfaffian is finite; withcheck_finite=True(default) such results are transparently recomputed in the log domain and recovered, so the caller gets the correct value without reaching forslog_pfaffian(). Only a magnitude that genuinely exceeds the input dtype’s floating range remains non-finite, and only then is aRuntimeWarningemitted. One extreme case is not auto-recovered: form > AUTO_SMALL_MAXthe linear signed path declares a pivot magnitude belowPfaffianStrategy.EPSILON(1e-30) an exact zero, so a matrix whose Pfaffian hinges on such a sub-1e-30pivot is reported as0.slog_pfaffian(), which uses an exact-zero pivot test, computes these extreme inputs correctly (as does the unrolledm <= AUTO_SMALL_MAXpath, which has no pivot floor).- Parameters:
matrix – Skew-symmetric matrix of shape
(..., 2n, 2n).sign – When
True(default) return the signed Pfaffian, otherwise its magnitude.check_input – When
True, validate thatmatrixis square in its last two dimensions and skew-symmetric (A == -A^T) before computing, raisingValueErrorotherwise. Off by default (False) so trusted inputs pay nothing; the check is an O(n^2) comparison, cheap relative to the O(n^3) Pfaffian.check_finite – When
True(default), verify the result is finite; if the fast path overflowed, recompute in the log domain and recover the value, warning only if it still exceeds the dtype’s range. This costs one device-to-host synchronization; passFalseto skip both the check and the recovery in hot loops (the raw fast-path result, possiblyinf, is returned).epsilon – Only affects the magnitude path (
sign=False). When a float is given, the magnitude is computed in the log domain and floored atsqrt(epsilon); elements below the floor get a zero gradient. WhenNone(default), the routing is unchanged and the magnitude is computed viaPfaffianFDBPf/PfaffianDet(orPfaffianBlockDetfor large block-form inputs) and floored atsqrt(PfaffianStrategy.EPSILON). Withmask_roundoff_gradient=Trueit is the per-call floor of|det(A)|(NonemeansPfaffianStrategy.EPSILON).mask_roundoff_gradient – Only valid with
sign=False. WhenTrue, every input size is computed byPfaffianMaskedMagnitude: the forward issqrt(max(|det(A)|, epsilon))and the backward gives a zero gradient to elements whose Pfaffian vanishes up to round-off (or that were clamped to the floor), instead of theO(1)gradient the unmasked backward derives from round-off. No numerical test separates such a structural zero from a genuine value at round-off level, so this is off by default (False); turn it on when exact zeros are expected, for example the parity-forbidden outcomes of a basis state. The backward costs one inverse, two 1-norms and one set of singular values per element. Elements whose determinant overflows are recovered in the log domain with the unmasked gradient; seePfaffianMaskedMagnitudefor the limits of the round-off criterion.
- Raises:
ValueError – If
mask_roundoff_gradient=Truewithsign=True, or ifcheck_input=Trueandmatrixis not square and skew-symmetric.TypeError – If
matrixhas an unsupported dtype (an integer, boolean or float8 dtype).
- Returns:
The Pfaffian of the input, of shape
(...,).- Return type:
torch.Tensor
- torch_pfaffian.slog_pfaffian(matrix: Tensor) tuple[torch.Tensor, torch.Tensor]¶
Log-domain signed Pfaffian of a batch of skew-symmetric matrices as
(phase, log|Pf|).Thin wrapper over
SlogPfaffianStrategy. The reconstruction isPf = phase * exp(log_abs). The log domain neither overflows for large matrices nor underflows for tiny Pfaffians, and the kernel never synchronizes with the host.log_absis differentiable whereverPf != 0;phaseis non-differentiable (usepfaffian()withsign=Truefor the full derivative).float16andbfloat16inputs are computed infloat32, andcomplex32inputs incomplex64, with aUserWarning; the result is cast back, since PyTorch has no LU factorization in those dtypes.- Parameters:
matrix – Skew-symmetric matrix of shape
(..., 2n, 2n).- Returns:
A pair
(phase, log_abs), each of shape(...,).phaseshares the input dtype (0whenPf = 0);log_absis in the matching real dtype (-infwhenPf = 0).- Return type:
tuple[torch.Tensor, torch.Tensor]
- Raises:
TypeError – If
matrixhas an unsupported dtype (an integer, boolean or float8 dtype).