Skip to content

Quaternions and rigid transforms

hmath.quaternion and hmath.rotation expose every public function of HMath.Quaternion and HMath.Rotation. They use the actual immutable Haskell objects and original checked algorithms. These finite, normalized rotation APIs have distinct types from the generic algebraic values in hmath.numeric_types.

from hmath import quaternion as q, rotation as r

with q.from_euler(0.1, 0.2, 0.3) as orientation:
    print(q.components(orientation))  # scalar-first [w, x, y, z]
    with r.so3(orientation) as rotation:
        with r.se3(rotation, [1, 2, 3]) as transform:
            print(r.transform_point(transform, [0, 0, 0]))
            with r.to_homogeneous(transform) as matrix:
                print(matrix.shape)  # (4, 4)
                print(matrix.to_list())

All real coefficients are the source Double. Python vector inputs become [Double]; nested list/tuple results retain their original structure. Matrix conversions accept or return the same owned Matrix Double used by the dense matrix API, including its shape and row-major logical values. A Float32 Matrix is a distinct coefficient type and must be converted explicitly.

Mathematical conventions

Quaternions are Hamilton quaternions in scalar-first (w,x,y,z) order. Rotations are active and right-handed, acting on column vectors. Angles are radians. multiply(a,b) and transform compose(a,b) apply b first. Euler angles use intrinsic ZYX, with the Python arguments and returned tuple ordered (roll,pitch,yaw). The source gimbal-lock convention chooses roll zero.

The quaternion constructor checks finite components. Normalization and inverse reject a zero quaternion. SO(3) construction normalizes a nonzero quaternion. Quaternion interpolation chooses the original shortest sign-equivalent arc; nlerp, slerp, squad and dual-quaternion interpolation retain their source parameter bounds and normalization behavior. SO(3) logarithms use the principal angle in [0,pi]. SE(3) twists are a tuple (omega,v) of two three-vectors. The source left-Jacobian formulas and their series near identity are unchanged. Rigid dual-quaternion interpolation remains ScLERP through SE(3), including its pure-translation limit.

SO3, SE3 and rotation.DualQuaternion retain the source normalized and rigid constraints. They do not represent arbitrary scale or shear. from_matrix and from_homogeneous keep the original shape, orthogonality, handedness and bottom row checks. No adapter sanitizes nonfinite data or substitutes a transform.

Ownership and C interface

Use context managers or close() for native objects. Every returned child owns its value independently of its parent. Equality uses the actual Haskell Eq instance, so a sign-equivalent rotation does not automatically imply object equality. Independent calls may share immutable objects while holding an owned reference on each participating thread.

hmath_rotations.h declares the C interface. Arguments and outputs use shared hmath_value owners. Scalar arguments must be common Double scalar values; vector arguments are lists of Double scalar values. A twist is a tuple of two such lists. Matrix arguments are shared Dense Matrix Double values. Opaque kinds are 72 Quaternion, 73 SO3, 74 SE3 and 75 Rotation.DualQuaternion. These tags are distinct from the generic Numeric quaternion types.

Each input is borrowed throughout its synchronous call. Success transfers one owned output reference; failure leaves the output pointer untouched. Release references with hmath_value_release. A live value keeps the Haskell runtime alive and final shutdown reports BUSY. The original Left MathError becomes status HMATH_MATH_ERROR, with complete constructor and payload available through hmath_last_math_error. Cancellation is checked before a call enters Haskell.

Functions

The table below lists every public function, its arguments and result shape. Names use Python snake case; the original numerical function is unchanged.

