Skip to content

Operators API Reference

NEW in v1.1.0 - Exact, compositional, invertible transformations for reasoning.

Overview

The operators module provides Clifford-inspired operators for exact transformations in VSA reasoning.

Key classes: - CliffordOperator - Phase-based operator for FHRR hypervectors - AbstractOperator - Base interface for all operators - OperatorKind - Enum for semantic operator types - OperatorMetadata - Metadata dataclass for operators

Module Structure

vsax.operators/
├── CliffordOperator      # Core operator implementation
├── AbstractOperator      # Abstract base class
├── OperatorKind          # Semantic type enum
└── OperatorMetadata      # Metadata dataclass

Quick Reference

Creating Operators

from vsax.operators import CliffordOperator, OperatorKind
import jax

# Create random operator
op = CliffordOperator.random(
    dim=512,
    kind=OperatorKind.SPATIAL,
    name="LEFT_OF",
    key=jax.random.PRNGKey(42)
)

Applying Transformations

from vsax import create_fhrr_model, VSAMemory

model = create_fhrr_model(dim=512)
memory = VSAMemory(model)
memory.add("concept")

# Apply operator
transformed = op.apply(memory["concept"])

# Exact inversion
recovered = op.inverse().apply(transformed)

Composing Operators

# Create two operators
op1 = CliffordOperator.random(512, key=jax.random.PRNGKey(1))
op2 = CliffordOperator.random(512, key=jax.random.PRNGKey(2))

# Compose
composed = op1.compose(op2)

Detailed API

CliffordOperator

vsax.operators.clifford.CliffordOperator dataclass

Bases: AbstractOperator

Clifford-inspired operator for FHRR hypervectors.

Represents a phase-based transformation that compiles to FHRR operations. The operator applies element-wise phase rotation to complex hypervectors:

apply(v) = v * exp(i * params)

This provides exact, compositional, invertible transformations inspired by Clifford algebra, where: - Elementary operators act as bivectors (phase generators) - Composed operators act as rotors (sum of generators) - Operator composition uses phase addition - Inversion uses phase negation

The operator is compatible with FHRR's phase algebra and preserves the unit-magnitude property of complex hypervectors.

Attributes:

Name Type Description
params ndarray

Phase rotation parameters as JAX array (shape: dim). Each element specifies the phase shift for that dimension.

metadata Optional[OperatorMetadata]

Optional semantic metadata (kind, name, description).

Example

from vsax import create_fhrr_model, VSAMemory from vsax.operators import CliffordOperator import jax

model = create_fhrr_model(dim=512) memory = VSAMemory(model) memory.add("test")

Create operator

op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))

Apply transformation

transformed = op.apply(memory["test"])

Verify exact inversion

recovered = op.inverse().apply(transformed) from vsax.similarity import cosine_similarity similarity = cosine_similarity(recovered.vec, memory["test"].vec) assert similarity > 0.999 # Exact inverse

