Note
Go to the end to download the full example code.
Demonstration of Trajectory Encoder for continuous sequence encoding.¶
This demo showcases the TrajectoryEncoder, which encodes continuous sequences like time series, paths, and motion trajectories into hypervectors. This is particularly useful for:
Time series analysis and classification
Path and trajectory matching
Motion pattern recognition
Gesture recognition
Robot navigation
Sensor data encoding
The encoder supports: - 1D sequences (time series) - 2D paths (planar motion) - 3D trajectories (spatial motion) - Time range normalization for consistent temporal scaling - Different scalar encoders (FractionalPowerEncoder, ThermometerEncoder)
24 from holovec import VSA
25 from holovec.encoders import TrajectoryEncoder, FractionalPowerEncoder, ThermometerEncoder
26 import math
27
28
29 def print_section(title):
30 """Print a section header."""
31 print(f"\n{'=' * 70}")
32 print(f"{title}")
33 print('=' * 70)
34
35
36 def demo_basic_1d_encoding():
37 """Demonstrate basic 1D time series encoding."""
38 print_section("Demo 1: Basic 1D Time Series Encoding")
39
40 model = VSA.create('FHRR', dim=10000, seed=42)
41 scalar_enc = FractionalPowerEncoder(model, min_val=0, max_val=100, seed=42)
42 encoder = TrajectoryEncoder(model, scalar_enc, n_dimensions=1, seed=42)
43
44 print(f"\nEncoder: {encoder}")
45 print(f"Configuration: {encoder.n_dimensions}D, time_range={encoder.time_range}")
46
47 # Encode a simple time series
48 time_series = [10.0, 20.0, 30.0, 40.0, 50.0]
49 hv = encoder.encode(time_series)
50
51 print(f"\nInput time series: {time_series}")
52 print(f"Encoded hypervector shape: {hv.shape}")
53 print(f"Input type: {encoder.input_type}")
54
55
56 def demo_different_dimensions():
57 """Demonstrate encoding in different dimensions."""
58 print_section("Demo 2: Encoding in Different Dimensions")
59
60 model = VSA.create('FHRR', dim=10000, seed=42)
61 scalar_enc = FractionalPowerEncoder(model, min_val=-50, max_val=50, seed=42)
62
63 print("\n1D Time Series:")
64 encoder_1d = TrajectoryEncoder(model, scalar_enc, n_dimensions=1, seed=42)
65 ts_1d = [0.0, 10.0, 20.0, 30.0]
66 hv_1d = encoder_1d.encode(ts_1d)
67 print(f" Input: {ts_1d}")
68 print(f" Hypervector shape: {hv_1d.shape}")
69
70 print("\n2D Path:")
71 encoder_2d = TrajectoryEncoder(model, scalar_enc, n_dimensions=2, seed=42)
72 path_2d = [(0, 0), (10, 10), (20, 20), (30, 30)]
73 hv_2d = encoder_2d.encode(path_2d)
74 print(f" Input: {path_2d}")
75 print(f" Hypervector shape: {hv_2d.shape}")
76
77 print("\n3D Trajectory:")
78 encoder_3d = TrajectoryEncoder(model, scalar_enc, n_dimensions=3, seed=42)
79 traj_3d = [(0, 0, 0), (10, 10, 5), (20, 20, 10), (30, 30, 15)]
80 hv_3d = encoder_3d.encode(traj_3d)
81 print(f" Input: {traj_3d}")
82 print(f" Hypervector shape: {hv_3d.shape}")
83
84
85 def demo_time_series_similarity():
86 """Demonstrate time series similarity analysis."""
87 print_section("Demo 3: Time Series Similarity Analysis")
88
89 model = VSA.create('FHRR', dim=10000, seed=42)
90 scalar_enc = FractionalPowerEncoder(model, min_val=0, max_val=100, seed=42)
91 encoder = TrajectoryEncoder(model, scalar_enc, n_dimensions=1, seed=42)
92
93 # Create similar and different time series
94 ts1 = [10.0, 20.0, 30.0, 40.0, 50.0]
95 ts2 = [10.0, 20.0, 30.0, 40.0, 51.0] # Slightly different
96 ts3 = [50.0, 40.0, 30.0, 20.0, 10.0] # Reversed
97 ts4 = [5.0, 15.0, 25.0, 35.0, 45.0] # Offset by -5
98
99 hv1 = encoder.encode(ts1)
100 hv2 = encoder.encode(ts2)
101 hv3 = encoder.encode(ts3)
102 hv4 = encoder.encode(ts4)
103
104 print("\nTime Series 1:", ts1)
105 print("Time Series 2:", ts2, "(slightly different)")
106 print("Time Series 3:", ts3, "(reversed)")
107 print("Time Series 4:", ts4, "(offset by -5)\n")
108
109 sim_1_2 = float(model.similarity(hv1, hv2))
110 sim_1_3 = float(model.similarity(hv1, hv3))
111 sim_1_4 = float(model.similarity(hv1, hv4))
112
113 print(f"Similarity (ts1 vs ts2): {sim_1_2:.3f}")
114 print(f"Similarity (ts1 vs ts3): {sim_1_3:.3f}")
115 print(f"Similarity (ts1 vs ts4): {sim_1_4:.3f}")
116
117 print("\nKey insights:")
118 print(" - Very similar sequences have high similarity")
119 print(" - Reversed sequences have low similarity (order matters)")
120 print(" - Offset sequences have moderate similarity")
121
122
123 def demo_path_similarity():
124 """Demonstrate 2D path similarity analysis."""
125 print_section("Demo 4: 2D Path Similarity Analysis")
126
127 model = VSA.create('FHRR', dim=10000, seed=42)
128 scalar_enc = FractionalPowerEncoder(model, min_val=-10, max_val=100, seed=42)
129 encoder = TrajectoryEncoder(model, scalar_enc, n_dimensions=2, seed=42)
130
131 # Define paths
132 path1 = [(0, 0), (10, 10), (20, 20), (30, 30)] # Diagonal
133 path2 = [(0, 0), (10, 10), (20, 20), (30, 31)] # Almost identical
134 path3 = [(0, 0), (10, 0), (20, 0), (30, 0)] # Horizontal
135 path4 = [(0, 0), (0, 10), (0, 20), (0, 30)] # Vertical
136
137 hv1 = encoder.encode(path1)
138 hv2 = encoder.encode(path2)
139 hv3 = encoder.encode(path3)
140 hv4 = encoder.encode(path4)
141
142 print("\nPath 1: Diagonal", path1)
143 print("Path 2: Almost identical", path2)
144 print("Path 3: Horizontal", path3)
145 print("Path 4: Vertical", path4)
146
147 sim_1_2 = float(model.similarity(hv1, hv2))
148 sim_1_3 = float(model.similarity(hv1, hv3))
149 sim_1_4 = float(model.similarity(hv1, hv4))
150
151 print(f"\nSimilarity (path1 vs path2): {sim_1_2:.3f}")
152 print(f"Similarity (path1 vs path3): {sim_1_3:.3f}")
153 print(f"Similarity (path1 vs path4): {sim_1_4:.3f}")
154
155 print("\nKey insight:")
156 print(" Path shape and direction are encoded in the hypervector")
157
158
159 def demo_time_range_normalization():
160 """Demonstrate time range normalization."""
161 print_section("Demo 5: Time Range Normalization")
162
163 model = VSA.create('FHRR', dim=10000, seed=42)
164 scalar_enc = FractionalPowerEncoder(model, min_val=0, max_val=100, seed=42)
165
166 # Without time normalization (default)
167 encoder_no_norm = TrajectoryEncoder(model, scalar_enc, n_dimensions=1, seed=42)
168
169 # With time normalization
170 encoder_with_norm = TrajectoryEncoder(
171 model, scalar_enc, n_dimensions=1, time_range=(0.0, 1.0), seed=42
172 )
173
174 time_series = [10.0, 20.0, 30.0, 40.0, 50.0]
175
176 hv_no_norm = encoder_no_norm.encode(time_series)
177 hv_with_norm = encoder_with_norm.encode(time_series)
178
179 print(f"\nInput time series: {time_series}")
180 print(f"\nWithout time normalization:")
181 print(f" Time indices used: 0, 1, 2, 3, 4")
182 print(f" Hypervector: shape {hv_no_norm.shape}")
183
184 print(f"\nWith time normalization (0.0 to 1.0):")
185 print(f" Time indices normalized: 0.00, 0.25, 0.50, 0.75, 1.00")
186 print(f" Hypervector: shape {hv_with_norm.shape}")
187
188 sim = float(model.similarity(hv_no_norm, hv_with_norm))
189 print(f"\nSimilarity between encodings: {sim:.3f}")
190 print("\nKey insight:")
191 print(" Time normalization makes sequences comparable regardless of length")
192
193
194 def demo_circular_path():
195 """Demonstrate encoding a circular path."""
196 print_section("Demo 6: Circular Path Encoding")
197
198 model = VSA.create('FHRR', dim=10000, seed=42)
199 scalar_enc = FractionalPowerEncoder(model, min_val=-15, max_val=15, seed=42)
200 encoder = TrajectoryEncoder(model, scalar_enc, n_dimensions=2, seed=42)
201
202 # Generate circular path
203 n_points = 8
204 radius = 10.0
205 circle = [
206 (radius * math.cos(2 * math.pi * i / n_points),
207 radius * math.sin(2 * math.pi * i / n_points))
208 for i in range(n_points)
209 ]
210
211 # Generate ellipse (similar to circle)
212 ellipse = [
213 (12.0 * math.cos(2 * math.pi * i / n_points),
214 8.0 * math.sin(2 * math.pi * i / n_points))
215 for i in range(n_points)
216 ]
217
218 # Generate square path
219 square = [(10, 10), (10, -10), (-10, -10), (-10, 10),
220 (10, 10), (10, -10), (-10, -10), (-10, 10)]
221
222 hv_circle = encoder.encode(circle)
223 hv_ellipse = encoder.encode(ellipse)
224 hv_square = encoder.encode(square)
225
226 print(f"\nCircle (radius={radius}, {n_points} points)")
227 print(f"First 3 points: {[tuple(round(x, 1) for x in p) for p in circle[:3]]}")
228
229 print(f"\nEllipse (rx=12, ry=8, {n_points} points)")
230 print(f"First 3 points: {[tuple(round(x, 1) for x in p) for p in ellipse[:3]]}")
231
232 print(f"\nSquare (side=20, {len(square)} points)")
233 print(f"Points: {square[:4]}...")
234
235 sim_circle_ellipse = float(model.similarity(hv_circle, hv_ellipse))
236 sim_circle_square = float(model.similarity(hv_circle, hv_square))
237
238 print(f"\nSimilarity (circle vs ellipse): {sim_circle_ellipse:.3f}")
239 print(f"Similarity (circle vs square): {sim_circle_square:.3f}")
240
241 print("\nKey insight:")
242 print(" Closed curves with similar shapes have higher similarity")
243
244
245 def demo_application_gesture_recognition():
246 """Demonstrate application: gesture recognition."""
247 print_section("Demo 7: Application - Gesture Recognition")
248
249 model = VSA.create('FHRR', dim=10000, seed=42)
250 scalar_enc = FractionalPowerEncoder(model, min_val=-20, max_val=20, seed=42)
251 encoder = TrajectoryEncoder(model, scalar_enc, n_dimensions=2, seed=42)
252
253 print("\nScenario: Recognize hand gestures from 2D trajectories\n")
254
255 # Training examples - gesture prototypes
256 swipe_right = [(0, 0), (5, 0), (10, 0), (15, 0), (20, 0)]
257 swipe_left = [(20, 0), (15, 0), (10, 0), (5, 0), (0, 0)]
258 swipe_up = [(0, 0), (0, 5), (0, 10), (0, 15), (0, 20)]
259 circle_gesture = [
260 (10, 0), (7, 7), (0, 10), (-7, 7),
261 (-10, 0), (-7, -7), (0, -10), (7, -7), (10, 0)
262 ]
263
264 # Create gesture prototypes
265 hv_right = encoder.encode(swipe_right)
266 hv_left = encoder.encode(swipe_left)
267 hv_up = encoder.encode(swipe_up)
268 hv_circle = encoder.encode(circle_gesture)
269
270 print("Gesture Library:")
271 print(f" - Swipe Right: {swipe_right}")
272 print(f" - Swipe Left: {swipe_left}")
273 print(f" - Swipe Up: {swipe_up}")
274 print(f" - Circle: {len(circle_gesture)} points")
275
276 # Test gestures (with variations)
277 test_gestures = [
278 ([(1, 0), (6, 0), (11, 0), (16, 0), (19, 0)], "Swipe Right"),
279 ([(19, 0), (14, 0), (9, 0), (4, 0), (1, 0)], "Swipe Left"),
280 ([(0, 1), (0, 6), (0, 11), (0, 16), (0, 19)], "Swipe Up"),
281 ([(10, 0), (7, 8), (0, 11), (-7, 7), (-10, 0), (-7, -8), (0, -11), (8, -7), (10, 0)], "Circle"),
282 ]
283
284 gestures_db = {
285 "Swipe Right": hv_right,
286 "Swipe Left": hv_left,
287 "Swipe Up": hv_up,
288 "Circle": hv_circle
289 }
290
291 print("\nTest Results:")
292 for gesture, true_label in test_gestures:
293 hv = encoder.encode(gesture)
294
295 # Find best match
296 best_match = None
297 best_sim = -1.0
298 for name, prototype in gestures_db.items():
299 sim = float(model.similarity(hv, prototype))
300 if sim > best_sim:
301 best_sim = sim
302 best_match = name
303
304 print(f"\n Test gesture: {true_label}")
305 print(f" Recognized as: {best_match} (similarity: {best_sim:.3f})")
306 print(f" Result: {'✓ Correct' if best_match == true_label else '✗ Incorrect'}")
307
308
309 def demo_application_robot_paths():
310 """Demonstrate application: robot path matching."""
311 print_section("Demo 8: Application - Robot Path Matching")
312
313 model = VSA.create('FHRR', dim=10000, seed=42)
314 scalar_enc = FractionalPowerEncoder(model, min_val=0, max_val=50, seed=42)
315 encoder = TrajectoryEncoder(model, scalar_enc, n_dimensions=2, seed=42)
316
317 print("\nScenario: Match robot paths for navigation planning\n")
318
319 # Known successful paths
320 path_a = [(0, 0), (10, 5), (20, 10), (30, 15), (40, 20)] # Gradual diagonal
321 path_b = [(0, 0), (5, 10), (10, 20), (15, 30), (20, 40)] # Steep diagonal
322 path_c = [(0, 0), (10, 0), (20, 5), (30, 10), (40, 15)] # Mostly horizontal
323
324 hv_a = encoder.encode(path_a)
325 hv_b = encoder.encode(path_b)
326 hv_c = encoder.encode(path_c)
327
328 path_library = {
329 "Path A (gradual diagonal)": hv_a,
330 "Path B (steep diagonal)": hv_b,
331 "Path C (mostly horizontal)": hv_c
332 }
333
334 print("Path Library:")
335 print(f" Path A: {path_a}")
336 print(f" Path B: {path_b}")
337 print(f" Path C: {path_c}")
338
339 # New path to match
340 new_path = [(0, 0), (9, 6), (19, 11), (29, 16), (39, 21)]
341
342 print(f"\nNew path to match: {new_path}")
343
344 hv_new = encoder.encode(new_path)
345
346 print("\nSimilarity to known paths:")
347 for name, prototype in path_library.items():
348 sim = float(model.similarity(hv_new, prototype))
349 print(f" {name}: {sim:.3f}")
350
351 print("\nKey insight:")
352 print(" Similar paths can be retrieved for navigation planning")
353
354
355 def demo_different_scalar_encoders():
356 """Demonstrate using different scalar encoders."""
357 print_section("Demo 9: Different Scalar Encoders")
358
359 print("\nFractionalPowerEncoder (for FHRR/HRR - complex models):")
360 model_fhrr = VSA.create('FHRR', dim=10000, seed=42)
361 scalar_fpe = FractionalPowerEncoder(model_fhrr, min_val=0, max_val=100, seed=42)
362 encoder_fpe = TrajectoryEncoder(model_fhrr, scalar_fpe, n_dimensions=1, seed=42)
363
364 ts = [10.0, 20.0, 30.0, 40.0]
365 hv_fpe = encoder_fpe.encode(ts)
366 print(f" Model: FHRR")
367 print(f" Time series: {ts}")
368 print(f" Encoded shape: {hv_fpe.shape}")
369
370 print("\nThermometerEncoder (for MAP/BSC - bipolar models):")
371 model_map = VSA.create('MAP', dim=10000, seed=42)
372 scalar_therm = ThermometerEncoder(model_map, min_val=0, max_val=100, n_bins=100, seed=42)
373 encoder_therm = TrajectoryEncoder(model_map, scalar_therm, n_dimensions=1, seed=42)
374
375 hv_therm = encoder_therm.encode(ts)
376 print(f" Model: MAP")
377 print(f" Time series: {ts}")
378 print(f" Encoded shape: {hv_therm.shape}")
379
380 print("\nKey insight:")
381 print(" TrajectoryEncoder works with any scalar encoder compatible with the model")
382
383
384 def main():
385 """Run all demos."""
386 print("=" * 70)
387 print("Trajectory Encoder - Comprehensive Demonstration")
388 print("=" * 70)
389 print("\nThe TrajectoryEncoder encodes continuous sequences (time series,")
390 print("paths, trajectories) into hypervectors. This is essential for:")
391 print(" - Time series analysis and classification")
392 print(" - Path and trajectory matching")
393 print(" - Motion pattern recognition")
394 print(" - Gesture recognition")
395 print(" - Robot navigation")
396
397 demo_basic_1d_encoding()
398 demo_different_dimensions()
399 demo_time_series_similarity()
400 demo_path_similarity()
401 demo_time_range_normalization()
402 demo_circular_path()
403 demo_application_gesture_recognition()
404 demo_application_robot_paths()
405 demo_different_scalar_encoders()
406
407 print("\n" + "=" * 70)
408 print("Demo Complete!")
409 print("=" * 70)
410 print("\nNext steps:")
411 print(" - See docs/theory/encoders.md for mathematical details")
412 print(" - Run tests: pytest tests/test_encoders_sequence.py -k Trajectory")
413 print(" - Try with different VSA models and scalar encoders")
414
415
416 if __name__ == '__main__':
417 main()