Livt packages
Eccelerators.Tokenization
Version 0.2.0
Bounded BPE and Unigram tokenization, text normalization, and decoding components for Livt hardware.
Published files (27)
src/Bpe/BpeMergeEngine64.lvt
namespace Eccelerators.Tokenization.Bpe
/**
* Applies ranked byte-pair merges to one bounded sequence of token symbols.
*
* The engine stores at most 64 symbols. Compute repeatedly selects the
* available pair with the lowest rank and merges every non-overlapping
* occurrence of that pair, matching the conventional BPE word algorithm.
*/
component BpeMergeEngine64
{
// Maximum number of input and output symbols in one piece.
public const MAX_SYMBOLS: int = 64
// Sentinel above every valid non-negative merge rank.
const NO_MERGE_RANK: int = 2147483647
mergeTable: IBpeMergeTable
tokens: int[64]
tokenCount: int
error: bool
/**
* Connects the engine to a caller-provided merge table.
*/
new(mergeTable: IBpeMergeTable)
{
this.mergeTable = mergeTable
}
/**
* Clears the current symbol sequence and error state.
*/
public fn Reset()
{
tokenCount = 0
error = false
}
/**
* Appends one initial symbol and returns whether it was accepted.
*/
public fn AppendSymbol(token: int) bool
{
if (tokenCount >= MAX_SYMBOLS) {
error = true
return false
}
tokens[tokenCount] = token
tokenCount++
return true
}
/**
* Applies all ranked merges until no pair in the table remains.
*/
public fn Compute()
{
var keepMerging = true
while (keepMerging && tokenCount > 1) {
var found = false
var bestRank = NO_MERGE_RANK
var bestLeft = 0
var bestRight = 0
var bestResult = 0
for (var index = 0; index + 1 < tokenCount; index++) {
this.mergeTable.Lookup(tokens[index], tokens[index + 1])
if (this.mergeTable.HasMerge()) {
var rank = this.mergeTable.GetRank()
if (!found || rank < bestRank) {
found = true
bestRank = rank
bestLeft = tokens[index]
bestRight = tokens[index + 1]
bestResult = this.mergeTable.GetMergedToken()
}
}
}
if (!found) {
keepMerging = false
} else {
var readIndex = 0
var writeIndex = 0
while (readIndex < tokenCount) {
var pairMatches = false
if (readIndex + 1 < tokenCount) {
pairMatches = tokens[readIndex] == bestLeft &&
tokens[readIndex + 1] == bestRight
}
if (pairMatches) {
tokens[writeIndex] = bestResult
readIndex = readIndex + 2
} else {
tokens[writeIndex] = tokens[readIndex]
readIndex++
}
writeIndex++
}
tokenCount = writeIndex
}
}
}
/**
* Returns the number of symbols currently stored.
*/
public fn GetCount() int { return tokenCount }
/**
* Returns one result symbol, or zero when the index is outside the result.
*/
public fn GetToken(index: int) int
{
if (index < 0 || index >= tokenCount) { return 0 }
return tokens[index]
}
/**
* Returns whether an input exceeded the bounded symbol storage.
*/
public fn HasError() bool { return error }
}