Source code in vsax/operators/clifford.py
@dataclass(frozen=True)
class CliffordOperator(AbstractOperator):
    """Clifford-inspired operator for FHRR hypervectors.

    Represents a phase-based transformation that compiles to FHRR operations.
    The operator applies element-wise phase rotation to complex hypervectors:

        apply(v) = v * exp(i * params)

    This provides exact, compositional, invertible transformations inspired
    by Clifford algebra, where:
    - Elementary operators act as bivectors (phase generators)
    - Composed operators act as rotors (sum of generators)
    - Operator composition uses phase addition
    - Inversion uses phase negation

    The operator is compatible with FHRR's phase algebra and preserves
    the unit-magnitude property of complex hypervectors.

    Attributes:
        params: Phase rotation parameters as JAX array (shape: dim).
                Each element specifies the phase shift for that dimension.
        metadata: Optional semantic metadata (kind, name, description).

    Example:
        >>> from vsax import create_fhrr_model, VSAMemory
        >>> from vsax.operators import CliffordOperator
        >>> import jax
        >>>
        >>> model = create_fhrr_model(dim=512)
        >>> memory = VSAMemory(model)
        >>> memory.add("test")
        >>>
        >>> # Create operator
        >>> op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))
        >>>
        >>> # Apply transformation
        >>> transformed = op.apply(memory["test"])
        >>>
        >>> # Verify exact inversion
        >>> recovered = op.inverse().apply(transformed)
        >>> from vsax.similarity import cosine_similarity
        >>> similarity = cosine_similarity(recovered.vec, memory["test"].vec)
        >>> assert similarity > 0.999  # Exact inverse
    """

    params: jnp.ndarray
    metadata: Optional[OperatorMetadata] = None

    def __post_init__(self) -> None:
        """Validate and convert parameters to JAX array."""
        # Ensure params is JAX array
        if not isinstance(self.params, jnp.ndarray):
            object.__setattr__(self, "params", jnp.array(self.params))

        # Validate shape
        if len(self.params.shape) != 1:
            raise ValueError(f"params must be 1-dimensional, got shape {self.params.shape}")

    @property
    def dim(self) -> int:
        """Dimensionality of operator.

        Returns:
            Integer dimension matching the hypervectors this operator
            can transform.
        """
        return int(self.params.shape[0])

    def apply(self, v: AbstractHypervector) -> ComplexHypervector:
        """Apply phase rotation to hypervector.

        Transforms the input hypervector by applying element-wise phase rotation:

            result = v * exp(i * params)

        This operation is:
        - Norm-preserving (maintains unit magnitude for FHRR)
        - Exactly invertible
        - Compatible with FHRR circular convolution

        Args:
            v: ComplexHypervector to transform. Must have same dimensionality
               as operator.

        Returns:
            Transformed ComplexHypervector with same shape as input.

        Raises:
            TypeError: If v is not a ComplexHypervector. CliffordOperator only
                       works with FHRR (complex-valued) representations.
            ValueError: If dimension of v doesn't match operator dimension.

        Example:
            >>> from vsax import create_fhrr_model, VSAMemory
            >>> from vsax.operators import CliffordOperator
            >>> import jax
            >>>
            >>> model = create_fhrr_model(dim=512)
            >>> memory = VSAMemory(model)
            >>> memory.add("test")
            >>>
            >>> op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))
            >>> transformed = op.apply(memory["test"])
            >>> print(transformed.shape)
            (512,)
        """
        if not isinstance(v, ComplexHypervector):
            raise TypeError(
                f"CliffordOperator only works with ComplexHypervector "
                f"(FHRR model), got {type(v).__name__}. "
                f"Hint: Use create_fhrr_model() to create compatible hypervectors."
            )

        if v.vec.shape[0] != self.dim:
            raise ValueError(
                f"Dimension mismatch: operator has dim={self.dim}, "
                f"hypervector has dim={v.vec.shape[0]}"
            )

        # Apply phase rotation: v * exp(i * params)
        # This is compatible with FHRR's phase-based algebra
        phase_shift = jnp.exp(1j * self.params)
        transformed = v.vec * phase_shift

        return ComplexHypervector(transformed)

    def inverse(self) -> "CliffordOperator":
        """Return exact inverse operator.

        For phase rotations, the inverse is phase negation:

            inverse(params) = -params
            exp(i * (-params)) = exp(-i * params) = conj(exp(i * params))

        This provides exact inversion with similarity > 0.999:

            op.inverse().apply(op.apply(v)) ≈ v

        Returns:
            CliffordOperator with negated phase parameters that exactly
            undoes this operator's transformation.

        Example:
            >>> from vsax import create_fhrr_model, VSAMemory
            >>> from vsax.operators import CliffordOperator
            >>> from vsax.similarity import cosine_similarity
            >>> import jax
            >>>
            >>> model = create_fhrr_model(dim=512)
            >>> memory = VSAMemory(model)
            >>> memory.add("test")
            >>>
            >>> op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))
            >>> transformed = op.apply(memory["test"])
            >>> recovered = op.inverse().apply(transformed)
            >>>
            >>> similarity = cosine_similarity(recovered.vec, memory["test"].vec)
            >>> print(f"Inversion accuracy: {similarity:.6f}")
            Inversion accuracy: 1.000000
        """
        return CliffordOperator(params=-self.params, metadata=self.metadata)

    def compose(self, other: AbstractOperator) -> "CliffordOperator":
        """Compose two operators.

        Creates a new operator that applies both transformations in sequence.
        For phase-based operators, composition uses phase addition:

            compose(op1, op2).params = op1.params + op2.params
            exp(i * (params1 + params2)) applies both rotations

        Composition is:
        - Associative: (op1 ∘ op2) ∘ op3 = op1 ∘ (op2 ∘ op3)
        - Commutative: op1 ∘ op2 = op2 ∘ op1 (for phase addition)

        Args:
            other: Another CliffordOperator to compose with. Must have
                   same dimensionality.

        Returns:
            Composed CliffordOperator representing both transformations.

        Raises:
            TypeError: If other is not a CliffordOperator.
            ValueError: If dimensions don't match.

        Example:
            >>> from vsax.operators import CliffordOperator
            >>> import jax
            >>>
            >>> op1 = CliffordOperator.random(512, name="OP1",
            ...                               key=jax.random.PRNGKey(0))
            >>> op2 = CliffordOperator.random(512, name="OP2",
            ...                               key=jax.random.PRNGKey(1))
            >>>
            >>> composed = op1.compose(op2)
            >>> print(composed.metadata.name)
            compose(OP1, OP2)
        """
        if not isinstance(other, CliffordOperator):
            raise TypeError(f"Can only compose with CliffordOperator, got {type(other).__name__}")

        if self.dim != other.dim:
            raise ValueError(
                f"Dimension mismatch: self has dim={self.dim}, other has dim={other.dim}"
            )

        # Compose by adding phases
        composed_params = self.params + other.params

        # Create metadata for composed operator
        if self.metadata or other.metadata:
            self_name = self.metadata.name if self.metadata else "op1"
            other_name = other.metadata.name if other.metadata else "op2"
            composed_metadata = OperatorMetadata(
                kind=OperatorKind.TRANSFORM,
                name=f"compose({self_name}, {other_name})",
                description="Composed operator",
            )
        else:
            composed_metadata = None

        return CliffordOperator(params=composed_params, metadata=composed_metadata)

    @staticmethod
    def random(
        dim: int,
        kind: OperatorKind = OperatorKind.GENERAL,
        name: str = "random_op",
        key: Optional[jax.Array] = None,
    ) -> "CliffordOperator":
        """Create random operator with uniform phase distribution.

        Samples phase parameters uniformly from [0, 2π) to create a random
        operator. Useful for generating basis operators for spatial relations,
        semantic roles, or other symbolic transformations.

        Args:
            dim: Dimensionality of the operator.
            kind: Semantic type of the operator (default: GENERAL).
            name: Human-readable name for the operator.
            key: JAX random key for reproducibility. If None, uses key(0).

        Returns:
            Random CliffordOperator with uniformly distributed phase parameters.

        Example:
            >>> from vsax.operators import CliffordOperator, OperatorKind
            >>> import jax
            >>>
            >>> # Create reproducible random operator
            >>> op = CliffordOperator.random(
            ...     dim=512,
            ...     kind=OperatorKind.SPATIAL,
            ...     name="LEFT_OF",
            ...     key=jax.random.PRNGKey(42)
            ... )
            >>> print(op.metadata.name)
            LEFT_OF
        """
        if key is None:
            key = jax.random.PRNGKey(0)

        # Sample uniform phases in [0, 2π)
        params = jax.random.uniform(key, (dim,), minval=0, maxval=2 * jnp.pi)

        metadata = OperatorMetadata(kind=kind, name=name)
        return CliffordOperator(params=params, metadata=metadata)

    def __repr__(self) -> str:
        """String representation of operator.

        Returns:
            String showing operator name, dimension, and kind.
        """
        name = self.metadata.name if self.metadata else "CliffordOperator"
        kind = self.metadata.kind.value if self.metadata else "unknown"
        return f"{name}(dim={self.dim}, kind={kind})"

