spyrit.core.meas.LinearSplit

class spyrit.core.meas.LinearSplit(H, meas_shape=None, meas_dims=None, *, noise_model=Identity(), dtype: dtype = torch.float32, device: device = device(type='cpu'))[source]

Bases: Linear

Simulate linear measurements by splitting an acquisition matrix \(H\in \mathbb{R}^{M\times N}\) that contains negative values. In pratice, only positive values can be implemented using a DMD. Therefore, we acquire

\[y =\mathcal{N}\left(Ax\right),\]

where \(\mathcal{N} \colon\, \mathbb{R}^{2M} \to \mathbb{R}^{2M}\) represents a noise operator (e.g., Gaussian), \(A \colon\, \mathbb{R}_+^{2M\times N}\) is the acquisition matrix that contains positive DMD patterns, \(x \in \mathbb{R}^N\) is the signal of interest., \(2M\) is the number of DMD patterns, and \(N\) is the dimension of the signal.

Given a matrix \(H\), we define the positive DMD patterns \(A\) from the positive and negative components \(H\). In practice, the even rows of \(A\) contain the positive components of \(H\), while odd rows of \(A\) contain the negative components of \(H\)

\[\begin{split}\begin{cases} A[0::2, :] = H_{+}, \text{ with } H_{+} = \max(0,H),\\ A[1::2, :] = H_{-}, \text{ with } H_{-} = \max(0,-H). \end{cases}\end{split}\]

Note

\(H_{+}\) and \(H_{-}\) are such that \(H_{+} - H_{-} = H\).

Important

The vector \(x \in \mathbb{R}^N\) represents a multi-dimensional array (e.g, an image \(X \in \mathbb{R}^{N_1 \times N_2}\) with \(N = N_1 \times N_2\)).

Args:

H (torch.tensor): measurement matrix (linear operator) with shape \((M, N)\). Only real values are supported.

meas_shape (tuple, optional): Shape of the underliying multi-dimensional array \(X\). Must be a tuple of integers \((N_1, ... ,N_k)\) such that \(\prod_k N_k = N\). If not, an error is raised. Defaults to None.

meas_dims (tuple, optional): Dimensions of \(X\) the acquisition matrix applies to. Must be a tuple with the same length as meas_shape. If not, an error is raised. Defaults to the last dimensions of the multi-dimensional array \(X\) (e.g., (-2,-1) when len(meas_shape)).

noise_model (see spyrit.core.noise): Noise model \(\mathcal{N}\). Defaults to = torch.nn.Identity.

Attributes:

A (torch.tensor): (Learnable) positive measurement matrix of shape \((2M, N)\) initialized as \(A\).

H (torch.tensor): (Learnable) measurement matrix of shape \((M, N)\) initialized as \(H\).

meas_shape (tuple): Shape of the underliying multi-dimensional array \(X\).

meas_dims (tuple): Dimensions the acquisition matrix applies to.

meas_ndim (int): Number of dimensions the acquisition matrix applies to. This is len(meas_dims)

noise_model (see spyrit.core.noise): Noise model \(\mathcal{N}\).

M (int): Number of measurements \(M\).

Examples:

Example 1: (3, 4) signals of length 15 are measured with an acquisition matrix of shape (10, 15). This produces (3, 4) measurements of length 20.

>>> import torch
>>> import spyrit.core.meas as meas
>>> H = torch.randn(10, 15)
>>> meas_op = meas.LinearSplit(H)
>>> x = torch.randn(3, 4, 15)
>>> y = meas_op(x)
>>> print(y.shape)
torch.Size([3, 4, 20])

Example 2: 3 signals of length (15, 4) are measured with an acquisition matrix of shape (10, 60). This produces 3 measurements of length 20. The acquisition matrix applies to both dimensions -2 and -1.

>>> import torch
>>> import spyrit.core.meas as meas
>>> H = torch.randn(10, 60)
>>> meas_op = meas.LinearSplit(H, meas_shape=(15, 4))
>>> x = torch.randn(3, 15, 4)
>>> y = meas_op(x)
>>> print(y.shape)
torch.Size([3, 20])
>>> print(meas_op.meas_dims)
torch.Size([-2, -1])

Methods

adjoint(y[, unvectorize])

Apply adjoint of matrix A.

adjoint_H(m[, unvectorize])

Apply adjoint of matrix H.

forward(x)

Simulate noisy measurements from matrix A.

forward_H(x)

Simulate noisy measurements from matrix H.

measure(x)

Simulate noiseless measurements from matrix A.

measure_H(x)

Simulate noiseless measurements from matrix H.

set_matrix_to_inverse(matrix_name)

unvectorize(input)

Unflatten the measured dimensions.

vectorize(input)

Flatten the measured dimensions.