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()

Gallery generated by Sphinx-Gallery