nenuscanner/utils/kernels.py

83 lines
2.6 KiB
Python

import numpy as np
import utils.vector_utils as vector_utils
def weighted_least_squares(A,y,weights):
"""Computes the weighted least squares solution of Ax=y.
Args:
A (Array ...,u,v): Design matrix.
y (Array ...,u): Target values.
weights (Array ...,u): Weights for each equation.
Returns:
Array ...,v : Weighted least squares solution.
"""
pinv = np.linalg.pinv(A*weights[...,np.newaxis])
result = np.einsum('...uv,...v->...u',pinv,y*weights)
return result
def least_squares(A,y):
"""Computes the least squares solution of Ax=y.
Args:
A (Array ...,u,v): Design matrix.
y (Array ...,u): Target values.
Returns:
Array ...,v : Least squares solution.
"""
result = weighted_least_squares(A,y,np.ones(A.shape[0]))
return result
def iteratively_reweighted_least_squares(A,y, epsilon=1e-5, it=20):
"""Computes the iteratively reweighted least squares solution. of Ax=y
Args:
A (Array ..., u, v): Design matrix.
y (Array ..., u): Target values.
epsilon (float, optional): Small value to avoid division by zero. Defaults to 1e-5.
it (int, optional): Number of iterations. Defaults to 20.
Returns:
Array ..., v: Iteratively reweighted least squares solution.
"""
weights = np.ones(y.shape)
for _ in range(it):
result = weighted_least_squares(A,y,weights)
ychap = np.einsum('...uv,...v->...u',A,result)
delta = np.abs(ychap-y)
weights = np.reciprocal(np.maximum(epsilon,np.sqrt(delta)))
return result
def matrix_kernel(A):
"""Computes the eigenvector corresponding to the smallest eigenvalue of the matrix A.
Args:
A (Array ..., n, n): Input square matrix.
Returns:
Array ..., n: Eigenvector corresponding to the smallest eigenvalue.
"""
eigval, eigvec = np.linalg.eig(A)
min_index = np.argmin(np.abs(eigval),axis=-1)
min_eigvec = np.take_along_axis(eigvec,min_index[...,None,None],-1)[...,0]
normed_eigvec = vector_utils.norm_vector(min_eigvec)[1]
return normed_eigvec
def masked_least_squares(A,y,mask):
"""Computes the least squares solution of Ax = y for masked data.
Args:
A (Array ..., n, p): Design matrix.
y (Array ..., n): Target values.
mask (Array ..., n, bool): Mask to select valid data points.
Returns:
Array ..., p: Least squares solution for the masked data.
"""
masked_solver = lambda A,y,mask : least_squares(A[mask,:],y[mask])
vectorized = np.vectorize(masked_solver,signature='(n,p),(n),(n)->(p)')
result = vectorized(A,y,mask)
return result