{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Getting Started\n", "\n", "This guide will get you started with FastQuat's core functionality." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating Quaternions\n", "\n", "There are several ways to create quaternions:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import jax\n", "import jax.numpy as jnp\n", "import jax.random as jr\n", "\n", "from fastquat import Quaternion\n", "\n", "# From components (w, x, y, z)\n", "q1 = Quaternion(0.0, -1.0, -1.0, -1.0)\n", "\n", "identity = Quaternion(1.0)\n", "i = Quaternion(x=1)\n", "j = Quaternion(y=1)\n", "k = Quaternion(z=1)\n", "\n", "# Convenience constructors\n", "q_zeros = Quaternion.zeros((2, 3))\n", "q_ones = Quaternion.ones((2, 3))\n", "q_twos = Quaternion.full((2, 3), 2)\n", "\n", "# From arrays\n", "array = jnp.array([1.0, 0.0, 0.0, 0.0])\n", "q2 = Quaternion.from_array(array)\n", "\n", "# Random normalized quaternions\n", "key = jr.key(42)\n", "q_random = Quaternion.random(key)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic Operations\n", "\n", "Quaternions support standard mathematical operations:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "q = Quaternion(1.0, 0.1, 0.2, 0.3)\n", "p = 2\n", "\n", "# Arithmetic\n", "q_sum = q1 + q2\n", "q_diff = q1 - q2\n", "q_product = q1 * q2\n", "q_power = q**p\n", "\n", "# Normalization\n", "norm = abs(q) # Quaternion norm\n", "q_unit = q.normalize() # Unit quaternion\n", "\n", "# Conjugation and inverse\n", "q_conj = q.conj() # Conjugate\n", "q_inv = 1 / q # Inverse, or q ** -1\n", "\n", "# Other operations\n", "q_log = q.log()\n", "q_exp = q.exp()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vector Rotation\n", "\n", "One of the most common uses of quaternions is rotating 3D vectors:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a 90° rotation around the z-axis\n", "angle = jnp.pi / 2\n", "q_rot = Quaternion(jnp.cos(angle / 2), 0.0, 0.0, jnp.sin(angle / 2))\n", "\n", "# Rotate a vector\n", "vector = jnp.array([1.0, 0.0, 0.0]) # Unit vector along x\n", "rotated = q_rot.rotate_vector(vector)\n", "print(rotated) # Should be approximately [0, 1, 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conversion to/from Rotation Matrices\n", "\n", "FastQuat can convert between quaternions and rotation matrices:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Quaternion to rotation matrix\n", "R = q_rot.to_rotation_matrix()\n", "print(R.shape) # (3, 3)\n", "\n", "# Rotation matrix to quaternion\n", "q_from_matrix = Quaternion.from_rotation_matrix(R)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Spherical Linear Interpolation (SLERP)\n", "\n", "SLERP provides smooth interpolation between quaternions:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Two different orientations\n", "q_start = Quaternion(1.0) # Identity\n", "q_end = Quaternion(0.7071, 0.7071, 0.0, 0.0) # 90° around x\n", "\n", "# Interpolate between them\n", "t = 0.5 # Halfway point\n", "q_mid = q_start.slerp(q_end, t)\n", "\n", "# Batch interpolation\n", "t_values = jnp.linspace(0, 1, 10)\n", "interpolated = q_start.slerp(q_end, t_values)\n", "print(interpolated.shape) # (10,) - 10 quaternions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## JAX Integration\n", "\n", "FastQuat is fully compatible with JAX transformations:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# JIT compilation\n", "@jax.jit\n", "def rotate_and_normalize(q, v):\n", " rotated = q.rotate_vector(v)\n", " return rotated / jnp.linalg.norm(rotated)\n", "\n", "\n", "# Vectorization\n", "batch_rotate = jax.vmap(lambda q, v: q.rotate_vector(v))\n", "\n", "# Create batches\n", "q_batch = Quaternion.random(key, shape=(100,))\n", "v_batch = jax.random.normal(key, (100, 3))\n", "\n", "# Process entire batch at once\n", "rotated_batch = batch_rotate(q_batch, v_batch)\n", "\n", "\n", "# Automatic differentiation\n", "def loss_function(q_params):\n", " q = Quaternion.from_array(q_params)\n", " rotated = q.rotate_vector(vector)\n", " return jnp.sum(rotated**2)\n", "\n", "\n", "grad_fn = jax.grad(loss_function)\n", "gradients = grad_fn(jnp.array([1.0, 0.1, 0.1, 0.1]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Performance Tips\n", "\n", "1. **Use JIT compilation** for repeated operations:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@jax.jit\n", "def batch_operation(quaternions):\n", " return quaternions.normalize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. **Prefer batch operations** over loops:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Good: vectorized operation\n", "results = q_batch.rotate_vector(v_batch)\n", "\n", "# Avoid: Python loops\n", "# results = [q.rotate_vector(v) for q, v in zip(q_batch, v_batch)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "3. **Normalize quaternions** when needed for rotations:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "q_unit = q.normalize() # Ensure unit quaternion for rotations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Next Steps\n", "\n", "* Explore the tutorials for detailed use cases\n", "* Check the [API reference](../api/quaternion.md) for complete API documentation\n", "* See advanced interpolation techniques with SLERP" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 4 }