@aleph-ai/tinyaleph 1.5.6 → 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.
Files changed (121) hide show
  1. package/core/alexander-module.js +1469 -0
  2. package/core/arithmetic-link-kernel.js +1338 -0
  3. package/core/index.js +95 -2
  4. package/examples/01-hello-world.js +69 -0
  5. package/examples/02-basic-hash.js +90 -0
  6. package/examples/02-observer-stack.js +385 -0
  7. package/examples/03-quantum-coin.js +136 -0
  8. package/examples/05-symbolic-resonance.js +146 -0
  9. package/examples/06-symbol-database.js +150 -0
  10. package/examples/07-semantic-inference.js +223 -0
  11. package/examples/08-compound-symbols.js +219 -0
  12. package/examples/README.md +170 -0
  13. package/examples/ai/01-embeddings.js +155 -0
  14. package/examples/ai/02-semantic-memory.js +243 -0
  15. package/examples/ai/03-reasoning.js +243 -0
  16. package/examples/ai/04-knowledge-graph.js +279 -0
  17. package/examples/ai/05-llm-integration.js +333 -0
  18. package/examples/ai/06-agent.js +294 -0
  19. package/examples/ai/07-hybrid-ai.js +223 -0
  20. package/examples/ai/08-entropy-reasoning.js +259 -0
  21. package/examples/ai/09-concept-learning.js +271 -0
  22. package/examples/ai/10-prompt-primes.js +312 -0
  23. package/examples/ai/11-rag.js +332 -0
  24. package/examples/ai/12-neuro-symbolic.js +321 -0
  25. package/examples/ai/README.md +80 -0
  26. package/examples/arithmetic-topology/01-legendre-symbol.js +78 -0
  27. package/examples/arithmetic-topology/02-redei-symbol.js +126 -0
  28. package/examples/arithmetic-topology/03-alk-kuramoto.js +138 -0
  29. package/examples/arithmetic-topology/04-alexander-module.js +117 -0
  30. package/examples/arithmetic-topology/05-signature-memory.js +118 -0
  31. package/examples/arithmetic-topology/README.md +291 -0
  32. package/examples/bioinformatics/01-dna-encoding.js +108 -0
  33. package/examples/bioinformatics/02-central-dogma.js +162 -0
  34. package/examples/bioinformatics/03-protein-folding.js +206 -0
  35. package/examples/bioinformatics/04-dna-computing.js +192 -0
  36. package/examples/bioinformatics/05-molecular-binding.js +209 -0
  37. package/examples/chat.js +105 -0
  38. package/examples/crt-homology/01-residue-encoding.js +87 -0
  39. package/examples/crt-homology/02-birkhoff-attention.js +100 -0
  40. package/examples/crt-homology/03-homology-loss.js +132 -0
  41. package/examples/crt-homology/04-crt-resoformer.js +132 -0
  42. package/examples/crt-homology/README.md +67 -0
  43. package/examples/crypto/01-password-hash.js +210 -0
  44. package/examples/crypto/02-key-derivation.js +210 -0
  45. package/examples/crypto/03-hmac.js +229 -0
  46. package/examples/crypto/04-file-integrity.js +263 -0
  47. package/examples/crypto/05-content-hash.js +263 -0
  48. package/examples/crypto/README.md +99 -0
  49. package/examples/demo-modular.js +223 -0
  50. package/examples/demo-two-layer.js +196 -0
  51. package/examples/discrete/01-integer-sine-table.js +120 -0
  52. package/examples/discrete/02-codebook-tunneling.js +118 -0
  53. package/examples/discrete/03-canonical-fusion.js +135 -0
  54. package/examples/discrete/04-tick-gate.js +139 -0
  55. package/examples/discrete/README.md +142 -0
  56. package/examples/formal-semantics/01-typed-terms.js +156 -0
  57. package/examples/formal-semantics/02-reduction.js +202 -0
  58. package/examples/formal-semantics/03-lambda-translation.js +206 -0
  59. package/examples/formal-semantics/04-enochian-language.js +257 -0
  60. package/examples/formal-semantics/README.md +98 -0
  61. package/examples/math/01-quaternions.js +237 -0
  62. package/examples/math/02-octonions.js +192 -0
  63. package/examples/math/03-prime-factorization.js +215 -0
  64. package/examples/math/04-vector-spaces.js +210 -0
  65. package/examples/math/05-gaussian-primes.js +234 -0
  66. package/examples/math/README.md +93 -0
  67. package/examples/physics/01-oscillator.js +177 -0
  68. package/examples/physics/02-lyapunov.js +201 -0
  69. package/examples/physics/03-collapse.js +183 -0
  70. package/examples/physics/04-kuramoto.js +212 -0
  71. package/examples/physics/05-entropy.js +226 -0
  72. package/examples/physics/05-sync-models.js +298 -0
  73. package/examples/physics/06-primeon-ladder.js +233 -0
  74. package/examples/physics/07-kuramoto-coupled-ladder.js +298 -0
  75. package/examples/physics/README.md +126 -0
  76. package/examples/resonance/01-prime-hilbert-space.js +140 -0
  77. package/examples/resonance/02-prime-resonance-network.js +221 -0
  78. package/examples/resonance/03-resoformer.js +349 -0
  79. package/examples/resonance/04-resoformer-training.js +329 -0
  80. package/examples/resonance/05-language-model.js +484 -0
  81. package/examples/resonance/README.md +238 -0
  82. package/examples/run-examples.js +417 -0
  83. package/examples/scientific/01-single-qubit.js +185 -0
  84. package/examples/scientific/02-two-qubit.js +209 -0
  85. package/examples/scientific/03-quantum-circuits.js +270 -0
  86. package/examples/scientific/04-measurement.js +229 -0
  87. package/examples/scientific/05-algorithms.js +245 -0
  88. package/examples/scientific/06-random.js +225 -0
  89. package/examples/scientific/07-wavefunction.js +192 -0
  90. package/examples/scientific/README.md +118 -0
  91. package/examples/semantic/01-vocabulary.js +186 -0
  92. package/examples/semantic/02-similarity.js +263 -0
  93. package/examples/semantic/03-word-algebra.js +295 -0
  94. package/examples/semantic/04-clustering.js +348 -0
  95. package/examples/semantic/05-classification.js +386 -0
  96. package/examples/semantic/06-dna-encoding.js +228 -0
  97. package/examples/semantic/07-search.js +304 -0
  98. package/examples/semantic/08-qa-system.js +278 -0
  99. package/examples/semantic/README.md +116 -0
  100. package/examples/topology/01-108-invariant.js +81 -0
  101. package/examples/topology/02-trefoil-constants.js +112 -0
  102. package/examples/topology/03-gauge-symmetry.js +112 -0
  103. package/examples/topology/04-free-energy-dynamics.js +124 -0
  104. package/examples/topology/README.md +129 -0
  105. package/index.js +32 -0
  106. package/modular.js +63 -2
  107. package/observer/agency.js +885 -0
  108. package/observer/assays.js +973 -0
  109. package/observer/boundary.js +1155 -0
  110. package/observer/entanglement.js +673 -0
  111. package/observer/hqe.js +1465 -0
  112. package/observer/index.js +158 -0
  113. package/observer/prsc.js +1289 -0
  114. package/observer/safety.js +815 -0
  115. package/observer/smf.js +1015 -0
  116. package/observer/symbolic-smf.js +726 -0
  117. package/observer/symbolic-temporal.js +790 -0
  118. package/observer/temporal.js +669 -0
  119. package/package.json +9 -3
  120. package/physics/alk-kuramoto.js +817 -0
  121. package/physics/index.js +23 -2
