@thi.ng/tsne 0.1.0 → 0.1.2
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/CHANGELOG.md +7 -1
- package/package.json +4 -4
- package/tsne.d.ts +4 -1
- package/tsne.js +14 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2025-02-
|
|
3
|
+
- **Last updated**: 2025-02-20T09:10:22Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -11,6 +11,12 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
11
11
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
12
12
|
and/or version bumps of transitive dependencies.
|
|
13
13
|
|
|
14
|
+
### [0.1.1](https://github.com/thi-ng/umbrella/tree/@thi.ng/tsne@0.1.1) (2025-02-20)
|
|
15
|
+
|
|
16
|
+
#### ⏱ Performance improvements
|
|
17
|
+
|
|
18
|
+
- more efficient use of vector ops ([af07e27](https://github.com/thi-ng/umbrella/commit/af07e27))
|
|
19
|
+
|
|
14
20
|
## [0.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/tsne@0.1.0) (2025-02-19)
|
|
15
21
|
|
|
16
22
|
#### 🚀 Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/tsne",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Highly configurable t-SNE implementation for arbitrary dimensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"@thi.ng/api": "^8.11.21",
|
|
43
43
|
"@thi.ng/math": "^5.11.21",
|
|
44
44
|
"@thi.ng/random": "^4.1.12",
|
|
45
|
-
"@thi.ng/transducers": "^9.2.
|
|
46
|
-
"@thi.ng/vectors": "^7.12.
|
|
45
|
+
"@thi.ng/transducers": "^9.2.20",
|
|
46
|
+
"@thi.ng/vectors": "^7.12.22"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"esbuild": "^0.25.0",
|
|
@@ -82,5 +82,5 @@
|
|
|
82
82
|
"status": "alpha",
|
|
83
83
|
"year": 2021
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "2958e6a9881bd9e06de587a2141f6d23c64278db\n"
|
|
86
86
|
}
|
package/tsne.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FloatArray } from "@thi.ng/api";
|
|
2
|
-
import { type ReadonlyVec } from "@thi.ng/vectors";
|
|
2
|
+
import { type DistanceFn, type ReadonlyVec, type VecOpVN, type VecOpVV } from "@thi.ng/vectors";
|
|
3
3
|
import type { TSNEOpts } from "./api.js";
|
|
4
4
|
export declare const DEFAULT_OPTS: TSNEOpts;
|
|
5
5
|
export declare class TSNE {
|
|
@@ -13,6 +13,9 @@ export declare class TSNE {
|
|
|
13
13
|
points: number[][];
|
|
14
14
|
steps: number[][];
|
|
15
15
|
gains: number[][];
|
|
16
|
+
opDist: DistanceFn;
|
|
17
|
+
opDivN: VecOpVN;
|
|
18
|
+
opSub: VecOpVV;
|
|
16
19
|
constructor(points: ReadonlyVec[], opts?: Partial<TSNEOpts>);
|
|
17
20
|
init(points: ReadonlyVec[]): void;
|
|
18
21
|
update(): number;
|
package/tsne.js
CHANGED
|
@@ -10,13 +10,10 @@ import {
|
|
|
10
10
|
sub,
|
|
11
11
|
zeroes
|
|
12
12
|
} from "@thi.ng/vectors";
|
|
13
|
-
const $distSq = distSq.impl();
|
|
14
|
-
const $divN = divN.impl();
|
|
15
|
-
const $sub = sub.impl();
|
|
16
13
|
const EPS = Number.EPSILON;
|
|
17
14
|
const DEFAULT_OPTS = {
|
|
18
15
|
rnd: SYSTEM,
|
|
19
|
-
dist:
|
|
16
|
+
dist: distSq,
|
|
20
17
|
perplexity: 10,
|
|
21
18
|
rate: 100,
|
|
22
19
|
eps: 1e-4,
|
|
@@ -47,6 +44,9 @@ class TSNE {
|
|
|
47
44
|
points;
|
|
48
45
|
steps;
|
|
49
46
|
gains;
|
|
47
|
+
opDist;
|
|
48
|
+
opDivN;
|
|
49
|
+
opSub;
|
|
50
50
|
constructor(points, opts = {}) {
|
|
51
51
|
this.opts = { ...DEFAULT_OPTS, ...opts };
|
|
52
52
|
this.init(points);
|
|
@@ -55,8 +55,11 @@ class TSNE {
|
|
|
55
55
|
const opts = this.opts;
|
|
56
56
|
const n = this.n = points.length;
|
|
57
57
|
const dim = this.dim = points[0].length;
|
|
58
|
+
this.opDist = opts.dist === distSq ? distSq.impl(dim) : opts.dist;
|
|
59
|
+
this.opDivN = divN.impl(dim);
|
|
60
|
+
this.opSub = sub.impl(dim);
|
|
58
61
|
this.p = initProbabilities(
|
|
59
|
-
pairwiseDistances(points,
|
|
62
|
+
pairwiseDistances(points, this.opDist),
|
|
60
63
|
n,
|
|
61
64
|
opts.perplexity,
|
|
62
65
|
opts.eps,
|
|
@@ -71,7 +74,7 @@ class TSNE {
|
|
|
71
74
|
}
|
|
72
75
|
update() {
|
|
73
76
|
if (++this.iter >= this.opts.maxIter) return 0;
|
|
74
|
-
const { n, dim, points, steps, gains } = this;
|
|
77
|
+
const { n, dim, points, steps, gains, opDivN, opSub } = this;
|
|
75
78
|
const {
|
|
76
79
|
rate,
|
|
77
80
|
minGain,
|
|
@@ -104,13 +107,12 @@ class TSNE {
|
|
|
104
107
|
ymean[d] += row[d];
|
|
105
108
|
}
|
|
106
109
|
}
|
|
107
|
-
|
|
108
|
-
for (i = 0; i < n; i++)
|
|
110
|
+
opDivN(null, ymean, n);
|
|
111
|
+
for (i = 0; i < n; i++) opSub(null, points[i], ymean);
|
|
109
112
|
return cost;
|
|
110
113
|
}
|
|
111
114
|
computeGradient() {
|
|
112
|
-
const { n, dim, points: y, p, q, qu } = this;
|
|
113
|
-
const { dist, gradientScale } = this.opts;
|
|
115
|
+
const { n, dim, points: y, p, q, qu, opDist } = this;
|
|
114
116
|
let i, j, rowIdx, d;
|
|
115
117
|
let rowI, rowJ;
|
|
116
118
|
let qsum = 0;
|
|
@@ -118,7 +120,7 @@ class TSNE {
|
|
|
118
120
|
rowIdx = i * n;
|
|
119
121
|
rowI = y[i];
|
|
120
122
|
for (j = i + 1; j < n; j++) {
|
|
121
|
-
d = 1 / (1 +
|
|
123
|
+
d = 1 / (1 + opDist(rowI, y[j]));
|
|
122
124
|
qu[rowIdx + j] = d;
|
|
123
125
|
qu[j * n + i] = d;
|
|
124
126
|
qsum += 2 * d;
|
|
@@ -130,7 +132,7 @@ class TSNE {
|
|
|
130
132
|
}
|
|
131
133
|
let cost = 0;
|
|
132
134
|
const gradient = new Array(n);
|
|
133
|
-
const gscale = tweenParam(gradientScale, this.iter);
|
|
135
|
+
const gscale = tweenParam(this.opts.gradientScale, this.iter);
|
|
134
136
|
for (i = 0; i < n; i++) {
|
|
135
137
|
rowIdx = i * n;
|
|
136
138
|
rowI = y[i];
|