Multiply reads an approximate sparse product off the graph: every pair the walk scored for each left row, in traversal order, rather than only the nearest.
It runs on an inner-product index alone, and its keys, products and row offsets land in an arena like Get’s rows.
Maxsim scores multi-row queries against multi-vector documents: every query row takes its best match within a key, and those maxima sum to that key’s score.
A document is one key holding its token rows, which is what a ValuesPerKey above one exists for, and the wanted count is over documents rather than rows.
It runs on an inner-product index alone, since a sum of maxima needs logits rather than distances.
The keys land as Multiply’s pairs do, one DenseProducts run per query, largest score first, and a zero wanted count keeps every key a query scored.
Attend is Flash Attention folded into the walk: every key it scores folds into each head’s running maximum, partition and weighted value sum, with no top-k cut, and the outputs land in an arena already divided by the partition.
The index stores no values, so a ValueLookup names, for every scored key, its row of a Values matrix as wide as the keys and stored in the index’s own quantization.
A key without a row, or values of another width or scalar type, refuses the call with StatusShapeMismatch, since a missing row is a wrong softmax rather than a smaller one.
A VRAM walk resolves its rows through a device function, which no Go function can be, so Attend refuses a VRAM index with StatusDevice.
With HeadCount: 8, row t * 8 + h of the queries is head h of token t, and the heads of one token share its walk.
The attended rows take the queries’ scalar type unless the config’s OutputsScalar names another.
A Carry of one DenseSoftmaxState per query row, lent rather than written into the arena, folds this branch into another over the same queries, such as a recent window kept out of the index.
API
Types
DenseAttendConfigDenseAttendConfig carries the optional settings of Attend.
HeadCount is the query heads sharing the index's key-value head, and with it one walk per token: row t * HeadCount + h is head h of token t, so it must divide the rows; zero means one.
Carry is the online-softmax state, one entry per query row and lent by the caller, which folds this call into another over the same queries by partial-softmax rescaling.
type DenseSoftmaxState struct {
MaximumScore float32
Partition float32
}
Fields
MaximumScore
float32
MaximumScore is the largest logit seen so far - the recurrence's m.
Partition
float32
Partition is the sum of exponentials taken against that maximum - the recurrence's l.
ValueLookupValueLookup resolves the keys an attention walk scores to their value rows, all of them rows of Values, which stays pinned until the call is final.
type ValueLookup struct {
Values RowsView
Row func(key Key) (row uint, found bool)
}
Values must be as wide as the keys and stored in the index's own quantization, since the call
reads them as such; a key Row names no row of Values for, or values of another shape, refuse
the call with StatusShapeMismatch. Row runs on the executor's threads together, so it must be
safe for concurrent use, and a panic inside it answers no row and becomes the call's error.
Row is a host function, while a VRAM walk resolves its rows through a device one, so Attend
refuses a VRAM handle with StatusDevice.
StructDenseProductsDenseProducts is the ragged sparse product Multiply wrote into its arena: per left row, every pair its walk scored, in traversal order.3
QueryQuery borrows one left row's pairs from the arena - a key naming each indexed entry, and its product - or one query's keys, refused with StatusInvalidArgument when query is not below Queries.
RequiredRequired reports the pairs the walks scored across every left row, or for Maxsim the keys scored across every query, before the wanted bound cut any.