@aleph-ai/tinyaleph 1.2.0 → 1.3.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 (35) hide show
  1. package/README.md +187 -2
  2. package/backends/bioinformatics/binding.js +503 -0
  3. package/backends/bioinformatics/dna-computing.js +664 -0
  4. package/backends/bioinformatics/encoding.js +339 -0
  5. package/backends/bioinformatics/folding.js +454 -0
  6. package/backends/bioinformatics/genetic-code.js +269 -0
  7. package/backends/bioinformatics/index.js +522 -0
  8. package/backends/bioinformatics/transcription.js +221 -0
  9. package/backends/bioinformatics/translation.js +264 -0
  10. package/backends/index.js +25 -1
  11. package/core/compound.js +532 -0
  12. package/core/hilbert.js +454 -1
  13. package/core/index.js +106 -12
  14. package/core/inference.js +605 -0
  15. package/core/resonance.js +245 -616
  16. package/core/symbols/archetypes.js +478 -0
  17. package/core/symbols/base.js +302 -0
  18. package/core/symbols/elements.js +487 -0
  19. package/core/symbols/hieroglyphs.js +303 -0
  20. package/core/symbols/iching.js +471 -0
  21. package/core/symbols/index.js +77 -0
  22. package/core/symbols/tarot.js +211 -0
  23. package/core/symbols.js +22 -0
  24. package/docs/design/BIOINFORMATICS_BACKEND_DESIGN.md +493 -0
  25. package/docs/guide/06-symbolic-ai.md +370 -0
  26. package/docs/guide/README.md +2 -1
  27. package/docs/reference/05-symbolic-ai.md +570 -0
  28. package/docs/reference/06-bioinformatics.md +546 -0
  29. package/docs/reference/README.md +32 -2
  30. package/docs/theory/11-prgraph-memory.md +559 -0
  31. package/docs/theory/12-resonant-attention.md +661 -0
  32. package/modular.js +33 -1
  33. package/package.json +1 -1
  34. package/physics/index.js +16 -0
  35. package/physics/kuramoto-coupled-ladder.js +603 -0
