@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
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Channel Primeon Z-Ladder
|
|
3
|
+
*
|
|
4
|
+
* Extension of PrimeonZLadderU with multiple Z sectors for hierarchical memory:
|
|
5
|
+
* - Fast Z (working memory): High leak rate, short-term storage
|
|
6
|
+
* - Slow Z (long-term memory): Low leak rate, persistent storage
|
|
7
|
+
* - Permanent Z (archival): No leak, permanent storage
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Named Z channels with individual configurations
|
|
11
|
+
* - Cross-channel interference
|
|
12
|
+
* - Channel-specific metrics and snapshots
|
|
13
|
+
* - Time-dependent Hamiltonian support
|
|
14
|
+
* - Shaped excitation pulses
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
PrimeonZLadderU,
|
|
21
|
+
C,
|
|
22
|
+
shannonEntropyNats,
|
|
23
|
+
probsOf,
|
|
24
|
+
normalize
|
|
25
|
+
} = require('./primeon_z_ladder_u');
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Z Channel configuration
|
|
29
|
+
*/
|
|
30
|
+
class ZChannel {
|
|
31
|
+
/**
|
|
32
|
+
* @param {object} config
|
|
33
|
+
* @param {string} config.name - Channel identifier
|
|
34
|
+
* @param {number} config.dz - Internal dimension per rung
|
|
35
|
+
* @param {number} config.leak - Leak rate from core to this channel
|
|
36
|
+
* @param {number} [config.decay=0] - Internal decay rate within channel
|
|
37
|
+
* @param {number} [config.crossCoupling=0] - Coupling to other channels
|
|
38
|
+
*/
|
|
39
|
+
constructor(config) {
|
|
40
|
+
this.name = config.name;
|
|
41
|
+
this.dz = config.dz ?? 1;
|
|
42
|
+
this.leak = Math.max(0, Math.min(1, config.leak ?? 0.05));
|
|
43
|
+
this.decay = config.decay ?? 0;
|
|
44
|
+
this.crossCoupling = config.crossCoupling ?? 0;
|
|
45
|
+
this.N = 0; // Set when attached to ladder
|
|
46
|
+
|
|
47
|
+
// State array (initialized when attached)
|
|
48
|
+
this.z = null;
|
|
49
|
+
|
|
50
|
+
// Metrics
|
|
51
|
+
this.totalFlux = 0;
|
|
52
|
+
this.lastFlux = 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Initialize channel state
|
|
57
|
+
* @param {number} N - Number of rungs
|
|
58
|
+
*/
|
|
59
|
+
init(N) {
|
|
60
|
+
this.N = N;
|
|
61
|
+
this.z = Array.from({ length: N * this.dz }, () => C.zero());
|
|
62
|
+
this.totalFlux = 0;
|
|
63
|
+
this.lastFlux = 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Reset channel to vacuum
|
|
68
|
+
*/
|
|
69
|
+
reset() {
|
|
70
|
+
for (let i = 0; i < this.z.length; i++) {
|
|
71
|
+
this.z[i] = C.zero();
|
|
72
|
+
}
|
|
73
|
+
this.totalFlux = 0;
|
|
74
|
+
this.lastFlux = 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Compute channel metrics
|
|
79
|
+
*/
|
|
80
|
+
metrics() {
|
|
81
|
+
const p = probsOf(this.z);
|
|
82
|
+
const H = shannonEntropyNats(p);
|
|
83
|
+
|
|
84
|
+
let norm = 0;
|
|
85
|
+
for (const v of this.z) {
|
|
86
|
+
norm += C.abs2(v);
|
|
87
|
+
}
|
|
88
|
+
norm = Math.sqrt(norm);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
name: this.name,
|
|
92
|
+
entropy: H,
|
|
93
|
+
norm,
|
|
94
|
+
totalFlux: this.totalFlux,
|
|
95
|
+
lastFlux: this.lastFlux,
|
|
96
|
+
coherence: 1 / (1 + H)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get state snapshot
|
|
102
|
+
*/
|
|
103
|
+
snapshot() {
|
|
104
|
+
return {
|
|
105
|
+
name: this.name,
|
|
106
|
+
dz: this.dz,
|
|
107
|
+
leak: this.leak,
|
|
108
|
+
decay: this.decay,
|
|
109
|
+
z: this.z.map(v => ({ re: v.re, im: v.im })),
|
|
110
|
+
...this.metrics()
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Restore from snapshot
|
|
116
|
+
*/
|
|
117
|
+
restore(snap) {
|
|
118
|
+
this.z = snap.z.map(v => new C(v.re, v.im));
|
|
119
|
+
this.totalFlux = snap.totalFlux;
|
|
120
|
+
this.lastFlux = snap.lastFlux;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* PrimeonZLadderMulti - Multi-channel Z-ladder with hierarchical memory
|
|
126
|
+
*/
|
|
127
|
+
class PrimeonZLadderMulti {
|
|
128
|
+
/**
|
|
129
|
+
* @param {object} opts
|
|
130
|
+
* @param {number} opts.N - Number of ladder rungs
|
|
131
|
+
* @param {number} [opts.d=1] - Core internal dimension per rung
|
|
132
|
+
* @param {number} [opts.J=0.25] - Nearest-neighbor coupling strength
|
|
133
|
+
* @param {object[]} opts.zChannels - Array of channel configurations
|
|
134
|
+
* @param {boolean} [opts.periodic=true] - Periodic boundary conditions
|
|
135
|
+
* @param {Function} [opts.Jt=null] - Time-dependent J function J(t)
|
|
136
|
+
*/
|
|
137
|
+
constructor(opts) {
|
|
138
|
+
this.N = opts.N;
|
|
139
|
+
this.d = opts.d ?? 1;
|
|
140
|
+
this.J = opts.J ?? 0.25;
|
|
141
|
+
this.J0 = this.J; // Store initial J for Jt reference
|
|
142
|
+
this.periodic = opts.periodic ?? true;
|
|
143
|
+
this.Jt = opts.Jt ?? null; // Time-dependent Hamiltonian
|
|
144
|
+
|
|
145
|
+
// Core state
|
|
146
|
+
this.psi = Array.from({ length: this.N * this.d }, () => C.zero());
|
|
147
|
+
|
|
148
|
+
// Z channels
|
|
149
|
+
this.channels = new Map();
|
|
150
|
+
const channelConfigs = opts.zChannels || [
|
|
151
|
+
{ name: 'fast', dz: 1, leak: 0.2 },
|
|
152
|
+
{ name: 'slow', dz: 1, leak: 0.02 },
|
|
153
|
+
{ name: 'permanent', dz: 1, leak: 0.001, decay: 0 }
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
for (const config of channelConfigs) {
|
|
157
|
+
const channel = new ZChannel(config);
|
|
158
|
+
channel.init(this.N);
|
|
159
|
+
this.channels.set(config.name, channel);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Metrics
|
|
163
|
+
this.t = 0;
|
|
164
|
+
this.stepCount = 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get a specific Z channel
|
|
169
|
+
* @param {string} name - Channel name
|
|
170
|
+
*/
|
|
171
|
+
getChannel(name) {
|
|
172
|
+
return this.channels.get(name);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get all channel names
|
|
177
|
+
*/
|
|
178
|
+
getChannelNames() {
|
|
179
|
+
return Array.from(this.channels.keys());
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Reset all state to vacuum
|
|
184
|
+
*/
|
|
185
|
+
reset() {
|
|
186
|
+
for (let i = 0; i < this.psi.length; i++) {
|
|
187
|
+
this.psi[i] = C.zero();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
for (const channel of this.channels.values()) {
|
|
191
|
+
channel.reset();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this.t = 0;
|
|
195
|
+
this.stepCount = 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get current coupling strength (may be time-dependent)
|
|
200
|
+
*/
|
|
201
|
+
getCurrentJ() {
|
|
202
|
+
if (this.Jt) {
|
|
203
|
+
return this.Jt(this.t);
|
|
204
|
+
}
|
|
205
|
+
return this.J;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Excite a specific rung
|
|
210
|
+
* @param {number} n - Rung index
|
|
211
|
+
* @param {C} [amp] - Complex amplitude
|
|
212
|
+
* @param {number} [k=0] - Internal index within rung
|
|
213
|
+
*/
|
|
214
|
+
exciteRung(n, amp = new C(1, 0), k = 0) {
|
|
215
|
+
const i = ((n % this.N) + this.N) % this.N * this.d + (k % this.d);
|
|
216
|
+
this.psi[i] = amp;
|
|
217
|
+
normalize(this.psi);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Excite multiple rungs uniformly
|
|
222
|
+
* @param {number[]} rungs - Array of rung indices
|
|
223
|
+
* @param {number} [ampScale=1] - Amplitude scale
|
|
224
|
+
*/
|
|
225
|
+
exciteRungs(rungs, ampScale = 1) {
|
|
226
|
+
for (const n of rungs) {
|
|
227
|
+
const idx = ((n % this.N) + this.N) % this.N;
|
|
228
|
+
const i = idx * this.d;
|
|
229
|
+
this.psi[i] = C.add(this.psi[i], new C(ampScale, 0));
|
|
230
|
+
}
|
|
231
|
+
normalize(this.psi);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Excite with prime-based rung mapping
|
|
236
|
+
* @param {number[]} primes - Prime numbers to map to rungs
|
|
237
|
+
* @param {number} [ampScale=1] - Amplitude scale
|
|
238
|
+
*/
|
|
239
|
+
excitePrimes(primes, ampScale = 1) {
|
|
240
|
+
for (const p of primes) {
|
|
241
|
+
const idx = ((p % this.N) + this.N) % this.N;
|
|
242
|
+
const i = idx * this.d;
|
|
243
|
+
this.psi[i] = C.add(this.psi[i], new C(ampScale, 0));
|
|
244
|
+
}
|
|
245
|
+
normalize(this.psi);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Shaped pulse excitation (Gaussian envelope)
|
|
250
|
+
* @param {number} centerRung - Center of the pulse
|
|
251
|
+
* @param {number} width - Width parameter σ
|
|
252
|
+
* @param {number} [amp=1] - Peak amplitude
|
|
253
|
+
* @param {number} [phase=0] - Phase offset
|
|
254
|
+
*/
|
|
255
|
+
gaussianPulse(centerRung, width, amp = 1, phase = 0) {
|
|
256
|
+
const sigma = width;
|
|
257
|
+
|
|
258
|
+
for (let n = 0; n < this.N; n++) {
|
|
259
|
+
const dist = Math.min(
|
|
260
|
+
Math.abs(n - centerRung),
|
|
261
|
+
Math.abs(n - centerRung + this.N),
|
|
262
|
+
Math.abs(n - centerRung - this.N)
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
const envelope = amp * Math.exp(-dist * dist / (2 * sigma * sigma));
|
|
266
|
+
const i = n * this.d;
|
|
267
|
+
|
|
268
|
+
this.psi[i] = C.add(this.psi[i], C.mul(
|
|
269
|
+
new C(envelope, 0),
|
|
270
|
+
C.exp(phase)
|
|
271
|
+
));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
normalize(this.psi);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Pi-pulse excitation (flip between states)
|
|
279
|
+
* @param {number} n - Rung to flip
|
|
280
|
+
* @param {number} [phase=0] - Phase of the flip
|
|
281
|
+
*/
|
|
282
|
+
piPulse(n, phase = 0) {
|
|
283
|
+
const idx = ((n % this.N) + this.N) % this.N;
|
|
284
|
+
const i = idx * this.d;
|
|
285
|
+
|
|
286
|
+
// Apply π rotation: multiply by e^(iπ/2) = i
|
|
287
|
+
this.psi[i] = C.mul(this.psi[i], C.exp(Math.PI / 2 + phase));
|
|
288
|
+
normalize(this.psi);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* One time step with multi-channel Z dynamics
|
|
293
|
+
* @param {number} [dt=0.01] - Time step size
|
|
294
|
+
*/
|
|
295
|
+
step(dt = 0.01) {
|
|
296
|
+
const N = this.N;
|
|
297
|
+
const d = this.d;
|
|
298
|
+
const J = this.getCurrentJ();
|
|
299
|
+
|
|
300
|
+
// --- 1) Core hopping dynamics ---
|
|
301
|
+
const next = Array.from({ length: N * d }, () => C.zero());
|
|
302
|
+
|
|
303
|
+
for (let n = 0; n < N; n++) {
|
|
304
|
+
const nL = (n === 0) ? (this.periodic ? N - 1 : 0) : n - 1;
|
|
305
|
+
const nR = (n === N - 1) ? (this.periodic ? 0 : N - 1) : n + 1;
|
|
306
|
+
|
|
307
|
+
for (let k = 0; k < d; k++) {
|
|
308
|
+
const i = n * d + k;
|
|
309
|
+
const iL = nL * d + k;
|
|
310
|
+
const iR = nR * d + k;
|
|
311
|
+
|
|
312
|
+
const psi = this.psi[i];
|
|
313
|
+
const psiL = this.psi[iL];
|
|
314
|
+
const psiR = this.psi[iR];
|
|
315
|
+
|
|
316
|
+
// Discrete Laplacian
|
|
317
|
+
const lap = C.add(C.sub(psiL, psi), C.sub(psiR, psi));
|
|
318
|
+
|
|
319
|
+
// -i * (dt*J) * lap
|
|
320
|
+
const delta = C.mul(lap, new C(0, -dt * J));
|
|
321
|
+
next[i] = C.add(psi, delta);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
this.psi = next;
|
|
326
|
+
|
|
327
|
+
// --- 2) Multi-channel leakage ---
|
|
328
|
+
for (const channel of this.channels.values()) {
|
|
329
|
+
channel.lastFlux = 0;
|
|
330
|
+
|
|
331
|
+
for (let i = 0; i < this.psi.length; i++) {
|
|
332
|
+
const a = this.psi[i];
|
|
333
|
+
const moved = C.scale(a, channel.leak);
|
|
334
|
+
|
|
335
|
+
// Subtract from core
|
|
336
|
+
this.psi[i] = C.sub(a, moved);
|
|
337
|
+
|
|
338
|
+
// Add to channel (fold core index into channel index)
|
|
339
|
+
const zi = i % (N * channel.dz);
|
|
340
|
+
channel.z[zi] = C.add(channel.z[zi], moved);
|
|
341
|
+
|
|
342
|
+
channel.lastFlux += C.abs2(moved);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
channel.totalFlux += channel.lastFlux;
|
|
346
|
+
|
|
347
|
+
// --- 3) Channel internal decay ---
|
|
348
|
+
if (channel.decay > 0) {
|
|
349
|
+
const decayFactor = 1 - channel.decay * dt;
|
|
350
|
+
for (let i = 0; i < channel.z.length; i++) {
|
|
351
|
+
channel.z[i] = C.scale(channel.z[i], decayFactor);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// --- 4) Cross-channel coupling ---
|
|
357
|
+
this._applyCrossChannelCoupling(dt);
|
|
358
|
+
|
|
359
|
+
// --- 5) Normalize core ---
|
|
360
|
+
normalize(this.psi);
|
|
361
|
+
|
|
362
|
+
this.t += dt;
|
|
363
|
+
this.stepCount++;
|
|
364
|
+
|
|
365
|
+
return this.metrics();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Apply cross-channel coupling
|
|
370
|
+
* @private
|
|
371
|
+
*/
|
|
372
|
+
_applyCrossChannelCoupling(dt) {
|
|
373
|
+
const channelList = Array.from(this.channels.values());
|
|
374
|
+
|
|
375
|
+
for (let a = 0; a < channelList.length; a++) {
|
|
376
|
+
for (let b = a + 1; b < channelList.length; b++) {
|
|
377
|
+
const chanA = channelList[a];
|
|
378
|
+
const chanB = channelList[b];
|
|
379
|
+
|
|
380
|
+
const coupling = Math.min(chanA.crossCoupling, chanB.crossCoupling);
|
|
381
|
+
if (coupling <= 0) continue;
|
|
382
|
+
|
|
383
|
+
// Transfer some amplitude between channels
|
|
384
|
+
const minLen = Math.min(chanA.z.length, chanB.z.length);
|
|
385
|
+
|
|
386
|
+
for (let i = 0; i < minLen; i++) {
|
|
387
|
+
const zA = chanA.z[i];
|
|
388
|
+
const zB = chanB.z[i];
|
|
389
|
+
|
|
390
|
+
const transfer = coupling * dt;
|
|
391
|
+
|
|
392
|
+
// A -> B
|
|
393
|
+
const toB = C.scale(zA, transfer);
|
|
394
|
+
chanA.z[i] = C.sub(zA, toB);
|
|
395
|
+
chanB.z[i] = C.add(zB, toB);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Run multiple steps
|
|
403
|
+
* @param {number} steps - Number of steps
|
|
404
|
+
* @param {number} [dt=0.01] - Time step size
|
|
405
|
+
*/
|
|
406
|
+
run(steps, dt = 0.01) {
|
|
407
|
+
const trajectory = [];
|
|
408
|
+
for (let i = 0; i < steps; i++) {
|
|
409
|
+
trajectory.push(this.step(dt));
|
|
410
|
+
}
|
|
411
|
+
return trajectory;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Compute core metrics
|
|
416
|
+
*/
|
|
417
|
+
coreMetrics() {
|
|
418
|
+
const p = probsOf(this.psi);
|
|
419
|
+
const H = shannonEntropyNats(p);
|
|
420
|
+
|
|
421
|
+
let meanRe = 0, meanIm = 0;
|
|
422
|
+
for (const v of this.psi) {
|
|
423
|
+
meanRe += v.re;
|
|
424
|
+
meanIm += v.im;
|
|
425
|
+
}
|
|
426
|
+
const orderParameter = Math.sqrt(meanRe * meanRe + meanIm * meanIm) / this.psi.length;
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
entropy: H,
|
|
430
|
+
coherence: 1 / (1 + H),
|
|
431
|
+
orderParameter
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Compute combined metrics
|
|
437
|
+
*/
|
|
438
|
+
metrics() {
|
|
439
|
+
const core = this.coreMetrics();
|
|
440
|
+
|
|
441
|
+
const channelMetrics = {};
|
|
442
|
+
for (const [name, channel] of this.channels) {
|
|
443
|
+
channelMetrics[name] = channel.metrics();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Compute total Z entropy
|
|
447
|
+
let totalZEntropy = 0;
|
|
448
|
+
for (const m of Object.values(channelMetrics)) {
|
|
449
|
+
totalZEntropy += m.entropy;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return {
|
|
453
|
+
t: this.t,
|
|
454
|
+
stepCount: this.stepCount,
|
|
455
|
+
core,
|
|
456
|
+
channels: channelMetrics,
|
|
457
|
+
totalZEntropy,
|
|
458
|
+
currentJ: this.getCurrentJ()
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Get per-channel metrics
|
|
464
|
+
*/
|
|
465
|
+
channelMetrics() {
|
|
466
|
+
const result = {};
|
|
467
|
+
for (const [name, channel] of this.channels) {
|
|
468
|
+
result[name] = channel.metrics();
|
|
469
|
+
}
|
|
470
|
+
return result;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Get probability distribution over rungs
|
|
475
|
+
*/
|
|
476
|
+
rungProbabilities() {
|
|
477
|
+
const probs = new Array(this.N).fill(0);
|
|
478
|
+
for (let n = 0; n < this.N; n++) {
|
|
479
|
+
for (let k = 0; k < this.d; k++) {
|
|
480
|
+
const i = n * this.d + k;
|
|
481
|
+
probs[n] += C.abs2(this.psi[i]);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
const total = probs.reduce((a, b) => a + b, 0) || 1;
|
|
485
|
+
return probs.map(p => p / total);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Sample a rung according to |ψ|² distribution
|
|
490
|
+
*/
|
|
491
|
+
sampleRung() {
|
|
492
|
+
const probs = this.rungProbabilities();
|
|
493
|
+
const r = Math.random();
|
|
494
|
+
let cumulative = 0;
|
|
495
|
+
for (let n = 0; n < this.N; n++) {
|
|
496
|
+
cumulative += probs[n];
|
|
497
|
+
if (r <= cumulative) return n;
|
|
498
|
+
}
|
|
499
|
+
return this.N - 1;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Collapse to a specific rung
|
|
504
|
+
* @param {number} n - Rung to collapse to
|
|
505
|
+
*/
|
|
506
|
+
collapseToRung(n) {
|
|
507
|
+
const idx = ((n % this.N) + this.N) % this.N;
|
|
508
|
+
|
|
509
|
+
for (let i = 0; i < this.psi.length; i++) {
|
|
510
|
+
const rungIdx = Math.floor(i / this.d);
|
|
511
|
+
if (rungIdx !== idx) {
|
|
512
|
+
this.psi[i] = C.zero();
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
normalize(this.psi);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Perform measurement and collapse
|
|
520
|
+
*/
|
|
521
|
+
measure() {
|
|
522
|
+
const probsBefore = this.rungProbabilities();
|
|
523
|
+
const sampledRung = this.sampleRung();
|
|
524
|
+
const probability = probsBefore[sampledRung];
|
|
525
|
+
|
|
526
|
+
this.collapseToRung(sampledRung);
|
|
527
|
+
|
|
528
|
+
return {
|
|
529
|
+
outcome: sampledRung,
|
|
530
|
+
probability,
|
|
531
|
+
probsBefore,
|
|
532
|
+
metricsAfter: this.metrics()
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Compute entanglement entropy between core and Z channels
|
|
538
|
+
* Uses bipartite entanglement measure
|
|
539
|
+
*/
|
|
540
|
+
entanglementEntropy() {
|
|
541
|
+
// Compute reduced density matrix for core
|
|
542
|
+
// For simplicity, use purity-based estimate: S ≈ log(d) - log(purity)
|
|
543
|
+
|
|
544
|
+
let corePurity = 0;
|
|
545
|
+
const coreProbs = this.rungProbabilities();
|
|
546
|
+
for (const p of coreProbs) {
|
|
547
|
+
corePurity += p * p;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Von Neumann entropy estimate
|
|
551
|
+
const maxEntropy = Math.log(this.N);
|
|
552
|
+
const entropy = maxEntropy - Math.log(1 / corePurity);
|
|
553
|
+
|
|
554
|
+
return Math.max(0, Math.min(maxEntropy, entropy));
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Get full state snapshot
|
|
559
|
+
*/
|
|
560
|
+
snapshot() {
|
|
561
|
+
const channelSnapshots = {};
|
|
562
|
+
for (const [name, channel] of this.channels) {
|
|
563
|
+
channelSnapshots[name] = channel.snapshot();
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return {
|
|
567
|
+
t: this.t,
|
|
568
|
+
stepCount: this.stepCount,
|
|
569
|
+
N: this.N,
|
|
570
|
+
d: this.d,
|
|
571
|
+
J: this.J,
|
|
572
|
+
periodic: this.periodic,
|
|
573
|
+
psi: this.psi.map(v => ({ re: v.re, im: v.im })),
|
|
574
|
+
channels: channelSnapshots,
|
|
575
|
+
...this.metrics()
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Restore from snapshot
|
|
581
|
+
*/
|
|
582
|
+
restore(snap) {
|
|
583
|
+
this.t = snap.t;
|
|
584
|
+
this.stepCount = snap.stepCount;
|
|
585
|
+
this.psi = snap.psi.map(v => new C(v.re, v.im));
|
|
586
|
+
|
|
587
|
+
for (const [name, channelSnap] of Object.entries(snap.channels)) {
|
|
588
|
+
const channel = this.channels.get(name);
|
|
589
|
+
if (channel) {
|
|
590
|
+
channel.restore(channelSnap);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Factory function for creating multi-channel ladder with prime-based config
|
|
598
|
+
* @param {number[]} primes - Prime numbers for initialization
|
|
599
|
+
* @param {object} [opts={}] - Additional options
|
|
600
|
+
*/
|
|
601
|
+
function createMultiChannelLadder(primes, opts = {}) {
|
|
602
|
+
const N = opts.N ?? Math.max(16, Math.max(...primes) + 1);
|
|
603
|
+
|
|
604
|
+
const zChannels = opts.zChannels || [
|
|
605
|
+
{ name: 'fast', dz: 1, leak: 0.2 },
|
|
606
|
+
{ name: 'slow', dz: 1, leak: 0.02, decay: 0.001 },
|
|
607
|
+
{ name: 'permanent', dz: 1, leak: 0.001, decay: 0 }
|
|
608
|
+
];
|
|
609
|
+
|
|
610
|
+
const ladder = new PrimeonZLadderMulti({
|
|
611
|
+
N,
|
|
612
|
+
d: opts.d ?? 1,
|
|
613
|
+
J: opts.J ?? 0.25,
|
|
614
|
+
zChannels,
|
|
615
|
+
periodic: opts.periodic ?? true,
|
|
616
|
+
Jt: opts.Jt ?? null
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
if (primes.length > 0) {
|
|
620
|
+
ladder.excitePrimes(primes, opts.ampScale ?? 1);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return ladder;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Adiabatic protocol helper
|
|
628
|
+
* Creates time-dependent J function for adiabatic quantum computing
|
|
629
|
+
*
|
|
630
|
+
* @param {number} J0 - Initial coupling
|
|
631
|
+
* @param {number} J1 - Final coupling
|
|
632
|
+
* @param {number} T - Total evolution time
|
|
633
|
+
* @param {string} [schedule='linear'] - Schedule type
|
|
634
|
+
*/
|
|
635
|
+
function createAdiabaticSchedule(J0, J1, T, schedule = 'linear') {
|
|
636
|
+
switch (schedule) {
|
|
637
|
+
case 'linear':
|
|
638
|
+
return (t) => J0 + (J1 - J0) * Math.min(1, t / T);
|
|
639
|
+
|
|
640
|
+
case 'quadratic':
|
|
641
|
+
return (t) => {
|
|
642
|
+
const s = Math.min(1, t / T);
|
|
643
|
+
return J0 + (J1 - J0) * s * s;
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
case 'sinusoidal':
|
|
647
|
+
return (t) => {
|
|
648
|
+
const s = Math.min(1, t / T);
|
|
649
|
+
return J0 + (J1 - J0) * (1 - Math.cos(Math.PI * s)) / 2;
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
case 'exponential':
|
|
653
|
+
return (t) => {
|
|
654
|
+
const s = Math.min(1, t / T);
|
|
655
|
+
const tau = T / 3; // Characteristic time
|
|
656
|
+
return J0 + (J1 - J0) * (1 - Math.exp(-s * T / tau));
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
default:
|
|
660
|
+
return (t) => J0;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
module.exports = {
|
|
665
|
+
ZChannel,
|
|
666
|
+
PrimeonZLadderMulti,
|
|
667
|
+
createMultiChannelLadder,
|
|
668
|
+
createAdiabaticSchedule
|
|
669
|
+
};
|