Source code for atlas_q.linalg_robust
"""
Robust Linear Algebra Operations with Fallback Cascade
Provides GPU-first SVD with automatic fallback to CPU and jitter-based
recovery for numerically unstable matrices.
Author: ATLAS-Q Contributors
Date: October 2025
License: MIT
"""
from typing import Tuple
import torch
[docs]
def robust_svd(X: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, str]:
"""
Robust SVD with fallback cascade: CUDA → jitter → CPU
Args:
X: Input tensor to decompose
Returns:
U, S, Vh, driver_used
Strategy:
1. Try torch.linalg.svd on GPU (cuSOLVER backend)
2. If fails, add small jitter and retry on GPU
3. If still fails, fall back to CPU SVD
4. Return which driver succeeded for diagnostics
"""
device = X.device
# Try 1: Direct CUDA SVD
try:
U, S, Vh = torch.linalg.svd(X, full_matrices=False)
return U, S, Vh, "torch_cuda"
except Exception:
pass
# Try 2: Add jitter for numerical stability
try:
Xj = X + (1e-12 * torch.randn_like(X))
U, S, Vh = torch.linalg.svd(Xj, full_matrices=False)
return U, S, Vh, "torch_cuda_jitter"
except Exception:
pass
# Try 3: CPU fallback (always works, slower)
U, S, Vh = torch.linalg.svd(X.cpu(), full_matrices=False)
return U.to(device), S.to(device), Vh.to(device), "torch_cpu"
[docs]
def robust_qr(X: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, str]:
"""
Robust QR decomposition with fallback
Args:
X: Input tensor to decompose
Returns:
Q, R, driver_used
"""
device = X.device
# Try 1: Direct CUDA QR
try:
Q, R = torch.linalg.qr(X)
return Q, R, "torch_cuda"
except Exception:
pass
# Try 2: CPU fallback
Q, R = torch.linalg.qr(X.cpu())
return Q.to(device), R.to(device), "torch_cpu"
[docs]
def condition_number(S: torch.Tensor) -> float:
"""
Compute condition number from singular values
Args:
S: Singular values (sorted descending)
Returns:
Condition number (σ_max / σ_min)
"""
if len(S) == 0 or S[-1] == 0:
return float("inf")
return float((S[0] / S[-1]).item())