MATRIX_NORMAL
Overview
The MATRIX_NORMAL
function computes the probability density function (PDF), log-PDF, or draws random samples from a matrix normal distribution, which generalizes the multivariate normal distribution to matrix-valued random variables. The matrix normal distribution is parameterized by a mean matrix, a row covariance matrix, and a column covariance matrix. The PDF is given by:
where is the observed matrix, is the mean matrix, is the row covariance matrix, is the column covariance matrix, is the number of rows, and is the number of columns. For more details, see the scipy.stats.matrix_normal documentation .
This wrapper exposes only the most commonly used parameters and methods (pdf
, logpdf
, rvs
). The seed
/random_state
and entropy
options from the underlying SciPy function are not supported. This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=MATRIX_NORMAL(x, mean, rowcov, colcov, [method], [size])
x
(2D list, required): Matrix at which to evaluate the function or as a template for sample shape. Must have at least two rows and columns.mean
(2D list, required): Mean matrix of the distribution. Must match the shape ofx
.rowcov
(2D list, required): Among-row covariance matrix. Must be square with size equal to number of rows inx
.colcov
(2D list, required): Among-column covariance matrix. Must be square with size equal to number of columns inx
.method
(string, optional, default=pdf
): Which method to compute:pdf
,logpdf
, orrvs
.size
(integer, optional, only forrvs
): Number of samples to draw ifmethod
isrvs
. Default is 1.
The function returns a 2D list of results for each input point (for pdf
and logpdf
), or a 2D list of sampled matrices (for rvs
). If the input is invalid, a string error message is returned.
Examples
Example 1: PDF Calculation
Inputs:
x | mean | rowcov | colcov | method | ||||
---|---|---|---|---|---|---|---|---|
1.0 | 2.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | |
3.0 | 4.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 |
Excel formula:
=MATRIX_NORMAL({1,2;3,4}, {0,0;0,0}, {1,0;0,1}, {1,0;0,1}, "pdf")
Expected output:
Result |
---|
0.000 |
Example 2: LogPDF Calculation
Inputs:
x | mean | rowcov | colcov | method | ||||
---|---|---|---|---|---|---|---|---|
1.0 | 2.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | logpdf |
3.0 | 4.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 |
Excel formula:
=MATRIX_NORMAL({1,2;3,4}, {0,0;0,0}, {1,0;0,1}, {1,0;0,1}, "logpdf")
Expected output:
Result |
---|
-18.676 |
Example 3: Single Random Sample
Inputs:
x | mean | rowcov | colcov | method | size | ||||
---|---|---|---|---|---|---|---|---|---|
1.0 | 2.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | rvs | 1 |
3.0 | 4.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 |
Excel formula:
=MATRIX_NORMAL({1,2;3,4}, {0,0;0,0}, {1,0;0,1}, {1,0;0,1}, "rvs", 1)
Expected output:
Sample Matrix |
---|
(varies) |
Example 4: Multiple Random Samples
Inputs:
x | mean | rowcov | colcov | method | size | ||||
---|---|---|---|---|---|---|---|---|---|
1.0 | 2.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | rvs | 2 |
3.0 | 4.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 |
Excel formula:
=MATRIX_NORMAL({1,2;3,4}, {0,0;0,0}, {1,0;0,1}, {1,0;0,1}, "rvs", 2)
Expected output:
Sample Matrix 1 | Sample Matrix 2 |
---|---|
(varies) | (varies) |
For random samples, the output will vary each time the function is called.
Python Code
import micropip
await micropip.install(['scipy', 'numpy'])
from scipy.stats import matrix_normal as scipy_matrix_normal
from typing import List, Optional, Union
def matrix_normal(
x: List[List[float]],
mean: Optional[List[List[float]]] = None,
rowcov: Optional[List[List[float]]] = None,
colcov: Optional[List[List[float]]] = None,
method: str = 'pdf',
size: Optional[int] = None
) -> Union[List[List[Optional[float]]], str]:
"""
Computes the PDF, log-PDF, or draws random samples from a matrix normal distribution.
Args:
x: 2D list of float values. Points at which to evaluate the function or fit the distribution.
mean: 2D list of float values. Mean matrix of the distribution. Default is zero matrix.
rowcov: 2D list of float values. Among-row covariance matrix. Default is identity matrix.
colcov: 2D list of float values. Among-column covariance matrix. Default is identity matrix.
method: Which method to compute (str): 'pdf', 'logpdf', 'rvs'. Default is 'pdf'.
size: Number of samples to draw if method is 'rvs'. Optional.
Returns:
2D list of results for each input point, or an error message (str) if input is invalid.
This example function is provided as-is without any representation of accuracy.
"""
# Validate x
if not isinstance(x, list) or len(x) < 2 or not all(isinstance(row, list) and len(row) > 0 for row in x):
return "Invalid input: x must be a 2D list with at least two rows."
try:
x_mat = [[float(val) for val in row] for row in x]
except Exception:
return "Invalid input: x must contain numeric values."
n_rows = len(x_mat)
n_cols = len(x_mat[0])
# Validate mean
if mean is not None:
if not isinstance(mean, list) or len(mean) != n_rows or not all(isinstance(row, list) and len(row) == n_cols for row in mean):
return "Invalid input: mean must be a 2D list with same shape as x."
try:
mean_mat = [[float(val) for val in row] for row in mean]
except Exception:
return "Invalid input: mean must contain numeric values."
else:
mean_mat = [[0.0 for _ in range(n_cols)] for _ in range(n_rows)]
# Validate rowcov
if rowcov is not None:
if not isinstance(rowcov, list) or len(rowcov) != n_rows or not all(isinstance(row, list) and len(row) == n_rows for row in rowcov):
return "Invalid input: rowcov must be a square 2D list with shape (n_rows, n_rows)."
try:
rowcov_mat = [[float(val) for val in row] for row in rowcov]
except Exception:
return "Invalid input: rowcov must contain numeric values."
else:
rowcov_mat = [[float(i == j) for j in range(n_rows)] for i in range(n_rows)]
# Validate colcov
if colcov is not None:
if not isinstance(colcov, list) or len(colcov) != n_cols or not all(isinstance(row, list) and len(row) == n_cols for row in colcov):
return "Invalid input: colcov must be a square 2D list with shape (n_cols, n_cols)."
try:
colcov_mat = [[float(val) for val in row] for row in colcov]
except Exception:
return "Invalid input: colcov must contain numeric values."
else:
colcov_mat = [[float(i == j) for j in range(n_cols)] for i in range(n_cols)]
# Validate method
if method not in ('pdf', 'logpdf', 'rvs'):
return "Invalid input: method must be one of 'pdf', 'logpdf', or 'rvs'."
try:
dist = scipy_matrix_normal(mean=mean_mat, rowcov=rowcov_mat, colcov=colcov_mat)
except Exception as e:
return f"scipy.stats.matrix_normal error: {e}"
if method in ('pdf', 'logpdf'):
try:
if method == 'pdf':
val = dist.pdf(x_mat)
else:
val = dist.logpdf(x_mat)
# Convert numpy types to native float for Excel compatibility
import numpy as np
if isinstance(val, np.generic):
val = float(val)
return [[val]]
except Exception as e:
return f"scipy.stats.matrix_normal {method} error: {e}"
elif method == 'rvs':
if size is not None:
try:
size_int = int(size)
if size_int < 1:
return "Invalid input: size must be >= 1."
except Exception:
return "Invalid input: size must be an integer."
else:
size_int = 1
try:
samples = dist.rvs(size=size_int)
# If size == 1, samples is a matrix; if size > 1, samples is a 3D array
import numpy as np
if size_int == 1:
# Return as 2D list
return [[float(val) for val in row] for row in samples]
else:
# Return as 2D list of flattened samples
return [ [float(val) for row in sample for val in row] for sample in samples ]
except Exception as e:
return f"scipy.stats.matrix_normal rvs error: {e}"
return "Unknown error."