FastQuat 0.5.2__tar.gz → 1.0b2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {fastquat-0.5.2 → fastquat-1.0b2}/.github/workflows/ci.yml +2 -2
  2. {fastquat-0.5.2 → fastquat-1.0b2}/.pre-commit-config.yaml +7 -0
  3. {fastquat-0.5.2 → fastquat-1.0b2}/.readthedocs.yaml +0 -6
  4. {fastquat-0.5.2 → fastquat-1.0b2}/PKG-INFO +25 -9
  5. {fastquat-0.5.2 → fastquat-1.0b2}/README.md +21 -6
  6. fastquat-1.0b2/docs/README.md +27 -0
  7. {fastquat-0.5.2 → fastquat-1.0b2}/docs/source/api/quaternion.md +1 -1
  8. {fastquat-0.5.2 → fastquat-1.0b2}/docs/source/conf.py +3 -0
  9. {fastquat-0.5.2 → fastquat-1.0b2}/docs/source/development.md +40 -18
  10. {fastquat-0.5.2 → fastquat-1.0b2}/docs/source/index.md +23 -26
  11. fastquat-1.0b2/docs/source/user-guide/getting-started.ipynb +293 -0
  12. {fastquat-0.5.2/docs/source → fastquat-1.0b2/docs/source/user-guide}/installation.md +13 -19
  13. fastquat-0.5.2/docs/source/examples/1-spherical-cap.ipynb → fastquat-1.0b2/docs/source/user-guide/tutorial-rotations.ipynb +21 -22
  14. fastquat-0.5.2/docs/source/examples/2-slerp-animation.ipynb → fastquat-1.0b2/docs/source/user-guide/tutorial-slerp.ipynb +5 -6
  15. fastquat-1.0b2/pyproject.toml +87 -0
  16. fastquat-1.0b2/src/fastquat/__init__.py +6 -0
  17. {fastquat-0.5.2 → fastquat-1.0b2}/src/fastquat/quaternion.py +150 -90
  18. fastquat-1.0b2/tests/conftest.py +13 -0
  19. fastquat-1.0b2/tests/test_base.py +418 -0
  20. fastquat-1.0b2/tests/test_indexing.py +208 -0
  21. fastquat-1.0b2/tests/test_math.py +591 -0
  22. fastquat-1.0b2/tests/test_pow.py +388 -0
  23. {fastquat-0.5.2 → fastquat-1.0b2}/tests/test_rotation.py +179 -272
  24. fastquat-1.0b2/tests/test_tensor.py +269 -0
  25. fastquat-1.0b2/uv.lock +3870 -0
  26. fastquat-0.5.2/docs/README.md +0 -96
  27. fastquat-0.5.2/docs/source/api/index.md +0 -9
  28. fastquat-0.5.2/docs/source/examples/index.md +0 -31
  29. fastquat-0.5.2/docs/source/quickstart.md +0 -164
  30. fastquat-0.5.2/pyproject.toml +0 -76
  31. fastquat-0.5.2/src/fastquat/__init__.py +0 -3
  32. fastquat-0.5.2/tests/test_base.py +0 -480
  33. fastquat-0.5.2/tests/test_math.py +0 -762
  34. fastquat-0.5.2/tests/test_pow.py +0 -496
  35. fastquat-0.5.2/tests/test_tensor.py +0 -426
  36. fastquat-0.5.2/uv.lock +0 -3048
  37. {fastquat-0.5.2 → fastquat-1.0b2}/.github/workflows/release.yml +0 -0
  38. {fastquat-0.5.2 → fastquat-1.0b2}/.gitignore +0 -0
  39. {fastquat-0.5.2 → fastquat-1.0b2}/docs/.gitignore +0 -0
  40. {fastquat-0.5.2 → fastquat-1.0b2}/docs/Makefile +0 -0
@@ -35,7 +35,7 @@ jobs:
35
35
  runs-on: ubuntu-latest
36
36
  strategy:
37
37
  matrix:
38
- python-version: ['3.10', '3.11', '3.12', '3.13']
38
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
39
39
 
