@aleph-ai/tinyaleph 1.5.7 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/alexander-module.js +1469 -0
- package/core/arithmetic-link-kernel.js +1338 -0
- package/core/index.js +95 -2
- 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/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/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/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/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/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 +417 -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,817 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ALK-Kuramoto Integration
|
|
3
|
+
*
|
|
4
|
+
* Extends Kuramoto oscillator dynamics with Arithmetic Link Kernel couplings.
|
|
5
|
+
* Uses ALK's J matrix for pairwise coupling and K³ tensor for triadic phase terms.
|
|
6
|
+
*
|
|
7
|
+
* Key equations:
|
|
8
|
+
* Standard Kuramoto: dθᵢ/dt = ωᵢ + (K/N) Σⱼ sin(θⱼ - θᵢ)
|
|
9
|
+
*
|
|
10
|
+
* ALK-Kuramoto: dθᵢ/dt = ωᵢ + Σⱼ Jᵢⱼ sin(θⱼ - θᵢ)
|
|
11
|
+
* + Σⱼ<ₖ K³ᵢⱼₖ sin(θⱼ + θₖ - 2θᵢ)
|
|
12
|
+
*
|
|
13
|
+
* The triadic term sin(θⱼ + θₖ - 2θᵢ) captures irreducible three-body
|
|
14
|
+
* phase correlations (Borromean coherence).
|
|
15
|
+
*
|
|
16
|
+
* @module physics/alk-kuramoto
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
import { KuramotoModel } from './kuramoto.js';
|
|
22
|
+
import { OscillatorBank } from './oscillator.js';
|
|
23
|
+
import { ArithmeticLinkKernel } from '../core/arithmetic-link-kernel.js';
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// ALK KURAMOTO MODEL
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ALK-Kuramoto Model
|
|
31
|
+
*
|
|
32
|
+
* Extends standard Kuramoto with:
|
|
33
|
+
* - Pairwise coupling from Legendre symbols (J matrix)
|
|
34
|
+
* - Triadic coupling from Rédei symbols (K³ tensor)
|
|
35
|
+
* - Higher-order couplings from Milnor invariants (Kⁿ)
|
|
36
|
+
*/
|
|
37
|
+
class ALKKuramotoModel {
|
|
38
|
+
/**
|
|
39
|
+
* Create an ALK-Kuramoto model
|
|
40
|
+
*
|
|
41
|
+
* @param {OscillatorBank|number[]} oscillators - Oscillator bank or natural frequencies
|
|
42
|
+
* @param {Object} alk - ArithmeticLinkKernel instance
|
|
43
|
+
* @param {Object} options - Configuration
|
|
44
|
+
* @param {number} options.couplingScale - Scale factor for J matrix (default: 0.1)
|
|
45
|
+
* @param {number} options.triadicScale - Scale factor for K³ tensor (default: 0.05)
|
|
46
|
+
* @param {boolean} options.useTriadic - Enable triadic coupling (default: true)
|
|
47
|
+
* @param {boolean} options.useHigherOrder - Enable n>3 couplings (default: false)
|
|
48
|
+
* @param {number} options.dt - Time step (default: 0.01)
|
|
49
|
+
*/
|
|
50
|
+
constructor(oscillators, alk, options = {}) {
|
|
51
|
+
// Handle oscillator input
|
|
52
|
+
if (oscillators instanceof OscillatorBank) {
|
|
53
|
+
this.bank = oscillators;
|
|
54
|
+
this.N = oscillators.size;
|
|
55
|
+
this.omega = new Float64Array(this.N);
|
|
56
|
+
for (let i = 0; i < this.N; i++) {
|
|
57
|
+
this.omega[i] = oscillators.oscillators[i].frequency;
|
|
58
|
+
}
|
|
59
|
+
} else if (Array.isArray(oscillators)) {
|
|
60
|
+
this.omega = Float64Array.from(oscillators);
|
|
61
|
+
this.N = oscillators.length;
|
|
62
|
+
this.bank = null;
|
|
63
|
+
} else {
|
|
64
|
+
throw new Error('oscillators must be OscillatorBank or frequency array');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Store ALK
|
|
68
|
+
this.alk = alk;
|
|
69
|
+
|
|
70
|
+
// Ensure prime count matches oscillator count
|
|
71
|
+
if (alk.r !== this.N) {
|
|
72
|
+
console.warn(`ALK has ${alk.r} primes but model has ${this.N} oscillators. Using min.`);
|
|
73
|
+
this.N = Math.min(alk.r, this.N);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Configuration
|
|
77
|
+
this.couplingScale = options.couplingScale ?? 0.1;
|
|
78
|
+
this.triadicScale = options.triadicScale ?? 0.05;
|
|
79
|
+
this.useTriadic = options.useTriadic ?? true;
|
|
80
|
+
this.useHigherOrder = options.useHigherOrder ?? false;
|
|
81
|
+
this.dt = options.dt ?? 0.01;
|
|
82
|
+
|
|
83
|
+
// State: phases
|
|
84
|
+
this.theta = new Float64Array(this.N);
|
|
85
|
+
for (let i = 0; i < this.N; i++) {
|
|
86
|
+
this.theta[i] = Math.random() * 2 * Math.PI;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Time tracking
|
|
90
|
+
this.time = 0;
|
|
91
|
+
this.steps = 0;
|
|
92
|
+
|
|
93
|
+
// Cache ALK matrices
|
|
94
|
+
this._J = null;
|
|
95
|
+
this._K3Entries = null;
|
|
96
|
+
|
|
97
|
+
// History for analysis
|
|
98
|
+
this.history = [];
|
|
99
|
+
this.maxHistory = options.maxHistory ?? 1000;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get cached J matrix (scaled)
|
|
104
|
+
*/
|
|
105
|
+
get J() {
|
|
106
|
+
if (!this._J) {
|
|
107
|
+
const rawJ = this.alk.J;
|
|
108
|
+
this._J = [];
|
|
109
|
+
for (let i = 0; i < this.N; i++) {
|
|
110
|
+
this._J[i] = new Float64Array(this.N);
|
|
111
|
+
for (let j = 0; j < this.N; j++) {
|
|
112
|
+
this._J[i][j] = this.couplingScale * rawJ[i][j];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return this._J;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get cached K³ entries (scaled)
|
|
121
|
+
*/
|
|
122
|
+
get K3Entries() {
|
|
123
|
+
if (!this._K3Entries) {
|
|
124
|
+
this._K3Entries = [];
|
|
125
|
+
const K3 = this.alk.K3;
|
|
126
|
+
for (const [, entry] of K3.entries) {
|
|
127
|
+
const [i, j, k] = entry.indices;
|
|
128
|
+
if (i < this.N && j < this.N && k < this.N) {
|
|
129
|
+
this._K3Entries.push({
|
|
130
|
+
i, j, k,
|
|
131
|
+
value: this.triadicScale * entry.value
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return this._K3Entries;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Compute pairwise coupling term for oscillator i
|
|
141
|
+
* Σⱼ Jᵢⱼ sin(θⱼ - θᵢ)
|
|
142
|
+
*
|
|
143
|
+
* @param {number} i - Oscillator index
|
|
144
|
+
* @returns {number} Pairwise coupling contribution
|
|
145
|
+
*/
|
|
146
|
+
_pairwiseCoupling(i) {
|
|
147
|
+
const J = this.J;
|
|
148
|
+
let sum = 0;
|
|
149
|
+
|
|
150
|
+
for (let j = 0; j < this.N; j++) {
|
|
151
|
+
if (i !== j && J[i][j] !== 0) {
|
|
152
|
+
sum += J[i][j] * Math.sin(this.theta[j] - this.theta[i]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return sum;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Compute triadic coupling term for oscillator i
|
|
161
|
+
* Σⱼ<ₖ K³ᵢⱼₖ sin(θⱼ + θₖ - 2θᵢ)
|
|
162
|
+
*
|
|
163
|
+
* This captures Borromean-type coherence where three oscillators
|
|
164
|
+
* lock together without pairwise locking.
|
|
165
|
+
*
|
|
166
|
+
* @param {number} i - Oscillator index
|
|
167
|
+
* @returns {number} Triadic coupling contribution
|
|
168
|
+
*/
|
|
169
|
+
_triadicCoupling(i) {
|
|
170
|
+
if (!this.useTriadic) return 0;
|
|
171
|
+
|
|
172
|
+
let sum = 0;
|
|
173
|
+
|
|
174
|
+
for (const entry of this.K3Entries) {
|
|
175
|
+
// Each entry affects all three oscillators in the triple
|
|
176
|
+
if (entry.i === i) {
|
|
177
|
+
// Oscillator i is first in triple
|
|
178
|
+
sum += entry.value * Math.sin(this.theta[entry.j] + this.theta[entry.k] - 2 * this.theta[i]);
|
|
179
|
+
} else if (entry.j === i) {
|
|
180
|
+
// Oscillator i is second
|
|
181
|
+
sum += entry.value * Math.sin(this.theta[entry.i] + this.theta[entry.k] - 2 * this.theta[i]);
|
|
182
|
+
} else if (entry.k === i) {
|
|
183
|
+
// Oscillator i is third
|
|
184
|
+
sum += entry.value * Math.sin(this.theta[entry.i] + this.theta[entry.j] - 2 * this.theta[i]);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return sum;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Compute full dθᵢ/dt
|
|
193
|
+
*
|
|
194
|
+
* @param {number} i - Oscillator index
|
|
195
|
+
* @returns {number} Phase derivative
|
|
196
|
+
*/
|
|
197
|
+
_dtheta(i) {
|
|
198
|
+
return this.omega[i] + this._pairwiseCoupling(i) + this._triadicCoupling(i);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Euler integration step
|
|
203
|
+
*
|
|
204
|
+
* @param {number} dt - Time step (uses this.dt if not provided)
|
|
205
|
+
*/
|
|
206
|
+
step(dt = this.dt) {
|
|
207
|
+
const newTheta = new Float64Array(this.N);
|
|
208
|
+
|
|
209
|
+
// Compute derivatives
|
|
210
|
+
for (let i = 0; i < this.N; i++) {
|
|
211
|
+
const dth = this._dtheta(i);
|
|
212
|
+
newTheta[i] = this.theta[i] + dth * dt;
|
|
213
|
+
// Wrap to [0, 2π)
|
|
214
|
+
newTheta[i] = ((newTheta[i] % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this.theta = newTheta;
|
|
218
|
+
this.time += dt;
|
|
219
|
+
this.steps++;
|
|
220
|
+
|
|
221
|
+
// Update oscillator bank if present
|
|
222
|
+
if (this.bank) {
|
|
223
|
+
for (let i = 0; i < this.N; i++) {
|
|
224
|
+
this.bank.oscillators[i].phase = this.theta[i];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Runge-Kutta 4 integration step (more accurate)
|
|
233
|
+
*
|
|
234
|
+
* @param {number} dt - Time step
|
|
235
|
+
*/
|
|
236
|
+
stepRK4(dt = this.dt) {
|
|
237
|
+
const k1 = new Float64Array(this.N);
|
|
238
|
+
const k2 = new Float64Array(this.N);
|
|
239
|
+
const k3 = new Float64Array(this.N);
|
|
240
|
+
const k4 = new Float64Array(this.N);
|
|
241
|
+
const temp = new Float64Array(this.N);
|
|
242
|
+
|
|
243
|
+
// k1 = f(t, y)
|
|
244
|
+
for (let i = 0; i < this.N; i++) {
|
|
245
|
+
k1[i] = this._dtheta(i);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// k2 = f(t + dt/2, y + k1*dt/2)
|
|
249
|
+
for (let i = 0; i < this.N; i++) {
|
|
250
|
+
temp[i] = this.theta[i] + k1[i] * dt / 2;
|
|
251
|
+
}
|
|
252
|
+
const savedTheta = this.theta;
|
|
253
|
+
this.theta = temp;
|
|
254
|
+
for (let i = 0; i < this.N; i++) {
|
|
255
|
+
k2[i] = this._dtheta(i);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// k3 = f(t + dt/2, y + k2*dt/2)
|
|
259
|
+
for (let i = 0; i < this.N; i++) {
|
|
260
|
+
temp[i] = savedTheta[i] + k2[i] * dt / 2;
|
|
261
|
+
}
|
|
262
|
+
this.theta = temp;
|
|
263
|
+
for (let i = 0; i < this.N; i++) {
|
|
264
|
+
k3[i] = this._dtheta(i);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// k4 = f(t + dt, y + k3*dt)
|
|
268
|
+
for (let i = 0; i < this.N; i++) {
|
|
269
|
+
temp[i] = savedTheta[i] + k3[i] * dt;
|
|
270
|
+
}
|
|
271
|
+
this.theta = temp;
|
|
272
|
+
for (let i = 0; i < this.N; i++) {
|
|
273
|
+
k4[i] = this._dtheta(i);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// y(t + dt) = y(t) + (k1 + 2*k2 + 2*k3 + k4) * dt / 6
|
|
277
|
+
for (let i = 0; i < this.N; i++) {
|
|
278
|
+
this.theta[i] = savedTheta[i] + (k1[i] + 2*k2[i] + 2*k3[i] + k4[i]) * dt / 6;
|
|
279
|
+
this.theta[i] = ((this.theta[i] % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this.time += dt;
|
|
283
|
+
this.steps++;
|
|
284
|
+
|
|
285
|
+
if (this.bank) {
|
|
286
|
+
for (let i = 0; i < this.N; i++) {
|
|
287
|
+
this.bank.oscillators[i].phase = this.theta[i];
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return this;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Evolve for multiple steps
|
|
296
|
+
*
|
|
297
|
+
* @param {number} numSteps - Number of steps
|
|
298
|
+
* @param {boolean} useRK4 - Use RK4 integration (default: false)
|
|
299
|
+
* @param {boolean} record - Record history (default: false)
|
|
300
|
+
*/
|
|
301
|
+
evolve(numSteps, useRK4 = false, record = false) {
|
|
302
|
+
const stepFn = useRK4 ? () => this.stepRK4() : () => this.step();
|
|
303
|
+
|
|
304
|
+
for (let i = 0; i < numSteps; i++) {
|
|
305
|
+
stepFn();
|
|
306
|
+
|
|
307
|
+
if (record) {
|
|
308
|
+
this._recordState();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return this;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Record current state to history
|
|
317
|
+
* @private
|
|
318
|
+
*/
|
|
319
|
+
_recordState() {
|
|
320
|
+
const state = {
|
|
321
|
+
time: this.time,
|
|
322
|
+
steps: this.steps,
|
|
323
|
+
theta: Float64Array.from(this.theta),
|
|
324
|
+
orderParameter: this.orderParameter(),
|
|
325
|
+
triadicCoherence: this.triadicCoherence()
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
this.history.push(state);
|
|
329
|
+
|
|
330
|
+
// Limit history size
|
|
331
|
+
while (this.history.length > this.maxHistory) {
|
|
332
|
+
this.history.shift();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Kuramoto order parameter r = |1/N Σⱼ e^(iθⱼ)|
|
|
338
|
+
*
|
|
339
|
+
* r = 1: Perfect synchronization
|
|
340
|
+
* r = 0: Incoherent (random phases)
|
|
341
|
+
*
|
|
342
|
+
* @returns {number} Order parameter in [0, 1]
|
|
343
|
+
*/
|
|
344
|
+
orderParameter() {
|
|
345
|
+
let realSum = 0;
|
|
346
|
+
let imagSum = 0;
|
|
347
|
+
|
|
348
|
+
for (let i = 0; i < this.N; i++) {
|
|
349
|
+
realSum += Math.cos(this.theta[i]);
|
|
350
|
+
imagSum += Math.sin(this.theta[i]);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return Math.sqrt(realSum * realSum + imagSum * imagSum) / this.N;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Mean phase Ψ = arg(Σⱼ e^(iθⱼ))
|
|
358
|
+
*
|
|
359
|
+
* @returns {number} Mean phase in [0, 2π)
|
|
360
|
+
*/
|
|
361
|
+
meanPhase() {
|
|
362
|
+
let realSum = 0;
|
|
363
|
+
let imagSum = 0;
|
|
364
|
+
|
|
365
|
+
for (let i = 0; i < this.N; i++) {
|
|
366
|
+
realSum += Math.cos(this.theta[i]);
|
|
367
|
+
imagSum += Math.sin(this.theta[i]);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const phase = Math.atan2(imagSum, realSum);
|
|
371
|
+
return ((phase % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Triadic coherence measure
|
|
376
|
+
* Measures phase coherence within Borromean triples
|
|
377
|
+
*
|
|
378
|
+
* For triple (i, j, k): coherence = |e^(i(θᵢ + θⱼ + θₖ))|
|
|
379
|
+
*
|
|
380
|
+
* @returns {number} Mean triadic coherence in [0, 1]
|
|
381
|
+
*/
|
|
382
|
+
triadicCoherence() {
|
|
383
|
+
const borromean = this.alk.findBorromeanTriples();
|
|
384
|
+
if (borromean.length === 0) return 0;
|
|
385
|
+
|
|
386
|
+
let totalCoherence = 0;
|
|
387
|
+
|
|
388
|
+
for (const triple of borromean) {
|
|
389
|
+
const [i, j, k] = triple.indices;
|
|
390
|
+
if (i >= this.N || j >= this.N || k >= this.N) continue;
|
|
391
|
+
|
|
392
|
+
const sumPhase = this.theta[i] + this.theta[j] + this.theta[k];
|
|
393
|
+
// Triadic coherence: how close is sum to 0 mod 2π?
|
|
394
|
+
const coherence = Math.cos(sumPhase);
|
|
395
|
+
totalCoherence += Math.abs(coherence);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return totalCoherence / borromean.length;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Phase variance (measure of incoherence)
|
|
403
|
+
*
|
|
404
|
+
* @returns {number} Circular variance in [0, 1]
|
|
405
|
+
*/
|
|
406
|
+
phaseVariance() {
|
|
407
|
+
return 1 - this.orderParameter();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Pairwise phase locking detection
|
|
412
|
+
* Returns pairs (i, j) where |θᵢ - θⱼ| < threshold
|
|
413
|
+
*
|
|
414
|
+
* @param {number} threshold - Phase difference threshold (default: π/6)
|
|
415
|
+
* @returns {Array} Locked pairs [{i, j, phaseDiff}]
|
|
416
|
+
*/
|
|
417
|
+
findLockedPairs(threshold = Math.PI / 6) {
|
|
418
|
+
const locked = [];
|
|
419
|
+
|
|
420
|
+
for (let i = 0; i < this.N; i++) {
|
|
421
|
+
for (let j = i + 1; j < this.N; j++) {
|
|
422
|
+
let diff = Math.abs(this.theta[i] - this.theta[j]);
|
|
423
|
+
diff = Math.min(diff, 2 * Math.PI - diff);
|
|
424
|
+
|
|
425
|
+
if (diff < threshold) {
|
|
426
|
+
locked.push({
|
|
427
|
+
i, j,
|
|
428
|
+
primes: [this.alk.primes[i], this.alk.primes[j]],
|
|
429
|
+
phaseDiff: diff,
|
|
430
|
+
coupling: this.J[i][j]
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return locked;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Find locked triads (three oscillators with mutual phase coherence)
|
|
441
|
+
*
|
|
442
|
+
* @param {number} threshold - Phase threshold
|
|
443
|
+
* @returns {Array} Locked triads
|
|
444
|
+
*/
|
|
445
|
+
findLockedTriads(threshold = Math.PI / 4) {
|
|
446
|
+
const locked = [];
|
|
447
|
+
|
|
448
|
+
for (const entry of this.K3Entries) {
|
|
449
|
+
const { i, j, k } = entry;
|
|
450
|
+
if (i >= this.N || j >= this.N || k >= this.N) continue;
|
|
451
|
+
|
|
452
|
+
const sumPhase = this.theta[i] + this.theta[j] + this.theta[k];
|
|
453
|
+
const coherence = Math.abs(Math.cos(sumPhase));
|
|
454
|
+
|
|
455
|
+
if (coherence > Math.cos(threshold)) {
|
|
456
|
+
locked.push({
|
|
457
|
+
indices: [i, j, k],
|
|
458
|
+
primes: [this.alk.primes[i], this.alk.primes[j], this.alk.primes[k]],
|
|
459
|
+
sumPhase,
|
|
460
|
+
coherence,
|
|
461
|
+
coupling: entry.value
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return locked;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Get current state as object
|
|
471
|
+
*/
|
|
472
|
+
getState() {
|
|
473
|
+
return {
|
|
474
|
+
time: this.time,
|
|
475
|
+
steps: this.steps,
|
|
476
|
+
N: this.N,
|
|
477
|
+
theta: Array.from(this.theta),
|
|
478
|
+
omega: Array.from(this.omega),
|
|
479
|
+
orderParameter: this.orderParameter(),
|
|
480
|
+
meanPhase: this.meanPhase(),
|
|
481
|
+
triadicCoherence: this.triadicCoherence(),
|
|
482
|
+
lockedPairs: this.findLockedPairs(),
|
|
483
|
+
lockedTriads: this.findLockedTriads()
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Set phases directly
|
|
489
|
+
*
|
|
490
|
+
* @param {number[]} phases - Array of phases
|
|
491
|
+
*/
|
|
492
|
+
setPhases(phases) {
|
|
493
|
+
for (let i = 0; i < Math.min(phases.length, this.N); i++) {
|
|
494
|
+
this.theta[i] = phases[i];
|
|
495
|
+
}
|
|
496
|
+
return this;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Reset to random phases
|
|
501
|
+
*/
|
|
502
|
+
reset() {
|
|
503
|
+
for (let i = 0; i < this.N; i++) {
|
|
504
|
+
this.theta[i] = Math.random() * 2 * Math.PI;
|
|
505
|
+
}
|
|
506
|
+
this.time = 0;
|
|
507
|
+
this.steps = 0;
|
|
508
|
+
this.history = [];
|
|
509
|
+
return this;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Clone the model
|
|
514
|
+
*/
|
|
515
|
+
clone() {
|
|
516
|
+
const clone = new ALKKuramotoModel(Array.from(this.omega), this.alk, {
|
|
517
|
+
couplingScale: this.couplingScale,
|
|
518
|
+
triadicScale: this.triadicScale,
|
|
519
|
+
useTriadic: this.useTriadic,
|
|
520
|
+
useHigherOrder: this.useHigherOrder,
|
|
521
|
+
dt: this.dt
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
clone.theta = Float64Array.from(this.theta);
|
|
525
|
+
clone.time = this.time;
|
|
526
|
+
clone.steps = this.steps;
|
|
527
|
+
|
|
528
|
+
return clone;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ============================================================================
|
|
533
|
+
// ALK NETWORK KURAMOTO
|
|
534
|
+
// ============================================================================
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* ALK Network Kuramoto
|
|
538
|
+
*
|
|
539
|
+
* Uses ALK's J matrix as the adjacency/coupling matrix for
|
|
540
|
+
* network-topology aware Kuramoto dynamics.
|
|
541
|
+
*/
|
|
542
|
+
class ALKNetworkKuramoto extends ALKKuramotoModel {
|
|
543
|
+
/**
|
|
544
|
+
* Create ALK Network Kuramoto model
|
|
545
|
+
*
|
|
546
|
+
* @param {number[]} frequencies - Natural frequencies
|
|
547
|
+
* @param {Object} alk - ArithmeticLinkKernel
|
|
548
|
+
* @param {Object} options - Configuration
|
|
549
|
+
*/
|
|
550
|
+
constructor(frequencies, alk, options = {}) {
|
|
551
|
+
super(frequencies, alk, options);
|
|
552
|
+
|
|
553
|
+
// Use symmetrized coupling for undirected network
|
|
554
|
+
this.useSymmetric = options.useSymmetric ?? true;
|
|
555
|
+
|
|
556
|
+
// Compute effective coupling matrix
|
|
557
|
+
this._effectiveJ = null;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Get effective coupling matrix
|
|
562
|
+
*/
|
|
563
|
+
get effectiveJ() {
|
|
564
|
+
if (!this._effectiveJ) {
|
|
565
|
+
if (this.useSymmetric) {
|
|
566
|
+
// Use (J + J^T) / 2
|
|
567
|
+
const Jsym = this.alk.Jsym;
|
|
568
|
+
this._effectiveJ = [];
|
|
569
|
+
for (let i = 0; i < this.N; i++) {
|
|
570
|
+
this._effectiveJ[i] = new Float64Array(this.N);
|
|
571
|
+
for (let j = 0; j < this.N; j++) {
|
|
572
|
+
this._effectiveJ[i][j] = this.couplingScale * Jsym[i][j];
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
} else {
|
|
576
|
+
this._effectiveJ = this.J;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return this._effectiveJ;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Override pairwise coupling to use effective J
|
|
584
|
+
*/
|
|
585
|
+
_pairwiseCoupling(i) {
|
|
586
|
+
const J = this.effectiveJ;
|
|
587
|
+
let sum = 0;
|
|
588
|
+
|
|
589
|
+
for (let j = 0; j < this.N; j++) {
|
|
590
|
+
if (i !== j && J[i][j] !== 0) {
|
|
591
|
+
sum += J[i][j] * Math.sin(this.theta[j] - this.theta[i]);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return sum;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Compute clustering coefficient based on ALK couplings
|
|
600
|
+
*
|
|
601
|
+
* @returns {number} Mean clustering coefficient
|
|
602
|
+
*/
|
|
603
|
+
clusteringCoefficient() {
|
|
604
|
+
const J = this.effectiveJ;
|
|
605
|
+
let totalCC = 0;
|
|
606
|
+
let validNodes = 0;
|
|
607
|
+
|
|
608
|
+
for (let i = 0; i < this.N; i++) {
|
|
609
|
+
// Find neighbors (non-zero coupling)
|
|
610
|
+
const neighbors = [];
|
|
611
|
+
for (let j = 0; j < this.N; j++) {
|
|
612
|
+
if (i !== j && Math.abs(J[i][j]) > 1e-10) {
|
|
613
|
+
neighbors.push(j);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const k = neighbors.length;
|
|
618
|
+
if (k < 2) continue;
|
|
619
|
+
|
|
620
|
+
// Count edges between neighbors
|
|
621
|
+
let triangles = 0;
|
|
622
|
+
for (let a = 0; a < k; a++) {
|
|
623
|
+
for (let b = a + 1; b < k; b++) {
|
|
624
|
+
if (Math.abs(J[neighbors[a]][neighbors[b]]) > 1e-10) {
|
|
625
|
+
triangles++;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const maxTriangles = k * (k - 1) / 2;
|
|
631
|
+
totalCC += triangles / maxTriangles;
|
|
632
|
+
validNodes++;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return validNodes > 0 ? totalCC / validNodes : 0;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Compute small-world coefficient
|
|
640
|
+
* σ = (C/C_random) / (L/L_random)
|
|
641
|
+
*
|
|
642
|
+
* @returns {number} Small-world coefficient (σ > 1 indicates small-world)
|
|
643
|
+
*/
|
|
644
|
+
smallWorldCoefficient() {
|
|
645
|
+
const C = this.clusteringCoefficient();
|
|
646
|
+
const r = this.orderParameter();
|
|
647
|
+
|
|
648
|
+
// Estimate random network values
|
|
649
|
+
const density = this._computeDensity();
|
|
650
|
+
const C_random = density; // Expected for random network
|
|
651
|
+
const L_random = Math.log(this.N); // Approximate for sparse random
|
|
652
|
+
|
|
653
|
+
// Use order parameter as proxy for path length
|
|
654
|
+
// Higher sync → shorter effective path
|
|
655
|
+
const L = 1 / (r + 0.1);
|
|
656
|
+
|
|
657
|
+
if (C_random < 1e-10 || L_random < 1e-10) return 1;
|
|
658
|
+
|
|
659
|
+
return (C / C_random) / (L / L_random);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Compute network density
|
|
664
|
+
* @private
|
|
665
|
+
*/
|
|
666
|
+
_computeDensity() {
|
|
667
|
+
const J = this.effectiveJ;
|
|
668
|
+
let edges = 0;
|
|
669
|
+
|
|
670
|
+
for (let i = 0; i < this.N; i++) {
|
|
671
|
+
for (let j = i + 1; j < this.N; j++) {
|
|
672
|
+
if (Math.abs(J[i][j]) > 1e-10) {
|
|
673
|
+
edges++;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const maxEdges = this.N * (this.N - 1) / 2;
|
|
679
|
+
return edges / maxEdges;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// ============================================================================
|
|
684
|
+
// FACTORY FUNCTIONS
|
|
685
|
+
// ============================================================================
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Create ALK-Kuramoto model from prime set
|
|
689
|
+
*
|
|
690
|
+
* @param {number[]} primes - Array of primes
|
|
691
|
+
* @param {Object} options - Configuration
|
|
692
|
+
* @returns {ALKKuramotoModel} Model instance
|
|
693
|
+
*/
|
|
694
|
+
function createALKKuramoto(primes, options = {}) {
|
|
695
|
+
const alk = new ArithmeticLinkKernel(primes, {
|
|
696
|
+
encoding: options.encoding || 'bipolar'
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
// Generate natural frequencies from primes
|
|
700
|
+
const omega = primes.map(p => Math.log(p));
|
|
701
|
+
|
|
702
|
+
return new ALKKuramotoModel(omega, alk, options);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Create ALK Network Kuramoto from prime set
|
|
707
|
+
*
|
|
708
|
+
* @param {number[]} primes - Array of primes
|
|
709
|
+
* @param {Object} options - Configuration
|
|
710
|
+
* @returns {ALKNetworkKuramoto} Model instance
|
|
711
|
+
*/
|
|
712
|
+
function createALKNetworkKuramoto(primes, options = {}) {
|
|
713
|
+
const alk = new ArithmeticLinkKernel(primes, {
|
|
714
|
+
encoding: options.encoding || 'bipolar'
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
const omega = primes.map(p => Math.log(p));
|
|
718
|
+
|
|
719
|
+
return new ALKNetworkKuramoto(omega, alk, options);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Run Borromean synchronization experiment
|
|
724
|
+
*
|
|
725
|
+
* Investigates how Borromean triples synchronize differently
|
|
726
|
+
* from pairwise-coupled oscillators.
|
|
727
|
+
*
|
|
728
|
+
* @param {number[]} primes - Array of primes
|
|
729
|
+
* @param {Object} options - Experiment options
|
|
730
|
+
* @returns {Object} Experiment results
|
|
731
|
+
*/
|
|
732
|
+
function runBorromeanExperiment(primes, options = {}) {
|
|
733
|
+
const alk = new ArithmeticLinkKernel(primes);
|
|
734
|
+
const borromean = alk.findBorromeanTriples();
|
|
735
|
+
|
|
736
|
+
const steps = options.steps || 1000;
|
|
737
|
+
const dt = options.dt || 0.01;
|
|
738
|
+
|
|
739
|
+
// Create model with triadic coupling
|
|
740
|
+
const modelTriadic = new ALKKuramotoModel(
|
|
741
|
+
primes.map(p => Math.log(p)),
|
|
742
|
+
alk,
|
|
743
|
+
{ useTriadic: true, dt }
|
|
744
|
+
);
|
|
745
|
+
|
|
746
|
+
// Create model without triadic coupling
|
|
747
|
+
const modelPairwise = new ALKKuramotoModel(
|
|
748
|
+
primes.map(p => Math.log(p)),
|
|
749
|
+
alk,
|
|
750
|
+
{ useTriadic: false, dt }
|
|
751
|
+
);
|
|
752
|
+
|
|
753
|
+
// Same initial conditions
|
|
754
|
+
const initialPhases = primes.map(() => Math.random() * 2 * Math.PI);
|
|
755
|
+
modelTriadic.setPhases(initialPhases);
|
|
756
|
+
modelPairwise.setPhases(initialPhases);
|
|
757
|
+
|
|
758
|
+
// Evolve both
|
|
759
|
+
const triadicHistory = [];
|
|
760
|
+
const pairwiseHistory = [];
|
|
761
|
+
|
|
762
|
+
for (let i = 0; i < steps; i++) {
|
|
763
|
+
modelTriadic.step();
|
|
764
|
+
modelPairwise.step();
|
|
765
|
+
|
|
766
|
+
if (i % 10 === 0) {
|
|
767
|
+
triadicHistory.push({
|
|
768
|
+
time: modelTriadic.time,
|
|
769
|
+
r: modelTriadic.orderParameter(),
|
|
770
|
+
triadic: modelTriadic.triadicCoherence()
|
|
771
|
+
});
|
|
772
|
+
pairwiseHistory.push({
|
|
773
|
+
time: modelPairwise.time,
|
|
774
|
+
r: modelPairwise.orderParameter(),
|
|
775
|
+
triadic: modelPairwise.triadicCoherence()
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return {
|
|
781
|
+
borromeanTriples: borromean,
|
|
782
|
+
triadicModel: {
|
|
783
|
+
finalR: modelTriadic.orderParameter(),
|
|
784
|
+
finalTriadic: modelTriadic.triadicCoherence(),
|
|
785
|
+
history: triadicHistory
|
|
786
|
+
},
|
|
787
|
+
pairwiseModel: {
|
|
788
|
+
finalR: modelPairwise.orderParameter(),
|
|
789
|
+
finalTriadic: modelPairwise.triadicCoherence(),
|
|
790
|
+
history: pairwiseHistory
|
|
791
|
+
},
|
|
792
|
+
comparison: {
|
|
793
|
+
rDifference: modelTriadic.orderParameter() - modelPairwise.orderParameter(),
|
|
794
|
+
triadicDifference: modelTriadic.triadicCoherence() - modelPairwise.triadicCoherence()
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// ============================================================================
|
|
800
|
+
// EXPORTS
|
|
801
|
+
// ============================================================================
|
|
802
|
+
|
|
803
|
+
export {
|
|
804
|
+
ALKKuramotoModel,
|
|
805
|
+
ALKNetworkKuramoto,
|
|
806
|
+
createALKKuramoto,
|
|
807
|
+
createALKNetworkKuramoto,
|
|
808
|
+
runBorromeanExperiment
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
export default {
|
|
812
|
+
ALKKuramotoModel,
|
|
813
|
+
ALKNetworkKuramoto,
|
|
814
|
+
createALKKuramoto,
|
|
815
|
+
createALKNetworkKuramoto,
|
|
816
|
+
runBorromeanExperiment
|
|
817
|
+
};
|