Skip to content

Tutorial 11: Analogical Reasoning with Conceptual Spaces

This tutorial demonstrates how to use VSAX for analogical reasoning within continuous conceptual spaces, based on the research by Goldowsky & Sarathy (2024).

Overview

Analogical reasoning is the ability to recognize and apply relationships between concepts. For example:

  • Category-based: "PURPLE is to BLUE as ORANGE is to ___?" (Answer: YELLOW)
  • Property-based: "If an APPLE is RED, what color is a BANANA?" (Answer: YELLOW)

VSAX enables analogical reasoning by: 1. Encoding concepts as points in continuous conceptual spaces using Fractional Power Encoding (FPE) 2. Finding analogies using the parallelogram model with binding operations 3. Decoding results using resonator networks and code books

Conceptual Spaces Theory

Conceptual Spaces Theory (CST) represents concepts geometrically in multi-dimensional spaces where:

  • Each dimension represents a quality (e.g., hue, saturation, brightness for colors)
  • Similar concepts are close together in the space
  • Concepts can be combined and transformed using geometric operations

The Color Domain Example

We'll use a 3D color space with dimensions: - Hue: Color wavelength (-10 to +10) - Saturation: Color intensity (-10 to +10) - Brightness: Lightness level (-10 to +10)

Colors are represented as points in this 3D space:

import jax
from vsax import VSAMemory, create_fhrr_model
from vsax.encoders.fpe import FractionalPowerEncoder

# Initialize model and encoder
key = jax.random.PRNGKey(42)
model = create_fhrr_model(dim=2048, key=key)
memory = VSAMemory(model)
encoder = FractionalPowerEncoder(model, memory)

# Create basis vectors for color dimensions
for dim_name in ["hue", "sat", "bright"]:
    memory.add(dim_name)

# Define colors as points in 3D space
colors = {
    "purple": [6.2, -6.2, 5.3],
    "blue": [4.8, -2.1, 4.5],
    "orange": [0.9, 8.7, 6.5],
    "yellow": [2.1, 9.0, 7.8],
}

# Encode colors using FPE
color_hvs = {}
for color_name, (h, s, b) in colors.items():
    hv = encoder.encode_multi(["hue", "sat", "bright"], [h, s, b])
    color_hvs[color_name] = hv

How FPE Works for Conceptual Spaces

Fractional Power Encoding creates a hypervector for a point in n-dimensional space by:

  1. Creating a basis hypervector for each dimension (e.g., hue, sat, bright)
  2. Raising each basis to the power of the coordinate value
  3. Binding (⊛) all powered bases together

For a color at (h, s, b):

Color(h, s, b) = hue^h ⊛ sat^s ⊛ bright^b

This encoding has important properties: - Continuous: Small changes in coordinates → small changes in hypervector - Compositional: Can combine dimensions independently - Invertible: Can extract individual dimensions via unbinding

Category-Based Analogies

Category-based analogies ask: "A is to B as C is to ___?"

The parallelogram model solves this using vector arithmetic:

X = (C ⊛ A^-1) ⊛ B

This works because: - C ⊛ A^-1 captures the transformation from A to C - Applying this transformation to B yields X

Example: PURPLE : BLUE :: ORANGE : X

from vsax.representations import ComplexHypervector
from vsax.similarity import cosine_similarity

# Solve: PURPLE : BLUE :: ORANGE : X
purple_inv = model.opset.inverse(color_hvs["purple"].vec)
x_vec = model.opset.bind(color_hvs["orange"].vec, purple_inv)
x_vec = model.opset.bind(x_vec, color_hvs["blue"].vec)
x_hv = ComplexHypervector(x_vec)

# Find closest match
for color_name, color_hv in color_hvs.items():
    sim = cosine_similarity(x_hv.vec, color_hv.vec)
    print(f"{color_name}: {sim:.4f}")

# Output:
# purple: 0.5234
# blue: 0.7891
# orange: 0.6543
# yellow: 0.9432  <- Best match!

The result is YELLOW, which makes intuitive sense: - Purple → Blue: reduce saturation, slightly reduce hue - Orange → Yellow: similar transformation

