EvaluatedApplications.AlgFormer 3.7.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package EvaluatedApplications.AlgFormer --version 3.7.0
                    
NuGet\Install-Package EvaluatedApplications.AlgFormer -Version 3.7.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EvaluatedApplications.AlgFormer" Version="3.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EvaluatedApplications.AlgFormer" Version="3.7.0" />
                    
Directory.Packages.props
<PackageReference Include="EvaluatedApplications.AlgFormer" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EvaluatedApplications.AlgFormer --version 3.7.0
                    
#r "nuget: EvaluatedApplications.AlgFormer, 3.7.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EvaluatedApplications.AlgFormer@3.7.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EvaluatedApplications.AlgFormer&version=3.7.0
                    
Install as a Cake Addin
#tool nuget:?package=EvaluatedApplications.AlgFormer&version=3.7.0
                    
Install as a Cake Tool

AlgFormer

EvaluatedApplications.AlgFormer — the reusable phasor-transformer engine from PrismFormer: two param-for-param comparable attention cores (softmax and holographic), data-parallel training, incremental serving, checkpointing with in-place growth, a capacity-sizing module, a subword tokenizer, data-source adapters, and MQTT-based distributed/swarm training. Pure double[] + SIMD — no external ML runtime, no native dependency. This page is comprehensive: every public type and member is documented below, because this package ships binary-only (no source, no separate docs site).

dotnet add package EvaluatedApplications.AlgFormer

Table of contents

  1. Quick start
  2. Core invariants — read before using anything
  3. Building a model
  4. Training
  5. Inference and serving
  6. HoloFormer depth: weight-tied iteration and StackIter (+ Preference training (DPO))
  7. Inspectors
  8. Latent thought steps
  9. ADAM & EVE — the per-layer gate
  10. Coherence gates, rising memory and atom preference
  11. Checkpointing
  12. Growth in place
  13. HoloShape, capacity-law sizing
  14. PrismSpec, the frozen production shape
  15. Weight-management utilities
  16. Subword tokenizer
  17. Data sources
  18. Distributed / swarm training
  19. Parallelism primitives
  20. Self-check oracles (GradCheck family)
  21. Exceptions
  22. License

Quick start

using PrismFormer;

// A tiny model: 16 tokens, 4 relation shifts, 2 layers, up to 6 tokens of context, 16-wide, nothing frozen.
var model = new AlgFormer(vocab: 16, shifts: 4, layers: 2, maxContext: 6, dModel: 16, frozenPrefix: 0);

// Train on (context tokens, target token) pairs — data-parallel via EvalApp under the hood.
var data = new List<(int[] Ctx, int Target)>
{
    (new[] { 1, 2, 3 }, 4),
    (new[] { 2, 3, 4 }, 5),
};
var trainer = new PrismTrainer(model);
double loss = trainer.TrainEpoch(data, batchSize: 2, lr: 5e-2, shuffleSeed: 1);

// Inference.
int next = model.Predict(new[] { 1, 2, 3 });
double[] logits = model.LogitsFor(new[] { 1, 2, 3 });
int[] generated = model.Generate(new[] { 1, 2, 3 }, maxNewTokens: 5, temperature: 0.8, seed: 1);

Console.WriteLine($"loss={loss:F3} next={next} logits.Length={logits.Length} generated=[{string.Join(",", generated)}]");

HoloFormer is a drop-in for AlgFormer with the same constructor shape, same training/serve/checkpoint surface — swap the type name to switch attention cores.


Core invariants

Read this section before writing any code against the package — these are the mistakes the package itself has been bitten by.

  • Shift count S must be > 1. S=1 collapses the relation-bank to a pure per-position diagonal map (y[i]=bank[i]·x[i], no cross-channel term) — attention breaks structurally. Go small on Dim/Layers instead of shrinking Shifts to 1.
  • HoloFormer.Iters/IterAlphaServe/IterClean/IterTau are runtime knobs, NOT serialized. A resumed checkpoint always loads with these at their defaults — reset them yourself after Deserialize/Load.
  • Arch flags (bindFfn/golden/normalize/unitary/growFromFront/goldenExact) must carry forward on every grow/upgrade. GrowLayers/GrowShifts/HoloUpgrade.* all do this correctly if you go through them; hand-rolling a rebuild and forgetting a flag silently reverts geometry to ctor defaults and scrambles trained banks.
  • The embedding's frozen prefix is FrozenPrefix reals per row (0..Dim, can be partial). Step/ Accumulate zero gradient there; a number's exact value/signature is preserved. RestoreFrozen re-snaps it after any operation (e.g. weight averaging) that could introduce floating-point drift.
  • Checkpoint formats throw CheckpointFormatException, never a bare EndOfStreamException, on a truncated/incompatible/future-version buffer. Catch this type specifically if you want to fall back to a fresh model on a bad checkpoint.
  • Step returns bool — false means the whole batch was dropped because its gradient was non-finite (NaN/∞); the optimizer state and every parameter are left untouched. SkippedSteps on both cores counts this monotonically. Always check the return value (or at least watch SkippedSteps) in a long training run.
  • Thread-safety: a single AlgFormer/HoloFormer instance is not safe for concurrent Step/ Accumulate calls, by design — data-parallel training shards accumulate into separate Grads buffers (see Training) and apply with one serialized Step. Serving (Predict/LogitsFor/ Generate/KvCache) is read-only and safe to call concurrently on an unchanging model, but a KvCache itself is per-generation, single-threaded state — never share one cache across threads.
  • Production HoloFormer depth is the per-layer StackIter family (StackIterAccumulate/ StackIterLogitsCpu/PrimeIter/StepIter), not the single-layer Iters/IterAccumulate oracle (that one only works when Layers == 1).
  • alpha arrays for StackIter are per-layer (double[], length must equal Layers) — pass a uniform array (every entry equal) to reproduce old scalar-alpha behaviour bit-for-bit; a newly grown layer should start its own entry at 0 and ramp to 1 while settled layers stay at 1.0.

Building a model

Member Purpose
AlgFormer(int vocab, int shifts, int layers, int maxContext, int dModel = 0, int frozenPrefix = -1, Func<int,double[]>? embedSeed = null, int seed = 42, bool bindFfn = false, bool golden = false, bool growFromFront = true, bool goldenExact = false) Softmax-attention core. dModel<=0 and frozenPrefix<0 default to the Phasor codec's width/frozen-count.
HoloFormer(int vocab, int shifts, int layers, int maxContext, int dModel = 0, int frozenPrefix = -1, Func<int,double[]>? embedSeed = null, int seed = 42, bool bindFfn = false, bool golden = false, bool normalize = true, bool unitary = false, bool growFromFront = true, bool goldenExact = false, HoloInit init = HoloInit.Random, double snakeGrowth = 0.5) Holographic-attention core; two extra flags (normalize, unitary) vs AlgFormer, plus the opt-in snake init (below).
HoloInit.Snake / snakeGrowth (ctor, HoloFormer only, experimental, default OFF = HoloInit.Random, unchanged) Smooth-spiral init: banks start diagonal so each token's stream moves outward layer to layer with few sign reversals and no hairpins. snakeGrowth = total outward growth over the stack as a fraction of the entry norm (default 0.5, smaller = gentler), auto-capped to the usable band. Construction-only, deterministic by seed, not serialized. Build at the FULL shape (a model grown from 1 layer gets identity layers, not snake ones). HoloFormer.MeasureTrajectory(int[] toks) returns the per-dimension TrajectoryStats for any model.
HoloInit.ZeroLayers (ctor init:, HoloFormer only, opt-in, default OFF) Every layer starts the way a grown layer does: the residual output projections Ro/Ao are zero, so the whole fresh stack is the identity (logits = embed-to-readout path, for any K/alpha). The inner banks (Rq/Rk/Rv/A1/Ag) stay random on purpose: zeroing them too would give zero gradient everywhere and the model could never learn. Inner banks receive gradient from the second step, once Ro/Ao have moved. Construction-only, not serialized.
AlgFormer.Mini(int vocab, Func<int,double[]>? embedSeed = null, int seed = 42) / HoloFormer.Mini(...) Preset: full Phasor width, identity comps frozen, 4 layers, 32 shifts, 16-token context.
Vocab, Dim, Context, Shifts, Layers (int, both cores) The four/five construction dimensions, read back.
FrozenPrefix (int, both cores) Exact frozen leading-column count of every embedding row (any 0..Dim).
GrowFromFront (bool, both cores) Whether a future LoadUpgrade context-grow preserves the old high-index ("just before prediction") row — see Growth.
BindFfn/Golden/GoldenExact/Normalize/Unitary (bool, HoloFormer only; AlgFormer exposes none of these as properties) The arch flags as constructed.
ParamCount (long, both cores) Total trainable+frozen parameter count.
Map (IParallelMap, both cores) Fan-out used by the per-position forward loops at serve time; see Parallelism.
using PrismFormer;

