Skip to Content

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:

f(X)=exp(12tr[R1(XM)C1(XM)T])(2π)np/2Rp/2Cn/2f(X) = \frac{\exp\left(-\frac{1}{2} \mathrm{tr}\left[R^{-1}(X-M)C^{-1}(X-M)^T\right]\right)}{(2\pi)^{np/2} |R|^{p/2} |C|^{n/2}}

where XX is the observed matrix, MM is the mean matrix, RR is the row covariance matrix, CC is the column covariance matrix, nn is the number of rows, and pp 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 of x.
  • rowcov (2D list, required): Among-row covariance matrix. Must be square with size equal to number of rows in x.
  • colcov (2D list, required): Among-column covariance matrix. Must be square with size equal to number of columns in x.
  • method (string, optional, default=pdf): Which method to compute: pdf, logpdf, or rvs.
  • size (integer, optional, only for rvs): Number of samples to draw if method is rvs. 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:

xmeanrowcovcolcovmethod
1.02.00.00.01.00.01.00.0pdf
3.04.00.00.00.01.00.01.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:

xmeanrowcovcolcovmethod
1.02.00.00.01.00.01.00.0logpdf
3.04.00.00.00.01.00.01.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:

xmeanrowcovcolcovmethodsize
1.02.00.00.01.00.01.00.0rvs1
3.04.00.00.00.01.00.01.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:

xmeanrowcovcolcovmethodsize
1.02.00.00.01.00.01.00.0rvs2
3.04.00.00.00.01.00.01.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 1Sample 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."

Example Workbook

Link to Workbook

Last updated on