Python function Argument types, in order Result Original function
quaternion.quaternion(w, x, y, z) float, float, float, float Quaternion HMath.Quaternion.quaternion
quaternion.components(value) Quaternion list[float] HMath.Quaternion.components
quaternion.norm(value) Quaternion float HMath.Quaternion.norm
quaternion.normalize(value) Quaternion Quaternion HMath.Quaternion.normalize
quaternion.inverse(value) Quaternion Quaternion HMath.Quaternion.inverse
quaternion.conjugate(value) Quaternion Quaternion HMath.Quaternion.conjugate
quaternion.multiply(a, b) Quaternion, Quaternion Quaternion HMath.Quaternion.multiply
quaternion.add(a, b) Quaternion, Quaternion Quaternion HMath.Quaternion.add
quaternion.scale(factor, value) float, Quaternion Quaternion HMath.Quaternion.scale
quaternion.rotate_vector(value, vector) Quaternion, list[float] list[float] HMath.Quaternion.rotateVector
quaternion.axis_angle(axis, angle) list[float], float Quaternion HMath.Quaternion.axisAngle
quaternion.to_axis_angle(value) Quaternion (list[float], float) HMath.Quaternion.toAxisAngle
quaternion.from_euler(roll, pitch, yaw) float, float, float Quaternion HMath.Quaternion.fromEuler
quaternion.to_euler(value) Quaternion (float, float, float) HMath.Quaternion.toEuler
quaternion.to_matrix(value) Quaternion Matrix Double HMath.Quaternion.toMatrix
quaternion.from_matrix(matrix) Matrix Double Quaternion HMath.Quaternion.fromMatrix
quaternion.nlerp(fraction, a, b) float, Quaternion, Quaternion Quaternion HMath.Quaternion.nlerp
quaternion.slerp(fraction, a, b) float, Quaternion, Quaternion Quaternion HMath.Quaternion.slerp
quaternion.squad(fraction, q0, q1, q2, q3) float, Quaternion, Quaternion, Quaternion, Quaternion Quaternion HMath.Quaternion.squad
quaternion.exponential(value) Quaternion Quaternion HMath.Quaternion.exponential
quaternion.logarithm(value) Quaternion Quaternion HMath.Quaternion.logarithm
quaternion.swing_twist(axis, value) list[float], Quaternion (Quaternion, Quaternion) HMath.Quaternion.swingTwist
rotation.so3(value) Quaternion SO3 HMath.Rotation.so3
rotation.rotation_quaternion(value) SO3 Quaternion HMath.Rotation.rotationQuaternion
rotation.identity_rotation() SO3 HMath.Rotation.identityRotation
rotation.compose_rotation(a, b) SO3, SO3 SO3 HMath.Rotation.composeRotation
rotation.inverse_rotation(value) SO3 SO3 HMath.Rotation.inverseRotation
rotation.rotate(value, vector) SO3, list[float] list[float] HMath.Rotation.rotate
rotation.exp_so3(omega) list[float] SO3 HMath.Rotation.expSO3
rotation.log_so3(value) SO3 list[float] HMath.Rotation.logSO3
rotation.se3(rotation, translation) SO3, list[float] SE3 HMath.Rotation.se3
rotation.rotation_part(value) SE3 SO3 HMath.Rotation.rotationPart
rotation.translation_part(value) SE3 list[float] HMath.Rotation.translationPart
rotation.identity_transform() SE3 HMath.Rotation.identityTransform
rotation.compose(a, b) SE3, SE3 SE3 HMath.Rotation.compose
rotation.inverse(value) SE3 SE3 HMath.Rotation.inverse
rotation.transform_point(value, point) SE3, list[float] list[float] HMath.Rotation.transformPoint
rotation.exp_se3(twist) (list[float], list[float]) SE3 HMath.Rotation.expSE3
rotation.log_se3(value) SE3 (list[float], list[float]) HMath.Rotation.logSE3
rotation.to_homogeneous(value) SE3 Matrix Double HMath.Rotation.toHomogeneous
rotation.from_homogeneous(matrix) Matrix Double SE3 HMath.Rotation.fromHomogeneous
rotation.dual_quaternion(real, dual) Quaternion, Quaternion DualQuaternion HMath.Rotation.dualQuaternion
rotation.dual_parts(value) DualQuaternion (Quaternion, Quaternion) HMath.Rotation.dualParts
rotation.to_dual_quaternion(value) SE3 DualQuaternion HMath.Rotation.toDualQuaternion
rotation.from_dual_quaternion(value) DualQuaternion SE3 HMath.Rotation.fromDualQuaternion
rotation.multiply_dual(a, b) DualQuaternion, DualQuaternion DualQuaternion HMath.Rotation.multiplyDual
rotation.inverse_dual(value) DualQuaternion DualQuaternion HMath.Rotation.inverseDual
rotation.interpolate_dual(fraction, a, b) float, DualQuaternion, DualQuaternion DualQuaternion HMath.Rotation.interpolateDual