40
40
  steps:
41
41
  - name: Checkout code
@@ -58,7 +58,7 @@ jobs:
58
58
 
59
59
  - name: Install project's wheel and dependencies
60
60
  run: |
61
- uv sync --group dev --no-install-project
61
+ uv sync --locked --no-install-project
62
62
  uv pip install dist/fastquat-*.whl
63
63
 
64
64
  - name: Run tests
@@ -30,6 +30,13 @@ repos:
30
30
  - id: end-of-file-fixer
31
31
  - id: check-merge-conflict
32
32
 
33
+ - repo: https://github.com/kynan/nbstripout
34
+ rev: 0.6.1
35
+ hooks:
36
+ - id: nbstripout
37
+ name: notebook stripping
38
+ args: [--extra-keys=metadata.language_info.version]
39
+
33
40
  - repo: https://github.com/pre-commit/mirrors-mypy
34
41
  rev: 'v1.19.0'
35
42
  hooks:
@@ -1,10 +1,8 @@
1
1
  # Read the Docs configuration file
2
2
  # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3
3
 
4
- # Required
5
4
  version: 2
6
5
 
7
- # Set the OS, Python version, and other tools you might need
8
6
  build:
9
7
  os: ubuntu-24.04
10
8
  tools:
@@ -20,10 +18,6 @@ sphinx:
20
18
  configuration: docs/source/conf.py
21
19
  fail_on_warning: false
22
20
 
23
- # Optionally build your docs in additional formats such as PDF and ePub
24
- # formats:
25
- # - pdf
26
-
27
21
  # Set the version of Python and other tools you might need
28
22
  submodules:
29
23
  include: all
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: FastQuat
3
- Version: 0.5.2
3
+ Version: 1.0b2
4
4
  Summary: High-performance quaternions with JAX support
5
5
  Project-URL: homepage, https://fastquat.readthedocs.io
6
6
  Project-URL: repository, https://github.com/CMBSciPol/fastquat
@@ -12,12 +12,13 @@ Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
15
16
  Classifier: Topic :: Scientific/Engineering :: Astronomy
16
17
  Classifier: Topic :: Scientific/Engineering :: Mathematics
17
18
  Classifier: Topic :: Scientific/Engineering :: Physics
18
19
  Requires-Python: >=3.10
19
20
  Requires-Dist: jax>=0.4.0
20
- Requires-Dist: jaxlib>=0.4.0
21
+ Requires-Dist: typing-extensions; python_version < '3.11'
21
22
  Description-Content-Type: text/markdown
22
23
 
23
24
  # FastQuat - High-Performance Quaternions with JAX
@@ -52,13 +53,28 @@ import jax.numpy as jnp
52
53
  from fastquat import Quaternion
53
54
 
54
55
  # Create quaternions
55
- q1 = Quaternion.ones() # Identity quaternion
56
+ q1 = Quaternion(1) # Identity quaternion
56
57
  q2 = Quaternion(0.7071, 0.7071, 0.0, 0.0) # 90° rotation around x-axis
58
+ q = Quaternion(1.0, 0.1, 0.2, 0.3)
59
+ p = 2
57
60
 
58
- # Quaternion operations
59
- q3 = q1 * q2 # Multiplication
60
- q_inv = 1 / q1 # Inverse, or q1 ** -1
61
- q_norm = q1.normalize() # Normalization
61
+ # Arithmetic
62
+ q_sum = q1 + q2
63
+ q_diff = q1 - q2
64
+ q_product = q1 * q2
65
+ q_power = q**p
66
+
67
+ # Normalization
68
+ norm = abs(q) # Quaternion norm
69
+ q_unit = q.normalize() # Unit quaternion
70
+
71
+ # Conjugation and inverse
72
+ q_conj = q.conj() # Conjugate
73
+ q_inv = 1 / q # Inverse, or q ** -1
74
+
75
+ # Other operations
76
+ q_log = q.log()
77
+ q_exp = q.exp()
62
78
 
63
79
  # Rotate vectors