Attributes

dim property

Dimensionality of operator.

Returns:

Type Description
int

Integer dimension matching the hypervectors this operator

int

can transform.

Functions

__init__(params, metadata=None)

apply(v)

Apply phase rotation to hypervector.

Transforms the input hypervector by applying element-wise phase rotation:

result = v * exp(i * params)

This operation is: - Norm-preserving (maintains unit magnitude for FHRR) - Exactly invertible - Compatible with FHRR circular convolution

Parameters:

Name Type Description Default
v AbstractHypervector

ComplexHypervector to transform. Must have same dimensionality as operator.

required

Returns:

Type Description
ComplexHypervector

Transformed ComplexHypervector with same shape as input.

Raises:

Type Description
TypeError

If v is not a ComplexHypervector. CliffordOperator only works with FHRR (complex-valued) representations.

ValueError

If dimension of v doesn't match operator dimension.

Example

from vsax import create_fhrr_model, VSAMemory from vsax.operators import CliffordOperator import jax

model = create_fhrr_model(dim=512) memory = VSAMemory(model) memory.add("test")

op = CliffordOperator.random(512, key=jax.random.PRNGKey(0)) transformed = op.apply(memory["test"]) print(transformed.shape) (512,)

Source code in vsax/operators/clifford.py
def apply(self, v: AbstractHypervector) -> ComplexHypervector:
    """Apply phase rotation to hypervector.

    Transforms the input hypervector by applying element-wise phase rotation:

        result = v * exp(i * params)

    This operation is:
    - Norm-preserving (maintains unit magnitude for FHRR)
    - Exactly invertible
    - Compatible with FHRR circular convolution

    Args:
        v: ComplexHypervector to transform. Must have same dimensionality
           as operator.

    Returns:
        Transformed ComplexHypervector with same shape as input.

    Raises:
        TypeError: If v is not a ComplexHypervector. CliffordOperator only
                   works with FHRR (complex-valued) representations.
        ValueError: If dimension of v doesn't match operator dimension.

    Example:
        >>> from vsax import create_fhrr_model, VSAMemory
        >>> from vsax.operators import CliffordOperator
        >>> import jax
        >>>
        >>> model = create_fhrr_model(dim=512)
        >>> memory = VSAMemory(model)
        >>> memory.add("test")
        >>>
        >>> op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))
        >>> transformed = op.apply(memory["test"])
        >>> print(transformed.shape)
        (512,)
    """
    if not isinstance(v, ComplexHypervector):
        raise TypeError(
            f"CliffordOperator only works with ComplexHypervector "
            f"(FHRR model), got {type(v).__name__}. "
            f"Hint: Use create_fhrr_model() to create compatible hypervectors."
        )

    if v.vec.shape[0] != self.dim:
        raise ValueError(
            f"Dimension mismatch: operator has dim={self.dim}, "
            f"hypervector has dim={v.vec.shape[0]}"
        )

    # Apply phase rotation: v * exp(i * params)
    # This is compatible with FHRR's phase-based algebra
    phase_shift = jnp.exp(1j * self.params)
    transformed = v.vec * phase_shift

    return ComplexHypervector(transformed)

