@graphty/algorithms 1.5.0 → 1.7.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 +13 -0
- package/dist/algorithms.js +33 -23
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +10 -7
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/clustering/mcl.d.ts.map +1 -1
- package/dist/src/clustering/mcl.js +33 -21
- package/dist/src/clustering/mcl.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -4
- package/src/algorithms/community/girvan-newman.ts +19 -8
- package/src/clustering/mcl.ts +38 -24
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@graphty/algorithms)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://graphty.app/docs/algorithms/)
|
|
8
|
+
[](https://graphty.app/storybook/algorithms/)
|
|
8
9
|
[](https://graphty.app/algorithms/)
|
|
9
10
|
|
|
10
11
|
A comprehensive TypeScript graph algorithms library with 98 algorithms optimized for browser environments and visualization applications.
|
|
@@ -1028,6 +1029,18 @@ const result = grsbm(graph, {
|
|
|
1028
1029
|
|
|
1029
1030
|
## Interactive Examples
|
|
1030
1031
|
|
|
1032
|
+
### Storybook (Recommended)
|
|
1033
|
+
|
|
1034
|
+
Explore algorithms with interactive Storybook demos: **[View Storybook →](https://graphty.app/storybook/algorithms/)**
|
|
1035
|
+
|
|
1036
|
+
Storybook provides:
|
|
1037
|
+
- **Animated visualizations** showing how each algorithm works step-by-step
|
|
1038
|
+
- **Interactive controls** to modify parameters and graph types
|
|
1039
|
+
- **Deterministic output** with seeded randomness for reproducibility
|
|
1040
|
+
- **Visual testing** with Chromatic for regression detection
|
|
1041
|
+
|
|
1042
|
+
### Legacy HTML Examples
|
|
1043
|
+
|
|
1031
1044
|
Try out all algorithms with interactive visualizations: **[Live Demo →](https://graphty.app/algorithms/)**
|
|
1032
1045
|
|
|
1033
1046
|
The library includes comprehensive examples demonstrating each algorithm. You can:
|
package/dist/algorithms.js
CHANGED
|
@@ -6370,7 +6370,7 @@ function girvanNewman(graph, options = {}) {
|
|
|
6370
6370
|
});
|
|
6371
6371
|
while (Array.from(workingGraph.edges()).length > 0 && iterations < maxIterations) {
|
|
6372
6372
|
iterations++;
|
|
6373
|
-
const edgeBetweenness = calculateEdgeBetweenness(workingGraph);
|
|
6373
|
+
const { betweenness: edgeBetweenness, edgeEndpoints } = calculateEdgeBetweenness(workingGraph);
|
|
6374
6374
|
if (edgeBetweenness.size === 0) {
|
|
6375
6375
|
break;
|
|
6376
6376
|
}
|
|
@@ -6378,9 +6378,9 @@ function girvanNewman(graph, options = {}) {
|
|
|
6378
6378
|
const edgesToRemove = [];
|
|
6379
6379
|
for (const [edgeKey, centrality] of edgeBetweenness) {
|
|
6380
6380
|
if (Math.abs(centrality - maxBetweenness) < 1e-10) {
|
|
6381
|
-
const
|
|
6382
|
-
if (
|
|
6383
|
-
edgesToRemove.push(
|
|
6381
|
+
const endpoints = edgeEndpoints.get(edgeKey);
|
|
6382
|
+
if (endpoints) {
|
|
6383
|
+
edgesToRemove.push(endpoints);
|
|
6384
6384
|
}
|
|
6385
6385
|
}
|
|
6386
6386
|
}
|
|
@@ -6405,9 +6405,11 @@ function girvanNewman(graph, options = {}) {
|
|
|
6405
6405
|
}
|
|
6406
6406
|
function calculateEdgeBetweenness(graph) {
|
|
6407
6407
|
const edgeBetweenness = /* @__PURE__ */ new Map();
|
|
6408
|
+
const edgeEndpoints = /* @__PURE__ */ new Map();
|
|
6408
6409
|
for (const edge of graph.edges()) {
|
|
6409
6410
|
const edgeKey = getEdgeKey(edge.source, edge.target);
|
|
6410
6411
|
edgeBetweenness.set(edgeKey, 0);
|
|
6412
|
+
edgeEndpoints.set(edgeKey, { source: edge.source, target: edge.target });
|
|
6411
6413
|
}
|
|
6412
6414
|
for (const sourceNode of graph.nodes()) {
|
|
6413
6415
|
const source = sourceNode.id;
|
|
@@ -6458,7 +6460,7 @@ function calculateEdgeBetweenness(graph) {
|
|
|
6458
6460
|
edgeBetweenness.set(edgeKey, betweenness / 2);
|
|
6459
6461
|
}
|
|
6460
6462
|
}
|
|
6461
|
-
return edgeBetweenness;
|
|
6463
|
+
return { betweenness: edgeBetweenness, edgeEndpoints };
|
|
6462
6464
|
}
|
|
6463
6465
|
function findAllShortestPaths(graph, source) {
|
|
6464
6466
|
const distances = /* @__PURE__ */ new Map();
|
|
@@ -9022,7 +9024,7 @@ function buildTransitionMatrix(graph, nodeIds, selfLoops) {
|
|
|
9022
9024
|
nodeIds.forEach((id, index) => nodeToIndex.set(id, index));
|
|
9023
9025
|
for (let i = 0; i < n; i++) {
|
|
9024
9026
|
const nodeId = nodeIds[i];
|
|
9025
|
-
if (
|
|
9027
|
+
if (nodeId === void 0) {
|
|
9026
9028
|
continue;
|
|
9027
9029
|
}
|
|
9028
9030
|
const neighbors = graph.neighbors(nodeId);
|
|
@@ -9221,37 +9223,45 @@ function extractClusters(matrix, nodeIds) {
|
|
|
9221
9223
|
attractors.add(nodeId);
|
|
9222
9224
|
}
|
|
9223
9225
|
}
|
|
9224
|
-
|
|
9226
|
+
const attractorToCommunity = /* @__PURE__ */ new Map();
|
|
9225
9227
|
for (let j = 0; j < n; j++) {
|
|
9226
|
-
|
|
9228
|
+
let maxVal = 0;
|
|
9229
|
+
let attractorRow = -1;
|
|
9227
9230
|
for (let i = 0; i < n; i++) {
|
|
9228
9231
|
const matrixRow = matrix[i];
|
|
9229
9232
|
if (!matrixRow) {
|
|
9230
9233
|
continue;
|
|
9231
9234
|
}
|
|
9232
9235
|
const val = matrixRow[j];
|
|
9233
|
-
if (val !== void 0 && val >
|
|
9234
|
-
|
|
9235
|
-
|
|
9236
|
+
if (val !== void 0 && val > maxVal) {
|
|
9237
|
+
maxVal = val;
|
|
9238
|
+
attractorRow = i;
|
|
9236
9239
|
}
|
|
9237
9240
|
}
|
|
9238
|
-
if (
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
);
|
|
9245
|
-
|
|
9241
|
+
if (attractorRow >= 0) {
|
|
9242
|
+
let community = attractorToCommunity.get(attractorRow);
|
|
9243
|
+
if (!community) {
|
|
9244
|
+
community = [];
|
|
9245
|
+
attractorToCommunity.set(attractorRow, community);
|
|
9246
|
+
}
|
|
9247
|
+
community.push(j);
|
|
9248
|
+
nodeToCluster.set(j, attractorRow);
|
|
9246
9249
|
}
|
|
9247
9250
|
}
|
|
9248
|
-
for (
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
+
for (const [, memberIndices] of attractorToCommunity) {
|
|
9252
|
+
communities.push(
|
|
9253
|
+
memberIndices.map((idx) => {
|
|
9254
|
+
const nodeId = nodeIds[idx];
|
|
9255
|
+
return nodeId;
|
|
9256
|
+
}).filter((node) => node !== void 0)
|
|
9257
|
+
);
|
|
9258
|
+
}
|
|
9259
|
+
for (let j = 0; j < n; j++) {
|
|
9260
|
+
if (!nodeToCluster.has(j)) {
|
|
9261
|
+
const nodeId = nodeIds[j];
|
|
9251
9262
|
if (nodeId !== void 0) {
|
|
9252
9263
|
communities.push([nodeId]);
|
|
9253
9264
|
}
|
|
9254
|
-
nodeToCluster.set(i, clusterIndex++);
|
|
9255
9265
|
}
|
|
9256
9266
|
}
|
|
9257
9267
|
return { communities, attractors };
|