@hviana/sema 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +470 -0
- package/AUTHORS.md +12 -0
- package/COMMERCIAL-LICENSE.md +19 -0
- package/CONTRIBUTING.md +15 -0
- package/HOW_IT_WORKS.md +4210 -0
- package/LICENSE.md +117 -0
- package/README.md +290 -0
- package/TRADEMARKS.md +19 -0
- package/example/demo.ts +46 -0
- package/example/train_base.ts +2675 -0
- package/index.html +893 -0
- package/package.json +25 -0
- package/src/alphabet.ts +34 -0
- package/src/alu/README.md +332 -0
- package/src/alu/src/alu.ts +541 -0
- package/src/alu/src/expr.ts +339 -0
- package/src/alu/src/index.ts +115 -0
- package/src/alu/src/kernel-arith.ts +377 -0
- package/src/alu/src/kernel-bits.ts +199 -0
- package/src/alu/src/kernel-logic.ts +102 -0
- package/src/alu/src/kernel-nd.ts +235 -0
- package/src/alu/src/kernel-numeric.ts +466 -0
- package/src/alu/src/operation.ts +344 -0
- package/src/alu/src/parser.ts +574 -0
- package/src/alu/src/resonance.ts +161 -0
- package/src/alu/src/text.ts +83 -0
- package/src/alu/src/value.ts +327 -0
- package/src/alu/test/alu.test.ts +1004 -0
- package/src/bytes.ts +62 -0
- package/src/config.ts +227 -0
- package/src/derive/README.md +295 -0
- package/src/derive/src/deduction.ts +263 -0
- package/src/derive/src/index.ts +24 -0
- package/src/derive/src/priority-queue.ts +70 -0
- package/src/derive/src/rewrite.ts +127 -0
- package/src/derive/src/trie.ts +242 -0
- package/src/derive/test/derive.test.ts +137 -0
- package/src/extension.ts +42 -0
- package/src/geometry.ts +511 -0
- package/src/index.ts +38 -0
- package/src/ingest-cache.ts +224 -0
- package/src/mind/articulation.ts +137 -0
- package/src/mind/attention.ts +1061 -0
- package/src/mind/canonical.ts +107 -0
- package/src/mind/graph-search.ts +1100 -0
- package/src/mind/index.ts +18 -0
- package/src/mind/junction.ts +347 -0
- package/src/mind/learning.ts +246 -0
- package/src/mind/match.ts +507 -0
- package/src/mind/mechanisms/alu.ts +33 -0
- package/src/mind/mechanisms/cast.ts +568 -0
- package/src/mind/mechanisms/confluence.ts +268 -0
- package/src/mind/mechanisms/cover.ts +248 -0
- package/src/mind/mechanisms/extraction.ts +422 -0
- package/src/mind/mechanisms/recall.ts +241 -0
- package/src/mind/mind.ts +483 -0
- package/src/mind/pipeline-mechanism.ts +326 -0
- package/src/mind/pipeline.ts +300 -0
- package/src/mind/primitives.ts +201 -0
- package/src/mind/rationale.ts +275 -0
- package/src/mind/reasoning.ts +198 -0
- package/src/mind/recognition.ts +234 -0
- package/src/mind/resonance.ts +0 -0
- package/src/mind/trace.ts +108 -0
- package/src/mind/traverse.ts +556 -0
- package/src/mind/types.ts +281 -0
- package/src/rabitq-hnsw/README.md +303 -0
- package/src/rabitq-hnsw/src/database.ts +492 -0
- package/src/rabitq-hnsw/src/heap.ts +90 -0
- package/src/rabitq-hnsw/src/hnsw.ts +514 -0
- package/src/rabitq-hnsw/src/index.ts +15 -0
- package/src/rabitq-hnsw/src/prng.ts +39 -0
- package/src/rabitq-hnsw/src/rabitq.ts +308 -0
- package/src/rabitq-hnsw/src/store.ts +994 -0
- package/src/rabitq-hnsw/test/hnsw.test.ts +1213 -0
- package/src/store-sqlite.ts +928 -0
- package/src/store.ts +2148 -0
- package/src/vec.ts +124 -0
- package/test/00-extract.test.mjs +151 -0
- package/test/01-floor.test.mjs +20 -0
- package/test/02-roundtrip.test.mjs +83 -0
- package/test/03-recall.test.mjs +98 -0
- package/test/04-think.test.mjs +627 -0
- package/test/05-concepts.test.mjs +84 -0
- package/test/08-storage.test.mjs +948 -0
- package/test/09-edges.test.mjs +65 -0
- package/test/11-universality.test.mjs +180 -0
- package/test/13-conversation.test.mjs +228 -0
- package/test/14-scaling.test.mjs +503 -0
- package/test/15-decomposition-gap.test.mjs +0 -0
- package/test/16-bridge.test.mjs +250 -0
- package/test/17-intelligence.test.mjs +240 -0
- package/test/18-alu.test.mjs +209 -0
- package/test/19-nd.test.mjs +254 -0
- package/test/20-stability.test.mjs +489 -0
- package/test/21-partial.test.mjs +158 -0
- package/test/22-multihop.test.mjs +130 -0
- package/test/23-rationale.test.mjs +316 -0
- package/test/24-generalization.test.mjs +416 -0
- package/test/25-embedding.test.mjs +75 -0
- package/test/26-cooperative.test.mjs +89 -0
- package/test/27-saturation-drop.test.mjs +637 -0
- package/test/28-unknowable.test.mjs +88 -0
- package/test/29-counterfactual.test.mjs +476 -0
- package/test/30-conflict-resolution.test.mjs +166 -0
- package/test/31-audit.test.mjs +288 -0
- package/test/32-confluence.test.mjs +173 -0
- package/test/33-multi-candidate.test.mjs +222 -0
- package/test/34-cross-region.test.mjs +252 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { Prng } from "./prng.js";
|
|
2
|
+
|
|
3
|
+
export interface QueryContext {
|
|
4
|
+
vmin: number;
|
|
5
|
+
delta: number;
|
|
6
|
+
sumQInt: number;
|
|
7
|
+
/**
|
|
8
|
+
* Per-query lookup table of length nbytes*256. `qlut[p*256 + b]` is the sum of
|
|
9
|
+
* the quantised query values at the (up to 8) coordinates whose code bits are
|
|
10
|
+
* set in byte value `b` at code-byte position `p`. The query/code inner product
|
|
11
|
+
* for a stored code is then sum over its bytes of qlut[p*256 + codeByte_p].
|
|
12
|
+
*/
|
|
13
|
+
qlut: Uint8Array | Uint16Array;
|
|
14
|
+
/** number of bytes per code (paddedDim / 8). */
|
|
15
|
+
nbytes: number;
|
|
16
|
+
/** true when the (centered) query has zero norm. */
|
|
17
|
+
zero: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface RaBitQOptions {
|
|
21
|
+
queryBits?: number;
|
|
22
|
+
rounds?: number;
|
|
23
|
+
seed?: number;
|
|
24
|
+
centroid?: ArrayLike<number>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function nextPow2(n: number): number {
|
|
28
|
+
let p = 1;
|
|
29
|
+
while (p < n) p <<= 1;
|
|
30
|
+
return p;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Set-bit count for every byte value, for counting code bits during the byte scan. */
|
|
34
|
+
const POPCOUNT8 = new Uint8Array(256);
|
|
35
|
+
for (let i = 1; i < 256; i++) POPCOUNT8[i] = POPCOUNT8[i >> 1] + (i & 1);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 1-bit RaBitQ quantizer (cosine) -- the ONLY representation of a vector kept by
|
|
39
|
+
* the index. A D-dimensional vector collapses to ceil(D/32) 32-bit words of sign
|
|
40
|
+
* bits, e.g. a 256-d vector goes from 256*4 = 1024 bytes to 32 bytes of code.
|
|
41
|
+
*
|
|
42
|
+
* Each vector is centered by an optional centroid, normalised, rotated by a
|
|
43
|
+
* fast random orthogonal transform (random sign flips + Walsh-Hadamard,
|
|
44
|
+
* O(D log D)) and reduced to one sign bit per padded dimension. The random
|
|
45
|
+
* rotation makes the quantisation error essentially uniform across vectors, so
|
|
46
|
+
* the cosine estimate needs only a single fixed scale (`cosFactor`) rather than
|
|
47
|
+
* any per-vector correction.
|
|
48
|
+
*
|
|
49
|
+
* Two estimators are provided:
|
|
50
|
+
* - `estimate` : full-precision query vs stored code (accurate)
|
|
51
|
+
* - `codeDistanceBytes` : stored code vs stored code (Hamming based; used while
|
|
52
|
+
* building the graph, where neither side is full precision)
|
|
53
|
+
*
|
|
54
|
+
* Reference: Gao & Long, "RaBitQ: Quantizing High-Dimensional Vectors with a
|
|
55
|
+
* Theoretical Error Bound for Approximate Nearest Neighbor Search", SIGMOD 2024.
|
|
56
|
+
*/
|
|
57
|
+
export class RaBitQuantizer {
|
|
58
|
+
readonly dim: number;
|
|
59
|
+
readonly paddedDim: number;
|
|
60
|
+
readonly codeWords: number;
|
|
61
|
+
readonly queryBits: number;
|
|
62
|
+
readonly rounds: number;
|
|
63
|
+
readonly seed: number;
|
|
64
|
+
readonly centroid: Float64Array;
|
|
65
|
+
|
|
66
|
+
private readonly sqrtD: number;
|
|
67
|
+
private readonly maxQInt: number;
|
|
68
|
+
private readonly signs: Float64Array[];
|
|
69
|
+
private readonly scratch: Float64Array;
|
|
70
|
+
|
|
71
|
+
/** Fixed cosine inner-product scale (= 1 / E[L1] of a rotated unit vector). */
|
|
72
|
+
readonly cosFactor: number;
|
|
73
|
+
|
|
74
|
+
// byte-LUT machinery for the query/code estimator
|
|
75
|
+
private readonly nbytes: number;
|
|
76
|
+
/** coordinate index sitting at byte position p, bit k -> bitCoord[p*8 + k]. */
|
|
77
|
+
private readonly bitCoord: Int32Array;
|
|
78
|
+
/** true when the largest possible LUT entry overflows a Uint8. */
|
|
79
|
+
private readonly lutWide: boolean;
|
|
80
|
+
|
|
81
|
+
constructor(dim: number, opts: RaBitQOptions = {}) {
|
|
82
|
+
this.dim = dim;
|
|
83
|
+
this.paddedDim = nextPow2(dim);
|
|
84
|
+
this.codeWords = Math.ceil(this.paddedDim / 32);
|
|
85
|
+
this.queryBits = opts.queryBits ?? 8;
|
|
86
|
+
this.rounds = opts.rounds ?? 3;
|
|
87
|
+
this.seed = (opts.seed ?? 0x1234abcd) >>> 0;
|
|
88
|
+
this.sqrtD = Math.sqrt(this.paddedDim);
|
|
89
|
+
this.cosFactor = Math.sqrt(Math.PI / (2 * this.paddedDim));
|
|
90
|
+
this.maxQInt = (1 << this.queryBits) - 1;
|
|
91
|
+
this.centroid = new Float64Array(dim);
|
|
92
|
+
if (opts.centroid) {
|
|
93
|
+
for (let i = 0; i < dim; i++) this.centroid[i] = opts.centroid[i] ?? 0;
|
|
94
|
+
}
|
|
95
|
+
const prng = new Prng(this.seed);
|
|
96
|
+
this.signs = [];
|
|
97
|
+
for (let r = 0; r < this.rounds; r++) {
|
|
98
|
+
const s = new Float64Array(this.paddedDim);
|
|
99
|
+
for (let i = 0; i < this.paddedDim; i++) {
|
|
100
|
+
s[i] = prng.next() < 0.5 ? -1 : 1;
|
|
101
|
+
}
|
|
102
|
+
this.signs.push(s);
|
|
103
|
+
}
|
|
104
|
+
this.scratch = new Float64Array(this.paddedDim);
|
|
105
|
+
|
|
106
|
+
// Map (code-byte position, bit-in-byte) -> coordinate, honouring the host
|
|
107
|
+
// byte order so the Uint8 view of the (Uint32) code buffer is interpreted
|
|
108
|
+
// correctly on both little- and big-endian platforms.
|
|
109
|
+
this.nbytes = this.paddedDim >>> 3;
|
|
110
|
+
const littleEndian = new Uint8Array(new Uint32Array([1]).buffer)[0] === 1;
|
|
111
|
+
this.bitCoord = new Int32Array(this.nbytes * 8);
|
|
112
|
+
for (let p = 0; p < this.nbytes; p++) {
|
|
113
|
+
const word = p >>> 2;
|
|
114
|
+
const localByte = littleEndian ? p & 3 : 3 - (p & 3);
|
|
115
|
+
const bitBase = word * 32 + localByte * 8;
|
|
116
|
+
for (let k = 0; k < 8; k++) this.bitCoord[p * 8 + k] = bitBase + k;
|
|
117
|
+
}
|
|
118
|
+
this.lutWide = 8 * this.maxQInt > 255;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** In-place fast Walsh-Hadamard transform; `a.length` must be a power of two. */
|
|
122
|
+
private fwht(a: Float64Array): void {
|
|
123
|
+
const n = a.length;
|
|
124
|
+
for (let len = 1; len < n; len <<= 1) {
|
|
125
|
+
const span = len << 1;
|
|
126
|
+
for (let i = 0; i < n; i += span) {
|
|
127
|
+
for (let j = i; j < i + len; j++) {
|
|
128
|
+
const u = a[j];
|
|
129
|
+
const v = a[j + len];
|
|
130
|
+
a[j] = u + v;
|
|
131
|
+
a[j + len] = u - v;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Apply the orthogonal rotation in place (a.length === paddedDim). */
|
|
138
|
+
private rotate(a: Float64Array): void {
|
|
139
|
+
const n = this.paddedDim;
|
|
140
|
+
const inv = 1 / this.sqrtD;
|
|
141
|
+
for (let r = 0; r < this.rounds; r++) {
|
|
142
|
+
const s = this.signs[r];
|
|
143
|
+
for (let i = 0; i < n; i++) a[i] *= s[i];
|
|
144
|
+
this.fwht(a);
|
|
145
|
+
for (let i = 0; i < n; i++) a[i] *= inv;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Encode a raw vector into its 1-bit sign code (the whole representation). */
|
|
150
|
+
encode(vec: ArrayLike<number>): Uint32Array {
|
|
151
|
+
const dim = this.dim;
|
|
152
|
+
const pd = this.paddedDim;
|
|
153
|
+
const buf = this.scratch;
|
|
154
|
+
let sq = 0;
|
|
155
|
+
for (let i = 0; i < dim; i++) {
|
|
156
|
+
const v = vec[i] - this.centroid[i];
|
|
157
|
+
buf[i] = v;
|
|
158
|
+
sq += v * v;
|
|
159
|
+
}
|
|
160
|
+
for (let i = dim; i < pd; i++) buf[i] = 0;
|
|
161
|
+
const code = new Uint32Array(this.codeWords);
|
|
162
|
+
if (sq === 0) {
|
|
163
|
+
return code;
|
|
164
|
+
}
|
|
165
|
+
const invNorm = 1 / Math.sqrt(sq);
|
|
166
|
+
for (let i = 0; i < dim; i++) buf[i] *= invNorm; // unit residual; padded dims stay 0
|
|
167
|
+
this.rotate(buf);
|
|
168
|
+
for (let i = 0; i < pd; i++) {
|
|
169
|
+
if (buf[i] > 0) code[i >>> 5] |= 1 << (i & 31);
|
|
170
|
+
}
|
|
171
|
+
return code;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Pre-process a full-precision query into the structure consumed by `estimate`. */
|
|
175
|
+
prepareQuery(vec: ArrayLike<number>): QueryContext {
|
|
176
|
+
const dim = this.dim;
|
|
177
|
+
const pd = this.paddedDim;
|
|
178
|
+
const nb = this.nbytes;
|
|
179
|
+
const buf = this.scratch;
|
|
180
|
+
let sq = 0;
|
|
181
|
+
for (let i = 0; i < dim; i++) {
|
|
182
|
+
const v = vec[i] - this.centroid[i];
|
|
183
|
+
buf[i] = v;
|
|
184
|
+
sq += v * v;
|
|
185
|
+
}
|
|
186
|
+
for (let i = dim; i < pd; i++) buf[i] = 0;
|
|
187
|
+
const qNorm = Math.sqrt(sq);
|
|
188
|
+
const qlut = this.lutWide
|
|
189
|
+
? new Uint16Array(nb * 256)
|
|
190
|
+
: new Uint8Array(nb * 256);
|
|
191
|
+
if (qNorm === 0) {
|
|
192
|
+
return { vmin: 0, delta: 0, sumQInt: 0, qlut, nbytes: nb, zero: true };
|
|
193
|
+
}
|
|
194
|
+
const invNorm = 1 / qNorm;
|
|
195
|
+
for (let i = 0; i < dim; i++) buf[i] *= invNorm;
|
|
196
|
+
this.rotate(buf);
|
|
197
|
+
let vmin = Infinity;
|
|
198
|
+
let vmax = -Infinity;
|
|
199
|
+
for (let i = 0; i < pd; i++) {
|
|
200
|
+
const x = buf[i];
|
|
201
|
+
if (x < vmin) vmin = x;
|
|
202
|
+
if (x > vmax) vmax = x;
|
|
203
|
+
}
|
|
204
|
+
const range = vmax - vmin;
|
|
205
|
+
const delta = range > 0 ? range / this.maxQInt : 0;
|
|
206
|
+
const invDelta = delta > 0 ? 1 / delta : 0;
|
|
207
|
+
|
|
208
|
+
// Quantise each (rotated) query coordinate to queryBits bits.
|
|
209
|
+
const qint = buf; // reuse: write the integer code back over the float buffer
|
|
210
|
+
let sumQInt = 0;
|
|
211
|
+
for (let i = 0; i < pd; i++) {
|
|
212
|
+
let q = delta > 0 ? Math.round((buf[i] - vmin) * invDelta) : 0;
|
|
213
|
+
if (q < 0) q = 0;
|
|
214
|
+
else if (q > this.maxQInt) q = this.maxQInt;
|
|
215
|
+
qint[i] = q;
|
|
216
|
+
sumQInt += q;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Build the byte LUT: qlut[p*256 + v] = sum of qint at coords whose bit is
|
|
220
|
+
// set in v, grown incrementally as qlut[..(v with lowest set bit cleared)..]
|
|
221
|
+
// plus the contribution of that lowest set bit.
|
|
222
|
+
const bitCoord = this.bitCoord;
|
|
223
|
+
for (let p = 0; p < nb; p++) {
|
|
224
|
+
const base = p << 8;
|
|
225
|
+
const cb = p << 3;
|
|
226
|
+
for (let v = 1; v < 256; v++) {
|
|
227
|
+
const low = v & -v;
|
|
228
|
+
const k = 31 - Math.clz32(low);
|
|
229
|
+
qlut[base + v] = qlut[base + (v & (v - 1))] + qint[bitCoord[cb + k]];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return { vmin, delta, sumQInt, qlut, nbytes: nb, zero: false };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Estimate the cosine distance (1 - cosine) between a stored code and a
|
|
237
|
+
* full-precision query, reading the code's bytes against the query's byte LUT.
|
|
238
|
+
* The code's set-bit count is tallied in the same byte scan, so nothing beyond
|
|
239
|
+
* the code itself is needed.
|
|
240
|
+
*
|
|
241
|
+
* `codeBytes` is a Uint8 view of the packed code buffer and `byteOffset` is the
|
|
242
|
+
* code's start byte (id * paddedDim/8).
|
|
243
|
+
*/
|
|
244
|
+
estimate(codeBytes: Uint8Array, byteOffset: number, q: QueryContext): number {
|
|
245
|
+
if (q.zero) {
|
|
246
|
+
return 1;
|
|
247
|
+
}
|
|
248
|
+
const nb = q.nbytes;
|
|
249
|
+
const lut = q.qlut;
|
|
250
|
+
let dot = 0;
|
|
251
|
+
let popcount = 0;
|
|
252
|
+
for (let p = 0; p < nb; p++) {
|
|
253
|
+
const b = codeBytes[byteOffset + p];
|
|
254
|
+
dot += lut[(p << 8) + b];
|
|
255
|
+
popcount += POPCOUNT8[b];
|
|
256
|
+
}
|
|
257
|
+
// A = sum_i sign_i * q_rot_i, recovered from the quantised query.
|
|
258
|
+
const A = q.vmin * (2 * popcount - this.paddedDim) +
|
|
259
|
+
q.delta * (2 * dot - q.sumQInt);
|
|
260
|
+
return 1 - this.cosFactor * A;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Cosine distance (1 - cosine, in [0, 2]) between two packed codes, computed
|
|
265
|
+
* directly from the BLOB bytes via their sign-bit Hamming distance — no word
|
|
266
|
+
* reinterpretation, so it is endianness-agnostic. Identical codes score 0.
|
|
267
|
+
*
|
|
268
|
+
* This is the distance used to build the graph (code vs code) and to answer a
|
|
269
|
+
* query given an already-quantized code. It is coarser than `estimate`, where
|
|
270
|
+
* one side is full precision.
|
|
271
|
+
*/
|
|
272
|
+
codeDistanceBytes(a: Uint8Array, b: Uint8Array): number {
|
|
273
|
+
const nb = this.nbytes;
|
|
274
|
+
let ham = 0;
|
|
275
|
+
// 32-bit-word Hamming: this is the hot arithmetic of graph construction
|
|
276
|
+
// (every candidate/prune comparison), so fold 4 bytes into one word and
|
|
277
|
+
// popcount it — ~4× fewer loop iterations than a byte-LUT scan, with no
|
|
278
|
+
// allocation and no dependence on the buffers' alignment or endianness
|
|
279
|
+
// (both sides are composed identically, so XOR is order-agnostic).
|
|
280
|
+
let p = 0;
|
|
281
|
+
for (const n4 = nb & ~3; p < n4; p += 4) {
|
|
282
|
+
let x = (a[p] ^ b[p]) |
|
|
283
|
+
((a[p + 1] ^ b[p + 1]) << 8) |
|
|
284
|
+
((a[p + 2] ^ b[p + 2]) << 16) |
|
|
285
|
+
((a[p + 3] ^ b[p + 3]) << 24);
|
|
286
|
+
x -= (x >>> 1) & 0x55555555;
|
|
287
|
+
x = (x & 0x33333333) + ((x >>> 2) & 0x33333333);
|
|
288
|
+
x = (x + (x >>> 4)) & 0x0f0f0f0f;
|
|
289
|
+
ham += Math.imul(x, 0x01010101) >>> 24;
|
|
290
|
+
}
|
|
291
|
+
for (; p < nb; p++) ham += POPCOUNT8[a[p] ^ b[p]];
|
|
292
|
+
return (2 * ham) / this.paddedDim;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Pack a code (codeWords 32-bit words) into its little-endian BLOB bytes. */
|
|
296
|
+
codeToBytes(code: ArrayLike<number>): Uint8Array {
|
|
297
|
+
const u = new Uint32Array(this.codeWords);
|
|
298
|
+
for (let i = 0; i < this.codeWords; i++) u[i] = code[i];
|
|
299
|
+
return new Uint8Array(u.buffer, 0, u.byteLength);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Reinterpret a code BLOB as a copy of codeWords 32-bit words. */
|
|
303
|
+
bytesToCode(bytes: Uint8Array): Uint32Array {
|
|
304
|
+
const u = new Uint32Array(this.codeWords);
|
|
305
|
+
new Uint8Array(u.buffer).set(bytes);
|
|
306
|
+
return u;
|
|
307
|
+
}
|
|
308
|
+
}
|