inverse()

Return exact inverse operator.

For phase rotations, the inverse is phase negation:

inverse(params) = -params
exp(i * (-params)) = exp(-i * params) = conj(exp(i * params))

This provides exact inversion with similarity > 0.999:

op.inverse().apply(op.apply(v)) ≈ v

Returns:

Type Description
CliffordOperator

CliffordOperator with negated phase parameters that exactly

CliffordOperator

undoes this operator's transformation.

Example

from vsax import create_fhrr_model, VSAMemory from vsax.operators import CliffordOperator from vsax.similarity import cosine_similarity import jax

model = create_fhrr_model(dim=512) memory = VSAMemory(model) memory.add("test")

op = CliffordOperator.random(512, key=jax.random.PRNGKey(0)) transformed = op.apply(memory["test"]) recovered = op.inverse().apply(transformed)

similarity = cosine_similarity(recovered.vec, memory["test"].vec) print(f"Inversion accuracy: {similarity:.6f}") Inversion accuracy: 1.000000

Source code in vsax/operators/clifford.py
def inverse(self) -> "CliffordOperator":
    """Return exact inverse operator.

    For phase rotations, the inverse is phase negation:

        inverse(params) = -params
        exp(i * (-params)) = exp(-i * params) = conj(exp(i * params))

    This provides exact inversion with similarity > 0.999:

        op.inverse().apply(op.apply(v)) ≈ v

    Returns:
        CliffordOperator with negated phase parameters that exactly
        undoes this operator's transformation.

    Example:
        >>> from vsax import create_fhrr_model, VSAMemory
        >>> from vsax.operators import CliffordOperator
        >>> from vsax.similarity import cosine_similarity
        >>> import jax
        >>>
        >>> model = create_fhrr_model(dim=512)
        >>> memory = VSAMemory(model)
        >>> memory.add("test")
        >>>
        >>> op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))
        >>> transformed = op.apply(memory["test"])
        >>> recovered = op.inverse().apply(transformed)
        >>>
        >>> similarity = cosine_similarity(recovered.vec, memory["test"].vec)
        >>> print(f"Inversion accuracy: {similarity:.6f}")
        Inversion accuracy: 1.000000
    """
    return CliffordOperator(params=-self.params, metadata=self.metadata)

compose(other)

Compose two operators.

Creates a new operator that applies both transformations in sequence. For phase-based operators, composition uses phase addition:

compose(op1, op2).params = op1.params + op2.params
exp(i * (params1 + params2)) applies both rotations

Composition is: - Associative: (op1 ∘ op2) ∘ op3 = op1 ∘ (op2 ∘ op3) - Commutative: op1 ∘ op2 = op2 ∘ op1 (for phase addition)

Parameters:

Name Type Description Default
other AbstractOperator

Another CliffordOperator to compose with. Must have same dimensionality.

required

Returns:

Type Description
CliffordOperator

Composed CliffordOperator representing both transformations.

Raises:

Type Description
TypeError

If other is not a CliffordOperator.

ValueError

If dimensions don't match.

Example

from vsax.operators import CliffordOperator import jax

op1 = CliffordOperator.random(512, name="OP1", ... key=jax.random.PRNGKey(0)) op2 = CliffordOperator.random(512, name="OP2", ... key=jax.random.PRNGKey(1))

composed = op1.compose(op2) print(composed.metadata.name) compose(OP1, OP2)

Source code in vsax/operators/clifford.py
def compose(self, other: AbstractOperator) -> "CliffordOperator":
    """Compose two operators.

    Creates a new operator that applies both transformations in sequence.
    For phase-based operators, composition uses phase addition:

        compose(op1, op2).params = op1.params + op2.params
        exp(i * (params1 + params2)) applies both rotations

    Composition is:
    - Associative: (op1 ∘ op2) ∘ op3 = op1 ∘ (op2 ∘ op3)
    - Commutative: op1 ∘ op2 = op2 ∘ op1 (for phase addition)

    Args:
        other: Another CliffordOperator to compose with. Must have
               same dimensionality.

    Returns:
        Composed CliffordOperator representing both transformations.

    Raises:
        TypeError: If other is not a CliffordOperator.
        ValueError: If dimensions don't match.

    Example:
        >>> from vsax.operators import CliffordOperator
        >>> import jax
        >>>
        >>> op1 = CliffordOperator.random(512, name="OP1",
        ...                               key=jax.random.PRNGKey(0))
        >>> op2 = CliffordOperator.random(512, name="OP2",
        ...                               key=jax.random.PRNGKey(1))
        >>>
        >>> composed = op1.compose(op2)
        >>> print(composed.metadata.name)
        compose(OP1, OP2)
    """
    if not isinstance(other, CliffordOperator):
        raise TypeError(f"Can only compose with CliffordOperator, got {type(other).__name__}")

    if self.dim != other.dim:
        raise ValueError(
            f"Dimension mismatch: self has dim={self.dim}, other has dim={other.dim}"
        )

    # Compose by adding phases
    composed_params = self.params + other.params

    # Create metadata for composed operator
    if self.metadata or other.metadata:
        self_name = self.metadata.name if self.metadata else "op1"
        other_name = other.metadata.name if other.metadata else "op2"
        composed_metadata = OperatorMetadata(
            kind=OperatorKind.TRANSFORM,
            name=f"compose({self_name}, {other_name})",
            description="Composed operator",
        )
    else:
        composed_metadata = None

    return CliffordOperator(params=composed_params, metadata=composed_metadata)

