@sparkleideas/plugins 3.0.0-alpha.8

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 (80) hide show
  1. package/README.md +401 -0
  2. package/__tests__/collection-manager.test.ts +332 -0
  3. package/__tests__/dependency-graph.test.ts +434 -0
  4. package/__tests__/enhanced-plugin-registry.test.ts +488 -0
  5. package/__tests__/plugin-registry.test.ts +368 -0
  6. package/__tests__/ruvector-bridge.test.ts +2429 -0
  7. package/__tests__/ruvector-integration.test.ts +1602 -0
  8. package/__tests__/ruvector-migrations.test.ts +1099 -0
  9. package/__tests__/ruvector-quantization.test.ts +846 -0
  10. package/__tests__/ruvector-streaming.test.ts +1088 -0
  11. package/__tests__/sdk.test.ts +325 -0
  12. package/__tests__/security.test.ts +348 -0
  13. package/__tests__/utils/ruvector-test-utils.ts +860 -0
  14. package/examples/plugin-creator/index.ts +636 -0
  15. package/examples/plugin-creator/plugin-creator.test.ts +312 -0
  16. package/examples/ruvector/README.md +288 -0
  17. package/examples/ruvector/attention-patterns.ts +394 -0
  18. package/examples/ruvector/basic-usage.ts +288 -0
  19. package/examples/ruvector/docker-compose.yml +75 -0
  20. package/examples/ruvector/gnn-analysis.ts +501 -0
  21. package/examples/ruvector/hyperbolic-hierarchies.ts +557 -0
  22. package/examples/ruvector/init-db.sql +119 -0
  23. package/examples/ruvector/quantization.ts +680 -0
  24. package/examples/ruvector/self-learning.ts +447 -0
  25. package/examples/ruvector/semantic-search.ts +576 -0
  26. package/examples/ruvector/streaming-large-data.ts +507 -0
  27. package/examples/ruvector/transactions.ts +594 -0
  28. package/examples/ruvector-plugins/hook-pattern-library.ts +486 -0
  29. package/examples/ruvector-plugins/index.ts +79 -0
  30. package/examples/ruvector-plugins/intent-router.ts +354 -0
  31. package/examples/ruvector-plugins/mcp-tool-optimizer.ts +424 -0
  32. package/examples/ruvector-plugins/reasoning-bank.ts +657 -0
  33. package/examples/ruvector-plugins/ruvector-plugins.test.ts +518 -0
  34. package/examples/ruvector-plugins/semantic-code-search.ts +498 -0
  35. package/examples/ruvector-plugins/shared/index.ts +20 -0
  36. package/examples/ruvector-plugins/shared/vector-utils.ts +257 -0
  37. package/examples/ruvector-plugins/sona-learning.ts +445 -0
  38. package/package.json +97 -0
  39. package/src/collections/collection-manager.ts +661 -0
  40. package/src/collections/index.ts +56 -0
  41. package/src/collections/official/index.ts +1040 -0
  42. package/src/core/base-plugin.ts +416 -0
  43. package/src/core/plugin-interface.ts +215 -0
  44. package/src/hooks/index.ts +685 -0
  45. package/src/index.ts +378 -0
  46. package/src/integrations/agentic-flow.ts +743 -0
  47. package/src/integrations/index.ts +88 -0
  48. package/src/integrations/ruvector/ARCHITECTURE.md +1245 -0
  49. package/src/integrations/ruvector/attention-advanced.ts +1040 -0
  50. package/src/integrations/ruvector/attention-executor.ts +782 -0
  51. package/src/integrations/ruvector/attention-mechanisms.ts +757 -0
  52. package/src/integrations/ruvector/attention.ts +1063 -0
  53. package/src/integrations/ruvector/gnn.ts +3050 -0
  54. package/src/integrations/ruvector/hyperbolic.ts +1948 -0
  55. package/src/integrations/ruvector/index.ts +394 -0
  56. package/src/integrations/ruvector/migrations/001_create_extension.sql +135 -0
  57. package/src/integrations/ruvector/migrations/002_create_vector_tables.sql +259 -0
  58. package/src/integrations/ruvector/migrations/003_create_indices.sql +328 -0
  59. package/src/integrations/ruvector/migrations/004_create_functions.sql +598 -0
  60. package/src/integrations/ruvector/migrations/005_create_attention_functions.sql +654 -0
  61. package/src/integrations/ruvector/migrations/006_create_gnn_functions.sql +728 -0
  62. package/src/integrations/ruvector/migrations/007_create_hyperbolic_functions.sql +762 -0
  63. package/src/integrations/ruvector/migrations/index.ts +35 -0
  64. package/src/integrations/ruvector/migrations/migrations.ts +647 -0
  65. package/src/integrations/ruvector/quantization.ts +2036 -0
  66. package/src/integrations/ruvector/ruvector-bridge.ts +2000 -0
  67. package/src/integrations/ruvector/self-learning.ts +2376 -0
  68. package/src/integrations/ruvector/streaming.ts +1737 -0
  69. package/src/integrations/ruvector/types.ts +1945 -0
  70. package/src/providers/index.ts +643 -0
  71. package/src/registry/dependency-graph.ts +568 -0
  72. package/src/registry/enhanced-plugin-registry.ts +994 -0
  73. package/src/registry/plugin-registry.ts +604 -0
  74. package/src/sdk/index.ts +563 -0
  75. package/src/security/index.ts +594 -0
  76. package/src/types/index.ts +446 -0
  77. package/src/workers/index.ts +700 -0
  78. package/tmp.json +0 -0
  79. package/tsconfig.json +25 -0
  80. package/vitest.config.ts +23 -0