64
80
  vector = jnp.array([1.0, 0.0, 0.0])
@@ -120,7 +136,7 @@ rotated_batch = batch_rotate(q_batch, vectors)
120
136
  ### SLERP
121
137
  ```python
122
138
  # Smooth rotation interpolation
123
- q_start = Quaternion.ones()
139
+ q_start = Quaternion(1.0)
124
140
  q_end = Quaternion.from_rotation_matrix(rotation_matrix)
125
141
 
126
142
  # Generate smooth interpolation
@@ -30,13 +30,28 @@ import jax.numpy as jnp
30
30
  from fastquat import Quaternion
31
31
 
32
32
  # Create quaternions
33
- q1 = Quaternion.ones() # Identity quaternion
33
+ q1 = Quaternion(1) # Identity quaternion
34
34
  q2 = Quaternion(0.7071, 0.7071, 0.0, 0.0) # 90° rotation around x-axis
35
+ q = Quaternion(1.0, 0.1, 0.2, 0.3)
36
+ p = 2
35
37
 
36
- # Quaternion operations
37
- q3 = q1 * q2 # Multiplication
38
- q_inv = 1 / q1 # Inverse, or q1 ** -1
39
- q_norm = q1.normalize() # Normalization
38
+ # Arithmetic
39
+ q_sum = q1 + q2
40
+ q_diff = q1 - q2
41
+ q_product = q1 * q2
42
+ q_power = q**p
43
+
44
+ # Normalization
45
+ norm = abs(q) # Quaternion norm
46
+ q_unit = q.normalize() # Unit quaternion
47
+
48
+ # Conjugation and inverse
49
+ q_conj = q.conj() # Conjugate
50
+ q_inv = 1 / q # Inverse, or q ** -1
51
+
52
+ # Other operations
53
+ q_log = q.log()
54
+ q_exp = q.exp()
40
55
 
41
56
  # Rotate vectors
42
57
  vector = jnp.array([1.0, 0.0, 0.0])
@@ -98,7 +113,7 @@ rotated_batch = batch_rotate(q_batch, vectors)
98
113
  ### SLERP
99
114
  ```python
100
115
  # Smooth rotation interpolation
101
- q_start = Quaternion.ones()
116
+ q_start = Quaternion(1.0)
102
117
  q_end = Quaternion.from_rotation_matrix(rotation_matrix)
103
118
 
104
119
  # Generate smooth interpolation
@@ -0,0 +1,27 @@
1
+ # Documentation Build Instructions
2
+
3
+ This documentation uses **PEP 735 dependency groups** instead of separate requirements files to avoid duplication.
4
+
5
+
6
+ ## Building Documentation Locally
7
+
8
+ The dependency group `docs` is included in the group `dev` which is installed by default when using ̀uv` (recommended).
9
+ No extra step other than setting up and activating the virtual environment is required:
10
+ ```bash
11
+ # From the docs/ directory
12
+ uv sync --locked --group cuda12
13
+ source .venv/bin/activate
14
+ ```
15
+
16
+ If you're not using uv, you can install the docs dependencies manually:
17
+ ```bash
18
+ # Install the project with docs dependencies (pip >= 25.1)
19
+ pip install --upgrade pip
20
+ pip install -e . --group dev
21
+ ```
22
+
23
+ Then build the docs
24
+ ```bash
25
+ cd docs
26
+ make html
27
+ ```
@@ -39,7 +39,7 @@ compilation, automatic differentiation, and vectorization.
39
39
  ## Core Operations
40
40
 
41
41
  ```{eval-rst}
42
- .. automethod:: fastquat.Quaternion.norm
42
+ .. automethod:: fastquat.Quaternion.__abs__
43
43
  .. automethod:: fastquat.Quaternion.normalize
44
44
  .. automethod:: fastquat.Quaternion.conjugate
45
45
  .. automethod:: fastquat.Quaternion.conj
@@ -4,6 +4,9 @@
4
4
  import os
5
5
  import sys
6
6
 
