Source code for linear_operator_learning.kernel.utils
"""Generic Utilities."""
from math import sqrt
import numpy as np
from numpy import ndarray
from scipy.spatial.distance import pdist
[docs]
def topk(vec: ndarray, k: int):
"""Get the top k values from a Numpy array.
Args:
vec (ndarray): A 1D numpy array
k (int): Number of elements to keep
Returns:
values, indices: top k values and their indices
"""
assert np.ndim(vec) == 1, "'vec' must be a 1D array"
assert k > 0, "k should be greater than 0"
sort_perm = np.flip(np.argsort(vec)) # descending order
indices = sort_perm[:k]
values = vec[indices]
return values, indices
[docs]
def sanitize_complex_conjugates(vec: ndarray, tol: float = 10.0):
"""This function acts on 1D complex vectors. If the real parts of two elements are close, sets them equal. Furthermore, sets to 0 the imaginary parts smaller than `tol` times the machine precision.
Args:
vec (ndarray): A 1D vector to sanitize.
tol (float, optional): Tolerance for comparisons. Defaults to 10.0.
"""
assert issubclass(vec.dtype.type, np.complexfloating), "The input element should be complex"
assert vec.ndim == 1
rcond = tol * np.finfo(vec.dtype).eps
pdist_real_part = pdist(vec.real[:, None])
# Set the same element whenever pdist is smaller than eps*tol
condensed_idxs = np.argwhere(pdist_real_part < rcond)[:, 0]
fuzzy_real = vec.real.copy()
if condensed_idxs.shape[0] >= 1:
for idx in condensed_idxs:
i, j = _row_col_from_condensed_index(vec.real.shape[0], idx)
avg = 0.5 * (fuzzy_real[i] + fuzzy_real[j])
fuzzy_real[i] = avg
fuzzy_real[j] = avg
fuzzy_imag = vec.imag.copy()
fuzzy_imag[np.abs(fuzzy_imag) < rcond] = 0.0
return fuzzy_real + 1j * fuzzy_imag
def _row_col_from_condensed_index(d, index):
# Credits to: https://stackoverflow.com/a/14839010
b = 1 - (2 * d)
i = (-b - sqrt(b**2 - 8 * index)) // 2
j = index + i * (b + i + 2) // 2 + 1
return (int(i), int(j))