Unary Operations
Unary operations transform a single hypervector, with no second operand. PyHDC
defines four: permute, inverse, negative, and normalize. Each is a
method on Encoding, mirrored on Hypervector, and
exported as a module-level function (pyhdc.permute(), pyhdc.inverse(),
pyhdc.negative(), pyhdc.normalize()). All four operate dimension-first
(axis 0 is the dimension D) and broadcast over any trailing batch axes, so a
(D,) vector and a (D, N) batch are handled the same way.
permute is defined for every encoding. inverse, negative, and
normalize are family-specific: an encoding wires each one only where its
algebra defines it, and the call raises NotImplementedError otherwise. An
exception raise marks an operation the encoding does not support rather than returning a wrong
result. The component function behind each operation, per family, is in the
support table on The components Submodule.
Permutation
Available for: every encoding
Permutation cyclically shifts a hypervector along axis 0, the dimension axis. It
is encoding-agnostic: every encoding uses the same CyclicShift, so permute
is defined everywhere. A shift of one position maps coordinate \(i\) to
coordinate \((i + 1) \bmod D\):
The permutation by \(k\) positions is a bijection on the \(D\) coordinates, so it preserves both the set of element values and the vector’s norm. A permuted vector is close to orthogonal to the original, which is what makes permutation useful for marking position and structure.
Sequence and structure encoding. Permutation gives you a position marker
that does not depend on any second operand. Permuting a symbol by its index
before bundling distinguishes [a, b, c] from [c, b, a]: the same three
symbols at different positions produce different bundle results because each
is shifted by a different amount. The same mechanism tags roles in a structure
(permute the filler before binding it to its slot), so order survives the
collapse into a single hypervector.
Right-shift and left-shift operators. Hypervector exposes permutation
through the shift operators. a >> k permutes a by +k positions and
a << k permutes by -k positions:
import pyhdc
enc = pyhdc.MAP_I(dimension=10_000)
a = enc.generate() # (10000,)
shifted = a >> 3 # permute by +3
restored = shifted << 3 # permute by -3, exact inverse
The shift count \(k\) must be a Python or numpy integer, a bool or a
float is rejected and Python raises TypeError. The operators dispatch
to pyhdc.permute(), so a >> k is identical to
enc.permute(a, shift=k) and a << k to enc.permute(a, shift=-k).
Left-shift inverts right-shift exactly. Because cyclic shift is a bijection, shifting by \(-k\) undoes shifting by \(+k\) with no approximation:
So (a >> k) << k returns the original vector for every encoding and every
integer \(k\).
Inverse
inverse returns the binding inverse of a hypervector: the operand that
unbinds it. The ~a operator routes to pyhdc.inverse(). The inverse is
family-specific, because each binding rule inverts differently:
Self-inverse multiply and XOR (
IdentityInverse): the element is its own inverse, soinverse(a)returnsaunchanged. Used byMAP_I,MAP_I_Bits,MAP_B, andBSC, where binding by a bipolar or binary vector is exactly undone by binding again.Circular convolution (
ReverseInverse): keep coordinate 0 and reverse the remaining coordinates along axis 0, the exact involution inverse of convolution. Used byHRR,HRR_NoNorm, andHRR_ConstNorm.Angle binding (
PhaseNegate): negate the phase modulo \(2\pi\). Used byFHRR.
MAP_C does not define inverse: its elements are continuous on
\([-1, 1]\), so element-wise multiply is not exactly self-inverse. VTB,
MBAT, and the four BSDC variants also leave it unset, so ~a on those
raises NotImplementedError.
Negative
negative returns the bundling (additive) inverse through Negate,
element-wise negation. Bundling a vector with its negative cancels that vector’s
contribution to a superposition, which is what makes it the additive inverse.
negative is defined for the MAP family (MAP_C, MAP_I, MAP_I_Bits,
MAP_B), the HRR family (HRR, HRR_NoNorm, HRR_ConstNorm), VTB,
and MBAT. FHRR (a phase has no additive inverse), BSC, and the BSDC
variants do not define it.
Normalize
normalize maps a hypervector back to its encoding’s entry element
distribution. The rule depends on the family:
MAP (
SignNormalize): take the sign, sending integer or clipped sums back to bipolar{-1, 0, +1}. Used byMAP_C,MAP_I,MAP_I_Bits, andMAP_B.HRR family, VTB, MBAT (
L2Normalize): scale each vector to unit L2 length along axis 0, the form cosine similarity expects.FHRR (
WrapPhase): wrap phases into the \([-\pi, \pi)\) range.
BSC and the BSDC variants do not define normalize.
See also
How to Encode Sequences with Permutation : encoding ordered sequences and structures with permutation.
How to Use Operator Syntax : the
~,>>, and<<operators and the operands they accept.The components Submodule : the per-family component support table.