7
+ # Force JAX to use CPU only (must be set before JAX is imported)
8
+ os.environ['JAX_PLATFORMS'] = 'cpu'
9
+
7
10
  # Add the source path
8
11
  sys.path.insert(0, os.path.abspath('../../src'))
9
12
 
@@ -105,36 +105,58 @@ FastQuat is designed for high performance. When contributing:
105
105
  Here's how to add a new method to the Quaternion class:
106
106
 
107
107
  ```python
108
- def new_method(self, parameter: Array) -> Quaternion:
109
- """Brief description of what the method does.
110
-
111
- Args:
112
- parameter: Description of the parameter
113
-
114
- Returns:
115
- Description of the return value
116
- """
117
- # Implementation using JAX operations
118
- result = jnp.some_operation(self.wxyz, parameter)
119
- return Quaternion.from_array(result)
108
+ from typing import Self
109
+
110
+ import jax.numpy as jnp
111
+ from jax.typing import ArrayLike
112
+
113
+
114
+ class Quaternion:
115
+ ...
116
+ def new_method(self, parameter: ArrayLike) -> Self:
117
+ """Brief description of what the method does.
118
+
119
+ Args:
120
+ parameter: Description of the parameter
121
+
122
+ Returns:
123
+ Description of the return value
124
+ """
125
+ # Implementation using JAX operations
126
+ parameter = jnp.asarray(parameter)
127
+ result = jnp.some_operation(self.wxyz, parameter)
128
+ return Quaternion.from_array(result)
120
129
  ```
121
130
 
122
131
  Then add tests:
123
132
 
124
133
  ```python
134
+ import jax
135
+ import jax.numpy as jnp
136
+ import pytest
137
+
138
+ from fastquat import Quaternion
139
+
140
+
141
+ @pytest.mark.parametrize(
142
+ 'parameter, expected_values',
143
+ [
144
+ (..., ...),
145
+ ]
146
+ )
125
147
  @pytest.mark.parametrize('do_jit', [False, True])
126
- def test_new_method(do_jit):
148
+ def test_new_method(parameter, expected_values, do_jit):
127
149
  """Test the new method."""
128
- def test_fn(q, param):
129
- return q.new_method(param)
150
+ def test_fn(q_, parameter_):
151
+ return q_.new_method(parameter_)
130
152
 
131
153
  if do_jit:
132
- test_fn = jax.jit(test_fn)
154
+ test_fn = jax.jit(test_fn, static_argnums=1)
133
155
 
134
156
  # Test implementation
135
- q = Quaternion.ones()
157
+ q = Quaternion(1.0)
136
158
  result = test_fn(q, parameter)
137
- assert jnp.allclose(result.wxyz, expected_result)
159
+ assert jnp.allclose(result.wxyz, expected_values)
138
160
  ```
139
161
 
140
162
  ## Documentation
@@ -19,55 +19,52 @@ FastQuat provides optimized quaternion operations with full JAX compatibility, f
19
19
  ## Quick Start
20
20
 
21
21
  ```python
22
- import jax.numpy as jnp
23
22
  from fastquat import Quaternion
24
23
 
25
24
  # Create quaternions
26
- q1 = Quaternion.ones() # Identity quaternion
25
+ q1 = Quaternion(1.0) # Identity quaternion
27
26
  q2 = Quaternion(0.7071, 0.7071, 0.0, 0.0) # 90° rotation around x-axis
28
-
29
- # Quaternion operations
30
- q3 = q1 * q2 # Multiplication
31
- q_inv = 1 / q1 # Inverse
32
- q_norm = q1.normalize() # Normalization
33
-
34
- # Rotate vectors
35
- vector = jnp.array([1.0, 0.0, 0.0])
36
- rotated = q2.rotate_vector(vector)
37
-
38
- # Spherical interpolation (SLERP)
39
- interpolated = q1.slerp(q2, t=0.5) # Halfway between q1 and q2
40
27
  ```
41
28
 