random(dim, kind=OperatorKind.GENERAL, name='random_op', key=None) staticmethod

Create random operator with uniform phase distribution.

Samples phase parameters uniformly from [0, 2π) to create a random operator. Useful for generating basis operators for spatial relations, semantic roles, or other symbolic transformations.

Parameters:

Name Type Description Default
dim int

Dimensionality of the operator.

required
kind OperatorKind

Semantic type of the operator (default: GENERAL).

GENERAL
name str

Human-readable name for the operator.

'random_op'
key Optional[Array]

JAX random key for reproducibility. If None, uses key(0).

None

Returns:

Type Description
CliffordOperator

Random CliffordOperator with uniformly distributed phase parameters.

Example

from vsax.operators import CliffordOperator, OperatorKind import jax

Create reproducible random operator

op = CliffordOperator.random( ... dim=512, ... kind=OperatorKind.SPATIAL, ... name="LEFT_OF", ... key=jax.random.PRNGKey(42) ... ) print(op.metadata.name) LEFT_OF

Source code in vsax/operators/clifford.py
@staticmethod
def random(
    dim: int,
    kind: OperatorKind = OperatorKind.GENERAL,
    name: str = "random_op",
    key: Optional[jax.Array] = None,
) -> "CliffordOperator":
    """Create random operator with uniform phase distribution.

    Samples phase parameters uniformly from [0, 2π) to create a random
    operator. Useful for generating basis operators for spatial relations,
    semantic roles, or other symbolic transformations.

    Args:
        dim: Dimensionality of the operator.
        kind: Semantic type of the operator (default: GENERAL).
        name: Human-readable name for the operator.
        key: JAX random key for reproducibility. If None, uses key(0).

    Returns:
        Random CliffordOperator with uniformly distributed phase parameters.

    Example:
        >>> from vsax.operators import CliffordOperator, OperatorKind
        >>> import jax
        >>>
        >>> # Create reproducible random operator
        >>> op = CliffordOperator.random(
        ...     dim=512,
        ...     kind=OperatorKind.SPATIAL,
        ...     name="LEFT_OF",
        ...     key=jax.random.PRNGKey(42)
        ... )
        >>> print(op.metadata.name)
        LEFT_OF
    """
    if key is None:
        key = jax.random.PRNGKey(0)

    # Sample uniform phases in [0, 2π)
    params = jax.random.uniform(key, (dim,), minval=0, maxval=2 * jnp.pi)

    metadata = OperatorMetadata(kind=kind, name=name)
    return CliffordOperator(params=params, metadata=metadata)

AbstractOperator

vsax.operators.base.AbstractOperator

Bases: ABC

Abstract base class for all operators.

Operators provide exact, compositional, invertible transformations for hypervectors. They represent "what happens" in a VSA system, while hypervectors represent "what exists".

All concrete operator implementations must inherit from this class and implement the abstract methods: apply(), inverse(), and compose().

Example

from vsax.operators import CliffordOperator import jax

Create operator

op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))

Apply to hypervector

transformed = op.apply(hypervector)

Invert

original = op.inverse().apply(transformed)

Source code in vsax/operators/base.py
class AbstractOperator(ABC):
    """Abstract base class for all operators.

    Operators provide exact, compositional, invertible transformations
    for hypervectors. They represent "what happens" in a VSA system,
    while hypervectors represent "what exists".

    All concrete operator implementations must inherit from this class
    and implement the abstract methods: apply(), inverse(), and compose().

    Example:
        >>> from vsax.operators import CliffordOperator
        >>> import jax
        >>>
        >>> # Create operator
        >>> op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))
        >>>
        >>> # Apply to hypervector
        >>> transformed = op.apply(hypervector)
        >>>
        >>> # Invert
        >>> original = op.inverse().apply(transformed)
    """

    @abstractmethod
    def apply(self, v: AbstractHypervector) -> AbstractHypervector:
        """Apply operator to hypervector.

        Transforms the input hypervector according to the operator's
        transformation rule. The specific transformation depends on the
        concrete operator implementation.

        Args:
            v: Hypervector to transform.

        Returns:
            Transformed hypervector of the same type as input.

        Raises:
            TypeError: If input hypervector type is not supported.
            ValueError: If dimensions don't match.
        """
        pass

    @abstractmethod
    def inverse(self) -> "AbstractOperator":
        """Return exact inverse operator.

        The inverse operator undoes the transformation of the original
        operator. For exact operators:

            op.inverse().apply(op.apply(v)) ≈ v

        with high precision (similarity > 0.999).

        Returns:
            Inverse operator that undoes this operator's transformation.
        """
        pass

    @abstractmethod
    def compose(self, other: "AbstractOperator") -> "AbstractOperator":
        """Compose with another operator.

        Creates a new operator that applies both transformations in sequence:

            composed = self.compose(other)
            composed.apply(v) ≈ self.apply(other.apply(v))

        Composition order follows mathematical convention (self ∘ other).

        Args:
            other: Operator to compose with.

        Returns:
            Composed operator representing both transformations.

        Raises:
            TypeError: If other is not compatible operator type.
            ValueError: If dimensions don't match.
        """
        pass

    @property
    @abstractmethod
    def dim(self) -> int:
        """Dimensionality of operator.

        Returns:
            Integer dimensionality that matches the hypervectors
            this operator can transform.
        """
        pass

