Note
Go to the end to download the full example code.
Integration Patterns and Multimodal Fusion¶
Topics: Multimodal fusion, encoder integration, design patterns, hierarchical encoding Time: 25 minutes Prerequisites: 10_encoders_scalar.py, 14_encoders_ngram.py, 23_app_symbolic_reasoning.py Related: 20-22_app_*.py (domain-specific applications)
This example demonstrates integration patterns for building complex hyperdimensional computing systems. Learn how to combine multiple encoders, fuse multimodal data, and structure hierarchical representations for real-world applications.
Key concepts: - Multimodal fusion: Combining text, images, and numeric data - Encoder composition: Integrate scalar, sequence, spatial encoders - Hierarchical encoding: Build layered representations - Design patterns: Reusable structures for HDC systems - End-to-end workflow: From raw data to query answering
This capstone example shows how the individual encoders and techniques work together to build sophisticated AI systems.
25 import numpy as np
26 from holovec import VSA
27 from holovec.encoders import (
28 FractionalPowerEncoder,
29 NGramEncoder,
30 VectorEncoder,
31 PositionBindingEncoder,
32 )
33 from holovec.retrieval import ItemStore
34
35 print("=" * 70)
36 print("Integration Patterns and Multimodal Fusion")
37 print("=" * 70)
38 print()
39
40 # Create model
41 model = VSA.create('FHRR', dim=10000, seed=42)
42
43 # ============================================================================
44 # Pattern 1: Multimodal Fusion - Combining Different Data Types
45 # ============================================================================
46 print("=" * 70)
47 print("Pattern 1: Multimodal Fusion - Product Reviews")
48 print("=" * 70)
49
50 print("\nScenario: Encode product reviews with text + rating + price")
51
52 # Setup encoders for different modalities
53 print("\n Setting up encoders:")
54
55 # Text modality: N-gram encoder
56 text_encoder = NGramEncoder(model, n=3, seed=42)
57 print(" - Text: NGramEncoder (3-grams)")
58
59 # Rating modality: Scalar encoder (1-5 stars)
60 rating_encoder = FractionalPowerEncoder(model, min_val=1, max_val=5, bandwidth=0.2, seed=43)
61 print(" - Rating: FractionalPowerEncoder (1-5 stars)")
62
63 # Price modality: Scalar encoder ($0-$1000)
64 price_encoder = FractionalPowerEncoder(model, min_val=0, max_val=1000, bandwidth=20, seed=44)
65 print(" - Price: FractionalPowerEncoder ($0-$1000)")
66
67 # Define modality dimension vectors
68 TEXT_DIM = model.random(seed=100)
69 RATING_DIM = model.random(seed=101)
70 PRICE_DIM = model.random(seed=102)
71
72 print("\n Modality dimensions: TEXT, RATING, PRICE")
73
74 # Encode example product reviews
75 print("\n" + "=" * 70)
76 print("Encoding 3 product reviews:")
77 print("=" * 70)
78
79 reviews = [
80 {
81 "id": "product_A",
82 "text": "excellent quality fast shipping",
83 "rating": 5.0,
84 "price": 49.99
85 },
86 {
87 "id": "product_B",
88 "text": "poor quality slow shipping",
89 "rating": 2.0,
90 "price": 39.99
91 },
92 {
93 "id": "product_C",
94 "text": "excellent product fast delivery",
95 "rating": 4.5,
96 "price": 89.99
97 }
98 ]
99
100 encoded_reviews = {}
101
102 for review in reviews:
103 print(f"\n {review['id']}:")
104 print(f" Text: '{review['text']}'")
105 print(f" Rating: {review['rating']}/5, Price: ${review['price']}")
106
107 # Encode each modality
108 text_hv = text_encoder.encode(review["text"])
109 rating_hv = rating_encoder.encode(review["rating"])
110 price_hv = price_encoder.encode(review["price"])
111
112 # Bind each modality to its dimension vector
113 text_bound = model.bind(TEXT_DIM, text_hv)
114 rating_bound = model.bind(RATING_DIM, rating_hv)
115 price_bound = model.bind(PRICE_DIM, price_hv)
116
117 # Bundle all modalities into single multimodal representation
118 multimodal_hv = model.bundle([text_bound, rating_bound, price_bound])
119 encoded_reviews[review["id"]] = multimodal_hv
120
121 print(f" → Multimodal HV shape: {multimodal_hv.shape}")
122
123 # Query: Find products similar to "excellent fast shipping, 5 stars, ~$50"
124 print("\n" + "=" * 70)
125 print("Query: Products like 'excellent fast', 5 stars, $50")
126 print("=" * 70)
127
128 query_text = "excellent fast"
129 query_rating = 5.0
130 query_price = 50.0
131
132 # Encode query
133 query_text_hv = text_encoder.encode(query_text)
134 query_rating_hv = rating_encoder.encode(query_rating)
135 query_price_hv = price_encoder.encode(query_price)
136
137 # Bind to dimensions
138 query_text_bound = model.bind(TEXT_DIM, query_text_hv)
139 query_rating_bound = model.bind(RATING_DIM, query_rating_hv)
140 query_price_bound = model.bind(PRICE_DIM, query_price_hv)
141
142 # Bundle query modalities
143 query_hv = model.bundle([query_text_bound, query_rating_bound, query_price_bound])
144
145 print("\nSimilarity to products:")
146 for prod_id, prod_hv in encoded_reviews.items():
147 sim = float(model.similarity(query_hv, prod_hv))
148 print(f" {prod_id}: {sim:.3f}")
149
150 print("\nKey observation:")
151 print(" - Product A ranks highest (excellent/fast + 5 stars + $49.99)")
152 print(" - Multimodal fusion combines complementary information")
153 print(" - Each modality contributes to overall similarity")
154
155 # ============================================================================
156 # Pattern 2: Hierarchical Encoding - Part-Whole Relationships
157 # ============================================================================
158 print("\n" + "=" * 70)
159 print("Pattern 2: Hierarchical Encoding - Document Structure")
160 print("=" * 70)
161
162 print("\nScenario: Encode document with sections and paragraphs")
163
164 # Define hierarchy levels
165 DOCUMENT = model.random(seed=200)
166 SECTION = model.random(seed=201)
167 PARAGRAPH = model.random(seed=202)
168
169 print(" Hierarchy: DOCUMENT → SECTION → PARAGRAPH")
170
171 # Encode document structure
172 print("\n" + "=" * 70)
173 print("Document: 'Machine Learning Tutorial'")
174 print("=" * 70)
175
176 # Section 1: Introduction
177 intro_para1 = "machine learning algorithms process data"
178 intro_para2 = "supervised learning uses labeled data"
179
180 intro_p1_hv = text_encoder.encode(intro_para1)
181 intro_p2_hv = text_encoder.encode(intro_para2)
182
183 intro_section = model.bundle([
184 model.bind(PARAGRAPH, intro_p1_hv),
185 model.bind(PARAGRAPH, intro_p2_hv)
186 ])
187
188 print("\n Section 1 (Introduction):")
189 print(f" Para 1: '{intro_para1}'")
190 print(f" Para 2: '{intro_para2}'")
191
192 # Section 2: Methods
193 methods_para1 = "neural networks learn patterns from data"
194 methods_para2 = "decision trees create classification rules"
195
196 methods_p1_hv = text_encoder.encode(methods_para1)
197 methods_p2_hv = text_encoder.encode(methods_para2)
198
199 methods_section = model.bundle([
200 model.bind(PARAGRAPH, methods_p1_hv),
201 model.bind(PARAGRAPH, methods_p2_hv)
202 ])
203
204 print("\n Section 2 (Methods):")
205 print(f" Para 1: '{methods_para1}'")
206 print(f" Para 2: '{methods_para2}'")
207
208 # Combine sections into document
209 document_hv = model.bundle([
210 model.bind(SECTION, intro_section),
211 model.bind(SECTION, methods_section)
212 ])
213
214 print("\n → Document HV (hierarchical encoding)")
215
216 # Query: Which section discusses "neural networks"?
217 print("\n" + "=" * 70)
218 print("Query: Which section discusses 'neural networks'?")
219 print("=" * 70)
220
221 query_nn = text_encoder.encode("neural networks")
222
223 # Check similarity to each section
224 sim_intro = float(model.similarity(intro_section, model.bind(PARAGRAPH, query_nn)))
225 sim_methods = float(model.similarity(methods_section, model.bind(PARAGRAPH, query_nn)))
226
227 print(f"\n Intro section: {sim_intro:.3f}")
228 print(f" Methods section: {sim_methods:.3f} ← Best match!")
229
230 print("\nKey observation:")
231 print(" - Hierarchical structure preserves part-whole relationships")
232 print(" - Can query at different levels (document, section, paragraph)")
233 print(" - Enables structured document retrieval")
234
235 # ============================================================================
236 # Pattern 3: Encoder Composition - Building Complex Encoders
237 # ============================================================================
238 print("\n" + "=" * 70)
239 print("Pattern 3: Encoder Composition - Feature Vectors with Labels")
240 print("=" * 70)
241
242 print("\nScenario: Encode labeled feature vectors (supervised learning)")
243
244 # Setup: Vector encoder for features + position encoder for class label
245 feature_dim = 5
246 feature_encoder = VectorEncoder(
247 model,
248 FractionalPowerEncoder(model, min_val=0, max_val=1, seed=45),
249 n_dimensions=feature_dim,
250 seed=46
251 )
252
253 label_encoder = PositionBindingEncoder(model, seed=47)
254
255 print(f" Features: VectorEncoder ({feature_dim}D)")
256 print(" Labels: PositionBindingEncoder")
257
258 # Define label and feature dimensions
259 FEATURES = model.random(seed=300)
260 LABEL = model.random(seed=301)
261
262 # Encode training examples
263 print("\n" + "=" * 70)
264 print("Encoding training examples:")
265 print("=" * 70)
266
267 training_data = [
268 {"features": np.array([0.8, 0.9, 0.1, 0.2, 0.1]), "label": ["class_A"]},
269 {"features": np.array([0.2, 0.1, 0.9, 0.8, 0.9]), "label": ["class_B"]},
270 {"features": np.array([0.7, 0.8, 0.2, 0.3, 0.2]), "label": ["class_A"]},
271 ]
272
273 encoded_examples = []
274
275 for i, example in enumerate(training_data):
276 print(f"\n Example {i+1}:")
277 print(f" Features: {example['features']}")
278 print(f" Label: {example['label'][0]}")
279
280 # Encode features and label
281 features_hv = feature_encoder.encode(example["features"])
282 label_hv = label_encoder.encode(example["label"])
283
284 # Bind to dimensions
285 features_bound = model.bind(FEATURES, features_hv)
286 label_bound = model.bind(LABEL, label_hv)
287
288 # Bundle into example representation
289 example_hv = model.bundle([features_bound, label_bound])
290 encoded_examples.append(example_hv)
291
292 # Create training memory
293 training_memory = model.bundle(encoded_examples)
294 print("\n → Training memory (bundled all examples)")
295
296 # Query: Predict label for new features
297 print("\n" + "=" * 70)
298 print("Prediction: Classify new features")
299 print("=" * 70)
300
301 test_features = np.array([0.85, 0.90, 0.15, 0.25, 0.15])
302 print(f"\n Test features: {test_features}")
303
304 # Encode test features
305 test_features_hv = feature_encoder.encode(test_features)
306 test_features_bound = model.bind(FEATURES, test_features_hv)
307
308 # Query training memory for similar examples
309 print("\n Similarity to training examples:")
310 for i, ex_hv in enumerate(encoded_examples):
311 sim = float(model.similarity(test_features_bound, ex_hv))
312 label = training_data[i]["label"][0]
313 print(f" Example {i+1} ({label}): {sim:.3f}")
314
315 # Extract label from most similar example
316 query_label = model.unbind(encoded_examples[0], FEATURES) # Most similar to example 1
317 sim_a = float(model.similarity(query_label, label_encoder.encode(["class_A"])))
318 sim_b = float(model.similarity(query_label, label_encoder.encode(["class_B"])))
319
320 print(f"\n Predicted label probabilities:")
321 print(f" class_A: {sim_a:.3f} ← Prediction")
322 print(f" class_B: {sim_b:.3f}")
323
324 print("\nKey observation:")
325 print(" - Composition combines multiple encoders")
326 print(" - Enables flexible, structured data encoding")
327 print(" - Supports supervised learning paradigms")
328
329 # ============================================================================
330 # Pattern 4: Semantic Binding - Context-Dependent Representations
331 # ============================================================================
332 print("\n" + "=" * 70)
333 print("Pattern 4: Semantic Binding - Word Sense Disambiguation")
334 print("=" * 70)
335
336 print("\nScenario: Encode words with context to disambiguate meaning")
337
338 # Setup: Encode word + context
339 WORD = model.random(seed=400)
340 CONTEXT = model.random(seed=401)
341
342 # Encode "bank" in different contexts
343 bank = model.random(seed=500)
344
345 context1 = text_encoder.encode("river water shore")
346 context2 = text_encoder.encode("money deposit account")
347
348 print("\n Word: 'bank'")
349 print(" Context 1: 'river water shore' (riverbank)")
350 print(" Context 2: 'money deposit account' (financial bank)")
351
352 # Create context-dependent representations
353 bank_river = model.bundle([
354 model.bind(WORD, bank),
355 model.bind(CONTEXT, context1)
356 ])
357
358 bank_financial = model.bundle([
359 model.bind(WORD, bank),
360 model.bind(CONTEXT, context2)
361 ])
362
363 print("\n → bank_river (riverbank sense)")
364 print(" → bank_financial (financial sense)")
365
366 # Test: Which sense matches new context?
367 print("\n" + "=" * 70)
368 print("Test: 'bank' in context 'deposit money account'")
369 print("=" * 70)
370
371 test_context = text_encoder.encode("deposit money account")
372 test_bank = model.bundle([
373 model.bind(WORD, bank),
374 model.bind(CONTEXT, test_context)
375 ])
376
377 sim_river = float(model.similarity(test_bank, bank_river))
378 sim_financial = float(model.similarity(test_bank, bank_financial))
379
380 print(f"\n Similarity to riverbank sense: {sim_river:.3f}")
381 print(f" Similarity to financial sense: {sim_financial:.3f} ← Best match!")
382
383 print("\nKey observation:")
384 print(" - Context binding creates distinct word senses")
385 print(" - Disambiguates polysemous words automatically")
386 print(" - Models compositional semantics")
387
388 # ============================================================================
389 # Pattern 5: End-to-End Application - Multimodal Search Engine
390 # ============================================================================
391 print("\n" + "=" * 70)
392 print("Pattern 5: End-to-End Multimodal Search Engine")
393 print("=" * 70)
394
395 print("\nScenario: Search products by text description + price range")
396
397 # Build product database
398 product_store = ItemStore(model)
399
400 products = [
401 {"id": "laptop_premium", "desc": "high performance laptop fast processor", "price": 1200},
402 {"id": "laptop_budget", "desc": "affordable laptop basic performance", "price": 400},
403 {"id": "phone_premium", "desc": "smartphone fast processor excellent camera", "price": 900},
404 {"id": "phone_budget", "desc": "basic phone affordable price", "price": 200},
405 ]
406
407 print("\n Building product database:")
408
409 for prod in products:
410 desc_hv = text_encoder.encode(prod["desc"])
411 price_hv = price_encoder.encode(float(prod["price"]))
412
413 prod_hv = model.bundle([
414 model.bind(TEXT_DIM, desc_hv),
415 model.bind(PRICE_DIM, price_hv)
416 ])
417
418 product_store.add(prod["id"], prod_hv)
419 print(f" {prod['id']}: '{prod['desc']}' (${prod['price']})")
420
421 # Query: "fast laptop under $500"
422 print("\n" + "=" * 70)
423 print("Query: 'fast laptop' under $500")
424 print("=" * 70)
425
426 query_desc = "fast laptop"
427 query_max_price = 500
428
429 query_desc_hv = text_encoder.encode(query_desc)
430 query_price_hv = price_encoder.encode(float(query_max_price))
431
432 query_multimodal = model.bundle([
433 model.bind(TEXT_DIM, query_desc_hv),
434 model.bind(PRICE_DIM, query_price_hv)
435 ])
436
437 # Search product database
438 results = product_store.query(query_multimodal, k=4)
439
440 print("\n Search results (ranked by relevance):")
441 for i, (prod_id, sim) in enumerate(results, 1):
442 # Find product details
443 prod = next(p for p in products if p["id"] == prod_id)
444 print(f" {i}. {prod_id}: {sim:.3f}")
445 print(f" Description: '{prod['desc']}'")
446 print(f" Price: ${prod['price']}")
447
448 print("\nKey observation:")
449 print(" - End-to-end workflow: data → encoding → retrieval")
450 print(" - Multimodal query combines text and price constraints")
451 print(" - ItemStore enables efficient similarity search")
452
453 # ============================================================================
454 # Summary
455 # ============================================================================
456 print("\n" + "=" * 70)
457 print("Summary: Integration Patterns Key Takeaways")
458 print("=" * 70)
459 print()
460 print("✓ Multimodal fusion: Combine text, numeric, and other data types")
461 print("✓ Hierarchical encoding: Build layered, structured representations")
462 print("✓ Encoder composition: Integrate multiple encoders flexibly")
463 print("✓ Semantic binding: Context-dependent representations")
464 print("✓ End-to-end systems: Complete application workflows")
465 print()
466 print("Integration pattern recipes:")
467 print()
468 print("1. Multimodal Fusion:")
469 print(" - Encode each modality separately")
470 print(" - Bind each to unique dimension vector")
471 print(" - Bundle all modalities into single HV")
472 print(" - Query: bundle query modalities same way")
473 print()
474 print("2. Hierarchical Encoding:")
475 print(" - Define level dimension vectors (document, section, paragraph)")
476 print(" - Encode bottom-up: leaf → intermediate → root")
477 print(" - Bind each level's content to its dimension")
478 print(" - Bundle across levels for complete structure")
479 print()
480 print("3. Encoder Composition:")
481 print(" - Combine encoders for complex data (features + labels)")
482 print(" - Use consistent dimension binding pattern")
483 print(" - Enable flexible, reusable encoding pipelines")
484 print()
485 print("4. Context Binding:")
486 print(" - Bind primary concept to WORD dimension")
487 print(" - Bind context to CONTEXT dimension")
488 print(" - Bundle for context-dependent representation")
489 print(" - Enables disambiguation and semantic composition")
490 print()
491 print("Design principles:")
492 print(" - Modularity: Combine encoders like building blocks")
493 print(" - Consistency: Use same bind/bundle patterns")
494 print(" - Flexibility: Adapt patterns to your domain")
495 print(" - Scalability: Patterns work for any data scale")
496 print()
497 print("Applications:")
498 print(" - Multimodal search: Text + image + metadata")
499 print(" - Document understanding: Hierarchical structure")
500 print(" - Recommendation systems: User preferences + item features")
501 print(" - Semantic search: Context-aware retrieval")
502 print()
503 print("Next steps:")
504 print(" → Apply patterns to your domain")
505 print(" → Combine with cleanup strategies (27, 28)")
506 print(" → Build domain-specific applications (20-22)")
507 print()
508 print("=" * 70)