Skip to content

Fix log determinants with constant Kronecker diagonal noise - #162

Open
DiadkoShmek wants to merge 1 commit into
cornellius-gp:mainfrom
DiadkoShmek:lezo50-kron-constant-logdet-20261105
Open

DiadkoShmek wants to merge 1 commit into
cornellius-gp:mainfrom
DiadkoShmek:lezo50-kron-constant-logdet-20261105

Conversation

@DiadkoShmek

Copy link
Copy Markdown

logdet() can raise AttributeError: 'Tensor' object has no attribute 'linear_ops' when an added diagonal is a Kronecker product of constant-diagonal factors and the matrix reaches the existing fast-path threshold. A 1024-dimensional covariance triggers this with default settings, also blocking Gaussian log-probability evaluation.

Recognize this constant diagonal locally in _logdet and reuse the existing spectral shift, logdet(K + dI) = sum(log(eigenvalues(K) + d)). This removes the broken factor reconstruction and its incorrect scaling, while preserving the existing small-matrix fallback and solve/root routes.

import torch
from linear_operator.operators import (
    ConstantDiagLinearOperator,
    DiagLinearOperator,
    KroneckerProductAddedDiagLinearOperator,
    KroneckerProductDiagLinearOperator,
    KroneckerProductLinearOperator,
)

a = torch.linspace(1, 2, 32, dtype=torch.double)
b = torch.linspace(3, 5, 32, dtype=torch.double)
k = KroneckerProductLinearOperator(DiagLinearOperator(a), DiagLinearOperator(b))
d = KroneckerProductDiagLinearOperator(
    ConstantDiagLinearOperator(torch.tensor([2.0], dtype=torch.double), diag_shape=32),
    ConstantDiagLinearOperator(torch.tensor([3.0], dtype=torch.double), diag_shape=32),
)
matrix = KroneckerProductAddedDiagLinearOperator(k, d)
result = matrix.logdet()  # Default settings, 1024 x 1024 matrix.
torch.testing.assert_close(result, torch.log(torch.kron(a, b) + 6).sum())
print(result)

BASE raises at matrix.logdet(); the change returns approximately 2536.626652357273, matching the diagonal reference without overriding any settings.

CPU validation:

  • The complete affected native module passes 247 tests. The new regression raises in six BASE subtests and passes on the change, covering float32/float64, positive/zero/two-negative constant factors, and selected noise gradients/Hessians.
  • A separate NumPy/analytic/finite-difference reference passes 29 cases/165 checks; independent review passes 53 scenarios/240 checks. These include batch metadata, different diagonal factorizations, nonconstant-diagonal controls and the default-size Gaussian value/first-gradient path.
  • Exact workflow Flake8/pre-commit, all-files hooks, and wheel/sdist builds pass. Both HTML documentation builds succeed with zero Sphinx logger warnings, while retaining the same 25 existing Python RuntimeWarnings from the unchanged type formatter in docs/source/conf.py. No warning suppression or warning-free claim.

This is a constant-noise log-determinant repair, not a general Kronecker higher-derivative, solve/root, GPU or performance claim.

I directed this work and take responsibility for the contribution and its follow-up. AI assistance was used in producing the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant