0
# Advanced Mathematics
1
2
Advanced mathematical operations including exponential/logarithm functions, Riemannian manifold operations, and distance metrics for quaternions.
3
4
## Capabilities
5
6
### Exponential and Logarithm Operations
7
8
Quaternion exponential and logarithm functions for advanced mathematical computations.
9
10
```python { .api }
11
@classmethod
12
def exp(cls, q):
13
"""
14
Quaternion exponential function.
15
16
Computes exp(q) for any quaternion using the formula:
17
exp(q) = exp(q.scalar) * (cos(|q.vector|) + (q.vector/|q.vector|) * sin(|q.vector|))
18
19
Parameters:
20
q: Quaternion, input quaternion argument
21
22
Returns:
23
Quaternion: exp(q)
24
25
Note:
26
Can compute exponential of any quaternion, not just unit quaternions.
27
For pure imaginary quaternions, reduces to Euler's formula.
28
"""
29
30
@classmethod
31
def log(cls, q):
32
"""
33
Quaternion natural logarithm.
34
35
Computes log(q) using the formula:
36
log(q) = log(|q|) + (q.vector/|q.vector|) * acos(q.scalar/|q|)
37
38
Parameters:
39
q: Quaternion, input quaternion (should be non-zero)
40
41
Returns:
42
Quaternion: log(q) = (log(|q|), v/|v| * acos(w/|q|))
43
For zero quaternion: (-inf, nan*vector)
44
For real quaternions: (log(|q|), [0,0,0])
45
46
Note:
47
Undefined for zero quaternion (returns -inf + nan*i + nan*j + nan*k).
48
For real quaternions, returns real logarithm with zero vector part.
49
"""
50
```
51
52
**Usage Examples:**
53
54
```python
55
from pyquaternion import Quaternion
56
import numpy as np
57
58
# Basic exponential and logarithm
59
q = Quaternion(1, 0.5, 0.3, 0.2)
60
exp_q = Quaternion.exp(q)
61
log_exp_q = Quaternion.log(exp_q)
62
63
print(f"Original: {q}")
64
print(f"exp(q): {exp_q}")
65
print(f"log(exp(q)): {log_exp_q}") # Should approximately equal original
66
67
# Pure imaginary quaternion (like Euler's formula)
68
pure_imag = Quaternion(0, 1, 0, 0) # i
69
exp_i = Quaternion.exp(pure_imag)
70
print(f"exp(i): {exp_i}") # Should be cos(1) + i*sin(1)
71
72
# Real quaternion
73
real_q = Quaternion(2.0) # Pure real
74
exp_real = Quaternion.exp(real_q)
75
log_real = Quaternion.log(real_q)
76
print(f"exp(2): {exp_real}") # Should be (e^2, 0, 0, 0)
77
print(f"log(2): {log_real}") # Should be (ln(2), 0, 0, 0)
78
79
# Zero and problematic cases
80
try:
81
zero_q = Quaternion(0, 0, 0, 0)
82
log_zero = Quaternion.log(zero_q)
83
print(f"log(0): {log_zero}") # (-inf, nan, nan, nan)
84
except:
85
print("Zero quaternion logarithm handling")
86
```
87
88
### Manifold Operations
89
90
Exponential and logarithm maps on the quaternion Riemannian manifold for advanced geometric computations.
91
92
```python { .api }
93
@classmethod
94
def exp_map(cls, q, eta):
95
"""
96
Quaternion exponential map on Riemannian manifold.
97
98
Computes the endpoint of geodesic starting at q in direction eta,
99
with length equal to magnitude of eta.
100
101
Parameters:
102
q: Quaternion, base point of exponential map
103
eta: Quaternion, tangent vector argument (direction and magnitude)
104
105
Returns:
106
Quaternion: Endpoint quaternion p = q * exp(eta)
107
108
Note:
109
Important for integrating orientation variations (angular velocities).
110
Projects quaternion tangent vectors onto the quaternion manifold.
111
"""
112
113
@classmethod
114
def sym_exp_map(cls, q, eta):
115
"""
116
Quaternion symmetrized exponential map.
117
118
Symmetric formulation analogous to exponential maps for
119
symmetric positive definite tensors.
120
121
Parameters:
122
q: Quaternion, base point
123
eta: Quaternion, tangent vector argument
124
125
Returns:
126
Quaternion: p = sqrt(q) * exp(eta) * sqrt(q)
127
"""
128
129
@classmethod
130
def log_map(cls, q, p):
131
"""
132
Quaternion logarithm map on Riemannian manifold.
133
134
Finds tangent vector with length and direction given by
135
the geodesic joining q and p.
136
137
Parameters:
138
q: Quaternion, base point where logarithm is computed
139
p: Quaternion, target point
140
141
Returns:
142
Quaternion: Tangent vector from q to p
143
Formula: log(q^(-1) * p)
144
"""
145
146
@classmethod
147
def sym_log_map(cls, q, p):
148
"""
149
Quaternion symmetrized logarithm map.
150
151
Symmetric formulation for numerically stable gradient descent
152
on the Riemannian quaternion manifold.
153
154
Parameters:
155
q: Quaternion, base point
156
p: Quaternion, target point
157
158
Returns:
159
Quaternion: Symmetrized tangent vector
160
Formula: log(q^(-1/2) * p * q^(-1/2))
161
"""
162
```
163
164
**Usage Examples:**
165
166
```python
167
# Manifold operations for trajectory planning
168
q_start = Quaternion(axis=[0, 0, 1], degrees=0)
169
q_end = Quaternion(axis=[0, 0, 1], degrees=90)
170
171
# Compute tangent vector from start to end
172
tangent_vec = Quaternion.log_map(q_start, q_end)
173
print(f"Tangent vector: {tangent_vec}")
174
175
# Move along geodesic using exponential map
176
fraction = 0.3 # 30% of the way
177
scaled_tangent = Quaternion(tangent_vec.elements * fraction)
178
intermediate = Quaternion.exp_map(q_start, scaled_tangent)
179
print(f"30% along geodesic: {intermediate}")
180
181
# Verify round-trip
182
reconstructed_end = Quaternion.exp_map(q_start, tangent_vec)
183
print(f"Original end: {q_end}")
184
print(f"Reconstructed: {reconstructed_end}")
185
186
# Symmetrized operations (more numerically stable)
187
sym_tangent = Quaternion.sym_log_map(q_start, q_end)
188
sym_intermediate = Quaternion.sym_exp_map(q_start, scaled_tangent)
189
print(f"Symmetric tangent: {sym_tangent}")
190
print(f"Symmetric intermediate: {sym_intermediate}")
191
```
192
193
### Distance Metrics
194
195
Various distance measures between quaternions for similarity analysis and optimization.
196
197
```python { .api }
198
@classmethod
199
def absolute_distance(cls, q0, q1):
200
"""
201
Quaternion absolute distance accounting for sign ambiguity.
202
203
Computes chord distance of shortest path connecting q0 to q1,
204
accounting for the fact that q and -q represent the same rotation.
205
206
Parameters:
207
q0: Quaternion, first quaternion
208
q1: Quaternion, second quaternion
209
210
Returns:
211
float: Positive chord distance, good indicator for rotation similarity
212
Returns min(|q0 - q1|, |q0 + q1|)
213
214
Note:
215
Does not measure distance on hypersphere, but accounts for
216
quaternion double-cover (q ≡ -q for rotations).
217
"""
218
219
@classmethod
220
def distance(cls, q0, q1):
221
"""
222
Intrinsic geodesic distance between quaternions.
223
224
Computes length of geodesic arc connecting q0 to q1 on the
225
quaternion manifold.
226
227
Parameters:
228
q0: Quaternion, first quaternion
229
q1: Quaternion, second quaternion
230
231
Returns:
232
float: Geodesic arc length
233
Formula: |log_map(q0, q1).norm|
234
"""
235
236
@classmethod
237
def sym_distance(cls, q0, q1):
238
"""
239
Symmetrized geodesic distance between quaternions.
240
241
More numerically stable for iterative gradient descent on
242
Riemannian quaternion manifold.
243
244
Parameters:
245
q0: Quaternion, first quaternion
246
q1: Quaternion, second quaternion
247
248
Returns:
249
float: Symmetrized geodesic distance
250
251
Note:
252
Distance between q and -q equals π, making this less useful
253
for rotation similarity when samples span angles > π/2.
254
"""
255
```
256
257
**Usage Examples:**
258
259
```python
260
# Compare different distance metrics
261
q1 = Quaternion(axis=[1, 0, 0], degrees=30)
262
q2 = Quaternion(axis=[1, 0, 0], degrees=60)
263
q3 = Quaternion(axis=[0, 1, 0], degrees=30) # Different axis
264
265
# Compute various distances
266
abs_dist_12 = Quaternion.absolute_distance(q1, q2)
267
abs_dist_13 = Quaternion.absolute_distance(q1, q3)
268
269
geo_dist_12 = Quaternion.distance(q1, q2)
270
geo_dist_13 = Quaternion.distance(q1, q3)
271
272
sym_dist_12 = Quaternion.sym_distance(q1, q2)
273
sym_dist_13 = Quaternion.sym_distance(q1, q3)
274
275
print("Distance comparison:")
276
print(f"q1 to q2 (same axis, 30° apart):")
277
print(f" Absolute: {abs_dist_12:.4f}")
278
print(f" Geodesic: {geo_dist_12:.4f}")
279
print(f" Symmetric: {sym_dist_12:.4f}")
280
281
print(f"q1 to q3 (different axis, same angle):")
282
print(f" Absolute: {abs_dist_13:.4f}")
283
print(f" Geodesic: {geo_dist_13:.4f}")
284
print(f" Symmetric: {sym_dist_13:.4f}")
285
286
# Demonstrate sign ambiguity handling
287
q_pos = Quaternion(1, 0, 0, 0)
288
q_neg = Quaternion(-1, 0, 0, 0) # Same rotation, opposite quaternion
289
290
regular_dist = (q_pos - q_neg).norm # Regular Euclidean distance
291
absolute_dist = Quaternion.absolute_distance(q_pos, q_neg)
292
293
print(f"\nSign ambiguity demonstration:")
294
print(f"q = {q_pos}")
295
print(f"-q = {q_neg}")
296
print(f"Regular Euclidean distance: {regular_dist:.4f}")
297
print(f"Absolute distance: {absolute_dist:.4f}") # Should be ~0
298
```
299
300
### Clustering and Optimization Applications
301
302
```python
303
# Example: Quaternion averaging using distance metrics
304
def quaternion_mean_iterative(quaternions, max_iterations=100, tolerance=1e-6):
305
"""
306
Compute quaternion mean using iterative optimization on manifold.
307
"""
308
# Initialize with first quaternion
309
mean_q = quaternions[0].normalised
310
311
for iteration in range(max_iterations):
312
# Compute tangent vectors to all quaternions
313
tangent_sum = Quaternion(0, 0, 0, 0)
314
315
for q in quaternions:
316
tangent_vec = Quaternion.log_map(mean_q, q)
317
tangent_sum += tangent_vec
318
319
# Average tangent vector
320
avg_tangent = Quaternion(tangent_sum.elements / len(quaternions))
321
322
# Update mean using exponential map
323
step_size = 0.5 # Learning rate
324
scaled_tangent = Quaternion(avg_tangent.elements * step_size)
325
new_mean = Quaternion.exp_map(mean_q, scaled_tangent)
326
327
# Check convergence
328
update_distance = Quaternion.distance(mean_q, new_mean)
329
if update_distance < tolerance:
330
break
331
332
mean_q = new_mean.normalised
333
334
return mean_q
335
336
# Usage
337
sample_quaternions = [
338
Quaternion(axis=[1, 0, 0], degrees=10),
339
Quaternion(axis=[1, 0, 0], degrees=20),
340
Quaternion(axis=[1, 0, 0], degrees=15),
341
Quaternion(axis=[1, 0, 0], degrees=12),
342
]
343
344
mean_quaternion = quaternion_mean_iterative(sample_quaternions)
345
print(f"Mean quaternion: {mean_quaternion}")
346
print(f"Mean angle: {mean_quaternion.degrees:.1f}°")
347
```