SPECIAL_ORTHO_GROUP
Overview
The SPECIAL_ORTHO_GROUP function generates random rotation matrices from the special orthogonal group SO(N), which is the group of all orthogonal N \times N matrices with determinant +1. These matrices represent proper rotations in N-dimensional Euclidean space, preserving both distances and orientation.
This implementation uses the scipy.stats.special_ortho_group distribution from SciPy. The function draws random samples from the Haar distribution, which is the unique uniform distribution on SO(N). The Haar measure, named after mathematician Alfréd Haar, provides a mathematically rigorous way to sample “uniformly at random” from continuous groups like SO(N). For more mathematical background, see the Wikipedia article on orthogonal groups.
An orthogonal matrix Q satisfies the property:
Q Q^T = Q^T Q = I
where I is the identity matrix and Q^T is the transpose of Q. For SO(N) specifically, the additional constraint \det(Q) = +1 ensures the transformation is a pure rotation without reflection.
The algorithm generates a Haar-distributed orthogonal matrix using scipy.stats.ortho_group, then adjusts the result to guarantee the determinant is +1. For 3D rotations specifically, SciPy also provides scipy.spatial.transform.Rotation.random as an alternative.
Random rotation matrices from SO(N) have applications in:
- 3D graphics and robotics: Generating random orientations for objects or sensors
- Monte Carlo simulations: Sampling over rotation spaces
- Statistical physics: Modeling spin systems and lattice gauge theories
- Machine learning: Random projections and data augmentation with rotational transformations
This example function is provided as-is without any representation of accuracy.
Excel Usage
=SPECIAL_ORTHO_GROUP(dim, size, seed)
dim(int, required): Dimension of the square matrix (must be >= 2).size(int, optional, default: null): Number of matrices to generate (must be >= 1). If omitted, returns a single matrix.seed(int, optional, default: null): Random seed for reproducibility.
Returns (list[list]): 2D orthogonal matrix, or error message string.
Examples
Example 1: Single 3x3 orthogonal matrix
Inputs:
| dim | seed |
|---|---|
| 3 | 42 |
Excel formula:
=SPECIAL_ORTHO_GROUP(3, 42)
Expected output:
| Result | ||
|---|---|---|
| -0.6 | -0.28396 | -0.74791 |
| 0.16702 | -0.95875 | 0.23003 |
| -0.78237 | 0.0131 | 0.62268 |
Example 2: Two 3x3 orthogonal matrices stacked
Inputs:
| dim | size | seed |
|---|---|---|
| 3 | 2 | 42 |
Excel formula:
=SPECIAL_ORTHO_GROUP(3, 2, 42)
Expected output:
| Result | ||
|---|---|---|
| -0.6 | 0.19174 | -0.77668 |
| 0.16702 | -0.91944 | -0.35601 |
| -0.78237 | -0.34332 | 0.51964 |
| -0.97717 | 0.0153 | 0.2119 |
| -0.15023 | 0.6555 | -0.7401 |
| -0.15022 | -0.75504 | -0.63824 |
Example 3: Single 4x4 orthogonal matrix
Inputs:
| dim | seed |
|---|---|
| 4 | 42 |
Excel formula:
=SPECIAL_ORTHO_GROUP(4, 42)
Expected output:
| Result | |||
|---|---|---|---|
| -0.28654 | -0.81725 | 0.35728 | -0.34978 |
| -0.07976 | 0.09445 | -0.61237 | -0.78085 |
| -0.37363 | -0.38245 | -0.66888 | 0.51646 |
| -0.8786 | 0.4206 | 0.22352 | -0.03467 |
Example 4: Three 4x4 orthogonal matrices stacked
Inputs:
| dim | size | seed |
|---|---|---|
| 4 | 3 | 42 |
Excel formula:
=SPECIAL_ORTHO_GROUP(4, 3, 42)
Expected output:
| Result | |||
|---|---|---|---|
| -0.28654 | -0.86948 | -0.34295 | -0.21044 |
| 0.07976 | -0.03961 | -0.49616 | 0.86365 |
| 0.37363 | -0.48695 | 0.70777 | 0.34977 |
| -0.8786 | 0.07289 | 0.36779 | 0.29578 |
| 0.13105 | 0.57196 | 0.77031 | -0.24962 |
| 0.13104 | 0.53472 | -0.60554 | -0.57466 |
| -0.88384 | 0.39686 | -0.06705 | 0.23839 |
| 0.42951 | 0.479 | -0.18827 | 0.74204 |
| 0.48258 | 0.24018 | 0.02527 | 0.8419 |
| -0.5577 | 0.31707 | -0.72488 | 0.25098 |
| -0.47635 | -0.71085 | 0.21804 | 0.46929 |
| 0.47873 | -0.58006 | -0.65297 | -0.08932 |
Python Code
import numpy as np
from scipy.stats import special_ortho_group as scipy_special_ortho_group
def special_ortho_group(dim, size=None, seed=None):
"""
Draws random samples from the special orthogonal group SO(N), returning orthogonal matrices with determinant +1.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.special_ortho_group.html
This example function is provided as-is without any representation of accuracy.
Args:
dim (int): Dimension of the square matrix (must be >= 2).
size (int, optional): Number of matrices to generate (must be >= 1). If omitted, returns a single matrix. Default is None.
seed (int, optional): Random seed for reproducibility. Default is None.
Returns:
list[list]: 2D orthogonal matrix, or error message string.
"""
def to_2d_list(arr):
"""Convert numpy arrays to 2D lists."""
arr = np.asarray(arr)
if arr.ndim == 2:
return arr.tolist()
elif arr.ndim == 3:
# Multiple matrices: flatten into a single 2D list
return [row for mat in arr for row in mat.tolist()]
else:
return "Invalid output shape from scipy.special_ortho_group."
def valid_matrix(matrix):
"""Check for invalid values in a 2D matrix."""
for row in matrix:
for val in row:
if not isinstance(val, (int, float)):
return False
if val != val or val in (float('inf'), float('-inf')):
return False
return True
# Validate dim - accept float if it represents an integer
if isinstance(dim, float) and dim.is_integer():
dim = int(dim)
if not isinstance(dim, int) or dim < 2:
return "Invalid input: dim must be an integer >= 2."
# Validate size - accept float if it represents an integer
if size is not None:
if isinstance(size, float) and size.is_integer():
size = int(size)
if not isinstance(size, int) or size < 1:
return "Invalid input: size must be an integer >= 1 or None."
try:
# Draw samples, only pass size if not None
rng_seed = int(seed) if seed is not None else None
if size is None:
result = scipy_special_ortho_group.rvs(dim, random_state=rng_seed)
else:
result = scipy_special_ortho_group.rvs(dim, size=size, random_state=rng_seed)
except Exception as e:
return f"scipy.special_ortho_group error: {e}"
out = to_2d_list(result)
if isinstance(out, list) and all(isinstance(row, list) for row in out):
if not valid_matrix(out):
return "Invalid output: matrix contains non-numeric or special values."
return out
return out