numz 0.0.2 → 0.1.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.
- package/demo/index.html +2 -2
- package/demo/main.js +11 -4
- package/package.json +2 -2
- package/src/calculus/derivative/index.js +16 -0
- package/src/calculus/index.js +22 -0
- package/src/calculus/integral/index.js +21 -0
- package/src/discret/bitwise/index.js +34 -0
- package/src/discret/combination/index.js +86 -0
- package/src/discret/index-dep.js +110 -0
- package/src/discret/index.js +4 -0
- package/src/discret/permutation/index.js +89 -0
- package/src/discret/sequences/index.js +30 -0
- package/src/index.js +6 -1
- package/src/signal/fft/index.js +10 -6
- package/src/signal/functions/index.js +3 -0
- package/src/signal/functions/periodic/index.js +69 -0
- package/src/signal/functions/pulse/index.js +116 -0
- package/src/signal/functions/sequence/index.js +103 -0
- package/src/signal/index.js +2 -0
- package/src/stats/distributions/continuos/index.js +35 -0
- package/src/stats/distributions/discret/index.js +45 -0
- package/src/stats/distributions/index.js +3 -0
- package/src/stats/distributions/multivar/index.js +40 -0
- package/src/stats/index.js +2 -1
- package/src/ufunc/index.js +1 -0
- package/test.js +0 -0
package/demo/index.html
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Vite App</title>
|
|
8
|
-
<link
|
|
8
|
+
<!-- <link
|
|
9
9
|
href="https://fonts.googleapis.com/css?family=Gloria+Hallelujah&display=swap"
|
|
10
10
|
rel="stylesheet"
|
|
11
|
-
/>
|
|
11
|
+
/> -->
|
|
12
12
|
<!-- <style>
|
|
13
13
|
body{
|
|
14
14
|
font-family: "Gloria Hallelujah", cursive;
|
package/demo/main.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { percentile } from "numz/stats";
|
|
2
|
+
import { fft1d } from 'numz/signal'
|
|
3
|
+
import { Complex } from "ziko/math/complex";
|
|
4
|
+
|
|
5
|
+
console.log(
|
|
6
|
+
percentile([1,2,3,4,5,6,7,8,9,10], 50)
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// console.log(fft1d([1, 2, 1, -1, 1.5]))
|
|
10
|
+
|
|
11
|
+
// console.log(Complex)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "numz",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "scientific computing with zikojs",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
"rollup": "^4.24.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"ziko": "^0.54.
|
|
32
|
+
"ziko": "^0.54.4"
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const derivative = (f, x, h = 1e-8) => (f(x + h) - f(x - h)) / (2 * h);
|
|
2
|
+
export const derivative_n = (f, x, n = 1, h = 1e-8) => {
|
|
3
|
+
if (n === 0) return f(x);
|
|
4
|
+
const df = (x0) => derivative(f, x0, h);
|
|
5
|
+
return derivative_n(df, x, n - 1, h);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export const partial_derivative = (f, vars, varIndex, h = 1e-8) => {
|
|
10
|
+
const x1 = [...vars];
|
|
11
|
+
const x2 = [...vars];
|
|
12
|
+
x1[varIndex] += h;
|
|
13
|
+
x2[varIndex] -= h;
|
|
14
|
+
return (f(...x1) - f(...x2)) / (2 * h);
|
|
15
|
+
};
|
|
16
|
+
export const gradient = (f, vars, h = 1e-8) => vars.map((_, i) => partial_derivative(f, vars, i, h));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export * from './derivative/index.js'
|
|
2
|
+
export * from './integral/index.js'
|
|
3
|
+
import { factorial } from "../discret";
|
|
4
|
+
export const taylor_series = (f, x0, n=5, h=1e-5) => {
|
|
5
|
+
let sum=0;
|
|
6
|
+
for(let i=0;i<=n;i++){
|
|
7
|
+
sum += derivative_n(f,x0,i,h) / factorial(i)*(x0**i);
|
|
8
|
+
}
|
|
9
|
+
return sum;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const newton_raphson = (f, x0, tol=1e-8, maxIter=100) => {
|
|
13
|
+
let x=x0;
|
|
14
|
+
for(let i=0;i<maxIter;i++){
|
|
15
|
+
const fx=f(x), dfx=derivative(f,x);
|
|
16
|
+
if(Math.abs(dfx)<1e-12) break;
|
|
17
|
+
const dx=fx/dfx;
|
|
18
|
+
x-=dx;
|
|
19
|
+
if(Math.abs(dx)<tol) break;
|
|
20
|
+
}
|
|
21
|
+
return x;
|
|
22
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const integral_simpson = (f, a, b, n=1000) => {
|
|
2
|
+
if(n%2===1) n+=1;
|
|
3
|
+
const h=(b-a)/n;
|
|
4
|
+
let s=f(a)+f(b);
|
|
5
|
+
for(let i=1;i<n;i++){
|
|
6
|
+
s+=f(a+i*h)*(i%2===0?2:4);
|
|
7
|
+
}
|
|
8
|
+
return s*h/3;
|
|
9
|
+
};
|
|
10
|
+
export const integral_trapezoid = (f, a, b, n=1000) => {
|
|
11
|
+
const h=(b-a)/n;
|
|
12
|
+
let s=(f(a)+f(b))/2;
|
|
13
|
+
for(let i=1;i<n;i++) s+=f(a+i*h);
|
|
14
|
+
return s*h;
|
|
15
|
+
};
|
|
16
|
+
export const integral_midpoint = (f, a, b, n=1000)=>{
|
|
17
|
+
const h=(b-a)/n;
|
|
18
|
+
let s=0;
|
|
19
|
+
for(let i=0;i<n;i++) s+=f(a+(i+0.5)*h);
|
|
20
|
+
return s*h;
|
|
21
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export const bitmasks = (n) => {
|
|
4
|
+
const res = [];
|
|
5
|
+
for (let i = 0; i < 1 << n; i++) {
|
|
6
|
+
const mask = [];
|
|
7
|
+
for (let j = 0; j < n; j++) mask.push((i >> j) & 1);
|
|
8
|
+
res.push(mask);
|
|
9
|
+
}
|
|
10
|
+
return res;
|
|
11
|
+
};
|
|
12
|
+
export const subsets_by_mask = (arr) => {
|
|
13
|
+
const n = arr.length,
|
|
14
|
+
res = [];
|
|
15
|
+
for (let i = 0; i < 1 << n; i++) {
|
|
16
|
+
const subset = [];
|
|
17
|
+
for (let j = 0; j < n; j++) if ((i >> j) & 1) subset.push(arr[j]);
|
|
18
|
+
res.push(subset);
|
|
19
|
+
}
|
|
20
|
+
return res;
|
|
21
|
+
};
|
|
22
|
+
export const gray_code = (n) => {
|
|
23
|
+
if (n === 0) return [0];
|
|
24
|
+
const prev = gray_code(n - 1);
|
|
25
|
+
return [...prev, ...prev.map((x) => x | (1 << (n - 1)))];
|
|
26
|
+
};
|
|
27
|
+
export const hamming_weight = (x) => {
|
|
28
|
+
let count = 0;
|
|
29
|
+
while (x) {
|
|
30
|
+
x &= x - 1;
|
|
31
|
+
count++;
|
|
32
|
+
}
|
|
33
|
+
return count;
|
|
34
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const combinations = (arr, repetition = false) => {
|
|
2
|
+
const n = arr.length,
|
|
3
|
+
result = [];
|
|
4
|
+
if (!repetition) {
|
|
5
|
+
const back = (start, cur) => {
|
|
6
|
+
if (cur.length) result.push([...cur]);
|
|
7
|
+
for (let i = start; i < n; i++) {
|
|
8
|
+
cur.push(arr[i]);
|
|
9
|
+
back(i + 1, cur);
|
|
10
|
+
cur.pop();
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
back(0, []);
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
const back = (start, cur) => {
|
|
17
|
+
if (cur.length) result.push([...cur]);
|
|
18
|
+
for (let i = start; i < n; i++) {
|
|
19
|
+
cur.push(arr[i]);
|
|
20
|
+
back(i, cur);
|
|
21
|
+
cur.pop();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
back(0, []);
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export const k_combinations = (arr, k, repetition = false) => {
|
|
31
|
+
const n = arr.length,
|
|
32
|
+
result = [];
|
|
33
|
+
if (!repetition) {
|
|
34
|
+
const back = (start, cur) => {
|
|
35
|
+
if (cur.length === k) result.push([...cur]);
|
|
36
|
+
else
|
|
37
|
+
for (let i = start; i < n; i++) {
|
|
38
|
+
cur.push(arr[i]);
|
|
39
|
+
back(i + 1, cur);
|
|
40
|
+
cur.pop();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
back(0, []);
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
const back = (start, cur) => {
|
|
47
|
+
if (cur.length === k) result.push([...cur]);
|
|
48
|
+
else
|
|
49
|
+
for (let i = start; i < n; i++) {
|
|
50
|
+
cur.push(arr[i]);
|
|
51
|
+
back(i, cur);
|
|
52
|
+
cur.pop();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
back(0, []);
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const multiset_combinations = (arr, k) => {
|
|
60
|
+
const counter = {},
|
|
61
|
+
unique = [];
|
|
62
|
+
for (const x of arr) {
|
|
63
|
+
if (!counter[x]) {
|
|
64
|
+
counter[x] = 0;
|
|
65
|
+
unique.push(x);
|
|
66
|
+
}
|
|
67
|
+
counter[x]++;
|
|
68
|
+
}
|
|
69
|
+
const result = [];
|
|
70
|
+
const back = (i, cur, remaining) => {
|
|
71
|
+
if (cur.length === k) {
|
|
72
|
+
result.push([...cur]);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (i >= unique.length) return;
|
|
76
|
+
const u = unique[i],
|
|
77
|
+
max_use = Math.min(counter[u], k - cur.length);
|
|
78
|
+
for (let use = 0; use <= max_use; use++) {
|
|
79
|
+
for (let j = 0; j < use; j++) cur.push(u);
|
|
80
|
+
back(i + 1, cur, remaining - use);
|
|
81
|
+
for (let j = 0; j < use; j++) cur.pop();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
back(0, [], k);
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// ==========================================
|
|
2
|
+
// Discrete Mathematics / Combinatorics
|
|
3
|
+
// ==========================================
|
|
4
|
+
// ------------------------------
|
|
5
|
+
// Binomial & Multichoose
|
|
6
|
+
// ------------------------------
|
|
7
|
+
export const binomial = (n, k) => {
|
|
8
|
+
if (n !== Math.floor(n) || k !== Math.floor(k))
|
|
9
|
+
return TypeError("n,k must be integers");
|
|
10
|
+
if (k < 0 || k > n) return 0;
|
|
11
|
+
k = Math.min(k, n - k);
|
|
12
|
+
let r = 1;
|
|
13
|
+
for (let i = 1; i <= k; i++) r = (r * (n - (k - i))) / i;
|
|
14
|
+
return r;
|
|
15
|
+
};
|
|
16
|
+
export const comb_repetition = (n, k) => binomial(n + k - 1, k);
|
|
17
|
+
export const multichoose = comb_repetition;
|
|
18
|
+
|
|
19
|
+
// Comb // Perm
|
|
20
|
+
export const power_set = (arr) => {
|
|
21
|
+
const n = arr.length,
|
|
22
|
+
result = [];
|
|
23
|
+
for (let i = 0; i < 1 << n; i++) {
|
|
24
|
+
const subset = [];
|
|
25
|
+
for (let j = 0; j < n; j++) if ((i >> j) & 1) subset.push(arr[j]);
|
|
26
|
+
result.push(subset);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const cartesian = (...sets) => {
|
|
32
|
+
let result = [[]];
|
|
33
|
+
for (const set of sets) {
|
|
34
|
+
const temp = [];
|
|
35
|
+
for (const x of result) for (const y of set) temp.push([...x, y]);
|
|
36
|
+
result = temp;
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ------------------------------
|
|
42
|
+
// Counting / Sequences
|
|
43
|
+
// ------------------------------
|
|
44
|
+
export const derangement = (n) => {
|
|
45
|
+
if (n !== Math.floor(n)) return TypeError("n must be integer");
|
|
46
|
+
let r = 1;
|
|
47
|
+
for (let i = 1; i <= n; i++) {
|
|
48
|
+
r = i * r + (i % 2 === 0 ? 1 : -1);
|
|
49
|
+
}
|
|
50
|
+
return Math.round(r / Math.E);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const catalan = (n) => binomial(2 * n, n) / (n + 1);
|
|
54
|
+
|
|
55
|
+
export const stirling2 = (n, k) => {
|
|
56
|
+
if (k < 0 || k > n) return 0;
|
|
57
|
+
let S = Array(k + 1).fill(0);
|
|
58
|
+
S[0] = 1;
|
|
59
|
+
for (let i = 1; i <= n; i++)
|
|
60
|
+
for (let j = k; j > 0; j--) S[j] = j * S[j] + S[j - 1];
|
|
61
|
+
return S[k];
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const bell = (n) => {
|
|
65
|
+
let B = [1];
|
|
66
|
+
for (let i = 1; i <= n; i++) {
|
|
67
|
+
B[i] = 0;
|
|
68
|
+
for (let j = 0; j < i; j++) B[i] += binomial(i - 1, j) * B[j];
|
|
69
|
+
}
|
|
70
|
+
return B[n];
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const lah = (n, k) => {
|
|
74
|
+
if (n < 0 || k < 0 || k > n) return 0;
|
|
75
|
+
return (binomial(n - 1, k - 1) * factorial(n)) / factorial(k);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// // Eulerian numbers: number of permutations with exactly k ascents
|
|
79
|
+
export const eulerian = (n,k)=>{
|
|
80
|
+
if(k<0||k>=n) return 0;
|
|
81
|
+
let dp=[Array(k+2).fill(0)];
|
|
82
|
+
dp[0][0]=1;
|
|
83
|
+
for(let i=1;i<=n;i++){
|
|
84
|
+
const ndp=Array(k+2).fill(0);
|
|
85
|
+
for(let j=0;j<=Math.min(i-1,k);j++){
|
|
86
|
+
ndp[j]= (i-j)*dp[i-1]?[j]??0:
|
|
87
|
+
ndp[j+1]= (j+1)*dp[i-1][j];
|
|
88
|
+
}
|
|
89
|
+
dp=ndp;
|
|
90
|
+
}
|
|
91
|
+
return dp[k];
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Partition numbers
|
|
95
|
+
export const partition_number = (n) => {
|
|
96
|
+
if (n === 0) return 1;
|
|
97
|
+
let p = [1];
|
|
98
|
+
for (let i = 1; i <= n; i++) {
|
|
99
|
+
let s = 0;
|
|
100
|
+
for (let k = 1; ; k++) {
|
|
101
|
+
let j1 = i - (k * (3 * k - 1)) / 2;
|
|
102
|
+
let j2 = i - (k * (3 * k + 1)) / 2;
|
|
103
|
+
if (j1 < 0 && j2 < 0) break;
|
|
104
|
+
if (j1 >= 0) s += (k % 2 === 0 ? -1 : 1) * p[j1];
|
|
105
|
+
if (j2 >= 0) s += (k % 2 === 0 ? -1 : 1) * p[j2];
|
|
106
|
+
}
|
|
107
|
+
p.push(s);
|
|
108
|
+
}
|
|
109
|
+
return p[n];
|
|
110
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export const permutations = (arr, repetition = false) => {
|
|
2
|
+
const n = arr.length,
|
|
3
|
+
result = [];
|
|
4
|
+
if (repetition) {
|
|
5
|
+
const back = (cur) => {
|
|
6
|
+
if (cur.length === n) result.push([...cur]);
|
|
7
|
+
else
|
|
8
|
+
for (let i = 0; i < n; i++) {
|
|
9
|
+
cur.push(arr[i]);
|
|
10
|
+
back(cur);
|
|
11
|
+
cur.pop();
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
back([]);
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
const back = (cur, used) => {
|
|
18
|
+
if (cur.length === n) result.push([...cur]);
|
|
19
|
+
else
|
|
20
|
+
for (let i = 0; i < n; i++) {
|
|
21
|
+
if (used[i]) continue;
|
|
22
|
+
used[i] = true;
|
|
23
|
+
cur.push(arr[i]);
|
|
24
|
+
back(cur, used);
|
|
25
|
+
cur.pop();
|
|
26
|
+
used[i] = false;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
back([], Array(n).fill(false));
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export const k_permutations = (arr, k, repetition = false) => {
|
|
35
|
+
const n = arr.length,
|
|
36
|
+
result = [];
|
|
37
|
+
if (repetition) {
|
|
38
|
+
const back = (cur) => {
|
|
39
|
+
if (cur.length === k) result.push([...cur]);
|
|
40
|
+
else
|
|
41
|
+
for (let i = 0; i < n; i++) {
|
|
42
|
+
cur.push(arr[i]);
|
|
43
|
+
back(cur);
|
|
44
|
+
cur.pop();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
back([]);
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
const back = (cur, used) => {
|
|
51
|
+
if (cur.length === k) result.push([...cur]);
|
|
52
|
+
else
|
|
53
|
+
for (let i = 0; i < n; i++) {
|
|
54
|
+
if (used[i]) continue;
|
|
55
|
+
used[i] = true;
|
|
56
|
+
cur.push(arr[i]);
|
|
57
|
+
back(cur, used);
|
|
58
|
+
cur.pop();
|
|
59
|
+
used[i] = false;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
back([], Array(n).fill(false));
|
|
63
|
+
return result;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const multiset_permutations = (arr) => {
|
|
67
|
+
const result = [],
|
|
68
|
+
counter = {};
|
|
69
|
+
for (const x of arr) counter[x] = (counter[x] || 0) + 1;
|
|
70
|
+
const unique = Object.keys(counter);
|
|
71
|
+
const n = arr.length;
|
|
72
|
+
const back = (cur) => {
|
|
73
|
+
if (cur.length === n) {
|
|
74
|
+
result.push([...cur]);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
for (const u of unique) {
|
|
78
|
+
if (counter[u] > 0) {
|
|
79
|
+
cur.push(u);
|
|
80
|
+
counter[u]--;
|
|
81
|
+
back(cur);
|
|
82
|
+
cur.pop();
|
|
83
|
+
counter[u]++;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
back([]);
|
|
88
|
+
return result;
|
|
89
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const factorial = (n) => {
|
|
2
|
+
if (n < 0 || n !== Math.floor(n))
|
|
3
|
+
return TypeError("n must be non-negative integer");
|
|
4
|
+
let r = 1;
|
|
5
|
+
for (let i = 2; i <= n; i++) r *= i;
|
|
6
|
+
return r;
|
|
7
|
+
};
|
|
8
|
+
export const double_factorial = (n) => {
|
|
9
|
+
if (n < 0 || n !== Math.floor(n))
|
|
10
|
+
return TypeError("n must be non-negative integer");
|
|
11
|
+
let r = 1;
|
|
12
|
+
for (let i = n; i > 1; i -= 2) r *= i;
|
|
13
|
+
return r;
|
|
14
|
+
};
|
|
15
|
+
export const falling = (n, k) => {
|
|
16
|
+
if (n !== Math.floor(n) || k !== Math.floor(k))
|
|
17
|
+
return TypeError("n,k must be integers");
|
|
18
|
+
if (k < 0) return 0;
|
|
19
|
+
let r = 1;
|
|
20
|
+
for (let i = 0; i < k; i++) r *= n - i;
|
|
21
|
+
return r;
|
|
22
|
+
};
|
|
23
|
+
export const rising = (n, k) => {
|
|
24
|
+
if (n !== Math.floor(n) || k !== Math.floor(k))
|
|
25
|
+
return TypeError("n,k must be integers");
|
|
26
|
+
if (k < 0) return 0;
|
|
27
|
+
let r = 1;
|
|
28
|
+
for (let i = 0; i < k; i++) r *= n + i;
|
|
29
|
+
return r;
|
|
30
|
+
};
|
package/src/index.js
CHANGED
package/src/signal/fft/index.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
import { Complex } from 'ziko/math/complex'
|
|
2
|
+
import {add, sub} from 'ziko/math/functions/arithmetic'
|
|
3
|
+
export function fft1d(arr) {
|
|
2
4
|
const N = arr.length;
|
|
3
5
|
if (N === 1) return [arr[0]];
|
|
4
6
|
|
|
5
7
|
const even = fft1d(arr.filter((_, i) => i % 2 === 0));
|
|
6
8
|
const odd = fft1d(arr.filter((_, i) => i % 2 === 1));
|
|
9
|
+
|
|
10
|
+
|
|
7
11
|
|
|
8
12
|
const out = new Array(N);
|
|
9
13
|
for (let k = 0; k < N/2; k++) {
|
|
10
|
-
const t = Complex.
|
|
11
|
-
out[k] = even[k]
|
|
12
|
-
out[k + N/2] = even[k]
|
|
14
|
+
const t = Complex.Twidlle(N, k).mul(odd[k]);
|
|
15
|
+
out[k] = add(even[k], t)
|
|
16
|
+
out[k + N/2] = sub(even[k], t)
|
|
13
17
|
}
|
|
14
18
|
return out;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
function fftnd(data) {
|
|
21
|
+
export function fftnd(data) {
|
|
18
22
|
if (data instanceof Matrix) data = data.toComplex();
|
|
19
23
|
|
|
20
24
|
if (Array.isArray(data) && !Array.isArray(data[0])) {
|
|
@@ -41,7 +45,7 @@ function fftnd(data) {
|
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
if (Array.isArray(data)) {
|
|
44
|
-
return data.map(
|
|
48
|
+
return data.map(fftnd);
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
throw new Error("Invalid data type for FFT");
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// --------------------------
|
|
2
|
+
// Corrected Periodic Functions with Duty
|
|
3
|
+
// --------------------------
|
|
4
|
+
|
|
5
|
+
// Square wave: amplitude A, period T, duty cycle, centered at t0
|
|
6
|
+
export const square = (t, T = 1, A = 1, duty = 0.5, t0 = 0) => {
|
|
7
|
+
const f = (v) => {
|
|
8
|
+
const phase = ((v - t0) % T + T) % T; // normalize to [0,T)
|
|
9
|
+
return phase < duty * T ? A : -A;
|
|
10
|
+
};
|
|
11
|
+
if (Array.isArray(t)) return t.map(f);
|
|
12
|
+
return f(t);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Triangle wave: amplitude A, period T, duty cycle, centered at t0
|
|
16
|
+
export const triangle = (t, T = 1, A = 1, duty = 0.5, t0 = 0) => {
|
|
17
|
+
const f = (v) => {
|
|
18
|
+
const phase = ((v - t0) % T + T) % T;
|
|
19
|
+
if (phase < duty * T) {
|
|
20
|
+
return (A / (duty * T)) * phase * 2 - A; // rising slope
|
|
21
|
+
} else {
|
|
22
|
+
return A - (A / ((1 - duty) * T)) * (phase - duty * T) * 2; // falling slope
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
if (Array.isArray(t)) return t.map(f);
|
|
26
|
+
return f(t);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Sawtooth wave: amplitude A, period T, duty cycle, centered at t0
|
|
30
|
+
export const sawtoothPeriodic = (t, T = 1, A = 1, duty = 1, t0 = 0) => {
|
|
31
|
+
const f = (v) => {
|
|
32
|
+
const phase = ((v - t0) % T + T) % T;
|
|
33
|
+
if (phase < duty * T) {
|
|
34
|
+
return (A / (duty * T)) * phase - A; // rising part
|
|
35
|
+
} else {
|
|
36
|
+
return A - (A / ((1 - duty) * T)) * (phase - duty * T); // optional falling part
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (Array.isArray(t)) return t.map(f);
|
|
40
|
+
return f(t);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Pulse train: amplitude A, period T, pulse width, centered at t0
|
|
44
|
+
export const pulseTrain = (t, T = 1, width = 0.5, A = 1, t0 = 0) => {
|
|
45
|
+
const f = (v) => {
|
|
46
|
+
const phase = ((v - t0) % T + T) % T;
|
|
47
|
+
return phase < width ? A : 0;
|
|
48
|
+
};
|
|
49
|
+
if (Array.isArray(t)) return t.map(f);
|
|
50
|
+
return f(t);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// PWM: amplitude A, period T, duty cycle, centered at t0
|
|
54
|
+
export const pwm = (t, T = 1, duty = 0.5, A = 1, t0 = 0) => {
|
|
55
|
+
const f = (v) => {
|
|
56
|
+
const phase = ((v - t0) % T + T) % T;
|
|
57
|
+
return phase < duty * T ? A : -A;
|
|
58
|
+
};
|
|
59
|
+
if (Array.isArray(t)) return t.map(f);
|
|
60
|
+
return f(t);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
// Sinusoidal wave
|
|
65
|
+
export const sinusoid = (t, f = 1, A = 1, phase = 0) => {
|
|
66
|
+
const fcn = (v) => A * Math.sin(2 * Math.PI * f * v + phase);
|
|
67
|
+
if (Array.isArray(t)) return t.map(fcn);
|
|
68
|
+
return fcn(t);
|
|
69
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export const noise = null
|
|
2
|
+
// Sign function (signum)
|
|
3
|
+
export const signum = (t, t0 = 0, A = 1) => {
|
|
4
|
+
if (Array.isArray(t)) return t.map(v => (v - t0) > 0 ? A : (v - t0) < 0 ? -A : 0);
|
|
5
|
+
return (t - t0) > 0 ? A : (t - t0) < 0 ? -A : 0;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// Ramp function
|
|
9
|
+
export const rampe = (t, t0 = 0, A = 1) => {
|
|
10
|
+
if (Array.isArray(t)) return t.map(v => v < t0 ? 0 : A * (v - t0));
|
|
11
|
+
return t < t0 ? 0 : A * (t - t0);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Rectangular pulse (width = 1 for simplicity, centered at t0)
|
|
15
|
+
export const rect = (t, t0 = 0, A = 1, width = 1) => {
|
|
16
|
+
const half = width / 2;
|
|
17
|
+
if (Array.isArray(t)) return t.map(v => (v >= t0 - half && v <= t0 + half ? A : 0));
|
|
18
|
+
return (t >= t0 - half && t <= t0 + half ? A : 0);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Triangular pulse (period T, centered at t0)
|
|
22
|
+
export const tri = (t, T = 1, t0 = 0, A = 1) => {
|
|
23
|
+
const half = T / 2;
|
|
24
|
+
const x = t - t0;
|
|
25
|
+
if (Array.isArray(t)) {
|
|
26
|
+
return t.map(v => {
|
|
27
|
+
const y = v - t0;
|
|
28
|
+
return (Math.abs(y) <= half) ? A * (1 - 2 * Math.abs(y) / T) : 0;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return (Math.abs(x) <= half) ? A * (1 - 2 * Math.abs(x) / T) : 0;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// Dirac delta approximation
|
|
36
|
+
// Since δ(t) is not a true function, we approximate with a narrow pulse
|
|
37
|
+
export const dirac = (t, t0 = 0, eps = 1e-6, A = 1) => {
|
|
38
|
+
if (Array.isArray(t)) return t.map(v => Math.abs(v - t0) < eps ? A / eps : 0);
|
|
39
|
+
return Math.abs(t - t0) < eps ? A / eps : 0;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Lorentzian (Cauchy) function
|
|
43
|
+
// L(t) = (A / π) * (gamma / ((t - t0)^2 + gamma^2))
|
|
44
|
+
export const lorentz = (t, t0 = 0, gamma = 1, A = 1) => {
|
|
45
|
+
const value = (v) => (A / Math.PI) * (gamma / ((v - t0) ** 2 + gamma ** 2));
|
|
46
|
+
if (Array.isArray(t)) return t.map(value);
|
|
47
|
+
return value(t);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Sinc function: sin(pi*(t-t0)) / (pi*(t-t0))
|
|
51
|
+
export const sinc = (t, t0 = 0, A = 1) => {
|
|
52
|
+
const f = (v) => {
|
|
53
|
+
const x = Math.PI * (v - t0);
|
|
54
|
+
return x === 0 ? A : A * Math.sin(x) / x;
|
|
55
|
+
};
|
|
56
|
+
if (Array.isArray(t)) return t.map(f);
|
|
57
|
+
return f(t);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
// Gaussian pulse
|
|
62
|
+
export const gaussian = (t, t0 = 0, sigma = 1, A = 1) => {
|
|
63
|
+
const f = (v) => A * Math.exp(-((v - t0) ** 2) / (2 * sigma ** 2));
|
|
64
|
+
if (Array.isArray(t)) return t.map(f);
|
|
65
|
+
return f(t);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Exponential pulse (causal)
|
|
69
|
+
export const expPulse = (t, t0 = 0, alpha = 1, A = 1) => {
|
|
70
|
+
const f = (v) => (v >= t0 ? A * Math.exp(-alpha * (v - t0)) : 0);
|
|
71
|
+
if (Array.isArray(t)) return t.map(f);
|
|
72
|
+
return f(t);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Trapezoidal pulse
|
|
76
|
+
export const trapezoid = (t, t0 = 0, rise = 0.5, width = 1, fall = 0.5, A = 1) => {
|
|
77
|
+
const f = (v) => {
|
|
78
|
+
const x = v - t0;
|
|
79
|
+
if (x < 0 || x > rise + width + fall) return 0;
|
|
80
|
+
if (x < rise) return A * (x / rise);
|
|
81
|
+
if (x < rise + width) return A;
|
|
82
|
+
return A * (1 - (x - rise - width) / fall);
|
|
83
|
+
};
|
|
84
|
+
if (Array.isArray(t)) return t.map(f);
|
|
85
|
+
return f(t);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Hamming window (useful for DSP)
|
|
89
|
+
export const hamming = (t, t0 = 0, T = 1, A = 1) => {
|
|
90
|
+
const f = (v) => {
|
|
91
|
+
const x = (v - t0) / T;
|
|
92
|
+
return (x >= 0 && x <= 1) ? A * (0.54 - 0.46 * Math.cos(2 * Math.PI * x)) : 0;
|
|
93
|
+
};
|
|
94
|
+
if (Array.isArray(t)) return t.map(f);
|
|
95
|
+
return f(t);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Hanning window
|
|
99
|
+
export const hanning = (t, t0 = 0, T = 1, A = 1) => {
|
|
100
|
+
const f = (v) => {
|
|
101
|
+
const x = (v - t0) / T;
|
|
102
|
+
return (x >= 0 && x <= 1) ? A * 0.5 * (1 - Math.cos(2 * Math.PI * x)) : 0;
|
|
103
|
+
};
|
|
104
|
+
if (Array.isArray(t)) return t.map(f);
|
|
105
|
+
return f(t);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Dirichlet (periodic sinc) function
|
|
109
|
+
export const dirichlet = (t, N = 5, t0 = 0, A = 1) => {
|
|
110
|
+
const f = (v) => {
|
|
111
|
+
const x = Math.PI * (v - t0);
|
|
112
|
+
return x === 0 ? A : A * Math.sin(N * x) / (N * Math.sin(x));
|
|
113
|
+
};
|
|
114
|
+
if (Array.isArray(t)) return t.map(f);
|
|
115
|
+
return f(t);
|
|
116
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { mapfun, nthr, pow } from "ziko/math/functions";
|
|
2
|
+
|
|
3
|
+
export const zeros = n => new Array(n).fill(0);
|
|
4
|
+
export const ones = n => new Array(n).fill(1);
|
|
5
|
+
export const nums = (n, num) => new Array(n).fill(num);
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const arange = (a, b, step, include = false) => {
|
|
9
|
+
if(a instanceof Array && typeof b === 'number') return mapfun(x => arange(x, b, step, include), ...a);
|
|
10
|
+
if(b instanceof Array && typeof a === 'number') return mapfun(x => arange(a, x, step, include), ...b);
|
|
11
|
+
if(a instanceof Array && b instanceof Array){
|
|
12
|
+
if(a.length !== b.length) return TypeError('');
|
|
13
|
+
let res = new Array(a.length).fill(null)
|
|
14
|
+
return res.map((_, i) => arange(a[i], b[i], step, include))
|
|
15
|
+
}
|
|
16
|
+
if(typeof a === 'number' && typeof b === 'number'){
|
|
17
|
+
const values = [];
|
|
18
|
+
let i;
|
|
19
|
+
if(a<b){
|
|
20
|
+
for (i = a; include ? i<=b : i<b ; i += step)
|
|
21
|
+
values.push((i * 10) / 10);
|
|
22
|
+
}
|
|
23
|
+
else{
|
|
24
|
+
for(i = a; include ? i>=b: i>b ; i -= step)
|
|
25
|
+
values.push((i * 10) / 10);
|
|
26
|
+
}
|
|
27
|
+
return values
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const linspace = (a, b, n = Math.abs(b-a) + 1, endpoint = true) =>{
|
|
32
|
+
if(Math.floor(n) !== n) return TypeError('');
|
|
33
|
+
let c = [a, b].find(n => n.isComplex?.())
|
|
34
|
+
if(c){
|
|
35
|
+
let z1 = new c.constructor(a);
|
|
36
|
+
let z2 = new c.constructor(b)
|
|
37
|
+
if (!n) n = Math.abs(z1.a - z2.a) + 1;
|
|
38
|
+
const X = linspace(z1.a, z2.a, n, endpoint);
|
|
39
|
+
const Y = linspace(z1.a, z2.a, n, endpoint);
|
|
40
|
+
let Z = new Array(n).fill(null);
|
|
41
|
+
Z = Z.map((_, i) => new z1.constructor(X[i], Y[i]));
|
|
42
|
+
return Z;
|
|
43
|
+
}
|
|
44
|
+
if(a instanceof Array && typeof b === 'number') return mapfun(x => linspace(x, b, step, include), ...a);
|
|
45
|
+
if(b instanceof Array && typeof a === 'number') return mapfun(x => linspace(a, x, step, include), ...b);
|
|
46
|
+
if(a instanceof Array && b instanceof Array){
|
|
47
|
+
if(a.length !== b.length) return TypeError('');
|
|
48
|
+
let res = new Array(a.length).fill(null)
|
|
49
|
+
return res.map((_, i) => linspace(a[i], b[i], step, include))
|
|
50
|
+
}
|
|
51
|
+
if(typeof a === 'number' && typeof b === 'number'){
|
|
52
|
+
const [max, min] = [a, b].sort((a, b) => b-a);
|
|
53
|
+
let Y = [], step, i;
|
|
54
|
+
endpoint ? step = (max - min) / (n - 1) : step = (max - min) / n;
|
|
55
|
+
if(a < b)
|
|
56
|
+
for(i = 0; i < n; i++)
|
|
57
|
+
Y.push(+(min + step * i).toFixed(8))
|
|
58
|
+
else
|
|
59
|
+
for(i = 0; i < n; i++)
|
|
60
|
+
Y.push(+(max - step * i).toFixed(8))
|
|
61
|
+
return Y
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const logspace = (a, b, n = Math.abs(b-a) + 1, base = Math.E, endpoint = true) => {
|
|
66
|
+
const ls = linspace(a, b, n, endpoint);
|
|
67
|
+
return mapfun(x => pow(base, x), ...ls)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const geomspace = (a, b, n = Math.abs(b-a) + 1, endpoint = true, precison = 8) =>{
|
|
71
|
+
if(Math.floor(n) !== n) return TypeError('n must be and integer');
|
|
72
|
+
let c = [a, b].find(n => n.isComplex?.())
|
|
73
|
+
if(c){
|
|
74
|
+
let z1 = new c.constructor(a);
|
|
75
|
+
let z2 = new c.constructor(b);
|
|
76
|
+
if (!n) n = Math.abs(z1.a - z2.a) + 1;
|
|
77
|
+
const ratio = nthr(z2.clone().div(z1.clone()), n-1);
|
|
78
|
+
let i;
|
|
79
|
+
const Y = [];
|
|
80
|
+
for(i = 0; i < n; i++){
|
|
81
|
+
Y[i] = z1.clone().mul(pow(ratio.clone(), i))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return Y.map(n => n.toFixed(precison))
|
|
85
|
+
}
|
|
86
|
+
if(a instanceof Array && typeof b === 'number') return mapfun(x => geomspace(x, b, n, endpoint, precison), ...a);
|
|
87
|
+
if(b instanceof Array && typeof a === 'number') return mapfun(x => geomspace(a, x, n, endpoint, precison), ...b);
|
|
88
|
+
if(a instanceof Array && b instanceof Array){
|
|
89
|
+
if(a.length !== b.length) return TypeError('');
|
|
90
|
+
let res = new Array(a.length).fill(null)
|
|
91
|
+
return res.map((_, i) => geomspace(a[i], b[i], n, endpoint, precison))
|
|
92
|
+
}
|
|
93
|
+
if(typeof a === 'number' && typeof b === 'number'){
|
|
94
|
+
const [max, min]= [a, b].sort((a, b) => b-a);
|
|
95
|
+
let base = endpoint ? nthr(max/min, n-1) : nthr(max/min, n);
|
|
96
|
+
const Y = [min];
|
|
97
|
+
let i;
|
|
98
|
+
for(i = 1; i < n; i++)
|
|
99
|
+
Y.push(Y[i-1] * base )
|
|
100
|
+
const Fixed = Y.map(n => + n.toFixed(precison))
|
|
101
|
+
return a < b ? Fixed : Fixed.reverse()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const dist_normal = (x, mean = 0, std = 1) => {
|
|
2
|
+
const coeff = 1 / (std * Math.sqrt(2 * Math.PI));
|
|
3
|
+
const expPart = Math.exp(-((x - mean) ** 2) / (2 * std ** 2));
|
|
4
|
+
return coeff * expPart;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const dist_uniform = (x, a = 0, b = 1) => (x < a || x > b ? 0 : 1 / (b - a));
|
|
8
|
+
|
|
9
|
+
export const dist_exponential = (x, lambda = 1) => (x < 0 ? 0 : lambda * Math.exp(-lambda * x));
|
|
10
|
+
|
|
11
|
+
export const dist_gamma = (x, k, theta = 1) => {
|
|
12
|
+
if (x < 0) return 0;
|
|
13
|
+
const gamma = (n) => {
|
|
14
|
+
if (n <= 1) return 1;
|
|
15
|
+
return (n - 1) * gamma(n - 1);
|
|
16
|
+
};
|
|
17
|
+
return Math.pow(x, k - 1) * Math.exp(-x / theta) / (gamma(k) * Math.pow(theta, k));
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const dist_beta = (x, alpha, beta) => {
|
|
21
|
+
if (x < 0 || x > 1) return 0;
|
|
22
|
+
const gamma = (n) => (n <= 1 ? 1 : (n - 1) * gamma(n - 1));
|
|
23
|
+
const B = (alpha, beta) => gamma(alpha) * gamma(beta) / gamma(alpha + beta);
|
|
24
|
+
return Math.pow(x, alpha - 1) * Math.pow(1 - x, beta - 1) / B(alpha, beta);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const dist_cauchy = (x, x0 = 0, gamma = 1) => 1 / (Math.PI * gamma * (1 + ((x - x0) / gamma) ** 2));
|
|
28
|
+
|
|
29
|
+
export const dist_chi2 = (x, k) => dist_gamma(x, k / 2, 2);
|
|
30
|
+
|
|
31
|
+
export const dist_student_t = (x, nu) => {
|
|
32
|
+
const gamma = (n) => (n <= 1 ? 1 : (n - 1) * gamma(n - 1));
|
|
33
|
+
const coeff = gamma((nu + 1) / 2) / (Math.sqrt(nu * Math.PI) * gamma(nu / 2));
|
|
34
|
+
return coeff * Math.pow(1 + (x ** 2) / nu, -(nu + 1) / 2);
|
|
35
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// ------------------------------
|
|
2
|
+
// Discrete Distributions
|
|
3
|
+
// ------------------------------
|
|
4
|
+
export const dist_binomial = (k, n, p) => {
|
|
5
|
+
if (k < 0 || k > n) return 0;
|
|
6
|
+
const comb = (n, k) => {
|
|
7
|
+
if (k === 0 || k === n) return 1;
|
|
8
|
+
let res = 1;
|
|
9
|
+
for (let i = 1; i <= k; i++) res *= (n - i + 1) / i;
|
|
10
|
+
return res;
|
|
11
|
+
};
|
|
12
|
+
return comb(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const dist_poisson = (k, lambda) => {
|
|
16
|
+
if (k < 0) return 0;
|
|
17
|
+
const factorial = (n) => (n <= 1 ? 1 : n * factorial(n - 1));
|
|
18
|
+
return Math.pow(lambda, k) * Math.exp(-lambda) / factorial(k);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const dist_geometric = (k, p) => (k < 1 ? 0 : p * Math.pow(1 - p, k - 1));
|
|
22
|
+
|
|
23
|
+
export const dist_negative_binomial = (k, r, p) => {
|
|
24
|
+
if (k < 0) return 0;
|
|
25
|
+
const comb = (n, k) => {
|
|
26
|
+
if (k === 0 || k === n) return 1;
|
|
27
|
+
let res = 1;
|
|
28
|
+
for (let i = 1; i <= k; i++) res *= (n - i + 1) / i;
|
|
29
|
+
return res;
|
|
30
|
+
};
|
|
31
|
+
return comb(k + r - 1, k) * Math.pow(p, r) * Math.pow(1 - p, k);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const dist_hypergeometric = (k, N, K, n) => {
|
|
35
|
+
if (k < 0 || k > n || k > K) return 0;
|
|
36
|
+
const comb = (n, k) => {
|
|
37
|
+
if (k === 0 || k === n) return 1;
|
|
38
|
+
let res = 1;
|
|
39
|
+
for (let i = 1; i <= k; i++) res *= (n - i + 1) / i;
|
|
40
|
+
return res;
|
|
41
|
+
};
|
|
42
|
+
return (comb(K, k) * comb(N - K, n - k)) / comb(N, n);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const dist_bernoulli = (k, p) => (k === 0 ? 1 - p : k === 1 ? p : 0);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// ------------------------------
|
|
2
|
+
// Multivariate Distributions
|
|
3
|
+
// ------------------------------
|
|
4
|
+
export const dist_multinomial = (kArray, n, pArray) => {
|
|
5
|
+
const factorial = (x) => (x <= 1 ? 1 : x * factorial(x - 1));
|
|
6
|
+
const comb = factorial(n) / kArray.reduce((acc, k) => acc * factorial(k), 1);
|
|
7
|
+
const prob = kArray.reduce((acc, ki, i) => acc * Math.pow(pArray[i], ki), 1);
|
|
8
|
+
return comb * prob;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const dist_multivariate_normal = (xArray, meanArray, covMatrix) => {
|
|
12
|
+
const n = xArray.length;
|
|
13
|
+
const det = (m) => {
|
|
14
|
+
if (n === 1) return m[0][0];
|
|
15
|
+
if (n === 2) return m[0][0] * m[1][1] - m[0][1] * m[1][0];
|
|
16
|
+
throw new Error('Only 1x1 and 2x2 supported for now');
|
|
17
|
+
};
|
|
18
|
+
const inv = (m) => {
|
|
19
|
+
if (n === 1) return [[1 / m[0][0]]];
|
|
20
|
+
if (n === 2) {
|
|
21
|
+
const [[a,b],[c,d]] = m;
|
|
22
|
+
const detM = a*d-b*c;
|
|
23
|
+
return [[d/detM,-b/detM],[-c/detM,a/detM]];
|
|
24
|
+
}
|
|
25
|
+
throw new Error('Only 1x1 and 2x2 supported for now');
|
|
26
|
+
};
|
|
27
|
+
const diff = xArray.map((xi, i) => xi - meanArray[i]);
|
|
28
|
+
const covInv = inv(covMatrix);
|
|
29
|
+
const exponent = -0.5 * diff.reduce((sum, _, i) =>
|
|
30
|
+
sum + diff[i] * (covInv[i][0] * diff[0] + covInv[i][1] * diff[1] || 0), 0);
|
|
31
|
+
const denom = Math.sqrt((2 * Math.PI) ** n * det(covMatrix));
|
|
32
|
+
return Math.exp(exponent) / denom;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const dist_dirichlet = (xArray, alphaArray) => {
|
|
36
|
+
const gamma = (n) => (n <= 1 ? 1 : (n - 1) * gamma(n - 1));
|
|
37
|
+
const B = alphaArray.reduce((acc, a) => acc * gamma(a), 1) / gamma(alphaArray.reduce((a,b)=>a+b,0));
|
|
38
|
+
const prod = xArray.reduce((acc, xi, i) => acc * Math.pow(xi, alphaArray[i]-1),1);
|
|
39
|
+
return prod / B;
|
|
40
|
+
};
|
package/src/stats/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'ziko/math/functions'
|
package/test.js
ADDED
|
File without changes
|