@danielsimonjr/mathts-functions 0.32.0 → 0.34.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.
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Number-theory fills — closes gaps left by the existing combinatorics/number-theory
3
+ * surface (`typed/combinatorics.ts`): continued fractions, Euler numbers, the signed
4
+ * Stirling numbers of the first kind, discrete logarithm (BSGS), primitive roots,
5
+ * multiplicative order, the Kronecker symbol, and lexicographic
6
+ * permutation/combination *enumerators* (the existing `permutations`/`combinations`
7
+ * only return counts, not the tuples themselves).
8
+ *
9
+ * Plain exported functions (not `mathTyped` dispatch) — all take/return `number`
10
+ * or generic arrays, matching the style of `descriptive-stats.ts`.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+ /**
15
+ * Simple continued fraction expansion `[a0, a1, a2, ...]` of `x`, where
16
+ * `a_i = floor(r)` and `r <- 1 / (r - a_i)`.
17
+ *
18
+ * Stops after `maxTerms` (default 20) or once the fractional part is smaller
19
+ * than `1e-12` (the remaining value is effectively an integer).
20
+ *
21
+ * @param x - The number to expand
22
+ * @param maxTerms - Maximum number of terms to compute (default 20)
23
+ * @returns The sequence of partial-quotient terms
24
+ *
25
+ * @example
26
+ * continuedFraction(3.245, 5) // => [3, 4, 12, 4, ...]
27
+ */
28
+ export declare function continuedFraction(x: number, maxTerms?: number): number[];
29
+ /**
30
+ * Euler numbers `E_0..E_n` (the coefficients in the secant Maclaurin series).
31
+ *
32
+ * `E_0 = 1`; all odd-index Euler numbers are 0; for even `m > 0`:
33
+ * `E_m = -sum_{k=0}^{m/2-1} C(m, 2k) * E_{2k}`.
34
+ *
35
+ * @param n - Non-negative integer: compute E_0 through E_n
36
+ * @returns Array of length `n + 1`: `[E_0, E_1, ..., E_n]`
37
+ *
38
+ * @example
39
+ * eulerNumbers(6) // => [1, 0, -1, 0, 5, 0, -61]
40
+ */
41
+ export declare function eulerNumbers(n: number): number[];
42
+ /**
43
+ * Signed Stirling number of the first kind `s(n, k)`.
44
+ *
45
+ * Recurrence: `s(n, k) = s(n-1, k-1) - (n-1)*s(n-1, k)`, with `s(0, 0) = 1`
46
+ * and `s(n, 0) = 0` for `n > 0`.
47
+ *
48
+ * @param n - Non-negative integer
49
+ * @param k - Non-negative integer, `0 <= k <= n`
50
+ * @returns The signed Stirling number `s(n, k)`
51
+ *
52
+ * @example
53
+ * stirlingS1(5, 2) // => -50
54
+ */
55
+ export declare function stirlingS1(n: number, k: number): number;
56
+ /**
57
+ * Discrete logarithm via baby-step giant-step: the smallest `x >= 0` such
58
+ * that `g^x === h (mod p)`, or `-1` if none exists within `[0, p-1]`.
59
+ *
60
+ * Uses `BigInt` internally for modular exponentiation/inversion to avoid
61
+ * overflow. `m = ceil(sqrt(p-1))` baby steps are stored in a map; the giant
62
+ * steps multiply by `g^(-m) mod p` each round.
63
+ *
64
+ * @param g - Base
65
+ * @param h - Target
66
+ * @param p - Prime modulus
67
+ * @returns The smallest non-negative `x` with `g^x === h (mod p)`, or `-1`
68
+ *
69
+ * @example
70
+ * discreteLog(2, 3, 5) // => 3 (2^3 = 8 === 3 mod 5)
71
+ */
72
+ export declare function discreteLog(g: number, h: number, p: number): number;
73
+ /**
74
+ * Smallest primitive root modulo a prime `p`.
75
+ *
76
+ * For each candidate `g = 2, 3, ...`, `g` is a primitive root iff
77
+ * `g^((p-1)/q) !== 1 (mod p)` for every prime factor `q` of `p - 1`.
78
+ *
79
+ * @param p - An odd prime (p = 2 returns 1 trivially)
80
+ * @returns The smallest primitive root modulo p
81
+ *
82
+ * @example
83
+ * primitiveRoot(7) // => 3
84
+ */
85
+ export declare function primitiveRoot(p: number): number;
86
+ /**
87
+ * Multiplicative order of `a` modulo `n`: the smallest `k > 0` with
88
+ * `a^k === 1 (mod n)`. Returns `-1` if `gcd(a, n) !== 1` (no order exists).
89
+ *
90
+ * @param a - Integer
91
+ * @param n - Positive integer modulus
92
+ * @returns The multiplicative order, or -1 if undefined
93
+ *
94
+ * @example
95
+ * multiplicativeOrder(2, 7) // => 3
96
+ */
97
+ export declare function multiplicativeOrder(a: number, n: number): number;
98
+ /**
99
+ * Kronecker symbol `(a|n)`, generalizing the Jacobi symbol `(a|n)` (odd
100
+ * positive `n`) to all integers `n`.
101
+ *
102
+ * - `(a|0) = 1` if `|a| = 1`, else `0`.
103
+ * - Sign of `n` is extracted first: `(a|-1) = -1` if `a < 0`, else `1`.
104
+ * - Factors of 2 are extracted from `n` using `(a|2)`: `0` if `a` even,
105
+ * `1` if `a === ±1 (mod 8)`, `-1` if `a === ±3 (mod 8)`.
106
+ * - The remaining odd part is evaluated via the standard Jacobi reciprocity
107
+ * recursion.
108
+ *
109
+ * @param a - Integer
110
+ * @param n - Integer
111
+ * @returns -1, 0, or 1
112
+ *
113
+ * @example
114
+ * kroneckerSymbol(2, 3) // => -1
115
+ */
116
+ export declare function kroneckerSymbol(a: number, n: number): number;
117
+ /**
118
+ * Enumerate all length-`k` combinations of `arr` (index-order subsequences,
119
+ * i.e. lexicographic order for a sorted input) as an array of tuples.
120
+ *
121
+ * @param arr - Source array
122
+ * @param k - Combination length
123
+ * @returns All `C(arr.length, k)` combinations, in lexicographic order
124
+ *
125
+ * @example
126
+ * combinationsGen([1, 2, 3], 2) // => [[1,2],[1,3],[2,3]]
127
+ */
128
+ export declare function combinationsGen<T>(arr: readonly T[], k: number): T[][];
129
+ /**
130
+ * Enumerate all length-`k` permutations (ordered arrangements) of `arr`
131
+ * as an array of tuples, in lexicographic order of index selection.
132
+ * `k` defaults to `arr.length` (full permutations).
133
+ *
134
+ * @param arr - Source array
135
+ * @param k - Permutation length (default: `arr.length`)
136
+ * @returns All `n! / (n-k)!` permutations, in lexicographic order
137
+ *
138
+ * @example
139
+ * permutationsGen([1, 2, 3], 2) // => 6 tuples: [1,2],[1,3],[2,1],[2,3],[3,1],[3,2]
140
+ */
141
+ export declare function permutationsGen<T>(arr: readonly T[], k?: number): T[][];
142
+ //# sourceMappingURL=extra.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extra.d.ts","sourceRoot":"","sources":["../../src/numbertheory/extra.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,MAAM,EAAE,CAcpE;AAiBD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBhD;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAevD;AAqCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA+BnE;AAoBD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAmB/C;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAehE;AAaD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA0C5D;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAoBtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,GAAE,MAAmB,GAAG,CAAC,EAAE,EAAE,CAwBnF"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Gauss-Legendre quadrature nodes and weights.
3
+ *
4
+ * `rootsLegendre(n)` finds the n roots of the degree-n Legendre polynomial
5
+ * P_n via Newton's method (initial guess from the standard asymptotic
6
+ * approximation), then derives the corresponding quadrature weights. This is
7
+ * the classical fixed-node table underlying Gauss-Legendre quadrature on
8
+ * [-1, 1]; callers needing a custom node count (rather than the library's
9
+ * built-in fixed-order `integrate`/`gaussLegendre` routines) use this
10
+ * directly.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+ /** Result of {@link rootsLegendre}: nodes ascending on [-1, 1] with matching weights. */
15
+ export interface RootsLegendreResult {
16
+ nodes: number[];
17
+ weights: number[];
18
+ }
19
+ /**
20
+ * n-point Gauss-Legendre quadrature nodes and weights on [-1, 1].
21
+ *
22
+ * Nodes are the roots of the degree-n Legendre polynomial P_n, refined by
23
+ * Newton's method from the standard asymptotic initial guess
24
+ * `cos(pi*(i+0.75)/(n+0.5))`. Weights are `2 / ((1-x_i^2) * P'_n(x_i)^2)`.
25
+ *
26
+ * @param n - Number of quadrature points (positive integer)
27
+ * @returns Nodes (ascending) and matching weights
28
+ *
29
+ * @example
30
+ * rootsLegendre(3)
31
+ * // { nodes: [-0.7745966692, 0, 0.7745966692],
32
+ * // weights: [0.5555555556, 0.8888888889, 0.5555555556] }
33
+ */
34
+ export declare function rootsLegendre(n: number): RootsLegendreResult;
35
+ //# sourceMappingURL=gauss-nodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gauss-nodes.d.ts","sourceRoot":"","sources":["../../src/numeric/gauss-nodes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,yFAAyF;AACzF,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAuBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,mBAAmB,CA+B5D"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Convolution Operations
3
+ *
4
+ * Implements 1D and 2D convolution using both direct and FFT methods.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ /**
9
+ * Convolution mode - determines output size
10
+ */
11
+ export type ConvMode = 'full' | 'same' | 'valid';
12
+ /**
13
+ * Direct 1D convolution (for small inputs)
14
+ *
15
+ * @param x - Input signal
16
+ * @param h - Convolution kernel
17
+ * @param mode - Output mode: 'full', 'same', or 'valid'
18
+ * @returns Convolution result
19
+ */
20
+ export declare function convDirect(x: number[] | Float64Array, h: number[] | Float64Array, mode?: ConvMode): number[];
21
+ /**
22
+ * FFT-based 1D convolution (efficient for large inputs)
23
+ *
24
+ * Uses the convolution theorem: conv(x,h) = IFFT(FFT(x) * FFT(h))
25
+ *
26
+ * @param x - Input signal
27
+ * @param h - Convolution kernel
28
+ * @param mode - Output mode: 'full', 'same', or 'valid'
29
+ * @returns Convolution result
30
+ */
31
+ export declare function convFFT(x: number[] | Float64Array, h: number[] | Float64Array, mode?: ConvMode): number[];
32
+ /**
33
+ * 1D Convolution with automatic method selection
34
+ *
35
+ * Automatically selects direct or FFT method based on input sizes.
36
+ *
37
+ * @param x - Input signal
38
+ * @param h - Convolution kernel
39
+ * @param mode - Output mode: 'full' (default), 'same', or 'valid'
40
+ * @returns Convolution result
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Simple convolution
45
+ * const signal = [1, 2, 3, 4, 5];
46
+ * const kernel = [1, 0, -1]; // Edge detection
47
+ * const result = conv(signal, kernel, 'same');
48
+ * ```
49
+ */
50
+ export declare function conv(x: number[] | Float64Array, h: number[] | Float64Array, mode?: ConvMode): number[];
51
+ /**
52
+ * Cross-correlation of two signals
53
+ *
54
+ * Cross-correlation is convolution with the kernel reversed.
55
+ *
56
+ * @param x - First signal
57
+ * @param h - Second signal
58
+ * @param mode - Output mode
59
+ * @returns Cross-correlation result
60
+ */
61
+ export declare function xcorr(x: number[] | Float64Array, h: number[] | Float64Array, mode?: ConvMode): number[];
62
+ /**
63
+ * Auto-correlation of a signal
64
+ *
65
+ * @param x - Input signal
66
+ * @param mode - Output mode
67
+ * @returns Auto-correlation result
68
+ */
69
+ export declare function autocorr(x: number[] | Float64Array, mode?: ConvMode): number[];
70
+ /**
71
+ * Direct 2D convolution
72
+ *
73
+ * @param image - 2D input array
74
+ * @param kernel - 2D convolution kernel
75
+ * @param mode - Output mode
76
+ * @returns 2D convolution result
77
+ */
78
+ export declare function conv2Direct(image: number[][], kernel: number[][], mode?: ConvMode): number[][];
79
+ /**
80
+ * FFT-based 2D convolution
81
+ *
82
+ * @param image - 2D input array
83
+ * @param kernel - 2D convolution kernel
84
+ * @param mode - Output mode
85
+ * @returns 2D convolution result
86
+ */
87
+ export declare function conv2FFT(image: number[][], kernel: number[][], mode?: ConvMode): number[][];
88
+ /**
89
+ * 2D Convolution with automatic method selection
90
+ *
91
+ * @param image - 2D input array
92
+ * @param kernel - 2D convolution kernel
93
+ * @param mode - Output mode: 'full' (default), 'same', or 'valid'
94
+ * @returns 2D convolution result
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * // Edge detection with Sobel kernel
99
+ * const image = [
100
+ * [1, 2, 3],
101
+ * [4, 5, 6],
102
+ * [7, 8, 9],
103
+ * ];
104
+ * const sobelX = [
105
+ * [-1, 0, 1],
106
+ * [-2, 0, 2],
107
+ * [-1, 0, 1],
108
+ * ];
109
+ * const edges = conv2(image, sobelX, 'same');
110
+ * ```
111
+ */
112
+ export declare function conv2(image: number[][], kernel: number[][], mode?: ConvMode): number[][];
113
+ //# sourceMappingURL=conv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conv.d.ts","sourceRoot":"","sources":["../../src/signal/conv.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAYjD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,IAAI,GAAE,QAAiB,GACtB,MAAM,EAAE,CA8CV;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CACrB,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,IAAI,GAAE,QAAiB,GACtB,MAAM,EAAE,CAsDV;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAClB,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,IAAI,GAAE,QAAiB,GACtB,MAAM,EAAE,CAWV;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CACnB,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAC1B,IAAI,GAAE,QAAiB,GACtB,MAAM,EAAE,CAKV;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,IAAI,GAAE,QAAiB,GAAG,MAAM,EAAE,CAEtF;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EAAE,EAAE,EACjB,MAAM,EAAE,MAAM,EAAE,EAAE,EAClB,IAAI,GAAE,QAAiB,GACtB,MAAM,EAAE,EAAE,CA8DZ;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EAAE,EAAE,EACjB,MAAM,EAAE,MAAM,EAAE,EAAE,EAClB,IAAI,GAAE,QAAiB,GACtB,MAAM,EAAE,EAAE,CAiGZ;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAE,QAAiB,GAAG,MAAM,EAAE,EAAE,CAgBhG"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Real FFT: compute the full FFT of a real signal and keep only the first
3
+ * `floor(n/2)+1` bins — the non-redundant half of the conjugate-symmetric spectrum.
4
+ *
5
+ * @param x Real input signal
6
+ * @returns `{ re, im }` arrays of length `floor(n/2)+1`
7
+ */
8
+ export declare function rfft(x: number[]): {
9
+ re: number[];
10
+ im: number[];
11
+ };
12
+ /**
13
+ * Inverse real FFT: reconstruct the full conjugate-symmetric spectrum of length `n`
14
+ * from the non-redundant half produced by {@link rfft} (bins `n/2+1..n-1` are the
15
+ * conjugates of bins `n/2-1..1`), inverse-FFT it, and return the real parts.
16
+ *
17
+ * @param spec `{ re, im }` half-spectrum (bins `0..floor(n/2)`)
18
+ * @param n Length of the reconstructed real signal
19
+ * @returns Real-valued signal of length `n`
20
+ */
21
+ export declare function irfft(spec: {
22
+ re: number[];
23
+ im: number[];
24
+ }, n: number): number[];
25
+ /**
26
+ * Shift the zero-frequency component to the center of the spectrum (roll by `floor(n/2)`).
27
+ */
28
+ export declare function fftshift(x: number[]): number[];
29
+ /**
30
+ * Inverse of {@link fftshift} (roll by `ceil(n/2)`).
31
+ */
32
+ export declare function ifftshift(x: number[]): number[];
33
+ /**
34
+ * DFT sample frequencies: `[0, 1, ..., ceil(n/2)-1, -floor(n/2), ..., -1] / (n*d)`.
35
+ *
36
+ * @param n Number of samples
37
+ * @param d Sample spacing (default 1)
38
+ */
39
+ export declare function fftfreq(n: number, d?: number): number[];
40
+ /**
41
+ * DFT sample frequencies matching {@link rfft} output: `[0, 1, ..., floor(n/2)] / (n*d)`.
42
+ *
43
+ * @param n Number of samples
44
+ * @param d Sample spacing (default 1)
45
+ */
46
+ export declare function rfftfreq(n: number, d?: number): number[];
47
+ /**
48
+ * 2-D FFT: FFT each row, then FFT each column of the result. Delegates directly to
49
+ * the package's N-dimensional `fft`, which already performs exactly this row-then-
50
+ * column transform when given a 2-D array.
51
+ */
52
+ export declare function fftn(x: number[][]): {
53
+ re: number[][];
54
+ im: number[][];
55
+ };
56
+ //# sourceMappingURL=fft-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fft-helpers.d.ts","sourceRoot":"","sources":["../../src/signal/fft-helpers.ts"],"names":[],"mappings":"AA+BA;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,CAYhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAY/E;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAI9C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAI/C;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAE,MAAU,GAAG,MAAM,EAAE,CAW1D;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAE,MAAU,GAAG,MAAM,EAAE,CAO3D;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG;IAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CAAA;CAAE,CAKtE"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Fast Fourier Transform (FFT)
3
+ *
4
+ * Implements the Cooley-Tukey radix-2 decimation-in-time FFT algorithm.
5
+ * For non-power-of-2 lengths, zero-pads to next power of 2.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ /**
10
+ * Complex number representation for FFT
11
+ */
12
+ export interface ComplexNumber {
13
+ re: number;
14
+ im: number;
15
+ }
16
+ /**
17
+ * FFT result containing the frequency spectrum
18
+ */
19
+ export interface FFTResult {
20
+ /** Complex frequency components */
21
+ spectrum: ComplexNumber[];
22
+ /** Original signal length before padding */
23
+ originalLength: number;
24
+ /** Padded length (power of 2) */
25
+ paddedLength: number;
26
+ }
27
+ /**
28
+ * Create a complex number
29
+ */
30
+ export declare function complex(re: number, im?: number): ComplexNumber;
31
+ /**
32
+ * Complex conjugate
33
+ */
34
+ export declare function complexConj(a: ComplexNumber): ComplexNumber;
35
+ /**
36
+ * Complex magnitude
37
+ */
38
+ export declare function complexAbs(a: ComplexNumber): number;
39
+ /**
40
+ * Complex phase/argument
41
+ */
42
+ export declare function complexArg(a: ComplexNumber): number;
43
+ /**
44
+ * Compute the Fast Fourier Transform of a real or complex signal.
45
+ *
46
+ * Uses the Cooley-Tukey radix-2 decimation-in-time algorithm.
47
+ * Input is zero-padded to the next power of 2 if necessary.
48
+ *
49
+ * @param signal - Input signal (real numbers or complex numbers)
50
+ * @returns FFT result with spectrum and length info
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // FFT of a real signal
55
+ * const signal = [1, 0, -1, 0];
56
+ * const result = fft(signal);
57
+ * console.log(result.spectrum); // Frequency components
58
+ *
59
+ * // FFT of a complex signal
60
+ * const complexSignal = [
61
+ * { re: 1, im: 0 },
62
+ * { re: 0, im: 1 },
63
+ * ];
64
+ * const result2 = fft(complexSignal);
65
+ * ```
66
+ */
67
+ export declare function fft(signal: number[] | Float64Array | ComplexNumber[]): FFTResult;
68
+ /**
69
+ * Compute the Inverse Fast Fourier Transform.
70
+ *
71
+ * Recovers the time-domain signal from its frequency spectrum.
72
+ *
73
+ * @param spectrum - Complex frequency spectrum
74
+ * @param originalLength - Optional: truncate result to this length
75
+ * @returns Recovered signal
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * // Round-trip test
80
+ * const signal = [1, 2, 3, 4];
81
+ * const result = fft(signal);
82
+ * const recovered = ifft(result.spectrum, result.originalLength);
83
+ * // recovered ≈ signal
84
+ * ```
85
+ */
86
+ export declare function ifft(spectrum: ComplexNumber[], originalLength?: number): ComplexNumber[];
87
+ /**
88
+ * Compute the real part of IFFT result
89
+ */
90
+ export declare function ifftReal(spectrum: ComplexNumber[], originalLength?: number): number[];
91
+ /**
92
+ * Compute the magnitude spectrum (|X(k)|)
93
+ */
94
+ export declare function fftMagnitude(spectrum: ComplexNumber[]): number[];
95
+ /**
96
+ * Compute the power spectrum (|X(k)|²)
97
+ */
98
+ export declare function fftPower(spectrum: ComplexNumber[]): number[];
99
+ /**
100
+ * Compute the phase spectrum (arg(X(k)))
101
+ */
102
+ export declare function fftPhase(spectrum: ComplexNumber[]): number[];
103
+ /**
104
+ * Compute FFT frequency bins for a given sample rate
105
+ *
106
+ * @param n - Number of FFT points
107
+ * @param sampleRate - Sample rate in Hz
108
+ * @returns Array of frequencies in Hz
109
+ */
110
+ export declare function fftFrequencies(n: number, sampleRate?: number): number[];
111
+ /**
112
+ * Compute the 2D FFT of a matrix
113
+ *
114
+ * @param matrix - 2D array of real or complex values
115
+ * @returns 2D frequency spectrum
116
+ */
117
+ export declare function fft2(matrix: number[][] | ComplexNumber[][]): ComplexNumber[][];
118
+ /**
119
+ * Compute the 2D inverse FFT
120
+ *
121
+ * @param spectrum - 2D frequency spectrum
122
+ * @returns 2D spatial domain result
123
+ */
124
+ export declare function ifft2(spectrum: ComplexNumber[][]): ComplexNumber[][];
125
+ /**
126
+ * Shift zero-frequency component to center of spectrum
127
+ *
128
+ * @param spectrum - FFT spectrum
129
+ * @returns Shifted spectrum
130
+ */
131
+ export declare function fftshift<T>(spectrum: T[]): T[];
132
+ /**
133
+ * Inverse of fftshift
134
+ */
135
+ export declare function ifftshift<T>(spectrum: T[]): T[];
136
+ //# sourceMappingURL=fft.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fft.d.ts","sourceRoot":"","sources":["../../src/signal/fft.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,mCAAmC;IACnC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,4CAA4C;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,GAAE,MAAU,GAAG,aAAa,CAEjE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,aAAa,GAAG,aAAa,CAE3D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,CAEnD;AA0DD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,GAAG,aAAa,EAAE,GAAG,SAAS,CAqChF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAuBxF;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAGrF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAEhE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAE5D;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,GAAE,MAAU,GAAG,MAAM,EAAE,CAa1E;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,aAAa,EAAE,EAAE,GAAG,aAAa,EAAE,EAAE,CAoC9E;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,GAAG,aAAa,EAAE,EAAE,CA8BpE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAI9C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAI/C"}
@@ -0,0 +1,62 @@
1
+ type Vec = readonly number[] | Float64Array;
2
+ /** Polynomial/deconvolution division result: `signal = conv(divisor, quotient) + remainder`. */
3
+ export interface DeconvolveResult {
4
+ quotient: number[];
5
+ remainder: number[];
6
+ }
7
+ /**
8
+ * FIR bandpass filter coefficients by the windowed-sinc method (Hamming
9
+ * window): `h[n] = (f2·sinc(f2·(n−M/2)) − f1·sinc(f1·(n−M/2)))·hamming[n]`,
10
+ * `M = numtaps−1`. `[f1, f2]` are cutoffs normalized to Nyquist (1 = Nyquist).
11
+ * This is the array-cutoff (bandpass) case the scalar-only `firwin` in
12
+ * `../signal-filter-extra.ts` didn't support (resolves the Phase-0 note).
13
+ */
14
+ export declare function firwinBandpass(numtaps: number, cutoffs: readonly [number, number]): number[];
15
+ /**
16
+ * Savitzky-Golay smoothing (`scipy.signal.savgol_filter`, default `mode='interp'`).
17
+ * For each interior position, fits a degree-`polyorder` polynomial (via the
18
+ * normal equations over a Vandermonde of the window offsets) to the centered
19
+ * `windowLength`-point window and takes the fitted value at the center. Edge
20
+ * points reuse the nearest full boundary window's fit, evaluated at the edge
21
+ * point's actual offset from that window's center (scipy's boundary handling).
22
+ * Exact on polynomials of degree <= `polyorder`.
23
+ */
24
+ export declare function savgol(x: Vec, windowLength: number, polyorder: number): number[];
25
+ /**
26
+ * FIR/polynomial deconvolution (`scipy.signal.deconvolve`): standard
27
+ * synthetic long division so that `signal = conv(divisor, quotient) + remainder`,
28
+ * with `quotient` of length `signal.length - divisor.length + 1` and
29
+ * `remainder` the same length as `signal` (zero when `divisor` exactly divides).
30
+ */
31
+ export declare function deconvolve(signal: Vec, divisor: Vec): DeconvolveResult;
32
+ /**
33
+ * Wiener adaptive filter (`scipy.signal.wiener`-style, per-sample noise
34
+ * estimate): local mean `m` and variance `v` over a sliding window of size
35
+ * `mysize` (same-length, zero-padded at the edges — matches `convDirect`'s
36
+ * `'same'` convention), noise power `= mean(v)`; output
37
+ * `m + max(0, v−noise)/max(v, noise)·(x−m)` (0 where both `v` and `noise` are 0).
38
+ */
39
+ export declare function wiener(x: Vec, mysize?: number): number[];
40
+ /**
41
+ * Least-squares linear-phase FIR design (`scipy.signal.firls`): `bands` is a
42
+ * flat list of `[lo, hi]` band-edge pairs (normalized to Nyquist, 1 = Nyquist)
43
+ * and `desired` the corresponding response values at those edges (linearly
44
+ * interpolated within each band; gaps between bands are unconstrained
45
+ * transition regions). Solves the normal equations of the cosine-basis
46
+ * representation of a symmetric (Type I odd-length / Type II even-length)
47
+ * linear-phase filter against a dense trapezoid-quadrature sampling of the
48
+ * specified bands, then maps the fitted basis coefficients back to taps.
49
+ */
50
+ export declare function firls(numtaps: number, bands: readonly number[], desired: readonly number[]): number[];
51
+ /**
52
+ * Parks-McClellan-style equiripple FIR design. **This is NOT the exact
53
+ * Remez-exchange algorithm** — it is Lawson's algorithm, an iteratively
54
+ * reweighted least squares (IRLS) scheme that approximates the minimax
55
+ * (Chebyshev) solution by repeatedly re-solving the `firls` normal equations
56
+ * with per-sample weights pushed up wherever the previous iteration's error
57
+ * was largest, converging toward (but not guaranteed to reach) a true
58
+ * equiripple response. Documented as approximate per the Task 3 spec.
59
+ */
60
+ export declare function remez(numtaps: number, bands: readonly number[], desired: readonly number[]): number[];
61
+ export {};
62
+ //# sourceMappingURL=fir-smoothing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fir-smoothing.d.ts","sourceRoot":"","sources":["../../src/signal/fir-smoothing.ts"],"names":[],"mappings":"AAUA,KAAK,GAAG,GAAG,SAAS,MAAM,EAAE,GAAG,YAAY,CAAC;AAG5C,gGAAgG;AAChG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAsCD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAa5F;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BhF;AAID;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,gBAAgB,CAiBtE;AAID;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,SAAI,GAAG,MAAM,EAAE,CAsBnD;AAoHD;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,EAAE,CAUV;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,EAAE,CAkBV"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Chebyshev I/II and elliptic (Cauer) IIR filter design, plus the supporting
3
+ * `zpk2sos`/`sosfilt`/`bilinear`/`buttord` utilities. Extends the Butterworth
4
+ * pipeline in `../signal-filter-extra.ts` with two more analog prototypes and
5
+ * reuses its shared zpk→transfer-function plumbing (`analogToDigital`,
6
+ * `polyFromRoots`). Matches `scipy.signal` — every coefficient set pinned
7
+ * against `scipy.signal.{cheby1,cheby2,ellip,bilinear,buttord}` (see
8
+ * `functions/tests/iir-design.test.ts`).
9
+ *
10
+ * The elliptic prototype (`ellipap`) follows Orfanidis, "Lecture Notes on
11
+ * Elliptic Filter Design" (the algorithm scipy itself implements): the filter
12
+ * degree equation is solved in closed form via the theta-function nome
13
+ * expansion (`ellipdeg`), and the "arc Jacobi sc" root (`arcJacSc1`) via the
14
+ * descending Landen transformation (`arcJacSn`) — no numerical optimizer is
15
+ * needed. Reuses the repo's existing AGM-based `ellipticKScalar` and
16
+ * `jacobiSN`/`jacobiCN`/`jacobiDN` (Phase 5 special functions, `m = k²`
17
+ * convention, matching scipy's `ellipk`/`ellipj`).
18
+ */
19
+ import { Complex } from '@danielsimonjr/mathts-core';
20
+ import { type FilterBtype } from '../signal-filter-extra.js';
21
+ type Vec = readonly number[] | Float64Array;
22
+ /**
23
+ * Chebyshev Type I digital IIR filter design — equiripple in the passband, `rp`
24
+ * dB of ripple. `Wn` is the cutoff (scalar) or `[low, high]` band edges,
25
+ * normalized to Nyquist. Matches `scipy.signal.cheby1(N, rp, Wn, btype)`.
26
+ */
27
+ export declare function cheby1(N: number, rp: number, Wn: number | readonly number[], btype?: FilterBtype): {
28
+ b: number[];
29
+ a: number[];
30
+ };
31
+ /**
32
+ * Chebyshev Type II digital IIR filter design — equiripple in the stopband,
33
+ * `rs` dB of stopband attenuation, monotone passband. `Wn` is the cutoff
34
+ * (scalar) or `[low, high]` band edges, normalized to Nyquist. Matches
35
+ * `scipy.signal.cheby2(N, rs, Wn, btype)`.
36
+ */
37
+ export declare function cheby2(N: number, rs: number, Wn: number | readonly number[], btype?: FilterBtype): {
38
+ b: number[];
39
+ a: number[];
40
+ };
41
+ /**
42
+ * Elliptic (Cauer) digital IIR filter design — equiripple in both passband
43
+ * (`rp` dB) and stopband (`rs` dB); the steepest roll-off of the four classical
44
+ * IIR families for a given order. `Wn` is the cutoff (scalar) or `[low, high]`
45
+ * band edges, normalized to Nyquist. Matches `scipy.signal.ellip(N, rp, rs, Wn,
46
+ * btype)` exactly (verified against `scipy.signal` 1.17.1 — see
47
+ * `functions/tests/iir-design.test.ts`); this is a full port of scipy's
48
+ * closed-form (nome-based) elliptic design, not an approximation.
49
+ */
50
+ export declare function ellip(N: number, rp: number, rs: number, Wn: number | readonly number[], btype?: FilterBtype): {
51
+ b: number[];
52
+ a: number[];
53
+ };
54
+ /**
55
+ * Analog-to-digital bilinear (Tustin) transform of a transfer function: given
56
+ * `H(s) = b(s)/a(s)` (coefficients highest-degree-first), substitutes
57
+ * `s = 2·fs·(z−1)/(z+1)` to produce the digital `{ b, a }` (no pre-warping is
58
+ * done — the caller pre-warps `fs`/critical frequencies if needed). Matches
59
+ * `scipy.signal.bilinear(b, a, fs)`.
60
+ */
61
+ export declare function bilinear(bIn: Vec, aIn: Vec, fs: number): {
62
+ b: number[];
63
+ a: number[];
64
+ };
65
+ /**
66
+ * Minimum Butterworth filter order (and the corresponding `-3dB`-ish natural
67
+ * frequency `Wn`) meeting a passband/stopband spec, for a digital lowpass
68
+ * (`wp < ws`) or highpass (`wp > ws`) filter. `wp`/`ws` are normalized to
69
+ * Nyquist (0..1); `gpass`/`gstop` are in dB. Matches
70
+ * `scipy.signal.buttord(wp, ws, gpass, gstop)` (scalar/digital case only —
71
+ * the bandpass/bandstop array form is not implemented).
72
+ */
73
+ export declare function buttord(wp: number, ws: number, gpass: number, gstop: number): {
74
+ N: number;
75
+ Wn: number;
76
+ };
77
+ type ZpkRoot = number | Complex;
78
+ /**
79
+ * Group zeros/poles/gain into cascaded second-order sections:
80
+ * `[[b0,b1,b2,a0,a1,a2], …]`, each a monic-denominator biquad (`a0 = 1`) with
81
+ * the overall gain folded into the first section's numerator. `z` is
82
+ * zero-padded (roots at the origin) if shorter than `p`. Matches
83
+ * `scipy.signal.zpk2sos` in effect (the two decompositions can differ in
84
+ * pairing order, but the resulting cascaded transfer function is identical).
85
+ */
86
+ export declare function zpk2sos(z: readonly ZpkRoot[], p: readonly ZpkRoot[], k: number): number[][];
87
+ /**
88
+ * Apply a cascade of second-order sections (`[[b0,b1,b2,a0,a1,a2], …]`, as
89
+ * produced by `zpk2sos`) to `x`, each biquad in direct-form-II transposed.
90
+ * Matches `scipy.signal.sosfilt(sos, x)`.
91
+ */
92
+ export declare function sosfilt(sos: readonly (readonly number[])[], x: Vec): number[];
93
+ export {};
94
+ //# sourceMappingURL=iir-design.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iir-design.d.ts","sourceRoot":"","sources":["../../src/signal/iir-design.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAC;AAKnC,KAAK,GAAG,GAAG,SAAS,MAAM,EAAE,GAAG,YAAY,CAAC;AAoB5C;;;;GAIG;AACH,wBAAgB,MAAM,CACpB,CAAC,EAAE,MAAM,EACT,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAC9B,KAAK,GAAE,WAAmB,GACzB;IAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAI9B;AAgCD;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,CAAC,EAAE,MAAM,EACT,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAC9B,KAAK,GAAE,WAAmB,GACzB;IAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAI9B;AAkJD;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CACnB,CAAC,EAAE,MAAM,EACT,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAC9B,KAAK,GAAE,WAAmB,GACzB;IAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAK9B;AA4BD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,GAAG;IAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CA8BrF;AAID;;;;;;;GAOG;AACH,wBAAgB,OAAO,CACrB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAc3B;AAID,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAoDhC;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAmB3F;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,EAAE,CAS7E"}