42
- ## Contents
29
+ ## Quaternion Operations
30
+
31
+ | Operation | Syntax | Description |
32
+ |-----------|--------|-------------|
33
+ | Addition | `q1 + q2` | Component-wise addition |
34
+ | Subtraction | `q1 - q2` | Component-wise subtraction |
35
+ | Multiplication | `q1 * q2` | Hamilton product |
36
+ | Exponentiation | `q ** p` | Quaternion power |
37
+ | Inverse | `1 / q` | Multiplicative inverse |
38
+ | Norm | `abs(q)` | Quaternion magnitude |
39
+ | Normalization | `q.normalize()` | Unit quaternion |
40
+ | Conjugate | `q.conj()` | Quaternion conjugate |
41
+ | Rotation | `q.rotate_vector(v)` | Rotate 3D vector |
42
+ | SLERP | `q1.slerp(q2, t)` | Spherical interpolation |
43
+ | Log | `q.log()` | Quaternion logarithm |
44
+ | Exp | `q.exp()` | Quaternion exponential |
43
45
 
44
46
  ```{toctree}
45
47
  :maxdepth: 2
46
48
  :caption: User Guide
47
49
 
48
- installation.md
49
- quickstart.md
50
- ```
51
-
52
- ```{toctree}
53
- :maxdepth: 2
54
- :caption: Examples
55
-
56
- examples/index.md
50
+ user-guide/installation
51
+ user-guide/getting-started
52
+ user-guide/tutorial-rotations
53
+ user-guide/tutorial-slerp
57
54
  ```
58
55
 
59
56
  ```{toctree}
60
57
  :maxdepth: 2
61
58
  :caption: API Reference
62
59
 
63
- api/index
60
+ api/quaternion
64
61
  ```
65
62
 
66
63
  ```{toctree}
67
64
  :maxdepth: 1
68
65
  :caption: Development
69
66
 
70
- development.md
67
+ development
71
68
  ```
72
69
 
73
70
  ## Indices and tables
