nenuscanner/utils/quadratic_forms.py

99 lines
3.2 KiB
Python

import numpy as np
import utils.kernels as kernels
import utils.vector_utils as vector_utils
def evaluate_bilinear_form(Q,left,right):
"""evaluates bilinear forms at several points
Args:
Q (Array ...,ldim,rdim): bilinear form to evaluate
left (Array ...,ldim): points where the bilinear form is evaluated to the left
right (Array ...,rdim): points where the bilinear form is evaluated to the right
Returns:
Array ... bilinear forms evaluated
"""
result = np.einsum('...ij,...i,...j->...',Q,left,right)
return result
def evaluate_quadratic_form(Q,points):
"""evaluates quadratic forms at several points
Args:
Q (Array ...,dim,dim): quadratic form to evaluate
points (Array ...,dim): points where the quadratic form is evaluated
Returns:
Array ... quadratic forms evaluated
"""
result = evaluate_bilinear_form(Q,points,points)
return result
def merge_quadratic_to_homogeneous(Q,b,c):
"""merges quadratic form, linear term, and constant term into a homogeneous matrix
Args:
Q (Array ..., dim, dim): quadratic form matrix
b (Array ..., dim): linear term vector
c (Array ...): constant term
Returns:
Array ..., dim+1, dim+1: homogeneous matrix representing the quadratic form
"""
dim_points = Q.shape[-1]
stack_shape = np.broadcast_shapes(np.shape(Q)[:-2],np.shape(b)[:-1],np.shape(c))
Q_b = np.broadcast_to(Q,stack_shape+(dim_points,dim_points))
b_b = np.broadcast_to(np.expand_dims(b,-1),stack_shape+(dim_points,1))
c_b = np.broadcast_to(np.expand_dims(c,(-1,-2)),stack_shape+(1,1))
H = np.block([[Q_b,0.5*b_b],[0.5*np.swapaxes(b_b,-1,-2),c_b]])
return H
def quadratic_to_dot_product(points):
"""computes the matrix W such that
x.T@Ax = W(x).T*A[ui,uj]
Args:
points ( Array ...,ndim): points of dimension ndim
Returns:
Array ...,ni: dot product matrix (W)
Array ni: i indices of central matrix
Array ni: j indices of central matrix
"""
dim_points = points.shape[-1]
ui,uj = np.triu_indices(dim_points)
W = points[...,ui]*points[...,uj]
return W,ui,uj
def fit_quadratic_form(points):
"""Fits a quadratic form to the given zeroes.
Args:
points (Array ..., n, dim): Input points.
Returns:
Array ..., dim, dim: Fitted quadratic form matrix.
"""
dim_points = points.shape[-1]
normed_points = vector_utils.norm_vector(points)[1]
W,ui,uj = quadratic_to_dot_product(normed_points)
H = np.einsum('...ki,...kj->...ij',W,W)
V0 = kernels.matrix_kernel(H)
Q = np.zeros(V0.shape[:-1]+(dim_points,dim_points))
Q[...,ui,uj]=V0
return Q
# import matplotlib.pyplot as plt
# Q = np.random.randn(3,3)
# x0, y0 = np.linspace(-1,1,300),np.linspace(-1,1,300)
# x,y = np.meshgrid(x0,y0,indexing='ij')
# points = vector_utils.to_homogeneous(np.stack([x,y],axis=-1))
# f = evaluate_quadratic_form(Q,points)
# mask = np.abs(f)<0.01
# u,v = np.where(mask)
# zeros = vector_utils.to_homogeneous(np.stack([x0[u],y0[v]],axis=-1))+np.random.randn(5,u.shape[0],3)*0.1
# Qc = fit_quadratic_form(zeros)
# fchap = evaluate_quadratic_form(Qc,points[...,None,:])
# print()