var holo = new HoloFormer(vocab: 20, shifts: 6, layers: 2, maxContext: 8, dModel: 12, frozenPrefix: 0,
                           normalize: true, unitary: false);
Console.WriteLine($"Vocab={holo.Vocab} Dim={holo.Dim} Context={holo.Context} Shifts={holo.Shifts} " +
                   $"Layers={holo.Layers} FrozenPrefix={holo.FrozenPrefix} ParamCount={holo.ParamCount} " +
                   $"GrowFromFront={holo.GrowFromFront} Normalize={holo.Normalize}");

// opt-in snake init, then measure how straight the layer-to-layer trajectory is
var snake = new HoloFormer(vocab: 20, shifts: 6, layers: 6, maxContext: 8, dModel: 12, frozenPrefix: 0,
                            init: HoloInit.Snake, snakeGrowth: 0.5);
var st = snake.MeasureTrajectory(new[] { 1, 2, 3, 4, 5 });
Console.WriteLine($"stepFlip={st.StepSignFlip:P0} turn={st.MeanTurnDeg:F0} deg normMonotone={st.NormMonotone:P0}");

// opt-in zero-layers init: every layer starts as identity (Ro/Ao zero), inner banks random
var zero = new HoloFormer(vocab: 20, shifts: 6, layers: 6, maxContext: 8, dModel: 12, frozenPrefix: 0,
                           init: HoloInit.ZeroLayers);
Console.WriteLine($"zero-init OutputBankNorm(0)={zero.OutputBankNorm(0)}");

Using the real Phasor codec face (production seeding)

AlgFormer.Mini/HoloFormer.Mini and the production PrismSpec shape seed embeddings from the Phasor VSA codec (package EvaluatedApplications.Phasor, pulled in transitively) so a number token's embedding IS its exact value:

using Phasor;
using PrismFormer;

string[] vocabSymbols = { "0", "1", "2", "foo" };
var mini = AlgFormer.Mini(vocab: vocabSymbols.Length, embedSeed: id => PhasorCodec.Encode(vocabSymbols[id]));
Console.WriteLine($"mini dim={mini.Dim} frozenPrefix={mini.FrozenPrefix}");

Training

Member Purpose
IBatchTrainer (interface) double TrainBatch(IReadOnlyList<(int[] Ctx, int Target)> batch, double lr, CancellationToken ct = default) — implemented by PrismTrainer and both relay hosts, so a training loop can target local-only or local+networked interchangeably.
PrismTrainer(AlgFormer model, int parallelism = 0) Data-parallel trainer: splits a batch into shards, accumulates each shard's gradient independently, sums, applies one Adam Step. parallelism<=0 defaults to ProcessorCount-1. Every parallel/scheduling path runs through EvalApp — the ctor builds its pipelines immediately and THROWS if that fails; there is no fallback.
PrismTrainer.TrainBatch(batch, lr = 1e-3, ct = default) One minibatch step; returns mean cross-entropy loss.
PrismTrainer.AccumulateBatch(batch, out double meanLoss) Compute and return the batch's merged Grads without applying — for a distributed coordinator merging in gradients from remote workers before one Step.
PrismTrainer.TrainEpoch(data, batchSize, lr, shuffleSeed) One shuffled pass over data in minibatches; returns mean loss.
PrismTrainer.Train(data, epochs, batchSize = 256, baseLr = 1e-3, seed = 1, onEpoch = null) Multi-epoch loop with linear LR decay to 0.1× the base rate.
AlgFormer.Accumulate(toks, answer, Grads g) / (toks, answer, g, Scratch? s) Forward + backward one example; adds its gradient into g. The Scratch overload reuses a pooled row buffer (near-zero allocation across a shard).
AlgFormer.NewScratch() → Scratch One reusable row-pool per worker thread; pass to Accumulate.
AlgFormer.Step(Grads g, double lr = 1e-3, double scale = 1.0, double b1 = 0.9, double b2 = 0.999, double eps = 1e-8) → bool One Adam update from an accumulated gradient. Returns false (batch dropped, nothing touched) on a non-finite gradient.
AlgFormer.SkippedSteps (long) Monotonic count of Step calls that dropped a non-finite batch. Not reset by anything, not serialized.
AlgFormer.TrainStep(toks, answer, lr = 1e-3) Accumulate + Step in one call for a single example; returns the loss.
AlgFormer.TrainEpoch(data, batchSize, lr, shuffleSeed, parallelism = 0) Train directly on the model without going through PrismTrainer (uses the in-box TPL only).
AlgFormer.Train(data, epochs, batchSize = 256, baseLr = 1e-3, seed = 1, onEpoch = null) Multi-epoch direct-model loop, same LR decay as PrismTrainer.Train.
AlgFormer.NewGrads() → Grads A fresh, zeroed gradient buffer shaped for this model.
AlgFormer.Grads (nested class) Add(Grads o) sums another buffer in; Clear() zeros it for reuse.
AlgFormer.GradSignature(Grads g) → ulong FNV-1a checksum over every gradient value — a bit-identity guard for comparing two code paths' backward pass.
HoloFormer.Step(Grads g, ..., double clip = 0) Same Adam contract as AlgFormer.Step plus an optional global-gradient-norm clip. The global norm is always computed and checked for finiteness first, so a non-finite batch is dropped even with clip = 0.
HoloFormer.TrainEpoch(data, batchSize, lr, shuffleSeed, parallelism = 0, clip = 0) As AlgFormer.TrainEpoch, with the clip knob.
HoloFormer.TrainEpochAllPos(data, batchSize, lr, scoreP, K, alpha, shuffleSeed, parallelism = 0, clip = 0) Batched all-positions trainer over the StackIter path (every fed position scores a transition, not just the last) — see HoloFormer depth. Returns a mean loss already normalized by position count.
using PrismFormer;

var model = new AlgFormer(vocab: 10, shifts: 3, layers: 2, maxContext: 5, dModel: 8, frozenPrefix: 0);
var g = model.NewGrads();
var scratch = model.NewScratch();
double loss = model.Accumulate(new[] { 1, 2, 3 }, 4, g, scratch);
bool applied = model.Step(g, lr: 1e-2);
Console.WriteLine($"loss={loss:F4} applied={applied} skipped={model.SkippedSteps}");

// Or let PrismTrainer shard + merge automatically:
var trainer = new PrismTrainer(model);
var grads = trainer.AccumulateBatch(new[] { (new[] { 1, 2, 3 }, 4) }, out var meanLoss);
Console.WriteLine($"meanLoss={meanLoss:F4}");

Inference and serving

Member Purpose
Predict(int[] toks) → int Greedy next-token argmax.
LogitsFor(int[] toks) → double[] Full next-token logits at the final position.
PredictAsync(int[] toks) / LogitsForAsync(int[] toks) (AlgFormer only) Awaitable twins for a single-threaded host (browser WASM) whose Map implementation genuinely cannot block — see Parallelism. HoloFormer's async twins are not yet implemented.
Generate(int[] prompt, int maxNewTokens, double temperature = 0, int seed = 0) → int[] Autoregressive generation over a rolling Context-token window. temperature<=0 is greedy; >0 samples via a seeded RNG. Returns only the newly generated tokens. HoloFormer.Generate additionally folds in latent thought steps automatically on a short context.
KvCache (nested class, both cores) Per-generation incremental-serve state. AlgFormer's holds cached K/V per layer (O(T) per step); HoloFormer's holds one running holographic memory per layer (O(1) per step, independent of context length). Length (int) reports positions placed so far. Not thread-safe; one per generation.
NewCache() → KvCache Allocate a cache sized for this model.
Prime(KvCache c, int[] toks) → double[] Reset c and feed toks through it; returns next-token logits. Equivalent to LogitsFor but leaves the cache primed for Step.
Step(KvCache c, int tok) → double[] Append one token via the cache; O(T) (AlgFormer) or O(1) (HoloFormer) in the current length.
using PrismFormer;

var model = new AlgFormer(vocab: 10, shifts: 3, layers: 2, maxContext: 6, dModel: 8, frozenPrefix: 0);
var cache = model.NewCache();
double[] afterPrompt = model.Prime(cache, new[] { 1, 2, 3 });
double[] afterNext = model.Step(cache, 4);
Console.WriteLine($"cache length={cache.Length} logits lens: {afterPrompt.Length},{afterNext.Length}");

int[] generated = model.Generate(new[] { 1, 2, 3 }, maxNewTokens: 4, temperature: 0.7, seed: 7);
Console.WriteLine($"generated=[{string.Join(",", generated)}]");

HoloFormer depth

