Encode
A number becomes a face with its value encoded as phase — value in, phase out, deterministic. A symbol gets a salted hash-based random signature.
Phasor is a Vector Symbolic Architecture (VSA) codec for .NET. Tokens — numbers and text — become bundles of unit complex numbers called phasors. Bind, unbind, bundle, and correlate form the complete algebra: arithmetic is encoding, not calculation. It's the base package the rest of the Evaluated Applications stack (AlgFormer, HoloDb, HoloVoxel) is built on.
dotnet add package EvaluatedApplications.Phasorinstall, then this
dotnet add package EvaluatedApplications.Phasorusing Phasor;
// Encode a number and a symbol
double[] five = PhasorCodec.Encode("5");
double[] greeting = PhasorCodec.Encode("hello");
// Bind two numbers: adds them on the linear band
double[] fivePlusThree = PhasorCodec.Bind(five, PhasorCodec.Encode("3"));
int sum = PhasorCodec.DecodeSum(fivePlusThree, max: 10); // sum == 8numbers and symbols, one algebra
Symbolic and numeric data are usually kept separate: numbers flow through arithmetic circuits, symbols through lookup tables. Phasor bridges them. Bind two numbers on the linear band and you add them; bind on the log band and you multiply them. A symbol encodes to a fixed random phasor. Now both live in the same algebra — you can store them together, mix them, and read values back by correlation. This is the substrate for exact storage (no floating-point error in bundle/delete), similarity search at scale, and models that reason over both values and symbols with the same composition operators.
two operations
A number becomes a face with its value encoded as phase — value in, phase out, deterministic. A symbol gets a salted hash-based random signature.
Bind (complex multiply per component) builds relationships; bundle (sum) collects sets or superpositions; unbind (conjugate) extracts parts exactly; readout by correlation gives a dot-product score. On the linear band, bind is addition; on the log band, it's multiplication — there is no separate calculator, arithmetic is the composition.
pick the one that matches your workload
Fixed-width (256 reals) with a frozen identity prefix and a learned orbital tail. Built for neural models: the frozen part keeps values exact while the tail learns meaning downstream.
Configurable width, SIMD (Vector<double>), a planar layout (reals,
then imags) with a memoized number cache. Built for holographic storage and similarity search at scale.
Do not mix faces between the two profiles — they use different layouts and are not interchangeable inputs to the same op.
what you get
Bind, unbind, bundle and readout work the same way on numbers and symbols.
Bundle and unbind are exact; subtraction removes a contribution with no floating-point error.
Only .NET System and System.Numerics — no external libraries.
Works with ahead-of-time compilation and tree-shaking, no reflection tricks.
Symbols encode to repeatable, salted phasor signatures — reproducible, not cryptographic.
HoloCodec caches number faces to speed up repeated decodes.
new in v1.3.0 · a guide to the type
The Hologram type wraps a phasor face (a double[]) and applies the algebra
through operators for clarity, correctness, and expressiveness. It is built for readability and
prototyping, making the phasor algebra feel natural without sacrificing its power.
A hologram is a single phasor face with its layout reference built in. Where
PhasorCodec.Bind(a, b) is a static method call, (Hologram)a * (Hologram)b
reads as "bind a and b," and the operator machinery ensures you are working in the right layout and
applying the right semantics. The type is a readonly struct wrapping a double[], so it
converts freely to and from arrays without copying—use it for clarity, drop back to
double[] where raw performance matters.
*) — per-component complex multiply. On the linear
band, two numbers bind and their values add; on the log band, they multiply. A
symbol's bind gives you a composed relationship, and unbinding retrieves it.+) — component-wise sum. Merge multiple holograms into
one superposition: bind + unbind of constituents retrieves them losslessly (set-forming
operation)./) — multiply by the conjugate, the inverse of bind.
Extract a component: record / key gives you what was bound with key..Correlate(other)) — dot product. Measure how much of
one hologram is present in another: high correlation means strong association, near-zero means
unrelated.~) — flip the sign of imaginary parts. Undoes a
bind or unbind; a * ~a approximates identity.There is no separate arithmetic system—composition is how values and symbols are combined. This is the algebra's power: one operator set works on numbers and text and their mixtures.
Here is a record—a superposition of field-value pairs—built, stored, and retrieved:
using Phasor;
var dim = 256; // Hologram default dimension
// Create a record by binding roles (keys) to values and bundling
var name_role = Hologram.FromSymbol("name", dim);
var lily = Hologram.FromSymbol("Lily", dim);
var name_lily = name_role * lily; // bind: compose role and value
var age_role = Hologram.FromSymbol("age", dim);
var seven = Hologram.FromNumber(7, dim);
var age_seven = age_role * seven; // bind: compose role and numeric value
var record = Hologram.Zero(dim) + name_lily + age_seven; // bundle into superposition
// Extract and correlate
var name_extracted = record / name_role; // unbind: divide out the role
var age_extracted = record / age_role;
double corr_lily = name_extracted.Correlate(lily);
double corr_john = name_extracted.Correlate(Hologram.FromSymbol("John", dim));
Console.WriteLine($"Name field has Lily: {corr_lily:F2}");
Console.WriteLine($"Name field has John: {corr_john:F2}");
double corr_seven = age_extracted.Correlate(seven);
double corr_five = age_extracted.Correlate(Hologram.FromNumber(5, dim));
Console.WriteLine($"Age field has 7: {corr_seven:F2}");
Console.WriteLine($"Age field has 5: {corr_five:F2}");Name field has Lily: 128.59
Name field has John: -1.96
Age field has 7: 32.59
Age field has 5: 13.39Read those four numbers carefully, because the two fields behave differently and the difference is the most useful thing on this page.
The name field separates completely: 128.59 for the right value against -1.96 for the wrong one. Two symbols get independent random signatures, so an unrelated symbol correlates at the noise floor, near zero.
The age field separates by less than 3x: 32.59 for 7 against 13.39 for 5. That
is not a weaker implementation, it is the codec telling the truth. A number is not encoded as a
random signature, it is encoded as a phase proportional to its value, so 5 and 7 genuinely are
similar faces and 5 and 500 are not. Numbers carry a metric; symbols do not. If you want numbers to
behave like symbols, encode them with FromSymbol("7") instead of
FromNumber(7), and you give up arithmetic to get it.
So the honest rule is that correlation separates signal from noise for symbols, and
separates signal from nearby signal only by distance for numbers. Design your readout
accordingly: take an argmax over candidate values rather than a threshold, which is exactly what
DecodeSum and DecodeProduct do.
Numbers encode to holograms where the linear band encodes the value additively and the log band encodes it multiplicatively. When you bind two numbers, their bands compose:
var three = Hologram.FromNumber(3, dim);
var five = Hologram.FromNumber(5, dim);
var sum_encoded = three * five; // bind: compose on both bands
// Read out the linear band (addition)
int decoded_sum = PhasorCodec.DecodeSum(sum_encoded, max: 20);
Console.WriteLine(decoded_sum); // Output: 8
// On the log band, multiply
var two = Hologram.FromNumber(2, dim);
var four = Hologram.FromNumber(4, dim);
var product_encoded = two * four;
int decoded_product = PhasorCodec.DecodeProduct(product_encoded, max: 16);
Console.WriteLine(decoded_product); // Output: 8Arithmetic is composition, not calculation. The face carries both operations simultaneously, and you read out the band you care about.
The operators (*, +, /) are for clarity and
testing—they allocate a new array per operation. In tight loops or accumulation, use the
in-place static methods instead:
var result = Hologram.Zero(dim);
for (int i = 0; i < 100; i++)
{
var val = Hologram.FromNumber(i, dim);
result = result + val;
}double[] accumulator = new double[dim];
for (int i = 0; i < 100; i++)
{
var val = Hologram.FromNumber(i, dim);
Hologram.BundleInto(accumulator, val.Reals);
}Measured performance: at typical dimensions (d=64 to d=96), the allocating
Bind operator is approximately 1.7x slower than the in-place BindInto
static method. For bundling (+), use BundleInto. For unbinding
(/), use UnbindInto. Pre-allocate your accumulator once and reuse it.
A real example: HoloRouter.cs (a four-way swarm router) uses only bind,
bundle, and unbind with in-place methods to route arithmetic flows, accumulating into pre-allocated
buffers. It achieves 57.7% correctness at a 25% chance baseline with zero trained parameters—the
algebra alone provides the routing logic.
Hologram uses the interleaved (cos, sin, cos, sin, ...)
layout, same as PhasorCodec. Do not pass a hologram's face to HoloCodec's
operators—HoloCodec is planar (all reals, then all imags) and will produce
garbage. Use the one that matches your workload: Hologram for clarity,
HoloCodec for SIMD and large-scale similarity search.PhasorCodec requires a dimension that is even and >= 128
(64 reals frozen + >= 64 orbital). Hologram inherits this constraint. Odd
dimensions align down; anything below 128 throws ArgumentException.*,
+, /, ~) returns a new Hologram with a freshly
allocated double[]. Inside a loop or tight accumulation, the allocation overhead
dominates. Reach for BindInto, BundleInto, UnbindInto or
work directly with double[]..Reals is a live reference. The hologram's .Reals property
returns the internal array directly (not a copy). Modifying it mutates the hologram. This is by
design—it lets you call the in-place methods directly on a hologram's reals without an extra
copy—but it means a hologram is not truly immutable if you hand its reals out. In practice,
use it read-only or pass it to in-place methods; do not mutate it yourself.minimal example
using Phasor;
// Encode a number and a symbol
double[] five = PhasorCodec.Encode("5");
double[] greeting = PhasorCodec.Encode("hello");
// Bind two numbers: adds them on the linear band
double[] fivePlusThree = PhasorCodec.Bind(five, PhasorCodec.Encode("3"));
int sum = PhasorCodec.DecodeSum(fivePlusThree, max: 10); // sum == 8
// Bundle (superpose) items to build a set, then unbind to extract one
double[] pair = PhasorCodec.Bundle(greeting, five);
double[] extracted = PhasorCodec.Unbind(pair, greeting); // extracted ~= fiveFor larger workloads or similarity search, use HoloCodec (SIMD, configurable width):
using Phasor;
var codec = new HoloCodec(dim: 1024); // 1024-dimensional, ~256 in the number band
double[] encoded = codec.Encode("hello");
double similarity = codec.Dot(encoded, another);Compatibility: .NET 8.0+, Windows/Linux/macOS, no platform-specific code, no dependency to bring your own model or storage layer. License: proprietary — evaluation and non-commercial use are permitted, commercial use requires a commercial licence; no feature on this page is gated behind a tier or a licence key.