sweet-search 0.0.1 → 2.3.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.
Files changed (161) hide show
  1. package/LICENSE +190 -0
  2. package/NOTICE +23 -0
  3. package/core/cli.js +51 -0
  4. package/core/config.js +27 -0
  5. package/core/embedding/embedding-cache.js +467 -0
  6. package/core/embedding/embedding-local-model.js +845 -0
  7. package/core/embedding/embedding-remote.js +492 -0
  8. package/core/embedding/embedding-service.js +712 -0
  9. package/core/embedding/embedding-telemetry.js +219 -0
  10. package/core/embedding/index.js +40 -0
  11. package/core/graph/community-detector.js +294 -0
  12. package/core/graph/graph-expansion.js +839 -0
  13. package/core/graph/graph-extractor.js +2304 -0
  14. package/core/graph/graph-search.js +2148 -0
  15. package/core/graph/hcgs-generator.js +666 -0
  16. package/core/graph/index.js +16 -0
  17. package/core/graph/leiden-algorithm.js +547 -0
  18. package/core/graph/relationship-resolver.js +366 -0
  19. package/core/graph/repo-map.js +408 -0
  20. package/core/graph/summary-manager.js +549 -0
  21. package/core/indexing/artifact-builder.js +1054 -0
  22. package/core/indexing/ast-chunker.js +709 -0
  23. package/core/indexing/chunking/chunk-builder.js +170 -0
  24. package/core/indexing/chunking/markdown-chunker.js +503 -0
  25. package/core/indexing/chunking/plaintext-chunker.js +104 -0
  26. package/core/indexing/dedup/dedup-phase.js +159 -0
  27. package/core/indexing/dedup/exemplar-selector.js +65 -0
  28. package/core/indexing/document-chunker.js +56 -0
  29. package/core/indexing/incremental-parser.js +390 -0
  30. package/core/indexing/incremental-tracker.js +761 -0
  31. package/core/indexing/index-codebase-v21.js +472 -0
  32. package/core/indexing/index-maintainer.mjs +1674 -0
  33. package/core/indexing/index.js +90 -0
  34. package/core/indexing/indexer-ann.js +1077 -0
  35. package/core/indexing/indexer-build.js +742 -0
  36. package/core/indexing/indexer-phases.js +800 -0
  37. package/core/indexing/indexer-pool.js +764 -0
  38. package/core/indexing/indexer-sparse-gram.js +98 -0
  39. package/core/indexing/indexer-utils.js +536 -0
  40. package/core/indexing/indexer-worker.js +148 -0
  41. package/core/indexing/li-skip-policy.js +225 -0
  42. package/core/indexing/merkle-tracker.js +244 -0
  43. package/core/indexing/model-pool.js +166 -0
  44. package/core/infrastructure/code-graph-repository.js +120 -0
  45. package/core/infrastructure/codebase-repository.js +131 -0
  46. package/core/infrastructure/config/dedup.js +54 -0
  47. package/core/infrastructure/config/embedding.js +298 -0
  48. package/core/infrastructure/config/graph.js +80 -0
  49. package/core/infrastructure/config/index.js +82 -0
  50. package/core/infrastructure/config/indexing.js +8 -0
  51. package/core/infrastructure/config/platform.js +254 -0
  52. package/core/infrastructure/config/ranking.js +221 -0
  53. package/core/infrastructure/config/search.js +396 -0
  54. package/core/infrastructure/config/translation.js +89 -0
  55. package/core/infrastructure/config/vector-store.js +114 -0
  56. package/core/infrastructure/constants.js +86 -0
  57. package/core/infrastructure/coreml-cascade.js +909 -0
  58. package/core/infrastructure/coreml-cascade.json +46 -0
  59. package/core/infrastructure/coreml-provider.js +81 -0
  60. package/core/infrastructure/db-utils.js +69 -0
  61. package/core/infrastructure/dedup-hashing.js +83 -0
  62. package/core/infrastructure/hardware-capability.js +332 -0
  63. package/core/infrastructure/index.js +104 -0
  64. package/core/infrastructure/language-patterns/maps.js +121 -0
  65. package/core/infrastructure/language-patterns/registry-core.js +323 -0
  66. package/core/infrastructure/language-patterns/registry-data-query.js +155 -0
  67. package/core/infrastructure/language-patterns/registry-object-oriented.js +285 -0
  68. package/core/infrastructure/language-patterns/registry-tooling.js +240 -0
  69. package/core/infrastructure/language-patterns/registry-web-style.js +143 -0
  70. package/core/infrastructure/language-patterns/registry.js +19 -0
  71. package/core/infrastructure/language-patterns.js +141 -0
  72. package/core/infrastructure/llm-provider.js +733 -0
  73. package/core/infrastructure/manifest.json +46 -0
  74. package/core/infrastructure/maxsim.wasm +0 -0
  75. package/core/infrastructure/model-fetcher.js +423 -0
  76. package/core/infrastructure/model-registry.js +214 -0
  77. package/core/infrastructure/native-inference.js +587 -0
  78. package/core/infrastructure/native-resolver.js +187 -0
  79. package/core/infrastructure/native-sparse-gram.js +257 -0
  80. package/core/infrastructure/native-tokenizer.js +160 -0
  81. package/core/infrastructure/onnx-mutex.js +45 -0
  82. package/core/infrastructure/onnx-session-utils.js +261 -0
  83. package/core/infrastructure/ort-pipeline.js +111 -0
  84. package/core/infrastructure/project-detector.js +102 -0
  85. package/core/infrastructure/quantization.js +410 -0
  86. package/core/infrastructure/simd-distance.js +502 -0
  87. package/core/infrastructure/simd-distance.wasm +0 -0
  88. package/core/infrastructure/tree-sitter-provider.js +665 -0
  89. package/core/infrastructure/webgpu-maxsim.js +222 -0
  90. package/core/query/index.js +35 -0
  91. package/core/query/intent-detector.js +201 -0
  92. package/core/query/intent-router.js +156 -0
  93. package/core/query/query-router-catboost.js +222 -0
  94. package/core/query/query-router-ml.js +266 -0
  95. package/core/query/query-router.js +213 -0
  96. package/core/ranking/cascaded-scorer.js +379 -0
  97. package/core/ranking/flashrank.js +810 -0
  98. package/core/ranking/index.js +49 -0
  99. package/core/ranking/late-interaction-index.js +2383 -0
  100. package/core/ranking/late-interaction-model.js +812 -0
  101. package/core/ranking/local-reranker.js +374 -0
  102. package/core/ranking/mmr.js +379 -0
  103. package/core/ranking/quality-scorer.js +363 -0
  104. package/core/search/context-expander.js +1167 -0
  105. package/core/search/dedup/sibling-expander.js +327 -0
  106. package/core/search/index.js +16 -0
  107. package/core/search/search-boost.js +259 -0
  108. package/core/search/search-cli.js +544 -0
  109. package/core/search/search-format.js +282 -0
  110. package/core/search/search-fusion.js +327 -0
  111. package/core/search/search-hybrid.js +204 -0
  112. package/core/search/search-pattern-chunks.js +337 -0
  113. package/core/search/search-pattern-planner.js +439 -0
  114. package/core/search/search-pattern-prefilter.js +412 -0
  115. package/core/search/search-pattern-ripgrep.js +663 -0
  116. package/core/search/search-pattern.js +463 -0
  117. package/core/search/search-postprocess.js +452 -0
  118. package/core/search/search-semantic.js +706 -0
  119. package/core/search/search-server.js +554 -0
  120. package/core/search/session-daemon-prewarm.mjs +164 -0
  121. package/core/search/session-warmup.js +595 -0
  122. package/core/search/sweet-search.js +632 -0
  123. package/core/search/warmup-metrics.js +532 -0
  124. package/core/start-server.js +6 -0
  125. package/core/training/query-router/features/extractor.js +762 -0
  126. package/core/training/query-router/features/multilingual-patterns.js +431 -0
  127. package/core/training/query-router/features/text-segmenter.js +303 -0
  128. package/core/training/query-router/features/unicode-utils.js +383 -0
  129. package/core/training/query-router/output/v45_router_d4.js +11521 -0
  130. package/core/training/query-router/output/v46_router_d4.js +11498 -0
  131. package/core/vector-store/binary-heap.js +227 -0
  132. package/core/vector-store/binary-hnsw-index.js +1004 -0
  133. package/core/vector-store/float-vector-store.js +234 -0
  134. package/core/vector-store/hnsw-index.js +580 -0
  135. package/core/vector-store/index.js +39 -0
  136. package/core/vector-store/seismic-index.js +498 -0
  137. package/core/vocabulary/index.js +84 -0
  138. package/core/vocabulary/vocab-constants.js +20 -0
  139. package/core/vocabulary/vocab-miner-extractors.js +375 -0
  140. package/core/vocabulary/vocab-miner-nl.js +404 -0
  141. package/core/vocabulary/vocab-miner-utils.js +146 -0
  142. package/core/vocabulary/vocab-miner.js +574 -0
  143. package/core/vocabulary/vocab-prewarm-cli.js +110 -0
  144. package/core/vocabulary/vocab-ranker.js +492 -0
  145. package/core/vocabulary/vocab-warmer.js +523 -0
  146. package/core/vocabulary/vocab-warmup-orchestrator.js +425 -0
  147. package/core/vocabulary/vocabulary-utils.js +704 -0
  148. package/crates/wasm-router/pkg/package.json +13 -0
  149. package/crates/wasm-router/pkg/query_router_wasm.d.ts +36 -0
  150. package/crates/wasm-router/pkg/query_router_wasm.js +271 -0
  151. package/crates/wasm-router/pkg/query_router_wasm_bg.wasm +0 -0
  152. package/crates/wasm-router/pkg/query_router_wasm_bg.wasm.d.ts +19 -0
  153. package/mcp/config-gen.js +121 -0
  154. package/mcp/server.js +335 -0
  155. package/mcp/tool-handlers.js +476 -0
  156. package/package.json +131 -9
  157. package/scripts/benchmark-harness.js +794 -0
  158. package/scripts/init.js +1058 -0
  159. package/scripts/smoke-test.js +435 -0
  160. package/scripts/uninstall.js +478 -0
  161. package/scripts/verify-runtime.js +176 -0
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Quantization & Distance Utilities — pure math functions shared across domains.
3
+ *
4
+ * Extracted from embedding-service.js during DDD boundary cleanup.
5
+ * No domain dependencies — only pure computation.
6
+ */
7
+
8
+ // =============================================================================
9
+ // BINARY QUANTIZATION
10
+ // =============================================================================
11
+
12
+ export function floatToBinary(embedding) {
13
+ const numBytes = Math.ceil(embedding.length / 8);
14
+ const binary = new Uint8Array(numBytes);
15
+ for (let i = 0; i < embedding.length; i++) {
16
+ if (embedding[i] > 0) {
17
+ binary[Math.floor(i / 8)] |= (1 << (7 - (i % 8)));
18
+ }
19
+ }
20
+ return binary;
21
+ }
22
+
23
+ // =============================================================================
24
+ // CENTROID & ROTATION
25
+ // =============================================================================
26
+
27
+ export function computeCentroid(embeddings) {
28
+ if (!embeddings || embeddings.length === 0) return null;
29
+ const dim = embeddings[0].length;
30
+ const centroid = new Float64Array(dim);
31
+ for (const emb of embeddings) {
32
+ for (let i = 0; i < dim; i++) centroid[i] += emb[i];
33
+ }
34
+ const n = embeddings.length;
35
+ for (let i = 0; i < dim; i++) centroid[i] /= n;
36
+ return new Float32Array(centroid);
37
+ }
38
+
39
+ export function generateSignVector(dim, seed = 42) {
40
+ const signs = new Float32Array(dim);
41
+ let s = seed | 0;
42
+ for (let i = 0; i < dim; i++) {
43
+ s = (s + 0x6D2B79F5) | 0;
44
+ let t = Math.imul(s ^ (s >>> 15), 1 | s);
45
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
46
+ signs[i] = ((t ^ (t >>> 14)) >>> 31) ? 1.0 : -1.0;
47
+ }
48
+ return signs;
49
+ }
50
+
51
+ function nextPow2(n) {
52
+ let p = 1;
53
+ while (p < n) p <<= 1;
54
+ return p;
55
+ }
56
+
57
+ /**
58
+ * Standard Walsh-Hadamard Transform (natural / Hadamard ordering).
59
+ * This is the default used by all existing indexes. Do NOT change
60
+ * the output ordering — it would silently break every index on disk.
61
+ */
62
+ export function walshHadamardTransform(v) {
63
+ const n = v.length;
64
+ for (let len = 1; len < n; len <<= 1) {
65
+ for (let i = 0; i < n; i += len << 1) {
66
+ for (let j = 0; j < len; j++) {
67
+ const u = v[i + j];
68
+ const w = v[i + j + len];
69
+ v[i + j] = u + w;
70
+ v[i + j + len] = u - w;
71
+ }
72
+ }
73
+ }
74
+ const scale = 1.0 / Math.sqrt(n);
75
+ for (let i = 0; i < n; i++) v[i] *= scale;
76
+ return v;
77
+ }
78
+
79
+ /**
80
+ * CRA-4: Sequency-ordered Walsh-Hadamard Transform.
81
+ *
82
+ * Same butterfly as walshHadamardTransform, then permutes to sequency (Walsh)
83
+ * ordering. Clusters similar-frequency components together, reducing
84
+ * quantization error (GSR, arXiv 2505.03810).
85
+ *
86
+ * MUST be opt-in via whtOrdering='sequency' — never default.
87
+ * Indexes built with sequency ordering are NOT compatible with natural-order indexes.
88
+ */
89
+ export function walshHadamardTransformSequency(v) {
90
+ // Step 1: standard butterfly (natural order)
91
+ walshHadamardTransform(v);
92
+
93
+ // Step 2: permute from natural to sequency order
94
+ const n = v.length;
95
+ const bits = 31 - Math.clz32(n);
96
+ if (n <= 1 || bits === 0) return v;
97
+
98
+ const tmp = new Float32Array(n);
99
+ for (let i = 0; i < n; i++) {
100
+ const g = i ^ (i >>> 1);
101
+ let r = 0, x = g;
102
+ for (let b = 0; b < bits; b++) { r = (r << 1) | (x & 1); x >>>= 1; }
103
+ tmp[i] = v[r];
104
+ }
105
+ v.set(tmp);
106
+ return v;
107
+ }
108
+
109
+ export function fastRotate(v, signs, sequency = false) {
110
+ const origDim = v.length;
111
+ const padDim = nextPow2(origDim);
112
+ const buf = new Float32Array(padDim);
113
+ for (let i = 0; i < origDim; i++) buf[i] = v[i] * signs[i];
114
+ if (sequency) {
115
+ walshHadamardTransformSequency(buf);
116
+ } else {
117
+ walshHadamardTransform(buf);
118
+ }
119
+ return padDim === origDim ? buf : buf.subarray(0, origDim);
120
+ }
121
+
122
+ // =============================================================================
123
+ // FAST PSEUDO-RANDOM ROTATION (CRA-14)
124
+ // =============================================================================
125
+
126
+ /**
127
+ * CRA-14: Weaviate-style fast pseudo-random rotation using a sequence of
128
+ * random Givens (pairwise plane) rotations. Achieves variance equalization
129
+ * comparable to WHT at O(d × numRotations) cost, which is cheaper than
130
+ * WHT's O(d log d) for high dimensions (d >= 768).
131
+ *
132
+ * For our d=128 this is similar speed to WHT. Provided for future model
133
+ * scaling and A/B testing against WHT.
134
+ *
135
+ * @param {Float32Array} v - Input vector (modified in-place)
136
+ * @param {number} seed - Deterministic seed for rotation angles and pairs
137
+ * @param {number} [numRounds=3] - Number of rotation rounds (more = better equalization)
138
+ * @returns {Float32Array} Rotated vector (same reference as input)
139
+ */
140
+ export function fastPseudoRandomRotate(v, seed, numRounds = 3) {
141
+ const dim = v.length;
142
+ if (dim < 2) return v;
143
+
144
+ // Deterministic PRNG from seed
145
+ let s = seed | 0;
146
+ const prng = () => {
147
+ s = (s + 0x6D2B79F5) | 0;
148
+ let t = Math.imul(s ^ (s >>> 15), 1 | s);
149
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
150
+ return ((t ^ (t >>> 14)) >>> 0) / 0x100000000;
151
+ };
152
+
153
+ // Apply numRounds passes of dim/2 random Givens rotations.
154
+ // Each pass randomly pairs all dimensions and applies a random rotation angle.
155
+ const indices = new Uint32Array(dim);
156
+ for (let i = 0; i < dim; i++) indices[i] = i;
157
+
158
+ for (let round = 0; round < numRounds; round++) {
159
+ // Fisher-Yates shuffle for random pairing
160
+ for (let i = dim - 1; i > 0; i--) {
161
+ const j = (prng() * (i + 1)) | 0;
162
+ const tmp = indices[i]; indices[i] = indices[j]; indices[j] = tmp;
163
+ }
164
+
165
+ // Apply Givens rotation to each pair
166
+ for (let p = 0; p < dim - 1; p += 2) {
167
+ const i = indices[p];
168
+ const j = indices[p + 1];
169
+ const theta = prng() * 2 * Math.PI;
170
+ const c = Math.cos(theta);
171
+ const sn = Math.sin(theta);
172
+ const vi = v[i];
173
+ const vj = v[j];
174
+ v[i] = c * vi - sn * vj;
175
+ v[j] = sn * vi + c * vj;
176
+ }
177
+ }
178
+
179
+ // Normalize to preserve L2 norm (Givens rotations are orthogonal, but
180
+ // accumulated floating-point error can cause small drift)
181
+ let normSq = 0;
182
+ for (let i = 0; i < dim; i++) normSq += v[i] * v[i];
183
+ if (normSq > 0) {
184
+ const scale = Math.sqrt(normSq);
185
+ // Only renormalize if drift exceeds epsilon
186
+ if (Math.abs(scale - 1.0) > 1e-6) {
187
+ for (let i = 0; i < dim; i++) v[i] /= scale;
188
+ }
189
+ }
190
+
191
+ return v;
192
+ }
193
+
194
+ // =============================================================================
195
+ // WUSH CALIBRATED ROTATION (CRA-3)
196
+ // =============================================================================
197
+
198
+ /**
199
+ * Calibrate a WUSH transform from sample embeddings.
200
+ * Computes the covariance matrix, eigendecomposition, and produces
201
+ * the calibration scaling vector S^(-1/2) and rotation matrix U.
202
+ *
203
+ * The full WUSH transform is: T = H × diag(S^(-1/2)) × U^T
204
+ * where H is the Walsh-Hadamard matrix, and U,S come from the
205
+ * eigendecomposition of the covariance matrix.
206
+ *
207
+ * @param {Float32Array[]} samples - Sample embedding vectors (L2-normalized)
208
+ * @param {number} dim - Embedding dimension
209
+ * @returns {{ eigenVecs: Float64Array, invSqrtEigenVals: Float64Array }} Calibration data
210
+ */
211
+ export function calibrateWUSH(samples, dim) {
212
+ const n = samples.length;
213
+ if (n < dim) throw new Error(`WUSH calibration requires >= ${dim} samples, got ${n}`);
214
+
215
+ // Compute covariance matrix C = (1/N) × X^T × X (symmetric, dim × dim)
216
+ const C = new Float64Array(dim * dim);
217
+ for (let s = 0; s < n; s++) {
218
+ const x = samples[s];
219
+ for (let i = 0; i < dim; i++) {
220
+ const xi = x[i];
221
+ for (let j = i; j < dim; j++) {
222
+ C[i * dim + j] += xi * x[j];
223
+ }
224
+ }
225
+ }
226
+ // Symmetrize and normalize
227
+ for (let i = 0; i < dim; i++) {
228
+ C[i * dim + i] /= n;
229
+ for (let j = i + 1; j < dim; j++) {
230
+ const v = C[i * dim + j] / n;
231
+ C[i * dim + j] = v;
232
+ C[j * dim + i] = v;
233
+ }
234
+ }
235
+
236
+ // Jacobi eigendecomposition of symmetric C.
237
+ // eigenVecs columns are eigenvectors (stored row-major as V[i*dim+j]).
238
+ const V = new Float64Array(dim * dim);
239
+ for (let i = 0; i < dim; i++) V[i * dim + i] = 1.0; // identity
240
+
241
+ const maxIter = 100;
242
+ for (let iter = 0; iter < maxIter; iter++) {
243
+ // Find largest off-diagonal element
244
+ let maxVal = 0, p = 0, q = 0;
245
+ for (let i = 0; i < dim; i++) {
246
+ for (let j = i + 1; j < dim; j++) {
247
+ const absVal = Math.abs(C[i * dim + j]);
248
+ if (absVal > maxVal) { maxVal = absVal; p = i; q = j; }
249
+ }
250
+ }
251
+ if (maxVal < 1e-10) break; // converged
252
+
253
+ // Jacobi rotation for (p, q)
254
+ const cpp = C[p * dim + p];
255
+ const cqq = C[q * dim + q];
256
+ const cpq = C[p * dim + q];
257
+
258
+ const theta = 0.5 * Math.atan2(2 * cpq, cpp - cqq);
259
+ const c = Math.cos(theta);
260
+ const s2 = Math.sin(theta);
261
+
262
+ // Update C: rotate rows/cols p and q
263
+ for (let i = 0; i < dim; i++) {
264
+ if (i === p || i === q) continue;
265
+ const cip = C[i * dim + p];
266
+ const ciq = C[i * dim + q];
267
+ C[i * dim + p] = C[p * dim + i] = c * cip + s2 * ciq;
268
+ C[i * dim + q] = C[q * dim + i] = -s2 * cip + c * ciq;
269
+ }
270
+ C[p * dim + p] = c * c * cpp + 2 * c * s2 * cpq + s2 * s2 * cqq;
271
+ C[q * dim + q] = s2 * s2 * cpp - 2 * c * s2 * cpq + c * c * cqq;
272
+ C[p * dim + q] = C[q * dim + p] = 0;
273
+
274
+ // Update eigenvector matrix V
275
+ for (let i = 0; i < dim; i++) {
276
+ const vip = V[i * dim + p];
277
+ const viq = V[i * dim + q];
278
+ V[i * dim + p] = c * vip + s2 * viq;
279
+ V[i * dim + q] = -s2 * vip + c * viq;
280
+ }
281
+ }
282
+
283
+ // Extract eigenvalues (diagonal of C) and compute S^(-1/2)
284
+ const invSqrtEigenVals = new Float64Array(dim);
285
+ for (let i = 0; i < dim; i++) {
286
+ const ev = Math.max(C[i * dim + i], 1e-12);
287
+ invSqrtEigenVals[i] = 1.0 / Math.sqrt(ev);
288
+ }
289
+
290
+ return { eigenVecs: V, invSqrtEigenVals };
291
+ }
292
+
293
+ /**
294
+ * Apply the WUSH-calibrated rotation: T_wush × v = H × diag(S^(-1/2)) × U^T × v
295
+ *
296
+ * Steps:
297
+ * 1. Project: w = U^T × v (rotate into eigenbasis)
298
+ * 2. Scale: w[i] *= S^(-1/2)[i] (equalize dimension variance)
299
+ * 3. WHT: w = H × w (spread information across dimensions)
300
+ *
301
+ * @param {Float32Array} v - Input vector
302
+ * @param {Float64Array} eigenVecs - Eigenvector matrix (dim×dim, row-major)
303
+ * @param {Float64Array} invSqrtEigenVals - S^(-1/2) diagonal
304
+ * @param {Float32Array} signs - Sign-flip vector (for randomization)
305
+ * @returns {Float32Array} Rotated vector
306
+ */
307
+ export function wushRotate(v, eigenVecs, invSqrtEigenVals, signs) {
308
+ const dim = v.length;
309
+
310
+ // Step 1: w = U^T × v (U stored row-major in eigenVecs, so U^T × v = transpose-multiply)
311
+ const w = new Float32Array(dim);
312
+ for (let i = 0; i < dim; i++) {
313
+ let sum = 0;
314
+ for (let j = 0; j < dim; j++) {
315
+ sum += eigenVecs[j * dim + i] * v[j]; // column i of V = row j, col i
316
+ }
317
+ // Step 2: scale by S^(-1/2)
318
+ w[i] = sum * invSqrtEigenVals[i];
319
+ }
320
+
321
+ // Step 3: Sign-flip + WHT (reuses existing infrastructure)
322
+ for (let i = 0; i < dim; i++) w[i] *= signs[i];
323
+ walshHadamardTransform(w);
324
+
325
+ return w;
326
+ }
327
+
328
+ // =============================================================================
329
+ // ASYMMETRIC QUANTIZATION
330
+ // =============================================================================
331
+
332
+ export function asymmetricDocEncode(embedding, centroid, signs) {
333
+ const dim = embedding.length;
334
+ const centered = new Float32Array(dim);
335
+ for (let i = 0; i < dim; i++) centered[i] = embedding[i] - centroid[i];
336
+ const rotated = fastRotate(centered, signs);
337
+ return floatToBinary(rotated);
338
+ }
339
+
340
+ export function asymmetricQueryEncode(embedding, centroid, signs) {
341
+ const dim = embedding.length;
342
+ const centered = new Float32Array(dim);
343
+ for (let i = 0; i < dim; i++) centered[i] = embedding[i] - centroid[i];
344
+ const rotated = fastRotate(centered, signs);
345
+ let maxAbs = 0;
346
+ for (let i = 0; i < dim; i++) {
347
+ const abs = Math.abs(rotated[i]);
348
+ if (abs > maxAbs) maxAbs = abs;
349
+ }
350
+ const int4 = new Int8Array(dim);
351
+ if (maxAbs > 0) {
352
+ const scale = 7.0 / maxAbs;
353
+ for (let i = 0; i < dim; i++) {
354
+ int4[i] = Math.round(Math.max(-7, Math.min(7, rotated[i] * scale)));
355
+ }
356
+ }
357
+ let norm = 0;
358
+ for (let i = 0; i < dim; i++) norm += rotated[i] * rotated[i];
359
+ return { int4, norm };
360
+ }
361
+
362
+ // =============================================================================
363
+ // INT8 QUANTIZATION
364
+ // =============================================================================
365
+
366
+ export function floatToInt8(embedding) {
367
+ const int8 = new Int8Array(embedding.length);
368
+ let maxAbs = 0;
369
+ for (let i = 0; i < embedding.length; i++) {
370
+ const abs = Math.abs(embedding[i]);
371
+ if (abs > maxAbs) maxAbs = abs;
372
+ }
373
+ if (maxAbs === 0) return int8;
374
+ const scale = 127 / maxAbs;
375
+ for (let i = 0; i < embedding.length; i++) {
376
+ int8[i] = Math.round(Math.max(-127, Math.min(127, embedding[i] * scale)));
377
+ }
378
+ return int8;
379
+ }
380
+
381
+ export function normalizedFloatToInt8(embedding) {
382
+ const int8 = new Int8Array(embedding.length);
383
+ for (let i = 0; i < embedding.length; i++) {
384
+ const clamped = Math.max(-1, Math.min(1, embedding[i]));
385
+ int8[i] = Math.round(clamped * 127);
386
+ }
387
+ return int8;
388
+ }
389
+
390
+ // =============================================================================
391
+ // TRUNCATION & SHUFFLE
392
+ // =============================================================================
393
+
394
+ export function truncateForHNSW(embedding, targetDim) {
395
+ if (embedding.length <= targetDim) return embedding;
396
+ const truncated = embedding.slice(0, targetDim);
397
+ let norm = 0;
398
+ for (let i = 0; i < truncated.length; i++) norm += truncated[i] * truncated[i];
399
+ norm = Math.sqrt(norm);
400
+ if (norm > 0) for (let i = 0; i < truncated.length; i++) truncated[i] /= norm;
401
+ return truncated;
402
+ }
403
+
404
+ export function fisherYatesShuffle(arr) {
405
+ for (let i = arr.length - 1; i > 0; i--) {
406
+ const j = Math.floor(Math.random() * (i + 1));
407
+ const tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
408
+ }
409
+ return arr;
410
+ }