Weight-tied iteration gives depth via composition with zero new parameters: the same layer (or layer stack) is applied K times. Two entry families exist:

  • Iters/IterAccumulate/IterClean — a single-layer (Layers == 1) oracle. Not the production path.
  • StackIter* — per-layer weight-tied K-iteration, the production path. Every layer is applied K times with its own per-layer alpha ramp; layer l's K-iterated output feeds layer l+1.
Member Purpose
Iters (int field, default 1) Serve-time weight-tied iteration count for the single-layer oracle path. Not serialized.
IterAlphaServe (double field, default 1) α applied to the extra serve-time iterations. Not serialized.
IterClean (bool field) Enables vocab-attractor cleanup between single-layer iteration passes.
IterTau (double field, default 32) Cleanup softmax temperature when IterClean is on.
IterAccumulate(toks, answer, g, int iters, double alpha) → double Forward K weight-tied passes of the single layer (Layers==1 only), backprop through all of them. iters=1 reproduces plain Accumulate.
StackIterAccumulate(toks, answer, g, int K, double[] alpha) → double Forward Layers layers × K weight-tied passes each; backprop through all Layers·K passes. K=1 reproduces plain Accumulate. alpha.Length must equal Layers.
StackIterLogitsCpu(toks, int K, double[] alpha) → double[] Serve-time logits under the same per-layer K-iteration — the CPU reference for a GPU StackIter implementation.
StackIterAccumulateAllPos(int[] seq, g, int scoreP, int K, double[] alpha) → (double lossSum, int count) Scores the last scoreP transitions of one forward instead of only the final position. scoreP is a transition count, not an offset (saturates at however many are available). lossSum is a sum, not a mean — divide by count yourself, or use Step(..., scale: count). Accepts seq.Length up to Context+1 (one token of controlled overflow trains the otherwise-untrainable final context position); anything longer throws ArgumentException.
StackIterAccumulateAllPosMean(seq, g, scoreP, K, alpha) → (double meanLoss, int count) Convenience wrapper returning the mean directly; (0,0) if nothing could be scored.
NewCache(int stackK) → KvCache A cache sized for the StackK-aware serve path (holds stackK independent running memories per layer).
PrimeIter(KvCache c, int[] toks, int stackK, double[] alpha) → double[] StackIter-aware Prime; c must come from NewCache(stackK).
StepIter(KvCache c, int tok, int stackK, double[] alpha) → double[] StackIter-aware Step, O(1) per token regardless of context length. Throws ArgumentOutOfRangeException/ArgumentException on a stackK/alpha mismatch with the cache. stackK=1 reproduces plain Step bit-for-bit.
using PrismFormer;

var holo = new HoloFormer(vocab: 12, shifts: 4, layers: 2, maxContext: 6, dModel: 8, frozenPrefix: 0);
var alpha = new double[holo.Layers];
Array.Fill(alpha, 1.0);   // every layer fully "on" — a settled model; a newly grown layer would start its own entry at 0

var g = holo.NewGrads();
double loss = holo.StackIterAccumulate(new[] { 1, 2, 3 }, 4, g, K: 2, alpha);
holo.Step(g, lr: 1e-2);

double[] served = holo.StackIterLogitsCpu(new[] { 1, 2, 3 }, K: 2, alpha);
Console.WriteLine($"trainLoss={loss:F4} servedLogits.Length={served.Length}");

// O(1)/token incremental serve at the same K:
var cache = holo.NewCache(stackK: 2);
holo.PrimeIter(cache, new[] { 1, 2, 3 }, stackK: 2, alpha);
double[] next = holo.StepIter(cache, 4, stackK: 2, alpha);
Console.WriteLine($"StepIter logits length={next.Length}");

// All-positions training over a window one token longer than Context (trains the final context position):
var seq = new[] { 1, 2, 3, 4, 5, 6, 1 };   // length 7 == Context(6)+1
var g2 = holo.NewGrads();
var (lossSum, count) = holo.StackIterAccumulateAllPos(seq, g2, scoreP: seq.Length, K: 2, alpha);
Console.WriteLine($"allPos meanLoss={(count > 0 ? lossSum / count : 0):F4} count={count}");

Preference training (DPO)

HoloFormer (CPU) has what a Direct Preference Optimization step needs, on the same weight-tied per-layer K-iteration forward the all-positions trainer uses, so train and score depth match.

Member What it does
SequenceLogProb(int[] seq, int scoreFrom, int K, double[] alpha) Summed log P of tokens seq[scoreFrom..] given everything before them (<= 0). scoreFrom = index of the first reply token = prompt length, in 1..seq.Length. seq.Length must be 2..Context+1: left-truncate the prompt yourself, identically for policy and reference.
SequenceLogProb(int[] context, int[] continuation, K, alpha) Same, on context ++ continuation, scoring the continuation.
SequenceLogProbs(seqs, scoreFrom, K, alpha) Batch form.
Clone() Bit-exact independent copy. Freeze a reference model with var reference = policy.Clone(); and never Step it.
StackIterAccumulateAllPosWeighted(seqs, scoreFrom, weights, Grads g, K, alpha) Adds weights[i] * grad(NLL_i) to g, scoring only each sequence's reply span. Positive weight pushes that sequence's log-prob up, negative pushes it down, 0 skips it. Gradients are summed, not averaged: use Step(g, lr, scale: pairs). Returns the per-sequence unweighted NLL. A non-finite weight throws before anything is accumulated; a non-finite gradient is dropped by Step as usual.
HoloFormer.Dpo(policyChosen, policyRejected, refChosen, refRejected, beta) Returns DpoTerm(Margin, Loss, WeightChosen, WeightRejected); the two weights are exactly the ones to pass for the chosen and rejected sequences.
using PrismFormer;

var policy = new HoloFormer(vocab: 32, shifts: 4, layers: 2, maxContext: 12, dModel: 16, frozenPrefix: 0);
var reference = policy.Clone();                      // frozen
var alpha = new[] { 1.0, 1.0 };
int[] prompt = { 1, 2, 3, 4 };
int[] chosen = prompt.Concat(new[] { 5, 6 }).ToArray();
int[] rejected = prompt.Concat(new[] { 7, 8 }).ToArray();
int from = prompt.Length;
const double beta = 0.1;

var g = policy.NewGrads();
var t = HoloFormer.Dpo(
    policy.SequenceLogProb(chosen, from, 2, alpha), policy.SequenceLogProb(rejected, from, 2, alpha),
    reference.SequenceLogProb(chosen, from, 2, alpha), reference.SequenceLogProb(rejected, from, 2, alpha), beta);
policy.StackIterAccumulateAllPosWeighted(new[] { chosen, rejected }, new[] { from, from },
    new[] { t.WeightChosen, t.WeightRejected }, g, K: 2, alpha);
policy.Step(g, lr: 1e-3, scale: 1);                  // scale = number of pairs in the batch
Console.WriteLine($"margin={t.Margin:F4} loss={t.Loss:F4}");

Inspectors

Read-only interpretability helpers — none affect forward/backward math or trainable state.

Member Purpose
LayerFaces(int[] toks) → double[][] The hidden face at the last position as it moves up the residual stream, one entry per layer boundary plus the final output.
ProbeControl(int[] toks) → (List<double> Gates, List<double> AttnPeak) (AlgFormer only) Per-layer gate activation and attention-peak diagnostics.
AttentionWeights(int[] toks) → double[][][] (AlgFormer only) The softmax attention weights of one forward pass, [layer][query][key]. Each query row sums to 1 over keys 0..query (causal; later keys are 0). Returns copies; has no effect on training or serving. HoloFormer has no softmax weights: use InspectAttention for its resonance row.
InspectStackIter(toks, int K, double[] alpha) → double[][] (HoloFormer only) Last-position face at every (layer × pass) boundary under StackIter — decode any entry with DecodeFace.
InspectStackIterFaces(toks, int K, double[] alpha) → double[][][] Like InspectStackIter but for every position, not just the last — grid[boundary][position].
InspectAttention(toks, int K, double[] alpha) → double[][] Per-(layer × pass) resonance of the last position's query against every earlier position's key — the holographic analog of an attention-weight row.
InspectRetrieval(toks, int K, double[] alpha) → double[] What the final query pulled out of the top layer's memory bundle — decode with DecodeFace.
DecodeFace(double[] face) → double[] Decode any raw face to per-token logits via the model's own tied readout (logit_w = C_w + ⟨Emb_w, face⟩).
using PrismFormer;

var holo = new HoloFormer(vocab: 12, shifts: 4, layers: 2, maxContext: 6, dModel: 8, frozenPrefix: 0);
var alpha = new double[holo.Layers]; Array.Fill(alpha, 1.0);
int[] toks = { 1, 2, 3 };

