@aleph-ai/tinyaleph 1.1.0 → 1.2.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/README.md +230 -2
- package/core/entanglement.js +712 -0
- package/core/events.js +907 -0
- package/core/hypercomplex.js +500 -0
- package/core/index.js +46 -0
- package/core/rformer-layers.js +811 -0
- package/docs/reference/01-core.md +515 -1
- package/docs/reference/02-physics.md +186 -1
- package/package.json +1 -1
- package/physics/index.js +62 -0
- package/physics/kuramoto-coupled-ladder.js +603 -0
- package/physics/primeon_z_ladder_multi.js +669 -0
- package/physics/primeon_z_ladder_u.js +493 -0
- package/physics/stochastic-kuramoto.js +566 -0
package/physics/index.js
CHANGED
|
@@ -42,6 +42,41 @@ const {
|
|
|
42
42
|
createPeerCoupling
|
|
43
43
|
} = require('./sync-models');
|
|
44
44
|
|
|
45
|
+
// Stochastic Kuramoto models
|
|
46
|
+
const {
|
|
47
|
+
StochasticKuramoto,
|
|
48
|
+
ColoredNoiseKuramoto,
|
|
49
|
+
ThermalKuramoto,
|
|
50
|
+
gaussianRandom
|
|
51
|
+
} = require('./stochastic-kuramoto');
|
|
52
|
+
|
|
53
|
+
// Primeon Z-Ladder with canonical U evolution
|
|
54
|
+
const {
|
|
55
|
+
PrimeonZLadderU,
|
|
56
|
+
createPrimeonLadder,
|
|
57
|
+
shannonEntropyNats,
|
|
58
|
+
probsOf,
|
|
59
|
+
normalize: normalizeComplex,
|
|
60
|
+
C: Complex
|
|
61
|
+
} = require('./primeon_z_ladder_u');
|
|
62
|
+
|
|
63
|
+
// Multi-channel Primeon Z-Ladder
|
|
64
|
+
const {
|
|
65
|
+
ZChannel,
|
|
66
|
+
PrimeonZLadderMulti,
|
|
67
|
+
createMultiChannelLadder,
|
|
68
|
+
createAdiabaticSchedule
|
|
69
|
+
} = require('./primeon_z_ladder_multi');
|
|
70
|
+
|
|
71
|
+
// Kuramoto-coupled ladder (hybrid quantum + oscillator dynamics)
|
|
72
|
+
const {
|
|
73
|
+
KuramotoCoupledLadder,
|
|
74
|
+
createKuramotoLadder,
|
|
75
|
+
runCollapsePressureExperiment,
|
|
76
|
+
kuramotoOrderParameter,
|
|
77
|
+
getPhase
|
|
78
|
+
} = require('./kuramoto-coupled-ladder');
|
|
79
|
+
|
|
45
80
|
module.exports = {
|
|
46
81
|
// Oscillators
|
|
47
82
|
Oscillator,
|
|
@@ -57,6 +92,33 @@ module.exports = {
|
|
|
57
92
|
createHierarchicalCoupling,
|
|
58
93
|
createPeerCoupling,
|
|
59
94
|
|
|
95
|
+
// Stochastic Kuramoto models
|
|
96
|
+
StochasticKuramoto,
|
|
97
|
+
ColoredNoiseKuramoto,
|
|
98
|
+
ThermalKuramoto,
|
|
99
|
+
gaussianRandom,
|
|
100
|
+
|
|
101
|
+
// Primeon Z-Ladder (canonical U evolution)
|
|
102
|
+
PrimeonZLadderU,
|
|
103
|
+
createPrimeonLadder,
|
|
104
|
+
shannonEntropyNats,
|
|
105
|
+
probsOf,
|
|
106
|
+
normalizeComplex,
|
|
107
|
+
Complex,
|
|
108
|
+
|
|
109
|
+
// Multi-channel Primeon Z-Ladder
|
|
110
|
+
ZChannel,
|
|
111
|
+
PrimeonZLadderMulti,
|
|
112
|
+
createMultiChannelLadder,
|
|
113
|
+
createAdiabaticSchedule,
|
|
114
|
+
|
|
115
|
+
// Kuramoto-coupled ladder (hybrid model)
|
|
116
|
+
KuramotoCoupledLadder,
|
|
117
|
+
createKuramotoLadder,
|
|
118
|
+
runCollapsePressureExperiment,
|
|
119
|
+
kuramotoOrderParameter,
|
|
120
|
+
getPhase,
|
|
121
|
+
|
|
60
122
|
// Entropy & Information
|
|
61
123
|
shannonEntropy,
|
|
62
124
|
stateEntropy,
|
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kuramoto-Coupled Primeon Z-Ladder
|
|
3
|
+
*
|
|
4
|
+
* Hybrid model combining:
|
|
5
|
+
* - Quantum ladder hopping dynamics
|
|
6
|
+
* - Kuramoto oscillator synchronization on rung phases
|
|
7
|
+
* - Z-flux interpreted as "collapse pressure"
|
|
8
|
+
*
|
|
9
|
+
* Physics interpretation:
|
|
10
|
+
* - Each rung ψ_n = |ψ_n| e^(iθ_n) has phase θ_n acting as oscillator
|
|
11
|
+
* - Kuramoto coupling promotes phase coherence between rungs
|
|
12
|
+
* - Z-flux accumulation represents decoherence/collapse pressure
|
|
13
|
+
* - When collapse pressure exceeds threshold, measurement triggers
|
|
14
|
+
*
|
|
15
|
+
* Key concepts:
|
|
16
|
+
* - Order parameter r = |⟨e^(iθ)⟩| measures global synchronization
|
|
17
|
+
* - High sync (r→1) = quantum coherence preserved
|
|
18
|
+
* - Low sync (r→0) = decoherence, collapse pressure builds
|
|
19
|
+
* - Collapse events reduce uncertainty but reset sync
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
PrimeonZLadderMulti,
|
|
26
|
+
ZChannel,
|
|
27
|
+
createMultiChannelLadder,
|
|
28
|
+
createAdiabaticSchedule
|
|
29
|
+
} = require('./primeon_z_ladder_multi');
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
C,
|
|
33
|
+
shannonEntropyNats,
|
|
34
|
+
probsOf,
|
|
35
|
+
normalize
|
|
36
|
+
} = require('./primeon_z_ladder_u');
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Extract phase from complex number
|
|
40
|
+
* @param {C} z - Complex number
|
|
41
|
+
* @returns {number} Phase in radians
|
|
42
|
+
*/
|
|
43
|
+
function getPhase(z) {
|
|
44
|
+
return Math.atan2(z.im, z.re);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Compute Kuramoto order parameter from phases
|
|
49
|
+
* @param {number[]} phases - Array of phases
|
|
50
|
+
* @returns {{r: number, psi: number}} Order parameter magnitude and mean phase
|
|
51
|
+
*/
|
|
52
|
+
function kuramotoOrderParameter(phases) {
|
|
53
|
+
if (phases.length === 0) return { r: 0, psi: 0 };
|
|
54
|
+
|
|
55
|
+
let sumCos = 0, sumSin = 0;
|
|
56
|
+
for (const theta of phases) {
|
|
57
|
+
sumCos += Math.cos(theta);
|
|
58
|
+
sumSin += Math.sin(theta);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const r = Math.sqrt(sumCos * sumCos + sumSin * sumSin) / phases.length;
|
|
62
|
+
const psi = Math.atan2(sumSin, sumCos);
|
|
63
|
+
|
|
64
|
+
return { r, psi };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* KuramotoCoupledLadder - Hybrid quantum ladder with Kuramoto synchronization
|
|
69
|
+
*
|
|
70
|
+
* @extends PrimeonZLadderMulti
|
|
71
|
+
*/
|
|
72
|
+
class KuramotoCoupledLadder extends PrimeonZLadderMulti {
|
|
73
|
+
/**
|
|
74
|
+
* @param {object} opts
|
|
75
|
+
* @param {number} opts.N - Number of rungs
|
|
76
|
+
* @param {number} [opts.J=0.25] - Quantum hopping strength
|
|
77
|
+
* @param {number} [opts.K=0.1] - Kuramoto coupling strength
|
|
78
|
+
* @param {number[]} [opts.frequencies=null] - Natural frequencies per rung
|
|
79
|
+
* @param {number} [opts.collapseThreshold=1.0] - Collapse pressure threshold
|
|
80
|
+
* @param {number} [opts.collapseDecay=0.1] - Pressure decay rate
|
|
81
|
+
* @param {boolean} [opts.autoCollapse=false] - Auto-trigger collapse
|
|
82
|
+
* @param {object[]} [opts.zChannels] - Z channel configurations
|
|
83
|
+
*/
|
|
84
|
+
constructor(opts) {
|
|
85
|
+
super(opts);
|
|
86
|
+
|
|
87
|
+
// Kuramoto parameters
|
|
88
|
+
this.K = opts.K ?? 0.1;
|
|
89
|
+
|
|
90
|
+
// Natural frequencies (default: prime-based)
|
|
91
|
+
if (opts.frequencies) {
|
|
92
|
+
this.frequencies = opts.frequencies.slice(0, this.N);
|
|
93
|
+
while (this.frequencies.length < this.N) {
|
|
94
|
+
this.frequencies.push(1.0);
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
// Prime-based frequencies
|
|
98
|
+
this.frequencies = this._generatePrimeFrequencies();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Collapse pressure dynamics
|
|
102
|
+
this.collapsePressure = 0;
|
|
103
|
+
this.collapseThreshold = opts.collapseThreshold ?? 1.0;
|
|
104
|
+
this.collapseDecay = opts.collapseDecay ?? 0.1;
|
|
105
|
+
this.autoCollapse = opts.autoCollapse ?? false;
|
|
106
|
+
|
|
107
|
+
// Tracking
|
|
108
|
+
this.collapseEvents = [];
|
|
109
|
+
this.orderParameterHistory = [];
|
|
110
|
+
this.maxHistoryLength = opts.maxHistory ?? 1000;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Generate prime-based natural frequencies
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
_generatePrimeFrequencies() {
|
|
118
|
+
const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47];
|
|
119
|
+
const frequencies = [];
|
|
120
|
+
|
|
121
|
+
for (let n = 0; n < this.N; n++) {
|
|
122
|
+
// Use log of prime for smoother distribution
|
|
123
|
+
const primeIdx = n % primes.length;
|
|
124
|
+
frequencies.push(Math.log(primes[primeIdx]) / Math.log(2));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return frequencies;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get phases of all rungs
|
|
132
|
+
*/
|
|
133
|
+
getRungPhases() {
|
|
134
|
+
const phases = [];
|
|
135
|
+
|
|
136
|
+
for (let n = 0; n < this.N; n++) {
|
|
137
|
+
// Use dominant component within rung
|
|
138
|
+
let maxAmp = 0;
|
|
139
|
+
let phase = 0;
|
|
140
|
+
|
|
141
|
+
for (let k = 0; k < this.d; k++) {
|
|
142
|
+
const i = n * this.d + k;
|
|
143
|
+
const amp = C.abs2(this.psi[i]);
|
|
144
|
+
if (amp > maxAmp) {
|
|
145
|
+
maxAmp = amp;
|
|
146
|
+
phase = getPhase(this.psi[i]);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
phases.push(phase);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return phases;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Get amplitudes of all rungs
|
|
158
|
+
*/
|
|
159
|
+
getRungAmplitudes() {
|
|
160
|
+
const amplitudes = [];
|
|
161
|
+
|
|
162
|
+
for (let n = 0; n < this.N; n++) {
|
|
163
|
+
let amp2 = 0;
|
|
164
|
+
for (let k = 0; k < this.d; k++) {
|
|
165
|
+
const i = n * this.d + k;
|
|
166
|
+
amp2 += C.abs2(this.psi[i]);
|
|
167
|
+
}
|
|
168
|
+
amplitudes.push(Math.sqrt(amp2));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return amplitudes;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Compute current order parameter
|
|
176
|
+
*/
|
|
177
|
+
orderParameter() {
|
|
178
|
+
const phases = this.getRungPhases();
|
|
179
|
+
const amplitudes = this.getRungAmplitudes();
|
|
180
|
+
|
|
181
|
+
// Weight by amplitude (weighted order parameter)
|
|
182
|
+
let sumCos = 0, sumSin = 0, totalWeight = 0;
|
|
183
|
+
|
|
184
|
+
for (let n = 0; n < this.N; n++) {
|
|
185
|
+
const weight = amplitudes[n];
|
|
186
|
+
sumCos += weight * Math.cos(phases[n]);
|
|
187
|
+
sumSin += weight * Math.sin(phases[n]);
|
|
188
|
+
totalWeight += weight;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (totalWeight === 0) return { r: 0, psi: 0, weighted: true };
|
|
192
|
+
|
|
193
|
+
const r = Math.sqrt(sumCos * sumCos + sumSin * sumSin) / totalWeight;
|
|
194
|
+
const psi = Math.atan2(sumSin, sumCos);
|
|
195
|
+
|
|
196
|
+
return { r, psi, weighted: true };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* One time step with Kuramoto phase coupling
|
|
201
|
+
* @param {number} [dt=0.01] - Time step size
|
|
202
|
+
*/
|
|
203
|
+
step(dt = 0.01) {
|
|
204
|
+
// --- 1) Kuramoto phase dynamics ---
|
|
205
|
+
this._applyKuramotoCoupling(dt);
|
|
206
|
+
|
|
207
|
+
// --- 2) Standard ladder dynamics (hopping + Z-flux) ---
|
|
208
|
+
const parentMetrics = super.step(dt);
|
|
209
|
+
|
|
210
|
+
// --- 3) Update collapse pressure from Z-flux ---
|
|
211
|
+
this._updateCollapsePressure(dt);
|
|
212
|
+
|
|
213
|
+
// --- 4) Check for auto-collapse ---
|
|
214
|
+
if (this.autoCollapse && this.collapsePressure >= this.collapseThreshold) {
|
|
215
|
+
this._triggerCollapse();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// --- 5) Track order parameter ---
|
|
219
|
+
const orderParam = this.orderParameter();
|
|
220
|
+
this.orderParameterHistory.push({
|
|
221
|
+
t: this.t,
|
|
222
|
+
r: orderParam.r,
|
|
223
|
+
psi: orderParam.psi
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (this.orderParameterHistory.length > this.maxHistoryLength) {
|
|
227
|
+
this.orderParameterHistory.shift();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return this.metrics();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Apply Kuramoto phase coupling to ladder
|
|
235
|
+
* @private
|
|
236
|
+
*/
|
|
237
|
+
_applyKuramotoCoupling(dt) {
|
|
238
|
+
const N = this.N;
|
|
239
|
+
const phases = this.getRungPhases();
|
|
240
|
+
const amplitudes = this.getRungAmplitudes();
|
|
241
|
+
|
|
242
|
+
// Compute phase increments
|
|
243
|
+
const deltaPhase = new Array(N).fill(0);
|
|
244
|
+
|
|
245
|
+
for (let n = 0; n < N; n++) {
|
|
246
|
+
// Natural frequency evolution
|
|
247
|
+
deltaPhase[n] += this.frequencies[n] * dt;
|
|
248
|
+
|
|
249
|
+
// Kuramoto coupling
|
|
250
|
+
let coupling = 0;
|
|
251
|
+
for (let m = 0; m < N; m++) {
|
|
252
|
+
if (m !== n) {
|
|
253
|
+
// Weight coupling by amplitude product
|
|
254
|
+
const weight = amplitudes[n] * amplitudes[m];
|
|
255
|
+
coupling += weight * Math.sin(phases[m] - phases[n]);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
deltaPhase[n] += (this.K / N) * coupling * dt;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Apply phase increments
|
|
263
|
+
for (let n = 0; n < N; n++) {
|
|
264
|
+
for (let k = 0; k < this.d; k++) {
|
|
265
|
+
const i = n * this.d + k;
|
|
266
|
+
const amp = Math.sqrt(C.abs2(this.psi[i]));
|
|
267
|
+
const currentPhase = getPhase(this.psi[i]);
|
|
268
|
+
const newPhase = currentPhase + deltaPhase[n];
|
|
269
|
+
|
|
270
|
+
// Update with new phase, preserving amplitude
|
|
271
|
+
this.psi[i] = new C(
|
|
272
|
+
amp * Math.cos(newPhase),
|
|
273
|
+
amp * Math.sin(newPhase)
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Update collapse pressure from Z-flux
|
|
281
|
+
* @private
|
|
282
|
+
*/
|
|
283
|
+
_updateCollapsePressure(dt) {
|
|
284
|
+
// Sum recent Z-flux from all channels
|
|
285
|
+
let totalFlux = 0;
|
|
286
|
+
for (const channel of this.channels.values()) {
|
|
287
|
+
totalFlux += channel.lastFlux;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Flux increases pressure, with decay
|
|
291
|
+
this.collapsePressure += totalFlux;
|
|
292
|
+
this.collapsePressure *= (1 - this.collapseDecay * dt);
|
|
293
|
+
|
|
294
|
+
// Clamp to non-negative
|
|
295
|
+
this.collapsePressure = Math.max(0, this.collapsePressure);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Trigger a collapse event
|
|
300
|
+
* @private
|
|
301
|
+
*/
|
|
302
|
+
_triggerCollapse() {
|
|
303
|
+
const preBefore = this.rungProbabilities();
|
|
304
|
+
const orderBefore = this.orderParameter();
|
|
305
|
+
|
|
306
|
+
// Perform measurement
|
|
307
|
+
const result = this.measure();
|
|
308
|
+
|
|
309
|
+
// Record event
|
|
310
|
+
this.collapseEvents.push({
|
|
311
|
+
t: this.t,
|
|
312
|
+
step: this.stepCount,
|
|
313
|
+
pressure: this.collapsePressure,
|
|
314
|
+
orderBefore: orderBefore.r,
|
|
315
|
+
outcome: result.outcome,
|
|
316
|
+
probability: result.probability
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Reset collapse pressure after collapse
|
|
320
|
+
this.collapsePressure = 0;
|
|
321
|
+
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Manually trigger collapse
|
|
327
|
+
*/
|
|
328
|
+
triggerCollapse() {
|
|
329
|
+
return this._triggerCollapse();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Get synchronization metrics
|
|
334
|
+
*/
|
|
335
|
+
syncMetrics() {
|
|
336
|
+
const orderParam = this.orderParameter();
|
|
337
|
+
const phases = this.getRungPhases();
|
|
338
|
+
const amplitudes = this.getRungAmplitudes();
|
|
339
|
+
|
|
340
|
+
// Compute phase variance
|
|
341
|
+
let phaseVariance = 0;
|
|
342
|
+
const meanPhase = orderParam.psi;
|
|
343
|
+
|
|
344
|
+
for (let n = 0; n < this.N; n++) {
|
|
345
|
+
let diff = phases[n] - meanPhase;
|
|
346
|
+
// Wrap to [-π, π]
|
|
347
|
+
while (diff > Math.PI) diff -= 2 * Math.PI;
|
|
348
|
+
while (diff < -Math.PI) diff += 2 * Math.PI;
|
|
349
|
+
phaseVariance += diff * diff * amplitudes[n];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const totalAmp = amplitudes.reduce((a, b) => a + b, 0);
|
|
353
|
+
phaseVariance = totalAmp > 0 ? phaseVariance / totalAmp : 0;
|
|
354
|
+
|
|
355
|
+
// Estimate critical coupling
|
|
356
|
+
const freqSpread = Math.max(...this.frequencies) - Math.min(...this.frequencies);
|
|
357
|
+
const criticalK = freqSpread * 2 / Math.PI;
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
orderParameter: orderParam.r,
|
|
361
|
+
meanPhase: orderParam.psi,
|
|
362
|
+
phaseVariance,
|
|
363
|
+
phaseStdDev: Math.sqrt(phaseVariance),
|
|
364
|
+
synchronization: orderParam.r,
|
|
365
|
+
criticalCoupling: criticalK,
|
|
366
|
+
supercritical: this.K > criticalK,
|
|
367
|
+
collapsePressure: this.collapsePressure,
|
|
368
|
+
pressureRatio: this.collapsePressure / this.collapseThreshold
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get collapse pressure dynamics
|
|
374
|
+
*/
|
|
375
|
+
collapseDynamics() {
|
|
376
|
+
return {
|
|
377
|
+
pressure: this.collapsePressure,
|
|
378
|
+
threshold: this.collapseThreshold,
|
|
379
|
+
ratio: this.collapsePressure / this.collapseThreshold,
|
|
380
|
+
willCollapse: this.collapsePressure >= this.collapseThreshold,
|
|
381
|
+
events: this.collapseEvents.slice(-10),
|
|
382
|
+
totalCollapses: this.collapseEvents.length
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Combined metrics
|
|
388
|
+
*/
|
|
389
|
+
metrics() {
|
|
390
|
+
const base = super.metrics();
|
|
391
|
+
const sync = this.syncMetrics();
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
...base,
|
|
395
|
+
kuramoto: {
|
|
396
|
+
K: this.K,
|
|
397
|
+
frequencies: this.frequencies,
|
|
398
|
+
...sync
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Reset state and history
|
|
405
|
+
*/
|
|
406
|
+
reset() {
|
|
407
|
+
super.reset();
|
|
408
|
+
this.collapsePressure = 0;
|
|
409
|
+
this.collapseEvents = [];
|
|
410
|
+
this.orderParameterHistory = [];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Run with sync tracking
|
|
415
|
+
* @param {number} steps - Number of steps
|
|
416
|
+
* @param {number} [dt=0.01] - Time step
|
|
417
|
+
* @returns {object} Trajectory and sync data
|
|
418
|
+
*/
|
|
419
|
+
runWithSync(steps, dt = 0.01) {
|
|
420
|
+
const trajectory = [];
|
|
421
|
+
const syncHistory = [];
|
|
422
|
+
|
|
423
|
+
for (let i = 0; i < steps; i++) {
|
|
424
|
+
this.step(dt);
|
|
425
|
+
trajectory.push(this.metrics());
|
|
426
|
+
syncHistory.push({
|
|
427
|
+
t: this.t,
|
|
428
|
+
...this.syncMetrics()
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return {
|
|
433
|
+
trajectory,
|
|
434
|
+
syncHistory,
|
|
435
|
+
collapseEvents: this.collapseEvents.slice()
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Detect synchronization transition
|
|
441
|
+
* @param {number} windowSize - Window for averaging
|
|
442
|
+
*/
|
|
443
|
+
detectSyncTransition(windowSize = 50) {
|
|
444
|
+
if (this.orderParameterHistory.length < windowSize * 2) {
|
|
445
|
+
return { detected: false, reason: 'insufficient_data' };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const history = this.orderParameterHistory;
|
|
449
|
+
const n = history.length;
|
|
450
|
+
|
|
451
|
+
// Compare early and late windows
|
|
452
|
+
const earlyWindow = history.slice(n - windowSize * 2, n - windowSize);
|
|
453
|
+
const lateWindow = history.slice(n - windowSize);
|
|
454
|
+
|
|
455
|
+
const earlyMean = earlyWindow.reduce((s, h) => s + h.r, 0) / windowSize;
|
|
456
|
+
const lateMean = lateWindow.reduce((s, h) => s + h.r, 0) / windowSize;
|
|
457
|
+
|
|
458
|
+
const change = lateMean - earlyMean;
|
|
459
|
+
const threshold = 0.2;
|
|
460
|
+
|
|
461
|
+
if (Math.abs(change) > threshold) {
|
|
462
|
+
return {
|
|
463
|
+
detected: true,
|
|
464
|
+
direction: change > 0 ? 'synchronizing' : 'desynchronizing',
|
|
465
|
+
earlyR: earlyMean,
|
|
466
|
+
lateR: lateMean,
|
|
467
|
+
change
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
detected: false,
|
|
473
|
+
earlyR: earlyMean,
|
|
474
|
+
lateR: lateMean,
|
|
475
|
+
change
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Get full snapshot including Kuramoto state
|
|
481
|
+
*/
|
|
482
|
+
snapshot() {
|
|
483
|
+
const base = super.snapshot();
|
|
484
|
+
|
|
485
|
+
return {
|
|
486
|
+
...base,
|
|
487
|
+
K: this.K,
|
|
488
|
+
frequencies: this.frequencies.slice(),
|
|
489
|
+
collapsePressure: this.collapsePressure,
|
|
490
|
+
collapseThreshold: this.collapseThreshold,
|
|
491
|
+
collapseEvents: this.collapseEvents.slice(),
|
|
492
|
+
orderParameterHistory: this.orderParameterHistory.slice(-100)
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Restore from snapshot
|
|
498
|
+
*/
|
|
499
|
+
restore(snap) {
|
|
500
|
+
super.restore(snap);
|
|
501
|
+
|
|
502
|
+
this.K = snap.K;
|
|
503
|
+
this.frequencies = snap.frequencies.slice();
|
|
504
|
+
this.collapsePressure = snap.collapsePressure;
|
|
505
|
+
this.collapseEvents = snap.collapseEvents?.slice() || [];
|
|
506
|
+
this.orderParameterHistory = snap.orderParameterHistory?.slice() || [];
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Create a Kuramoto-coupled ladder with prime resonances
|
|
512
|
+
* @param {number[]} primes - Primes for rung excitation
|
|
513
|
+
* @param {object} [opts={}] - Options
|
|
514
|
+
*/
|
|
515
|
+
function createKuramotoLadder(primes, opts = {}) {
|
|
516
|
+
const N = opts.N ?? Math.max(16, Math.max(...primes) + 1);
|
|
517
|
+
|
|
518
|
+
const ladder = new KuramotoCoupledLadder({
|
|
519
|
+
N,
|
|
520
|
+
d: opts.d ?? 1,
|
|
521
|
+
J: opts.J ?? 0.25,
|
|
522
|
+
K: opts.K ?? 0.1,
|
|
523
|
+
frequencies: opts.frequencies,
|
|
524
|
+
collapseThreshold: opts.collapseThreshold ?? 1.0,
|
|
525
|
+
collapseDecay: opts.collapseDecay ?? 0.1,
|
|
526
|
+
autoCollapse: opts.autoCollapse ?? false,
|
|
527
|
+
periodic: opts.periodic ?? true,
|
|
528
|
+
zChannels: opts.zChannels,
|
|
529
|
+
Jt: opts.Jt
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
if (primes.length > 0) {
|
|
533
|
+
ladder.excitePrimes(primes, opts.ampScale ?? 1);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return ladder;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Run a collapse pressure experiment
|
|
541
|
+
* Track how Z-flux builds collapse pressure until threshold
|
|
542
|
+
*
|
|
543
|
+
* @param {object} opts - Experiment options
|
|
544
|
+
* @returns {object} Experiment results
|
|
545
|
+
*/
|
|
546
|
+
function runCollapsePressureExperiment(opts = {}) {
|
|
547
|
+
const {
|
|
548
|
+
N = 16,
|
|
549
|
+
primes = [2, 3, 5, 7],
|
|
550
|
+
J = 0.25,
|
|
551
|
+
K = 0.1,
|
|
552
|
+
collapseThreshold = 0.5,
|
|
553
|
+
maxSteps = 1000,
|
|
554
|
+
dt = 0.01
|
|
555
|
+
} = opts;
|
|
556
|
+
|
|
557
|
+
const ladder = createKuramotoLadder(primes, {
|
|
558
|
+
N, J, K,
|
|
559
|
+
collapseThreshold,
|
|
560
|
+
autoCollapse: true,
|
|
561
|
+
collapseDecay: 0.05
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
const results = {
|
|
565
|
+
trajectory: [],
|
|
566
|
+
collapses: [],
|
|
567
|
+
finalState: null
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
for (let step = 0; step < maxSteps; step++) {
|
|
571
|
+
ladder.step(dt);
|
|
572
|
+
|
|
573
|
+
if (step % 10 === 0) {
|
|
574
|
+
results.trajectory.push({
|
|
575
|
+
step,
|
|
576
|
+
t: ladder.t,
|
|
577
|
+
orderParameter: ladder.orderParameter().r,
|
|
578
|
+
collapsePressure: ladder.collapsePressure,
|
|
579
|
+
entropy: ladder.coreMetrics().entropy
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Check for new collapses
|
|
584
|
+
if (ladder.collapseEvents.length > results.collapses.length) {
|
|
585
|
+
results.collapses.push(
|
|
586
|
+
ladder.collapseEvents[ladder.collapseEvents.length - 1]
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
results.finalState = ladder.metrics();
|
|
592
|
+
results.syncTransition = ladder.detectSyncTransition();
|
|
593
|
+
|
|
594
|
+
return results;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
module.exports = {
|
|
598
|
+
KuramotoCoupledLadder,
|
|
599
|
+
createKuramotoLadder,
|
|
600
|
+
runCollapsePressureExperiment,
|
|
601
|
+
kuramotoOrderParameter,
|
|
602
|
+
getPhase
|
|
603
|
+
};
|