@@ -0,0 +1,757 @@
1
+ /**
2
+ * RuVector PostgreSQL Bridge - Additional Attention Mechanisms
3
+ *
4
+ * Part 2: Sparse, Linear, Positional, Graph, Temporal, Multimodal, and Retrieval attention.
5
+ *
6
+ * @module @sparkleideas/plugins/integrations/ruvector/attention-mechanisms
7
+ */
8
+
9
+ import type {
10
+ AttentionMechanism,
11
+ AttentionConfig,
12
+ AttentionInput,
13
+ } from './types.js';
14
+
15
+ import {
16
+ BaseAttentionMechanism,
17
+ type AttentionCategory,
18
+ type AttentionOptions,
19
+ } from './attention.js';
20
+
21
+ // ============================================================================
22
+ // Sparse Attention Implementations
23
+ // ============================================================================
24
+
25
+ /**
26
+ * Sparse Attention (BigBird/Longformer style).
27
+ */
28
+ export class SparseAttention extends BaseAttentionMechanism {
29
+ readonly type: AttentionMechanism = 'sparse_attention';
30
+ readonly name = 'Sparse Attention';
31
+ readonly description = 'Sparse attention with local, global, and random components';
32
+ readonly category: AttentionCategory = 'sparse';
33
+
34
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
35
+ const blockSize = this.config.params?.blockSize ?? 64;
36
+ const numGlobal = this.config.params?.numGlobalTokens ?? 2;
37
+ const numRandom = this.config.params?.numRandomTokens ?? 3;
38
+ const scale = this.getScale();
39
+ const seqLen = keys.length;
40
+
41
+ // Build sparse attention pattern
42
+ const attendTo = new Set<number>();
43
+
44
+ // Global tokens
45
+ for (let i = 0; i < numGlobal && i < seqLen; i++) {
46
+ attendTo.add(i);
47
+ }
48
+
49
+ // Local window
50
+ const queryIdx = seqLen - 1;
51
+ for (let i = Math.max(0, queryIdx - blockSize); i < Math.min(seqLen, queryIdx + blockSize); i++) {
52
+ attendTo.add(i);
53
+ }
54
+
55
+ // Random tokens
56
+ for (let r = 0; r < numRandom; r++) {
57
+ attendTo.add(Math.floor(Math.random() * seqLen));
58
+ }
59
+
60
+ const scores = keys.map((k, i) => {
61
+ if (!attendTo.has(i)) return -Infinity;
62
+ return this.dotProduct(query, k) / scale;
63
+ });
64
+
65
+ const weights = this.softmax(scores);
66
+ return this.weightedSum(values, weights);
67
+ }
68
+
69
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
70
+ return Promise.all(queries.map(q => this.compute(q, keys, values)));
71
+ }
72
+
73
+ toSQL(input: AttentionInput): string {
74
+ const q = this.formatMatrix(input.query);
75
+ const k = this.formatMatrix(input.key);
76
+ const v = this.formatMatrix(input.value);
77
+ const blockSize = this.config.params?.blockSize ?? 64;
78
+ const numGlobal = this.config.params?.numGlobalTokens ?? 2;
79
+ return `SELECT ruvector.sparse_attention(${q}, ${k}, ${v}, ${blockSize}, ${numGlobal}, ${this.getScale()})`;
80
+ }
81
+
82
+ private dotProduct(a: number[], b: number[]): number {
83
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
84
+ }
85
+
86
+ private softmax(x: number[]): number[] {
87
+ const filtered = x.filter(v => v !== -Infinity);
88
+ if (filtered.length === 0) return x.map(() => 0);
89
+ const max = Math.max(...filtered);
90
+ const exp = x.map(v => v === -Infinity ? 0 : Math.exp(v - max));
91
+ const sum = exp.reduce((a, b) => a + b, 0);
92
+ return sum > 0 ? exp.map(v => v / sum) : exp;
93
+ }
94
+
95
+ private weightedSum(values: number[][], weights: number[]): number[] {
96
+ const dim = values[0].length;
97
+ const result = new Array(dim).fill(0);
98
+ for (let i = 0; i < values.length; i++) {
99
+ for (let j = 0; j < dim; j++) {
100
+ result[j] += weights[i] * values[i][j];
101
+ }
102
+ }
103
+ return result;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Block Sparse Attention.
109
+ */
110
+ export class BlockSparseAttention extends BaseAttentionMechanism {
111
+ readonly type: AttentionMechanism = 'block_sparse';
112
+ readonly name = 'Block Sparse Attention';
113
+ readonly description = 'Block-sparse attention with predefined block patterns';
114
+ readonly category: AttentionCategory = 'sparse';
115
+
116
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
117
+ const blockSize = this.config.params?.blockSize ?? 64;
118
+ const scale = this.getScale();
119
+ const seqLen = keys.length;
120
+ const numBlocks = Math.ceil(seqLen / blockSize);
121
+ const queryBlock = Math.floor((seqLen - 1) / blockSize);
122
+
123
+ const scores = keys.map((k, i) => {
124
+ const keyBlock = Math.floor(i / blockSize);
125
+ // Attend to same block and adjacent blocks
126
+ if (Math.abs(keyBlock - queryBlock) > 1) return -Infinity;
127
+ return this.dotProduct(query, k) / scale;
128
+ });
129
+
130
+ const weights = this.softmax(scores);
131
+ return this.weightedSum(values, weights);
132
+ }
133
+
134
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
135
+ return Promise.all(queries.map(q => this.compute(q, keys, values)));
136
+ }
137
+
138
+ toSQL(input: AttentionInput): string {
139
+ const q = this.formatMatrix(input.query);
140
+ const k = this.formatMatrix(input.key);
141
+ const v = this.formatMatrix(input.value);
142
+ const blockSize = this.config.params?.blockSize ?? 64;
143
+ return `SELECT ruvector.block_sparse_attention(${q}, ${k}, ${v}, ${blockSize}, ${this.getScale()})`;
144
+ }
145
+
146
+ private dotProduct(a: number[], b: number[]): number {
147
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
148
+ }
149
+
150
+ private softmax(x: number[]): number[] {
151
+ const filtered = x.filter(v => v !== -Infinity);
152
+ if (filtered.length === 0) return x.map(() => 0);
153
+ const max = Math.max(...filtered);
154
+ const exp = x.map(v => v === -Infinity ? 0 : Math.exp(v - max));
155
+ const sum = exp.reduce((a, b) => a + b, 0);
156
+ return sum > 0 ? exp.map(v => v / sum) : exp;
157
+ }
158
+
159
+ private weightedSum(values: number[][], weights: number[]): number[] {
160
+ const dim = values[0].length;
161
+ const result = new Array(dim).fill(0);
162
+ for (let i = 0; i < values.length; i++) {
163
+ for (let j = 0; j < dim; j++) {
164
+ result[j] += weights[i] * values[i][j];
165
+ }
166
+ }
167
+ return result;
168
+ }
169
+ }
170
+
171
+ // ============================================================================
172
+ // Linear Attention Implementations
173
+ // ============================================================================
174
+
175
+ /**
176
+ * Linear Attention - O(N) complexity.
177
+ */
178
+ export class LinearAttention extends BaseAttentionMechanism {
179
+ readonly type: AttentionMechanism = 'linear_attention';
180
+ readonly name = 'Linear Attention';
181
+ readonly description = 'Linear complexity attention using kernel feature maps';
182
+ readonly category: AttentionCategory = 'linear';
183
+
184
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
185
+ const featureMap = this.config.params?.featureMap ?? 'elu';
186
+ const dim = values[0].length;
187
+
188
+ // Apply feature map to query and keys
189
+ const phiQ = this.applyFeatureMap(query, featureMap);
190
+ const phiKs = keys.map(k => this.applyFeatureMap(k, featureMap));
191
+
192
+ // Compute KV matrix (sum of outer products)
193
+ const kvMatrix = new Array(dim).fill(null).map(() => new Array(dim).fill(0));
194
+ const kSum = new Array(dim).fill(0);
195
+
196
+ for (let i = 0; i < keys.length; i++) {
197
+ for (let d1 = 0; d1 < dim; d1++) {
198
+ kSum[d1] += phiKs[i][d1];
199
+ for (let d2 = 0; d2 < dim; d2++) {
200
+ kvMatrix[d1][d2] += phiKs[i][d1] * values[i][d2];
201
+ }
202
+ }
203
+ }
204
+
205
+ // Compute output: (phi(Q) @ KV) / (phi(Q) @ K_sum)
206
+ const numerator = new Array(dim).fill(0);
207
+ let denominator = 0;
208
+
209
+ for (let d = 0; d < dim; d++) {
210
+ denominator += phiQ[d] * kSum[d];
211
+ for (let d2 = 0; d2 < dim; d2++) {
212
+ numerator[d2] += phiQ[d] * kvMatrix[d][d2];
213
+ }
214
+ }
215
+
216
+ return numerator.map(n => n / (denominator + 1e-6));
217
+ }
218
+
219
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
220
+ return Promise.all(queries.map(q => this.compute(q, keys, values)));
221
+ }
222
+
223
+ toSQL(input: AttentionInput): string {
224
+ const q = this.formatMatrix(input.query);
225
+ const k = this.formatMatrix(input.key);
226
+ const v = this.formatMatrix(input.value);
227
+ const featureMap = this.config.params?.featureMap ?? 'elu';
228
+ return `SELECT ruvector.linear_attention(${q}, ${k}, ${v}, '${featureMap}')`;
229
+ }
230
+
231
+ private applyFeatureMap(x: number[], mapType: string): number[] {
232
+ switch (mapType) {
233
+ case 'elu':
234
+ return x.map(v => v > 0 ? v + 1 : Math.exp(v));
235
+ case 'relu':
236
+ return x.map(v => Math.max(0, v));
237
+ case 'exp':
238
+ return x.map(v => Math.exp(v));
239
+ default:
240
+ return x.map(v => v > 0 ? v + 1 : Math.exp(v));
241
+ }
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Performer Attention (FAVOR+).
247
+ */
248
+ export class PerformerAttention extends BaseAttentionMechanism {
249
+ readonly type: AttentionMechanism = 'performer';
250
+ readonly name = 'Performer Attention';
251
+ readonly description = 'FAVOR+ mechanism using random feature approximation';
252
+ readonly category: AttentionCategory = 'linear';
253
+
254
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
255
+ const numFeatures = this.config.params?.numFeatures ?? 256;
256
+ const dim = query.length;
257
+
258
+ // Generate random features (simplified - in practice these would be precomputed)
259
+ const randomMatrix = this.generateRandomFeatures(dim, numFeatures);
260
+
261
+ // Apply random feature map
262
+ const phiQ = this.randomFeatureMap(query, randomMatrix);
263
+ const phiKs = keys.map(k => this.randomFeatureMap(k, randomMatrix));
264
+
265
+ // Linear attention computation
266
+ const kvSum = new Array(numFeatures).fill(null).map(() => new Array(values[0].length).fill(0));
267
+ const kSum = new Array(numFeatures).fill(0);
268
+
269
+ for (let i = 0; i < keys.length; i++) {
270
+ for (let f = 0; f < numFeatures; f++) {
271
+ kSum[f] += phiKs[i][f];
272
+ for (let d = 0; d < values[0].length; d++) {
273
+ kvSum[f][d] += phiKs[i][f] * values[i][d];
274
+ }
275
+ }
276
+ }
277
+
278
+ const numerator = new Array(values[0].length).fill(0);
279
+ let denominator = 0;
280
+
281
+ for (let f = 0; f < numFeatures; f++) {
282
+ denominator += phiQ[f] * kSum[f];
283
+ for (let d = 0; d < values[0].length; d++) {
284
+ numerator[d] += phiQ[f] * kvSum[f][d];
285
+ }
286
+ }
287
+
288
+ return numerator.map(n => n / (denominator + 1e-6));
289
+ }
290
+
291
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
292
+ return Promise.all(queries.map(q => this.compute(q, keys, values)));
293
+ }
294
+
295
+ toSQL(input: AttentionInput): string {
296
+ const q = this.formatMatrix(input.query);
297
+ const k = this.formatMatrix(input.key);
298
+ const v = this.formatMatrix(input.value);
299
+ const numFeatures = this.config.params?.numFeatures ?? 256;
300
+ return `SELECT ruvector.performer_attention(${q}, ${k}, ${v}, ${numFeatures})`;
301
+ }
302
+
303
+ private generateRandomFeatures(inputDim: number, numFeatures: number): number[][] {
304
+ // Simplified random orthogonal features
305
+ return Array(numFeatures).fill(null).map(() =>
306
+ Array(inputDim).fill(0).map(() => (Math.random() - 0.5) * 2 / Math.sqrt(inputDim))
307
+ );
308
+ }
309
+
310
+ private randomFeatureMap(x: number[], randomMatrix: number[][]): number[] {
311
+ return randomMatrix.map(row => {
312
+ const dot = row.reduce((sum, r, i) => sum + r * x[i], 0);
313
+ return Math.exp(dot - 0.5 * x.reduce((s, v) => s + v * v, 0) / x.length);
314
+ });
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Linformer Attention (low-rank projection).
320
+ */
321
+ export class LinformerAttention extends BaseAttentionMechanism {
322
+ readonly type: AttentionMechanism = 'linformer';
323
+ readonly name = 'Linformer Attention';
324
+ readonly description = 'Low-rank projected attention for linear complexity';
325
+ readonly category: AttentionCategory = 'linear';
326
+
327
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
328
+ const projectedDim = this.config.params?.numFeatures ?? Math.min(256, keys.length);
329
+ const scale = this.getScale();
330
+
331
+ // Project keys and values to lower dimension
332
+ const projMatrix = this.generateProjectionMatrix(keys.length, projectedDim);
333
+ const projectedKeys = this.projectSequence(keys, projMatrix);
334
+ const projectedValues = this.projectSequence(values, projMatrix);
335
+
336
+ // Standard attention on projected sequence
337
+ const scores = projectedKeys.map(k => this.dotProduct(query, k) / scale);
338
+ const weights = this.softmax(scores);
339
+ return this.weightedSum(projectedValues, weights);
340
+ }
341
+
342
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
343
+ return Promise.all(queries.map(q => this.compute(q, keys, values)));
344
+ }
345
+
346
+ toSQL(input: AttentionInput): string {
347
+ const q = this.formatMatrix(input.query);
348
+ const k = this.formatMatrix(input.key);
349
+ const v = this.formatMatrix(input.value);
350
+ const projDim = this.config.params?.numFeatures ?? 256;
351
+ return `SELECT ruvector.linformer_attention(${q}, ${k}, ${v}, ${projDim}, ${this.getScale()})`;
352
+ }
353
+
354
+ private generateProjectionMatrix(seqLen: number, projDim: number): number[][] {
355
+ return Array(projDim).fill(null).map(() =>
356
+ Array(seqLen).fill(0).map(() => (Math.random() - 0.5) * 2 / Math.sqrt(seqLen))
357
+ );
358
+ }
359
+
360
+ private projectSequence(seq: number[][], projMatrix: number[][]): number[][] {
361
+ return projMatrix.map(projRow =>
362
+ seq[0].map((_, d) => projRow.reduce((sum, p, i) => sum + p * seq[i][d], 0))
363
+ );
364
+ }
365
+
366
+ private dotProduct(a: number[], b: number[]): number {
367
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
368
+ }
369
+
370
+ private softmax(x: number[]): number[] {
371
+ const max = Math.max(...x);
372
+ const exp = x.map(v => Math.exp(v - max));
373
+ const sum = exp.reduce((a, b) => a + b, 0);
374
+ return exp.map(v => v / sum);
375
+ }
376
+
377
+ private weightedSum(values: number[][], weights: number[]): number[] {
378
+ const dim = values[0].length;
379
+ const result = new Array(dim).fill(0);
380
+ for (let i = 0; i < values.length; i++) {
381
+ for (let j = 0; j < dim; j++) {
382
+ result[j] += weights[i] * values[i][j];
383
+ }
384
+ }
385
+ return result;
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Reformer Attention (LSH-based).
391
+ */
392
+ export class ReformerAttention extends BaseAttentionMechanism {
393
+ readonly type: AttentionMechanism = 'reformer';
394
+ readonly name = 'Reformer Attention';
395
+ readonly description = 'Locality-sensitive hashing attention for efficiency';
396
+ readonly category: AttentionCategory = 'linear';
397
+
398
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
399
+ const numBuckets = this.config.params?.numBuckets ?? 32;
400
+ const scale = this.getScale();
401
+
402
+ // Compute LSH bucket for query
403
+ const queryBucket = this.lshHash(query, numBuckets);
404
+
405
+ // Only attend to keys in same or nearby buckets
406
+ const scores = keys.map((k, i) => {
407
+ const keyBucket = this.lshHash(k, numBuckets);
408
+ if (Math.abs(keyBucket - queryBucket) > 1) return -Infinity;
409
+ return this.dotProduct(query, k) / scale;
410
+ });
411
+
412
+ const weights = this.softmax(scores);
413
+ return this.weightedSum(values, weights);
414
+ }
415
+
416
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
417
+ return Promise.all(queries.map(q => this.compute(q, keys, values)));
418
+ }
419
+
420
+ toSQL(input: AttentionInput): string {
421
+ const q = this.formatMatrix(input.query);
422
+ const k = this.formatMatrix(input.key);
423
+ const v = this.formatMatrix(input.value);
424
+ const numBuckets = this.config.params?.numBuckets ?? 32;
425
+ return `SELECT ruvector.reformer_attention(${q}, ${k}, ${v}, ${numBuckets}, ${this.getScale()})`;
426
+ }
427
+
428
+ private lshHash(vec: number[], numBuckets: number): number {
429
+ // Simplified LSH: project to random hyperplanes
430
+ const projection = vec.reduce((sum, v, i) => sum + v * Math.sin(i * 0.1), 0);
431
+ return Math.floor((projection + 10) / 20 * numBuckets) % numBuckets;
432
+ }
433
+
434
+ private dotProduct(a: number[], b: number[]): number {
435
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
436
+ }
437
+
438
+ private softmax(x: number[]): number[] {
439
+ const filtered = x.filter(v => v !== -Infinity);
440
+ if (filtered.length === 0) return x.map(() => 0);
441
+ const max = Math.max(...filtered);
442
+ const exp = x.map(v => v === -Infinity ? 0 : Math.exp(v - max));
443
+ const sum = exp.reduce((a, b) => a + b, 0);
444
+ return sum > 0 ? exp.map(v => v / sum) : exp;
445
+ }
446
+
447
+ private weightedSum(values: number[][], weights: number[]): number[] {
448
+ const dim = values[0].length;
449
+ const result = new Array(dim).fill(0);
450
+ for (let i = 0; i < values.length; i++) {
451
+ for (let j = 0; j < dim; j++) {
452
+ result[j] += weights[i] * values[i][j];
453
+ }
454
+ }
455
+ return result;
456
+ }
457
+ }
458
+
459
+ // ============================================================================
460
+ // Positional Attention Implementations
461
+ // ============================================================================
462
+
463
+ /**
464
+ * Relative Position Attention (T5, XLNet style).
465
+ */
466
+ export class RelativePositionAttention extends BaseAttentionMechanism {
467
+ readonly type: AttentionMechanism = 'relative_position';
468
+ readonly name = 'Relative Position Attention';
469
+ readonly description = 'Attention with relative position biases';
470
+ readonly category: AttentionCategory = 'positional';
471
+
472
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
473
+ const maxRelPos = this.config.params?.maxRelativePosition ?? 128;
474
+ const numBuckets = this.config.params?.numBuckets ?? 32;
475
+ const scale = this.getScale();
476
+ const queryIdx = keys.length - 1;
477
+
478
+ const scores = keys.map((k, i) => {
479
+ const relPos = i - queryIdx;
480
+ const bias = this.getRelativePositionBias(relPos, maxRelPos, numBuckets);
481
+ return this.dotProduct(query, k) / scale + bias;
482
+ });
483
+
484
+ const weights = this.softmax(scores);
485
+ return this.weightedSum(values, weights);
486
+ }
487
+
488
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
489
+ return Promise.all(queries.map((q, idx) => {
490
+ const maxRelPos = this.config.params?.maxRelativePosition ?? 128;
491
+ const numBuckets = this.config.params?.numBuckets ?? 32;
492
+ const scale = this.getScale();
493
+
494
+ const scores = keys.map((k, i) => {
495
+ const relPos = i - idx;
496
+ const bias = this.getRelativePositionBias(relPos, maxRelPos, numBuckets);
497
+ return this.dotProduct(q, k) / scale + bias;
498
+ });
499
+
500
+ const weights = this.softmax(scores);
501
+ return this.weightedSum(values, weights);
502
+ }));
503
+ }
504
+
505
+ toSQL(input: AttentionInput): string {
506
+ const q = this.formatMatrix(input.query);
507
+ const k = this.formatMatrix(input.key);
508
+ const v = this.formatMatrix(input.value);
509
+ const maxRelPos = this.config.params?.maxRelativePosition ?? 128;
510
+ return `SELECT ruvector.relative_position_attention(${q}, ${k}, ${v}, ${maxRelPos}, ${this.getScale()})`;
511
+ }
512
+
513
+ private getRelativePositionBias(relPos: number, maxDist: number, numBuckets: number): number {
514
+ // T5-style relative position bucketing
515
+ const clampedPos = Math.max(-maxDist, Math.min(maxDist, relPos));
516
+ const bucket = Math.floor((clampedPos + maxDist) / (2 * maxDist) * numBuckets);
517
+ return Math.sin(bucket * 0.1) * 0.1; // Simplified bias
518
+ }
519
+
520
+ private dotProduct(a: number[], b: number[]): number {
521
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
522
+ }
523
+
524
+ private softmax(x: number[]): number[] {
525
+ const max = Math.max(...x);
526
+ const exp = x.map(v => Math.exp(v - max));
527
+ const sum = exp.reduce((a, b) => a + b, 0);
528
+ return exp.map(v => v / sum);
529
+ }
530
+
531
+ private weightedSum(values: number[][], weights: number[]): number[] {
532
+ const dim = values[0].length;
533
+ const result = new Array(dim).fill(0);
534
+ for (let i = 0; i < values.length; i++) {
535
+ for (let j = 0; j < dim; j++) {
536
+ result[j] += weights[i] * values[i][j];
537
+ }
538
+ }
539
+ return result;
540
+ }
541
+ }
542
+
543
+ /**
544
+ * Rotary Position Embedding (RoPE) Attention.
545
+ */
546
+ export class RotaryPositionAttention extends BaseAttentionMechanism {
547
+ readonly type: AttentionMechanism = 'rotary_position';
548
+ readonly name = 'Rotary Position Attention';
549
+ readonly description = 'RoPE-based attention with rotary position embeddings';
550
+ readonly category: AttentionCategory = 'positional';
551
+
552
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
553
+ const base = this.config.params?.ropeBase ?? 10000;
554
+ const scale = this.getScale();
555
+ const queryPos = keys.length - 1;
556
+
557
+ // Apply RoPE to query
558
+ const rotatedQuery = this.applyRoPE(query, queryPos, base);
559
+
560
+ // Apply RoPE to keys and compute attention
561
+ const scores = keys.map((k, i) => {
562
+ const rotatedKey = this.applyRoPE(k, i, base);
563
+ return this.dotProduct(rotatedQuery, rotatedKey) / scale;
564
+ });
565
+
566
+ const weights = this.softmax(scores);
567
+ return this.weightedSum(values, weights);
568
+ }
569
+
570
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
571
+ const base = this.config.params?.ropeBase ?? 10000;
572
+ const scale = this.getScale();
573
+
574
+ return queries.map((q, qIdx) => {
575
+ const rotatedQuery = this.applyRoPE(q, qIdx, base);
576
+ const scores = keys.map((k, kIdx) => {
577
+ const rotatedKey = this.applyRoPE(k, kIdx, base);
578
+ return this.dotProduct(rotatedQuery, rotatedKey) / scale;
579
+ });
580
+ const weights = this.softmax(scores);
581
+ return this.weightedSum(values, weights);
582
+ });
583
+ }
584
+
585
+ toSQL(input: AttentionInput): string {
586
+ const q = this.formatMatrix(input.query);
587
+ const k = this.formatMatrix(input.key);
588
+ const v = this.formatMatrix(input.value);
589
+ const base = this.config.params?.ropeBase ?? 10000;
590
+ return `SELECT ruvector.rotary_position_attention(${q}, ${k}, ${v}, ${base}, ${this.getScale()})`;
591
+ }
592
+
593
+ private applyRoPE(vec: number[], pos: number, base: number): number[] {
594
+ const result = [...vec];
595
+ const dim = vec.length;
596
+ for (let i = 0; i < dim; i += 2) {
597
+ const freq = 1 / Math.pow(base, i / dim);
598
+ const angle = pos * freq;
599
+ const cos = Math.cos(angle);
600
+ const sin = Math.sin(angle);
601
+ const x = vec[i];
602
+ const y = i + 1 < dim ? vec[i + 1] : 0;
603
+ result[i] = x * cos - y * sin;
604
+ if (i + 1 < dim) result[i + 1] = x * sin + y * cos;
605
+ }
606
+ return result;
607
+ }
608
+
609
+ private dotProduct(a: number[], b: number[]): number {
610
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
611
+ }
612
+
613
+ private softmax(x: number[]): number[] {
614
+ const max = Math.max(...x);
615
+ const exp = x.map(v => Math.exp(v - max));
616
+ const sum = exp.reduce((a, b) => a + b, 0);
617
+ return exp.map(v => v / sum);
618
+ }
619
+
620
+ private weightedSum(values: number[][], weights: number[]): number[] {
621
+ const dim = values[0].length;
622
+ const result = new Array(dim).fill(0);
623
+ for (let i = 0; i < values.length; i++) {
624
+ for (let j = 0; j < dim; j++) {
625
+ result[j] += weights[i] * values[i][j];
626
+ }
627
+ }
628
+ return result;
629
+ }
630
+ }
631
+
632
+ /**
633
+ * ALiBi (Attention with Linear Biases).
634
+ */
635
+ export class ALiBiAttention extends BaseAttentionMechanism {
636
+ readonly type: AttentionMechanism = 'alibi';
637
+ readonly name = 'ALiBi Attention';
638
+ readonly description = 'Attention with linear position biases for extrapolation';
639
+ readonly category: AttentionCategory = 'positional';
640
+
641
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
642
+ const scale = this.getScale();
643
+ const queryIdx = keys.length - 1;
644
+ const slope = this.getALiBiSlope(0, this.config.numHeads); // Head 0
645
+
646
+ const scores = keys.map((k, i) => {
647
+ const distance = Math.abs(i - queryIdx);
648
+ const bias = -slope * distance;
649
+ return this.dotProduct(query, k) / scale + bias;
650
+ });
651
+
652
+ const weights = this.softmax(scores);
653
+ return this.weightedSum(values, weights);
654
+ }
655
+
656
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
657
+ return Promise.all(queries.map((q, qIdx) => {
658
+ const scale = this.getScale();
659
+ const slope = this.getALiBiSlope(0, this.config.numHeads);
660
+
661
+ const scores = keys.map((k, kIdx) => {
662
+ const distance = Math.abs(kIdx - qIdx);
663
+ const bias = -slope * distance;
664
+ return this.dotProduct(q, k) / scale + bias;
665
+ });
666
+
667
+ const weights = this.softmax(scores);
668
+ return this.weightedSum(values, weights);
669
+ }));
670
+ }
671
+
672
+ toSQL(input: AttentionInput): string {
673
+ const q = this.formatMatrix(input.query);
674
+ const k = this.formatMatrix(input.key);
675
+ const v = this.formatMatrix(input.value);
676
+ return `SELECT ruvector.alibi_attention(${q}, ${k}, ${v}, ${this.config.numHeads}, ${this.getScale()})`;
677
+ }
678
+
679
+ private getALiBiSlope(headIdx: number, numHeads: number): number {
680
+ const ratio = Math.pow(2, -8 / numHeads);
681
+ return Math.pow(ratio, headIdx + 1);
682
+ }
683
+
684
+ private dotProduct(a: number[], b: number[]): number {
685
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
686
+ }
687
+
688
+ private softmax(x: number[]): number[] {
689
+ const max = Math.max(...x);
690
+ const exp = x.map(v => Math.exp(v - max));
691
+ const sum = exp.reduce((a, b) => a + b, 0);
692
+ return exp.map(v => v / sum);
693
+ }
694
+
695
+ private weightedSum(values: number[][], weights: number[]): number[] {
696
+ const dim = values[0].length;
697
+ const result = new Array(dim).fill(0);
698
+ for (let i = 0; i < values.length; i++) {
699
+ for (let j = 0; j < dim; j++) {
700
+ result[j] += weights[i] * values[i][j];
701
+ }
702
+ }
703
+ return result;
704
+ }
705
+ }
706
+
707
+ /**
708
+ * Axial Attention (2D decomposition).
709
+ */
710
+ export class AxialAttention extends BaseAttentionMechanism {
711
+ readonly type: AttentionMechanism = 'axial';
712
+ readonly name = 'Axial Attention';
713
+ readonly description = '2D decomposed attention for images and structured data';
714
+ readonly category: AttentionCategory = 'positional';
715
+
716
+ async compute(query: number[], keys: number[][], values: number[][]): Promise<number[]> {
717
+ // For 1D sequences, this is similar to standard attention
718
+ const scale = this.getScale();
719
+ const scores = keys.map(k => this.dotProduct(query, k) / scale);
720
+ const weights = this.softmax(scores);
721
+ return this.weightedSum(values, weights);
722
+ }
723
+
724
+ async computeBatch(queries: number[][], keys: number[][], values: number[][]): Promise<number[][]> {
725
+ return Promise.all(queries.map(q => this.compute(q, keys, values)));
726
+ }
727
+
728
+ toSQL(input: AttentionInput): string {
729
+ const q = this.formatMatrix(input.query);
730
+ const k = this.formatMatrix(input.key);
731
+ const v = this.formatMatrix(input.value);
732
+ return `SELECT ruvector.axial_attention(${q}, ${k}, ${v}, ${this.getScale()})`;
733
+ }
734
+
735
+ private dotProduct(a: number[], b: number[]): number {
736
+ return a.reduce((sum, val, i) => sum + val * b[i], 0);
737
+ }
738
+
739
+ private softmax(x: number[]): number[] {
740
+ const max = Math.max(...x);
741
+ const exp = x.map(v => Math.exp(v - max));
742
+ const sum = exp.reduce((a, b) => a + b, 0);
743
+ return exp.map(v => v / sum);
744
+ }
745
+
746
+ private weightedSum(values: number[][], weights: number[]): number[] {
747
+ const dim = values[0].length;
748
+ const result = new Array(dim).fill(0);
749
+ for (let i = 0; i < values.length; i++) {
750
+ for (let j = 0; j < dim; j++) {
751
+ result[j] += weights[i] * values[i][j];
752
+ }
753
+ }
754
+ return result;
755
+ }
756
+ }
757
+