Source code for linear_operator_learning.kernel.linalg

"""Linear algebra utilities for the `kernel` algorithms."""

from warnings import warn

import numpy as np
from numpy import ndarray

from linear_operator_learning.kernel.utils import topk


[docs] def add_diagonal_(M: ndarray, alpha: float): """Add alpha to the diagonal of M inplace. Args: M (ndarray): The matrix to modify inplace. alpha (float): The value to add to the diagonal of M. """ np.fill_diagonal(M, M.diagonal() + alpha)
[docs] def stable_topk( vec: ndarray, k_max: int, rcond: float | None = None, ignore_warnings: bool = True, ): """Takes up to k_max indices of the top k_max values of vec. If the values are below rcond, they are discarded. Args: vec (ndarray): Vector to extract the top k indices from. k_max (int): Number of indices to extract. rcond (float, optional): Value below which the values are discarded. Defaults to None, in which case it is set according to the machine precision of vec's dtype. ignore_warnings (bool): If False, raise a warning when some elements are discarted for being below the requested numerical precision. """ if rcond is None: rcond = 10.0 * vec.shape[0] * np.finfo(vec.dtype).eps top_vec, top_idxs = topk(vec, k_max) if all(top_vec > rcond): return top_vec, top_idxs else: valid = top_vec > rcond # In the case of multiple occurrences of the maximum vec, the indices corresponding to the first occurrence are returned. first_invalid = np.argmax(np.logical_not(valid)) _first_discarded_val = np.max(np.abs(vec[first_invalid:])) if not ignore_warnings: warn( f"Warning: Discarted {k_max - vec.shape[0]} dimensions of the {k_max} requested due to numerical instability. Consider decreasing the k. The largest discarded value is: {_first_discarded_val:.3e}." ) return top_vec[valid], top_idxs[valid]
[docs] def weighted_norm(A: ndarray, M: ndarray | None = None): r"""Weighted norm of the columns of A. Args: A (ndarray): 1D or 2D array. If 2D, the columns are treated as vectors. M (ndarray or LinearOperator, optional): Weigthing matrix. the norm of the vector :math:`a` is given by :math:`\langle a, Ma \rangle` . Defaults to None, corresponding to the Identity matrix. Warning: no checks are performed on M being a PSD operator. Returns: (ndarray or float): If ``A.ndim == 2`` returns 1D array of floats corresponding to the norms of the columns of A. Else return a float. """ assert A.ndim <= 2, "'A' must be a vector or a 2D array" if M is None: norm = np.linalg.norm(A, axis=0) else: _A = np.dot(M, A) _A_T = np.dot(M.T, A) norm = np.real(np.sum(0.5 * (np.conj(A) * _A + np.conj(A) * _A_T), axis=0)) rcond = 10.0 * A.shape[0] * np.finfo(A.dtype).eps norm = np.where(norm < rcond, 0.0, norm) return np.sqrt(norm)