Add a quaternion dtype to NumPy with comprehensive quaternion arithmetic and mathematical operations
—
Fundamental quaternion functionality including the quaternion type, predefined constants, arithmetic operations, and efficient array manipulation functions. These operations form the foundation for all quaternion computations.
Create quaternions from individual components or arrays.
def quaternion(w=0.0, x=0.0, y=0.0, z=0.0):
"""
Create a quaternion from scalar and vector components.
Args:
w (float): Scalar component (real part)
x (float): i component (first imaginary part)
y (float): j component (second imaginary part)
z (float): k component (third imaginary part)
Returns:
quaternion: New quaternion with specified components
"""Standard quaternion constants for common operations.
# Fundamental quaternion constants
zero = quaternion(0, 0, 0, 0) # Zero quaternion
one = quaternion(1, 0, 0, 0) # Identity quaternion
x = quaternion(0, 1, 0, 0) # Basis quaternion i
y = quaternion(0, 0, 1, 0) # Basis quaternion j
z = quaternion(0, 0, 0, 1) # Basis quaternion kConvert between quaternion arrays and float arrays for interoperability and performance.
def as_float_array(a):
"""
View quaternion array as float array with shape (..., 4).
Args:
a (array_like): Quaternion array
Returns:
ndarray: Float array with components [w, x, y, z] in last dimension
Notes:
Fast view operation (no data copying). Output has one more dimension
than input, with size 4 representing [w, x, y, z] components.
"""
def as_quat_array(a):
"""
View float array as quaternion array.
Args:
a (array_like): Float array with last dimension divisible by 4
Returns:
quaternion array: Array interpreted as quaternions
Notes:
Input must have final dimension size divisible by 4. Components
interpreted as [w, x, y, z]. Fast view when input is C-contiguous.
"""
def from_float_array(a):
"""
Alias for as_quat_array.
Args:
a (array_like): Float array to convert
Returns:
quaternion array: Array interpreted as quaternions
"""Work with the 3D vector components of quaternions (x, y, z parts).
def as_vector_part(q):
"""
Extract vector parts from quaternions as float array.
Args:
q (quaternion array_like): Input quaternions
Returns:
ndarray: Float array of shape q.shape + (3,) containing [x, y, z] components
"""
def from_vector_part(v, vector_axis=-1):
"""
Create quaternions from vector parts (w=0).
Args:
v (array_like): Array of 3D vectors or quaternion array
vector_axis (int): Axis containing vector components (default: -1)
Returns:
quaternion array: Quaternions with w=0 and vector parts from input
Notes:
If input has quaternion dtype, returns unchanged. Otherwise, expects
dimension of size 3 or 4 along vector_axis. For size 4, sets w=0.
"""Convert quaternions to two-complex spinor representation.
def as_spinor_array(a):
"""
View quaternion array as spinors in two-complex representation.
Args:
a (quaternion array_like): Input quaternion array
Returns:
ndarray: Complex array of shape a.shape + (2,)
Notes:
Slower operation involving memory copying due to column reordering.
Maps quaternion components to two complex numbers.
"""Quaternions support all standard mathematical operations through NumPy's ufunc system:
q1 + q2q1 - q2q1 * q2 (quaternion product)q1 / q2 (multiply by reciprocal)q ** n (quaternion exponentiation)np.conjugate(q) or q.conjugate(): Quaternion conjugatenp.abs(q) or q.norm(): Quaternion norm/magnitudeq.normalized(): Unit quaternion (norm 1)np.exp(q): Quaternion exponentialnp.log(q): Quaternion logarithmnp.sqrt(q): Quaternion square rootnp.sin(q), np.cos(q), np.tan(q)np.arcsin(q), np.arccos(q), np.arctan(q)q1 == q2q1 != q2q1 < q2, q1 <= q2, q1 > q2, q1 >= q2 (lexicographic)np.isnan(q): Check for NaN componentsnp.isinf(q): Check for infinite componentsnp.isfinite(q): Check if all components are finiteq.nonzero(): Check if quaternion is non-zeroimport quaternion
import numpy as np
# Create quaternions
q1 = quaternion.quaternion(1, 2, 3, 4)
q2 = quaternion.quaternion(0.5, -1, 0, 2)
# Array operations
q_array = np.array([q1, q2, quaternion.x, quaternion.y])
print(f"Array shape: {q_array.shape}")
# Convert to float representation
float_repr = quaternion.as_float_array(q_array)
print(f"Float array shape: {float_repr.shape}") # (..., 4)
# Extract vector parts
vectors = quaternion.as_vector_part(q_array)
print(f"Vector parts shape: {vectors.shape}") # (..., 3)
# Create from vectors (pure quaternions)
pure_quats = quaternion.from_vector_part(vectors)
# Mathematical operations
conjugates = np.conjugate(q_array)
norms = np.abs(q_array)
normalized = q_array / norms[..., np.newaxis]
# Check properties
finite_mask = np.isfinite(q_array)
nonzero_mask = np.array([q.nonzero() for q in q_array])
# Advanced comparison with tolerance
close_mask = quaternion.isclose(q_array, normalized, rtol=1e-10)
all_close = quaternion.allclose(q_array, normalized, verbose=True)Precise comparison functions with configurable tolerances for quaternion equality testing.
def isclose(a, b, rtol=4*np.finfo(float).eps, atol=0.0, equal_nan=False):
"""
Element-wise test for close equality with tolerance.
Args:
a (array_like): First quaternion array
b (array_like): Second quaternion array
rtol (float): Relative tolerance (default: 4*machine epsilon)
atol (float): Absolute tolerance (default: 0.0)
equal_nan (bool): Consider NaN values as equal (default: False)
Returns:
ndarray: Boolean array indicating element-wise closeness
Notes:
Uses |a - b| <= atol + rtol * |b| comparison formula.
More stringent defaults than numpy.isclose for quaternion precision.
"""
def allclose(a, b, rtol=4*np.finfo(float).eps, atol=0.0, equal_nan=False, verbose=False):
"""
Test if all quaternions in arrays are close within tolerance.
Args:
a (array_like): First quaternion array
b (array_like): Second quaternion array
rtol (float): Relative tolerance (default: 4*machine epsilon)
atol (float): Absolute tolerance (default: 0.0)
equal_nan (bool): Consider NaN values as equal (default: False)
verbose (bool): Print non-close values if result is False (default: False)
Returns:
bool: True if all elements are close, False otherwise
Notes:
Wrapper around isclose() returning single boolean result.
Verbose mode prints mismatched values for debugging.
"""Install with Tessl CLI
npx tessl i tessl/pypi-numpy-quaternion