Attributes

dim abstractmethod property

Dimensionality of operator.

Returns:

Type Description
int

Integer dimensionality that matches the hypervectors

int

this operator can transform.

Functions

apply(v) abstractmethod

Apply operator to hypervector.

Transforms the input hypervector according to the operator's transformation rule. The specific transformation depends on the concrete operator implementation.

Parameters:

Name Type Description Default
v AbstractHypervector

Hypervector to transform.

required

Returns:

Type Description
AbstractHypervector

Transformed hypervector of the same type as input.

Raises:

Type Description
TypeError

If input hypervector type is not supported.

ValueError

If dimensions don't match.

Source code in vsax/operators/base.py
@abstractmethod
def apply(self, v: AbstractHypervector) -> AbstractHypervector:
    """Apply operator to hypervector.

    Transforms the input hypervector according to the operator's
    transformation rule. The specific transformation depends on the
    concrete operator implementation.

    Args:
        v: Hypervector to transform.

    Returns:
        Transformed hypervector of the same type as input.

    Raises:
        TypeError: If input hypervector type is not supported.
        ValueError: If dimensions don't match.
    """
    pass

inverse() abstractmethod

Return exact inverse operator.

The inverse operator undoes the transformation of the original operator. For exact operators:

op.inverse().apply(op.apply(v)) ≈ v

with high precision (similarity > 0.999).

Returns:

Type Description
AbstractOperator

Inverse operator that undoes this operator's transformation.

Source code in vsax/operators/base.py
@abstractmethod
def inverse(self) -> "AbstractOperator":
    """Return exact inverse operator.

    The inverse operator undoes the transformation of the original
    operator. For exact operators:

        op.inverse().apply(op.apply(v)) ≈ v

    with high precision (similarity > 0.999).

    Returns:
        Inverse operator that undoes this operator's transformation.
    """
    pass

compose(other) abstractmethod

Compose with another operator.

Creates a new operator that applies both transformations in sequence:

composed = self.compose(other)
composed.apply(v) ≈ self.apply(other.apply(v))

Composition order follows mathematical convention (self ∘ other).

Parameters:

Name Type Description Default
other AbstractOperator

Operator to compose with.

required

Returns:

Type Description
AbstractOperator

Composed operator representing both transformations.

Raises:

Type Description
TypeError

If other is not compatible operator type.

ValueError

If dimensions don't match.

Source code in vsax/operators/base.py
@abstractmethod
def compose(self, other: "AbstractOperator") -> "AbstractOperator":
    """Compose with another operator.

    Creates a new operator that applies both transformations in sequence:

        composed = self.compose(other)
        composed.apply(v) ≈ self.apply(other.apply(v))

    Composition order follows mathematical convention (self ∘ other).

    Args:
        other: Operator to compose with.

    Returns:
        Composed operator representing both transformations.

    Raises:
        TypeError: If other is not compatible operator type.
        ValueError: If dimensions don't match.
    """
    pass

OperatorKind

vsax.operators.kinds.OperatorKind

Bases: Enum

Semantic types for operators.

Operator kinds provide semantic metadata inspired by Clifford algebra grades. They help categorize operators by their intended use and transformation type.

Attributes:

Name Type Description
RELATION

Semantic or abstract relations (e.g., graph edges, roles).

TRANSFORM

Geometric transformations (e.g., rotations, reflections).

LOGICAL

Logical operations and constraints.

SPATIAL

Spatial relations (e.g., LEFT_OF, ABOVE, NEAR).

TEMPORAL

Temporal relations and sequences.

SEMANTIC

Semantic roles (e.g., AGENT, PATIENT, THEME).

GENERAL

General-purpose operators without specific semantics.

Example

from vsax.operators import OperatorKind, CliffordOperator import jax

op = CliffordOperator.random( ... dim=512, ... kind=OperatorKind.SPATIAL, ... name="LEFT_OF", ... key=jax.random.PRNGKey(0) ... ) print(op.metadata.kind) OperatorKind.SPATIAL

