@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.
- package/core/alexander-module.js +1469 -0
- package/core/arithmetic-link-kernel.js +1338 -0
- package/core/emotion.js +565 -0
- package/core/gravity.js +714 -0
- package/core/hilbert.js +506 -3
- package/core/index.js +132 -4
- package/core/nonlocal.js +744 -0
- package/core/oracle.js +662 -0
- package/examples/01-hello-world.js +69 -0
- package/examples/02-basic-hash.js +90 -0
- package/examples/02-observer-stack.js +385 -0
- package/examples/03-quantum-coin.js +136 -0
- package/examples/05-symbolic-resonance.js +146 -0
- package/examples/06-symbol-database.js +150 -0
- package/examples/07-semantic-inference.js +223 -0
- package/examples/08-compound-symbols.js +219 -0
- package/examples/README.md +170 -0
- package/examples/ai/01-embeddings.js +155 -0
- package/examples/ai/02-semantic-memory.js +243 -0
- package/examples/ai/03-reasoning.js +243 -0
- package/examples/ai/04-knowledge-graph.js +279 -0
- package/examples/ai/05-llm-integration.js +333 -0
- package/examples/ai/06-agent.js +294 -0
- package/examples/ai/07-hybrid-ai.js +223 -0
- package/examples/ai/08-entropy-reasoning.js +259 -0
- package/examples/ai/09-concept-learning.js +271 -0
- package/examples/ai/10-prompt-primes.js +312 -0
- package/examples/ai/11-rag.js +332 -0
- package/examples/ai/12-neuro-symbolic.js +321 -0
- package/examples/ai/README.md +80 -0
- package/examples/arithmetic-topology/01-legendre-symbol.js +78 -0
- package/examples/arithmetic-topology/02-redei-symbol.js +126 -0
- package/examples/arithmetic-topology/03-alk-kuramoto.js +138 -0
- package/examples/arithmetic-topology/04-alexander-module.js +117 -0
- package/examples/arithmetic-topology/05-signature-memory.js +118 -0
- package/examples/arithmetic-topology/README.md +291 -0
- package/examples/bioinformatics/01-dna-encoding.js +108 -0
- package/examples/bioinformatics/02-central-dogma.js +162 -0
- package/examples/bioinformatics/03-protein-folding.js +206 -0
- package/examples/bioinformatics/04-dna-computing.js +192 -0
- package/examples/bioinformatics/05-molecular-binding.js +209 -0
- package/examples/book-operators-demo.js +155 -0
- package/examples/chat.js +105 -0
- package/examples/crt-homology/01-residue-encoding.js +87 -0
- package/examples/crt-homology/02-birkhoff-attention.js +100 -0
- package/examples/crt-homology/03-homology-loss.js +132 -0
- package/examples/crt-homology/04-crt-resoformer.js +132 -0
- package/examples/crt-homology/README.md +67 -0
- package/examples/crypto/01-password-hash.js +210 -0
- package/examples/crypto/02-key-derivation.js +210 -0
- package/examples/crypto/03-hmac.js +229 -0
- package/examples/crypto/04-file-integrity.js +263 -0
- package/examples/crypto/05-content-hash.js +263 -0
- package/examples/crypto/README.md +99 -0
- package/examples/demo-modular.js +223 -0
- package/examples/demo-two-layer.js +196 -0
- package/examples/discrete/01-integer-sine-table.js +120 -0
- package/examples/discrete/02-codebook-tunneling.js +118 -0
- package/examples/discrete/03-canonical-fusion.js +135 -0
- package/examples/discrete/04-tick-gate.js +139 -0
- package/examples/discrete/README.md +142 -0
- package/examples/emotion-demo.js +200 -0
- package/examples/formal-semantics/01-typed-terms.js +156 -0
- package/examples/formal-semantics/02-reduction.js +202 -0
- package/examples/formal-semantics/03-lambda-translation.js +206 -0
- package/examples/formal-semantics/04-enochian-language.js +257 -0
- package/examples/formal-semantics/README.md +98 -0
- package/examples/gravity-demo.js +190 -0
- package/examples/math/01-quaternions.js +237 -0
- package/examples/math/02-octonions.js +192 -0
- package/examples/math/03-prime-factorization.js +215 -0
- package/examples/math/04-vector-spaces.js +210 -0
- package/examples/math/05-gaussian-primes.js +234 -0
- package/examples/math/README.md +93 -0
- package/examples/nonlocal-demo.js +237 -0
- package/examples/oracle-demo.js +204 -0
- package/examples/physics/01-oscillator.js +177 -0
- package/examples/physics/02-lyapunov.js +201 -0
- package/examples/physics/03-collapse.js +183 -0
- package/examples/physics/04-kuramoto.js +212 -0
- package/examples/physics/05-entropy.js +226 -0
- package/examples/physics/05-sync-models.js +298 -0
- package/examples/physics/06-primeon-ladder.js +233 -0
- package/examples/physics/07-kuramoto-coupled-ladder.js +298 -0
- package/examples/physics/README.md +126 -0
- package/examples/quantum/01-prime-hunter.js +79 -0
- package/examples/quantum/02-entanglement-demo.js +79 -0
- package/examples/quantum/03-wave-analysis.js +63 -0
- package/examples/resonance/01-prime-hilbert-space.js +140 -0
- package/examples/resonance/02-prime-resonance-network.js +221 -0
- package/examples/resonance/03-resoformer.js +349 -0
- package/examples/resonance/04-resoformer-training.js +329 -0
- package/examples/resonance/05-language-model.js +484 -0
- package/examples/resonance/README.md +238 -0
- package/examples/run-examples.js +427 -0
- package/examples/scientific/01-single-qubit.js +185 -0
- package/examples/scientific/02-two-qubit.js +209 -0
- package/examples/scientific/03-quantum-circuits.js +270 -0
- package/examples/scientific/04-measurement.js +229 -0
- package/examples/scientific/05-algorithms.js +245 -0
- package/examples/scientific/06-random.js +225 -0
- package/examples/scientific/07-wavefunction.js +192 -0
- package/examples/scientific/README.md +118 -0
- package/examples/semantic/01-vocabulary.js +186 -0
- package/examples/semantic/02-similarity.js +263 -0
- package/examples/semantic/03-word-algebra.js +295 -0
- package/examples/semantic/04-clustering.js +348 -0
- package/examples/semantic/05-classification.js +386 -0
- package/examples/semantic/06-dna-encoding.js +228 -0
- package/examples/semantic/07-search.js +304 -0
- package/examples/semantic/08-qa-system.js +278 -0
- package/examples/semantic/README.md +116 -0
- package/examples/topology/01-108-invariant.js +81 -0
- package/examples/topology/02-trefoil-constants.js +112 -0
- package/examples/topology/03-gauge-symmetry.js +112 -0
- package/examples/topology/04-free-energy-dynamics.js +124 -0
- package/examples/topology/README.md +129 -0
- package/index.js +32 -0
- package/modular.js +63 -2
- package/package.json +8 -3
- package/physics/alk-kuramoto.js +817 -0
- 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
|
+
};
|