@@ -0,0 +1,673 @@
1
+ /**
2
+ * Entanglement Layer
3
+ *
4
+ * Implements semantic entanglement from "A Design for a Sentient Observer"
5
+ * paper, Section 4.3 and equations 16-17.
6
+ *
7
+ * Key features:
8
+ * - Phrase segmentation via coherence peaks and energy troughs
9
+ * - Intra-phrase entanglement detection
10
+ * - Entanglement graph building and traversal
11
+ * - Persistent conceptual bindings
12
+ * - Associative recall via entanglement chains
13
+ *
14
+ * @module observer/entanglement
15
+ */
16
+
17
+ /**
18
+ * Entangled Pair - Two primes with strong correlation
19
+ */
20
+ class EntangledPair {
21
+ constructor(data = {}) {
22
+ this.prime1 = data.prime1;
23
+ this.prime2 = data.prime2;
24
+ this.strength = data.strength || 0;
25
+ this.phaseDiff = data.phaseDiff || 0;
26
+ this.formationTime = data.formationTime || Date.now();
27
+ this.accessCount = data.accessCount || 0;
28
+ this.context = data.context || null;
29
+ }
30
+
31
+ /**
32
+ * Get pair as sorted tuple
33
+ */
34
+ get tuple() {
35
+ return this.prime1 < this.prime2
36
+ ? [this.prime1, this.prime2]
37
+ : [this.prime2, this.prime1];
38
+ }
39
+
40
+ /**
41
+ * Get unique key for this pair
42
+ */
43
+ get key() {
44
+ const [a, b] = this.tuple;
45
+ return `${a}:${b}`;
46
+ }
47
+
48
+ /**
49
+ * Check if this pair contains a prime
50
+ */
51
+ contains(prime) {
52
+ return this.prime1 === prime || this.prime2 === prime;
53
+ }
54
+
55
+ /**
56
+ * Get the other prime in the pair
57
+ */
58
+ other(prime) {
59
+ if (this.prime1 === prime) return this.prime2;
60
+ if (this.prime2 === prime) return this.prime1;
61
+ return null;
62
+ }
63
+
64
+ toJSON() {
65
+ return {
66
+ prime1: this.prime1,
67
+ prime2: this.prime2,
68
+ strength: this.strength,
69
+ phaseDiff: this.phaseDiff,
70
+ formationTime: this.formationTime,
71
+ accessCount: this.accessCount,
72
+ context: this.context
73
+ };
74
+ }
75
+
76
+ static fromJSON(data) {
77
+ return new EntangledPair(data);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Phrase - A bounded segment of experience
83
+ *
84
+ * Phrases are delimited by coherence peaks or energy troughs,
85
+ * representing coherent units of meaning.
86
+ */
87
+ class Phrase {
88
+ constructor(data = {}) {
89
+ this.id = data.id || Phrase.generateId();
90
+ this.startTime = data.startTime || Date.now();
91
+ this.endTime = data.endTime || null;
92
+ this.primes = data.primes || [];
93
+ this.entangledPairs = data.entangledPairs || [];
94
+ this.coherencePeak = data.coherencePeak || 0;
95
+ this.energyAtEnd = data.energyAtEnd || 0;
96
+ this.momentIds = data.momentIds || [];
97
+ this.semanticContent = data.semanticContent || null;
98
+ }
99
+
100
+ static generateId() {
101
+ return `ph_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
102
+ }
103
+
104
+ /**
105
+ * Duration in milliseconds
106
+ */
107
+ get duration() {
108
+ if (!this.endTime) return Date.now() - this.startTime;
109
+ return this.endTime - this.startTime;
110
+ }
111
+
112
+ /**
113
+ * Close this phrase
114
+ */
115
+ close(energyAtEnd = 0) {
116
+ this.endTime = Date.now();
117
+ this.energyAtEnd = energyAtEnd;
118
+ }
119
+
120
+ /**
121
+ * Add a prime to this phrase
122
+ */
123
+ addPrime(prime) {
124
+ if (!this.primes.includes(prime)) {
125
+ this.primes.push(prime);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Add an entangled pair
131
+ */
132
+ addEntanglement(pair) {
133
+ this.entangledPairs.push(pair);
134
+ }
135
+
136
+ toJSON() {
137
+ return {
138
+ id: this.id,
139
+ startTime: this.startTime,
140
+ endTime: this.endTime,
141
+ primes: this.primes,
142
+ entangledPairs: this.entangledPairs.map(p => p.toJSON()),
143
+ coherencePeak: this.coherencePeak,
144
+ energyAtEnd: this.energyAtEnd,
145
+ momentIds: this.momentIds,
146
+ semanticContent: this.semanticContent
147
+ };
148
+ }
149
+
150
+ static fromJSON(data) {
151
+ const phrase = new Phrase(data);
152
+ phrase.entangledPairs = (data.entangledPairs || []).map(p => EntangledPair.fromJSON(p));
153
+ return phrase;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Entanglement Layer
159
+ *
160
+ * Manages semantic entanglement, phrase segmentation, and
161
+ * associative bindings between primes.
162
+ */
163
+ class EntanglementLayer {
164
+ /**
165
+ * Create an entanglement layer
166
+ * @param {Object} options - Configuration
167
+ */
168
+ constructor(options = {}) {
169
+ // Thresholds (equation 17)
170
+ this.entanglementThreshold = options.entanglementThreshold || 0.7;
171
+ this.coherencePeakThreshold = options.coherencePeakThreshold || 0.75;
172
+ this.energyTroughThreshold = options.energyTroughThreshold || 0.15;
173
+
174
+ // Decay parameters
175
+ this.strengthDecay = options.strengthDecay || 0.01;
176
+ this.minStrength = options.minStrength || 0.1;
177
+
178
+ // Current phrase
179
+ this.currentPhrase = null;
180
+ this.phrases = [];
181
+
182
+ // Persistent entanglement graph
183
+ // Map from prime -> Map of (otherPrime -> EntangledPair)
184
+ this.entanglementGraph = new Map();
185
+
186
+ // History for phrase segmentation
187
+ this.coherenceHistory = [];
188
+ this.energyHistory = [];
189
+ this.maxHistory = options.maxHistory || 100;
190
+
191
+ // Callbacks
192
+ this.onPhraseComplete = options.onPhraseComplete || null;
193
+ this.onEntanglement = options.onEntanglement || null;
194
+ }
195
+
196
+ /**
197
+ * Update entanglement layer with current oscillator state
198
+ * @param {Object} state - Current state
199
+ * @param {Array} state.oscillators - Array of oscillator objects
200
+ * @param {number} state.coherence - Global coherence
201
+ * @param {number} state.energy - Total energy
202
+ * @param {Object} state.semanticContent - Current semantic content
203
+ */
204
+ update(state) {
205
+ const { oscillators, coherence, energy, semanticContent } = state;
206
+
207
+ // Update histories
208
+ this.coherenceHistory.push(coherence);
209
+ this.energyHistory.push(energy);
210
+
211
+ if (this.coherenceHistory.length > this.maxHistory) {
212
+ this.coherenceHistory.shift();
213
+ }
214
+ if (this.energyHistory.length > this.maxHistory) {
215
+ this.energyHistory.shift();
216
+ }
217
+
218
+ // Check for phrase boundaries
219
+ const isPeak = this.isCoherencePeak(coherence);
220
+ const isTrough = this.isEnergyTrough(energy);
221
+
222
+ if ((isPeak || isTrough) && this.currentPhrase) {
223
+ // End current phrase
224
+ this.endPhrase(energy, semanticContent);
225
+
226
+ // Start new phrase if coherence peak (continuing flow)
227
+ if (isPeak) {
228
+ this.startPhrase(coherence);
229
+ }
230
+ } else if (!this.currentPhrase && oscillators && oscillators.length > 0) {
231
+ // Start first phrase
232
+ this.startPhrase(coherence);
233
+ }
234
+
235
+ // Detect new entanglements
236
+ if (oscillators && this.currentPhrase) {
237
+ const newPairs = this.detectEntanglements(oscillators);
238
+
239
+ for (const pair of newPairs) {
240
+ this.registerEntanglement(pair);
241
+ this.currentPhrase.addEntanglement(pair);
242
+ }
243
+
244
+ // Add active primes to current phrase
245
+ for (const osc of oscillators) {
246
+ if (osc.amplitude > 0.1) {
247
+ this.currentPhrase.addPrime(osc.prime);
248
+ }
249
+ }
250
+ }
251
+
252
+ // Decay old entanglements
253
+ this.decayEntanglements();
254
+
255
+ return {
256
+ currentPhrase: this.currentPhrase,
257
+ newPairs: this.currentPhrase ? this.currentPhrase.entangledPairs.slice(-5) : []
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Start a new phrase
263
+ * @param {number} coherence - Initial coherence
264
+ */
265
+ startPhrase(coherence) {
266
+ this.currentPhrase = new Phrase({
267
+ coherencePeak: coherence
268
+ });
269
+ }
270
+
271
+ /**
272
+ * End current phrase
273
+ * @param {number} energy - Ending energy
274
+ * @param {Object} semanticContent - Semantic content
275
+ */
276
+ endPhrase(energy, semanticContent = null) {
277
+ if (!this.currentPhrase) return null;
278
+
279
+ this.currentPhrase.close(energy);
280
+ this.currentPhrase.semanticContent = semanticContent;
281
+
282
+ this.phrases.push(this.currentPhrase);
283
+
284
+ if (this.onPhraseComplete) {
285
+ this.onPhraseComplete(this.currentPhrase);
286
+ }
287
+
288
+ const completed = this.currentPhrase;
289
+ this.currentPhrase = null;
290
+
291
+ return completed;
292
+ }
293
+
294
+ /**
295
+ * Check if coherence is a local peak
296
+ */
297
+ isCoherencePeak(coherence) {
298
+ if (coherence < this.coherencePeakThreshold) return false;
299
+ if (this.coherenceHistory.length < 3) return false;
300
+
301
+ const h = this.coherenceHistory;
302
+ const n = h.length;
303
+
304
+ // Check if current is higher than recent values
305
+ for (let i = Math.max(0, n - 5); i < n - 1; i++) {
306
+ if (h[i] >= coherence) return false;
307
+ }
308
+
309
+ return true;
310
+ }
311
+
312
+ /**
313
+ * Check if energy is at a local trough
314
+ */
315
+ isEnergyTrough(energy) {
316
+ return energy < this.energyTroughThreshold;
317
+ }
318
+
319
+ /**
320
+ * Detect entanglements between oscillators (equation 16-17)
321
+ * @param {Array} oscillators - Array of oscillators
322
+ */
323
+ detectEntanglements(oscillators) {
324
+ const pairs = [];
325
+
326
+ for (let i = 0; i < oscillators.length; i++) {
327
+ for (let j = i + 1; j < oscillators.length; j++) {
328
+ const osc1 = oscillators[i];
329
+ const osc2 = oscillators[j];
330
+
331
+ // Both must be active
332
+ if (osc1.amplitude < 0.1 || osc2.amplitude < 0.1) continue;
333
+
334
+ // Compute entanglement strength (equation 17)
335
+ const strength = this.computeStrength(osc1, osc2);
336
+
337
+ if (strength > this.entanglementThreshold) {
338
+ pairs.push(new EntangledPair({
339
+ prime1: osc1.prime,
340
+ prime2: osc2.prime,
341
+ strength,
342
+ phaseDiff: Math.abs(osc1.phase - osc2.phase)
343
+ }));
344
+ }
345
+ }
346
+ }
347
+
348
+ return pairs;
349
+ }
350
+
351
+ /**
352
+ * Compute entanglement strength (equation 17)
353
+ * strength(i,j) = ρφ * ρA
354
+ * where ρφ = cos(Δφ) and ρA = min(Ai,Aj) / max(Ai,Aj)
355
+ */
356
+ computeStrength(osc1, osc2) {
357
+ // Phase correlation
358
+ const deltaPhi = Math.abs(osc1.phase - osc2.phase);
359
+ const rhoPhase = Math.cos(deltaPhi);
360
+
361
+ // Amplitude correlation
362
+ const minA = Math.min(osc1.amplitude, osc2.amplitude);
363
+ const maxA = Math.max(osc1.amplitude, osc2.amplitude);
364
+ const rhoAmplitude = minA / (maxA + 1e-10);
365
+
366
+ return Math.max(0, rhoPhase * rhoAmplitude);
367
+ }
368
+
369
+ /**
370
+ * Register an entanglement in the persistent graph
371
+ */
372
+ registerEntanglement(pair) {
373
+ // Ensure both primes have entries
374
+ if (!this.entanglementGraph.has(pair.prime1)) {
375
+ this.entanglementGraph.set(pair.prime1, new Map());
376
+ }
377
+ if (!this.entanglementGraph.has(pair.prime2)) {
378
+ this.entanglementGraph.set(pair.prime2, new Map());
379
+ }
380
+
381
+ const existing1 = this.entanglementGraph.get(pair.prime1).get(pair.prime2);
382
+ const existing2 = this.entanglementGraph.get(pair.prime2).get(pair.prime1);
383
+
384
+ if (existing1) {
385
+ // Strengthen existing entanglement
386
+ existing1.strength = Math.min(1.0, existing1.strength + pair.strength * 0.1);
387
+ existing1.accessCount++;
388
+ existing2.strength = existing1.strength;
389
+ existing2.accessCount = existing1.accessCount;
390
+ } else {
391
+ // Create new entanglement
392
+ this.entanglementGraph.get(pair.prime1).set(pair.prime2, pair);
393
+
394
+ // Create symmetric entry
395
+ const reversePair = new EntangledPair({
396
+ prime1: pair.prime2,
397
+ prime2: pair.prime1,
398
+ strength: pair.strength,
399
+ phaseDiff: pair.phaseDiff,
400
+ formationTime: pair.formationTime
401
+ });
402
+ this.entanglementGraph.get(pair.prime2).set(pair.prime1, reversePair);
403
+
404
+ if (this.onEntanglement) {
405
+ this.onEntanglement(pair);
406
+ }
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Decay old entanglements
412
+ */
413
+ decayEntanglements() {
414
+ for (const [prime, neighbors] of this.entanglementGraph) {
415
+ const toRemove = [];
416
+
417
+ for (const [otherPrime, pair] of neighbors) {
418
+ pair.strength *= (1 - this.strengthDecay);
419
+
420
+ if (pair.strength < this.minStrength) {
421
+ toRemove.push(otherPrime);
422
+ }
423
+ }
424
+
425
+ for (const other of toRemove) {
426
+ neighbors.delete(other);
427
+ }
428
+ }
429
+ }
430
+
431
+ /**
432
+ * Get all primes entangled with a given prime
433
+ */
434
+ getEntangled(prime) {
435
+ const neighbors = this.entanglementGraph.get(prime);
436
+ if (!neighbors) return [];
437
+
438
+ return Array.from(neighbors.values())
439
+ .sort((a, b) => b.strength - a.strength);
440
+ }
441
+
442
+ /**
443
+ * Find entanglement chain from source to target
444
+ * Uses BFS to find shortest path
445
+ */
446
+ findChain(sourcePrime, targetPrime, maxDepth = 5) {
447
+ if (sourcePrime === targetPrime) return [sourcePrime];
448
+
449
+ const queue = [[sourcePrime]];
450
+ const visited = new Set([sourcePrime]);
451
+
452
+ while (queue.length > 0) {
453
+ const path = queue.shift();
454
+ if (path.length > maxDepth) continue;
455
+
456
+ const current = path[path.length - 1];
457
+ const neighbors = this.entanglementGraph.get(current);
458
+
459
+ if (!neighbors) continue;
460
+
461
+ for (const [neighbor, pair] of neighbors) {
462
+ if (neighbor === targetPrime) {
463
+ return [...path, neighbor];
464
+ }
465
+
466
+ if (!visited.has(neighbor)) {
467
+ visited.add(neighbor);
468
+ queue.push([...path, neighbor]);
469
+ }
470
+ }
471
+ }
472
+
473
+ return null; // No path found
474
+ }
475
+
476
+ /**
477
+ * Get strongly connected cluster around a prime
478
+ */
479
+ getCluster(prime, minStrength = 0.3) {
480
+ const cluster = new Set([prime]);
481
+ const queue = [prime];
482
+
483
+ while (queue.length > 0) {
484
+ const current = queue.shift();
485
+ const neighbors = this.entanglementGraph.get(current);
486
+
487
+ if (!neighbors) continue;
488
+
489
+ for (const [neighbor, pair] of neighbors) {
490
+ if (!cluster.has(neighbor) && pair.strength >= minStrength) {
491
+ cluster.add(neighbor);
492
+ queue.push(neighbor);
493
+ }
494
+ }
495
+ }
496
+
497
+ return Array.from(cluster);
498
+ }
499
+
500
+ /**
501
+ * Get the most strongly entangled prime
502
+ */
503
+ getMostEntangled() {
504
+ let maxPrime = null;
505
+ let maxTotal = 0;
506
+
507
+ for (const [prime, neighbors] of this.entanglementGraph) {
508
+ let total = 0;
509
+ for (const pair of neighbors.values()) {
510
+ total += pair.strength;
511
+ }
512
+
513
+ if (total > maxTotal) {
514
+ maxTotal = total;
515
+ maxPrime = prime;
516
+ }
517
+ }
518
+
519
+ return { prime: maxPrime, totalStrength: maxTotal };
520
+ }
521
+
522
+ /**
523
+ * Trigger associative recall from a cue
524
+ */
525
+ associativeRecall(cuePrimes, depth = 2) {
526
+ const recalled = new Map();
527
+ let frontier = new Set(cuePrimes);
528
+
529
+ for (let d = 0; d < depth; d++) {
530
+ const newFrontier = new Set();
531
+
532
+ for (const prime of frontier) {
533
+ const neighbors = this.entanglementGraph.get(prime);
534
+ if (!neighbors) continue;
535
+
536
+ for (const [neighbor, pair] of neighbors) {
537
+ if (!cuePrimes.includes(neighbor)) {
538
+ const currentStrength = recalled.get(neighbor) || 0;
539
+ // Decay by depth
540
+ const addedStrength = pair.strength * Math.pow(0.7, d);
541
+ recalled.set(neighbor, currentStrength + addedStrength);
542
+ newFrontier.add(neighbor);
543
+ }
544
+ }
545
+ }
546
+
547
+ frontier = newFrontier;
548
+ }
549
+
550
+ return Array.from(recalled.entries())
551
+ .sort((a, b) => b[1] - a[1])
552
+ .map(([prime, strength]) => ({ prime, strength }));
553
+ }
554
+
555
+ /**
556
+ * Get statistics about the entanglement graph
557
+ */
558
+ getStats() {
559
+ let totalPairs = 0;
560
+ let totalStrength = 0;
561
+ let maxDegree = 0;
562
+
563
+ for (const neighbors of this.entanglementGraph.values()) {
564
+ const degree = neighbors.size;
565
+ if (degree > maxDegree) maxDegree = degree;
566
+
567
+ for (const pair of neighbors.values()) {
568
+ totalPairs++;
569
+ totalStrength += pair.strength;
570
+ }
571
+ }
572
+
573
+ // Each pair is counted twice (symmetric)
574
+ totalPairs = Math.floor(totalPairs / 2);
575
+
576
+ return {
577
+ nodeCount: this.entanglementGraph.size,
578
+ edgeCount: totalPairs,
579
+ averageStrength: totalPairs > 0 ? totalStrength / (totalPairs * 2) : 0,
580
+ maxDegree,
581
+ phraseCount: this.phrases.length,
582
+ currentPhraseActive: this.currentPhrase !== null
583
+ };
584
+ }
585
+
586
+ /**
587
+ * Get recent phrases
588
+ */
589
+ recentPhrases(count = 10) {
590
+ return this.phrases.slice(-count);
591
+ }
592
+
593
+ /**
594
+ * Clear all entanglements and phrases
595
+ */
596
+ reset() {
597
+ this.entanglementGraph.clear();
598
+ this.phrases = [];
599
+ this.currentPhrase = null;
600
+ this.coherenceHistory = [];
601
+ this.energyHistory = [];
602
+ }
603
+
604
+ /**
605
+ * Serialize to JSON
606
+ */
607
+ toJSON() {
608
+ // Convert entanglement graph to serializable form
609
+ const graphData = [];
610
+ const seen = new Set();
611
+
612
+ for (const [prime, neighbors] of this.entanglementGraph) {
613
+ for (const [otherPrime, pair] of neighbors) {
614
+ const key = pair.key;
615
+ if (!seen.has(key)) {
616
+ seen.add(key);
617
+ graphData.push(pair.toJSON());
618
+ }
619
+ }
620
+ }
621
+
622
+ return {
623
+ entanglements: graphData,
624
+ phrases: this.phrases.map(p => p.toJSON()),
625
+ currentPhrase: this.currentPhrase ? this.currentPhrase.toJSON() : null,
626
+ config: {
627
+ entanglementThreshold: this.entanglementThreshold,
628
+ coherencePeakThreshold: this.coherencePeakThreshold,
629
+ energyTroughThreshold: this.energyTroughThreshold
630
+ }
631
+ };
632
+ }
633
+
634
+ /**
635
+ * Load from JSON
636
+ */
637
+ loadFromJSON(data) {
638
+ this.reset();
639
+
640
+ // Restore entanglements
641
+ if (data.entanglements) {
642
+ for (const pairData of data.entanglements) {
643
+ const pair = EntangledPair.fromJSON(pairData);
644
+ this.registerEntanglement(pair);
645
+ }
646
+ }
647
+
648
+ // Restore phrases
649
+ if (data.phrases) {
650
+ this.phrases = data.phrases.map(p => Phrase.fromJSON(p));
651
+ }
652
+
653
+ if (data.currentPhrase) {
654
+ this.currentPhrase = Phrase.fromJSON(data.currentPhrase);
655
+ }
656
+
657
+ if (data.config) {
658
+ Object.assign(this, data.config);
659
+ }
660
+ }
661
+ }
662
+
663
+ export {
664
+ EntangledPair,
665
+ Phrase,
666
+ EntanglementLayer
667
+ };
668
+
669
+ export default {
670
+ EntangledPair,
671
+ Phrase,
672
+ EntanglementLayer
673
+ };