@aleph-ai/tinyaleph 1.6.2 → 1.7.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/backends/index.js CHANGED
@@ -9,6 +9,15 @@ import ScientificBackend from './scientific/index.js';
9
9
 
10
10
  import bioinformatics from './bioinformatics/index.js';
11
11
 
12
+ // Named exports for ESM compatibility
13
+ export {
14
+ Backend,
15
+ SemanticBackend,
16
+ CryptographicBackend,
17
+ ScientificBackend,
18
+ bioinformatics
19
+ };
20
+
12
21
  export default {
13
22
  Backend,
14
23
  SemanticBackend,
@@ -525,10 +525,6 @@ class SemanticBackend extends Backend {
525
525
  }
526
526
  }
527
527
 
528
- export {
529
- SemanticBackend
530
- };
528
+ export { SemanticBackend };
531
529
 
532
- export default {
533
- SemanticBackend
534
- };
530
+ export default SemanticBackend;
@@ -19,63 +19,7 @@
19
19
  'use strict';
20
20
 
21
21
  import { isPrime, firstNPrimes, factorize } from './prime.js';
22
-
23
- // ============================================================================
24
- // MODULAR EXPONENTIATION UTILITIES
25
- // ============================================================================
26
-
27
- /**
28
- * Fast modular exponentiation: a^n mod m
29
- * Uses binary exponentiation for O(log n) complexity
30
- *
31
- * @param {bigint|number} base - Base
32
- * @param {bigint|number} exp - Exponent
33
- * @param {bigint|number} mod - Modulus
34
- * @returns {bigint} Result
35
- */
36
- function modPow(base, exp, mod) {
37
- base = BigInt(base);
38
- exp = BigInt(exp);
39
- mod = BigInt(mod);
40
-
41
- if (mod === 1n) return 0n;
42
-
43
- let result = 1n;
44
- base = base % mod;
45
-
46
- while (exp > 0n) {
47
- if (exp % 2n === 1n) {
48
- result = (result * base) % mod;
49
- }
50
- exp = exp >> 1n;
51
- base = (base * base) % mod;
52
- }
53
-
54
- return result;
55
- }
56
-
57
- /**
58
- * Extended Euclidean Algorithm for modular inverse
59
- * @param {bigint} a - Number
60
- * @param {bigint} m - Modulus
61
- * @returns {bigint} a^(-1) mod m
62
- */
63
- function modInverse(a, m) {
64
- a = BigInt(a);
65
- m = BigInt(m);
66
-
67
- let [old_r, r] = [a, m];
68
- let [old_s, s] = [1n, 0n];
69
-
70
- while (r !== 0n) {
71
- const quotient = old_r / r;
72
- [old_r, r] = [r, old_r - quotient * r];
73
- [old_s, s] = [s, old_s - quotient * s];
74
- }
75
-
76
- if (old_r > 1n) return null; // No inverse exists
77
- return ((old_s % m) + m) % m;
78
- }
22
+ import { modPowBigInt as modPow, modInverseBigInt as modInverse } from './math-utils.js';
79
23
 
80
24
  // ============================================================================
81
25
  // PHASE 1: PAIRWISE COUPLINGS - Legendre & Power Residue Symbols
@@ -35,46 +35,7 @@
35
35
  import { firstNPrimes, isPrime, factorize } from './prime.js';
36
36
  import { Complex, PrimeState } from './hilbert.js';
37
37
  import { SparsePrimeState, resonanceScore, Quaternion } from './rformer.js';
38
-
39
- function extendedGCD(a, b) {
40
- if (b === 0) {
41
- return { gcd: a, x: 1, y: 0 };
42
- }
43
-
44
- const { gcd, x: x1, y: y1 } = extendedGCD(b, a % b);
45
- const x = y1;
46
- const y = x1 - Math.floor(a / b) * y1;
47
-
48
- return { gcd, x, y };
49
- }
50
-
51
- /**
52
- * Modular multiplicative inverse
53
- * Returns a^{-1} mod m such that a * a^{-1} ≡ 1 (mod m)
54
- * @param {number} a - Number to invert
55
- * @param {number} m - Modulus
56
- * @returns {number|null} Inverse if exists, null otherwise
57
- */
58
- function modInverse(a, m) {
59
- a = ((a % m) + m) % m; // Normalize to positive
60
- const { gcd, x } = extendedGCD(a, m);
61
-
62
- if (gcd !== 1) {
63
- return null; // No inverse exists (not coprime)
64
- }
65
-
66
- return ((x % m) + m) % m;
67
- }
68
-
69
- /**
70
- * Check if two numbers are coprime
71
- * @param {number} a - First number
72
- * @param {number} b - Second number
73
- * @returns {boolean} True if gcd(a, b) = 1
74
- */
75
- function areCoprime(a, b) {
76
- return extendedGCD(a, b).gcd === 1;
77
- }
38
+ import { extendedGCD, modInverse, areCoprime } from './math-utils.js';
78
39
 
