Source code for torch_numopt.utils.stability

""" """

import logging
import torch
import torch.linalg

logger = logging.getLogger(__name__)


[docs] def fix_stability(mat: torch.Tensor): """ Procedure to adjust a matrix by adding a very small value to the diagonal to avoid numerical instability problems. Parameters ---------- mat: torch.Tensor Ill conditioned matrix. Returns ------- fixed_mat: torch.Tensor (Hopefully) Well conditioned matrix. """ eps = torch.finfo(mat.dtype).eps return mat + torch.eye(mat.shape[0], device=mat.device) * eps
[docs] def fix_cond(mat): """Check condition number and apply `fix_stability` if ill-conditioned.""" cond_number = torch.linalg.cond(mat) if cond_number > 1e8: mat = fix_stability(mat) if logger.isEnabledFor(logging.DEBUG): new_cond_number = torch.linalg.cond(mat) logger.debug("Numerical instability found, condition number was %g, new condition number is %g", cond_number, new_cond_number) return mat
[docs] def pinv_svd_trunc(mat: torch.Tensor, thresh: float = 1e-4): """ Procedure to calculate the pseudoinverse of a matrix by using truncated SVD in order to maintain numerical stability. Parameters ---------- mat: torch.Tensor Problematic matrix that we want to invert. thresh: float Threshold applied to the S matrix in the SVD procedure. Returns ------- inverted_mat: torch.Tensor Pseudoinverse of the input matrix. """ U, S, Vt = torch.linalg.svd(mat) S_tresh = S < thresh S_inv_trunc = 1.0 / S S_inv_trunc[S_tresh] = 0 return Vt.T @ torch.diag(S_inv_trunc) @ U.T