Source code for glimix_core.cov._lrfree
from numpy import asarray, dot, ones, zeros
from optimix import Function, Vector
from .._util import format_function
[docs]class LRFreeFormCov(Function):
"""
General semi-definite positive matrix of low rank, K = LLᵀ.
The covariance matrix K is given by LLᵀ, where L is a n×m matrix and n≥m. Therefore,
K will have rank(K) ≤ m.
Example
-------
.. doctest::
>>> from glimix_core.cov import LRFreeFormCov
>>> cov = LRFreeFormCov(3, 2)
>>> print(cov.L)
[[1. 1.]
[1. 1.]
[1. 1.]]
>>> cov.L = [[1, 2], [0, 3], [1, 3]]
>>> print(cov.L)
[[1. 2.]
[0. 3.]
[1. 3.]]
>>> cov.name = "F"
>>> print(cov)
LRFreeFormCov(n=3, m=2): F
L: [[1. 2.]
[0. 3.]
[1. 3.]]
"""
[docs] def __init__(self, n, m):
"""
Constructor.
Parameters
----------
n : int
Covariance dimension.
m : int
Upper limit of the covariance matrix rank.
"""
self._L = ones((n, m))
self._Lu = Vector(self._L.ravel())
Function.__init__(self, "LRFreeFormCov", Lu=self._Lu)
@property
def nparams(self):
"""
Number of parameters.
"""
return self._L.size
def listen(self, func):
"""
Listen to parameters change.
Parameters
----------
func : callable
Function to be called when a parameter changes.
"""
self._Lu.listen(func)
def fix(self):
"""
Disable parameter optimisation.
"""
self._Lu.fix()
def unfix(self):
"""
Enable parameter optimisation.
"""
self._Lu.unfix()
@property
def Lu(self):
"""
Lower-triangular, flat part of L.
"""
return self._Lu.value
@Lu.setter
def Lu(self, v):
self._Lu.value = v
@property
def L(self):
"""
Matrix L from K = LLᵀ.
Returns
-------
L : (n, m) ndarray
Parametric matrix.
"""
return self._L
@L.setter
def L(self, value):
self._Lu.value = asarray(value, float).ravel()
@property
def shape(self):
"""
Array shape.
"""
n = self._L.shape[0]
return (n, n)
def value(self):
"""
Covariance matrix.
Returns
-------
K : (n, n) ndarray
K = LLᵀ.
"""
return dot(self.L, self.L.T)
def gradient(self):
"""
Derivative of the covariance matrix over the lower triangular, flat part of L.
It is equal to
∂K/∂Lᵢⱼ = ALᵀ + LAᵀ,
where Aᵢⱼ is an n×m matrix of zeros except at [Aᵢⱼ]ᵢⱼ=1.
Returns
-------
Lu : ndarray
Derivative of K over the lower-triangular, flat part of L.
"""
L = self.L
n = self.L.shape[0]
grad = {"Lu": zeros((n, n, n * self._L.shape[1]))}
for ii in range(self._L.shape[0] * self._L.shape[1]):
row = ii // self._L.shape[1]
col = ii % self._L.shape[1]
grad["Lu"][row, :, ii] = L[:, col]
grad["Lu"][:, row, ii] += L[:, col]
return grad
def __str__(self):
return format_function(
self, {"n": self._L.shape[0], "m": self._L.shape[1]}, [("L", self._L)]
)