embed-cluster 0.3.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.
Files changed (63) hide show
  1. package/README.md +122 -0
  2. package/dist/__tests__/cluster.test.d.ts +2 -0
  3. package/dist/__tests__/cluster.test.d.ts.map +1 -0
  4. package/dist/__tests__/cluster.test.js +202 -0
  5. package/dist/__tests__/cluster.test.js.map +1 -0
  6. package/dist/__tests__/errors.test.d.ts +2 -0
  7. package/dist/__tests__/errors.test.d.ts.map +1 -0
  8. package/dist/__tests__/errors.test.js +68 -0
  9. package/dist/__tests__/errors.test.js.map +1 -0
  10. package/dist/__tests__/fixtures/embeddings-small.json +25 -0
  11. package/dist/__tests__/fixtures.test.d.ts +2 -0
  12. package/dist/__tests__/fixtures.test.d.ts.map +1 -0
  13. package/dist/__tests__/fixtures.test.js +44 -0
  14. package/dist/__tests__/fixtures.test.js.map +1 -0
  15. package/dist/__tests__/kmeans.test.d.ts +2 -0
  16. package/dist/__tests__/kmeans.test.d.ts.map +1 -0
  17. package/dist/__tests__/kmeans.test.js +220 -0
  18. package/dist/__tests__/kmeans.test.js.map +1 -0
  19. package/dist/__tests__/normalize.test.d.ts +2 -0
  20. package/dist/__tests__/normalize.test.d.ts.map +1 -0
  21. package/dist/__tests__/normalize.test.js +92 -0
  22. package/dist/__tests__/normalize.test.js.map +1 -0
  23. package/dist/__tests__/silhouette.test.d.ts +2 -0
  24. package/dist/__tests__/silhouette.test.d.ts.map +1 -0
  25. package/dist/__tests__/silhouette.test.js +126 -0
  26. package/dist/__tests__/silhouette.test.js.map +1 -0
  27. package/dist/__tests__/types.test.d.ts +2 -0
  28. package/dist/__tests__/types.test.d.ts.map +1 -0
  29. package/dist/__tests__/types.test.js +126 -0
  30. package/dist/__tests__/types.test.js.map +1 -0
  31. package/dist/clusterer.d.ts +17 -0
  32. package/dist/clusterer.d.ts.map +1 -0
  33. package/dist/clusterer.js +72 -0
  34. package/dist/clusterer.js.map +1 -0
  35. package/dist/errors.d.ts +7 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +14 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/index.d.ts +9 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +21 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/kmeans.d.ts +6 -0
  44. package/dist/kmeans.d.ts.map +1 -0
  45. package/dist/kmeans.js +250 -0
  46. package/dist/kmeans.js.map +1 -0
  47. package/dist/normalize.d.ts +10 -0
  48. package/dist/normalize.d.ts.map +1 -0
  49. package/dist/normalize.js +21 -0
  50. package/dist/normalize.js.map +1 -0
  51. package/dist/optimal-k.d.ts +11 -0
  52. package/dist/optimal-k.d.ts.map +1 -0
  53. package/dist/optimal-k.js +49 -0
  54. package/dist/optimal-k.js.map +1 -0
  55. package/dist/silhouette.d.ts +16 -0
  56. package/dist/silhouette.d.ts.map +1 -0
  57. package/dist/silhouette.js +95 -0
  58. package/dist/silhouette.js.map +1 -0
  59. package/dist/types.d.ts +74 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +3 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +48 -0
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const kmeans_1 = require("../kmeans");
5
+ // ---------------------------------------------------------------------------
6
+ // Helpers
7
+ // ---------------------------------------------------------------------------
8
+ function makeItems(coords) {
9
+ return coords.map((embedding, i) => ({ id: `item-${i}`, text: `doc ${i}`, embedding }));
10
+ }
11
+ // Two clearly separated 2D clusters
12
+ const GROUP_A = [[1, 0], [1.1, 0.1], [0.9, -0.1], [1.05, 0.05]];
13
+ const GROUP_B = [[-1, 0], [-1.1, 0.1], [-0.9, -0.1], [-1.05, 0.05]];
14
+ const TWO_CLUSTER_ITEMS = makeItems([...GROUP_A, ...GROUP_B]);
15
+ // Three clearly separated 2D clusters
16
+ const GROUP_C = [[0, 1], [0.1, 1.1], [-0.1, 0.9]];
17
+ const THREE_CLUSTER_ITEMS = makeItems([...GROUP_A, ...GROUP_B, ...GROUP_C]);
18
+ // ---------------------------------------------------------------------------
19
+ // euclideanDistance
20
+ // ---------------------------------------------------------------------------
21
+ (0, vitest_1.describe)('euclideanDistance', () => {
22
+ (0, vitest_1.it)('returns 0 for identical vectors', () => {
23
+ (0, vitest_1.expect)((0, kmeans_1.euclideanDistance)([1, 2, 3], [1, 2, 3])).toBeCloseTo(0, 10);
24
+ });
25
+ (0, vitest_1.it)('returns 5 for [0,0] vs [3,4]', () => {
26
+ (0, vitest_1.expect)((0, kmeans_1.euclideanDistance)([0, 0], [3, 4])).toBeCloseTo(5, 10);
27
+ });
28
+ (0, vitest_1.it)('is symmetric', () => {
29
+ const a = [1, 2, 3];
30
+ const b = [4, 5, 6];
31
+ (0, vitest_1.expect)((0, kmeans_1.euclideanDistance)(a, b)).toBeCloseTo((0, kmeans_1.euclideanDistance)(b, a), 10);
32
+ });
33
+ });
34
+ // ---------------------------------------------------------------------------
35
+ // cosineDistance
36
+ // ---------------------------------------------------------------------------
37
+ (0, vitest_1.describe)('cosineDistance', () => {
38
+ (0, vitest_1.it)('returns 0 for identical unit vectors', () => {
39
+ (0, vitest_1.expect)((0, kmeans_1.cosineDistance)([1, 0], [1, 0])).toBeCloseTo(0, 10);
40
+ });
41
+ (0, vitest_1.it)('returns 1 for orthogonal vectors', () => {
42
+ (0, vitest_1.expect)((0, kmeans_1.cosineDistance)([1, 0], [0, 1])).toBeCloseTo(1, 10);
43
+ });
44
+ (0, vitest_1.it)('returns 2 for opposite vectors', () => {
45
+ (0, vitest_1.expect)((0, kmeans_1.cosineDistance)([1, 0], [-1, 0])).toBeCloseTo(2, 10);
46
+ });
47
+ (0, vitest_1.it)('returns 1 for zero vector (degenerate case)', () => {
48
+ (0, vitest_1.expect)((0, kmeans_1.cosineDistance)([0, 0], [1, 0])).toBe(1);
49
+ });
50
+ });
51
+ // ---------------------------------------------------------------------------
52
+ // kMeansPlusPlusInit
53
+ // ---------------------------------------------------------------------------
54
+ (0, vitest_1.describe)('kMeansPlusPlusInit', () => {
55
+ (0, vitest_1.it)('returns k centroids', () => {
56
+ const vectors = makeItems([[1, 0], [0, 1], [-1, 0], [0, -1]]).map(i => i.embedding);
57
+ const rand = () => 0.5; // deterministic-ish
58
+ const centroids = (0, kmeans_1.kMeansPlusPlusInit)(vectors, 2, kmeans_1.euclideanDistance, rand);
59
+ (0, vitest_1.expect)(centroids).toHaveLength(2);
60
+ });
61
+ (0, vitest_1.it)('each centroid is a copy of an input vector', () => {
62
+ const vectors = makeItems([[1, 0], [0, 1], [-1, 0]]).map(i => i.embedding);
63
+ const rand = () => 0.3;
64
+ const centroids = (0, kmeans_1.kMeansPlusPlusInit)(vectors, 2, kmeans_1.euclideanDistance, rand);
65
+ for (const c of centroids) {
66
+ const match = vectors.some(v => v.every((val, i) => val === c[i]));
67
+ (0, vitest_1.expect)(match).toBe(true);
68
+ }
69
+ });
70
+ (0, vitest_1.it)('centroids are distinct for well-separated data', () => {
71
+ const vectors = [...GROUP_A, ...GROUP_B];
72
+ const rand = (() => { let i = 0; const seq = [0.1, 0.9]; return () => seq[i++ % seq.length]; })();
73
+ const centroids = (0, kmeans_1.kMeansPlusPlusInit)(vectors, 2, kmeans_1.euclideanDistance, rand);
74
+ (0, vitest_1.expect)(centroids).toHaveLength(2);
75
+ // They should not be the same point
76
+ const [c0, c1] = centroids;
77
+ const same = c0.every((v, i) => v === c1[i]);
78
+ (0, vitest_1.expect)(same).toBe(false);
79
+ });
80
+ });
81
+ // ---------------------------------------------------------------------------
82
+ // kMeans
83
+ // ---------------------------------------------------------------------------
84
+ (0, vitest_1.describe)('kMeans', () => {
85
+ (0, vitest_1.it)('returns k clusters for k=2', () => {
86
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
87
+ (0, vitest_1.expect)(result.clusters).toHaveLength(2);
88
+ (0, vitest_1.expect)(result.k).toBe(2);
89
+ });
90
+ (0, vitest_1.it)('all items are assigned to some cluster', () => {
91
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
92
+ const totalItems = result.clusters.reduce((s, c) => s + c.items.length, 0);
93
+ (0, vitest_1.expect)(totalItems).toBe(TWO_CLUSTER_ITEMS.length);
94
+ });
95
+ (0, vitest_1.it)('converges for well-separated clusters', () => {
96
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
97
+ (0, vitest_1.expect)(result.converged).toBe(true);
98
+ });
99
+ (0, vitest_1.it)('centroids are near the true group means for k=2', () => {
100
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
101
+ // Sort clusters by centroid x coordinate
102
+ const sorted = [...result.clusters].sort((a, b) => a.centroid[0] - b.centroid[0]);
103
+ // Negative-x cluster centroid should be near -1
104
+ (0, vitest_1.expect)(sorted[0].centroid[0]).toBeCloseTo(-1.0125, 1);
105
+ // Positive-x cluster centroid should be near +1
106
+ (0, vitest_1.expect)(sorted[1].centroid[0]).toBeCloseTo(1.0375, 1);
107
+ });
108
+ (0, vitest_1.it)('assigns GROUP_A items to one cluster and GROUP_B to another (k=2)', () => {
109
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
110
+ // All items in GROUP_A should share a cluster, all in GROUP_B another
111
+ const sorted = [...result.clusters].sort((a, b) => a.centroid[0] - b.centroid[0]);
112
+ const negCluster = sorted[0];
113
+ const posCluster = sorted[1];
114
+ for (const item of negCluster.items) {
115
+ (0, vitest_1.expect)(item.id.startsWith('item-4') || parseInt(item.id.split('-')[1]) >= 4).toBe(true);
116
+ }
117
+ for (const item of posCluster.items) {
118
+ (0, vitest_1.expect)(parseInt(item.id.split('-')[1])).toBeLessThan(4);
119
+ }
120
+ });
121
+ (0, vitest_1.it)('handles k=1 (single cluster contains all items)', () => {
122
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 1, { normalize: false, seed: 1 });
123
+ (0, vitest_1.expect)(result.clusters).toHaveLength(1);
124
+ (0, vitest_1.expect)(result.clusters[0].items).toHaveLength(TWO_CLUSTER_ITEMS.length);
125
+ });
126
+ (0, vitest_1.it)('handles k=3 on 3-cluster data', () => {
127
+ const result = (0, kmeans_1.kMeans)(THREE_CLUSTER_ITEMS, 3, { normalize: false, seed: 1 });
128
+ (0, vitest_1.expect)(result.clusters).toHaveLength(3);
129
+ const totalItems = result.clusters.reduce((s, c) => s + c.items.length, 0);
130
+ (0, vitest_1.expect)(totalItems).toBe(THREE_CLUSTER_ITEMS.length);
131
+ });
132
+ (0, vitest_1.it)('inertia is finite and non-negative', () => {
133
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
134
+ (0, vitest_1.expect)(result.quality.inertia).toBeGreaterThanOrEqual(0);
135
+ (0, vitest_1.expect)(isFinite(result.quality.inertia)).toBe(true);
136
+ });
137
+ (0, vitest_1.it)('inertia decreases as k increases', () => {
138
+ const r1 = (0, kmeans_1.kMeans)(THREE_CLUSTER_ITEMS, 1, { normalize: false, seed: 1 });
139
+ const r3 = (0, kmeans_1.kMeans)(THREE_CLUSTER_ITEMS, 3, { normalize: false, seed: 1 });
140
+ (0, vitest_1.expect)(r3.quality.inertia).toBeLessThan(r1.quality.inertia);
141
+ });
142
+ (0, vitest_1.it)('cluster.size equals cluster.items.length', () => {
143
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
144
+ for (const c of result.clusters) {
145
+ (0, vitest_1.expect)(c.size).toBe(c.items.length);
146
+ }
147
+ });
148
+ (0, vitest_1.it)('durationMs is non-negative', () => {
149
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
150
+ (0, vitest_1.expect)(result.durationMs).toBeGreaterThanOrEqual(0);
151
+ });
152
+ (0, vitest_1.it)('is deterministic with same seed', () => {
153
+ const r1 = (0, kmeans_1.kMeans)(THREE_CLUSTER_ITEMS, 3, { normalize: false, seed: 42 });
154
+ const r2 = (0, kmeans_1.kMeans)(THREE_CLUSTER_ITEMS, 3, { normalize: false, seed: 42 });
155
+ for (let c = 0; c < 3; c++) {
156
+ (0, vitest_1.expect)(r1.clusters[c].centroid).toEqual(r2.clusters[c].centroid);
157
+ }
158
+ });
159
+ (0, vitest_1.it)('supports custom distanceFn (cosine)', () => {
160
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, {
161
+ normalize: true,
162
+ seed: 1,
163
+ distanceFn: kmeans_1.cosineDistance,
164
+ });
165
+ (0, vitest_1.expect)(result.clusters).toHaveLength(2);
166
+ (0, vitest_1.expect)(result.converged).toBe(true);
167
+ });
168
+ (0, vitest_1.it)('throws EMPTY_INPUT for empty array', () => {
169
+ (0, vitest_1.expect)(() => (0, kmeans_1.kMeans)([], 2)).toThrowError();
170
+ try {
171
+ (0, kmeans_1.kMeans)([], 2);
172
+ }
173
+ catch (e) {
174
+ (0, vitest_1.expect)(e.code).toBe('EMPTY_INPUT');
175
+ }
176
+ });
177
+ (0, vitest_1.it)('throws INVALID_K when k > n', () => {
178
+ (0, vitest_1.expect)(() => (0, kmeans_1.kMeans)(makeItems([[1, 0]]), 2)).toThrowError();
179
+ try {
180
+ (0, kmeans_1.kMeans)(makeItems([[1, 0]]), 2);
181
+ }
182
+ catch (e) {
183
+ (0, vitest_1.expect)(e.code).toBe('INVALID_K');
184
+ }
185
+ });
186
+ (0, vitest_1.it)('throws INCONSISTENT_DIMENSIONS for mismatched embeddings', () => {
187
+ const items = [
188
+ { id: 'a', text: 'a', embedding: [1, 0] },
189
+ { id: 'b', text: 'b', embedding: [1, 0, 0] },
190
+ ];
191
+ (0, vitest_1.expect)(() => (0, kmeans_1.kMeans)(items, 2)).toThrowError();
192
+ try {
193
+ (0, kmeans_1.kMeans)(items, 2);
194
+ }
195
+ catch (e) {
196
+ (0, vitest_1.expect)(e.code).toBe('INCONSISTENT_DIMENSIONS');
197
+ }
198
+ });
199
+ (0, vitest_1.it)('normalize=true does not change number of clusters', () => {
200
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: true, seed: 1 });
201
+ (0, vitest_1.expect)(result.clusters).toHaveLength(2);
202
+ });
203
+ (0, vitest_1.it)('each ClusterItem has distanceToCentroid >= 0', () => {
204
+ const result = (0, kmeans_1.kMeans)(TWO_CLUSTER_ITEMS, 2, { normalize: false, seed: 1 });
205
+ for (const c of result.clusters) {
206
+ for (const item of c.items) {
207
+ (0, vitest_1.expect)(item.distanceToCentroid).toBeGreaterThanOrEqual(0);
208
+ }
209
+ }
210
+ });
211
+ (0, vitest_1.it)('each ClusterItem.clusterId matches its parent cluster.id', () => {
212
+ const result = (0, kmeans_1.kMeans)(THREE_CLUSTER_ITEMS, 3, { normalize: false, seed: 1 });
213
+ for (const c of result.clusters) {
214
+ for (const item of c.items) {
215
+ (0, vitest_1.expect)(item.clusterId).toBe(c.id);
216
+ }
217
+ }
218
+ });
219
+ });
220
+ //# sourceMappingURL=kmeans.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kmeans.test.js","sourceRoot":"","sources":["../../src/__tests__/kmeans.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=normalize.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/normalize.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const normalize_1 = require("../normalize");
5
+ const EPSILON = 1e-10;
6
+ (0, vitest_1.describe)('normalizeVector', () => {
7
+ (0, vitest_1.it)('normalizes [3, 4] to [0.6, 0.8] (magnitude=5)', () => {
8
+ const result = (0, normalize_1.normalizeVector)([3, 4]);
9
+ (0, vitest_1.expect)(result[0]).toBeCloseTo(0.6, 10);
10
+ (0, vitest_1.expect)(result[1]).toBeCloseTo(0.8, 10);
11
+ });
12
+ (0, vitest_1.it)('normalizes a unit vector [1, 0, 0] unchanged', () => {
13
+ const result = (0, normalize_1.normalizeVector)([1, 0, 0]);
14
+ (0, vitest_1.expect)(result[0]).toBeCloseTo(1.0, 10);
15
+ (0, vitest_1.expect)(result[1]).toBeCloseTo(0.0, 10);
16
+ (0, vitest_1.expect)(result[2]).toBeCloseTo(0.0, 10);
17
+ });
18
+ (0, vitest_1.it)('returns [0, 0, 0] for zero vector', () => {
19
+ const result = (0, normalize_1.normalizeVector)([0, 0, 0]);
20
+ (0, vitest_1.expect)(result).toEqual([0, 0, 0]);
21
+ });
22
+ (0, vitest_1.it)('returns a copy and does not mutate input', () => {
23
+ const input = [3, 4];
24
+ const result = (0, normalize_1.normalizeVector)(input);
25
+ (0, vitest_1.expect)(result).not.toBe(input);
26
+ (0, vitest_1.expect)(input[0]).toBe(3);
27
+ (0, vitest_1.expect)(input[1]).toBe(4);
28
+ });
29
+ (0, vitest_1.it)('normalizes [2, 2] to approximately [0.707, 0.707]', () => {
30
+ const result = (0, normalize_1.normalizeVector)([2, 2]);
31
+ const expected = Math.SQRT2 / 2;
32
+ (0, vitest_1.expect)(result[0]).toBeCloseTo(expected, 10);
33
+ (0, vitest_1.expect)(result[1]).toBeCloseTo(expected, 10);
34
+ });
35
+ (0, vitest_1.it)('resulting magnitude is approximately 1.0', () => {
36
+ const vecs = [
37
+ [3, 4],
38
+ [1, 2, 3],
39
+ [0.5, -0.3, 0.8, 0.1],
40
+ [100, 200, 300],
41
+ ];
42
+ for (const vec of vecs) {
43
+ const norm = (0, normalize_1.normalizeVector)(vec);
44
+ const magnitude = Math.sqrt(norm.reduce((s, x) => s + x * x, 0));
45
+ (0, vitest_1.expect)(Math.abs(magnitude - 1.0)).toBeLessThan(EPSILON);
46
+ }
47
+ });
48
+ (0, vitest_1.it)('handles single-element vector', () => {
49
+ const result = (0, normalize_1.normalizeVector)([5]);
50
+ (0, vitest_1.expect)(result[0]).toBeCloseTo(1.0, 10);
51
+ });
52
+ (0, vitest_1.it)('handles negative values', () => {
53
+ const result = (0, normalize_1.normalizeVector)([-3, 4]);
54
+ (0, vitest_1.expect)(result[0]).toBeCloseTo(-0.6, 10);
55
+ (0, vitest_1.expect)(result[1]).toBeCloseTo(0.8, 10);
56
+ const magnitude = Math.sqrt(result.reduce((s, x) => s + x * x, 0));
57
+ (0, vitest_1.expect)(Math.abs(magnitude - 1.0)).toBeLessThan(EPSILON);
58
+ });
59
+ });
60
+ (0, vitest_1.describe)('normalizeVectors', () => {
61
+ (0, vitest_1.it)('normalizes [[3,4],[0,1]] correctly', () => {
62
+ const result = (0, normalize_1.normalizeVectors)([[3, 4], [0, 1]]);
63
+ (0, vitest_1.expect)(result[0][0]).toBeCloseTo(0.6, 10);
64
+ (0, vitest_1.expect)(result[0][1]).toBeCloseTo(0.8, 10);
65
+ (0, vitest_1.expect)(result[1][0]).toBeCloseTo(0.0, 10);
66
+ (0, vitest_1.expect)(result[1][1]).toBeCloseTo(1.0, 10);
67
+ });
68
+ (0, vitest_1.it)('returns empty array for empty input', () => {
69
+ const result = (0, normalize_1.normalizeVectors)([]);
70
+ (0, vitest_1.expect)(result).toEqual([]);
71
+ });
72
+ (0, vitest_1.it)('returns array of same length as input', () => {
73
+ const input = [[1, 0], [0, 1], [1, 1]];
74
+ const result = (0, normalize_1.normalizeVectors)(input);
75
+ (0, vitest_1.expect)(result).toHaveLength(3);
76
+ });
77
+ (0, vitest_1.it)('each normalized vector has magnitude approximately 1.0', () => {
78
+ const input = [[1, 2], [3, 4], [5, 12]];
79
+ const result = (0, normalize_1.normalizeVectors)(input);
80
+ for (const vec of result) {
81
+ const magnitude = Math.sqrt(vec.reduce((s, x) => s + x * x, 0));
82
+ (0, vitest_1.expect)(Math.abs(magnitude - 1.0)).toBeLessThan(EPSILON);
83
+ }
84
+ });
85
+ (0, vitest_1.it)('handles zero vectors in batch without throwing', () => {
86
+ const result = (0, normalize_1.normalizeVectors)([[0, 0], [1, 0]]);
87
+ (0, vitest_1.expect)(result[0]).toEqual([0, 0]);
88
+ (0, vitest_1.expect)(result[1][0]).toBeCloseTo(1.0, 10);
89
+ (0, vitest_1.expect)(result[1][1]).toBeCloseTo(0.0, 10);
90
+ });
91
+ });
92
+ //# sourceMappingURL=normalize.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.test.js","sourceRoot":"","sources":["../../src/__tests__/normalize.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=silhouette.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"silhouette.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/silhouette.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const silhouette_1 = require("../silhouette");
5
+ const kmeans_1 = require("../kmeans");
6
+ // ---------------------------------------------------------------------------
7
+ // Helpers
8
+ // ---------------------------------------------------------------------------
9
+ function makeItems(coords) {
10
+ return coords.map((embedding, i) => ({ id: `item-${i}`, text: `doc ${i}`, embedding }));
11
+ }
12
+ // Well-separated 2D clusters
13
+ const GROUP_A = [[1, 0], [1.1, 0.05], [0.9, -0.05], [1.05, 0.02]];
14
+ const GROUP_B = [[-1, 0], [-1.1, 0.05], [-0.9, -0.05], [-1.05, 0.02]];
15
+ const WELL_SEPARATED = makeItems([...GROUP_A, ...GROUP_B]);
16
+ // Mixed/overlapping clusters
17
+ const GROUP_MIXED = [[0, 0], [0.1, 0.1], [-0.1, -0.1], [0.05, -0.05]];
18
+ const GROUP_MIXED2 = [[0.2, 0.2], [0.3, 0.1], [0.1, 0.3], [0.25, 0.25]];
19
+ const MIXED = makeItems([...GROUP_MIXED, ...GROUP_MIXED2]);
20
+ // ---------------------------------------------------------------------------
21
+ // Helpers to build a synthetic ClusterResult for unit-testing silhouette
22
+ // ---------------------------------------------------------------------------
23
+ function buildClusterResult(groups, baseItems) {
24
+ let itemIndex = 0;
25
+ const clusters = groups.map((group, cid) => {
26
+ const items = group.map((embedding) => {
27
+ const base = baseItems[itemIndex++];
28
+ return { ...base, embedding, clusterId: cid, distanceToCentroid: 0 };
29
+ });
30
+ const centroid = group.length > 0
31
+ ? group[0].map((_, i) => group.reduce((s, v) => s + v[i], 0) / group.length)
32
+ : [];
33
+ return { id: cid, centroid, items, size: items.length, avgDistanceToCentroid: 0, cohesion: 0 };
34
+ });
35
+ const quality = {
36
+ silhouette: { score: 0, perCluster: [] },
37
+ inertia: 0,
38
+ };
39
+ return { clusters, quality, k: groups.length, iterations: 1, converged: true, durationMs: 0 };
40
+ }
41
+ // ---------------------------------------------------------------------------
42
+ // Tests
43
+ // ---------------------------------------------------------------------------
44
+ (0, vitest_1.describe)('silhouetteScore', () => {
45
+ (0, vitest_1.it)('returns score in [-1, 1] for well-separated clusters', () => {
46
+ const result = (0, kmeans_1.kMeans)(WELL_SEPARATED, 2, { normalize: false, seed: 1 });
47
+ const sil = (0, silhouette_1.silhouetteScore)(result);
48
+ (0, vitest_1.expect)(sil.score).toBeGreaterThanOrEqual(-1);
49
+ (0, vitest_1.expect)(sil.score).toBeLessThanOrEqual(1);
50
+ });
51
+ (0, vitest_1.it)('well-separated clusters produce score > 0.5', () => {
52
+ const result = (0, kmeans_1.kMeans)(WELL_SEPARATED, 2, { normalize: false, seed: 1 });
53
+ const sil = (0, silhouette_1.silhouetteScore)(result);
54
+ (0, vitest_1.expect)(sil.score).toBeGreaterThan(0.5);
55
+ });
56
+ (0, vitest_1.it)('perCluster array has length equal to k', () => {
57
+ const result = (0, kmeans_1.kMeans)(WELL_SEPARATED, 2, { normalize: false, seed: 1 });
58
+ const sil = (0, silhouette_1.silhouetteScore)(result);
59
+ (0, vitest_1.expect)(sil.perCluster).toHaveLength(2);
60
+ });
61
+ (0, vitest_1.it)('perItem array has length equal to total items', () => {
62
+ const result = (0, kmeans_1.kMeans)(WELL_SEPARATED, 2, { normalize: false, seed: 1 });
63
+ const sil = (0, silhouette_1.silhouetteScore)(result);
64
+ (0, vitest_1.expect)(sil.perItem).toHaveLength(WELL_SEPARATED.length);
65
+ });
66
+ (0, vitest_1.it)('returns score=0 for k=1 (single cluster)', () => {
67
+ const result = (0, kmeans_1.kMeans)(WELL_SEPARATED, 1, { normalize: false, seed: 1 });
68
+ const sil = (0, silhouette_1.silhouetteScore)(result);
69
+ (0, vitest_1.expect)(sil.score).toBe(0);
70
+ });
71
+ (0, vitest_1.it)('each perItem value is in [-1, 1]', () => {
72
+ const result = (0, kmeans_1.kMeans)(WELL_SEPARATED, 2, { normalize: false, seed: 1 });
73
+ const sil = (0, silhouette_1.silhouetteScore)(result);
74
+ for (const s of sil.perItem ?? []) {
75
+ (0, vitest_1.expect)(s).toBeGreaterThanOrEqual(-1);
76
+ (0, vitest_1.expect)(s).toBeLessThanOrEqual(1);
77
+ }
78
+ });
79
+ (0, vitest_1.it)('mixed clusters produce lower score than well-separated clusters', () => {
80
+ const wellResult = (0, kmeans_1.kMeans)(WELL_SEPARATED, 2, { normalize: false, seed: 1 });
81
+ const mixedResult = (0, kmeans_1.kMeans)(MIXED, 2, { normalize: false, seed: 1 });
82
+ const wellSil = (0, silhouette_1.silhouetteScore)(wellResult);
83
+ const mixedSil = (0, silhouette_1.silhouetteScore)(mixedResult);
84
+ (0, vitest_1.expect)(wellSil.score).toBeGreaterThan(mixedSil.score);
85
+ });
86
+ (0, vitest_1.it)('score is the mean of perItem values', () => {
87
+ const result = (0, kmeans_1.kMeans)(WELL_SEPARATED, 2, { normalize: false, seed: 1 });
88
+ const sil = (0, silhouette_1.silhouetteScore)(result);
89
+ const perItem = sil.perItem ?? [];
90
+ const mean = perItem.reduce((s, v) => s + v, 0) / perItem.length;
91
+ (0, vitest_1.expect)(sil.score).toBeCloseTo(mean, 10);
92
+ });
93
+ (0, vitest_1.it)('returns score=0 for result with zero clusters', () => {
94
+ const emptyResult = {
95
+ clusters: [],
96
+ quality: { silhouette: { score: 0, perCluster: [] }, inertia: 0 },
97
+ k: 0,
98
+ iterations: 0,
99
+ converged: true,
100
+ durationMs: 0,
101
+ };
102
+ const sil = (0, silhouette_1.silhouetteScore)(emptyResult);
103
+ (0, vitest_1.expect)(sil.score).toBe(0);
104
+ });
105
+ (0, vitest_1.it)('singleton clusters: items with no same-cluster neighbors have a=0', () => {
106
+ // Build result with two singleton clusters
107
+ const dummyItems = makeItems([[1, 0], [-1, 0]]);
108
+ const result = buildClusterResult([[[1, 0]], [[-1, 0]]], dummyItems);
109
+ const sil = (0, silhouette_1.silhouetteScore)(result);
110
+ // a = 0 for singletons, b = distance to the other cluster
111
+ // s = (b - 0) / max(0, b) = 1
112
+ (0, vitest_1.expect)(sil.perItem?.[0]).toBeCloseTo(1, 5);
113
+ (0, vitest_1.expect)(sil.perItem?.[1]).toBeCloseTo(1, 5);
114
+ });
115
+ (0, vitest_1.it)('score improves with better clustering on 3-cluster data', () => {
116
+ const GROUP_C = [[0, 1], [0.05, 1.1], [-0.05, 0.9]];
117
+ const items3 = makeItems([...GROUP_A, ...GROUP_B, ...GROUP_C]);
118
+ const r3 = (0, kmeans_1.kMeans)(items3, 3, { normalize: false, seed: 1 });
119
+ const r2 = (0, kmeans_1.kMeans)(items3, 2, { normalize: false, seed: 1 });
120
+ const sil3 = (0, silhouette_1.silhouetteScore)(r3);
121
+ const sil2 = (0, silhouette_1.silhouetteScore)(r2);
122
+ // With 3 actual clusters, k=3 should score better than k=2
123
+ (0, vitest_1.expect)(sil3.score).toBeGreaterThan(sil2.score);
124
+ });
125
+ });
126
+ //# sourceMappingURL=silhouette.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"silhouette.test.js","sourceRoot":"","sources":["../../src/__tests__/silhouette.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/types.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ (0, vitest_1.describe)('types — compile-time checks', () => {
5
+ (0, vitest_1.it)('EmbedItem requires id, text, embedding', () => {
6
+ const item = {
7
+ id: 'test-id',
8
+ text: 'hello world',
9
+ embedding: [0.1, 0.2, 0.3],
10
+ };
11
+ (0, vitest_1.expect)(item.id).toBe('test-id');
12
+ (0, vitest_1.expect)(item.text).toBe('hello world');
13
+ (0, vitest_1.expect)(item.embedding).toEqual([0.1, 0.2, 0.3]);
14
+ });
15
+ (0, vitest_1.it)('EmbedItem supports optional metadata', () => {
16
+ const item = {
17
+ id: 'x',
18
+ text: 'y',
19
+ embedding: [1],
20
+ metadata: { source: 'web', timestamp: 1234567890 },
21
+ };
22
+ (0, vitest_1.expect)(item.metadata?.source).toBe('web');
23
+ });
24
+ (0, vitest_1.it)('ClusterItem extends EmbedItem with clusterId and distanceToCentroid', () => {
25
+ const ci = {
26
+ id: 'ci-1',
27
+ text: 'some text',
28
+ embedding: [0.5, 0.5],
29
+ clusterId: 2,
30
+ distanceToCentroid: 0.12,
31
+ };
32
+ (0, vitest_1.expect)(ci.clusterId).toBe(2);
33
+ (0, vitest_1.expect)(ci.distanceToCentroid).toBe(0.12);
34
+ // Inherited from EmbedItem
35
+ (0, vitest_1.expect)(ci.id).toBe('ci-1');
36
+ (0, vitest_1.expect)(ci.text).toBe('some text');
37
+ });
38
+ (0, vitest_1.it)('ClusterOptions has all-optional fields', () => {
39
+ // An empty object should be a valid ClusterOptions
40
+ const opts = {};
41
+ (0, vitest_1.expect)(opts).toBeDefined();
42
+ const fullOpts = {
43
+ k: 5,
44
+ autoK: true,
45
+ maxK: 10,
46
+ maxIterations: 100,
47
+ tolerance: 1e-4,
48
+ seed: 42,
49
+ normalize: true,
50
+ labeler: (_items, _id) => 'topic',
51
+ distanceFn: (a, b) => a.reduce((s, v, i) => s + Math.abs(v - b[i]), 0),
52
+ };
53
+ (0, vitest_1.expect)(fullOpts.k).toBe(5);
54
+ });
55
+ (0, vitest_1.it)('ClusterResult has clusters, quality, k, converged', () => {
56
+ const silhouette = { score: 0.8, perCluster: [0.75, 0.85] };
57
+ const quality = { silhouette, inertia: 0.42 };
58
+ const result = {
59
+ clusters: [],
60
+ quality,
61
+ k: 3,
62
+ iterations: 15,
63
+ converged: true,
64
+ durationMs: 123,
65
+ };
66
+ (0, vitest_1.expect)(result.clusters).toEqual([]);
67
+ (0, vitest_1.expect)(result.k).toBe(3);
68
+ (0, vitest_1.expect)(result.converged).toBe(true);
69
+ (0, vitest_1.expect)(result.quality.inertia).toBe(0.42);
70
+ });
71
+ (0, vitest_1.it)('Clusterer interface can be mock-implemented', () => {
72
+ const mockClusterer = {
73
+ cluster: async (_items, _options) => {
74
+ const silhouette = { score: 0.5, perCluster: [] };
75
+ const quality = { silhouette, inertia: 0 };
76
+ const result = {
77
+ clusters: [],
78
+ quality,
79
+ k: 2,
80
+ iterations: 10,
81
+ converged: true,
82
+ durationMs: 50,
83
+ };
84
+ return result;
85
+ },
86
+ findOptimalK: async (_items, _options) => ({
87
+ k: 3,
88
+ scores: [],
89
+ method: 'combined',
90
+ }),
91
+ silhouetteScore: (_result) => ({ score: 0.6, perCluster: [] }),
92
+ };
93
+ (0, vitest_1.expect)(mockClusterer).toBeDefined();
94
+ (0, vitest_1.expect)(typeof mockClusterer.cluster).toBe('function');
95
+ (0, vitest_1.expect)(typeof mockClusterer.findOptimalK).toBe('function');
96
+ (0, vitest_1.expect)(typeof mockClusterer.silhouetteScore).toBe('function');
97
+ });
98
+ (0, vitest_1.it)('ClusterErrorCode union has 5 values', () => {
99
+ const codes = [
100
+ 'EMPTY_INPUT',
101
+ 'INCONSISTENT_DIMENSIONS',
102
+ 'DEGENERATE_INPUT',
103
+ 'INVALID_K',
104
+ 'INVALID_OPTIONS',
105
+ ];
106
+ (0, vitest_1.expect)(codes).toHaveLength(5);
107
+ (0, vitest_1.expect)(codes).toContain('EMPTY_INPUT');
108
+ (0, vitest_1.expect)(codes).toContain('INCONSISTENT_DIMENSIONS');
109
+ (0, vitest_1.expect)(codes).toContain('DEGENERATE_INPUT');
110
+ (0, vitest_1.expect)(codes).toContain('INVALID_K');
111
+ (0, vitest_1.expect)(codes).toContain('INVALID_OPTIONS');
112
+ });
113
+ (0, vitest_1.it)('Cluster has required fields', () => {
114
+ const cluster = {
115
+ id: 0,
116
+ centroid: [1, 0, 0],
117
+ items: [],
118
+ size: 0,
119
+ avgDistanceToCentroid: 0,
120
+ cohesion: 0,
121
+ };
122
+ (0, vitest_1.expect)(cluster.id).toBe(0);
123
+ (0, vitest_1.expect)(cluster.centroid).toEqual([1, 0, 0]);
124
+ });
125
+ });
126
+ //# sourceMappingURL=types.test.js.map