Source code in vsax/operators/kinds.py
class OperatorKind(Enum):
    """Semantic types for operators.

    Operator kinds provide semantic metadata inspired by Clifford algebra grades.
    They help categorize operators by their intended use and transformation type.

    Attributes:
        RELATION: Semantic or abstract relations (e.g., graph edges, roles).
        TRANSFORM: Geometric transformations (e.g., rotations, reflections).
        LOGICAL: Logical operations and constraints.
        SPATIAL: Spatial relations (e.g., LEFT_OF, ABOVE, NEAR).
        TEMPORAL: Temporal relations and sequences.
        SEMANTIC: Semantic roles (e.g., AGENT, PATIENT, THEME).
        GENERAL: General-purpose operators without specific semantics.

    Example:
        >>> from vsax.operators import OperatorKind, CliffordOperator
        >>> import jax
        >>>
        >>> op = CliffordOperator.random(
        ...     dim=512,
        ...     kind=OperatorKind.SPATIAL,
        ...     name="LEFT_OF",
        ...     key=jax.random.PRNGKey(0)
        ... )
        >>> print(op.metadata.kind)
        OperatorKind.SPATIAL
    """

    RELATION = "relation"
    TRANSFORM = "transform"
    LOGICAL = "logical"
    SPATIAL = "spatial"
    TEMPORAL = "temporal"
    SEMANTIC = "semantic"
    GENERAL = "general"

OperatorMetadata

vsax.operators.kinds.OperatorMetadata dataclass

Optional metadata for operators.

Provides semantic information about an operator, including its kind, name, description, and properties. This metadata helps with debugging, visualization, and understanding operator compositions.

Attributes:

Name Type Description
kind OperatorKind

Semantic type of the operator.

name str

Human-readable name for the operator.

description Optional[str]

Optional detailed description of what the operator does.

invertible bool

Whether the operator has an exact inverse (default: True).

commutative bool

Whether the operator commutes with others (default: False).

Example

from vsax.operators import OperatorMetadata, OperatorKind

metadata = OperatorMetadata( ... kind=OperatorKind.SPATIAL, ... name="LEFT_OF", ... description="Spatial relation: object A is left of object B", ... invertible=True, ... commutative=False ... ) print(metadata.name) LEFT_OF

Source code in vsax/operators/kinds.py
@dataclass(frozen=True)
class OperatorMetadata:
    """Optional metadata for operators.

    Provides semantic information about an operator, including its kind,
    name, description, and properties. This metadata helps with debugging,
    visualization, and understanding operator compositions.

    Attributes:
        kind: Semantic type of the operator.
        name: Human-readable name for the operator.
        description: Optional detailed description of what the operator does.
        invertible: Whether the operator has an exact inverse (default: True).
        commutative: Whether the operator commutes with others (default: False).

    Example:
        >>> from vsax.operators import OperatorMetadata, OperatorKind
        >>>
        >>> metadata = OperatorMetadata(
        ...     kind=OperatorKind.SPATIAL,
        ...     name="LEFT_OF",
        ...     description="Spatial relation: object A is left of object B",
        ...     invertible=True,
        ...     commutative=False
        ... )
        >>> print(metadata.name)
        LEFT_OF
    """

    kind: OperatorKind
    name: str
    description: Optional[str] = None
    invertible: bool = True
    commutative: bool = False

Attributes

kind instance-attribute

name instance-attribute

description = None class-attribute instance-attribute

invertible = True class-attribute instance-attribute

commutative = False class-attribute instance-attribute

Usage Examples

Spatial Reasoning

from vsax import create_fhrr_model, VSAMemory
from vsax.operators import CliffordOperator, OperatorKind
from vsax.similarity import cosine_similarity
import jax

# Setup
model = create_fhrr_model(dim=512)
memory = VSAMemory(model)
memory.add_many(["cup", "plate", "table"])

# Create spatial operators
LEFT_OF = CliffordOperator.random(
    512, kind=OperatorKind.SPATIAL, name="LEFT_OF", key=jax.random.PRNGKey(100)
)
RIGHT_OF = LEFT_OF.inverse()

# Encode: "cup LEFT_OF plate"
scene = model.opset.bundle(
    memory["cup"].vec,
    LEFT_OF.apply(memory["plate"]).vec
)

# Query: What's LEFT_OF plate?
answer = RIGHT_OF.apply(model.rep_cls(scene))
similarity = cosine_similarity(answer.vec, memory["cup"].vec)
print(f"Similarity to 'cup': {similarity:.3f}")  # High similarity

Semantic Roles

# Create semantic operators
AGENT = CliffordOperator.random(
    512, kind=OperatorKind.SEMANTIC, name="AGENT", key=jax.random.PRNGKey(200)
)
PATIENT = CliffordOperator.random(
    512, kind=OperatorKind.SEMANTIC, name="PATIENT", key=jax.random.PRNGKey(201)
)

memory.add_many(["dog", "cat", "chase"])

# Encode: "dog chases cat"
sentence = model.opset.bundle(
    AGENT.apply(memory["dog"]).vec,
    memory["chase"].vec,
    PATIENT.apply(memory["cat"]).vec
)

