@thi.ng/tsne 0.1.0 → 0.1.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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2025-02-19T20:59:58Z
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.0",
3
+ "version": "0.1.1",
4
4
  "description": "Highly configurable t-SNE implementation for arbitrary dimensions",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -82,5 +82,5 @@
82
82
  "status": "alpha",
83
83
  "year": 2021
84
84
  },
85
- "gitHead": "bee617702ac61d093465b967f8f973dc566faa6b\n"
85
+ "gitHead": "76bad4103057c3a3edbe02740bfe5f342ac8a6b5\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: $distSq,
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, opts.dist),
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
- $divN(null, ymean, n);
108
- for (i = 0; i < n; i++) $sub(null, points[i], ymean);
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 + dist(rowI, y[j]));
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];