double[][] boundaries = holo.InspectStackIter(toks, K: 2, alpha);
double[] decodedFinal = holo.DecodeFace(boundaries[^1]);
double[][] attn = holo.InspectAttention(toks, K: 2, alpha);
double[] retrieved = holo.InspectRetrieval(toks, K: 2, alpha);
Console.WriteLine($"boundaries={boundaries.Length} decodedFinal.Length={decodedFinal.Length} " +
                   $"attnRows={attn.Length} retrieved.Length={retrieved.Length}");

// Softmax core: the attention weights themselves, [layer][query][key]; each row sums to 1 over keys 0..query.
var soft = new AlgFormer(vocab: 12, shifts: 4, layers: 2, maxContext: 6, dModel: 8, frozenPrefix: 0);
double[][][] w = soft.AttentionWeights(toks);
Console.WriteLine($"layers={w.Length} row sum={w[0][2].Sum():F3} weight on a later key={w[0][0][2]}");

Latent thought steps

HoloFormer-only, Layers == 1 oracle: after the prompt, fold N self-generated continuous faces into the bundle before decoding — differentiable internal "babble" with no new parameters and no discrete sampling.

Member Purpose
ThinkAccumulate(toks, answer, g, int nThoughts) → double Forward prompt + N thought steps, backprop through the whole recurrence. nThoughts=0 reproduces plain Accumulate.
ThoughtCount(int promptLen, double k = 1.5, int nmax = 16) → int How many thoughts to fold in to bring the bundle near the crosstalk edge; 0 on a full-context prompt or a non-single-layer model.
ThinkLogitsFor(toks, int nThoughts) → double[] Serve with N thought steps folded in before decode.
ThinkPredict(toks, int nThoughts) → int Greedy argmax over ThinkLogitsFor.
using PrismFormer;

var holo1 = new HoloFormer(vocab: 10, shifts: 3, layers: 1, maxContext: 8, dModel: 6, frozenPrefix: 0);
int n = holo1.ThoughtCount(promptLen: 3);
var g = holo1.NewGrads();
double loss = holo1.ThinkAccumulate(new[] { 1, 2, 3 }, 4, g, nThoughts: n);
int predicted = holo1.ThinkPredict(new[] { 1, 2, 3 }, n);
Console.WriteLine($"thoughts={n} loss={loss:F4} predicted={predicted}");

ADAM & EVE

HoloFormer only, opt-in, default OFF, byte-identical when unused. A per-layer Adam gate that nudges a layer's update toward a codebook-derived target norm range instead of letting magnitude drift unchecked. The CPU path documented here (Step with EveOptions, TrainEpochGated) is the reference; production training applies the same gate through the GPU-fused trainer in EvaluatedApplications.AlgFormer.Gpu.

Member Purpose
DefaultEveInterval (const int = 16) Default number of calls the codebook band is reused for before being recomputed.
UsableNorm(double eps = 1e-3, int eveInterval = DefaultEveInterval, bool forceRefresh = false) → double Self-derived saturation envelope from this model's own decode codebook: ln(Vocab/eps) / median‖Emb_w‖.
UsableRange(double eps = 1e-3, int eveInterval = DefaultEveInterval, bool forceRefresh = false) → (double floor, double ceiling) Codebook-derived target range: floor = ln(V/eps)/p95‖Emb_w‖, ceiling = ln(V/eps)/p05‖Emb_w‖.
LayerOutputNorm(toks, int K, double[] alpha) → double[] Per-layer StackIter output norm at the last position — the gate's "before" reading; K/alpha must match whatever produced the gradient being gated.
EveGain(double before, double after, double floor, double ceiling, double e = 0.05, bool distanceScaled = false, double inBoost = 1.0) → double (static) The gain formula in isolation — 1.0 inside the range; outside, 1±e (flat) or a saturating distance-scaled form.
BandCapGain(double before, double after, double ceiling) → double (static) The hard ratcheting band-cap gain: allowed=max(ceiling,before); never lets the layer's norm exceed allowed.
EveMode (enum) None (no gate, default) / Eve (symmetric push-pull, AMENDMENT 2/4/5) / PerLayerClip (plain per-layer gradient clip, no directional gating) / BandCap (hard ratchet, AMENDMENT 6).
EveOptions (readonly struct) Mode, K (envelope multiplier), Eps, LayerOutNorm/LayerInput/StackK/Alpha (required for Eve/BandCap, from the same forward that produced the gradient), EveInterval, EveDistanceScaled, EveInBoost. Zero-initialised (default) ⇒ Mode=None, safe.
Step(Grads g, EveOptions eve, double lr = 1e-3, double scale = 1.0, double b1 = 0.9, double b2 = 0.999, double eps = 1e-8, double clip = 0, double nudge = 0.05) → bool Gated twin of the plain Step; same non-finite guard, same return contract, plus the per-layer gain selected by eve.Mode.
TrainEpochGated(data, batchSize, lr, shuffleSeed, EveMode mode, int stackK, double[] alpha, double k, double eveEps = 1e-3, int parallelism = 0, double clip = 0, int eveInterval = DefaultEveInterval, bool distanceScaled = false, double inBoost = 1.0) → double Batched trainer that wires up LayerOutputNorm/EveOptions for you and trains through StackIterAccumulate, so the gate's "before" matches the gradient's own forward.
using PrismFormer;

var holo = new HoloFormer(vocab: 12, shifts: 4, layers: 2, maxContext: 6, dModel: 8, frozenPrefix: 0);
var alpha = new double[holo.Layers]; Array.Fill(alpha, 1.0);

var (floor, ceiling) = holo.UsableRange();
double[] before = holo.LayerOutputNorm(new[] { 1, 2, 3 }, K: 2, alpha);

var g = holo.NewGrads();
holo.StackIterAccumulate(new[] { 1, 2, 3 }, 4, g, K: 2, alpha);

var eve = new HoloFormer.EveOptions
{
    Mode = HoloFormer.EveMode.BandCap,
    K = 1.0,
    LayerOutNorm = before,
    LayerInput = null,     // see note below — populate from the same forward in real use
    StackK = 2,
    Alpha = alpha,
};
Console.WriteLine($"floor={floor:F4} ceiling={ceiling:F4} before[0]={before[0]:F4} mode={eve.Mode}");

