@aleph-ai/tinyaleph 1.5.7 → 1.6.1

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 (122) hide show
  1. package/core/alexander-module.js +1469 -0
  2. package/core/arithmetic-link-kernel.js +1338 -0
  3. package/core/emotion.js +565 -0
  4. package/core/gravity.js +714 -0
  5. package/core/hilbert.js +506 -3
  6. package/core/index.js +132 -4
  7. package/core/nonlocal.js +744 -0
  8. package/core/oracle.js +662 -0
  9. package/examples/01-hello-world.js +69 -0
  10. package/examples/02-basic-hash.js +90 -0
  11. package/examples/02-observer-stack.js +385 -0
  12. package/examples/03-quantum-coin.js +136 -0
  13. package/examples/05-symbolic-resonance.js +146 -0
  14. package/examples/06-symbol-database.js +150 -0
  15. package/examples/07-semantic-inference.js +223 -0
  16. package/examples/08-compound-symbols.js +219 -0
  17. package/examples/README.md +170 -0
  18. package/examples/ai/01-embeddings.js +155 -0
  19. package/examples/ai/02-semantic-memory.js +243 -0
  20. package/examples/ai/03-reasoning.js +243 -0
  21. package/examples/ai/04-knowledge-graph.js +279 -0
  22. package/examples/ai/05-llm-integration.js +333 -0
  23. package/examples/ai/06-agent.js +294 -0
  24. package/examples/ai/07-hybrid-ai.js +223 -0
  25. package/examples/ai/08-entropy-reasoning.js +259 -0
  26. package/examples/ai/09-concept-learning.js +271 -0
  27. package/examples/ai/10-prompt-primes.js +312 -0
  28. package/examples/ai/11-rag.js +332 -0
  29. package/examples/ai/12-neuro-symbolic.js +321 -0
  30. package/examples/ai/README.md +80 -0
  31. package/examples/arithmetic-topology/01-legendre-symbol.js +78 -0
  32. package/examples/arithmetic-topology/02-redei-symbol.js +126 -0
  33. package/examples/arithmetic-topology/03-alk-kuramoto.js +138 -0
  34. package/examples/arithmetic-topology/04-alexander-module.js +117 -0
  35. package/examples/arithmetic-topology/05-signature-memory.js +118 -0
  36. package/examples/arithmetic-topology/README.md +291 -0
  37. package/examples/bioinformatics/01-dna-encoding.js +108 -0
  38. package/examples/bioinformatics/02-central-dogma.js +162 -0
  39. package/examples/bioinformatics/03-protein-folding.js +206 -0
  40. package/examples/bioinformatics/04-dna-computing.js +192 -0
  41. package/examples/bioinformatics/05-molecular-binding.js +209 -0
  42. package/examples/book-operators-demo.js +155 -0
  43. package/examples/chat.js +105 -0
  44. package/examples/crt-homology/01-residue-encoding.js +87 -0
  45. package/examples/crt-homology/02-birkhoff-attention.js +100 -0
  46. package/examples/crt-homology/03-homology-loss.js +132 -0
  47. package/examples/crt-homology/04-crt-resoformer.js +132 -0
  48. package/examples/crt-homology/README.md +67 -0
  49. package/examples/crypto/01-password-hash.js +210 -0
  50. package/examples/crypto/02-key-derivation.js +210 -0
  51. package/examples/crypto/03-hmac.js +229 -0
  52. package/examples/crypto/04-file-integrity.js +263 -0
  53. package/examples/crypto/05-content-hash.js +263 -0
  54. package/examples/crypto/README.md +99 -0
  55. package/examples/demo-modular.js +223 -0
  56. package/examples/demo-two-layer.js +196 -0
  57. package/examples/discrete/01-integer-sine-table.js +120 -0
  58. package/examples/discrete/02-codebook-tunneling.js +118 -0
  59. package/examples/discrete/03-canonical-fusion.js +135 -0
  60. package/examples/discrete/04-tick-gate.js +139 -0
  61. package/examples/discrete/README.md +142 -0
  62. package/examples/emotion-demo.js +200 -0
  63. package/examples/formal-semantics/01-typed-terms.js +156 -0
  64. package/examples/formal-semantics/02-reduction.js +202 -0
  65. package/examples/formal-semantics/03-lambda-translation.js +206 -0
  66. package/examples/formal-semantics/04-enochian-language.js +257 -0
  67. package/examples/formal-semantics/README.md +98 -0
  68. package/examples/gravity-demo.js +190 -0
  69. package/examples/math/01-quaternions.js +237 -0
  70. package/examples/math/02-octonions.js +192 -0
  71. package/examples/math/03-prime-factorization.js +215 -0
  72. package/examples/math/04-vector-spaces.js +210 -0
  73. package/examples/math/05-gaussian-primes.js +234 -0
  74. package/examples/math/README.md +93 -0
  75. package/examples/nonlocal-demo.js +237 -0
  76. package/examples/oracle-demo.js +204 -0
  77. package/examples/physics/01-oscillator.js +177 -0
  78. package/examples/physics/02-lyapunov.js +201 -0
  79. package/examples/physics/03-collapse.js +183 -0
  80. package/examples/physics/04-kuramoto.js +212 -0
  81. package/examples/physics/05-entropy.js +226 -0
  82. package/examples/physics/05-sync-models.js +298 -0
  83. package/examples/physics/06-primeon-ladder.js +233 -0
  84. package/examples/physics/07-kuramoto-coupled-ladder.js +298 -0
  85. package/examples/physics/README.md +126 -0
  86. package/examples/quantum/01-prime-hunter.js +79 -0
  87. package/examples/quantum/02-entanglement-demo.js +79 -0
  88. package/examples/quantum/03-wave-analysis.js +63 -0
  89. package/examples/resonance/01-prime-hilbert-space.js +140 -0
  90. package/examples/resonance/02-prime-resonance-network.js +221 -0
  91. package/examples/resonance/03-resoformer.js +349 -0
  92. package/examples/resonance/04-resoformer-training.js +329 -0
  93. package/examples/resonance/05-language-model.js +484 -0
  94. package/examples/resonance/README.md +238 -0
  95. package/examples/run-examples.js +427 -0
  96. package/examples/scientific/01-single-qubit.js +185 -0
  97. package/examples/scientific/02-two-qubit.js +209 -0
  98. package/examples/scientific/03-quantum-circuits.js +270 -0
  99. package/examples/scientific/04-measurement.js +229 -0
  100. package/examples/scientific/05-algorithms.js +245 -0
  101. package/examples/scientific/06-random.js +225 -0
  102. package/examples/scientific/07-wavefunction.js +192 -0
  103. package/examples/scientific/README.md +118 -0
  104. package/examples/semantic/01-vocabulary.js +186 -0
  105. package/examples/semantic/02-similarity.js +263 -0
  106. package/examples/semantic/03-word-algebra.js +295 -0
  107. package/examples/semantic/04-clustering.js +348 -0
  108. package/examples/semantic/05-classification.js +386 -0
  109. package/examples/semantic/06-dna-encoding.js +228 -0
  110. package/examples/semantic/07-search.js +304 -0
  111. package/examples/semantic/08-qa-system.js +278 -0
  112. package/examples/semantic/README.md +116 -0
  113. package/examples/topology/01-108-invariant.js +81 -0
  114. package/examples/topology/02-trefoil-constants.js +112 -0
  115. package/examples/topology/03-gauge-symmetry.js +112 -0
  116. package/examples/topology/04-free-energy-dynamics.js +124 -0
  117. package/examples/topology/README.md +129 -0
  118. package/index.js +32 -0
  119. package/modular.js +63 -2
  120. package/package.json +8 -3
  121. package/physics/alk-kuramoto.js +817 -0
  122. package/physics/index.js +23 -2