# Query: Who is the AGENT?
who = AGENT.inverse().apply(model.rep_cls(sentence))
similarity = cosine_similarity(who.vec, memory["dog"].vec)
print(f"AGENT is 'dog': {similarity:.3f}")  # High similarity

Operator Composition

# Compose spatial relations
left_and_up = LEFT_OF.compose(ABOVE)

# Apply composed transformation
transformed = left_and_up.apply(memory["origin"])

# Exact inverse
recovered = left_and_up.inverse().apply(transformed)
similarity = cosine_similarity(recovered.vec, memory["origin"].vec)
print(f"Recovery: {similarity:.6f}")  # > 0.999

Properties

Exact Inversion

CliffordOperator provides exact inversion with similarity > 0.999:

op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))
hv = memory["test"]

transformed = op.apply(hv)
recovered = op.inverse().apply(transformed)

similarity = cosine_similarity(recovered.vec, hv.vec)
assert similarity > 0.999  # Exact recovery

Associativity

Composition is associative:

op1 = CliffordOperator.random(512, key=jax.random.PRNGKey(1))
op2 = CliffordOperator.random(512, key=jax.random.PRNGKey(2))
op3 = CliffordOperator.random(512, key=jax.random.PRNGKey(3))

hv = memory["test"]

# (op1 ∘ op2) ∘ op3
left = op1.compose(op2).compose(op3).apply(hv)

# op1 ∘ (op2 ∘ op3)
right = op1.compose(op2.compose(op3)).apply(hv)

similarity = cosine_similarity(left.vec, right.vec)
assert similarity > 0.999  # Associative

Commutativity

For phase-based operators, composition is commutative:

# op1 ∘ op2
comp_12 = op1.compose(op2).apply(hv)

# op2 ∘ op1
comp_21 = op2.compose(op1).apply(hv)

similarity = cosine_similarity(comp_12.vec, comp_21.vec)
assert similarity > 0.999  # Commutative

Norm Preservation

Operators preserve the unit magnitude of FHRR vectors:

hv = memory["test"]
transformed = op.apply(hv)

# Both have unit magnitude
assert jnp.allclose(jnp.abs(hv.vec), 1.0, atol=1e-5)
assert jnp.allclose(jnp.abs(transformed.vec), 1.0, atol=1e-5)

Type Safety

CliffordOperator only works with ComplexHypervector (FHRR):

from vsax.representations import ComplexHypervector, RealHypervector

# Works with ComplexHypervector ✅
complex_hv = memory["test"]  # ComplexHypervector from FHRR model
result = op.apply(complex_hv)

# Error with other types ❌
real_hv = RealHypervector(jnp.ones(512))
result = op.apply(real_hv)  # TypeError with helpful message

Performance

Computational Complexity

Operation Complexity JAX-native GPU-accelerated
apply() O(dim)
inverse() O(dim)
compose() O(dim)

Test Coverage

  • 96% coverage on CliffordOperator module
  • 23 comprehensive tests covering all properties
  • Properties tested: inversion, composition, associativity, commutativity, type safety

Design Principles

JAX-Native

All operations use JAX for GPU acceleration:

import jax

# JIT-compile operator application
@jax.jit
def transform(op, hv):
    return op.apply(hv)

# GPU-accelerated
result = transform(op, memory["test"])

Immutable

Operators are immutable (frozen dataclasses):

op = CliffordOperator.random(512, key=jax.random.PRNGKey(0))

# Cannot modify ❌
# op.params = new_params  # Raises FrozenInstanceError

# Create new operator instead ✅
new_op = CliffordOperator(params=new_params)

FHRR-Compatible

Operators compile to FHRR's phase algebra:

# Phase-based implementation
# apply(v) = v * exp(i * params)

# Compatible with FHRR circular convolution
bound = model.opset.bind(
    op.apply(hv1).vec,
    hv2.vec
)

Comparison with Other Approaches

VSA Bundling

Aspect Bundling CliffordOperator
Inversion ~0.6-0.7 similarity >0.999 similarity
Directionality Lost Preserved
Use case Symmetric relations Asymmetric transformations
Example "dog AND cat" "dog CHASES cat"

Other VSA Libraries

VSAX is the first VSA library to provide: - Clifford-inspired operators with exact inversion - Compositional algebra for transformations - Semantic typing with OperatorKind enum - Full integration with VSA operations

Future Extensions

Planned for future releases:

  • Pre-defined spatial operators (LEFT_OF, ABOVE, NEAR, etc.)
  • Pre-defined semantic operators (AGENT, PATIENT, THEME, etc.)
  • Operator learning from data
  • Batch operator application with vmap
  • Non-commutative operators for sequences
  • Visualization tools

References

Clifford Algebra: - Hestenes & Sobczyk (1984) - "Clifford Algebra to Geometric Calculus" - Dorst et al. (2007) - "Geometric Algebra for Computer Science"

VSA Theory: - Kanerva (2009) - "Hyperdimensional Computing" - Plate (1995) - "Holographic Reduced Representations" - Gayler (2004) - "Vector Symbolic Architectures answer Jackendoff's challenges"