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.
Example 1: Single 3x3 orthogonal matrix
Inputs:
| dim | seed |
|---|---|
| 3 | 42 |
Excel formula:
=SPECIAL_ORTHO_GROUP(3, 42)
Expected output:
| Result | ||
|---|---|---|
| -0.600002 | -0.283962 | -0.747906 |
| 0.167015 | -0.958746 | 0.230026 |
| -0.78237 | 0.0131045 | 0.622676 |
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.600002 | 0.191744 | -0.77668 |
| 0.167015 | -0.919436 | -0.35601 |
| -0.78237 | -0.343324 | 0.519639 |
| -0.977171 | 0.0152953 | 0.211902 |
| -0.150232 | 0.6555 | -0.740101 |
| -0.150222 | -0.75504 | -0.638238 |
Example 3: Single 4x4 orthogonal matrix
Inputs:
| dim | seed |
|---|---|
| 4 | 42 |
Excel formula:
=SPECIAL_ORTHO_GROUP(4, 42)
Expected output:
| Result | |||
|---|---|---|---|
| -0.286541 | -0.817253 | 0.357279 | -0.349775 |
| -0.079761 | 0.0944496 | -0.612368 | -0.780847 |
| -0.373634 | -0.382451 | -0.668876 | 0.516462 |
| -0.878595 | 0.420603 | 0.223519 | -0.034671 |
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.286541 | -0.869479 | -0.342952 | -0.21044 |
| 0.079761 | -0.0396118 | -0.496162 | 0.863651 |
| 0.373634 | -0.486955 | 0.707768 | 0.349767 |
| -0.878595 | 0.072888 | 0.367794 | 0.295779 |
| 0.131049 | 0.571957 | 0.770312 | -0.24962 |
| 0.13104 | 0.534717 | -0.605539 | -0.574656 |
| -0.883841 | 0.39686 | -0.0670547 | 0.238393 |
| 0.429512 | 0.479004 | -0.188271 | 0.742044 |
| 0.482576 | 0.240182 | 0.0252718 | 0.841899 |
| -0.557701 | 0.317068 | -0.724877 | 0.250978 |
| -0.47635 | -0.710851 | 0.218045 | 0.469294 |
| 0.478727 | -0.580061 | -0.652971 | -0.0893223 |
Python Code
Show 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):
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 "Error: Invalid output shape from scipy.stats.special_ortho_group."
def valid_matrix(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
try:
# 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 "Error: 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 "Error: 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"Error: scipy.stats.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 "Error: Invalid output: matrix contains non-numeric or special values."
return out
return out
except Exception as e:
return f"Error: {str(e)}"