@@ -0,0 +1,503 @@
1
+ /**
2
+ * Molecular Binding - Protein-Ligand and Protein-Protein Interactions
3
+ *
4
+ * Models molecular binding using prime resonance:
5
+ * - Binding affinity correlates with golden ratio resonance
6
+ * - Docking uses multi-system Kuramoto coupling
7
+ * - Affinity scoring combines electrostatic, hydrophobic, and resonance terms
8
+ */
9
+
10
+ const {
11
+ AMINO_ACID_PRIMES,
12
+ getChargeFromPrime,
13
+ getHydrophobicityFromPrime
14
+ } = require('./encoding');
15
+
16
+ // Import core modules with fallback
17
+ let calculateResonance, findGoldenPairs, resonanceSignature, primeToFrequency, KuramotoModel;
18
+
19
+ try {
20
+ const core = require('../../core');
21
+ const physics = require('../../physics');
22
+
23
+ calculateResonance = core.calculateResonance;
24
+ findGoldenPairs = core.findGoldenPairs;
25
+ resonanceSignature = core.resonanceSignature;
26
+ primeToFrequency = core.primeToFrequency;
27
+ KuramotoModel = physics.KuramotoModel;
28
+ } catch (e) {
29
+ // Fallback implementations
30
+ const PHI = 1.618033988749895;
31
+
32
+ calculateResonance = (p1, p2) => {
33
+ const ratio = Math.max(p1, p2) / Math.min(p1, p2);
34
+ return 1 / (1 + Math.abs(ratio - PHI));
35
+ };
36
+
37
+ findGoldenPairs = (primes) => {
38
+ const pairs = [];
39
+ for (let i = 0; i < primes.length; i++) {
40
+ for (let j = i + 1; j < primes.length; j++) {
41
+ if (calculateResonance(primes[i], primes[j]) > 0.8) {
42
+ pairs.push([primes[i], primes[j]]);
43
+ }
44
+ }
45
+ }
46
+ return pairs;
47
+ };
48
+
49
+ resonanceSignature = (primes) => {
50
+ let sum = 0, count = 0;
51
+ for (let i = 0; i < primes.length; i++) {
52
+ for (let j = i + 1; j < primes.length; j++) {
53
+ sum += calculateResonance(primes[i], primes[j]);
54
+ count++;
55
+ }
56
+ }
57
+ return { mean: sum / Math.max(count, 1), count };
58
+ };
59
+
60
+ primeToFrequency = (p, base = 1, logScale = 10) => base + Math.log(p) / logScale;
61
+ }
62
+
63
+ /**
64
+ * BindingAffinityCalculator
65
+ *
66
+ * Computes molecular binding using prime resonance scoring
67
+ */
68
+ class BindingAffinityCalculator {
69
+ constructor(options = {}) {
70
+ this.options = {
71
+ resonanceWeight: options.resonanceWeight || 0.4,
72
+ electrostaticWeight: options.electrostaticWeight || 0.3,
73
+ hydrophobicWeight: options.hydrophobicWeight || 0.3,
74
+ goldenBonus: options.goldenBonus || 0.1,
75
+ ...options
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Compute binding affinity between two molecules
81
+ * @param {number[]} mol1Primes - First molecule as prime array
82
+ * @param {number[]} mol2Primes - Second molecule as prime array
83
+ * @returns {object} Binding affinity result
84
+ */
85
+ computeAffinity(mol1Primes, mol2Primes) {
86
+ const interactions = [];
87
+ let totalScore = 0;
88
+
89
+ for (let i = 0; i < mol1Primes.length; i++) {
90
+ for (let j = 0; j < mol2Primes.length; j++) {
91
+ const p1 = mol1Primes[i];
92
+ const p2 = mol2Primes[j];
93
+
94
+ // Calculate interaction components
95
+ const resonance = calculateResonance(p1, p2);
96
+ const electrostatic = this.electrostaticInteraction(p1, p2);
97
+ const hydrophobic = this.hydrophobicInteraction(p1, p2);
98
+
99
+ const pairScore =
100
+ this.options.resonanceWeight * resonance +
101
+ this.options.electrostaticWeight * electrostatic +
102
+ this.options.hydrophobicWeight * hydrophobic;
103
+
104
+ if (pairScore > 0.2) {
105
+ interactions.push({
106
+ residue1: i,
107
+ residue2: j,
108
+ prime1: p1,
109
+ prime2: p2,
110
+ score: pairScore,
111
+ resonance,
112
+ electrostatic,
113
+ hydrophobic
114
+ });
115
+ totalScore += pairScore;
116
+ }
117
+ }
118
+ }
119
+
120
+ // Golden ratio bonus
121
+ const allPrimes = [...mol1Primes, ...mol2Primes];
122
+ const goldenPairs = findGoldenPairs(allPrimes);
123
+ const goldenBonus = goldenPairs.length * this.options.goldenBonus;
124
+
125
+ // Normalize by interface size
126
+ const interfaceSize = mol1Primes.length * mol2Primes.length;
127
+ const normalizedAffinity = (totalScore / interfaceSize) + goldenBonus;
128
+
129
+ // Convert to binding energy (kcal/mol approximation)
130
+ const bindingEnergy = -1.98 * 300 * Math.log(Math.max(normalizedAffinity, 0.01)) / 1000;
131
+
132
+ // Resonance signature of the complex
133
+ const signature = resonanceSignature(allPrimes);
134
+
135
+ return {
136
+ affinity: normalizedAffinity,
137
+ bindingEnergy,
138
+ interactions: interactions.sort((a, b) => b.score - a.score),
139
+ goldenPairs: goldenPairs.length,
140
+ interfaceSize,
141
+ resonanceSignature: signature
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Electrostatic interaction between two primes
147
+ */
148
+ electrostaticInteraction(p1, p2) {
149
+ const q1 = getChargeFromPrime(p1);
150
+ const q2 = getChargeFromPrime(p2);
151
+
152
+ if (q1 * q2 < 0) return 1.0; // Opposite charges attract
153
+ if (q1 * q2 > 0) return -0.5; // Same charges repel
154
+ return 0;
155
+ }
156
+
157
+ /**
158
+ * Hydrophobic interaction
159
+ */
160
+ hydrophobicInteraction(p1, p2) {
161
+ const h1 = getHydrophobicityFromPrime(p1);
162
+ const h2 = getHydrophobicityFromPrime(p2);
163
+
164
+ // Like attracts like in hydrophobic effect
165
+ if (h1 > 0 && h2 > 0) {
166
+ return Math.sqrt(h1 * h2) / 5; // Both hydrophobic
167
+ }
168
+ if (h1 < 0 && h2 < 0) {
169
+ return Math.sqrt(-h1 * -h2) / 10; // Both hydrophilic
170
+ }
171
+ return -0.1; // Mixed - unfavorable
172
+ }
173
+
174
+ /**
175
+ * Screen a library of ligands against a target
176
+ */
177
+ screenLibrary(targetPrimes, ligandLibrary) {
178
+ return ligandLibrary
179
+ .map(ligand => ({
180
+ id: ligand.id,
181
+ name: ligand.name,
182
+ ...this.computeAffinity(targetPrimes, ligand.primes)
183
+ }))
184
+ .sort((a, b) => b.affinity - a.affinity);
185
+ }
186
+
187
+ /**
188
+ * Find hotspot residues (key binding determinants)
189
+ */
190
+ findHotspots(mol1Primes, mol2Primes, threshold = 0.5) {
191
+ const affinity = this.computeAffinity(mol1Primes, mol2Primes);
192
+
193
+ // Count interactions per residue
194
+ const residueScores = {};
195
+ for (const int of affinity.interactions) {
196
+ const key1 = `mol1_${int.residue1}`;
197
+ const key2 = `mol2_${int.residue2}`;
198
+
199
+ residueScores[key1] = (residueScores[key1] || 0) + int.score;
200
+ residueScores[key2] = (residueScores[key2] || 0) + int.score;
201
+ }
202
+
203
+ // Filter hotspots above threshold
204
+ const hotspots = Object.entries(residueScores)
205
+ .filter(([_, score]) => score > threshold)
206
+ .sort((a, b) => b[1] - a[1])
207
+ .map(([residue, score]) => ({ residue, score }));
208
+
209
+ return hotspots;
210
+ }
211
+ }
212
+
213
+ /**
214
+ * MolecularDocker
215
+ *
216
+ * Docks molecules using Kuramoto oscillator synchronization
217
+ */
218
+ class MolecularDocker {
219
+ constructor(options = {}) {
220
+ this.options = {
221
+ coupling: options.coupling || 0.2,
222
+ steps: options.steps || 500,
223
+ dt: options.dt || 0.01,
224
+ ...options
225
+ };
226
+
227
+ this.affinityCalculator = new BindingAffinityCalculator(options);
228
+ }
229
+
230
+ /**
231
+ * Dock two molecules using oscillator dynamics
232
+ */
233
+ dock(receptorPrimes, ligandPrimes) {
234
+ const n1 = receptorPrimes.length;
235
+ const n2 = ligandPrimes.length;
236
+
237
+ // Initialize oscillator phases
238
+ const receptorPhases = new Array(n1).fill(0).map(() => Math.random() * 2 * Math.PI);
239
+ const ligandPhases = new Array(n2).fill(0).map(() => Math.random() * 2 * Math.PI);
240
+
241
+ // Frequencies from primes
242
+ const receptorFreqs = receptorPrimes.map(p => primeToFrequency(p, 1, 10));
243
+ const ligandFreqs = ligandPrimes.map(p => primeToFrequency(p, 1, 10));
244
+
245
+ // Cross-coupling matrix
246
+ const crossCoupling = this.computeCrossCoupling(receptorPrimes, ligandPrimes);
247
+
248
+ // Evolution
249
+ const trajectory = [];
250
+
251
+ for (let step = 0; step < this.options.steps; step++) {
252
+ // Update receptor phases
253
+ for (let i = 0; i < n1; i++) {
254
+ let dPhase = receptorFreqs[i];
255
+
256
+ // Internal coupling (within receptor)
257
+ for (let j = 0; j < n1; j++) {
258
+ if (i !== j) {
259
+ dPhase += this.options.coupling * 0.5 *
260
+ Math.sin(receptorPhases[j] - receptorPhases[i]);
261
+ }
262
+ }
263
+
264
+ // Cross coupling (receptor-ligand)
265
+ for (let j = 0; j < n2; j++) {
266
+ dPhase += crossCoupling[i][j] *
267
+ Math.sin(ligandPhases[j] - receptorPhases[i]);
268
+ }
269
+
270
+ receptorPhases[i] += dPhase * this.options.dt;
271
+ }
272
+
273
+ // Update ligand phases
274
+ for (let i = 0; i < n2; i++) {
275
+ let dPhase = ligandFreqs[i];
276
+
277
+ // Internal coupling (within ligand)
278
+ for (let j = 0; j < n2; j++) {
279
+ if (i !== j) {
280
+ dPhase += this.options.coupling * 0.5 *
281
+ Math.sin(ligandPhases[j] - ligandPhases[i]);
282
+ }
283
+ }
284
+
285
+ // Cross coupling (ligand-receptor)
286
+ for (let j = 0; j < n1; j++) {
287
+ dPhase += crossCoupling[j][i] *
288
+ Math.sin(receptorPhases[j] - ligandPhases[i]);
289
+ }
290
+
291
+ ligandPhases[i] += dPhase * this.options.dt;
292
+ }
293
+
294
+ // Record trajectory
295
+ if (step % 10 === 0) {
296
+ trajectory.push({
297
+ step,
298
+ interSystemCoherence: this.calculateCoherence(receptorPhases, ligandPhases),
299
+ receptorOrder: this.calculateOrder(receptorPhases),
300
+ ligandOrder: this.calculateOrder(ligandPhases)
301
+ });
302
+ }
303
+ }
304
+
305
+ // Extract final pose from phases
306
+ const pose = this.phasesToPose(receptorPhases, ligandPhases);
307
+
308
+ // Calculate final binding score
309
+ const bindingScore = this.calculateBindingFromPhases(
310
+ receptorPhases, ligandPhases, crossCoupling
311
+ );
312
+
313
+ return {
314
+ success: true,
315
+ receptorPhases: [...receptorPhases],
316
+ ligandPhases: [...ligandPhases],
317
+ pose,
318
+ dockingScore: bindingScore,
319
+ finalCoherence: trajectory[trajectory.length - 1]?.interSystemCoherence || 0,
320
+ trajectory
321
+ };
322
+ }
323
+
324
+ /**
325
+ * Compute cross-coupling between two molecules
326
+ */
327
+ computeCrossCoupling(primes1, primes2) {
328
+ const matrix = [];
329
+
330
+ for (let i = 0; i < primes1.length; i++) {
331
+ const row = [];
332
+ for (let j = 0; j < primes2.length; j++) {
333
+ const resonance = calculateResonance(primes1[i], primes2[j]);
334
+ row.push(resonance * this.options.coupling);
335
+ }
336
+ matrix.push(row);
337
+ }
338
+
339
+ return matrix;
340
+ }
341
+
342
+ /**
343
+ * Calculate inter-system coherence
344
+ */
345
+ calculateCoherence(phases1, phases2) {
346
+ let coherence = 0;
347
+ let count = 0;
348
+
349
+ for (const p1 of phases1) {
350
+ for (const p2 of phases2) {
351
+ coherence += Math.cos(p1 - p2);
352
+ count++;
353
+ }
354
+ }
355
+
356
+ return Math.abs(coherence / count);
357
+ }
358
+
359
+ /**
360
+ * Calculate order parameter for one system
361
+ */
362
+ calculateOrder(phases) {
363
+ let sumCos = 0, sumSin = 0;
364
+ for (const p of phases) {
365
+ sumCos += Math.cos(p);
366
+ sumSin += Math.sin(p);
367
+ }
368
+ return Math.sqrt(sumCos * sumCos + sumSin * sumSin) / phases.length;
369
+ }
370
+
371
+ /**
372
+ * Convert phases to binding pose
373
+ */
374
+ phasesToPose(receptorPhases, ligandPhases) {
375
+ // Phase differences indicate relative orientations
376
+ const meanReceptorPhase = receptorPhases.reduce((a, b) => a + b, 0) / receptorPhases.length;
377
+ const meanLigandPhase = ligandPhases.reduce((a, b) => a + b, 0) / ligandPhases.length;
378
+
379
+ return {
380
+ rotation: (meanLigandPhase - meanReceptorPhase) * 180 / Math.PI,
381
+ bindingMode: Math.abs(meanLigandPhase - meanReceptorPhase) < 0.5 ? 'aligned' : 'rotated'
382
+ };
383
+ }
384
+
385
+ /**
386
+ * Calculate binding from final phases
387
+ */
388
+ calculateBindingFromPhases(phases1, phases2, coupling) {
389
+ let score = 0;
390
+
391
+ for (let i = 0; i < phases1.length; i++) {
392
+ for (let j = 0; j < phases2.length; j++) {
393
+ const phaseDiff = Math.abs(phases1[i] - phases2[j]);
394
+ const inPhase = Math.cos(phaseDiff);
395
+ score += coupling[i][j] * (1 + inPhase) / 2;
396
+ }
397
+ }
398
+
399
+ return score / (phases1.length * phases2.length);
400
+ }
401
+ }
402
+
403
+ /**
404
+ * ProteinProteinDocker
405
+ * Specialized docker for protein-protein interactions
406
+ */
407
+ class ProteinProteinDocker extends MolecularDocker {
408
+ constructor(options = {}) {
409
+ super({
410
+ ...options,
411
+ coupling: options.coupling || 0.15,
412
+ steps: options.steps || 1000
413
+ });
414
+ }
415
+
416
+ /**
417
+ * Dock with interface prediction
418
+ */
419
+ dockWithInterface(protein1Primes, protein2Primes) {
420
+ // First, predict interface residues
421
+ const interface1 = this.predictInterface(protein1Primes);
422
+ const interface2 = this.predictInterface(protein2Primes);
423
+
424
+ // Dock using interface residues
425
+ const dockResult = this.dock(
426
+ interface1.map(i => protein1Primes[i]),
427
+ interface2.map(i => protein2Primes[i])
428
+ );
429
+
430
+ return {
431
+ ...dockResult,
432
+ interface1,
433
+ interface2,
434
+ contactMap: this.buildContactMap(
435
+ dockResult.receptorPhases,
436
+ dockResult.ligandPhases,
437
+ interface1,
438
+ interface2
439
+ )
440
+ };
441
+ }
442
+
443
+ /**
444
+ * Predict interface residues (surface exposed, interactive)
445
+ */
446
+ predictInterface(primes) {
447
+ // Interface residues tend to be:
448
+ // 1. Charged (for electrostatic interactions)
449
+ // 2. Aromatic (for stacking interactions)
450
+ // 3. At certain sequence positions
451
+
452
+ const candidates = [];
453
+
454
+ for (let i = 0; i < primes.length; i++) {
455
+ const p = primes[i];
456
+ const charge = getChargeFromPrime(p);
457
+ const isAromatic = [47, 53, 59, 97].includes(p); // F, W, Y, H
458
+
459
+ let interfaceScore = 0;
460
+ if (Math.abs(charge) > 0) interfaceScore += 0.5;
461
+ if (isAromatic) interfaceScore += 0.3;
462
+
463
+ // Check neighbors for hydrophobic patches
464
+ const neighbors = primes.slice(Math.max(0, i - 2), i + 3);
465
+ const hydrophobicPatch = neighbors.filter(p => p >= 23 && p <= 43).length >= 3;
466
+ if (hydrophobicPatch) interfaceScore += 0.2;
467
+
468
+ if (interfaceScore > 0.3) {
469
+ candidates.push(i);
470
+ }
471
+ }
472
+
473
+ return candidates;
474
+ }
475
+
476
+ /**
477
+ * Build contact map from docking
478
+ */
479
+ buildContactMap(phases1, phases2, indices1, indices2) {
480
+ const contacts = [];
481
+
482
+ for (let i = 0; i < phases1.length; i++) {
483
+ for (let j = 0; j < phases2.length; j++) {
484
+ const phaseDiff = Math.abs(phases1[i] - phases2[j]);
485
+ if (phaseDiff < 0.5 || phaseDiff > 2 * Math.PI - 0.5) {
486
+ contacts.push({
487
+ residue1: indices1[i],
488
+ residue2: indices2[j],
489
+ strength: 1 - Math.min(phaseDiff, 2 * Math.PI - phaseDiff) / 0.5
490
+ });
491
+ }
492
+ }
493
+ }
494
+
495
+ return contacts;
496
+ }
497
+ }
498
+
499
+ module.exports = {
500
+ BindingAffinityCalculator,
501
+ MolecularDocker,
502
+ ProteinProteinDocker
503
+ };