@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.
@@ -130,12 +130,512 @@ class Hypercomplex {
130
130
  .slice(0, n);
131
131
  }
132
132
 
133
+ // ============================================
134
+ // ADVANCED OPERATIONS: exp, log, pow, slerp
135
+ // ============================================
136
+
137
+ /**
138
+ * Get the scalar (real) part
139
+ */
140
+ scalar() {
141
+ return this.c[0];
142
+ }
143
+
144
+ /**
145
+ * Get the vector (imaginary) part as a new Hypercomplex with zero scalar
146
+ */
147
+ vector() {
148
+ const v = new Hypercomplex(this.dim);
149
+ for (let i = 1; i < this.dim; i++) {
150
+ v.c[i] = this.c[i];
151
+ }
152
+ return v;
153
+ }
154
+
155
+ /**
156
+ * Get the norm of the vector part only
157
+ */
158
+ vectorNorm() {
159
+ let s = 0;
160
+ for (let i = 1; i < this.dim; i++) {
161
+ s += this.c[i] * this.c[i];
162
+ }
163
+ return Math.sqrt(s);
164
+ }
165
+
166
+ /**
167
+ * Hypercomplex exponential: e^q
168
+ *
169
+ * For q = a + v (scalar a, vector v):
170
+ * exp(q) = e^a * (cos|v| + v̂·sin|v|)
171
+ *
172
+ * where v̂ = v/|v| is the unit vector direction.
173
+ *
174
+ * This generalizes:
175
+ * - Complex: e^(a+bi) = e^a(cos b + i·sin b)
176
+ * - Quaternion: e^(a+v) = e^a(cos|v| + v̂·sin|v|)
177
+ *
178
+ * @returns {Hypercomplex} The exponential
179
+ */
180
+ exp() {
181
+ const a = this.c[0]; // scalar part
182
+ const vNorm = this.vectorNorm();
183
+
184
+ const ea = Math.exp(a);
185
+ const result = new Hypercomplex(this.dim);
186
+
187
+ if (vNorm < 1e-10) {
188
+ // Pure scalar: exp(a) = e^a
189
+ result.c[0] = ea;
190
+ return result;
191
+ }
192
+
193
+ // exp(a + v) = e^a * (cos|v| + v̂·sin|v|)
194
+ const cosV = Math.cos(vNorm);
195
+ const sinV = Math.sin(vNorm);
196
+
197
+ result.c[0] = ea * cosV;
198
+
199
+ // Vector part: e^a * sin|v| * v̂ = e^a * sin|v| * v/|v|
200
+ const scale = ea * sinV / vNorm;
201
+ for (let i = 1; i < this.dim; i++) {
202
+ result.c[i] = scale * this.c[i];
203
+ }
204
+
205
+ return result;
206
+ }
207
+
208
+ /**
209
+ * Hypercomplex logarithm: log(q)
210
+ *
211
+ * For q = a + v (scalar a, vector v):
212
+ * log(q) = log|q| + v̂·arccos(a/|q|)
213
+ *
214
+ * where v̂ = v/|v| is the unit vector direction.
215
+ *
216
+ * Note: Like complex log, this has branch cuts. We return the principal value.
217
+ *
218
+ * @returns {Hypercomplex} The natural logarithm
219
+ */
220
+ log() {
221
+ const qNorm = this.norm();
222
+ const vNorm = this.vectorNorm();
223
+
224
+ const result = new Hypercomplex(this.dim);
225
+
226
+ if (qNorm < 1e-10) {
227
+ // log(0) is undefined, return large negative scalar
228
+ result.c[0] = -Infinity;
229
+ return result;
230
+ }
231
+
232
+ // Scalar part: log|q|
233
+ result.c[0] = Math.log(qNorm);
234
+
235
+ if (vNorm < 1e-10) {
236
+ // Pure scalar: log(a) = ln(|a|) + π if a < 0
237
+ if (this.c[0] < 0) {
238
+ // Add π in the "first imaginary" direction as convention
239
+ result.c[1] = Math.PI;
240
+ }
241
+ return result;
242
+ }
243
+
244
+ // Vector part: arccos(a/|q|) * v̂
245
+ const theta = Math.acos(Math.max(-1, Math.min(1, this.c[0] / qNorm)));
246
+ const scale = theta / vNorm;
247
+
248
+ for (let i = 1; i < this.dim; i++) {
249
+ result.c[i] = scale * this.c[i];
250
+ }
251
+
252
+ return result;
253
+ }
254
+
255
+ /**
256
+ * Hypercomplex power: q^n
257
+ *
258
+ * Computed as: q^n = exp(n * log(q))
259
+ *
260
+ * Works for integer and fractional exponents.
261
+ *
262
+ * @param {number} n - The exponent
263
+ * @returns {Hypercomplex} q raised to power n
264
+ */
265
+ pow(n) {
266
+ if (n === 0) {
267
+ return Hypercomplex.basis(this.dim, 0, 1); // Return 1
268
+ }
269
+
270
+ if (n === 1) {
271
+ return this.clone();
272
+ }
273
+
274
+ if (n === -1) {
275
+ return this.inverse();
276
+ }
277
+
278
+ // General case: q^n = exp(n * log(q))
279
+ return this.log().scale(n).exp();
280
+ }
281
+
282
+ /**
283
+ * Integer power using repeated squaring (more numerically stable)
284
+ * @param {number} n - Integer exponent
285
+ * @returns {Hypercomplex} q raised to integer power n
286
+ */
287
+ powInt(n) {
288
+ if (!Number.isInteger(n)) {
289
+ return this.pow(n);
290
+ }
291
+
292
+ if (n === 0) {
293
+ return Hypercomplex.basis(this.dim, 0, 1);
294
+ }
295
+
296
+ if (n < 0) {
297
+ return this.inverse().powInt(-n);
298
+ }
299
+
300
+ // Repeated squaring
301
+ let result = Hypercomplex.basis(this.dim, 0, 1);
302
+ let base = this.clone();
303
+
304
+ while (n > 0) {
305
+ if (n & 1) {
306
+ result = result.mul(base);
307
+ }
308
+ base = base.mul(base);
309
+ n >>= 1;
310
+ }
311
+
312
+ return result;
313
+ }
314
+
315
+ /**
316
+ * Square root: q^(1/2)
317
+ * @returns {Hypercomplex} Principal square root
318
+ */
319
+ sqrt() {
320
+ return this.pow(0.5);
321
+ }
322
+
323
+ /**
324
+ * Spherical Linear Interpolation (SLERP)
325
+ *
326
+ * Interpolates along the shortest arc on the unit hypersphere.
327
+ * Both this and other should be normalized for proper geometric interpretation.
328
+ *
329
+ * slerp(q1, q2, t) = q1 * (q1^-1 * q2)^t
330
+ *
331
+ * Or equivalently:
332
+ * slerp(q1, q2, t) = (sin((1-t)θ)/sin(θ)) * q1 + (sin(tθ)/sin(θ)) * q2
333
+ *
334
+ * where θ = arccos(q1·q2)
335
+ *
336
+ * @param {Hypercomplex} other - Target hypercomplex
337
+ * @param {number} t - Interpolation parameter [0, 1]
338
+ * @returns {Hypercomplex} Interpolated value
339
+ */
340
+ slerp(other, t) {
341
+ // Compute dot product
342
+ let dot = this.dot(other);
343
+
344
+ // Handle antipodal case (choose shorter path)
345
+ let q2 = other;
346
+ if (dot < 0) {
347
+ q2 = other.scale(-1);
348
+ dot = -dot;
349
+ }
350
+
351
+ // Clamp dot to valid range for acos
352
+ dot = Math.min(1, Math.max(-1, dot));
353
+
354
+ // If very close, use linear interpolation to avoid division by zero
355
+ if (dot > 0.9995) {
356
+ const result = new Hypercomplex(this.dim);
357
+ for (let i = 0; i < this.dim; i++) {
358
+ result.c[i] = this.c[i] + t * (q2.c[i] - this.c[i]);
359
+ }
360
+ return result.normalize();
361
+ }
362
+
363
+ // Standard slerp formula
364
+ const theta = Math.acos(dot);
365
+ const sinTheta = Math.sin(theta);
366
+
367
+ const s1 = Math.sin((1 - t) * theta) / sinTheta;
368
+ const s2 = Math.sin(t * theta) / sinTheta;
369
+
370
+ const result = new Hypercomplex(this.dim);
371
+ for (let i = 0; i < this.dim; i++) {
372
+ result.c[i] = s1 * this.c[i] + s2 * q2.c[i];
373
+ }
374
+
375
+ return result;
376
+ }
377
+
378
+ /**
379
+ * Normalized Linear Interpolation (NLERP)
380
+ *
381
+ * Faster but non-constant velocity interpolation.
382
+ *
383
+ * @param {Hypercomplex} other - Target hypercomplex
384
+ * @param {number} t - Interpolation parameter [0, 1]
385
+ * @returns {Hypercomplex} Interpolated value
386
+ */
387
+ nlerp(other, t) {
388
+ const result = new Hypercomplex(this.dim);
389
+ for (let i = 0; i < this.dim; i++) {
390
+ result.c[i] = (1 - t) * this.c[i] + t * other.c[i];
391
+ }
392
+ return result.normalize();
393
+ }
394
+
395
+ /**
396
+ * Spherical Quadrangle Interpolation (SQUAD)
397
+ *
398
+ * Smooth cubic interpolation through a sequence of rotations.
399
+ * Uses De Casteljau construction with slerp.
400
+ *
401
+ * squad(q1, a, b, q2, t) = slerp(slerp(q1, q2, t), slerp(a, b, t), 2t(1-t))
402
+ *
403
+ * The control points a and b are typically computed as:
404
+ * a = q1 * exp(-(log(q1^-1 * q2) + log(q1^-1 * q0)) / 4)
405
+ * b = q2 * exp(-(log(q2^-1 * q3) + log(q2^-1 * q1)) / 4)
406
+ *
407
+ * @param {Hypercomplex} a - First control point
408
+ * @param {Hypercomplex} b - Second control point
409
+ * @param {Hypercomplex} q2 - End point
410
+ * @param {number} t - Interpolation parameter [0, 1]
411
+ * @returns {Hypercomplex} Interpolated value
412
+ */
413
+ squad(a, b, q2, t) {
414
+ const slerp1 = this.slerp(q2, t);
415
+ const slerp2 = a.slerp(b, t);
416
+ return slerp1.slerp(slerp2, 2 * t * (1 - t));
417
+ }
418
+
419
+ /**
420
+ * Compute SQUAD control point for smooth path through [q0, q1, q2]
421
+ *
422
+ * @param {Hypercomplex} q0 - Previous point
423
+ * @param {Hypercomplex} q2 - Next point
424
+ * @returns {Hypercomplex} Control point for q1
425
+ */
426
+ squadControlPoint(q0, q2) {
427
+ const q1Inv = this.inverse();
428
+
429
+ const log1 = q1Inv.mul(q2).log();
430
+ const log2 = q1Inv.mul(q0).log();
431
+
432
+ const sum = log1.add(log2).scale(-0.25);
433
+
434
+ return this.mul(sum.exp());
435
+ }
436
+
437
+ /**
438
+ * Sandwich product: q * v * q*
439
+ *
440
+ * This is the fundamental rotation/reflection operation.
441
+ * For unit quaternions, this rotates a vector v by the rotation represented by q.
442
+ *
443
+ * @param {Hypercomplex} v - Vector to transform (can have any scalar part)
444
+ * @returns {Hypercomplex} Transformed vector
445
+ */
446
+ sandwich(v) {
447
+ return this.mul(v).mul(this.conjugate());
448
+ }
449
+
450
+ /**
451
+ * Apply rotation to a pure vector (zero scalar part)
452
+ *
453
+ * For quaternions, this is the standard way to rotate 3D vectors:
454
+ * v' = q * (0 + v) * q*
455
+ *
456
+ * @param {number[]} vec - Vector as array [x, y, z, ...] (length = dim - 1)
457
+ * @returns {number[]} Rotated vector
458
+ */
459
+ rotateVector(vec) {
460
+ // Create pure vector hypercomplex (zero scalar)
461
+ const v = new Hypercomplex(this.dim);
462
+ for (let i = 0; i < Math.min(vec.length, this.dim - 1); i++) {
463
+ v.c[i + 1] = vec[i];
464
+ }
465
+
466
+ // Apply sandwich product
467
+ const rotated = this.sandwich(v);
468
+
469
+ // Extract vector part
470
+ const result = new Array(this.dim - 1);
471
+ for (let i = 0; i < this.dim - 1; i++) {
472
+ result[i] = rotated.c[i + 1];
473
+ }
474
+
475
+ return result;
476
+ }
477
+
478
+ /**
479
+ * Create a rotation hypercomplex from axis-angle representation
480
+ *
481
+ * For quaternions: q = cos(θ/2) + sin(θ/2) * (axis)
482
+ *
483
+ * @param {number} dim - Dimension
484
+ * @param {number[]} axis - Rotation axis (will be normalized)
485
+ * @param {number} angle - Rotation angle in radians
486
+ * @returns {Hypercomplex} Rotation hypercomplex
487
+ */
488
+ static fromAxisAngle(dim, axis, angle) {
489
+ const h = new Hypercomplex(dim);
490
+
491
+ // Normalize axis
492
+ let axisNorm = 0;
493
+ for (const a of axis) axisNorm += a * a;
494
+ axisNorm = Math.sqrt(axisNorm);
495
+
496
+ if (axisNorm < 1e-10) {
497
+ h.c[0] = 1;
498
+ return h;
499
+ }
500
+
501
+ const halfAngle = angle / 2;
502
+ const sinHalf = Math.sin(halfAngle);
503
+ const cosHalf = Math.cos(halfAngle);
504
+
505
+ h.c[0] = cosHalf;
506
+
507
+ // Map axis to imaginary components
508
+ const n = Math.min(axis.length, dim - 1);
509
+ for (let i = 0; i < n; i++) {
510
+ h.c[i + 1] = sinHalf * axis[i] / axisNorm;
511
+ }
512
+
513
+ return h;
514
+ }
515
+
516
+ /**
517
+ * Extract axis and angle from a unit hypercomplex
518
+ *
519
+ * @returns {object} { axis: number[], angle: number }
520
+ */
521
+ toAxisAngle() {
522
+ const h = this.normalize();
523
+
524
+ // Clamp scalar part for acos
525
+ const cosHalf = Math.max(-1, Math.min(1, h.c[0]));
526
+ const angle = 2 * Math.acos(cosHalf);
527
+
528
+ const sinHalf = Math.sin(angle / 2);
529
+
530
+ const axis = new Array(this.dim - 1);
531
+ if (Math.abs(sinHalf) < 1e-10) {
532
+ // Near identity rotation, axis is arbitrary
533
+ axis.fill(0);
534
+ axis[0] = 1;
535
+ } else {
536
+ for (let i = 0; i < this.dim - 1; i++) {
537
+ axis[i] = h.c[i + 1] / sinHalf;
538
+ }
539
+ }
540
+
541
+ return { axis, angle };
542
+ }
543
+
544
+ /**
545
+ * Create rotation between two vectors
546
+ *
547
+ * @param {number} dim - Dimension
548
+ * @param {number[]} from - Source vector
549
+ * @param {number[]} to - Target vector
550
+ * @returns {Hypercomplex} Rotation hypercomplex
551
+ */
552
+ static rotationBetween(dim, from, to) {
553
+ // Normalize inputs
554
+ let fromNorm = 0, toNorm = 0;
555
+ for (let i = 0; i < from.length; i++) fromNorm += from[i] * from[i];
556
+ for (let i = 0; i < to.length; i++) toNorm += to[i] * to[i];
557
+ fromNorm = Math.sqrt(fromNorm);
558
+ toNorm = Math.sqrt(toNorm);
559
+
560
+ const fromUnit = from.map(x => x / fromNorm);
561
+ const toUnit = to.map(x => x / toNorm);
562
+
563
+ // Compute cross product for axis (works in 3D, generalize for higher)
564
+ // For now, assume 3D cross product
565
+ if (fromUnit.length >= 3 && toUnit.length >= 3) {
566
+ const axis = [
567
+ fromUnit[1] * toUnit[2] - fromUnit[2] * toUnit[1],
568
+ fromUnit[2] * toUnit[0] - fromUnit[0] * toUnit[2],
569
+ fromUnit[0] * toUnit[1] - fromUnit[1] * toUnit[0]
570
+ ];
571
+
572
+ // Compute angle from dot product
573
+ let dot = 0;
574
+ for (let i = 0; i < 3; i++) dot += fromUnit[i] * toUnit[i];
575
+ const angle = Math.acos(Math.max(-1, Math.min(1, dot)));
576
+
577
+ return Hypercomplex.fromAxisAngle(dim, axis, angle);
578
+ }
579
+
580
+ // Fallback: identity rotation
581
+ return Hypercomplex.basis(dim, 0, 1);
582
+ }
583
+
584
+ /**
585
+ * Get the angle of rotation (for unit hypercomplex)
586
+ * @returns {number} Rotation angle in radians
587
+ */
588
+ angle() {
589
+ const cosHalf = Math.max(-1, Math.min(1, this.c[0] / this.norm()));
590
+ return 2 * Math.acos(cosHalf);
591
+ }
592
+
593
+ /**
594
+ * Check if this is a unit hypercomplex (norm ≈ 1)
595
+ * @param {number} tolerance - Tolerance for comparison
596
+ */
597
+ isUnit(tolerance = 1e-6) {
598
+ return Math.abs(this.norm() - 1) < tolerance;
599
+ }
600
+
601
+ /**
602
+ * Linear interpolation (component-wise, not normalized)
603
+ * @param {Hypercomplex} other - Target
604
+ * @param {number} t - Interpolation parameter
605
+ */
606
+ lerp(other, t) {
607
+ const result = new Hypercomplex(this.dim);
608
+ for (let i = 0; i < this.dim; i++) {
609
+ result.c[i] = (1 - t) * this.c[i] + t * other.c[i];
610
+ }
611
+ return result;
612
+ }
613
+
133
614
  // Serialization
