UNIFORM_DIRECTION

Overview

The UNIFORM_DIRECTION function generates random unit vectors (directions) that are uniformly distributed on the surface of a hypersphere in n-dimensional space. This is essential for applications in Monte Carlo simulations, directional statistics, computer graphics, and machine learning where unbiased sampling of directions is required.

This implementation uses the SciPy library’s uniform_direction distribution, which is part of the scipy.stats module. The underlying algorithm is based on Marsaglia’s method (1972), a well-established technique for generating uniformly distributed points on the surface of an n-sphere.

Marsaglia’s algorithm works by generating n independent standard normal random variables x_1, x_2, \ldots, x_n and then normalizing the resulting vector to unit length. The normalized vector is computed as:

\mathbf{u} = \frac{\mathbf{x}}{\|\mathbf{x}\|} = \frac{(x_1, x_2, \ldots, x_n)}{\sqrt{x_1^2 + x_2^2 + \cdots + x_n^2}}

This method leverages the spherical symmetry of the multivariate normal distribution. Since the joint distribution of independent standard normal variables is rotationally invariant, the projection onto the unit sphere yields a uniform distribution over the hypersphere’s surface.

In geometric terms, for dim=2, the function samples points uniformly from a unit circle (S^1). For dim=3, it samples from the surface of a unit sphere (S^2), which can be interpreted as random 3D directions. Higher dimensions generalize to hyperspheres S^{n-1} embedded in n-dimensional Euclidean space. Each output vector has Euclidean norm equal to 1.

For the original algorithm, see: Marsaglia, G. (1972). “Choosing a Point from the Surface of a Sphere”. Annals of Mathematical Statistics, 43(2): 645–646. doi:10.1214/aoms/1177692644.

This example function is provided as-is without any representation of accuracy.

Excel Usage

=UNIFORM_DIRECTION(dim, size, seed)
  • dim (int, required): Number of dimensions for the unit vectors. Must be >= 2.
  • size (int, optional, default: 1): Number of samples to generate. Must be >= 1.
  • seed (int, optional, default: null): Random seed for reproducibility.

Returns (list[list]): 2D list of unit vectors, or error message string.

Examples

Example 1: Single 2D unit vector

Inputs:

dim seed
2 42

Excel formula:

=UNIFORM_DIRECTION(2, 42)

Expected output:

Result
0.96337 -0.26816

Example 2: Single 3D unit vector

Inputs:

dim seed
3 42

Excel formula:

=UNIFORM_DIRECTION(3, 42)

Expected output:

Result
0.6 -0.16702 0.78237

Example 3: Multiple 2D unit vectors

Inputs:

dim size seed
2 4 42

Excel formula:

=UNIFORM_DIRECTION(2, 4, 42)

Expected output:

Result
0.96337 -0.26816
0.39135 0.92024
-0.70713 -0.70708
0.89942 0.43708

Example 4: Multiple 5D unit vectors

Inputs:

dim size seed
5 2 42

Excel formula:

=UNIFORM_DIRECTION(5, 2, 42)

Expected output:

Result
0.28396 -0.07904 0.37027 0.87069 -0.13386
-0.12251 0.82632 0.40156 -0.24565 0.28389

Python Code

from scipy.stats import uniform_direction as scipy_uniform_direction
import numpy as np

def uniform_direction(dim, size=1, seed=None):
    """
    Draws random unit vectors uniformly distributed on the surface of a hypersphere in the specified dimension.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.uniform_direction.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        dim (int): Number of dimensions for the unit vectors. Must be >= 2.
        size (int, optional): Number of samples to generate. Must be >= 1. Default is 1.
        seed (int, optional): Random seed for reproducibility. Default is None.

    Returns:
        list[list]: 2D list of unit vectors, or error message string.
    """
    def is_int(x):
        if isinstance(x, bool):
            return False
        if isinstance(x, int):
            return True
        if isinstance(x, float):
            return x.is_integer()
        return False

    # Validate dim
    if not is_int(dim) or int(dim) < 2:
        return "Invalid input: dim must be an integer >= 2."
    dim = int(dim)
    # Validate size
    if size is None:
        size = 1
    if not is_int(size) or int(size) < 1:
        return "Invalid input: size must be an integer >= 1."
    size = int(size)
    try:
        # Draw random unit vectors
        rng_seed = int(seed) if seed is not None else None
        result = scipy_uniform_direction.rvs(dim=dim, size=size, random_state=rng_seed)
    except Exception as e:
        return f"scipy.stats.uniform_direction error: {e}"
    # Always return a 2D list of floats
    arr = np.array(result)
    if arr.ndim == 1:
        # Single sample: shape (dim,)
        return [arr.astype(float).tolist()]
    elif arr.ndim == 2:
        # Multiple samples: shape (size, dim)
        return arr.astype(float).tolist()
    else:
        return "Unexpected output shape from scipy.stats.uniform_direction."

Online Calculator