Property-Based Analogies

Property-based analogies identify salient properties and transfer them between objects.

Example: "If an APPLE is RED, what color is a BANANA?"

This uses the same parallelogram approach:

# Use color hypervectors as stand-ins for objects
apple_hv = color_hvs["red"]
banana_hv = color_hvs["yellow"]

# Solve: APPLE : RED :: BANANA : X
# X = (banana ⊛ apple^-1) ⊛ red
apple_inv = model.opset.inverse(apple_hv.vec)
x_vec = model.opset.bind(banana_hv.vec, apple_inv)
x_vec = model.opset.bind(x_vec, color_hvs["red"].vec)

# Result will be closest to YELLOW

Decoding with Code Books

For fine-grained decoding, we create a code book: a dictionary mapping coordinate values to their hypervectors.

def create_color_codebook(encoder, resolution=41):
    """Create code book for color space (-10 to +10 per dimension)."""
    values = jnp.linspace(-10, 10, resolution)
    codebook = {}

    for h in values:
        for s in values:
            for b in values:
                hv = encoder.encode_multi(
                    ["hue", "sat", "bright"],
                    [float(h), float(s), float(b)]
                )
                codebook[(float(h), float(s), float(b))] = hv

    return codebook

# Create code book
codebook = create_color_codebook(encoder, resolution=21)  # 21^3 = 9261 entries

# Decode by finding nearest neighbor
def decode_hypervector(query_hv, codebook):
    best_coords = None
    best_sim = -1.0

    for coords, hv in codebook.items():
        sim = cosine_similarity(query_hv.vec, hv.vec)
        if sim > best_sim:
            best_sim = sim
            best_coords = coords

    return best_coords, best_sim

# Decode the analogy result
coords, sim = decode_hypervector(x_hv, codebook)
print(f"Decoded: hue={coords[0]:.1f}, sat={coords[1]:.1f}, bright={coords[2]:.1f}")
print(f"Similarity: {sim:.4f}")

Using Cleanup Memory for Decoding

VSAX includes CleanupMemory for projecting noisy vectors onto known codebooks:

from vsax.resonator import CleanupMemory

# Add all code book entries to memory
for coords, hv in codebook.items():
    name = f"code_{coords}"
    memory._basis[name] = hv

# Create cleanup memory
codebook_names = list(memory._basis.keys())
cleanup = CleanupMemory(codebook_names, memory, threshold=0.0)

# Query for nearest neighbor
best_name, similarity = cleanup.query(x_hv, return_similarity=True)

CleanupMemory finds the best match by computing similarity to all code book entries and returning the nearest neighbor. This is efficient for moderate-sized code books and provides exact nearest-neighbor lookup.

Improving Accuracy

The accuracy of analogical reasoning with FPE depends on several factors:

  1. Dimensionality: Higher dimensions (4096+) provide better approximation but require more memory
  2. Scale parameter: The FractionalPowerEncoder scale parameter controls the sensitivity to coordinate changes
  3. Code book resolution: Finer-grained code books improve decoding accuracy
  4. Normalization: Normalizing hypervectors after binding operations can improve similarity matching

Example with higher dimensionality and scale adjustment:

# Use higher dimensionality for better accuracy
model = create_fhrr_model(dim=4096, key=key)
encoder = FractionalPowerEncoder(model, memory, scale=0.1)

# Normalize after binding operations
x_hv = ComplexHypervector(x_vec).normalize()

Note: The example code demonstrates the approach even though numerical results may vary. The parallelogram model works best when the conceptual space geometry closely matches the hypervector algebra properties.

Complete Example

Here's a complete working example:

import jax
import jax.numpy as jnp
from vsax import VSAMemory, create_fhrr_model
from vsax.encoders.fpe import FractionalPowerEncoder
from vsax.representations import ComplexHypervector
from vsax.similarity import cosine_similarity

# Setup
key = jax.random.PRNGKey(42)
model = create_fhrr_model(dim=2048, key=key)
memory = VSAMemory(model)
encoder = FractionalPowerEncoder(model, memory)

# Create basis vectors
for dim in ["hue", "sat", "bright"]:
    memory.add(dim)