134
615
  toArray() { return [...this.c]; }
135
616
 
136
617
  clone() {
137
618
  return new Hypercomplex(this.dim, Float64Array.from(this.c));
138
619
  }
620
+
621
+ /**
622
+ * String representation
623
+ */
624
+ toString() {
625
+ const parts = [];
626
+ const labels = ['', 'i', 'j', 'k', 'e4', 'e5', 'e6', 'e7',
627
+ 'e8', 'e9', 'e10', 'e11', 'e12', 'e13', 'e14', 'e15'];
628
+
629
+ for (let i = 0; i < this.dim; i++) {
630
+ if (Math.abs(this.c[i]) > 1e-10) {
631
+ const label = labels[i] || `e${i}`;
632
+ const sign = this.c[i] >= 0 && parts.length > 0 ? '+' : '';
633
+ parts.push(`${sign}${this.c[i].toFixed(4)}${label}`);
634
+ }
635
+ }
636
+
637
+ return parts.length > 0 ? parts.join('') : '0';
638
+ }
139
639
  }
140
640
 
141
641
  module.exports = { Hypercomplex };
package/core/index.js CHANGED
@@ -84,6 +84,32 @@ const {
84
84
  applyResonanceOperator
85
85
  } = require('./rformer');
86
86
 
87
+ // ResoFormer complete layers
88
+ const {
89
+ ResonantMultiHeadAttention,
90
+ PrimeFFN,
91
+ PrimeLayerNorm,
92
+ PositionalPrimeEncoding,
93
+ ResoFormerBlock,
94
+ ResoFormer
95
+ } = require('./rformer-layers');
96
+
97
+ // Prime Entanglement Graph
98
+ const {
99
+ EntanglementEdge,
100
+ PrimeEntanglementGraph,
101
+ createEntanglementGraph
102
+ } = require('./entanglement');
103
+
104
+ // Event system and streaming
105
+ const {
106
+ AlephEventEmitter,
107
+ AlephMonitor,
108
+ EvolutionStream,
109
+ createEvolutionStream,
110
+ createMonitor
111
+ } = require('./events');
112
+
87
113
  // TensorFlow.js layers (lazy load - may not be available)
88
114
  let rformerTF = null;
89
115
  try {
@@ -155,6 +181,26 @@ module.exports = {
155
181
  PRGraphMemory,
156
182
  applyResonanceOperator,
157
183
 
184
+ // ResoFormer Complete Layers
185
+ ResonantMultiHeadAttention,
186
+ PrimeFFN,
187
+ PrimeLayerNorm,
188
+ PositionalPrimeEncoding,
189
+ ResoFormerBlock,
190
+ ResoFormer,
191
+
192
+ // Prime Entanglement Graph
193
+ EntanglementEdge,
194
+ PrimeEntanglementGraph,
195
+ createEntanglementGraph,
196
+
197
+ // Event System and Streaming
198
+ AlephEventEmitter,
199
+ AlephMonitor,
200
+ EvolutionStream,
201
+ createEvolutionStream,
202
+ createMonitor,
203
+
158
204
  // TensorFlow.js ResoFormer layers (if available)
159
205
  ...(rformerTF || {}),
160
206