EveOptions.LayerInput must be the per-layer double[][][] input retained from the same forward that produced LayerOutNorm (an internal pairing the package doesn't expose a public accessor for yet) — in practice you drive Eve/BandCap through TrainEpochGated, which wires this correctly for you; building EveOptions by hand for anything but PerLayerClip needs that pairing done right or Step throws ArgumentException.


Coherence gates, rising memory and atom preference

Every switch in this section defaults to off (false). With a switch off, the model computes the same numbers as a model built without the option.

Atom shared-memory gate. AtomField.MemoryCoherenceGate (bool, default false) with AtomField.MemoryCoherenceC (double, default 1.0, the floor in units of the crosstalk rms). Each channel pair of the shared memory read is soft-thresholded by the crosstalk the other writers leave. Use it when many atoms share one medium and each reader should keep only its own signal. It needs Coupling = AtomCoupling.Memory, works with MemoryLocality in Holographic and Dense modes, and throws InvalidOperationException when MemoryMoleculeSize > 0.

In-layer gate. HoloFormer.AttentionCoherenceGate (bool, default false) with HoloFormer.AttentionCoherenceC (double, default 1.0). Each layer's holographic readout is soft-thresholded per channel pair by its derived crosstalk floor, before the layer's RMS norm. Use it when a bundle holds many items and a query should read out only its own. It works on a single HoloFormer and on each atom of a field. It is honoured by StackIterForward, StackIterAccumulate, StackIterAccumulateAllPos, the DPO methods, LogitsFor, Prime, Step, PrimeIter and StepIter. While it is on, the legacy K=1 Forward and Accumulate, the L=1 IterAccumulate oracle, ThinkAccumulate, Eve's layer replay and the LocalLoss, LocalRepair and Oph hooks throw NotSupportedException.

Both gates are runtime settings and are not serialized. A model trained gated and served ungated is a different function. Set the same values on every copy that is trained, loaded or served.

Rising memory. AtomField.MemoryRise (bool, default false) with MemoryRiseDelay (int, default 160), MemoryRiseGain (double, default 8) and MemoryRisePeg (int, default 0, meaning the atoms' context). Each atom keeps a second memory per site. A note enters at age MemoryRiseDelay with gain 1 and reaches gain MemoryRiseGain at age MemoryRisePeg. The learned read amplitude MemoryRiseAmplitude(site) starts at zero. Use it when notes from well before the current window should still reach the readers. It needs Coupling = AtomCoupling.Memory, works with MemoryLocality, and throws InvalidOperationException when MemoryMoleculeSize > 0 or when MemoryRisePeg does not exceed MemoryRiseDelay. A checkpoint saved with it on uses the MEM7 layout. A checkpoint saved with it off uses MEM6, and MEM6 loads with it off.

Atom preference lane. AtomField.SequenceLogProb(int[][] seqs, int scoreFrom) returns the summed log-probability of the reply under the softmax of the mean of the atom logits. A single int[] is fed to every atom. SequenceLogProbs is the batch form. TrainStepAllPositionsWeighted(seqs, scoreFrom, weights, lr, scale) adds weights[i] * grad(NLL) for each window and takes one Adam step. A positive weight raises that reply's log-probability and a negative weight lowers it. The step always uses the combined loss and returns each window's unweighted NLL. Pair it with HoloFormer.Dpo for preference training on a field. Each atom's window has the same length, 2 to Context + 1 tokens. The lane has no switch.


Checkpointing

Both cores support two independent save formats:

  • Stream (Save/Load): writes/fills a 4-int header (v,d,s,layers) + parameters to/from an existing BinaryWriter/BinaryReader. Load requires an existing instance of the same shape; it never reconstructs one. Arch flags are not persisted here.
  • Byte array (Serialize/Deserialize): fully self-describing (shape + arch flags + parameters), so Deserialize reconstructs a model of the exact right shape from nothing else. Prefer this unless you have a specific reason to use the stream pair.
Member Purpose
Save(BinaryWriter w) Write header + parameters (no flags) + a versioned trailer.
Load(BinaryReader r) → bool Fill this (already-constructed) instance's parameters from a stream; false on a shape mismatch. Throws CheckpointFormatException on a truncated/corrupt trailer.
Serialize() → byte[] Self-describing bytes: shape + arch flags + parameters + versioned trailer.
Deserialize(byte[] bytes) → AlgFormer/HoloFormer (static) Reconstruct a model from Serialize bytes. Backward-compatible across three historical on-disk layouts (ancient/pre-flags, flags-no-trailer, current). Throws CheckpointFormatException on anything that doesn't match a known layout.
SerializeTrainable() → byte[] Serialize only Pos/C/banks (skips the frozen Emb block) — a lean per-batch re-sync when EmbFrozen is true.
EmbFrozen (bool) True when the whole embedding is frozen (FrozenPrefix >= Dim) — SerializeTrainable is only valid then.
FrozenDoublePrefix (long) Leading fully-frozen doubles in the flat Save/Serialize parameter layout (the whole V·d embedding block when codec-only, else 0).
SerializeGradient(Grads g) → byte[] / DeserializeGradient(byte[] wire) → Grads Wire format for a gradient buffer — the transport primitive behind distributed training.
SerializeOptimizer() → byte[] / LoadOptimizer(byte[] bytes) → bool (HoloFormer only) Persist/restore the Adam step counter + per-parameter moments, so a resumed model keeps its momentum instead of re-warming over ~1/(1-β2) steps. LoadOptimizer returns false (leaving the optimizer cold) if the byte length doesn't match the model's current shape (e.g. after a grow).
CheckpointFormatException Thrown by both Deserializes and both Loads on a format mismatch. FoundVersion (int) reports the trailer version found, or -1 if unreadable.
using PrismFormer;

var model = new HoloFormer(vocab: 10, shifts: 3, layers: 2, maxContext: 5, dModel: 8, frozenPrefix: 0);
byte[] bytes = model.Serialize();
var reloaded = HoloFormer.Deserialize(bytes);
Console.WriteLine($"roundtrip ok: Vocab={reloaded.Vocab} Layers={reloaded.Layers} ParamCount={reloaded.ParamCount}");

// Gradient transport:
var g = model.NewGrads();
model.Accumulate(new[] { 1, 2, 3 }, 4, g);
byte[] gradWire = model.SerializeGradient(g);
var gradBack = model.DeserializeGradient(gradWire);

// Optimizer state round-trip:
model.Step(g, lr: 1e-2);
byte[] optState = model.SerializeOptimizer();
bool restored = model.LoadOptimizer(optState);
Console.WriteLine($"optimizer restored={restored}");

// Malformed buffer -> typed exception, not a bare EndOfStreamException:
try { HoloFormer.Deserialize(new byte[] { 1, 2, 3 }); }
catch (CheckpointFormatException ex) { Console.WriteLine($"caught: {ex.Message[..Math.Min(40, ex.Message.Length)]}..."); }

Growth in place

Every grow returns a new model and leaves the original untouched; new capacity starts as an identity no-op (output unchanged) and trains from there.

Member Purpose
GrowLayers(int extra, bool zeroOutputOnly = true, int seed = 42, bool atFront = false) Append (or, if atFront, insert at the front) extra identity-initialised layers. zeroOutputOnly=true zeros only the new layer's output projections (identity, but trains immediately); false zeros the whole layer (identity, but dead — never trains). atFront=true keeps the original first layer as the permanent last layer across every future grow.
GrowShifts(int extra, int seed = 42) Widen every layer's relation banks by extra shift rows (zero-init, identity until trained).
LoadUpgrade(BinaryReader r, int oldMaxT) → bool Load an older, smaller checkpoint (fewer shifts/context/vocab) into this larger, freshly-constructed model. Accepts either core's Save or Serialize byte layout. false on an incompatible shape (dim/layers must match exactly; vocab/shifts/context may only grow).
OutputBankNorm(int layer) → double L2 norm of one layer's residual output projections — the liveness test for a non-destructively grown layer (0 right after GrowLayers(zeroOutputOnly:true), nonzero once it has received gradient).
HoloUpgrade.To(HoloFormer m, int vocab, int shifts, int ctx, int dim, int frozen, Func<int,double[]>? seed = null) (static) Rebuild at an arbitrary larger shape and LoadUpgrade the old weights in — HoloFormer's one-call growth helper.
HoloUpgrade.GrowContext(m, int newCtx, int dim, int frozen, seed = null, double ratio = HoloShape.Edge) (static) Grow context and re-derive shifts via HoloShape.ShiftsFor so the over-bundle ratio holds as the window lengthens.
HoloUpgrade.GrowShifts(m, int newShifts, int dim, int frozen, seed = null) (static) Grow shift-banks to an absolute new count.
HoloUpgrade.GrowVocab(m, int newVocab, int dim, int frozen, seed = null) (static) Grow the vocabulary to an absolute new size.
using PrismFormer;

var model = new HoloFormer(vocab: 10, shifts: 3, layers: 2, maxContext: 5, dModel: 8, frozenPrefix: 0);
var grown = model.GrowLayers(extra: 1, zeroOutputOnly: true);
Console.WriteLine($"layers {model.Layers} -> {grown.Layers}, new layer live-test norm={grown.OutputBankNorm(grown.Layers - 1):F6}");

var widened = HoloUpgrade.GrowShifts(grown, newShifts: 5, dim: grown.Dim, frozen: grown.FrozenPrefix);
Console.WriteLine($"shifts {grown.Shifts} -> {widened.Shifts}");

var deeper = HoloUpgrade.GrowContext(widened, newCtx: 12, dim: widened.Dim, frozen: widened.FrozenPrefix);
Console.WriteLine($"context {widened.Context} -> {deeper.Context}, shifts re-derived to {deeper.Shifts}");

HoloShape

Static class — model-shape sizing from measured over-bundling constants. Don't hand-pick Shifts; derive them here.

Member Purpose
CleanFrac (const double = 0.12) K90/bindRank — fraction of a bundle that decodes ≥90% clean.
Edge/Comfort/Clean (const double = 1.0/0.5/0.25) Over-bundle design-point ratios (ctx / bindRank). Clean is the measured-best default without a cleanup path.
BindRank(int shifts, int d) → int shifts·d/2 — the crosstalk edge.
CleanCapacity(int shifts, int d) → int Tokens from a bundle that read back ≥90% clean.
InteractionBudget(int shifts, int d) → int Free 2nd-order interaction budget (≈ bindRank/4).
ShiftsFor(int ctx, int d, double ratio = Clean) → int Shifts derived so a ctx-token context sits at the target over-bundle ratio. The normal way to pick Shifts.
EquivCompute(int d, int layers, int k) → long Dense-transformer compute-equivalent param count (12·d²·layers·k).
InvisibleMultiplier(long storedParams, int d, int layers, int k) → double EquivCompute / storedParams — the "invisible params" over-bundling manufactures.
GoldenRatioInv (const double) φ⁻¹, the golden-angle spacing constant.
BuildShiftTable(int s, int d, bool golden, bool goldenExact) → int[] The exact per-bank-row rotation table both cores' constructors build — public so a foreign assembly (e.g. a GPU implementation) can reproduce it byte-identically instead of risking drift.
GoldenStep(int d) → int The single rotation step goldenExact uses — nearest integer to d·φ⁻¹, walked to the nearest value coprime to d.
DistinctShiftCount(int s, int d, bool golden, bool goldenExact = false) → int How many distinct shift offsets a table of this shape actually produces (can be less than min(s,d) under legacy golden:true, goldenExact:false).
ShiftsCollide(int s, int d, bool golden, bool goldenExact = false) → bool True when some bank rows duplicate another's diagonal (wasted params) — check this before committing to a new golden-spaced shape.
DerivedShape (readonly record struct: Shifts, Context, Layers) The output of Derive.
Derive(int dim, int stackK = 2, double ratio = Clean) → DerivedShape Shape-from-dimension scaling law: Shifts=dim, Context=ratio·dim²/2, Layers from a measured per-pass contraction factor. Pure calculation — constructs nothing. Treat the output as a starting shape to try, not a guarantee (two of its constants are single measurements).
using PrismFormer;

int ctx = 64, dim = 32;
int shifts = HoloShape.ShiftsFor(ctx, dim);                      // the normal way to pick Shifts
bool collides = HoloShape.ShiftsCollide(shifts, dim, golden: true);
var derived = HoloShape.Derive(dim: 128, stackK: 2);
Console.WriteLine($"ShiftsFor({ctx},{dim})={shifts} collides={collides} " +
                   $"Derive(128) -> Shifts={derived.Shifts} Context={derived.Context} Layers={derived.Layers}");

PrismSpec

Static class — the one frozen production shape every swarm node must match exactly to merge gradients. Diagnostics/experiments can still build off-spec models directly via the constructors; those never join the swarm.

Member Purpose
Version (const string = "PRISM-3") The spec generation tag.
Vocab, Context (512), Layers (32), Shifts (64), InitSeed (1), Dim (256), FrozenPrefix (=Dim) The frozen dimensions.
NewModel(Func<int,double[]>? embedSeed = null) → AlgFormer Build THE production model — a deep, identity-init stack (built 1-layer-then-grown so every layer but the first starts as an identity pass-through). Deterministic: every node produces a byte-identical fresh model.
VocabHash (string) 8-hex content hash of the subword table — folds the vocab's actual content into Signature so a regenerated vocab (even same/larger count) is a hard fork.
Signature (string) Compact tag ("PRISM-3/v.../h.../d.../f.../c.../L.../S...") written into checkpoints so an incompatible model is rejected instead of silently mis-merged.
Fields (sealed record) Parsed signature fields.
Parse(string sig) → Fields? Parse a Signature string; null if unparseable.
CanUpgradeFrom(Fields old) → bool Whether an old checkpoint can be upgraded in place (same version/vocab-hash/dim/frozen/layers; shifts/context same-or-smaller).
MeshCompatible(string theirSig) → bool Exact-signature swarm gate — only an identical-spec peer may exchange weights.
using PrismFormer;

var production = PrismSpec.NewModel();   // the real shape: Dim 256, Context 512, Layers 32, Shifts 64 — large; fine to construct, don't train it in a demo
Console.WriteLine($"Signature={PrismSpec.Signature}");
Console.WriteLine($"MeshCompatible(self)={PrismSpec.MeshCompatible(PrismSpec.Signature)}");
var parsed = PrismSpec.Parse(PrismSpec.Signature);
Console.WriteLine($"parsed.Layers={parsed?.Layers} CanUpgradeFrom(self)={(parsed != null && PrismSpec.CanUpgradeFrom(parsed))}");

Weight-management utilities

Member Purpose
EmbRow(int id) → double[] Read-only copy of a token's current embedding row (diagnostics).
Face(int id) → double[] (HoloFormer only) Read-only view (no clone) of a token's codec face. Do not mutate.
Seed(int id, double[] face) Overwrite a token's embedding row from an external face (e.g. a codec encoding), e.g. when a symbol is first assigned an id.
ResetToken(int id, int seed) Reclaim a vocab slot for reuse: reseed the learned tail, zero the readout bias, drop the optimizer moment. The frozen prefix is left intact.
RestoreFrozen(Func<int,double[]> face) Re-snap only the frozen identity prefix of every row to its canonical face — call after any operation (weight averaging, a bleed) that could introduce floating-point drift there.
ReinitFrom(AlgFormer/HoloFormer src) Overwrite every parameter from a same-shape model and clear optimizer state in place.
PartialAverage(AlgFormer/HoloFormer o, double alpha) Elastic-average the overlapping parameters with another model that shares this model's codec but may differ in depth/shifts/context — only the aligned low-index components move. alpha is the merge rate.
using PrismFormer;

var a = new AlgFormer(vocab: 8, shifts: 3, layers: 2, maxContext: 4, dModel: 6, frozenPrefix: 0, seed: 1);
var b = new AlgFormer(vocab: 8, shifts: 3, layers: 3, maxContext: 4, dModel: 6, frozenPrefix: 0, seed: 2);
a.PartialAverage(b, alpha: 0.1);     // only the shared (first 2 of 3) layers move
a.ResetToken(id: 0, seed: 99);
Console.WriteLine($"row0 after reset: [{string.Join(",", a.EmbRow(0).Select(x => x.ToString("F3")))}]");

Tokenizer

A fixed printable-ASCII character vocabulary, optionally extended with a deterministic committed list of subword n-grams (2..16 chars). With an empty subword list, encoding is byte-for-byte char-level.

Member Purpose
CharVocab (ITokenizer) The base char vocabulary. Lo/Hi (32/126), Printable (95), End (95, STOP), N (96), Pad (0). Total/Size (int) — 96 + subword count, the real model vocab. Id(char)/Chr(int)/Symbol(int)/Encode(string)/Decode(ids).
ITokenizer (interface) int[] Encode(string s) — the minimal contract CharVocab/SubwordVocab/a custom tokenizer must satisfy to feed the data sources.
SubwordVocab (sealed class) MaxLen (const int = 16) — longest subword accepted. CharN (96), Size, Subwords. Ctor from a subword list (throws ArgumentException on an out-of-range/duplicate/non-printable entry). Encode(string)/Symbol(int)/Decode(ids).
SubwordBuilder (static) BuilderMaxLen (const int = 4). FromSegments(segments, topBi, topTri, topQuad, includeAllDigit2 = true) → List<string> — mine the top-K n-grams per length (plus every 2-digit pair) from a corpus, in a canonical, reproducible order.
SubwordTable (static) List (IReadOnlyList<string>) — the package's own committed subword list, loaded once from an embedded resource. Empty if the resource is absent (pure char-level fallback).
using PrismFormer;

var chars = new CharVocab();
int[] charIds = chars.Encode("hi");
Console.WriteLine($"CharVocab.Total={CharVocab.Total} encoded=[{string.Join(",", charIds)}] decoded={chars.Decode(charIds)}");

var mined = SubwordBuilder.FromSegments(new[] { "the cat sat", "the cat ran" }, topBi: 4, topTri: 2, topQuad: 0, includeAllDigit2: false);
var sw = new SubwordVocab(mined);
int[] subIds = sw.Encode("the cat");
Console.WriteLine($"mined=[{string.Join(",", mined)}] subwordVocabSize={sw.Size} encodedLen={subIds.Length}");

Console.WriteLine($"SubwordTable.List.Count={SubwordTable.List.Count}");   // the package's own shipped list

Data sources

All implement IJobSource (long Count; (int[] Ctx, int Target) GetExample(long index)), so a distributed host can ship only example positions — every node reconstructs the same example from the same source deterministically.

Member Purpose
CorpusSource Continuous-text lane: dense context→next-token windows, reset at file/segment boundaries. Ctor (int ctx, IEnumerable<string> segments, ITokenizer? vocab = null, int minCtx = 0); minCtx < ctx enables variable-length windows. FromFolders(ctx, vocab, params string[] folders) (static) reads every *.txt under the folders. Vocab/Segments exposed.
CorpusResidentSlice Opt-in memory-bounded wrapper around CorpusSource for corpora too large to hold resident in full: holds a random byte-budgeted subset, periodically MaybeReroll-refreshed. Non-deterministic over time — never use with the position-only swarm relay or a seeded-replay run. ChunkBytes (const long). Ctor (int ctx, ITokenizer? vocab, long budgetBytes, IEnumerable<string> folders, int minCtx = 0, int? seed = null); FromFolders(...) (static); MaybeReroll(TimeSpan interval) → bool.
PairSource Independent prompt → target lane (Q&A/chat): one example per target token, never spanning into another pair. Ctor (int ctx, IEnumerable<(string Prompt, string Target)> pairs, ITokenizer? vocab = null). PairCount, SkippedTooLong (pairs that can't fit the context), SampleQA(long seed), TokenRuns. FromFolders(ctx, vocab, params folders) reads .tsv/.pairs files; FromChat(ctx, vocab, transcript) / ChatPairs(transcript) build pairs from a "user: .../prism: ..." transcript.
GroupChat (static) Turns a multi-party transcript into training pairs: HumanTag/AiTag ("user: "/"prism: "). Pairs(transcript), AsChat(qa), Swap(transcript).
MixSource MixSource(params IJobSource[] sources) — unions several sources into one index-addressable stream.
GossipInbox A gossip/ folder as a live training-pair inbox: GossipInbox(string folder, int cap = 50_000); Add(pairs, from = null) → new-count; Count; Folder. Deduplicated, capacity-capped.
using PrismFormer;

var corpus = new CorpusSource(ctx: 4, segments: new[]
{
    "the quick brown fox jumps over the lazy dog, again and again, for no particular reason at all",
    "jumps over the lazy dog while the quick brown fox watches patiently from across the yard",
});
var (ctxTokens, target) = corpus.GetExample(0);
Console.WriteLine($"CorpusSource.Count={corpus.Count} example0: ctxLen={ctxTokens.Length} target={target}");

var pairs = new PairSource(ctx: 16, pairs: new[] { ("hello", "world"), ("foo", "bar") });
Console.WriteLine($"PairSource.Count={pairs.Count} PairCount={pairs.PairCount} SkippedTooLong={pairs.SkippedTooLong}");

var mixed = new MixSource(corpus, pairs);
Console.WriteLine($"MixSource.Count={mixed.Count}");

var tempDir = Path.Combine(Path.GetTempPath(), "algformer-package-doc-gossip");
var inbox = new GossipInbox(tempDir);
int added = inbox.Add(new[] { ("hi", "there") });
Console.WriteLine($"GossipInbox added={added} count={inbox.Count}");
Directory.Delete(tempDir, recursive: true);

var chatPairs = GroupChat.Pairs("user: hello\nprism: hi there\nuser: how are you\n");
Console.WriteLine($"GroupChat.Pairs -> {chatPairs.Count} pair(s)");

CorpusSource's default tokenizer is the full shipped subword vocabulary (CharVocab, ~36.9k entries at the time of writing), not raw characters — a short segment can tokenize to fewer tokens than its character count, and a segment with encodedLength <= minCtx (default minCtx = ctx) is silently dropped. Use long-enough segments (or a small ctx) or pass your own ITokenizer/CharVocab() if you need character-level, predictable-length windows.


Swarm

Distributed/federated training over MQTT — both host and worker only make outbound connections to a broker, so it works through any home NAT with no port-forwarding. Two transports:

  • MqttRelay — full model + full batch data crosses the wire every round. Simple, works for any IBatchTrainer consumer, but ships your training data.
  • MqttJobRelay (MqttJob*) — only a manifest (once) + example positions cross the wire; every worker reconstructs its shard locally from the same IJobSource. No training data ever leaves the host.

A third, independent layer — SwarmChatter — is a ping-ranked peer-gossip mesh for exchanging training pairs, weight slices, and inference queries between peers (not gradient-merge training).

Member Purpose
IBatchTrainer See Training — implemented by PrismTrainer, MqttRelayHost, MqttJobHost.
MqttRelay (static) DefaultBroker/DefaultRoomName/Broker/Port/DefaultRoom — configurable via PRISM_BROKER/PRISM_BROKER_PORT/PRISM_ROOM env vars (also PRISM_BROKER_USER/PASS/TLS). NewRoom() → random room id. MakeRoomCode(room)/ParseRoomCode(code) — pasteable base64 connection codes.
MqttRelayHost(AlgFormer model) : IBatchTrainer Model, ChunkTarget (4096), MinRoundIntervalMs (500), ActiveWorkers, Hosting. StartRelay(onEvent = null, room = null) → pasteable code (connects to the broker — do this only with a live broker reachable). StopRelay(). TrainBatch(...) as IBatchTrainer.
MqttRelayWorker Model (AlgFormer?, null until synced). JoinRoom(string code, onEvent = null, ct = default) — blocks on the calling thread processing messages until the host finishes or ct cancels; call from a background thread/task.
MqttJob (static) MakeCode(room)/ParseCode(input) — connection codes for the position-only relay (distinct prefix from MqttRelay's).
MqttJobHost(AlgFormer model, IJobSource source, byte[] manifest) : IJobTrainer Same shape as MqttRelayHost but trains via TrainPositions; ships the manifest once, then only positions.
MqttJobWorker(Func<byte[], IJobSource> sourceFactory) Model (AlgFormer?). JoinRoom(...) — sourceFactory maps the received manifest bytes to the matching local IJobSource.
IJobSource / IJobTrainer See Data sources / TrainPositions(IReadOnlyList<long> positions, double lr) → mean loss.
LocalJobTrainer(AlgFormer model, IJobSource source) : IJobTrainer Reconstructs assigned examples locally and trains on local cores — the non-networked IJobTrainer.
SyntheticJobSource(long count, int vocab = 32, int ctxLen = 4, int seed = 12345) : IJobSource Deterministic synthetic data for tests/demos. Manifest()/FromManifest(byte[]) (static) round-trip its parameters.
SwarmChatter(string room, Func<string,(double Conf,string Continuation)> serve, Action<string,string> onPair, Action<int,double[]>? onWeightSlice = null, Action<string>? log = null, Action<bool,string>? onGroup = null, Func<string,string>? groupServe = null, Action<string>? absorbContext = null, string? signature = null) The gossip-mesh peer. AnswerQuorum/BleedFanout/PingSample/GossipSample/PeerTtlMs/MaxPeers (tunable public fields). PeerCount, ReconnectDropped (monotonic pile-up counter). Start()/Stop() connect/disconnect (needs a live broker). SharePair(prompt, target), ShareWeightSlice(start, vals), BroadcastRoster(), AskSwarm(prompt, timeoutMs = 8000), GroupBroadcast(human, text), GroupAskNext(transcript, onReply, timeoutMs = 8000) (async).

Construction and wiring compile and run without a broker; only Start/StartRelay/JoinRoom actually connect out:

using PrismFormer;

var model = new AlgFormer(vocab: 10, shifts: 3, layers: 2, maxContext: 5, dModel: 8, frozenPrefix: 0);
var relayHost = new MqttRelayHost(model) { ChunkTarget = 2048, MinRoundIntervalMs = 250 };
Console.WriteLine($"relay host ready: ActiveWorkers={relayHost.ActiveWorkers} Hosting={relayHost.Hosting}");
// relayHost.StartRelay(...) would dial out to MqttRelay.Broker — only call this with a real broker reachable.

var source = new SyntheticJobSource(count: 1000, vocab: model.Vocab, ctxLen: 3);
var jobHost = new MqttJobHost(model, source, manifest: source.Manifest());
Console.WriteLine($"job host ready: ActiveWorkers={jobHost.ActiveWorkers}");

var local = new LocalJobTrainer(model, source);
double trainedLoss = local.TrainPositions(new long[] { 0, 1, 2, 3 }, lr: 1e-2);
Console.WriteLine($"local job-trainer loss={trainedLoss:F4}");

string roomCode = MqttRelay.MakeRoomCode(MqttRelay.NewRoom());
string? parsedRoom = MqttRelay.ParseRoomCode(roomCode);
Console.WriteLine($"room code round-trips: {parsedRoom != null}");

var chatter = new SwarmChatter("demo-room", serve: _ => (0.9, "ok"), onPair: (_, __) => { }, signature: "demo-sig")
{
    AnswerQuorum = 2,
    BleedFanout = 2,
};
Console.WriteLine($"chatter constructed: PeerCount={chatter.PeerCount} ReconnectDropped={chatter.ReconnectDropped}");
// chatter.Start() would dial out to the broker — only call this with a real broker reachable.

Parallelism

Member Purpose
IParallelMap (interface) The only parallelism primitive the pure cores know about. Map(int chunks, int minForParallel, Action<int> body) — synchronous, blocking; safe from any desktop/off-UI-thread caller, never from a genuinely single-threaded host (deadlocks). MapAsync(...) — the browser/WASM-safe alternative, has a default implementation (sequential await below minForParallel, else one Task.Run per chunk).
SequentialMap Instance (singleton) — the default Map on every model; a plain loop, both sync and async.
PrismEval.Cpu → IParallelMap The EvalApp CPU-gated fan-out — set a model's Map to this for serve-time parallelism across cores (training has its own, separate parallelism via PrismTrainer/IBatchTrainer; don't nest the two).
PrismEval.Licensed (bool) Whether the EvalApp pipeline built successfully (else a sequential fallback). Not a license gate — nothing in this package is gated behind a key; this only reflects build success.
PrismEval.DefaultKey (const string) The shipped EvalApp key.
PrismEval.Send(Func<CancellationToken,Task> publish, ct = default) Route an outbound network publish through the Network-gated pipeline (used internally by the swarm transports).
using PrismFormer;

var model = new AlgFormer(vocab: 10, shifts: 3, layers: 2, maxContext: 5, dModel: 8, frozenPrefix: 0)
{
    Map = PrismEval.Cpu,   // serve-time fan-out across cores; leave the default SequentialMap for training
};
double[] logits = model.LogitsFor(new[] { 1, 2, 3 });
Console.WriteLine($"PrismEval.Licensed={PrismEval.Licensed} logits.Length={logits.Length}");

Self-check oracles

Both cores ship finite-difference gradient-check oracles and round-trip/regression self-checks as public static methods — call them from your own harness to prove the math on your build/runtime, not just trust the package's own CI. Each uses a small, fixed, internal toy model and returns true/false (with the worst relative error via out double worstRel where applicable).

Member Checks
AlgFormer.GradCheck(out double worstRel) The GLU-combine FFN path (default bindFfn:false).
AlgFormer.GradCheckBind(out double worstRel) The complex-bind FFN path (bindFfn:true).
HoloFormer.GradCheck(out double worstRel) The holographic core's default (GLU) path.
HoloFormer.GradCheckBind(out double worstRel) The complex-bind FFN path.
HoloFormer.GradCheckUnitary(out double worstRel) The unit-modulus-normalised (unitary:true) path.
HoloFormer.GradCheckThink(out double worstRel) The latent-thought recurrence.
HoloFormer.CheckThinkN0(out double maxDiff) nThoughts=0 reproduces plain Accumulate exactly.
HoloFormer.FlatGrad(Grads g) → double[] Flattens a gradient buffer to one array — a helper for writing your own probes against the oracles above.
HoloFormer.GradCheckIter(out double worstRel) The single-layer weight-tied iteration path.
HoloFormer.GradCheckCleanIter(out double worstRel) The single-layer iteration + vocab-attractor cleanup path.
HoloFormer.GradCheckStackIter(out double worstRel) The per-layer StackIter path.
HoloFormer.GradCheckStackIterPerLayerAlpha(out double worstRel) StackIter with non-uniform per-layer alpha.
HoloFormer.GradCheckStackIterAllPos(out double worstRel) StackIterAccumulateAllPos matches the sum of single-position StackIterAccumulate calls.
HoloFormer.GradCheckStackIterAllPosOverflow(out double worstRel) The one-token-overflow (final-position-trainable) case.
HoloFormer.GradCheckStackIterAllPosOverflowGuard() → bool Rejects an overflow of more than one token.
HoloFormer.RegressionStackIterAllPosBackCompat(out double worstRel) In-window lengths stay bit-identical to the pre-overflow-fix behaviour.
using PrismFormer;

bool ok1 = AlgFormer.GradCheck(out var rel1);
bool ok2 = HoloFormer.GradCheckStackIter(out var rel2);
bool ok3 = HoloFormer.GradCheckStackIterAllPos(out var rel3);
Console.WriteLine($"GradCheck ok={ok1} rel={rel1:E2}; StackIter ok={ok2} rel={rel2:E2}; AllPos ok={ok3} rel={rel3:E2}");

Exceptions

Type Thrown when
CheckpointFormatException A Deserialize/Load buffer or stream trailer is truncated, carries a wrong magic (different model type/corruption), or a version newer than this build understands. FoundVersion reports what was found (-1 if unreadable).
ArgumentException / ArgumentOutOfRangeException A StackIter/EVE call with a wrong-length alpha/LayerOutNorm/LayerInput array, a StackIterAccumulateAllPos sequence more than one token past Context, a Gate-style vocab/logits-length mismatch, or an out-of-range GrowLayers(atFront) insert index — always named explicitly, never a bare index-out-of-range.

Other public surface worth knowing about

  • DistNet (public static class) exists as wire-format plumbing shared by the two MQTT relay transports; every one of its members is internal (visible only to an InternalsVisibleTo-granted assembly). A normal NuGet consumer sees an empty class — nothing to call directly. Use MqttRelayHost/ MqttJobHost/MqttRelayWorker/MqttJobWorker instead; they already use it for you.
  • Phasor dependency. AlgFormer/HoloFormer's dModel/frozenPrefix default from Phasor.PhasorLayout.Dim/FrozenReals, and PhasorCodec.Encode(string) is the standard embedSeed source for a production-shaped model — both come from the separate EvaluatedApplications.Phasor NuGet package, pulled in automatically as a dependency.

License

Proprietary — this package ships the compiled library only; see LICENSE for the full terms. Installing and using unmodified copies for internal evaluation and non-commercial development or testing is licensed; commercial, production, or revenue-generating use requires a separate commercial licence from the owner. No feature on this page is gated behind a tier or a licence key — every capability described works identically with or without one. Copyright (c) 2026 Dongyang Stephen Chen, trading as Evaluated Applications. All rights reserved.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on EvaluatedApplications.AlgFormer:

Package Downloads
EvaluatedApplications.AlgFormer.Gpu

ILGPU/CUDA acceleration for the AlgFormer package's HoloFormer model: GpuHoloTrainer runs batched GPU forward/backward training (CPU Adam by default, with an opt-in fused on-GPU Adam step) and GPU inference (Logits, StackIterLogits). GpuDevice auto-detects a CUDA device at startup and otherwise runs the SAME kernels on ILGPU's own CPU accelerator, so one build works with or without a CUDA card; genuinely over-length windows still run on the CPU HoloFormer directly. Every kernel is gradchecked against the CPU HoloFormer as its correctness oracle (float-close fp32, not bit-identical). Also ships an opt-in, default-OFF "ADAM & EVE" per-layer directional gradient gate layered on the fused on-GPU Adam step, live in production training (not an unused experiment) since 2026-09-24, plus preference (DPO) training on the GPU: per-sequence log-probabilities (SequenceLogProb) and a signed-weight all-positions training step (TrainBatchAllPosWeighted), at the same weight-tied depth the trainer trains at, with a frozen reference model (NewReference); exact bit-identical GPU page transforms for Phasor's Pleroma key band (PleromaPageTransform: Forward, Inverse, Dft over a 61-bit or sub-40-bit prime field, with an ILGPU CPU and a managed backend) and the Pleroma Cascade Newton pass (PleromaNewtonGpu); and a deprecated non-holo GpuModel/GpuTrainer twin for the older softmax-attention AlgFormer core. Add this package only if you want GPU acceleration; the core AlgFormer package stays dependency-free and AOT/trim-safe without it.

EvaluatedApplications.Prose

Grammar-driven synthetic corpus generator: mines nouns, verbs and adjectives and the syntax that joins them from real text with the rules of grammar, stores them in HoloDb, and recombines them into new grammatical sentences built only from words and pairings the text used, plus reading-comprehension Q&A pairs (single-sentence, multi-sentence passage, and two-turn). Rules-first (deterministic, zero-training) part-of-speech tagging, chunking and role assignment; mining fans out across cores through EvalApp (generation does too, opt-in); an optional mini-HoloFormer scorer re-ranks generated candidates by next-lemma likelihood once trained (POS tagging stays 100% rules-based).

EvaluatedApplications.Prism

Beta: A production standard for AlgFormer/HoloFormer models: an append-only lineage journal that answers "what was true at this point in training" without ever re-deriving it from current state, a confidence-gated decode policy (resonance-floor or nucleus sampling, with a degeneracy guard), and a growth surface that grows a model's context, layers, shifts, or vocabulary correctly by construction while stamping the journal automatically. For teams running AlgFormer/HoloFormer models in production who want checkpoint lineage and decode behaviour to stay correct through every growth step, not re-derived from whatever is live at the time.

EvaluatedApplications.EvalApp.Neural

An always-learning neural concurrency tuner for EvalApp. A small holographic policy model (HoloFormer, d48/L2/K2/shifts8) replaces the built-in heuristic on your app's resource gates and keeps learning from its own decisions, so it re-converges when the best concurrency moves. Ships with a warm-start model, makes at most one decision per 25 ms, and keeps learning in production. Opt in with .WithNeuralTuning(), or pass in a model you own with .WithNeuralTuning(model).

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.1 114 11/10/2026
4.0.0 90 11/9/2026
3.7.0 100 11/9/2026
3.4.0 116 11/3/2026
3.3.0 185 10/8/2026
3.2.0 124 10/6/2026
3.1.0 159 10/3/2026
3.0.0 160 10/3/2026
2.20.2 192 10/3/2026
2.20.1 160 10/3/2026
2.20.0 174 10/2/2026
2.19.1 182 10/2/2026
2.19.0 114 9/25/2026
2.18.0 126 9/24/2026
2.17.0 123 9/24/2026
2.16.0 123 9/24/2026
2.15.0 143 9/23/2026
2.14.0 126 9/23/2026
2.13.0 112 9/23/2026
2.12.2 117 9/22/2026
Loading failed