# Encode colors
colors = {
    "purple": [6.2, -6.2, 5.3],
    "blue": [4.8, -2.1, 4.5],
    "orange": [0.9, 8.7, 6.5],
    "yellow": [2.1, 9.0, 7.8],
}

color_hvs = {
    name: encoder.encode_multi(["hue", "sat", "bright"], coords)
    for name, coords in colors.items()
}

# Solve analogy: PURPLE : BLUE :: ORANGE : X
purple_inv = model.opset.inverse(color_hvs["purple"].vec)
x_vec = model.opset.bind(color_hvs["orange"].vec, purple_inv)
x_vec = model.opset.bind(x_vec, color_hvs["blue"].vec)
x_hv = ComplexHypervector(x_vec)

# Find best match
best_match = max(
    color_hvs.items(),
    key=lambda item: cosine_similarity(x_hv.vec, item[1].vec)
)

print(f"PURPLE : BLUE :: ORANGE : {best_match[0].upper()}")
# Output: PURPLE : BLUE :: ORANGE : YELLOW

Running the Full Example

VSAX includes a complete example demonstrating all concepts:

uv run python examples/analogical_reasoning.py

This example shows: - Encoding colors in 3D conceptual space - Category-based analogy (PURPLE:BLUE::ORANGE:YELLOW) - Property-based analogy (APPLE:RED::BANANA:YELLOW) - Code book creation and decoding - Similarity matrices - Visualizations of the conceptual space

Key Insights

  1. FPE enables geometric reasoning: By encoding concepts as points in continuous spaces, we can use geometric transformations (like the parallelogram model) for reasoning.

  2. Binding = geometric transformation: The binding operation captures relationships and transformations between concepts.

  3. Inverse unbinds: A^-1 reverses the binding, allowing us to extract or remove relationships.

  4. Similarity = proximity: Cosine similarity in hypervector space corresponds to proximity in conceptual space.

  5. Code books enable precise decoding: Dense sampling of the space allows mapping hypervectors back to coordinates.

Comparison with Other Approaches

Approach Strengths Limitations
FPE (this tutorial) Continuous, compositional, efficient Requires defining conceptual spaces
Word embeddings Learned from data Fixed dimensionality, not compositional
Knowledge graphs Explicit relations Discrete, no continuous properties
Neural networks Flexible, powerful Black box, computationally expensive

FPE combines the best of multiple worlds: - Continuous like embeddings - Compositional like symbolic systems - Geometric like conceptual spaces - Efficient like hyperdimensional computing

Mathematical Foundation

The parallelogram model for analogies has a solid mathematical foundation:

Given: A : B :: C : X

In conceptual space:

X = C - A + B  (vector arithmetic)

In hypervector space with FPE:

X = C ⊛ A^-1 ⊛ B  (binding operations)

Why this works: - FPE preserves geometric relationships - Binding in hypervector space ≈ vector addition in conceptual space - Inverse in hypervector space ≈ vector subtraction in conceptual space

The key insight: FPE is an approximate homomorphism between conceptual space geometry and hypervector algebra.

Extensions and Applications

This approach can be extended to:

  1. Multi-domain reasoning: Combine multiple conceptual spaces (color + size + shape)
  2. Abstract analogies: Apply to non-perceptual domains (e.g., social relationships)
  3. Concept learning: Learn new concepts from analogies
  4. Creative reasoning: Generate novel concepts via transformations
  5. Metaphor understanding: Map between distant conceptual domains

References

  • Goldowsky, H., & Sarathy, V. (2024). Analogical Reasoning Within a Conceptual Hyperspace. arXiv:2411.08684.
  • Gärdenfors, P. (2004). Conceptual Spaces: The Geometry of Thought. MIT Press.
  • Plate, T. A. (2003). Holographic Reduced Representation. CSLI Publications.
  • Komer, B., et al. (2019). A Neural Representation of Continuous Space Using Fractional Binding. CogSci.
  • Frady, E. P., et al. (2021). Computing on Functions Using Randomized Vector Representations. arXiv:2109.03429.

Next Steps

Further Reading