79
40
  /**
80
41
  * Softmax function
package/core/hilbert.js CHANGED
@@ -17,6 +17,7 @@
17
17
  * Complex number class for amplitudes
18
18
  */
19
19
  import { factorize, isPrime, firstNPrimes } from './prime.js';
20
+ import { modPow, modInverse } from './math-utils.js';
20
21
 
21
22
  class Complex {
22
23
  constructor(re = 0, im = 0) {
@@ -1372,21 +1373,7 @@ function findPrimitiveRoot(p) {
1372
1373
  return null;
1373
1374
  }
1374
1375
 
1375
- /**
1376
- * Modular exponentiation: a^b mod m
1377
- */
1378
- function modPow(a, b, m) {
1379
- let result = 1;
1380
- a = a % m;
1381
- while (b > 0) {
1382
- if (b % 2 === 1) {
1383
- result = (result * a) % m;
1384
- }
1385
- b = Math.floor(b / 2);
1386
- a = (a * a) % m;
1387
- }
1388
- return result;
1389
- }
1376
+ // modPow imported from math-utils.js
1390
1377
 
1391
1378
  /**
1392
1379
  * Discrete logarithm: find x such that g^x ≡ n (mod p)
@@ -1419,21 +1406,7 @@ function discreteLog(n, g, p) {
1419
1406
  return -1; // Not found
1420
1407
  }
1421
1408
 
1422
- /**
1423
- * Modular inverse using extended Euclidean algorithm
1424
- */
1425
- function modInverse(a, m) {
1426
- let [old_r, r] = [a, m];
1427
- let [old_s, s] = [1, 0];
1428
-
1429
- while (r !== 0) {
1430
- const q = Math.floor(old_r / r);
1431
- [old_r, r] = [r, old_r - q * r];
1432
- [old_s, s] = [s, old_s - q * s];
1433
- }
1434
-
1435
- return ((old_s % m) + m) % m;
1436
- }
1409
+ // modInverse imported from math-utils.js
1437
1410
 
1438
1411
  /**
1439
1412
  * Extended Resonance Operators including Möbius and Euler Totient
@@ -17,11 +17,16 @@ class Hypercomplex {
17
17
  throw new Error('Dimension must be power of 2');
18
18
  }
19
19
  this.dim = dim;
20
- this.c = components instanceof Float64Array
21
- ? components
20
+ this.c = components instanceof Float64Array
21
+ ? components
22
22
  : new Float64Array(dim);
23
23
  }
24
24
 
25
+ // Backward compatibility getter
26
+ get components() {
27
+ return this.c;
28
+ }
29
+
25
30
  // Factory methods
26
31
  static zero(dim) { return new Hypercomplex(dim); }
27
32
 
@@ -54,6 +59,11 @@ class Hypercomplex {
54
59
  return r;
55
60
  }
56
61
 
62
+ // Alias for sub()
63
+ subtract(other) {
64
+ return this.sub(other);
65
+ }
66
+
57
67
  scale(k) {
58
68
  const r = new Hypercomplex(this.dim);
59
69
  for (let i = 0; i < this.dim; i++) r.c[i] = this.c[i] * k;
package/core/index.js CHANGED
@@ -114,7 +114,7 @@ import { Complex,
114
114
  findPrimitiveRoot,
115
115
  modPow,
116
116
  discreteLog,
117
- modInverse,
117
+ modInverse as hilbertModInverse,
118
118
  gcd } from './hilbert.js';
119
119
 
120
120
  // Golden Ratio Resonance (from symprime symbolic AI)
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Shared Math Utilities for tinyaleph
3
+ *
4
+ * This module provides common mathematical functions used across multiple
5
+ * core modules to avoid duplicate definitions that cause bundler issues.
6
+ *
7
+ * @module core/math-utils
8
+ */
9
+
10
+ // ============================================================================
11
+ // EXTENDED EUCLIDEAN ALGORITHM
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Extended Euclidean Algorithm for regular numbers
16
+ * Returns { gcd, x, y } such that gcd = a*x + b*y
17
+ *
18
+ * @param {number} a - First number
19
+ * @param {number} b - Second number
20
+ * @returns {{ gcd: number, x: number, y: number }}
21
+ */
22
+ export function extendedGCD(a, b) {
23
+ if (b === 0) {
24
+ return { gcd: a, x: 1, y: 0 };
25
+ }
26
+
27
+ const result = extendedGCD(b, a % b);
28
+ return {
29
+ gcd: result.gcd,
30
+ x: result.y,
31
+ y: result.x - Math.floor(a / b) * result.y
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Extended Euclidean Algorithm for BigInt
37
+ * Returns { gcd, x, y } such that gcd = a*x + b*y
38
+ *
39
+ * @param {bigint} a - First number
40
+ * @param {bigint} b - Second number
41
+ * @returns {{ gcd: bigint, x: bigint, y: bigint }}
42
+ */
43
+ export function extendedGCDBigInt(a, b) {
44
+ if (b === 0n) {
45
+ return { gcd: a, x: 1n, y: 0n };
46
+ }
47
+
48
+ const result = extendedGCDBigInt(b, a % b);
49
+ return {
50
+ gcd: result.gcd,
51
+ x: result.y,
52
+ y: result.x - (a / b) * result.y
53
+ };
54
+ }
55
+
56
+ // ============================================================================
57
+ // MODULAR INVERSE
58
+ // ============================================================================
59
+
60
+ /**
61
+ * Compute modular inverse using Extended Euclidean Algorithm
62
+ * Works with regular numbers
63
+ *
64
+ * @param {number} a - Number to find inverse of
65
+ * @param {number} m - Modulus
66
+ * @returns {number|null} The modular inverse, or null if no inverse exists
67
+ */
68
+ export function modInverse(a, m) {
69
+ a = ((a % m) + m) % m; // Normalize to positive
70
+ const { gcd, x } = extendedGCD(a, m);
71
+
72
+ if (gcd !== 1) {
73
+ return null; // No inverse exists (not coprime)
74
+ }
75
+
76
+ return ((x % m) + m) % m;
77
+ }
78
+
79
+ /**
80
+ * Compute modular inverse for BigInt values
81
+ * Uses Extended Euclidean Algorithm
82
+ *
83
+ * @param {bigint} a - Number to find inverse of
84
+ * @param {bigint} m - Modulus
85
+ * @returns {bigint|null} The modular inverse, or null if no inverse exists
86
+ */
87
+ export function modInverseBigInt(a, m) {
88
+ a = BigInt(a);
89
+ m = BigInt(m);
90
+
91
+ let [old_r, r] = [a, m];
92
+ let [old_s, s] = [1n, 0n];
93
+
94
+ while (r !== 0n) {
95
+ const quotient = old_r / r;
96
+ [old_r, r] = [r, old_r - quotient * r];
97
+ [old_s, s] = [s, old_s - quotient * s];
98
+ }
99
+
100
+ if (old_r > 1n) return null; // No inverse exists
101
+ return ((old_s % m) + m) % m;
102
+ }
103
+
104
+ // ============================================================================
105
+ // MODULAR EXPONENTIATION
106
+ // ============================================================================
107
+
108
+ /**
109
+ * Modular exponentiation for regular numbers
110
+ * Computes (base^exp) mod m efficiently
111
+ *
112
+ * @param {number} base - Base
113
+ * @param {number} exp - Exponent
114
+ * @param {number} m - Modulus
115
+ * @returns {number} (base^exp) mod m
116
+ */
117
+ export function modPow(base, exp, m) {
118
+ if (m === 1) return 0;
119
+
120
+ let result = 1;
121
+ base = base % m;
122
+
123
+ while (exp > 0) {
124
+ if (exp % 2 === 1) {
125
+ result = (result * base) % m;
126
+ }
127
+ exp = Math.floor(exp / 2);
128
+ base = (base * base) % m;
129
+ }
130
+
131
+ return result;
132
+ }
133
+
134
+ /**
135
+ * Modular exponentiation for BigInt
136
+ * Computes (base^exp) mod m efficiently
137
+ *
138
+ * @param {bigint} base - Base
139
+ * @param {bigint} exp - Exponent
140
+ * @param {bigint} m - Modulus
141
+ * @returns {bigint} (base^exp) mod m
142
+ */
143
+ export function modPowBigInt(base, exp, m) {
144
+ if (m === 1n) return 0n;
145
+
146
+ let result = 1n;
147
+ base = base % m;
148
+
149
+ while (exp > 0n) {
150
+ if (exp % 2n === 1n) {
151
+ result = (result * base) % m;
152
+ }
153
+ exp = exp / 2n;
154
+ base = (base * base) % m;
155
+ }
156
+
157
+ return result;
158
+ }
159
+
160
+ // ============================================================================
161
+ // COPRIMALITY
162
+ // ============================================================================
163
+
164
+ /**
165
+ * Check if two numbers are coprime (gcd = 1)
166
+ *
167
+ * @param {number} a - First number
168
+ * @param {number} b - Second number
169
+ * @returns {boolean} True if gcd(a, b) = 1
170
+ */
171
+ export function areCoprime(a, b) {
172
+ return extendedGCD(a, b).gcd === 1;
173
+ }
174
+
175
+ /**
176
+ * Check if two BigInt numbers are coprime
177
+ *
178
+ * @param {bigint} a - First number
179
+ * @param {bigint} b - Second number
180
+ * @returns {boolean} True if gcd(a, b) = 1
181
+ */
182
+ export function areCoprimeBI(a, b) {
183
+ return extendedGCDBigInt(a, b).gcd === 1n;
184
+ }
185
+
186
+ // ============================================================================
187
+ // GCD / LCM
188
+ // ============================================================================
189
+
190
+ /**
191
+ * Greatest Common Divisor (regular numbers)
192
+ *
193
+ * @param {number} a - First number
194
+ * @param {number} b - Second number
195
+ * @returns {number} GCD of a and b
196
+ */
197
+ export function gcd(a, b) {
198
+ return extendedGCD(a, b).gcd;
199
+ }
200
+
201
+ /**
202
+ * Greatest Common Divisor (BigInt)
203
+ *
204
+ * @param {bigint} a - First number
205
+ * @param {bigint} b - Second number
206
+ * @returns {bigint} GCD of a and b
207
+ */
208
+ export function gcdBigInt(a, b) {
209
+ return extendedGCDBigInt(a, b).gcd;
210
+ }
211
+
212
+ /**
213
+ * Least Common Multiple (regular numbers)
214
+ *
215
+ * @param {number} a - First number
216
+ * @param {number} b - Second number
217
+ * @returns {number} LCM of a and b
218
+ */
219
+ export function lcm(a, b) {
220
+ return Math.abs(a * b) / gcd(a, b);
221
+ }
222
+
223
+ /**
224
+ * Least Common Multiple (BigInt)
225
+ *
226
+ * @param {bigint} a - First number
227
+ * @param {bigint} b - Second number
228
+ * @returns {bigint} LCM of a and b
229
+ */
230
+ export function lcmBigInt(a, b) {
231
+ const g = gcdBigInt(a, b);
232
+ const product = a * b;
233
+ return product < 0n ? -product / g : product / g;
234
+ }
235
+
236
+ // Default export with all functions
237
+ export default {
238
+ // Extended GCD
239
+ extendedGCD,
240
+ extendedGCDBigInt,
241
+
242
+ // Modular inverse
243
+ modInverse,
244
+ modInverseBigInt,
245
+
246
+ // Modular exponentiation
247
+ modPow,
248
+ modPowBigInt,
249
+
250
+ // Coprimality
251
+ areCoprime,
252
+ areCoprimeBI,
253
+
254
+ // GCD/LCM
255
+ gcd,
256
+ gcdBigInt,
257
+ lcm,
258
+ lcmBigInt,
259
+ };
package/engine/index.js CHANGED
@@ -1,14 +1,56 @@
1
1
  /**
2
- * Engine - exports unified AlephEngine
2
+ * Engine - exports unified AlephEngine with createEngine factory
3
3
  */
4
4
 
5
5
  import { AlephEngine } from './aleph.js';
6
6
 
7
+ // Import all backends for factory
8
+ import SemanticBackend from '../backends/semantic/index.js';
9
+ import ScientificBackend from '../backends/scientific/index.js';
10
+ import CryptographicBackend from '../backends/cryptographic/index.js';
11
+
12
+ /**
13
+ * Factory function to create an AlephEngine with specified backend
14
+ * @param {string} backendType - Backend type: 'semantic', 'quantum', 'scientific', 'cryptographic'
15
+ * @param {object} [options={}] - Engine and backend options
16
+ * @returns {AlephEngine} Configured engine instance
17
+ */
18
+ function createEngine(backendType, options = {}) {
19
+ let backend;
20
+
21
+ const defaultConfig = {
22
+ dimension: 16,
23
+ primes: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53],
24
+ ...options.backendConfig
25
+ };
26
+
27
+ switch (backendType.toLowerCase()) {
28
+ case 'semantic':
29
+ backend = new SemanticBackend(defaultConfig);
30
+ break;
31
+ case 'quantum':
32
+ case 'scientific':
33
+ backend = new ScientificBackend(defaultConfig);
34
+ break;
35
+ case 'cryptographic':
36
+ case 'crypto':
37
+ backend = new CryptographicBackend(defaultConfig);
38
+ break;
39
+ default:
40
+ // Default to semantic backend
41
+ backend = new SemanticBackend(defaultConfig);
42
+ }
43
+
44
+ return new AlephEngine(backend, options.engineConfig || options);
45
+ }
46
+
7
47
  export {
8
- AlephEngine
48
+ AlephEngine,
49
+ createEngine
9
50
  };
10
51
 
11
52
  // Default export for compatibility with modular.js
12
53
  export default {
13
- AlephEngine
54
+ AlephEngine,
55
+ createEngine
14
56
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aleph-ai/tinyaleph",
3
- "version": "1.6.2",
3
+ "version": "1.7.1",
4
4
  "description": "Prime-resonant semantic computing framework - hypercomplex algebra, oscillator dynamics, arithmetic topology, and entropy-minimizing reasoning",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -4,17 +4,98 @@
4
4
 
5
5
  import { Hypercomplex } from '../core/hypercomplex.js';
6
6
 
7
- function collapseProbability(entropyIntegral, lyapunovFactor = 1) {
8
- const factor = lyapunovFactor < 0 ? 1.5 : 0.5;
9
- return (1 - Math.exp(-entropyIntegral)) * factor;
7
+ /**
8
+ * Calculate collapse probability using Born rule approximation
9
+ * @param {Hypercomplex|object} state - HypercomplexState or CollapseState object
10
+ * @param {number} [threshold=0.5] - Collapse threshold
11
+ * @returns {number} Probability value 0-1
12
+ */
13
+ function collapseProbability(state, threshold = 0.5) {
14
+ // Handle CollapseState object with entropy/coherence/lyapunov
15
+ if (state && typeof state === 'object' && 'entropy' in state) {
16
+ const { entropy = 0, coherence = 0.5, lyapunov = 0 } = state;
17
+ const factor = lyapunov < 0 ? 1.5 : 0.5;
18
+ return (1 - Math.exp(-entropy * coherence)) * factor;
19
+ }
20
+
21
+ // Handle Hypercomplex state
22
+ if (state && state.c) {
23
+ const n = state.norm ? state.norm() : Math.sqrt(state.c.reduce((s, v) => s + v * v, 0));
24
+ if (n < 1e-10) return 0;
25
+
26
+ // Compute Born-rule probability based on dominant component
27
+ const probs = state.c.map(v => (v / n) ** 2);
28
+ const maxProb = Math.max(...probs);
29
+ return maxProb > threshold ? maxProb : 0;
30
+ }
31
+
32
+ // Legacy signature: collapseProbability(entropyIntegral, lyapunovFactor)
33
+ if (typeof state === 'number') {
34
+ const entropyIntegral = state;
35
+ const lyapunovFactor = threshold;
36
+ const factor = lyapunovFactor < 0 ? 1.5 : 0.5;
37
+ return (1 - Math.exp(-entropyIntegral)) * factor;
38
+ }
39
+
40
+ return 0;
10
41
  }
11
42
 
12
- function shouldCollapse(coherence, entropy, probability, thresholds) {
13
- const { minCoherence = 0.7, minEntropy = 1.8 } = thresholds;
14
- return coherence > minCoherence && entropy > minEntropy && Math.random() < probability;
43
+ /**
44
+ * Determine if state should collapse
45
+ * @param {Hypercomplex|object} state - HypercomplexState or CollapseState
46
+ * @param {number} threshold - Collapse threshold
47
+ * @returns {boolean} True if collapse should occur
48
+ */
49
+ function shouldCollapse(state, threshold = 0.5) {
50
+ // Handle CollapseState with entropy/coherence
51
+ if (state && typeof state === 'object' && 'entropy' in state) {
52
+ const { entropy = 0, coherence = 0.5, lyapunov = 0 } = state;
53
+ return coherence > threshold && entropy > 1.0 && lyapunov < 0.5;
54
+ }
55
+
56
+ // Handle Hypercomplex state
57
+ if (state && state.c) {
58
+ const prob = collapseProbability(state, threshold);
59
+ return prob > threshold && Math.random() < prob;
60
+ }
61
+
62
+ // Legacy signature: shouldCollapse(coherence, entropy, probability, thresholds)
63
+ if (typeof state === 'number') {
64
+ const coherence = state;
65
+ const entropy = threshold;
66
+ const probability = arguments[2] || 0.5;
67
+ const thresholds = arguments[3] || {};
68
+ const { minCoherence = 0.7, minEntropy = 1.8 } = thresholds;
69
+ return coherence > minCoherence && entropy > minEntropy && Math.random() < probability;
70
+ }
71
+
72
+ return false;
15
73
  }
16
74
 
75
+ /**
76
+ * Measure state and return collapsed index
77
+ * @param {Hypercomplex} hypercomplex - State to measure
78
+ * @param {Hypercomplex} [basis=null] - Optional measurement basis
79
+ * @returns {number} Collapsed index (dominant component index)
80
+ */
17
81
  function measureState(hypercomplex, basis = null) {
82
+ if (!hypercomplex || !hypercomplex.c) return 0;
83
+
84
+ if (!basis) {
85
+ let maxIdx = 0, maxVal = 0;
86
+ for (let i = 0; i < hypercomplex.dim; i++) {
87
+ const v = Math.abs(hypercomplex.c[i]);
88
+ if (v > maxVal) { maxVal = v; maxIdx = i; }
89
+ }
90
+ return maxIdx; // Return just the index as a number
91
+ }
92
+ return hypercomplex.dot(basis);
93
+ }
94
+
95
+ /**
96
+ * Legacy measureState that returns full object
97
+ */
98
+ function measureStateDetailed(hypercomplex, basis = null) {
18
99
  if (!basis) {
19
100
  let maxIdx = 0, maxVal = 0;
20
101
  for (let i = 0; i < hypercomplex.dim; i++) {
@@ -37,12 +118,26 @@ function collapseToIndex(hypercomplex, index) {
37
118
 
38
119
  /**
39
120
  * Probabilistic measurement with Born rule
121
+ * @param {Hypercomplex|number[]} hypercomplexOrAmplitudes - State or amplitudes array
122
+ * @returns {{ index: number, probability: number }} Measurement result
40
123
  */
41
- function bornMeasurement(hypercomplex) {
42
- const n = hypercomplex.norm();
43
- if (n < 1e-10) return { index: 0, probability: 1 };
124
+ function bornMeasurement(hypercomplexOrAmplitudes) {
125
+ let probabilities;
126
+
127
+ // Handle plain number array (amplitudes)
128
+ if (Array.isArray(hypercomplexOrAmplitudes)) {
129
+ const amplitudes = hypercomplexOrAmplitudes;
130
+ const sumSq = amplitudes.reduce((s, v) => s + v * v, 0);
131
+ if (sumSq < 1e-10) return { index: 0, probability: 1 };
132
+ probabilities = amplitudes.map(v => (v * v) / sumSq);
133
+ } else {
134
+ // Handle Hypercomplex object
135
+ const hypercomplex = hypercomplexOrAmplitudes;
136
+ const n = hypercomplex.norm ? hypercomplex.norm() : Math.sqrt(hypercomplex.c.reduce((s, v) => s + v * v, 0));
137
+ if (n < 1e-10) return { index: 0, probability: 1 };
138
+ probabilities = hypercomplex.c.map(v => (v / n) ** 2);
139
+ }
44
140
 
45
- const probabilities = hypercomplex.c.map(v => (v / n) ** 2);
46
141
  const r = Math.random();
47
142
  let cumulative = 0;
48
143