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.
- package/README.md +122 -0
- package/dist/__tests__/cluster.test.d.ts +2 -0
- package/dist/__tests__/cluster.test.d.ts.map +1 -0
- package/dist/__tests__/cluster.test.js +202 -0
- package/dist/__tests__/cluster.test.js.map +1 -0
- package/dist/__tests__/errors.test.d.ts +2 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.js +68 -0
- package/dist/__tests__/errors.test.js.map +1 -0
- package/dist/__tests__/fixtures/embeddings-small.json +25 -0
- package/dist/__tests__/fixtures.test.d.ts +2 -0
- package/dist/__tests__/fixtures.test.d.ts.map +1 -0
- package/dist/__tests__/fixtures.test.js +44 -0
- package/dist/__tests__/fixtures.test.js.map +1 -0
- package/dist/__tests__/kmeans.test.d.ts +2 -0
- package/dist/__tests__/kmeans.test.d.ts.map +1 -0
- package/dist/__tests__/kmeans.test.js +220 -0
- package/dist/__tests__/kmeans.test.js.map +1 -0
- package/dist/__tests__/normalize.test.d.ts +2 -0
- package/dist/__tests__/normalize.test.d.ts.map +1 -0
- package/dist/__tests__/normalize.test.js +92 -0
- package/dist/__tests__/normalize.test.js.map +1 -0
- package/dist/__tests__/silhouette.test.d.ts +2 -0
- package/dist/__tests__/silhouette.test.d.ts.map +1 -0
- package/dist/__tests__/silhouette.test.js +126 -0
- package/dist/__tests__/silhouette.test.js.map +1 -0
- package/dist/__tests__/types.test.d.ts +2 -0
- package/dist/__tests__/types.test.d.ts.map +1 -0
- package/dist/__tests__/types.test.js +126 -0
- package/dist/__tests__/types.test.js.map +1 -0
- package/dist/clusterer.d.ts +17 -0
- package/dist/clusterer.d.ts.map +1 -0
- package/dist/clusterer.js +72 -0
- package/dist/clusterer.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +14 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/kmeans.d.ts +6 -0
- package/dist/kmeans.d.ts.map +1 -0
- package/dist/kmeans.js +250 -0
- package/dist/kmeans.js.map +1 -0
- package/dist/normalize.d.ts +10 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +21 -0
- package/dist/normalize.js.map +1 -0
- package/dist/optimal-k.d.ts +11 -0
- package/dist/optimal-k.d.ts.map +1 -0
- package/dist/optimal-k.js +49 -0
- package/dist/optimal-k.js.map +1 -0
- package/dist/silhouette.d.ts +16 -0
- package/dist/silhouette.d.ts.map +1 -0
- package/dist/silhouette.js +95 -0
- package/dist/silhouette.js.map +1 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# embed-cluster
|
|
2
|
+
|
|
3
|
+
Cluster embeddings into topics with automatic labeling.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install embed-cluster
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For dimensionality reduction (PCA or UMAP), install the optional peer dependencies:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install ml-pca # PCA-based dimensionality reduction
|
|
15
|
+
npm install umap-js # UMAP-based dimensionality reduction
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { cluster, createClusterer } from 'embed-cluster';
|
|
22
|
+
|
|
23
|
+
// Cluster raw embedding vectors
|
|
24
|
+
const result = await cluster(embeddings, { k: 5 });
|
|
25
|
+
|
|
26
|
+
console.log(result.clusters); // 5 clusters with labels, centroids, items
|
|
27
|
+
console.log(result.quality); // silhouette score, inertia, interpretation
|
|
28
|
+
|
|
29
|
+
// Or use a pre-configured clusterer
|
|
30
|
+
const clusterer = createClusterer({
|
|
31
|
+
autoK: true,
|
|
32
|
+
maxK: 15,
|
|
33
|
+
normalize: true,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const result = await clusterer.cluster(items);
|
|
37
|
+
const optimal = await clusterer.findOptimalK(items);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Available Exports
|
|
41
|
+
|
|
42
|
+
### Clustering Functions
|
|
43
|
+
|
|
44
|
+
- **`cluster(items, options): Promise<ClusterResult>`** -- Cluster EmbedItems using k-means++ and return a full ClusterResult with silhouette scores. Provide `options.k` for a fixed cluster count or `options.autoK = true` for automatic selection.
|
|
45
|
+
- **`findOptimalK(items, options?): OptimalKResult`** -- Try k from 2 to `maxK` (default min(10, √n)), compute silhouette score for each, and return the k that maximises the score.
|
|
46
|
+
- **`silhouetteScore(result): SilhouetteResult`** -- Compute per-item, per-cluster, and overall mean silhouette coefficients for an existing ClusterResult. Returns a value in [-1, 1]; higher is better.
|
|
47
|
+
- **`createClusterer(config): Clusterer`** -- Create a pre-configured Clusterer instance with `cluster()`, `findOptimalK()`, and `silhouetteScore()` bound to the given config.
|
|
48
|
+
|
|
49
|
+
### Utility Functions
|
|
50
|
+
|
|
51
|
+
- **`normalizeVector(vec: number[]): number[]`** -- L2-normalize a single vector to unit length. Returns a zero vector unchanged.
|
|
52
|
+
- **`normalizeVectors(vecs: number[][]): number[][]`** -- L2-normalize a batch of vectors independently.
|
|
53
|
+
- **`euclideanDistance(a, b): number`** -- Euclidean distance between two vectors.
|
|
54
|
+
- **`cosineDistance(a, b): number`** -- Cosine distance (1 - cosine similarity) between two vectors.
|
|
55
|
+
|
|
56
|
+
### Types
|
|
57
|
+
|
|
58
|
+
All TypeScript interfaces are exported for consumer use:
|
|
59
|
+
|
|
60
|
+
- `EmbedItem` -- Input item with id, text, embedding, and optional metadata
|
|
61
|
+
- `ClusterItem` -- An `EmbedItem` assigned to a cluster with distance-to-centroid
|
|
62
|
+
- `Cluster` -- A cluster with centroid, items, label, size, and cohesion metrics
|
|
63
|
+
- `ClusterOptions` -- Configuration for clustering (k, autoK, maxK, tolerance, seed, etc.)
|
|
64
|
+
- `ClusterResult` -- Full result including clusters, quality metrics, iteration count, and timing
|
|
65
|
+
- `Clusterer` -- Interface for a pre-configured clusterer instance
|
|
66
|
+
- `SilhouetteResult` -- Silhouette coefficient scores (overall, per-cluster, per-item)
|
|
67
|
+
- `OptimalKResult` -- Result of automatic k selection with scores per candidate k
|
|
68
|
+
- `ClusterQuality` -- Quality metrics including silhouette, inertia, and optional indices
|
|
69
|
+
- `VisualizationData` -- 2D projected points for visualization (PCA, UMAP, or t-SNE)
|
|
70
|
+
- `LabelerFn` -- Custom labeling function signature
|
|
71
|
+
|
|
72
|
+
### Error Handling
|
|
73
|
+
|
|
74
|
+
- **`ClusterError`** -- Error class with typed `code` field for programmatic error handling
|
|
75
|
+
- **`ClusterErrorCode`** -- Union type of error codes: `EMPTY_INPUT`, `INCONSISTENT_DIMENSIONS`, `DEGENERATE_INPUT`, `INVALID_K`, `INVALID_OPTIONS`
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { ClusterError } from 'embed-cluster';
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const result = await cluster([], { k: 3 });
|
|
82
|
+
} catch (err) {
|
|
83
|
+
if (err instanceof ClusterError) {
|
|
84
|
+
console.error(err.code); // 'EMPTY_INPUT'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Features
|
|
90
|
+
|
|
91
|
+
- **k-means++ clustering** -- Smart centroid initialization for faster convergence and better results
|
|
92
|
+
- **Silhouette analysis** -- Evaluate cluster quality with per-point and per-cluster silhouette coefficients
|
|
93
|
+
- **Automatic k selection** -- Find the optimal number of clusters using silhouette and elbow methods
|
|
94
|
+
- **PCA/UMAP visualization** -- Reduce high-dimensional embeddings to 2D for visualization (requires optional peer deps)
|
|
95
|
+
- **L2 normalization** -- Built-in vector normalization for cosine-distance clustering
|
|
96
|
+
- **Custom labeling** -- Provide your own labeling function or use built-in TF-IDF topic extraction
|
|
97
|
+
- **Reproducible results** -- Seed-based random number generation for deterministic clustering
|
|
98
|
+
- **TypeScript-first** -- Full type definitions with strict typing throughout
|
|
99
|
+
|
|
100
|
+
## Configuration
|
|
101
|
+
|
|
102
|
+
| Option | Type | Default | Description |
|
|
103
|
+
|--------|------|---------|-------------|
|
|
104
|
+
| `k` | `number` | -- | Number of clusters (required if `autoK` is false) |
|
|
105
|
+
| `autoK` | `boolean` | `false` | Automatically select optimal k |
|
|
106
|
+
| `maxK` | `number` | `10` | Maximum k to try when `autoK` is true |
|
|
107
|
+
| `maxIterations` | `number` | `100` | Maximum k-means iterations |
|
|
108
|
+
| `tolerance` | `number` | `1e-4` | Convergence tolerance |
|
|
109
|
+
| `seed` | `number` | -- | Random seed for reproducibility |
|
|
110
|
+
| `normalize` | `boolean` | `true` | L2-normalize embeddings before clustering |
|
|
111
|
+
| `labeler` | `LabelerFn` | -- | Custom labeling function |
|
|
112
|
+
| `distanceFn` | `Function` | -- | Custom distance function |
|
|
113
|
+
|
|
114
|
+
## CLI
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx embed-cluster --input embeddings.json --k 5 --format summary
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cluster.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const clusterer_1 = require("../clusterer");
|
|
8
|
+
const silhouette_1 = require("../silhouette");
|
|
9
|
+
const errors_1 = require("../errors");
|
|
10
|
+
const embeddings_small_json_1 = __importDefault(require("./fixtures/embeddings-small.json"));
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Helpers
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
function makeItems(coords) {
|
|
15
|
+
return coords.map((embedding, i) => ({ id: `item-${i}`, text: `doc ${i}`, embedding }));
|
|
16
|
+
}
|
|
17
|
+
// Two clear clusters: group near [1,0] and group near [-1,0]
|
|
18
|
+
const GROUP_A = [[1, 0.05], [1.1, 0], [0.9, -0.05], [1.0, 0.02]];
|
|
19
|
+
const GROUP_B = [[-1, 0.05], [-1.1, 0], [-0.9, -0.05], [-1.0, 0.02]];
|
|
20
|
+
const ITEMS_2 = makeItems([...GROUP_A, ...GROUP_B]);
|
|
21
|
+
// Three clear clusters
|
|
22
|
+
const GROUP_C = [[0, 1.0], [0.05, 1.1], [-0.05, 0.95]];
|
|
23
|
+
const ITEMS_3 = makeItems([...GROUP_A, ...GROUP_B, ...GROUP_C]);
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// cluster()
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
(0, vitest_1.describe)('cluster()', () => {
|
|
28
|
+
(0, vitest_1.it)('returns a ClusterResult with k=2 clusters', async () => {
|
|
29
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, { k: 2, normalize: false, seed: 1 });
|
|
30
|
+
(0, vitest_1.expect)(result.k).toBe(2);
|
|
31
|
+
(0, vitest_1.expect)(result.clusters).toHaveLength(2);
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)('all items appear in result', async () => {
|
|
34
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, { k: 2, normalize: false, seed: 1 });
|
|
35
|
+
const total = result.clusters.reduce((s, c) => s + c.items.length, 0);
|
|
36
|
+
(0, vitest_1.expect)(total).toBe(ITEMS_2.length);
|
|
37
|
+
});
|
|
38
|
+
(0, vitest_1.it)('quality.silhouette.score is populated (non-zero for separated data)', async () => {
|
|
39
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, { k: 2, normalize: false, seed: 1 });
|
|
40
|
+
(0, vitest_1.expect)(result.quality.silhouette.score).toBeGreaterThan(0.5);
|
|
41
|
+
});
|
|
42
|
+
(0, vitest_1.it)('quality.silhouette.perCluster has length k', async () => {
|
|
43
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, { k: 2, normalize: false, seed: 1 });
|
|
44
|
+
(0, vitest_1.expect)(result.quality.silhouette.perCluster).toHaveLength(2);
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.it)('throws ClusterError EMPTY_INPUT for empty array', async () => {
|
|
47
|
+
await (0, vitest_1.expect)((0, clusterer_1.cluster)([], { k: 2 })).rejects.toThrow(errors_1.ClusterError);
|
|
48
|
+
await (0, vitest_1.expect)((0, clusterer_1.cluster)([], { k: 2 })).rejects.toMatchObject({ code: 'EMPTY_INPUT' });
|
|
49
|
+
});
|
|
50
|
+
(0, vitest_1.it)('throws ClusterError INVALID_OPTIONS when neither k nor autoK provided', async () => {
|
|
51
|
+
await (0, vitest_1.expect)((0, clusterer_1.cluster)(ITEMS_2, {})).rejects.toThrow(errors_1.ClusterError);
|
|
52
|
+
await (0, vitest_1.expect)((0, clusterer_1.cluster)(ITEMS_2, {})).rejects.toMatchObject({ code: 'INVALID_OPTIONS' });
|
|
53
|
+
});
|
|
54
|
+
(0, vitest_1.it)('autoK=true selects k and returns result', async () => {
|
|
55
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_3, { autoK: true, normalize: false, seed: 1 });
|
|
56
|
+
(0, vitest_1.expect)(result.k).toBeGreaterThanOrEqual(2);
|
|
57
|
+
(0, vitest_1.expect)(result.clusters).toHaveLength(result.k);
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)('durationMs is populated', async () => {
|
|
60
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, { k: 2, normalize: false, seed: 1 });
|
|
61
|
+
(0, vitest_1.expect)(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('labeler is called for each cluster', async () => {
|
|
64
|
+
const labels = [];
|
|
65
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, {
|
|
66
|
+
k: 2,
|
|
67
|
+
normalize: false,
|
|
68
|
+
seed: 1,
|
|
69
|
+
labeler: (_items, id) => {
|
|
70
|
+
const label = `cluster-${id}`;
|
|
71
|
+
labels.push(label);
|
|
72
|
+
return label;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.expect)(labels).toHaveLength(2);
|
|
76
|
+
for (const c of result.clusters) {
|
|
77
|
+
(0, vitest_1.expect)(c.label).toBeDefined();
|
|
78
|
+
(0, vitest_1.expect)(c.label).toMatch(/^cluster-\d$/);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
(0, vitest_1.it)('async labeler is supported', async () => {
|
|
82
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, {
|
|
83
|
+
k: 2,
|
|
84
|
+
normalize: false,
|
|
85
|
+
seed: 1,
|
|
86
|
+
labeler: async (_items, id) => {
|
|
87
|
+
return `async-label-${id}`;
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
for (const c of result.clusters) {
|
|
91
|
+
(0, vitest_1.expect)(c.label).toMatch(/^async-label-\d$/);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
(0, vitest_1.it)('works with fixture data (20 items, 4D embeddings, k=3)', async () => {
|
|
95
|
+
const items = embeddings_small_json_1.default.items;
|
|
96
|
+
const result = await (0, clusterer_1.cluster)(items, { k: 3, normalize: true, seed: 42 });
|
|
97
|
+
(0, vitest_1.expect)(result.k).toBe(3);
|
|
98
|
+
const total = result.clusters.reduce((s, c) => s + c.items.length, 0);
|
|
99
|
+
(0, vitest_1.expect)(total).toBe(20);
|
|
100
|
+
});
|
|
101
|
+
(0, vitest_1.it)('fixture: silhouette score > 0.5 for well-separated clusters', async () => {
|
|
102
|
+
const items = embeddings_small_json_1.default.items;
|
|
103
|
+
const result = await (0, clusterer_1.cluster)(items, { k: 3, normalize: true, seed: 42 });
|
|
104
|
+
(0, vitest_1.expect)(result.quality.silhouette.score).toBeGreaterThan(0.5);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// findOptimalK()
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
(0, vitest_1.describe)('findOptimalK()', () => {
|
|
111
|
+
(0, vitest_1.it)('returns an OptimalKResult with a k value', () => {
|
|
112
|
+
const result = (0, clusterer_1.findOptimalK)(ITEMS_3, { normalize: false, seed: 1 });
|
|
113
|
+
(0, vitest_1.expect)(result.k).toBeGreaterThanOrEqual(2);
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_1.it)('method is "silhouette"', () => {
|
|
116
|
+
const result = (0, clusterer_1.findOptimalK)(ITEMS_3, { normalize: false, seed: 1 });
|
|
117
|
+
(0, vitest_1.expect)(result.method).toBe('silhouette');
|
|
118
|
+
});
|
|
119
|
+
(0, vitest_1.it)('scores array has an entry per k tried', () => {
|
|
120
|
+
const result = (0, clusterer_1.findOptimalK)(ITEMS_3, { normalize: false, seed: 1, maxK: 4 });
|
|
121
|
+
// kMin=2, kMax=min(4, n-1)
|
|
122
|
+
(0, vitest_1.expect)(result.scores.length).toBeGreaterThanOrEqual(1);
|
|
123
|
+
for (const entry of result.scores) {
|
|
124
|
+
(0, vitest_1.expect)(entry.k).toBeGreaterThanOrEqual(2);
|
|
125
|
+
(0, vitest_1.expect)(typeof entry.silhouette).toBe('number');
|
|
126
|
+
(0, vitest_1.expect)(typeof entry.inertia).toBe('number');
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
(0, vitest_1.it)('returns k >= 3 for clearly 3-cluster data (silhouette selects good k)', () => {
|
|
130
|
+
const result = (0, clusterer_1.findOptimalK)(ITEMS_3, { normalize: false, seed: 1, maxK: 5 });
|
|
131
|
+
// The selected k must be at least 3 (the true cluster count); silhouette
|
|
132
|
+
// may also prefer tighter sub-clusters when maxK allows it.
|
|
133
|
+
(0, vitest_1.expect)(result.k).toBeGreaterThanOrEqual(3);
|
|
134
|
+
});
|
|
135
|
+
(0, vitest_1.it)('selected k has the highest silhouette score in scores', () => {
|
|
136
|
+
const result = (0, clusterer_1.findOptimalK)(ITEMS_3, { normalize: false, seed: 1, maxK: 5 });
|
|
137
|
+
const best = result.scores.reduce((a, b) => (a.silhouette > b.silhouette ? a : b));
|
|
138
|
+
(0, vitest_1.expect)(result.k).toBe(best.k);
|
|
139
|
+
});
|
|
140
|
+
(0, vitest_1.it)('fixture: findOptimalK returns k=3 for 3-cluster fixture', () => {
|
|
141
|
+
const items = embeddings_small_json_1.default.items;
|
|
142
|
+
const result = (0, clusterer_1.findOptimalK)(items, { normalize: true, seed: 42, maxK: 6 });
|
|
143
|
+
(0, vitest_1.expect)(result.k).toBe(3);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
// createClusterer()
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
(0, vitest_1.describe)('createClusterer()', () => {
|
|
150
|
+
(0, vitest_1.it)('returns an object with cluster, findOptimalK, silhouetteScore', () => {
|
|
151
|
+
const c = (0, clusterer_1.createClusterer)({ normalize: false, seed: 1 });
|
|
152
|
+
(0, vitest_1.expect)(typeof c.cluster).toBe('function');
|
|
153
|
+
(0, vitest_1.expect)(typeof c.findOptimalK).toBe('function');
|
|
154
|
+
(0, vitest_1.expect)(typeof c.silhouetteScore).toBe('function');
|
|
155
|
+
});
|
|
156
|
+
(0, vitest_1.it)('cluster() uses bound config', async () => {
|
|
157
|
+
const c = (0, clusterer_1.createClusterer)({ normalize: false, seed: 1 });
|
|
158
|
+
const result = await c.cluster(ITEMS_2, { k: 2 });
|
|
159
|
+
(0, vitest_1.expect)(result.k).toBe(2);
|
|
160
|
+
(0, vitest_1.expect)(result.clusters).toHaveLength(2);
|
|
161
|
+
});
|
|
162
|
+
(0, vitest_1.it)('cluster() options override bound config', async () => {
|
|
163
|
+
const c = (0, clusterer_1.createClusterer)({ normalize: false, seed: 1, k: 2 });
|
|
164
|
+
// Override k=2 with k=1
|
|
165
|
+
const result = await c.cluster(ITEMS_2, { k: 1 });
|
|
166
|
+
(0, vitest_1.expect)(result.k).toBe(1);
|
|
167
|
+
});
|
|
168
|
+
(0, vitest_1.it)('findOptimalK() uses bound config', async () => {
|
|
169
|
+
const c = (0, clusterer_1.createClusterer)({ normalize: false, seed: 1 });
|
|
170
|
+
const result = await c.findOptimalK(ITEMS_3, { maxK: 5 });
|
|
171
|
+
(0, vitest_1.expect)(result.k).toBeGreaterThanOrEqual(2);
|
|
172
|
+
});
|
|
173
|
+
(0, vitest_1.it)('silhouetteScore() returns SilhouetteResult', async () => {
|
|
174
|
+
const c = (0, clusterer_1.createClusterer)({ normalize: false, seed: 1 });
|
|
175
|
+
const result = await c.cluster(ITEMS_2, { k: 2 });
|
|
176
|
+
const sil = c.silhouetteScore(result);
|
|
177
|
+
(0, vitest_1.expect)(typeof sil.score).toBe('number');
|
|
178
|
+
(0, vitest_1.expect)(sil.perCluster).toHaveLength(2);
|
|
179
|
+
});
|
|
180
|
+
(0, vitest_1.it)('two clusterers with different seeds can produce different assignments', async () => {
|
|
181
|
+
// Use a case where seed matters: run on data where init order could vary
|
|
182
|
+
const c1 = (0, clusterer_1.createClusterer)({ normalize: false, seed: 1 });
|
|
183
|
+
const c2 = (0, clusterer_1.createClusterer)({ normalize: false, seed: 99999 });
|
|
184
|
+
const r1 = await c1.cluster(ITEMS_3, { k: 3 });
|
|
185
|
+
const r2 = await c2.cluster(ITEMS_3, { k: 3 });
|
|
186
|
+
// Both should still produce 3 clusters — the assignments may differ
|
|
187
|
+
(0, vitest_1.expect)(r1.clusters).toHaveLength(3);
|
|
188
|
+
(0, vitest_1.expect)(r2.clusters).toHaveLength(3);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// silhouetteScore re-export from clusterer
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
(0, vitest_1.describe)('silhouetteScore re-export', () => {
|
|
195
|
+
(0, vitest_1.it)('silhouetteScore from clusterer matches silhouetteScore from silhouette module', async () => {
|
|
196
|
+
const result = await (0, clusterer_1.cluster)(ITEMS_2, { k: 2, normalize: false, seed: 1 });
|
|
197
|
+
const s1 = (0, clusterer_1.silhouetteScore)(result);
|
|
198
|
+
const s2 = (0, silhouette_1.silhouetteScore)(result);
|
|
199
|
+
(0, vitest_1.expect)(s1.score).toBeCloseTo(s2.score, 10);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
//# sourceMappingURL=cluster.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.test.js","sourceRoot":"","sources":["../../src/__tests__/cluster.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const errors_1 = require("../errors");
|
|
5
|
+
(0, vitest_1.describe)('ClusterError', () => {
|
|
6
|
+
(0, vitest_1.it)('extends Error', () => {
|
|
7
|
+
const err = new errors_1.ClusterError('something failed', 'EMPTY_INPUT');
|
|
8
|
+
(0, vitest_1.expect)(err).toBeInstanceOf(Error);
|
|
9
|
+
});
|
|
10
|
+
(0, vitest_1.it)('name is ClusterError', () => {
|
|
11
|
+
const err = new errors_1.ClusterError('msg', 'INVALID_K');
|
|
12
|
+
(0, vitest_1.expect)(err.name).toBe('ClusterError');
|
|
13
|
+
});
|
|
14
|
+
(0, vitest_1.it)('code is accessible', () => {
|
|
15
|
+
const err = new errors_1.ClusterError('bad k', 'INVALID_K');
|
|
16
|
+
(0, vitest_1.expect)(err.code).toBe('INVALID_K');
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.it)('instanceof ClusterError is correct', () => {
|
|
19
|
+
const err = new errors_1.ClusterError('test', 'INVALID_OPTIONS');
|
|
20
|
+
(0, vitest_1.expect)(err).toBeInstanceOf(errors_1.ClusterError);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)('message is preserved', () => {
|
|
23
|
+
const msg = 'embeddings array is empty';
|
|
24
|
+
const err = new errors_1.ClusterError(msg, 'EMPTY_INPUT');
|
|
25
|
+
(0, vitest_1.expect)(err.message).toBe(msg);
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.it)('constructs with EMPTY_INPUT code', () => {
|
|
28
|
+
const err = new errors_1.ClusterError('no items', 'EMPTY_INPUT');
|
|
29
|
+
(0, vitest_1.expect)(err.code).toBe('EMPTY_INPUT');
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.it)('constructs with INCONSISTENT_DIMENSIONS code', () => {
|
|
32
|
+
const err = new errors_1.ClusterError('dim mismatch', 'INCONSISTENT_DIMENSIONS');
|
|
33
|
+
(0, vitest_1.expect)(err.code).toBe('INCONSISTENT_DIMENSIONS');
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.it)('constructs with DEGENERATE_INPUT code', () => {
|
|
36
|
+
const err = new errors_1.ClusterError('all zeros', 'DEGENERATE_INPUT');
|
|
37
|
+
(0, vitest_1.expect)(err.code).toBe('DEGENERATE_INPUT');
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.it)('constructs with INVALID_K code', () => {
|
|
40
|
+
const err = new errors_1.ClusterError('k must be >= 2', 'INVALID_K');
|
|
41
|
+
(0, vitest_1.expect)(err.code).toBe('INVALID_K');
|
|
42
|
+
});
|
|
43
|
+
(0, vitest_1.it)('constructs with INVALID_OPTIONS code', () => {
|
|
44
|
+
const err = new errors_1.ClusterError('bad options', 'INVALID_OPTIONS');
|
|
45
|
+
(0, vitest_1.expect)(err.code).toBe('INVALID_OPTIONS');
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.it)('all 5 error codes construct correctly', () => {
|
|
48
|
+
const codes = [
|
|
49
|
+
'EMPTY_INPUT',
|
|
50
|
+
'INCONSISTENT_DIMENSIONS',
|
|
51
|
+
'DEGENERATE_INPUT',
|
|
52
|
+
'INVALID_K',
|
|
53
|
+
'INVALID_OPTIONS',
|
|
54
|
+
];
|
|
55
|
+
for (const code of codes) {
|
|
56
|
+
const err = new errors_1.ClusterError(`error: ${code}`, code);
|
|
57
|
+
(0, vitest_1.expect)(err).toBeInstanceOf(errors_1.ClusterError);
|
|
58
|
+
(0, vitest_1.expect)(err).toBeInstanceOf(Error);
|
|
59
|
+
(0, vitest_1.expect)(err.code).toBe(code);
|
|
60
|
+
(0, vitest_1.expect)(err.name).toBe('ClusterError');
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('stack trace is populated', () => {
|
|
64
|
+
const err = new errors_1.ClusterError('trace check', 'EMPTY_INPUT');
|
|
65
|
+
(0, vitest_1.expect)(err.stack).toBeDefined();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=errors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "20 synthetic 4D embeddings with 3 clear clusters",
|
|
3
|
+
"items": [
|
|
4
|
+
{ "id": "c0-0", "text": "doc 0", "embedding": [0.95, 0.1, -0.1, 0.05] },
|
|
5
|
+
{ "id": "c0-1", "text": "doc 1", "embedding": [1.0, -0.05, 0.08, -0.03] },
|
|
6
|
+
{ "id": "c0-2", "text": "doc 2", "embedding": [0.9, 0.15, -0.12, 0.1] },
|
|
7
|
+
{ "id": "c0-3", "text": "doc 3", "embedding": [0.98, 0.0, 0.05, -0.08] },
|
|
8
|
+
{ "id": "c0-4", "text": "doc 4", "embedding": [0.92, -0.1, 0.1, 0.05] },
|
|
9
|
+
{ "id": "c0-5", "text": "doc 5", "embedding": [0.97, 0.07, -0.07, 0.02] },
|
|
10
|
+
{ "id": "c1-0", "text": "doc 6", "embedding": [-0.05, 0.95, 0.1, 0.05] },
|
|
11
|
+
{ "id": "c1-1", "text": "doc 7", "embedding": [0.08, 1.0, -0.05, -0.03] },
|
|
12
|
+
{ "id": "c1-2", "text": "doc 8", "embedding": [-0.1, 0.9, 0.15, 0.1] },
|
|
13
|
+
{ "id": "c1-3", "text": "doc 9", "embedding": [0.0, 0.98, 0.05, -0.08] },
|
|
14
|
+
{ "id": "c1-4", "text": "doc 10", "embedding": [0.07, 0.93, -0.1, -0.05] },
|
|
15
|
+
{ "id": "c1-5", "text": "doc 11", "embedding": [-0.03, 0.97, 0.07, 0.02] },
|
|
16
|
+
{ "id": "c2-0", "text": "doc 12", "embedding": [0.05, -0.05, 0.95, 0.1] },
|
|
17
|
+
{ "id": "c2-1", "text": "doc 13", "embedding": [-0.08, 0.05, 1.0, -0.05] },
|
|
18
|
+
{ "id": "c2-2", "text": "doc 14", "embedding": [0.1, -0.1, 0.9, 0.15] },
|
|
19
|
+
{ "id": "c2-3", "text": "doc 15", "embedding": [-0.0, 0.0, 0.98, 0.05] },
|
|
20
|
+
{ "id": "c2-4", "text": "doc 16", "embedding": [0.07, 0.05, 0.93, -0.1] },
|
|
21
|
+
{ "id": "c2-5", "text": "doc 17", "embedding": [-0.03, -0.03, 0.97, 0.07] },
|
|
22
|
+
{ "id": "extra-0", "text": "doc 18", "embedding": [0.96, 0.12, -0.08, 0.03] },
|
|
23
|
+
{ "id": "extra-1", "text": "doc 19", "embedding": [-0.02, 0.96, 0.12, 0.04] }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fixtures.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const embeddings_small_json_1 = __importDefault(require("./fixtures/embeddings-small.json"));
|
|
8
|
+
(0, vitest_1.describe)('embeddings-small.json fixture', () => {
|
|
9
|
+
(0, vitest_1.it)('loads and parses', () => {
|
|
10
|
+
(0, vitest_1.expect)(embeddings_small_json_1.default).toBeDefined();
|
|
11
|
+
(0, vitest_1.expect)(typeof embeddings_small_json_1.default).toBe('object');
|
|
12
|
+
});
|
|
13
|
+
(0, vitest_1.it)('has exactly 20 items', () => {
|
|
14
|
+
(0, vitest_1.expect)(embeddings_small_json_1.default.items).toHaveLength(20);
|
|
15
|
+
});
|
|
16
|
+
(0, vitest_1.it)('each item has id, text, embedding fields', () => {
|
|
17
|
+
for (const item of embeddings_small_json_1.default.items) {
|
|
18
|
+
(0, vitest_1.expect)(typeof item.id).toBe('string');
|
|
19
|
+
(0, vitest_1.expect)(typeof item.text).toBe('string');
|
|
20
|
+
(0, vitest_1.expect)(Array.isArray(item.embedding)).toBe(true);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
(0, vitest_1.it)('all embeddings have length 4', () => {
|
|
24
|
+
for (const item of embeddings_small_json_1.default.items) {
|
|
25
|
+
(0, vitest_1.expect)(item.embedding).toHaveLength(4);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)('all embedding values are numbers', () => {
|
|
29
|
+
for (const item of embeddings_small_json_1.default.items) {
|
|
30
|
+
for (const val of item.embedding) {
|
|
31
|
+
(0, vitest_1.expect)(typeof val).toBe('number');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.it)('all item ids are unique', () => {
|
|
36
|
+
const ids = embeddings_small_json_1.default.items.map((i) => i.id);
|
|
37
|
+
const unique = new Set(ids);
|
|
38
|
+
(0, vitest_1.expect)(unique.size).toBe(20);
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)('has a description field', () => {
|
|
41
|
+
(0, vitest_1.expect)(typeof embeddings_small_json_1.default.description).toBe('string');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=fixtures.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.test.js","sourceRoot":"","sources":["../../src/__tests__/fixtures.test.ts"],"names":[],"mappings":";;;;;AAAA,mCAA8C;AAC9C,6FAAuD;AAEvD,IAAA,iBAAQ,EAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,IAAA,WAAE,EAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,IAAA,eAAM,EAAC,+BAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9B,IAAA,eAAM,EAAC,OAAO,+BAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,IAAA,eAAM,EAAC,+BAAO,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,KAAK,MAAM,IAAI,IAAI,+BAAO,CAAC,KAAK,EAAE,CAAC;YACjC,IAAA,eAAM,EAAC,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAA,eAAM,EAAC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAA,eAAM,EAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,KAAK,MAAM,IAAI,IAAI,+BAAO,CAAC,KAAK,EAAE,CAAC;YACjC,IAAA,eAAM,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,KAAK,MAAM,IAAI,IAAI,+BAAO,CAAC,KAAK,EAAE,CAAC;YACjC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACjC,IAAA,eAAM,EAAC,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,GAAG,GAAG,+BAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAA,eAAM,EAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,IAAA,eAAM,EAAC,OAAO,+BAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kmeans.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/kmeans.test.ts"],"names":[],"mappings":""}
|