@aleph-ai/tinyaleph 1.0.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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +278 -0
  3. package/backends/cryptographic/index.js +196 -0
  4. package/backends/index.js +15 -0
  5. package/backends/interface.js +89 -0
  6. package/backends/scientific/index.js +272 -0
  7. package/backends/semantic/index.js +527 -0
  8. package/backends/semantic/surface.js +393 -0
  9. package/backends/semantic/two-layer.js +375 -0
  10. package/core/fano.js +127 -0
  11. package/core/hilbert.js +564 -0
  12. package/core/hypercomplex.js +141 -0
  13. package/core/index.js +133 -0
  14. package/core/llm.js +132 -0
  15. package/core/prime.js +184 -0
  16. package/core/resonance.js +695 -0
  17. package/core/rformer-tf.js +1086 -0
  18. package/core/rformer.js +806 -0
  19. package/core/sieve.js +350 -0
  20. package/data.json +8163 -0
  21. package/docs/EXAMPLES_PLAN.md +293 -0
  22. package/docs/README.md +159 -0
  23. package/docs/design/ALEPH_CHAT_ARCHITECTURE.md +499 -0
  24. package/docs/guide/01-quickstart.md +298 -0
  25. package/docs/guide/02-semantic-computing.md +409 -0
  26. package/docs/guide/03-cryptographic.md +420 -0
  27. package/docs/guide/04-scientific.md +494 -0
  28. package/docs/guide/05-llm-integration.md +568 -0
  29. package/docs/guide/06-advanced.md +996 -0
  30. package/docs/guide/README.md +188 -0
  31. package/docs/reference/01-core.md +695 -0
  32. package/docs/reference/02-physics.md +601 -0
  33. package/docs/reference/03-backends.md +892 -0
  34. package/docs/reference/04-engine.md +632 -0
  35. package/docs/reference/README.md +252 -0
  36. package/docs/theory/01-prime-semantics.md +327 -0
  37. package/docs/theory/02-hypercomplex-algebra.md +421 -0
  38. package/docs/theory/03-phase-synchronization.md +364 -0
  39. package/docs/theory/04-entropy-reasoning.md +348 -0
  40. package/docs/theory/05-non-commutativity.md +402 -0
  41. package/docs/theory/06-two-layer-meaning.md +414 -0
  42. package/docs/theory/07-resonant-field-interface.md +419 -0
  43. package/docs/theory/08-semantic-sieve.md +520 -0
  44. package/docs/theory/09-temporal-emergence.md +298 -0
  45. package/docs/theory/10-quaternionic-memory.md +415 -0
  46. package/docs/theory/README.md +162 -0
  47. package/engine/aleph.js +418 -0
  48. package/engine/index.js +7 -0
  49. package/index.js +23 -0
  50. package/modular.js +254 -0
  51. package/package.json +99 -0
  52. package/physics/collapse.js +95 -0
  53. package/physics/entropy.js +88 -0
  54. package/physics/index.js +65 -0
  55. package/physics/kuramoto.js +91 -0
  56. package/physics/lyapunov.js +80 -0
  57. package/physics/oscillator.js +95 -0
  58. package/types/index.d.ts +575 -0