@@ -0,0 +1,1338 @@
1
+ /**
2
+ * Arithmetic Link Kernel (ALK) for TinyAleph
3
+ *
4
+ * Implements invariants from arithmetic topology to provide
5
+ * canonical multi-order coupling tensors for prime sets.
6
+ *
7
+ * Based on: "Arithmetic Link Kernels: Coupling Primes via Linking
8
+ * Symbols, Milnor Invariants, and Higher Residue Structure"
9
+ *
10
+ * Key concepts:
11
+ * - ALK(S; ℓ, m) = (J, {K⁽³⁾}, {K⁽ⁿ⁾})
12
+ * - J: Pairwise coupling matrix from Legendre/power residue symbols
13
+ * - K⁽³⁾: Triadic coupling from Rédei symbol
14
+ * - K⁽ⁿ⁾: Higher-order coupling from arithmetic Milnor invariants
15
+ *
16
+ * @module core/arithmetic-link-kernel
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ import { isPrime, firstNPrimes, factorize } from './prime.js';
22
+
23
+ // ============================================================================
24
+ // MODULAR EXPONENTIATION UTILITIES
25
+ // ============================================================================
26
+
27
+ /**
28
+ * Fast modular exponentiation: a^n mod m
29
+ * Uses binary exponentiation for O(log n) complexity
30
+ *
31
+ * @param {bigint|number} base - Base
32
+ * @param {bigint|number} exp - Exponent
33
+ * @param {bigint|number} mod - Modulus
34
+ * @returns {bigint} Result
35
+ */
36
+ function modPow(base, exp, mod) {
37
+ base = BigInt(base);
38
+ exp = BigInt(exp);
39
+ mod = BigInt(mod);
40
+
41
+ if (mod === 1n) return 0n;
42
+
43
+ let result = 1n;
44
+ base = base % mod;
45
+
46
+ while (exp > 0n) {
47
+ if (exp % 2n === 1n) {
48
+ result = (result * base) % mod;
49
+ }
50
+ exp = exp >> 1n;
51
+ base = (base * base) % mod;
52
+ }
53
+
54
+ return result;
55
+ }
56
+
57
+ /**
58
+ * Extended Euclidean Algorithm for modular inverse
59
+ * @param {bigint} a - Number
60
+ * @param {bigint} m - Modulus
61
+ * @returns {bigint} a^(-1) mod m
62
+ */
63
+ function modInverse(a, m) {
64
+ a = BigInt(a);
65
+ m = BigInt(m);
66
+
67
+ let [old_r, r] = [a, m];
68
+ let [old_s, s] = [1n, 0n];
69
+
70
+ while (r !== 0n) {
71
+ const quotient = old_r / r;
72
+ [old_r, r] = [r, old_r - quotient * r];
73
+ [old_s, s] = [s, old_s - quotient * s];
74
+ }
75
+
76
+ if (old_r > 1n) return null; // No inverse exists
77
+ return ((old_s % m) + m) % m;
78
+ }
79
+
80
+ // ============================================================================
81
+ // PHASE 1: PAIRWISE COUPLINGS - Legendre & Power Residue Symbols
82
+ // ============================================================================
83
+
84
+ /**
85
+ * Legendre Symbol Class
86
+ *
87
+ * The Legendre symbol (a/p) is the mod-2 linking number analogue
88
+ * in arithmetic topology. For odd prime p:
89
+ *
90
+ * (a/p) = a^((p-1)/2) mod p
91
+ *
92
+ * Returns:
93
+ * +1 if a is a quadratic residue mod p
94
+ * -1 if a is a non-residue mod p
95
+ * 0 if p divides a
96
+ */
97
+ class LegendreSymbol {
98
+ /**
99
+ * Compute Legendre symbol (a/p)
100
+ *
101
+ * @param {number} a - Integer
102
+ * @param {number} p - Odd prime
103
+ * @returns {number} -1, 0, or +1
104
+ */
105
+ static compute(a, p) {
106
+ if (!isPrime(p) || p === 2) {
107
+ throw new Error(`LegendreSymbol requires odd prime, got ${p}`);
108
+ }
109
+
110
+ a = ((a % p) + p) % p;
111
+ if (a === 0) return 0;
112
+
113
+ // Euler's criterion: (a/p) ≡ a^((p-1)/2) (mod p)
114
+ const exp = BigInt((p - 1) / 2);
115
+ const result = modPow(BigInt(a), exp, BigInt(p));
116
+
117
+ if (result === 1n) return 1;
118
+ if (result === BigInt(p) - 1n) return -1;
119
+ return 0;
120
+ }
121
+
122
+ /**
123
+ * Compute using quadratic reciprocity (alternative method)
124
+ *
125
+ * @param {number} a - Integer
126
+ * @param {number} p - Odd prime
127
+ * @returns {number} -1, 0, or +1
128
+ */
129
+ static computeReciprocity(a, p) {
130
+ // Reduce a mod p first
131
+ a = ((a % p) + p) % p;
132
+ if (a === 0) return 0;
133
+ if (a === 1) return 1;
134
+
135
+ // Factor out powers of 2
136
+ let e = 0;
137
+ while (a % 2 === 0) {
138
+ a = a / 2;
139
+ e++;
140
+ }
141
+
142
+ // (2/p) = (-1)^((p²-1)/8)
143
+ let result = 1;
144
+ if (e % 2 === 1) {
145
+ const pMod8 = p % 8;
146
+ if (pMod8 === 3 || pMod8 === 5) {
147
+ result = -result;
148
+ }
149
+ }
150
+
151
+ if (a === 1) return result;
152
+
153
+ // Quadratic reciprocity: (p/a)(a/p) = (-1)^((p-1)(a-1)/4)
154
+ if (p % 4 === 3 && a % 4 === 3) {
155
+ result = -result;
156
+ }
157
+
158
+ return result * LegendreSymbol.computeReciprocity(p % a, a);
159
+ }
160
+
161
+ /**
162
+ * Map Legendre symbol to coupling value
163
+ *
164
+ * @param {number} symbol - Legendre symbol value (-1, 0, +1)
165
+ * @param {string} encoding - 'bipolar' (±1), 'binary' (0/1), 'phase' (0/π)
166
+ * @returns {number} Coupling value
167
+ */
168
+ static toCoupling(symbol, encoding = 'bipolar') {
169
+ switch (encoding) {
170
+ case 'bipolar':
171
+ return symbol; // -1, 0, +1
172
+ case 'binary':
173
+ return symbol === 1 ? 1 : 0;
174
+ case 'phase':
175
+ return symbol === 1 ? 0 : Math.PI;
176
+ case 'unit':
177
+ return symbol === 0 ? 0 : 1;
178
+ default:
179
+ return symbol;
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Compute coupling matrix J for prime set S
185
+ * Jᵢⱼ := (pᵢ/pⱼ) for i ≠ j, 0 for i = j
186
+ *
187
+ * @param {number[]} primes - Array of primes
188
+ * @param {string} encoding - Coupling encoding
189
+ * @returns {number[][]} Coupling matrix
190
+ */
191
+ static computeCouplingMatrix(primes, encoding = 'bipolar') {
192
+ const r = primes.length;
193
+ const J = [];
194
+
195
+ for (let i = 0; i < r; i++) {
196
+ J[i] = new Array(r);
197
+ for (let j = 0; j < r; j++) {
198
+ if (i === j) {
199
+ J[i][j] = 0;
200
+ } else if (primes[i] === 2 || primes[j] === 2) {
201
+ // Handle p=2 specially: (a/2) not defined, use (2/p) instead
202
+ if (primes[j] === 2) {
203
+ const pMod8 = primes[i] % 8;
204
+ const val = (pMod8 === 1 || pMod8 === 7) ? 1 : -1;
205
+ J[i][j] = this.toCoupling(val, encoding);
206
+ } else {
207
+ const pMod8 = primes[j] % 8;
208
+ const val = (pMod8 === 1 || pMod8 === 7) ? 1 : -1;
209
+ J[i][j] = this.toCoupling(val, encoding);
210
+ }
211
+ } else {
212
+ const symbol = this.compute(primes[i], primes[j]);
213
+ J[i][j] = this.toCoupling(symbol, encoding);
214
+ }
215
+ }
216
+ }
217
+
218
+ return J;
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Power Residue Symbol Class
224
+ *
225
+ * Generalizes Legendre symbol to n-th power residues.
226
+ * For prime p ≡ 1 (mod n), the n-th power residue symbol
227
+ * (a/p)_n is an n-th root of unity.
228
+ */
229
+ class PowerResidueSymbol {
230
+ /**
231
+ * Compute n-th power residue symbol (a/p)_n
232
+ *
233
+ * @param {number} a - Integer
234
+ * @param {number} p - Prime with p ≡ 1 (mod n)
235
+ * @param {number} n - Power (typically prime)
236
+ * @returns {Object} { value: number, rootOfUnity: number }
237
+ */
238
+ static compute(a, p, n) {
239
+ if (!isPrime(p)) {
240
+ throw new Error(`PowerResidueSymbol requires prime, got ${p}`);
241
+ }
242
+
243
+ // Check p ≡ 1 (mod n) for n-th power residue to be defined
244
+ if ((p - 1) % n !== 0) {
245
+ return { value: 0, rootOfUnity: 0, defined: false };
246
+ }
247
+
248
+ a = ((a % p) + p) % p;
249
+ if (a === 0) return { value: 0, rootOfUnity: 0, defined: true };
250
+
251
+ // (a/p)_n ≡ a^((p-1)/n) (mod p)
252
+ const exp = BigInt((p - 1) / n);
253
+ const result = Number(modPow(BigInt(a), exp, BigInt(p)));
254
+
255
+ // Find which n-th root of unity this is
256
+ // result ≡ ζ_n^k for some k
257
+ const g = this.findPrimitiveRoot(p);
258
+ if (g === null) {
259
+ return { value: result, rootOfUnity: 0, defined: true };
260
+ }
261
+
262
+ // Discrete log to find k
263
+ const gPowN = Number(modPow(BigInt(g), exp, BigInt(p)));
264
+ let k = 0;
265
+ let current = 1;
266
+ for (let i = 0; i < n; i++) {
267
+ if (current === result) {
268
+ k = i;
269
+ break;
270
+ }
271
+ current = (current * gPowN) % p;
272
+ }
273
+
274
+ return {
275
+ value: result,
276
+ rootOfUnity: k, // ζ_n^k
277
+ phase: 2 * Math.PI * k / n,
278
+ defined: true
279
+ };
280
+ }
281
+
282
+ /**
283
+ * Find a primitive root mod p
284
+ * @private
285
+ */
286
+ static findPrimitiveRoot(p) {
287
+ if (!isPrime(p)) return null;
288
+ if (p === 2) return 1;
289
+
290
+ const phi = p - 1;
291
+ const factors = factorize(phi);
292
+
293
+ for (let g = 2; g < p; g++) {
294
+ let isPrimitive = true;
295
+ for (const q of Object.keys(factors)) {
296
+ const exp = phi / parseInt(q);
297
+ if (modPow(BigInt(g), BigInt(exp), BigInt(p)) === 1n) {
298
+ isPrimitive = false;
299
+ break;
300
+ }
301
+ }
302
+ if (isPrimitive) return g;
303
+ }
304
+
305
+ return null;
306
+ }
307
+
308
+ /**
309
+ * Compute n-th power residue coupling matrix
310
+ *
311
+ * @param {number[]} primes - Array of primes
312
+ * @param {number} n - Power
313
+ * @returns {Object[][]} Matrix of power residue data
314
+ */
315
+ static computeCouplingMatrix(primes, n) {
316
+ const r = primes.length;
317
+ const K = [];
318
+
319
+ for (let i = 0; i < r; i++) {
320
+ K[i] = [];
321
+ for (let j = 0; j < r; j++) {
322
+ if (i === j) {
323
+ K[i][j] = { value: 0, phase: 0, defined: true };
324
+ } else {
325
+ K[i][j] = this.compute(primes[i], primes[j], n);
326
+ }
327
+ }
328
+ }
329
+
330
+ return K;
331
+ }
332
+ }
333
+
334
+ // ============================================================================
335
+ // PHASE 2: TRIADIC COUPLINGS - Rédei Symbol
336
+ // ============================================================================
337
+
338
+ /**
339
+ * Rédei Symbol Class
340
+ *
341
+ * The Rédei symbol [p₁, p₂, p₃] ∈ {±1} is the arithmetic analogue
342
+ * of the triple linking number (Milnor's μ(123)).
343
+ *
344
+ * It detects Borromean-type coherence: three primes that have
345
+ * no pairwise coupling but exhibit irreducible triadic coupling.
346
+ *
347
+ * Classical constraints for computability:
348
+ * - p₁, p₂, p₃ are distinct odd primes
349
+ * - (p₁/p₂) = (p₂/p₃) = (p₃/p₁) = 1 (pairwise split)
350
+ * - p₁ ≡ p₂ ≡ 1 (mod 4) typically required
351
+ */
352
+ class RedeiSymbol {
353
+ /**
354
+ * Check if Rédei symbol is computable for triple
355
+ *
356
+ * @param {number} p1 - First prime
357
+ * @param {number} p2 - Second prime
358
+ * @param {number} p3 - Third prime
359
+ * @returns {Object} { computable: boolean, reason: string }
360
+ */
361
+ static isComputable(p1, p2, p3) {
362
+ // All must be distinct odd primes
363
+ if (!isPrime(p1) || !isPrime(p2) || !isPrime(p3)) {
364
+ return { computable: false, reason: 'All arguments must be prime' };
365
+ }
366
+ if (p1 === 2 || p2 === 2 || p3 === 2) {
367
+ return { computable: false, reason: 'Primes must be odd' };
368
+ }
369
+ if (p1 === p2 || p2 === p3 || p1 === p3) {
370
+ return { computable: false, reason: 'Primes must be distinct' };
371
+ }
372
+
373
+ // Check pairwise splitting: Legendre symbols all +1
374
+ const l12 = LegendreSymbol.compute(p1, p2);
375
+ const l23 = LegendreSymbol.compute(p2, p3);
376
+ const l31 = LegendreSymbol.compute(p3, p1);
377
+
378
+ if (l12 !== 1 || l23 !== 1 || l31 !== 1) {
379
+ return {
380
+ computable: false,
381
+ reason: 'Pairwise Legendre symbols must all be +1 (splitting condition)',
382
+ legendreSymbols: { l12, l23, l31 }
383
+ };
384
+ }
385
+
386
+ // Check congruence conditions (simplified version)
387
+ const allMod4 = (p1 % 4 === 1) && (p2 % 4 === 1) && (p3 % 4 === 1);
388
+ if (!allMod4) {
389
+ return {
390
+ computable: false,
391
+ reason: 'Classical Rédei requires pᵢ ≡ 1 (mod 4)',
392
+ congruences: { p1mod4: p1 % 4, p2mod4: p2 % 4, p3mod4: p3 % 4 }
393
+ };
394
+ }
395
+
396
+ return { computable: true, reason: 'All conditions satisfied' };
397
+ }
398
+
399
+ /**
400
+ * Compute Rédei symbol [p₁, p₂, p₃]
401
+ *
402
+ * @param {number} p1 - First prime
403
+ * @param {number} p2 - Second prime
404
+ * @param {number} p3 - Third prime
405
+ * @returns {Object} { value: number, computed: boolean, method: string }
406
+ */
407
+ static compute(p1, p2, p3) {
408
+ const check = this.isComputable(p1, p2, p3);
409
+ if (!check.computable) {
410
+ return { value: 0, computed: false, reason: check.reason };
411
+ }
412
+
413
+ // Find a such that a² ≡ p₁ (mod p₂)
414
+ const a = this.sqrtMod(p1, p2);
415
+ if (a === null) {
416
+ return { value: 0, computed: false, reason: 'sqrt computation failed' };
417
+ }
418
+
419
+ // Compute (a/p₃) as approximation to Rédei symbol
420
+ const redei = LegendreSymbol.compute(a, p3);
421
+
422
+ return {
423
+ value: redei,
424
+ computed: true,
425
+ method: 'genus_theory',
426
+ sqrt_p1_mod_p2: a
427
+ };
428
+ }
429
+
430
+ /**
431
+ * Compute square root mod p using Tonelli-Shanks
432
+ * @private
433
+ */
434
+ static sqrtMod(n, p) {
435
+ n = ((n % p) + p) % p;
436
+ if (n === 0) return 0;
437
+
438
+ // Check n is quadratic residue
439
+ if (LegendreSymbol.compute(n, p) !== 1) return null;
440
+
441
+ // Special case: p ≡ 3 (mod 4)
442
+ if (p % 4 === 3) {
443
+ return Number(modPow(BigInt(n), BigInt((p + 1) / 4), BigInt(p)));
444
+ }
445
+
446
+ // Tonelli-Shanks algorithm
447
+ let s = 0;
448
+ let q = p - 1;
449
+ while (q % 2 === 0) {
450
+ q = Math.floor(q / 2);
451
+ s++;
452
+ }
453
+
454
+ // Find non-residue z
455
+ let z = 2;
456
+ while (LegendreSymbol.compute(z, p) !== -1) z++;
457
+
458
+ let m = s;
459
+ let c = Number(modPow(BigInt(z), BigInt(q), BigInt(p)));
460
+ let t = Number(modPow(BigInt(n), BigInt(q), BigInt(p)));
461
+ let r = Number(modPow(BigInt(n), BigInt((q + 1) / 2), BigInt(p)));
462
+
463
+ while (true) {
464
+ if (t === 1) return r;
465
+
466
+ // Find least i such that t^(2^i) ≡ 1
467
+ let i = 1;
468
+ let temp = (t * t) % p;
469
+ while (temp !== 1) {
470
+ temp = (temp * temp) % p;
471
+ i++;
472
+ }
473
+
474
+ if (i === m) return null;
475
+
476
+ const b = Number(modPow(BigInt(c), BigInt(1 << (m - i - 1)), BigInt(p)));
477
+ m = i;
478
+ c = (b * b) % p;
479
+ t = (t * c) % p;
480
+ r = (r * b) % p;
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Compute triadic coupling tensor K⁽³⁾ for prime set
486
+ *
487
+ * @param {number[]} primes - Array of primes
488
+ * @returns {Object} Sparse tensor representation
489
+ */
490
+ static computeCouplingTensor(primes) {
491
+ const r = primes.length;
492
+ const tensor = {
493
+ size: r,
494
+ entries: new Map(),
495
+ borromean: []
496
+ };
497
+
498
+ for (let i = 0; i < r; i++) {
499
+ for (let j = i + 1; j < r; j++) {
500
+ for (let k = j + 1; k < r; k++) {
501
+ const result = this.compute(primes[i], primes[j], primes[k]);
502
+
503
+ if (result.computed) {
504
+ const key = `${i},${j},${k}`;
505
+ tensor.entries.set(key, {
506
+ indices: [i, j, k],
507
+ primes: [primes[i], primes[j], primes[k]],
508
+ value: result.value,
509
+ method: result.method
510
+ });
511
+
512
+ // Check for Borromean property
513
+ const l12 = LegendreSymbol.compute(primes[i], primes[j]);
514
+ const l23 = LegendreSymbol.compute(primes[j], primes[k]);
515
+ const l31 = LegendreSymbol.compute(primes[k], primes[i]);
516
+
517
+ if (l12 === 1 && l23 === 1 && l31 === 1 && result.value !== 0) {
518
+ tensor.borromean.push({
519
+ indices: [i, j, k],
520
+ primes: [primes[i], primes[j], primes[k]],
521
+ value: result.value
522
+ });
523
+ }
524
+ }
525
+ }
526
+ }
527
+ }
528
+
529
+ return tensor;
530
+ }
531
+ }
532
+
533
+ // ============================================================================
534
+ // PHASE 3: HIGHER-ORDER COUPLINGS - Arithmetic Milnor Invariants
535
+ // ============================================================================
536
+
537
+ /**
538
+ * Arithmetic Milnor Invariant Class
539
+ *
540
+ * Milnor invariants μₘ(I) for multi-index I = i₁···iₙ capture
541
+ * n-body prime interactions that are irreducible to lower orders.
542
+ */
543
+ class ArithmeticMilnorInvariant {
544
+ /**
545
+ * Create Milnor invariant calculator
546
+ *
547
+ * @param {number[]} primes - Prime set S = {p₁, ..., pᵣ}
548
+ * @param {number} ell - Prime ℓ for pro-ℓ structure
549
+ * @param {number} e - Power: m = ℓᵉ
550
+ */
551
+ constructor(primes, ell = 2, e = 1) {
552
+ this.primes = primes;
553
+ this.r = primes.length;
554
+ this.ell = ell;
555
+ this.e = e;
556
+ this.m = Math.pow(ell, e);
557
+ this.validPrimes = primes.filter(p => (p - 1) % ell === 0);
558
+ this._cache = new Map();
559
+ }
560
+
561
+ /**
562
+ * Check if multi-index I is valid
563
+ * @private
564
+ */
565
+ _validateIndex(I) {
566
+ if (!Array.isArray(I) || I.length < 2) {
567
+ return { valid: false, reason: 'Multi-index must have length ≥ 2' };
568
+ }
569
+ for (const i of I) {
570
+ if (i < 0 || i >= this.r) {
571
+ return { valid: false, reason: `Index ${i} out of range [0, ${this.r})` };
572
+ }
573
+ }
574
+ return { valid: true };
575
+ }
576
+
577
+ /**
578
+ * Compute μₘ(I) for multi-index I
579
+ *
580
+ * @param {number[]} I - Multi-index [i₁, i₂, ..., iₙ]
581
+ * @returns {Object} { value: number, modulus: number, computed: boolean }
582
+ */
583
+ compute(I) {
584
+ const check = this._validateIndex(I);
585
+ if (!check.valid) {
586
+ return { value: 0, modulus: this.m, computed: false, reason: check.reason };
587
+ }
588
+
589
+ const key = I.join(',');
590
+ if (this._cache.has(key)) {
591
+ return this._cache.get(key);
592
+ }
593
+
594
+ let result;
595
+
596
+ if (I.length === 2) {
597
+ result = this._computeMu2(I[0], I[1]);
598
+ } else if (I.length === 3) {
599
+ result = this._computeMu3(I[0], I[1], I[2]);
600
+ } else {
601
+ result = this._computeMuN(I);
602
+ }
603
+
604
+ this._cache.set(key, result);
605
+ return result;
606
+ }
607
+
608
+ /**
609
+ * Compute μₘ(i,j) - pairwise
610
+ * @private
611
+ */
612
+ _computeMu2(i, j) {
613
+ const pi = this.primes[i];
614
+ const pj = this.primes[j];
615
+
616
+ if (this.ell === 2) {
617
+ const leg = LegendreSymbol.compute(pi, pj);
618
+ const value = leg === 1 ? 0 : 1;
619
+ return {
620
+ value: value % this.m,
621
+ modulus: this.m,
622
+ computed: true,
623
+ method: 'legendre'
624
+ };
625
+ }
626
+
627
+ const prs = PowerResidueSymbol.compute(pi, pj, this.ell);
628
+ return {
629
+ value: prs.rootOfUnity % this.m,
630
+ modulus: this.m,
631
+ computed: prs.defined,
632
+ method: 'power_residue'
633
+ };
634
+ }
635
+
636
+ /**
637
+ * Compute μₘ(i,j,k) - triadic
638
+ * @private
639
+ */
640
+ _computeMu3(i, j, k) {
641
+ const mu_ij = this._computeMu2(i, j);
642
+ const mu_jk = this._computeMu2(j, k);
643
+ const mu_ki = this._computeMu2(k, i);
644
+
645
+ if (mu_ij.value !== 0 || mu_jk.value !== 0 || mu_ki.value !== 0) {
646
+ return {
647
+ value: 0,
648
+ modulus: this.m,
649
+ computed: false,
650
+ reason: 'Lower-order invariants must vanish',
651
+ lowerOrder: { mu_ij: mu_ij.value, mu_jk: mu_jk.value, mu_ki: mu_ki.value }
652
+ };
653
+ }
654
+
655
+ const pi = this.primes[i];
656
+ const pj = this.primes[j];
657
+ const pk = this.primes[k];
658
+
659
+ if (this.ell === 2) {
660
+ const redei = RedeiSymbol.compute(pi, pj, pk);
661
+ if (redei.computed) {
662
+ const value = redei.value === 1 ? 0 : 1;
663
+ return {
664
+ value: value % this.m,
665
+ modulus: this.m,
666
+ computed: true,
667
+ method: 'redei'
668
+ };
669
+ }
670
+ }
671
+
672
+ return this._computeMasseyTriple(i, j, k);
673
+ }
674
+
675
+ /**
676
+ * Compute μₘ(I) for |I| ≥ 4
677
+ * @private
678
+ */
679
+ _computeMuN(I) {
680
+ for (let len = 2; len < I.length; len++) {
681
+ for (let start = 0; start <= I.length - len; start++) {
682
+ const subIndex = I.slice(start, start + len);
683
+ const subMu = this.compute(subIndex);
684
+ if (subMu.value !== 0) {
685
+ return {
686
+ value: 0,
687
+ modulus: this.m,
688
+ computed: false,
689
+ reason: `Sub-index μ(${subIndex.join(',')}) = ${subMu.value} ≠ 0`
690
+ };
691
+ }
692
+ }
693
+ }
694
+
695
+ return this._computeFoxDerivative(I);
696
+ }
697
+
698
+ /**
699
+ * Approximate Massey triple product
700
+ * @private
701
+ */
702
+ _computeMasseyTriple(i, j, k) {
703
+ const pi = this.primes[i];
704
+ const pj = this.primes[j];
705
+ const pk = this.primes[k];
706
+
707
+ const hash = (pi * pj * pk) % this.m;
708
+
709
+ return {
710
+ value: hash,
711
+ modulus: this.m,
712
+ computed: true,
713
+ method: 'massey_approx',
714
+ note: 'Simplified computation'
715
+ };
716
+ }
717
+
718
+ /**
719
+ * Fox derivative computation for higher-order invariants
720
+ * @private
721
+ */
722
+ _computeFoxDerivative(I) {
723
+ const n = I.length;
724
+ let value = 0;
725
+
726
+ for (let i = 0; i < n; i++) {
727
+ const sign = (i % 2 === 0) ? 1 : -1;
728
+ value += sign * this.primes[I[i]];
729
+ }
730
+
731
+ value = ((value % this.m) + this.m) % this.m;
732
+
733
+ return {
734
+ value,
735
+ modulus: this.m,
736
+ computed: true,
737
+ method: 'fox_derivative_approx',
738
+ order: n
739
+ };
740
+ }
741
+
742
+ /**
743
+ * Get all non-vanishing invariants up to order n
744
+ *
745
+ * @param {number} maxOrder - Maximum order to compute
746
+ * @returns {Map} Map of multi-index → invariant value
747
+ */
748
+ getAllInvariants(maxOrder = 3) {
749
+ const invariants = new Map();
750
+
751
+ const generateIndices = (length) => {
752
+ if (length === 0) return [[]];
753
+ const shorter = generateIndices(length - 1);
754
+ const result = [];
755
+ for (const idx of shorter) {
756
+ const start = idx.length > 0 ? idx[idx.length - 1] + 1 : 0;
757
+ for (let i = start; i < this.r; i++) {
758
+ result.push([...idx, i]);
759
+ }
760
+ }
761
+ return result;
762
+ };
763
+
764
+ for (let order = 2; order <= maxOrder; order++) {
765
+ const indices = generateIndices(order);
766
+ for (const I of indices) {
767
+ const mu = this.compute(I);
768
+ if (mu.computed && mu.value !== 0) {
769
+ invariants.set(I.join(','), {
770
+ index: I,
771
+ ...mu
772
+ });
773
+ }
774
+ }
775
+ }
776
+
777
+ return invariants;
778
+ }
779
+ }
780
+
781
+ /**
782
+ * Multiple Residue Symbol Class
783
+ *
784
+ * The n-fold multiple residue symbol [p_{i₁}, ..., p_{iₙ}] ∈ μ_ℓ
785
+ * extends pairwise Legendre/power residue symbols to n-body interactions.
786
+ */
787
+ class MultipleResidueSymbol {
788
+ /**
789
+ * Compute n-fold multiple residue symbol
790
+ *
791
+ * @param {number[]} primes - Array of n primes [p_{i₁}, ..., p_{iₙ}]
792
+ * @param {number} ell - Prime ℓ
793
+ * @returns {Object} { value: Complex, rootOfUnity: number }
794
+ */
795
+ static compute(primes, ell = 2) {
796
+ if (primes.length < 2) {
797
+ return { value: 1, rootOfUnity: 0, computed: false, reason: 'Need at least 2 primes' };
798
+ }
799
+
800
+ const milnor = new ArithmeticMilnorInvariant(primes, ell);
801
+ const I = primes.map((_, i) => i);
802
+
803
+ for (let len = 2; len < primes.length; len++) {
804
+ for (let start = 0; start <= primes.length - len; start++) {
805
+ const subI = I.slice(start, start + len);
806
+ const mu = milnor.compute(subI);
807
+ if (mu.computed && mu.value !== 0) {
808
+ return {
809
+ value: 0,
810
+ rootOfUnity: 0,
811
+ computed: false,
812
+ reason: `Lower-order μ(${subI.join(',')}) = ${mu.value} ≠ 0`
813
+ };
814
+ }
815
+ }
816
+ }
817
+
818
+ const mu = milnor.compute(I);
819
+ const k = mu.value;
820
+ const phase = 2 * Math.PI * k / ell;
821
+
822
+ return {
823
+ value: { re: Math.cos(phase), im: Math.sin(phase) },
824
+ rootOfUnity: k,
825
+ phase,
826
+ computed: mu.computed,
827
+ method: mu.method
828
+ };
829
+ }
830
+ }
831
+
832
+ // ============================================================================
833
+ // ARITHMETIC LINK KERNEL - Main Class
834
+ // ============================================================================
835
+
836
+ /**
837
+ * Arithmetic Link Kernel (ALK)
838
+ *
839
+ * Packages arithmetic topology invariants as coupling tensors for
840
+ * prime-resonant operator dynamics.
841
+ *
842
+ * ALK(S; ℓ, m) = (J, {K⁽³⁾}, {K⁽ⁿ⁾})
843
+ */
844
+ class ArithmeticLinkKernel {
845
+ /**
846
+ * Create an Arithmetic Link Kernel
847
+ *
848
+ * @param {number[]} primes - Prime set S = {p₁, ..., pᵣ}
849
+ * @param {Object} options - Configuration
850
+ */
851
+ constructor(primes, options = {}) {
852
+ this.primes = primes.filter(p => isPrime(p)).sort((a, b) => a - b);
853
+ this.r = this.primes.length;
854
+
855
+ if (this.r < 2) {
856
+ throw new Error('ALK requires at least 2 primes');
857
+ }
858
+
859
+ this.ell = options.ell || 2;
860
+ this.e = options.e || 1;
861
+ this.m = Math.pow(this.ell, this.e);
862
+ this.encoding = options.encoding || 'bipolar';
863
+ this.maxOrder = options.maxOrder || 3;
864
+
865
+ this._J = null;
866
+ this._K3 = null;
867
+ this._Kn = new Map();
868
+ this._milnor = null;
869
+
870
+ this.metadata = {
871
+ created: Date.now(),
872
+ primeProduct: primes.reduce((a, b) => a * b, 1),
873
+ primeSum: primes.reduce((a, b) => a + b, 0)
874
+ };
875
+ }
876
+
877
+ /**
878
+ * Get pairwise coupling matrix J ∈ ℝʳˣʳ
879
+ */
880
+ get J() {
881
+ if (!this._J) {
882
+ this._J = LegendreSymbol.computeCouplingMatrix(this.primes, this.encoding);
883
+ }
884
+ return this._J;
885
+ }
886
+
887
+ /**
888
+ * Get coupling between specific primes
889
+ */
890
+ getCoupling(p1, p2) {
891
+ const i = this.primes.indexOf(p1);
892
+ const j = this.primes.indexOf(p2);
893
+
894
+ if (i === -1 || j === -1) {
895
+ throw new Error(`Primes ${p1}, ${p2} not in kernel`);
896
+ }
897
+
898
+ return this.J[i][j];
899
+ }
900
+
901
+ /**
902
+ * Get symmetrized coupling matrix (J + J^T) / 2
903
+ */
904
+ get Jsym() {
905
+ const J = this.J;
906
+ const Jsym = [];
907
+
908
+ for (let i = 0; i < this.r; i++) {
909
+ Jsym[i] = [];
910
+ for (let j = 0; j < this.r; j++) {
911
+ Jsym[i][j] = (J[i][j] + J[j][i]) / 2;
912
+ }
913
+ }
914
+
915
+ return Jsym;
916
+ }
917
+
918
+ /**
919
+ * Get triadic coupling tensor K⁽³⁾
920
+ */
921
+ get K3() {
922
+ if (!this._K3) {
923
+ this._K3 = RedeiSymbol.computeCouplingTensor(this.primes);
924
+ }
925
+ return this._K3;
926
+ }
927
+
928
+ /**
929
+ * Get triadic coupling for specific triple
930
+ */
931
+ getTriadicCoupling(p1, p2, p3) {
932
+ const sorted = [p1, p2, p3].sort((a, b) => a - b);
933
+ const i = this.primes.indexOf(sorted[0]);
934
+ const j = this.primes.indexOf(sorted[1]);
935
+ const k = this.primes.indexOf(sorted[2]);
936
+
937
+ if (i === -1 || j === -1 || k === -1) {
938
+ throw new Error('Primes not in kernel');
939
+ }
940
+
941
+ const key = `${i},${j},${k}`;
942
+ return this.K3.entries.get(key) || { value: 0, computed: false };
943
+ }
944
+
945
+ /**
946
+ * Get n-body coupling K⁽ⁿ⁾
947
+ */
948
+ getKn(n) {
949
+ if (n < 4) {
950
+ throw new Error('Use J for n=2 or K3 for n=3');
951
+ }
952
+
953
+ if (!this._Kn.has(n)) {
954
+ this._computeKn(n);
955
+ }
956
+
957
+ return this._Kn.get(n);
958
+ }
959
+
960
+ /**
961
+ * Compute K⁽ⁿ⁾ tensor
962
+ * @private
963
+ */
964
+ _computeKn(n) {
965
+ if (!this._milnor) {
966
+ this._milnor = new ArithmeticMilnorInvariant(this.primes, this.ell, this.e);
967
+ }
968
+
969
+ const tensor = {
970
+ order: n,
971
+ size: this.r,
972
+ entries: new Map()
973
+ };
974
+
975
+ const generateTuples = (remaining, current, start) => {
976
+ if (remaining === 0) {
977
+ const I = [...current];
978
+ const mu = this._milnor.compute(I);
979
+ if (mu.computed && mu.value !== 0) {
980
+ tensor.entries.set(I.join(','), {
981
+ indices: I,
982
+ primes: I.map(i => this.primes[i]),
983
+ value: mu.value,
984
+ modulus: mu.modulus
985
+ });
986
+ }
987
+ return;
988
+ }
989
+
990
+ for (let i = start; i < this.r; i++) {
991
+ current.push(i);
992
+ generateTuples(remaining - 1, current, i + 1);
993
+ current.pop();
994
+ }
995
+ };
996
+
997
+ generateTuples(n, [], 0);
998
+ this._Kn.set(n, tensor);
999
+ }
1000
+
1001
+ /**
1002
+ * Find all Borromean triples
1003
+ */
1004
+ findBorromeanTriples() {
1005
+ return this.K3.borromean;
1006
+ }
1007
+
1008
+ /**
1009
+ * Check if a specific triple is Borromean
1010
+ */
1011
+ isBorromean(p1, p2, p3) {
1012
+ const J = this.J;
1013
+ const i = this.primes.indexOf(p1);
1014
+ const j = this.primes.indexOf(p2);
1015
+ const k = this.primes.indexOf(p3);
1016
+
1017
+ if (i === -1 || j === -1 || k === -1) return false;
1018
+
1019
+ const trivial = this.encoding === 'bipolar' ? 1 : 0;
1020
+ if (J[i][j] !== trivial || J[j][k] !== trivial || J[k][i] !== trivial) {
1021
+ return false;
1022
+ }
1023
+
1024
+ const triadic = this.getTriadicCoupling(p1, p2, p3);
1025
+ return triadic.value !== 0;
1026
+ }
1027
+
1028
+ /**
1029
+ * Build interaction Hamiltonian using ALK couplings
1030
+ */
1031
+ buildHamiltonian(operators) {
1032
+ const J = this.J;
1033
+ const K3 = this.K3;
1034
+
1035
+ return (state) => {
1036
+ let result = state.clone ? state.clone() : { ...state };
1037
+
1038
+ if (operators.pairwise) {
1039
+ for (let i = 0; i < this.r; i++) {
1040
+ for (let j = i + 1; j < this.r; j++) {
1041
+ const coupling = J[i][j];
1042
+ if (Math.abs(coupling) > 1e-10) {
1043
+ const op = operators.pairwise(this.primes[i], this.primes[j]);
1044
+ result = op(result, coupling);
1045
+ }
1046
+ }
1047
+ }
1048
+ }
1049
+
1050
+ if (operators.triadic) {
1051
+ for (const [, entry] of K3.entries) {
1052
+ const [i, j, k] = entry.indices;
1053
+ const coupling = entry.value;
1054
+ if (Math.abs(coupling) > 1e-10) {
1055
+ const op = operators.triadic(
1056
+ this.primes[i],
1057
+ this.primes[j],
1058
+ this.primes[k]
1059
+ );
1060
+ result = op(result, coupling);
1061
+ }
1062
+ }
1063
+ }
1064
+
1065
+ return result;
1066
+ };
1067
+ }
1068
+
1069
+ /**
1070
+ * Get ALK as JSON-serializable object
1071
+ */
1072
+ toJSON() {
1073
+ return {
1074
+ primes: this.primes,
1075
+ ell: this.ell,
1076
+ m: this.m,
1077
+ encoding: this.encoding,
1078
+ J: this.J,
1079
+ K3: {
1080
+ size: this.K3.size,
1081
+ entries: Array.from(this.K3.entries.entries()),
1082
+ borromean: this.K3.borromean
1083
+ },
1084
+ metadata: this.metadata
1085
+ };
1086
+ }
1087
+
1088
+ /**
1089
+ * Create ALK from JSON
1090
+ */
1091
+ static fromJSON(json) {
1092
+ const alk = new ArithmeticLinkKernel(json.primes, {
1093
+ ell: json.ell,
1094
+ encoding: json.encoding
1095
+ });
1096
+
1097
+ alk._J = json.J;
1098
+ alk._K3 = {
1099
+ size: json.K3.size,
1100
+ entries: new Map(json.K3.entries),
1101
+ borromean: json.K3.borromean
1102
+ };
1103
+ alk.metadata = json.metadata;
1104
+
1105
+ return alk;
1106
+ }
1107
+
1108
+ /**
1109
+ * Get summary statistics
1110
+ */
1111
+ get stats() {
1112
+ const J = this.J;
1113
+ const K3 = this.K3;
1114
+
1115
+ let pairwiseNonTrivial = 0;
1116
+ let pairwiseSum = 0;
1117
+ const trivial = this.encoding === 'bipolar' ? 1 : 0;
1118
+
1119
+ for (let i = 0; i < this.r; i++) {
1120
+ for (let j = i + 1; j < this.r; j++) {
1121
+ if (J[i][j] !== trivial) {
1122
+ pairwiseNonTrivial++;
1123
+ }
1124
+ pairwiseSum += Math.abs(J[i][j]);
1125
+ }
1126
+ }
1127
+
1128
+ const maxPairwise = this.r * (this.r - 1) / 2;
1129
+
1130
+ return {
1131
+ numPrimes: this.r,
1132
+ pairwiseCouplings: maxPairwise,
1133
+ pairwiseNonTrivial,
1134
+ pairwiseDensity: pairwiseNonTrivial / maxPairwise,
1135
+ meanAbsCoupling: pairwiseSum / maxPairwise,
1136
+ triadicEntries: K3.entries.size,
1137
+ borromeanTriples: K3.borromean.length
1138
+ };
1139
+ }
1140
+ }
1141
+
1142
+ // ============================================================================
1143
+ // ALK OPERATORS - Integration with PrimeState / Hilbert dynamics
1144
+ // ============================================================================
1145
+
1146
+ /**
1147
+ * ALK-based resonance operators for PrimeState
1148
+ */
1149
+ const ALKOperators = {
1150
+ /**
1151
+ * ALK-weighted resonance operator
1152
+ */
1153
+ Resonance(alk) {
1154
+ const J = alk.J;
1155
+ const primes = alk.primes;
1156
+
1157
+ return (state) => {
1158
+ if (!state.amplitudes && !state.get) {
1159
+ throw new Error('State must have amplitudes');
1160
+ }
1161
+
1162
+ const result = state.clone ? state.clone() : { amplitudes: new Map(state.amplitudes) };
1163
+ const newAmps = new Map();
1164
+
1165
+ for (let i = 0; i < primes.length; i++) {
1166
+ const pi = primes[i];
1167
+ let sumRe = 0, sumIm = 0;
1168
+
1169
+ for (let j = 0; j < primes.length; j++) {
1170
+ const pj = primes[j];
1171
+ const amp = state.get ? state.get(pj) : (state.amplitudes.get(pj) || { re: 0, im: 0 });
1172
+ const coupling = J[i][j];
1173
+
1174
+ sumRe += coupling * (amp.re || 0);
1175
+ sumIm += coupling * (amp.im || 0);
1176
+ }
1177
+
1178
+ newAmps.set(pi, { re: sumRe, im: sumIm });
1179
+ }
1180
+
1181
+ for (const [p, amp] of newAmps) {
1182
+ if (result.set) {
1183
+ result.set(p, amp);
1184
+ } else if (result.amplitudes) {
1185
+ result.amplitudes.set(p, amp);
1186
+ }
1187
+ }
1188
+
1189
+ return result;
1190
+ };
1191
+ },
1192
+
1193
+ /**
1194
+ * Triadic phase-lock operator using K³
1195
+ */
1196
+ TriadicPhaseLock(alk) {
1197
+ const K3 = alk.K3;
1198
+ const primes = alk.primes;
1199
+
1200
+ return (state) => {
1201
+ if (!state.amplitudes && !state.get) {
1202
+ throw new Error('State must have amplitudes');
1203
+ }
1204
+
1205
+ const result = state.clone ? state.clone() : { amplitudes: new Map(state.amplitudes) };
1206
+
1207
+ for (const [, entry] of K3.entries) {
1208
+ const [i, j, k] = entry.indices;
1209
+ const pk = primes[k];
1210
+
1211
+ const get = (p) => state.get ? state.get(p) : state.amplitudes.get(p);
1212
+ const ak = get(pk);
1213
+
1214
+ if (!ak) continue;
1215
+
1216
+ const phase = entry.value * Math.PI / 2;
1217
+ const rotation = { re: Math.cos(phase), im: Math.sin(phase) };
1218
+
1219
+ const newAk = {
1220
+ re: (ak.re || 0) * rotation.re - (ak.im || 0) * rotation.im,
1221
+ im: (ak.im || 0) * rotation.re + (ak.re || 0) * rotation.im
1222
+ };
1223
+
1224
+ if (result.set) {
1225
+ result.set(pk, newAk);
1226
+ } else if (result.amplitudes) {
1227
+ result.amplitudes.set(pk, newAk);
1228
+ }
1229
+ }
1230
+
1231
+ return result;
1232
+ };
1233
+ }
1234
+ };
1235
+
1236
+ // ============================================================================
1237
+ // UTILITY FUNCTIONS
1238
+ // ============================================================================
1239
+
1240
+ /**
1241
+ * Find Borromean primes in a larger set
1242
+ */
1243
+ function findBorromeanPrimes(primes, maxResults = 100) {
1244
+ const alk = new ArithmeticLinkKernel(primes);
1245
+ return alk.findBorromeanTriples().slice(0, maxResults);
1246
+ }
1247
+
1248
+ /**
1249
+ * Compute pairwise coupling matrix for convenience
1250
+ */
1251
+ function computeLegendreMatrix(primes, encoding = 'bipolar') {
1252
+ return LegendreSymbol.computeCouplingMatrix(primes, encoding);
1253
+ }
1254
+
1255
+ /**
1256
+ * Quick check if triple might be Borromean
1257
+ */
1258
+ function quickBorromeanCheck(p1, p2, p3) {
1259
+ if (!isPrime(p1) || !isPrime(p2) || !isPrime(p3)) {
1260
+ return { possible: false, reason: 'Not all primes' };
1261
+ }
1262
+ if (p1 === 2 || p2 === 2 || p3 === 2) {
1263
+ return { possible: false, reason: 'Contains 2' };
1264
+ }
1265
+
1266
+ const l12 = LegendreSymbol.compute(p1, p2);
1267
+ const l23 = LegendreSymbol.compute(p2, p3);
1268
+ const l31 = LegendreSymbol.compute(p3, p1);
1269
+
1270
+ if (l12 !== 1 || l23 !== 1 || l31 !== 1) {
1271
+ return {
1272
+ possible: false,
1273
+ reason: 'Pairwise Legendre not all +1',
1274
+ legendreSymbols: { l12, l23, l31 }
1275
+ };
1276
+ }
1277
+
1278
+ const check = RedeiSymbol.isComputable(p1, p2, p3);
1279
+ if (!check.computable) {
1280
+ return { possible: true, reason: 'Rédei not computable: ' + check.reason };
1281
+ }
1282
+
1283
+ const redei = RedeiSymbol.compute(p1, p2, p3);
1284
+
1285
+ return {
1286
+ possible: redei.computed && redei.value !== 0,
1287
+ isBorromean: redei.computed && redei.value === -1,
1288
+ redeiSymbol: redei.value,
1289
+ reason: redei.computed ? 'Computed' : redei.reason
1290
+ };
1291
+ }
1292
+
1293
+ // ============================================================================
1294
+ // EXPORTS
1295
+ // ============================================================================
1296
+
1297
+ export {
1298
+ // Modular arithmetic
1299
+ modPow,
1300
+ modInverse,
1301
+
1302
+ // Phase 1: Pairwise
1303
+ LegendreSymbol,
1304
+ PowerResidueSymbol,
1305
+
1306
+ // Phase 2: Triadic
1307
+ RedeiSymbol,
1308
+
1309
+ // Phase 3: Higher-order
1310
+ ArithmeticMilnorInvariant,
1311
+ MultipleResidueSymbol,
1312
+
1313
+ // Main ALK class
1314
+ ArithmeticLinkKernel,
1315
+
1316
+ // Operators
1317
+ ALKOperators,
1318
+
1319
+ // Utilities
1320
+ findBorromeanPrimes,
1321
+ computeLegendreMatrix,
1322
+ quickBorromeanCheck
1323
+ };
1324
+
1325
+ export default {
1326
+ modPow,
1327
+ modInverse,
1328
+ LegendreSymbol,
1329
+ PowerResidueSymbol,
1330
+ RedeiSymbol,
1331
+ ArithmeticMilnorInvariant,
1332
+ MultipleResidueSymbol,
1333
+ ArithmeticLinkKernel,
1334
+ ALKOperators,
1335
+ findBorromeanPrimes,
1336
+ computeLegendreMatrix,
1337
+ quickBorromeanCheck
1338
+ };