Source code for torch_openreml.covariance.equal_entry_matrix

"""
Equal-entry covariance matrix.

This module provides an equal-entry covariance matrix in which every
entry shares a single common value, for use in linear mixed-effects
models.

Classes:
    EqualEntryMatrix:
        An equal-entry matrix :math:`V = \\sigma^2 J_{n \\times m}`.
"""

from torch_openreml.covariance.matrix import Matrix
from torch_openreml.covariance.transform import TransformExpPow2
import torch

[docs] class EqualEntryMatrix(Matrix): r""" Equal-entry matrix of size ``n x m`` with a single shared value across all entries. .. math:: \symbf{V} = \sigma^2 \symbf{J}_{n \times m} where :math:`\symbf{J}_{n \times m}` is the :math:`n \times m` matrix of ones. A single unconstrained scalar parameter is transformed to a positive variance via :class:`~torch_openreml.covariance.transform.TransformExpPow2` by default and is then replicated across every entry of the matrix. Consequently all entries equal :math:`\sigma^2`. When ``m`` is omitted it defaults to ``n``, giving the square all-ones matrix :math:`\sigma^2 \symbf{J}_n`. This is singular for ``n > 1`` and represents the contribution of a single random effect shared by all observations (e.g. a common-environment effect), to be combined with other components via :class:`~torch_openreml.covariance.Sum`. Non-square sizes (``m != n``) may instead be used as rectangular factors, e.g. inside :class:`~torch_openreml.covariance.Gram`. """ def __init__(self, n, m=None, param_specs=None): """ Initialize an equal-entry matrix of size ``n x m``. Args: n (int, list, tuple or pandas.Series): Number of rows, or a vector of levels whose distinct elements define it. Matrix dimension when ``m`` is omitted. m (int, list, tuple or pandas.Series, optional): Number of columns, or a vector of levels whose distinct elements define it. Defaults to ``n`` when omitted or ``None``. Default: ``None``. param_specs (dict): Parameter specifications. Keys should be strings representing parameter names. Values should be dictionaries containing the specification for each parameter. Each specification dictionary should contain the keys ``"fixed"``, ``"default"``, and ``"trans"``, representing whether the parameter is fixed or free (bool), the default value (1D torch.Tensor), and the transform (:class:`~torch_openreml.covariance.transform.Transform`), respectively. Example: .. jupyter-execute:: import torch from torch_openreml.covariance import EqualEntryMatrix mat = EqualEntryMatrix(3, 2) mat .. jupyter-execute:: mat = EqualEntryMatrix(3) mat .. jupyter-execute:: free_params = torch.tensor([0.5]) mat(free_params) .. jupyter-execute:: mat.grad(free_params) """ n = self.resolve_dim(n) m = n if m is None else m m = self.resolve_dim(m) param_specs = param_specs or { "sigma^2": { "fixed": False, "default": torch.tensor([0.0]), "trans": TransformExpPow2() } } super().__init__((n, m), param_specs)
[docs] def __call__(self, free_params=None): sigma2 = self.build_params(free_params) device = sigma2.device dtype = sigma2.dtype j_n_m = torch.ones((self.shape[0], self.shape[1]), device=device, dtype=dtype) v = sigma2 * j_n_m return v
[docs] def manual_grad(self, free_params=None): """ Compute the Jacobian of :meth:`__call__` with respect to trainable parameters using a closed-form analytic expression. Args: free_params (torch.Tensor or dict): Flat 1D parameter tensor or parameter dictionary. If omitted, default values are used. Default: ``None``. Returns: tuple: ``(grad, grad_names)``, where ``grad`` is a 3D tensor of shape ``(num_free_params, *shape)`` and ``grad_names`` is a list of the corresponding parameter names. Returns ``(None, [])`` when the matrix has no free parameters, after ``free_params`` is validated via :meth:`~torch_openreml.covariance.matrix.Matrix.build_params`. """ free_params = self.build_params(free_params, include_fixed=False, trans=False, out_format="tensor") if len(free_params) == 0: return None, [] device = free_params.device dtype = free_params.dtype j_n_m = torch.ones((self.shape[0], self.shape[1]), device=device, dtype=dtype) grad = (self.trans_grad(free_params) * j_n_m).unsqueeze(0) return grad, self.free_param_names