@@ -0,0 +1,293 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Getting Started\n",
8
+ "\n",
9
+ "This guide will get you started with FastQuat's core functionality."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "markdown",
14
+ "metadata": {},
15
+ "source": [
16
+ "## Creating Quaternions\n",
17
+ "\n",
18
+ "There are several ways to create quaternions:"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": null,
24
+ "metadata": {},
25
+ "outputs": [],
26
+ "source": [
27
+ "import jax\n",
28
+ "import jax.numpy as jnp\n",
29
+ "import jax.random as jr\n",
30
+ "\n",
31
+ "from fastquat import Quaternion\n",
32
+ "\n",
33
+ "# From components (w, x, y, z)\n",
34
+ "q1 = Quaternion(0.0, -1.0, -1.0, -1.0)\n",
35
+ "\n",
36
+ "identity = Quaternion(1.0)\n",
37
+ "i = Quaternion(x=1)\n",
38
+ "j = Quaternion(y=1)\n",
39
+ "k = Quaternion(z=1)\n",
40
+ "\n",
41
+ "# Convenience constructors\n",
42
+ "q_zeros = Quaternion.zeros((2, 3))\n",
43
+ "q_ones = Quaternion.ones((2, 3))\n",
44
+ "q_twos = Quaternion.full((2, 3), 2)\n",
45
+ "\n",
46
+ "# From arrays\n",
47
+ "array = jnp.array([1.0, 0.0, 0.0, 0.0])\n",
48
+ "q2 = Quaternion.from_array(array)\n",
49
+ "\n",
50
+ "# Random normalized quaternions\n",
51
+ "key = jr.key(42)\n",
52
+ "q_random = Quaternion.random(key)"
53
+ ]
54
+ },
55
+ {
56
+ "cell_type": "markdown",
57
+ "metadata": {},
58
+ "source": [
59
+ "## Basic Operations\n",
60
+ "\n",
61
+ "Quaternions support standard mathematical operations:"
62
+ ]
63
+ },
64
+ {
65
+ "cell_type": "code",
66
+ "execution_count": null,
67
+ "metadata": {},
68
+ "outputs": [],
69
+ "source": [
70
+ "q = Quaternion(1.0, 0.1, 0.2, 0.3)\n",
71
+ "p = 2\n",
72
+ "\n",
73
+ "# Arithmetic\n",
74
+ "q_sum = q1 + q2\n",
75
+ "q_diff = q1 - q2\n",
76
+ "q_product = q1 * q2\n",
77
+ "q_power = q**p\n",
78
+ "\n",
79
+ "# Normalization\n",
80
+ "norm = abs(q) # Quaternion norm\n",
81
+ "q_unit = q.normalize() # Unit quaternion\n",
82
+ "\n",
83
+ "# Conjugation and inverse\n",
84
+ "q_conj = q.conj() # Conjugate\n",
85
+ "q_inv = 1 / q # Inverse, or q ** -1\n",
86
+ "\n",
87
+ "# Other operations\n",
88
+ "q_log = q.log()\n",
89
+ "q_exp = q.exp()"
90
+ ]
91
+ },
92
+ {
93
+ "cell_type": "markdown",
94
+ "metadata": {},
95
+ "source": [
96
+ "## Vector Rotation\n",
97
+ "\n",
98
+ "One of the most common uses of quaternions is rotating 3D vectors:"
99
+ ]
100
+ },
101
+ {
102
+ "cell_type": "code",
103
+ "execution_count": null,
104
+ "metadata": {},
105
+ "outputs": [],
106
+ "source": [
107
+ "# Create a 90° rotation around the z-axis\n",
108
+ "angle = jnp.pi / 2\n",
109
+ "q_rot = Quaternion(jnp.cos(angle / 2), 0.0, 0.0, jnp.sin(angle / 2))\n",
110
+ "\n",
111
+ "# Rotate a vector\n",
112
+ "vector = jnp.array([1.0, 0.0, 0.0]) # Unit vector along x\n",
113
+ "rotated = q_rot.rotate_vector(vector)\n",
114
+ "print(rotated) # Should be approximately [0, 1, 0]"
115
+ ]
116
+ },
117
+ {
118
+ "cell_type": "markdown",
119
+ "metadata": {},
120
+ "source": [
121
+ "## Conversion to/from Rotation Matrices\n",
122
+ "\n",
123
+ "FastQuat can convert between quaternions and rotation matrices:"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "execution_count": null,
129
+ "metadata": {},
130
+ "outputs": [],
131
+ "source": [
132
+ "# Quaternion to rotation matrix\n",
133
+ "R = q_rot.to_rotation_matrix()\n",
134
+ "print(R.shape) # (3, 3)\n",
135
+ "\n",
136
+ "# Rotation matrix to quaternion\n",
137
+ "q_from_matrix = Quaternion.from_rotation_matrix(R)"
138
+ ]
139
+ },
140
+ {
141
+ "cell_type": "markdown",
142
+ "metadata": {},
143
+ "source": [
144
+ "## Spherical Linear Interpolation (SLERP)\n",
145
+ "\n",
146
+ "SLERP provides smooth interpolation between quaternions:"
147
+ ]
148
+ },
149
+ {
150
+ "cell_type": "code",
151
+ "execution_count": null,
152
+ "metadata": {},
153
+ "outputs": [],
154
+ "source": [
155
+ "# Two different orientations\n",
156
+ "q_start = Quaternion(1.0) # Identity\n",
157
+ "q_end = Quaternion(0.7071, 0.7071, 0.0, 0.0) # 90° around x\n",
158
+ "\n",
159
+ "# Interpolate between them\n",
160
+ "t = 0.5 # Halfway point\n",
161
+ "q_mid = q_start.slerp(q_end, t)\n",
162
+ "\n",
163
+ "# Batch interpolation\n",
164
+ "t_values = jnp.linspace(0, 1, 10)\n",
165
+ "interpolated = q_start.slerp(q_end, t_values)\n",
166
+ "print(interpolated.shape) # (10,) - 10 quaternions"
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "markdown",
171
+ "metadata": {},
172
+ "source": [
173
+ "## JAX Integration\n",
174
+ "\n",
175
+ "FastQuat is fully compatible with JAX transformations:"
176
+ ]
177
+ },
178
+ {
179
+ "cell_type": "code",
180
+ "execution_count": null,
181
+ "metadata": {},
182
+ "outputs": [],
183
+ "source": [
184
+ "# JIT compilation\n",
185
+ "@jax.jit\n",
186
+ "def rotate_and_normalize(q, v):\n",
187
+ " rotated = q.rotate_vector(v)\n",
188
+ " return rotated / jnp.linalg.norm(rotated)\n",
189
+ "\n",
190
+ "\n",
191
+ "# Vectorization\n",
192
+ "batch_rotate = jax.vmap(lambda q, v: q.rotate_vector(v))\n",
193
+ "\n",
194
+ "# Create batches\n",
195
+ "q_batch = Quaternion.random(key, shape=(100,))\n",
196
+ "v_batch = jax.random.normal(key, (100, 3))\n",
197
+ "\n",
198
+ "# Process entire batch at once\n",
199
+ "rotated_batch = batch_rotate(q_batch, v_batch)\n",
200
+ "\n",
201
+ "\n",
202
+ "# Automatic differentiation\n",
203
+ "def loss_function(q_params):\n",
204
+ " q = Quaternion.from_array(q_params)\n",
205
+ " rotated = q.rotate_vector(vector)\n",
206
+ " return jnp.sum(rotated**2)\n",
207
+ "\n",
208
+ "\n",
209
+ "grad_fn = jax.grad(loss_function)\n",
210
+ "gradients = grad_fn(jnp.array([1.0, 0.1, 0.1, 0.1]))"
211
+ ]
212
+ },
213
+ {
214
+ "cell_type": "markdown",
215
+ "metadata": {},
216
+ "source": [
217
+ "## Performance Tips\n",
218
+ "\n",
219
+ "1. **Use JIT compilation** for repeated operations:"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": null,
225
+ "metadata": {},
226
+ "outputs": [],
227
+ "source": [
228
+ "@jax.jit\n",
229
+ "def batch_operation(quaternions):\n",
230
+ " return quaternions.normalize()"
231
+ ]
232
+ },
233
+ {
234
+ "cell_type": "markdown",
235
+ "metadata": {},
236
+ "source": [
237
+ "2. **Prefer batch operations** over loops:"
238
+ ]
239
+ },
240
+ {
241
+ "cell_type": "code",
242
+ "execution_count": null,
243
+ "metadata": {},
244
+ "outputs": [],
245
+ "source": [
246
+ "# Good: vectorized operation\n",
247
+ "results = q_batch.rotate_vector(v_batch)\n",
248
+ "\n",
249
+ "# Avoid: Python loops\n",
250
+ "# results = [q.rotate_vector(v) for q, v in zip(q_batch, v_batch)]"
251
+ ]
252
+ },
253
+ {
254
+ "cell_type": "markdown",
255
+ "metadata": {},
256
+ "source": [
257
+ "3. **Normalize quaternions** when needed for rotations:"
258
+ ]
259
+ },
260
+ {
261
+ "cell_type": "code",
262
+ "execution_count": null,
263
+ "metadata": {},
264
+ "outputs": [],
265
+ "source": [
266
+ "q_unit = q.normalize() # Ensure unit quaternion for rotations"
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "markdown",
271
+ "metadata": {},
272
+ "source": [
273
+ "## Next Steps\n",
274
+ "\n",
275
+ "* Explore the tutorials for detailed use cases\n",
276
+ "* Check the [API reference](../api/quaternion.md) for complete API documentation\n",
277
+ "* See advanced interpolation techniques with SLERP"
278
+ ]
279
+ }
280
+ ],
281
+ "metadata": {
282
+ "kernelspec": {
283
+ "display_name": "Python 3",
284
+ "language": "python",
285
+ "name": "python3"
286
+ },
287
+ "language_info": {
288
+ "name": "python"
289
+ }
290
+ },
291
+ "nbformat": 4,
292
+ "nbformat_minor": 4
293
+ }