Source code for torch_openreml.covariance.simple_matrix

"""
Simple covariance matrix from a user-supplied function.

This module provides a minimal adapter for wrapping a plain function as a
:class:`~torch_openreml.covariance.matrix.Matrix`, intended for simple cases
where all parameters are free with identity transforms — no manual parameter
specifications or transform logic required.

Classes:
    SimpleMatrix:
        A covariance matrix backed by a user-defined callable.
"""

from torch_openreml.covariance.matrix import Matrix
from torch_openreml.covariance.param import simple_param_specs


[docs] class SimpleMatrix(Matrix): r""" A covariance matrix for simple, function-based parameterisations. This is the easiest way to use :class:`~torch_openreml.REML` with a custom covariance structure: provide the number of parameters and a function that maps a flat parameter tensor to the covariance matrix. All parameters are free and use an identity transform (unconstrained). The ``default`` argument sets the value used for each free parameter when none are provided. For more advanced needs (custom transforms, fixed parameters, manual gradients), subclass :class:`~torch_openreml.covariance.matrix.Matrix` directly. Args: n (int): Number of free parameters. call (callable): Function with signature ``call(free_params) -> torch.Tensor`` that constructs the covariance matrix from a flat 1D parameter tensor. manual_grad (callable, optional): Function with signature ``manual_grad(free_params) -> (grad, grad_names)`` for a closed-form Jacobian. If ``None`` (default), automatic differentiation is used. default (float or torch.Tensor, optional): Default value for each parameter. Passed to :func:`simple_param_specs`. Defaults to ``0.0``. Example: .. jupyter-execute:: import torch from torch_openreml.covariance import SimpleMatrix def my_v(free_params): n = free_params.shape[0] return torch.diag(free_params) mat = SimpleMatrix(n=3, call=my_v) mat(torch.tensor([1.0, 2.0, 3.0])) .. jupyter-execute:: mat.grad(torch.tensor([1.0, 2.0, 3.0])) """ def __init__(self, n, call, manual_grad=None, default=0.0): if call is None: raise ValueError("'call' must be provided.") super().__init__(None, simple_param_specs(n, default=default)) self._call = call self._manual_grad = manual_grad
[docs] def __call__(self, free_params=None): if free_params is None: free_params = self.free_param_defaults result = self._call(free_params) self._shape = tuple(result.shape) return result
[docs] def manual_grad(self, free_params=None): if self._manual_grad is None: raise NotImplementedError if free_params is None: free_params = self.free_param_defaults return self._manual_grad(free_params)