Home/Packages/Phasor

Phasor · foundation

Encode numbers and symbols as phasor faces. Compose them with one algebra.

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.

net8.0+ zero dependencies AOT & trim-safe no feature gated
dotnet add package EvaluatedApplications.Phasor

Quick start

install, then this

dotnet add package EvaluatedApplications.Phasor
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

The problem it solves

numbers 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.

How it works

two operations

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.

Compose

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.

Two profiles

pick the one that matches your workload

PhasorCodec

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.

HoloCodec

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.

Key features

what you get

One algebra, no special cases

Bind, unbind, bundle and readout work the same way on numbers and symbols.

Exact composition

Bundle and unbind are exact; subtraction removes a contribution with no floating-point error.

No dependencies

Only .NET System and System.Numerics — no external libraries.

AOT and trim compatible

Works with ahead-of-time compilation and tree-shaking, no reflection tricks.

Deterministic hashing

Symbols encode to repeatable, salted phasor signatures — reproducible, not cryptographic.

Memoized decode cache

HoloCodec caches number faces to speed up repeated decodes.

Hologram: readable algebra with operators

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.

What it is

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.

The algebra in plain language

  • Bind (operator *) — 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.
  • Bundle (operator +) — component-wise sum. Merge multiple holograms into one superposition: bind + unbind of constituents retrieves them losslessly (set-forming operation).
  • Unbind (operator /) — multiply by the conjugate, the inverse of bind. Extract a component: record / key gives you what was bound with key.
  • Correlate (method .Correlate(other)) — dot product. Measure how much of one hologram is present in another: high correlation means strong association, near-zero means unrelated.
  • Conjugate (operator ~) — 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.

A worked example

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}");
OutputName field has Lily: 128.59 Name field has John: -1.96 Age field has 7: 32.59 Age field has 5: 13.39

Read 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.

Arithmetic with numbers

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: 8

Arithmetic is composition, not calculation. The face carries both operations simultaneously, and you read out the band you care about.

Hot-path rule: use in-place operations in loops

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:

Slow (allocates 100 times)

var result = Hologram.Zero(dim); for (int i = 0; i < 100; i++) { var val = Hologram.FromNumber(i, dim); result = result + val; }

Fast (no allocation, reuses buffer)

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.

Gotchas

  • Layouts do not mix. 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.
  • Dimension floor. 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.
  • Operators allocate; in-place methods don't. Every operator (*, +, /, ~) 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.

Get started

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 ~= five

For 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.

Where Phasor shows up

It's the base package: AlgFormer's frozen input/output codec, HoloDb's row holograms, and HoloVoxel's chunk storage all build directly on it.