@@ -0,0 +1,806 @@
1
+ /**
2
+ * ResoFormer Primitives
3
+ *
4
+ * Resonant Field Transformer: a prime-indexed, phase-interference model with
5
+ * quaternionic (order-sensitive) composition, coherence-gated compute,
6
+ * entropy-stabilized "collapse," and a prime-resonant external memory.
7
+ *
8
+ * H_Q = H_P ⊗ ℍ (Prime Hilbert space tensor Quaternions)
9
+ *
10
+ * Based on the ResoFormer specification combining:
11
+ * - PRSC (Prime Resonance Symbolic Computing)
12
+ * - Quantum Semantics
13
+ * - Quaternionic Memory Field (QMF)
14
+ * - Prime Resonant Graph Database
15
+ */
16
+
17
+ const { firstNPrimes, isPrime, factorize } = require('./prime');
18
+ const { Complex, PrimeState } = require('./hilbert');
19
+
20
+ // ============================================================================
21
+ // QUATERNION ALGEBRA
22
+ // ============================================================================
23
+
24
+ /**
25
+ * Full Quaternion class for H_Q representation
26
+ * q = w + xi + yj + zk (Hamilton quaternion)
27
+ */
28
+ class Quaternion {
29
+ constructor(w = 1, x = 0, y = 0, z = 0) {
30
+ this.w = w; // scalar part
31
+ this.x = x; // i component
32
+ this.y = y; // j component
33
+ this.z = z; // k component
34
+ }
35
+
36
+ static zero() { return new Quaternion(0, 0, 0, 0); }
37
+ static one() { return new Quaternion(1, 0, 0, 0); }
38
+ static i() { return new Quaternion(0, 1, 0, 0); }
39
+ static j() { return new Quaternion(0, 0, 1, 0); }
40
+ static k() { return new Quaternion(0, 0, 0, 1); }
41
+
42
+ /**
43
+ * Random unit quaternion (uniform on 3-sphere)
44
+ */
45
+ static random() {
46
+ const u1 = Math.random();
47
+ const u2 = Math.random();
48
+ const u3 = Math.random();
49
+
50
+ const w = Math.sqrt(1 - u1) * Math.sin(2 * Math.PI * u2);
51
+ const x = Math.sqrt(1 - u1) * Math.cos(2 * Math.PI * u2);
52
+ const y = Math.sqrt(u1) * Math.sin(2 * Math.PI * u3);
53
+ const z = Math.sqrt(u1) * Math.cos(2 * Math.PI * u3);
54
+
55
+ return new Quaternion(w, x, y, z);
56
+ }
57
+
58
+ /**
59
+ * Create from axis-angle rotation
60
+ */
61
+ static fromAxisAngle(axis, angle) {
62
+ const s = Math.sin(angle / 2);
63
+ const c = Math.cos(angle / 2);
64
+ const norm = Math.sqrt(axis[0]**2 + axis[1]**2 + axis[2]**2);
65
+
66
+ return new Quaternion(
67
+ c,
68
+ s * axis[0] / norm,
69
+ s * axis[1] / norm,
70
+ s * axis[2] / norm
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Hamilton product: q1 × q2
76
+ * NON-COMMUTATIVE: q1 × q2 ≠ q2 × q1
77
+ */
78
+ mul(other) {
79
+ return new Quaternion(
80
+ this.w * other.w - this.x * other.x - this.y * other.y - this.z * other.z,
81
+ this.w * other.x + this.x * other.w + this.y * other.z - this.z * other.y,
82
+ this.w * other.y - this.x * other.z + this.y * other.w + this.z * other.x,
83
+ this.w * other.z + this.x * other.y - this.y * other.x + this.z * other.w
84
+ );
85
+ }
86
+
87
+ /**
88
+ * Quaternion addition
89
+ */
90
+ add(other) {
91
+ return new Quaternion(
92
+ this.w + other.w,
93
+ this.x + other.x,
94
+ this.y + other.y,
95
+ this.z + other.z
96
+ );
97
+ }
98
+
99
+ /**
100
+ * Scalar multiplication
101
+ */
102
+ scale(k) {
103
+ return new Quaternion(this.w * k, this.x * k, this.y * k, this.z * k);
104
+ }
105
+
106
+ /**
107
+ * Conjugate: q* = w - xi - yj - zk
108
+ */
109
+ conjugate() {
110
+ return new Quaternion(this.w, -this.x, -this.y, -this.z);
111
+ }
112
+
113
+ /**
114
+ * Norm: |q|² = w² + x² + y² + z²
115
+ */
116
+ norm2() {
117
+ return this.w**2 + this.x**2 + this.y**2 + this.z**2;
118
+ }
119
+
120
+ norm() {
121
+ return Math.sqrt(this.norm2());
122
+ }
123
+
124
+ /**
125
+ * Normalize to unit quaternion
126
+ */
127
+ normalize() {
128
+ const n = this.norm();
129
+ return n > 1e-10 ? this.scale(1/n) : Quaternion.one();
130
+ }
131
+
132
+ /**
133
+ * Inverse: q^(-1) = conj(q)/|q|^2
134
+ */
135
+ inverse() {
136
+ const n2 = this.norm2();
137
+ return n2 > 1e-10 ? this.conjugate().scale(1/n2) : Quaternion.zero();
138
+ }
139
+
140
+ /**
141
+ * Dot product (as 4-vectors)
142
+ */
143
+ dot(other) {
144
+ return this.w * other.w + this.x * other.x + this.y * other.y + this.z * other.z;
145
+ }
146
+
147
+ /**
148
+ * Commutator: [q1, q2] = q1×q2 - q2×q1
149
+ * Non-zero commutator indicates order matters!
150
+ */
151
+ commutator(other) {
152
+ const ab = this.mul(other);
153
+ const ba = other.mul(this);
154
+ return new Quaternion(
155
+ ab.w - ba.w,
156
+ ab.x - ba.x,
157
+ ab.y - ba.y,
158
+ ab.z - ba.z
159
+ );
160
+ }
161
+
162
+ /**
163
+ * Commutator norm - measure of non-commutativity
164
+ */
165
+ commutatorNorm(other) {
166
+ return this.commutator(other).norm();
167
+ }
168
+
169
+ toArray() { return [this.w, this.x, this.y, this.z]; }
170
+
171
+ toString() {
172
+ return `${this.w.toFixed(4)} + ${this.x.toFixed(4)}i + ${this.y.toFixed(4)}j + ${this.z.toFixed(4)}k`;
173
+ }
174
+ }
175
+
176
+ // ============================================================================
177
+ // SPARSE PRIME STATE (H_Q = H_P ⊗ ℍ)
178
+ // ============================================================================
179
+
180
+ /**
181
+ * Sparse Prime-Quaternion State
182
+ * Each token is represented as sparse activations over primes,
183
+ * with each active prime having a complex amplitude AND quaternion orientation.
184
+ *
185
+ * |Ψ_t⟩ = Σ_{p ∈ P_t} α_{t,p} · q_{t,p} · |p⟩
186
+ * - α_{t,p} ∈ ℂ (complex amplitude with phase)
187
+ * - q_{t,p} ∈ ℍ (quaternion orientation)
188
+ */
189
+ class SparsePrimeState {
190
+ constructor(numPrimes = 4096, activeK = 32) {
191
+ this.allPrimes = firstNPrimes(numPrimes);
192
+ this.k = activeK;
193
+
194
+ // Sparse activation: Map<prime, {amplitude: Complex, quaternion: Quaternion}>
195
+ this.activations = new Map();
196
+ }
197
+
198
+ /**
199
+ * Get active primes
200
+ */
201
+ getActivePrimes() {
202
+ return Array.from(this.activations.keys());
203
+ }
204
+
205
+ /**
206
+ * Set activation for a prime
207
+ */
208
+ set(p, amplitude, quaternion) {
209
+ if (!isPrime(p)) return this;
210
+ this.activations.set(p, {
211
+ amplitude: amplitude instanceof Complex ? amplitude : new Complex(amplitude, 0),
212
+ quaternion: quaternion instanceof Quaternion ? quaternion : Quaternion.one()
213
+ });
214
+ return this;
215
+ }
216
+
217
+ /**
218
+ * Get activation for a prime
219
+ */
220
+ get(p) {
221
+ return this.activations.get(p) || { amplitude: Complex.zero(), quaternion: Quaternion.zero() };
222
+ }
223
+
224
+ /**
225
+ * Create from prime-entropy hash (deterministic)
226
+ */
227
+ static fromHash(text, numPrimes = 4096, k = 32) {
228
+ const state = new SparsePrimeState(numPrimes, k);
229
+ const primes = state.allPrimes;
230
+
231
+ // Hash text to select k primes
232
+ let hash = 0;
233
+ for (let i = 0; i < text.length; i++) {
234
+ hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0;
235
+ }
236
+
237
+ const selectedPrimes = [];
238
+ for (let i = 0; i < k; i++) {
239
+ const idx = Math.abs((hash * (i + 1) * 31337) % primes.length);
240
+ selectedPrimes.push(primes[idx]);
241
+ }
242
+
243
+ // Assign amplitudes and quaternions based on text
244
+ for (let i = 0; i < selectedPrimes.length; i++) {
245
+ const p = selectedPrimes[i];
246
+ const phase = 2 * Math.PI * i / k;
247
+ const amplitude = Complex.fromPolar(1/Math.sqrt(k), phase);
248
+
249
+ // Create quaternion from character codes
250
+ const charSum = text.split('').reduce((s, c) => s + c.charCodeAt(0), 0);
251
+ const q = Quaternion.fromAxisAngle(
252
+ [Math.sin(charSum + i), Math.cos(charSum * i), Math.sin(i)],
253
+ (charSum * i) % (2 * Math.PI)
254
+ );
255
+
256
+ state.set(p, amplitude, q.normalize());
257
+ }
258
+
259
+ return state;
260
+ }
261
+
262
+ /**
263
+ * Create from explicit prime list
264
+ */
265
+ static fromPrimes(primes, amplitudes = null, quaternions = null) {
266
+ const state = new SparsePrimeState(4096, primes.length);
267
+
268
+ for (let i = 0; i < primes.length; i++) {
269
+ const p = primes[i];
270
+ const amp = amplitudes ? amplitudes[i] : new Complex(1/Math.sqrt(primes.length), 0);
271
+ const q = quaternions ? quaternions[i] : Quaternion.random();
272
+ state.set(p, amp, q);
273
+ }
274
+
275
+ return state;
276
+ }
277
+
278
+ /**
279
+ * Normalize amplitudes to unit norm
280
+ */
281
+ normalize() {
282
+ let sumSq = 0;
283
+ for (const [p, act] of this.activations) {
284
+ sumSq += act.amplitude.norm2();
285
+ }
286
+
287
+ const norm = Math.sqrt(sumSq);
288
+ if (norm < 1e-10) return this;
289
+
290
+ for (const [p, act] of this.activations) {
291
+ act.amplitude = act.amplitude.scale(1/norm);
292
+ }
293
+
294
+ return this;
295
+ }
296
+
297
+ /**
298
+ * Compute entropy over prime amplitudes
299
+ */
300
+ entropy() {
301
+ let sumSq = 0;
302
+ for (const [p, act] of this.activations) {
303
+ sumSq += act.amplitude.norm2();
304
+ }
305
+
306
+ if (sumSq < 1e-10) return 0;
307
+
308
+ let h = 0;
309
+ for (const [p, act] of this.activations) {
310
+ const prob = act.amplitude.norm2() / sumSq;
311
+ if (prob > 1e-10) {
312
+ h -= prob * Math.log2(prob);
313
+ }
314
+ }
315
+
316
+ return h;
317
+ }
318
+ }
319
+
320
+ // ============================================================================
321
+ // RESONANT ATTENTION SCORE
322
+ // ============================================================================
323
+
324
+ /**
325
+ * Resonance score between two sparse prime states
326
+ * Res(i,j) = α·Jaccard(P_i, P_j) + β·QuaternionAlign + γ·PhaseCoherence
327
+ */
328
+ function resonanceScore(stateI, stateJ, alpha = 0.33, beta = 0.33, gamma = 0.34) {
329
+ const primesI = new Set(stateI.getActivePrimes());
330
+ const primesJ = new Set(stateJ.getActivePrimes());
331
+
332
+ // 1. Jaccard similarity of prime sets
333
+ const intersection = new Set([...primesI].filter(p => primesJ.has(p)));
334
+ const union = new Set([...primesI, ...primesJ]);
335
+ const jaccard = intersection.size / (union.size || 1);
336
+
337
+ if (intersection.size === 0) {
338
+ return alpha * jaccard; // No overlap, just return Jaccard
339
+ }
340
+
341
+ // 2. Quaternion alignment on overlapping primes
342
+ let quatSum = 0;
343
+ for (const p of intersection) {
344
+ const qi = stateI.get(p).quaternion;
345
+ const qj = stateJ.get(p).quaternion;
346
+ quatSum += Math.abs(qi.dot(qj));
347
+ }
348
+ const quatAlign = quatSum / intersection.size;
349
+
350
+ // 3. Phase coherence on overlapping primes
351
+ let phaseSum = 0;
352
+ for (const p of intersection) {
353
+ const phaseI = stateI.get(p).amplitude.phase();
354
+ const phaseJ = stateJ.get(p).amplitude.phase();
355
+ phaseSum += Math.cos(phaseI - phaseJ);
356
+ }
357
+ const phaseCoherence = (phaseSum / intersection.size + 1) / 2; // Normalize to [0, 1]
358
+
359
+ return alpha * jaccard + beta * quatAlign + gamma * phaseCoherence;
360
+ }
361
+
362
+ /**
363
+ * Resonant attention over a set of states (replacing dot-product attention)
364
+ */
365
+ function resonantAttention(query, keys, values, temperature = 1.0) {
366
+ const n = keys.length;
367
+ if (n === 0) return null;
368
+
369
+ // Compute resonance scores
370
+ const scores = keys.map(k => resonanceScore(query, k));
371
+
372
+ // Softmax
373
+ const maxScore = Math.max(...scores);
374
+ const expScores = scores.map(s => Math.exp((s - maxScore) / temperature));
375
+ const sumExp = expScores.reduce((a, b) => a + b, 0);
376
+ const weights = expScores.map(e => e / sumExp);
377
+
378
+ // Weighted sum of values (as sparse states)
379
+ const result = new SparsePrimeState(query.allPrimes.length, query.k);
380
+
381
+ for (let i = 0; i < n; i++) {
382
+ const w = weights[i];
383
+ for (const [p, act] of values[i].activations) {
384
+ const current = result.get(p);
385
+ const newAmp = current.amplitude.add(act.amplitude.scale(w));
386
+ const newQuat = current.quaternion.add(act.quaternion.scale(w));
387
+ result.set(p, newAmp, newQuat.normalize());
388
+ }
389
+ }
390
+
391
+ return { result: result.normalize(), weights, scores };
392
+ }
393
+
394
+ // ============================================================================
395
+ // HAMILTON PRODUCT COMPOSITION (ORDER-SENSITIVE)
396
+ // ============================================================================
397
+
398
+ /**
399
+ * Compose two states using Hamilton product for quaternion mixing
400
+ * This is ORDER-SENSITIVE: compose(A, B) ≠ compose(B, A)
401
+ */
402
+ function hamiltonCompose(stateA, stateB) {
403
+ const result = new SparsePrimeState(stateA.allPrimes.length, stateA.k);
404
+
405
+ // Get union of active primes
406
+ const primesA = new Set(stateA.getActivePrimes());
407
+ const primesB = new Set(stateB.getActivePrimes());
408
+ const allPrimes = new Set([...primesA, ...primesB]);
409
+
410
+ for (const p of allPrimes) {
411
+ const actA = stateA.get(p);
412
+ const actB = stateB.get(p);
413
+
414
+ // Amplitude: multiply complex amplitudes
415
+ const newAmp = actA.amplitude.mul(actB.amplitude);
416
+
417
+ // Quaternion: Hamilton product (non-commutative!)
418
+ const newQuat = actA.quaternion.mul(actB.quaternion);
419
+
420
+ result.set(p, newAmp, newQuat.normalize());
421
+ }
422
+
423
+ return result.normalize();
424
+ }
425
+
426
+ /**
427
+ * Measure non-commutativity between two states
428
+ * Returns the average commutator norm over shared primes
429
+ */
430
+ function measureNonCommutativity(stateA, stateB) {
431
+ const primesA = new Set(stateA.getActivePrimes());
432
+ const primesB = new Set(stateB.getActivePrimes());
433
+ const shared = [...primesA].filter(p => primesB.has(p));
434
+
435
+ if (shared.length === 0) return 0;
436
+
437
+ let totalCommNorm = 0;
438
+ for (const p of shared) {
439
+ const qA = stateA.get(p).quaternion;
440
+ const qB = stateB.get(p).quaternion;
441
+ totalCommNorm += qA.commutatorNorm(qB);
442
+ }
443
+
444
+ return totalCommNorm / shared.length;
445
+ }
446
+
447
+ // ============================================================================
448
+ // COHERENCE-GATED HALTING (ACT-STYLE)
449
+ // ============================================================================
450
+
451
+ /**
452
+ * Coherence function for a sparse prime state
453
+ * C = Σ_{p,q ∈ P_t} w_pq · cos(θ_p - θ_q)
454
+ */
455
+ function computeCoherence(state, weights = null) {
456
+ const primes = state.getActivePrimes();
457
+ const n = primes.length;
458
+
459
+ if (n < 2) return 1.0; // Single or no prime = fully coherent
460
+
461
+ let sum = 0;
462
+ let count = 0;
463
+
464
+ for (let i = 0; i < n; i++) {
465
+ for (let j = i + 1; j < n; j++) {
466
+ const phaseI = state.get(primes[i]).amplitude.phase();
467
+ const phaseJ = state.get(primes[j]).amplitude.phase();
468
+ const w = weights ? weights[i * n + j] : 1;
469
+ sum += w * Math.cos(phaseI - phaseJ);
470
+ count++;
471
+ }
472
+ }
473
+
474
+ return (sum / count + 1) / 2; // Normalize to [0, 1]
475
+ }
476
+
477
+ /**
478
+ * Adaptive Computation Time (ACT) halting decision
479
+ * Returns { halt: boolean, probability: number, coherence: number }
480
+ */
481
+ function haltingDecision(state, threshold = 0.8, epsilon = 0.1) {
482
+ const coherence = computeCoherence(state);
483
+ const haltProbability = 1 / (1 + Math.exp(-(coherence - threshold) / epsilon));
484
+ const halt = Math.random() < haltProbability;
485
+
486
+ return { halt, probability: haltProbability, coherence };
487
+ }
488
+
489
+ /**
490
+ * Run computation with coherence-gated halting
491
+ * stepFn: (state, step) => newState
492
+ * Returns { finalState, steps, haltHistory }
493
+ */
494
+ function coherenceGatedCompute(initialState, stepFn, maxSteps = 100, threshold = 0.8) {
495
+ let state = initialState;
496
+ const history = [];
497
+
498
+ for (let step = 0; step < maxSteps; step++) {
499
+ const decision = haltingDecision(state, threshold);
500
+ history.push({ step, ...decision });
501
+
502
+ if (decision.halt) {
503
+ return { finalState: state, steps: step + 1, haltHistory: history, halted: true };
504
+ }
505
+
506
+ state = stepFn(state, step);
507
+ }
508
+
509
+ return { finalState: state, steps: maxSteps, haltHistory: history, halted: false };
510
+ }
511
+
512
+ // ============================================================================
513
+ // ENTROPY COLLAPSE HEAD (64-CODEBOOK)
514
+ // ============================================================================
515
+
516
+ /**
517
+ * Generate 64 attractor states (I-Ching style codebook)
518
+ */
519
+ function generateAttractorCodebook(numPrimes = 4096) {
520
+ const attractors = [];
521
+ const basePrimes = firstNPrimes(64); // First 64 primes as canonical bases
522
+
523
+ for (let i = 0; i < 64; i++) {
524
+ const state = new SparsePrimeState(numPrimes, 8);
525
+
526
+ // Each attractor activates 8 primes based on its index (6 bits)
527
+ for (let bit = 0; bit < 6; bit++) {
528
+ if ((i >> bit) & 1) {
529
+ const p = basePrimes[bit * 10 + (i % 10)]; // Spread across primes
530
+ const phase = 2 * Math.PI * bit / 6;
531
+ state.set(p, Complex.fromPolar(1/Math.sqrt(6), phase), Quaternion.random());
532
+ }
533
+ }
534
+
535
+ state.normalize();
536
+ attractors.push({ index: i, state });
537
+ }
538
+
539
+ return attractors;
540
+ }
541
+
542
+ /**
543
+ * Entropy collapse head: project to nearest attractor
544
+ */
545
+ class EntropyCollapseHead {
546
+ constructor(targetEntropy = 5.99) {
547
+ this.attractors = generateAttractorCodebook();
548
+ this.targetEntropy = targetEntropy;
549
+ }
550
+
551
+ /**
552
+ * Compute logits over attractors using resonance score
553
+ */
554
+ computeLogits(state) {
555
+ return this.attractors.map(a => resonanceScore(state, a.state));
556
+ }
557
+
558
+ /**
559
+ * Soft assignment (training mode)
560
+ */
561
+ softAssign(state, temperature = 1.0) {
562
+ const logits = this.computeLogits(state);
563
+ const maxLogit = Math.max(...logits);
564
+ const expLogits = logits.map(l => Math.exp((l - maxLogit) / temperature));
565
+ const sumExp = expLogits.reduce((a, b) => a + b, 0);
566
+ const probs = expLogits.map(e => e / sumExp);
567
+
568
+ return { logits, probs, entropy: this.computeEntropyFromProbs(probs) };
569
+ }
570
+
571
+ /**
572
+ * Hard assignment (inference mode)
573
+ */
574
+ hardAssign(state) {
575
+ const logits = this.computeLogits(state);
576
+ const maxIdx = logits.indexOf(Math.max(...logits));
577
+ return { index: maxIdx, attractor: this.attractors[maxIdx], confidence: logits[maxIdx] };
578
+ }
579
+
580
+ /**
581
+ * Compute entropy from probability distribution
582
+ */
583
+ computeEntropyFromProbs(probs) {
584
+ let h = 0;
585
+ for (const p of probs) {
586
+ if (p > 1e-10) {
587
+ h -= p * Math.log2(p);
588
+ }
589
+ }
590
+ return h;
591
+ }
592
+
593
+ /**
594
+ * Entropy regularization loss (toward target)
595
+ */
596
+ entropyLoss(state) {
597
+ const { entropy } = this.softAssign(state);
598
+ return Math.abs(entropy - this.targetEntropy);
599
+ }
600
+ }
601
+
602
+ // ============================================================================
603
+ // PR-GRAPH MEMORY (PUT/GET)
604
+ // ============================================================================
605
+
606
+ /**
607
+ * Prime Resonant Graph Database
608
+ * Persistent content-addressable memory with resonance-based retrieval
609
+ */
610
+ class PRGraphMemory {
611
+ constructor(numPrimes = 4096, lockThreshold = 0.8) {
612
+ this.allPrimes = firstNPrimes(numPrimes);
613
+ this.entries = new Map(); // key: hash -> {state, metadata, entropy, locked}
614
+ this.lockThreshold = lockThreshold;
615
+ this.decayRate = 0.1;
616
+ }
617
+
618
+ /**
619
+ * Generate prime-entropy hash for a key
620
+ */
621
+ _primeEntropyHash(key) {
622
+ let hash = 0;
623
+ for (let i = 0; i < key.length; i++) {
624
+ hash = ((hash << 5) - hash + key.charCodeAt(i)) | 0;
625
+ }
626
+ return Math.abs(hash);
627
+ }
628
+
629
+ /**
630
+ * PRG-Put: Write to memory
631
+ * 1. Prime-entropy hash selects k primes
632
+ * 2. Phase-code payload onto those primes
633
+ * 3. Store the superposition
634
+ */
635
+ put(key, state, metadata = {}) {
636
+ const hash = this._primeEntropyHash(key);
637
+
638
+ // Initial entropy (starts high, will decay toward lock)
639
+ const entropy = state.entropy();
640
+
641
+ this.entries.set(hash, {
642
+ key,
643
+ state,
644
+ metadata,
645
+ entropy,
646
+ locked: false,
647
+ createdAt: Date.now(),
648
+ accessCount: 0
649
+ });
650
+
651
+ return hash;
652
+ }
653
+
654
+ /**
655
+ * PRG-Get: Read from memory
656
+ * 1. Generate probe from query
657
+ * 2. Compute resonance overlap with all entries
658
+ * 3. Lock by entropy-guided resonance
659
+ * 4. Return best match
660
+ */
661
+ get(query, topK = 1) {
662
+ if (this.entries.size === 0) return [];
663
+
664
+ const results = [];
665
+
666
+ for (const [hash, entry] of this.entries) {
667
+ const score = resonanceScore(query, entry.state);
668
+
669
+ // Apply entropy decay
670
+ entry.entropy *= (1 - this.decayRate);
671
+
672
+ // Check lock condition: low entropy + high resonance
673
+ if (entry.entropy < 0.5 && score > this.lockThreshold) {
674
+ entry.locked = true;
675
+ }
676
+
677
+ entry.accessCount++;
678
+
679
+ results.push({
680
+ hash,
681
+ key: entry.key,
682
+ score,
683
+ state: entry.state,
684
+ metadata: entry.metadata,
685
+ locked: entry.locked,
686
+ entropy: entry.entropy
687
+ });
688
+ }
689
+
690
+ // Sort by score
691
+ results.sort((a, b) => b.score - a.score);
692
+
693
+ return results.slice(0, topK);
694
+ }
695
+
696
+ /**
697
+ * Delete by hash
698
+ */
699
+ delete(hash) {
700
+ return this.entries.delete(hash);
701
+ }
702
+
703
+ /**
704
+ * Get all locked entries (stable memories)
705
+ */
706
+ getLockedMemories() {
707
+ return Array.from(this.entries.values()).filter(e => e.locked);
708
+ }
709
+
710
+ /**
711
+ * CRT reconstruction (for distributed storage)
712
+ */
713
+ reconstructFromResidues(residues, primes) {
714
+ // Chinese Remainder Theorem reconstruction
715
+ // residues[i] ≡ value (mod primes[i])
716
+ let M = 1;
717
+ for (const p of primes) M *= p;
718
+
719
+ let result = 0;
720
+ for (let i = 0; i < primes.length; i++) {
721
+ const Mi = M / primes[i];
722
+ const yi = this._modInverse(Mi, primes[i]);
723
+ result = (result + residues[i] * Mi * yi) % M;
724
+ }
725
+
726
+ return result;
727
+ }
728
+
729
+ _modInverse(a, m) {
730
+ let [old_r, r] = [a, m];
731
+ let [old_s, s] = [1, 0];
732
+
733
+ while (r !== 0) {
734
+ const quotient = Math.floor(old_r / r);
735
+ [old_r, r] = [r, old_r - quotient * r];
736
+ [old_s, s] = [s, old_s - quotient * s];
737
+ }
738
+
739
+ return ((old_s % m) + m) % m;
740
+ }
741
+
742
+ /**
743
+ * Memory statistics
744
+ */
745
+ stats() {
746
+ const total = this.entries.size;
747
+ const locked = this.getLockedMemories().length;
748
+ const avgEntropy = total > 0
749
+ ? Array.from(this.entries.values()).reduce((s, e) => s + e.entropy, 0) / total
750
+ : 0;
751
+
752
+ return { total, locked, avgEntropy };
753
+ }
754
+ }
755
+
756
+ // ============================================================================
757
+ // RESONANCE OPERATOR (PHASE ROTATION)
758
+ // ============================================================================
759
+
760
+ /**
761
+ * Resonance operator: R̂(n)|p⟩ = e^(2πi log_p(n))|p⟩
762
+ * Applies log-based phase rotation to all active primes
763
+ */
764
+ function applyResonanceOperator(state, n) {
765
+ const result = new SparsePrimeState(state.allPrimes.length, state.k);
766
+
767
+ for (const [p, act] of state.activations) {
768
+ const logPhase = 2 * Math.PI * Math.log(n) / Math.log(p);
769
+ const rotation = Complex.fromPolar(1, logPhase);
770
+ const newAmp = act.amplitude.mul(rotation);
771
+ result.set(p, newAmp, act.quaternion);
772
+ }
773
+
774
+ return result;
775
+ }
776
+
777
+ module.exports = {
778
+ // Quaternion
779
+ Quaternion,
780
+
781
+ // Sparse Prime State
782
+ SparsePrimeState,
783
+
784
+ // Attention
785
+ resonanceScore,
786
+ resonantAttention,
787
+
788
+ // Composition
789
+ hamiltonCompose,
790
+ measureNonCommutativity,
791
+
792
+ // Halting
793
+ computeCoherence,
794
+ haltingDecision,
795
+ coherenceGatedCompute,
796
+
797
+ // Collapse
798
+ EntropyCollapseHead,
799
+ generateAttractorCodebook,
800
+
801
+ // Memory
802
+ PRGraphMemory,
803
+
804
+ // Operators
805
+ applyResonanceOperator
806
+ };