@graphty/algorithms 2.0.6 → 2.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/README.md +9 -11
- package/dist/algorithms.js +499 -30
- package/dist/algorithms.js.map +1 -1
- package/dist/algorithms.standalone.js +500 -31
- package/dist/algorithms.standalone.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +2 -2
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +1 -1
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/matching/isomorphism.js +3 -3
- package/dist/src/algorithms/matching/isomorphism.js.map +1 -1
- package/dist/src/algorithms/mst/prim.js +1 -1
- package/dist/src/algorithms/mst/prim.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.js +2 -2
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -1
- package/dist/src/algorithms/traversal/dfs.js +2 -2
- package/dist/src/algorithms/traversal/dfs.js.map +1 -1
- package/dist/src/clustering/spectral.js +2 -2
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexed/accelerator.d.ts +14 -2
- package/dist/src/indexed/accelerator.d.ts.map +1 -1
- package/dist/src/indexed/accelerator.js +8 -0
- package/dist/src/indexed/accelerator.js.map +1 -1
- package/dist/src/indexed/components.d.ts +8 -0
- package/dist/src/indexed/components.d.ts.map +1 -1
- package/dist/src/indexed/components.js +8 -1
- package/dist/src/indexed/components.js.map +1 -1
- package/dist/src/indexed/hits.d.ts +39 -0
- package/dist/src/indexed/hits.d.ts.map +1 -0
- package/dist/src/indexed/hits.js +95 -0
- package/dist/src/indexed/hits.js.map +1 -0
- package/dist/src/indexed/index.d.ts +5 -1
- package/dist/src/indexed/index.d.ts.map +1 -1
- package/dist/src/indexed/index.js +5 -1
- package/dist/src/indexed/index.js.map +1 -1
- package/dist/src/indexed/k-core.d.ts +32 -0
- package/dist/src/indexed/k-core.d.ts.map +1 -0
- package/dist/src/indexed/k-core.js +118 -0
- package/dist/src/indexed/k-core.js.map +1 -0
- package/dist/src/indexed/katz.d.ts +38 -0
- package/dist/src/indexed/katz.d.ts.map +1 -0
- package/dist/src/indexed/katz.js +61 -0
- package/dist/src/indexed/katz.js.map +1 -0
- package/dist/src/indexed/louvain.d.ts +33 -0
- package/dist/src/indexed/louvain.d.ts.map +1 -0
- package/dist/src/indexed/louvain.js +301 -0
- package/dist/src/indexed/louvain.js.map +1 -0
- package/package.json +6 -6
- package/src/algorithms/centrality/betweenness.ts +2 -2
- package/src/algorithms/community/girvan-newman.ts +1 -1
- package/src/algorithms/matching/isomorphism.ts +3 -3
- package/src/algorithms/mst/prim.ts +1 -1
- package/src/algorithms/shortest-path/bellman-ford.ts +3 -3
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +1 -1
- package/src/algorithms/shortest-path/dijkstra.ts +1 -1
- package/src/algorithms/traversal/bfs-unified.ts +2 -2
- package/src/algorithms/traversal/dfs.ts +2 -2
- package/src/clustering/spectral.ts +2 -2
- package/src/index.ts +10 -0
- package/src/indexed/accelerator.ts +26 -2
- package/src/indexed/components.ts +8 -1
- package/src/indexed/hits.ts +126 -0
- package/src/indexed/index.ts +5 -7
- package/src/indexed/k-core.ts +138 -0
- package/src/indexed/katz.ts +88 -0
- package/src/indexed/louvain.ts +345 -0
package/dist/algorithms.js
CHANGED
|
@@ -3282,7 +3282,7 @@ function breadthFirstSearchStandard(graph, startNode, options = {}) {
|
|
|
3282
3282
|
if (options.visitCallback) {
|
|
3283
3283
|
options.visitCallback(current.node, current.level);
|
|
3284
3284
|
}
|
|
3285
|
-
if (options.targetNode && current.node === options.targetNode) {
|
|
3285
|
+
if (options.targetNode !== void 0 && current.node === options.targetNode) {
|
|
3286
3286
|
break;
|
|
3287
3287
|
}
|
|
3288
3288
|
for (const neighbor of graph.neighbors(current.node)) {
|
|
@@ -3472,7 +3472,7 @@ function isBipartite(graph) {
|
|
|
3472
3472
|
visited.add(node.id);
|
|
3473
3473
|
while (queue.length > 0) {
|
|
3474
3474
|
const current = queue.shift();
|
|
3475
|
-
if (
|
|
3475
|
+
if (current === void 0) {
|
|
3476
3476
|
break;
|
|
3477
3477
|
}
|
|
3478
3478
|
const currentColor = color.get(current);
|
|
@@ -3526,7 +3526,7 @@ function dfsIterative(graph, startNode, visited, order, tree, options) {
|
|
|
3526
3526
|
if (options.visitCallback) {
|
|
3527
3527
|
options.visitCallback(current.node, current.depth);
|
|
3528
3528
|
}
|
|
3529
|
-
if (options.targetNode && current.node === options.targetNode) {
|
|
3529
|
+
if (options.targetNode !== void 0 && current.node === options.targetNode) {
|
|
3530
3530
|
break;
|
|
3531
3531
|
}
|
|
3532
3532
|
const neighbors = Array.from(graph.neighbors(current.node));
|
|
@@ -3547,7 +3547,7 @@ function dfsRecursive(graph, node, visited, order, tree, options, depth, parent
|
|
|
3547
3547
|
if (options.visitCallback) {
|
|
3548
3548
|
options.visitCallback(node, depth);
|
|
3549
3549
|
}
|
|
3550
|
-
if (options.targetNode && node === options.targetNode) {
|
|
3550
|
+
if (options.targetNode !== void 0 && node === options.targetNode) {
|
|
3551
3551
|
return;
|
|
3552
3552
|
}
|
|
3553
3553
|
}
|
|
@@ -3723,7 +3723,7 @@ function bellmanFord(graph, source, options = {}) {
|
|
|
3723
3723
|
distances.set(v, newDistance);
|
|
3724
3724
|
predecessors.set(v, u);
|
|
3725
3725
|
updated = true;
|
|
3726
|
-
if (options.target && v === options.target) {
|
|
3726
|
+
if (options.target !== void 0 && v === options.target) {
|
|
3727
3727
|
break;
|
|
3728
3728
|
}
|
|
3729
3729
|
}
|
|
@@ -4077,7 +4077,7 @@ class BidirectionalDijkstra {
|
|
|
4077
4077
|
return minDist;
|
|
4078
4078
|
}
|
|
4079
4079
|
reconstructPath() {
|
|
4080
|
-
if (
|
|
4080
|
+
if (this.meetingNode === null) {
|
|
4081
4081
|
return [];
|
|
4082
4082
|
}
|
|
4083
4083
|
const path = [];
|
|
@@ -4138,7 +4138,7 @@ function dijkstra$1(graph, source, options = {}) {
|
|
|
4138
4138
|
continue;
|
|
4139
4139
|
}
|
|
4140
4140
|
visited.add(currentNode);
|
|
4141
|
-
if (options.target && currentNode === options.target) {
|
|
4141
|
+
if (options.target !== void 0 && currentNode === options.target) {
|
|
4142
4142
|
break;
|
|
4143
4143
|
}
|
|
4144
4144
|
if (currentDistance === Infinity) {
|
|
@@ -4713,7 +4713,7 @@ function accumulateBetweenness(result, source, centrality, options) {
|
|
|
4713
4713
|
}
|
|
4714
4714
|
for (let i = stack.length - 1; i >= 0; i--) {
|
|
4715
4715
|
const w = stack[i];
|
|
4716
|
-
if (
|
|
4716
|
+
if (w === void 0) {
|
|
4717
4717
|
continue;
|
|
4718
4718
|
}
|
|
4719
4719
|
const wPreds = predecessors.get(w) ?? [];
|
|
@@ -4747,7 +4747,7 @@ function accumulateEdgeBetweenness(result, source, edgeCentrality, options) {
|
|
|
4747
4747
|
}
|
|
4748
4748
|
for (let i = stack.length - 1; i >= 0; i--) {
|
|
4749
4749
|
const w = stack[i];
|
|
4750
|
-
if (
|
|
4750
|
+
if (w === void 0) {
|
|
4751
4751
|
continue;
|
|
4752
4752
|
}
|
|
4753
4753
|
const wPreds = predecessors.get(w) ?? [];
|
|
@@ -5381,7 +5381,7 @@ function nodeEigenvectorCentrality(graph, nodeId, options = {}) {
|
|
|
5381
5381
|
const centrality = eigenvectorCentrality(graph, options);
|
|
5382
5382
|
return centrality[nodeId.toString()] ?? 0;
|
|
5383
5383
|
}
|
|
5384
|
-
function hits(graph, options = {}) {
|
|
5384
|
+
function hits$1(graph, options = {}) {
|
|
5385
5385
|
const { maxIterations = 100, tolerance = 1e-6, normalized = true } = options;
|
|
5386
5386
|
const hubs = {};
|
|
5387
5387
|
const authorities = {};
|
|
@@ -5498,14 +5498,14 @@ function nodeHITS(graph, nodeId, options = {}) {
|
|
|
5498
5498
|
if (!graph.hasNode(nodeId)) {
|
|
5499
5499
|
throw new Error(`Node ${String(nodeId)} not found in graph`);
|
|
5500
5500
|
}
|
|
5501
|
-
const result = hits(graph, options);
|
|
5501
|
+
const result = hits$1(graph, options);
|
|
5502
5502
|
const key = nodeId.toString();
|
|
5503
5503
|
return {
|
|
5504
5504
|
hub: result.hubs[key] ?? 0,
|
|
5505
5505
|
authority: result.authorities[key] ?? 0
|
|
5506
5506
|
};
|
|
5507
5507
|
}
|
|
5508
|
-
function katzCentrality(graph, options = {}) {
|
|
5508
|
+
function katzCentrality$1(graph, options = {}) {
|
|
5509
5509
|
const { alpha = 0.1, beta = 1, maxIterations = 100, tolerance = 1e-6, normalized = true } = options;
|
|
5510
5510
|
const centrality = {};
|
|
5511
5511
|
const nodes = Array.from(graph.nodes());
|
|
@@ -5566,7 +5566,7 @@ function nodeKatzCentrality(graph, nodeId, options = {}) {
|
|
|
5566
5566
|
if (!graph.hasNode(nodeId)) {
|
|
5567
5567
|
throw new Error(`Node ${String(nodeId)} not found in graph`);
|
|
5568
5568
|
}
|
|
5569
|
-
const centrality = katzCentrality(graph, options);
|
|
5569
|
+
const centrality = katzCentrality$1(graph, options);
|
|
5570
5570
|
return centrality[nodeId.toString()] ?? 0;
|
|
5571
5571
|
}
|
|
5572
5572
|
class SimpleDeltaPageRank {
|
|
@@ -6411,7 +6411,7 @@ function primMST(graph, startNode) {
|
|
|
6411
6411
|
};
|
|
6412
6412
|
}
|
|
6413
6413
|
const start = startNode ?? nodes[0]?.id;
|
|
6414
|
-
if (
|
|
6414
|
+
if (start === void 0) {
|
|
6415
6415
|
return {
|
|
6416
6416
|
edges: [],
|
|
6417
6417
|
totalWeight: 0
|
|
@@ -6579,7 +6579,7 @@ function findAllShortestPaths(graph, source) {
|
|
|
6579
6579
|
let queueIndex = 0;
|
|
6580
6580
|
while (queueIndex < queue.length) {
|
|
6581
6581
|
const current = queue[queueIndex++];
|
|
6582
|
-
if (
|
|
6582
|
+
if (current === void 0) {
|
|
6583
6583
|
continue;
|
|
6584
6584
|
}
|
|
6585
6585
|
if (visited.has(current)) {
|
|
@@ -7361,7 +7361,7 @@ class OptimizedLouvain {
|
|
|
7361
7361
|
for (let i = 0; i < membership.length; i++) {
|
|
7362
7362
|
membership[i] = community[membership[i]];
|
|
7363
7363
|
}
|
|
7364
|
-
level = aggregate(level, community, count);
|
|
7364
|
+
level = aggregate$1(level, community, count);
|
|
7365
7365
|
}
|
|
7366
7366
|
const groups = Array.from({ length: level.n }, () => []);
|
|
7367
7367
|
for (let i = 0; i < membership.length; i++) {
|
|
@@ -7544,7 +7544,7 @@ function buildCsr(n, counts, edges, self, degree) {
|
|
|
7544
7544
|
}
|
|
7545
7545
|
return { n, offsets, targets, weights, self, degree };
|
|
7546
7546
|
}
|
|
7547
|
-
function aggregate(level, community, count) {
|
|
7547
|
+
function aggregate$1(level, community, count) {
|
|
7548
7548
|
const self = new Float64Array(count);
|
|
7549
7549
|
const degree = new Float64Array(count);
|
|
7550
7550
|
const members = Array.from({ length: count }, () => []);
|
|
@@ -7652,7 +7652,7 @@ function calculateModularity$1(graph, communities, resolution = 1) {
|
|
|
7652
7652
|
}
|
|
7653
7653
|
return modularity;
|
|
7654
7654
|
}
|
|
7655
|
-
function louvain(graph, options = {}) {
|
|
7655
|
+
function louvain$1(graph, options = {}) {
|
|
7656
7656
|
const resolution = options.resolution ?? 1;
|
|
7657
7657
|
const maxIterations = options.maxIterations ?? 100;
|
|
7658
7658
|
const tolerance = options.tolerance ?? 1e-6;
|
|
@@ -9018,7 +9018,7 @@ function kCoreDecompositionImpl(graph) {
|
|
|
9018
9018
|
return { cores, coreness, maxCore };
|
|
9019
9019
|
}
|
|
9020
9020
|
function getKCore(graph, k) {
|
|
9021
|
-
const { coreness } = kCoreDecomposition(graph);
|
|
9021
|
+
const { coreness } = kCoreDecomposition$1(graph);
|
|
9022
9022
|
const kCore = /* @__PURE__ */ new Set();
|
|
9023
9023
|
for (const [node, core] of coreness) {
|
|
9024
9024
|
if (core >= k) {
|
|
@@ -9027,7 +9027,7 @@ function getKCore(graph, k) {
|
|
|
9027
9027
|
}
|
|
9028
9028
|
return kCore;
|
|
9029
9029
|
}
|
|
9030
|
-
function kCoreDecomposition(graph) {
|
|
9030
|
+
function kCoreDecomposition$1(graph) {
|
|
9031
9031
|
const adjacencySet = graphToAdjacencySet(graph);
|
|
9032
9032
|
return kCoreDecompositionImpl(adjacencySet);
|
|
9033
9033
|
}
|
|
@@ -9383,7 +9383,7 @@ function spectralClustering(graph, options) {
|
|
|
9383
9383
|
for (let i = 0; i < nodeIds.length; i++) {
|
|
9384
9384
|
const clusterId = kmeans.assignments[i] ?? 0;
|
|
9385
9385
|
const nodeId = nodeIds[i];
|
|
9386
|
-
if (
|
|
9386
|
+
if (nodeId === void 0) {
|
|
9387
9387
|
continue;
|
|
9388
9388
|
}
|
|
9389
9389
|
if (clusterId >= 0 && clusterId < k) {
|
|
@@ -9415,7 +9415,7 @@ function buildAdjacencyMatrix(graph, nodeIds) {
|
|
|
9415
9415
|
nodeIds.forEach((id, index2) => nodeToIndex.set(id, index2));
|
|
9416
9416
|
for (let i = 0; i < n; i++) {
|
|
9417
9417
|
const nodeId = nodeIds[i];
|
|
9418
|
-
if (
|
|
9418
|
+
if (nodeId === void 0) {
|
|
9419
9419
|
continue;
|
|
9420
9420
|
}
|
|
9421
9421
|
const neighbors = graph.neighbors(nodeId);
|
|
@@ -9955,7 +9955,7 @@ function getCandidatePairs(g1, g2, state, nodes1, nodes2) {
|
|
|
9955
9955
|
break;
|
|
9956
9956
|
}
|
|
9957
9957
|
}
|
|
9958
|
-
if (
|
|
9958
|
+
if (node1 === null) {
|
|
9959
9959
|
for (const [n] of state.in1) {
|
|
9960
9960
|
if (!state.core1.has(n)) {
|
|
9961
9961
|
node1 = n;
|
|
@@ -9963,7 +9963,7 @@ function getCandidatePairs(g1, g2, state, nodes1, nodes2) {
|
|
|
9963
9963
|
}
|
|
9964
9964
|
}
|
|
9965
9965
|
}
|
|
9966
|
-
if (
|
|
9966
|
+
if (node1 === null) {
|
|
9967
9967
|
for (const n of nodes1) {
|
|
9968
9968
|
if (!state.core1.has(n)) {
|
|
9969
9969
|
node1 = n;
|
|
@@ -9971,7 +9971,7 @@ function getCandidatePairs(g1, g2, state, nodes1, nodes2) {
|
|
|
9971
9971
|
}
|
|
9972
9972
|
}
|
|
9973
9973
|
}
|
|
9974
|
-
if (
|
|
9974
|
+
if (node1 === null) {
|
|
9975
9975
|
return pairs;
|
|
9976
9976
|
}
|
|
9977
9977
|
for (const node2 of nodes2) {
|
|
@@ -11708,6 +11708,467 @@ function dijkstra(g, source, options = {}) {
|
|
|
11708
11708
|
pathEdges: (target) => walkPredEdges(g, predArc, source, target)
|
|
11709
11709
|
};
|
|
11710
11710
|
}
|
|
11711
|
+
function l2Normalize(v) {
|
|
11712
|
+
let sum = 0;
|
|
11713
|
+
for (let i = 0; i < v.length; i++) {
|
|
11714
|
+
sum += v[i] * v[i];
|
|
11715
|
+
}
|
|
11716
|
+
const norm = Math.sqrt(sum);
|
|
11717
|
+
if (norm > 0) {
|
|
11718
|
+
for (let i = 0; i < v.length; i++) {
|
|
11719
|
+
v[i] /= norm;
|
|
11720
|
+
}
|
|
11721
|
+
}
|
|
11722
|
+
}
|
|
11723
|
+
function maxNormalize(v) {
|
|
11724
|
+
let max = 0;
|
|
11725
|
+
for (let i = 0; i < v.length; i++) {
|
|
11726
|
+
if (v[i] > max) {
|
|
11727
|
+
max = v[i];
|
|
11728
|
+
}
|
|
11729
|
+
}
|
|
11730
|
+
if (max > 0) {
|
|
11731
|
+
for (let i = 0; i < v.length; i++) {
|
|
11732
|
+
v[i] /= max;
|
|
11733
|
+
}
|
|
11734
|
+
}
|
|
11735
|
+
}
|
|
11736
|
+
function hits(s, o = {}) {
|
|
11737
|
+
const n = s.nodeCount;
|
|
11738
|
+
const maxIter = o.maxIterations ?? 100;
|
|
11739
|
+
const tol = o.tolerance ?? 1e-6;
|
|
11740
|
+
const rev = s.reverse();
|
|
11741
|
+
const fwdW = o.weighted === true ? s.weights : null;
|
|
11742
|
+
const revW = o.weighted === true ? rev.weights : null;
|
|
11743
|
+
let hubs = new Float64Array(n).fill(n === 0 ? 0 : 1 / Math.sqrt(n));
|
|
11744
|
+
let authorities = new Float64Array(n).fill(n === 0 ? 0 : 1 / Math.sqrt(n));
|
|
11745
|
+
let nextHubs = new Float64Array(n);
|
|
11746
|
+
let nextAuthorities = new Float64Array(n);
|
|
11747
|
+
let it = 0;
|
|
11748
|
+
let converged = false;
|
|
11749
|
+
for (; it < maxIter && !converged; it++) {
|
|
11750
|
+
for (let v = 0; v < n; v++) {
|
|
11751
|
+
let auth = 0;
|
|
11752
|
+
const inEnd = rev.rowPtr[v + 1];
|
|
11753
|
+
for (let a = rev.rowPtr[v]; a < inEnd; a++) {
|
|
11754
|
+
auth += hubs[rev.colIdx[a]] * (revW === null ? 1 : revW[a]);
|
|
11755
|
+
}
|
|
11756
|
+
nextAuthorities[v] = auth;
|
|
11757
|
+
let hub = 0;
|
|
11758
|
+
const outEnd = s.rowPtr[v + 1];
|
|
11759
|
+
for (let a = s.rowPtr[v]; a < outEnd; a++) {
|
|
11760
|
+
hub += authorities[s.colIdx[a]] * (fwdW === null ? 1 : fwdW[a]);
|
|
11761
|
+
}
|
|
11762
|
+
nextHubs[v] = hub;
|
|
11763
|
+
}
|
|
11764
|
+
l2Normalize(nextAuthorities);
|
|
11765
|
+
l2Normalize(nextHubs);
|
|
11766
|
+
let maxDiff = 0;
|
|
11767
|
+
for (let v = 0; v < n; v++) {
|
|
11768
|
+
const dh = Math.abs(nextHubs[v] - hubs[v]);
|
|
11769
|
+
if (dh > maxDiff) {
|
|
11770
|
+
maxDiff = dh;
|
|
11771
|
+
}
|
|
11772
|
+
const da = Math.abs(nextAuthorities[v] - authorities[v]);
|
|
11773
|
+
if (da > maxDiff) {
|
|
11774
|
+
maxDiff = da;
|
|
11775
|
+
}
|
|
11776
|
+
}
|
|
11777
|
+
[hubs, nextHubs] = [nextHubs, hubs];
|
|
11778
|
+
[authorities, nextAuthorities] = [nextAuthorities, authorities];
|
|
11779
|
+
converged = maxDiff < tol;
|
|
11780
|
+
}
|
|
11781
|
+
if (o.normalized === false) {
|
|
11782
|
+
maxNormalize(hubs);
|
|
11783
|
+
maxNormalize(authorities);
|
|
11784
|
+
}
|
|
11785
|
+
return { hubs, authorities, iterations: it, converged };
|
|
11786
|
+
}
|
|
11787
|
+
function kCoreDecomposition(s) {
|
|
11788
|
+
if (s.directed) {
|
|
11789
|
+
throw new Error("k-core requires an undirected graph. Pass s.toUndirected().snapshot.");
|
|
11790
|
+
}
|
|
11791
|
+
const n = s.nodeCount;
|
|
11792
|
+
const { rowPtr, colIdx } = s;
|
|
11793
|
+
const degree = new Uint32Array(n);
|
|
11794
|
+
let maxDegree = 0;
|
|
11795
|
+
for (let u = 0; u < n; u++) {
|
|
11796
|
+
let d = 0;
|
|
11797
|
+
let last = -1;
|
|
11798
|
+
const end = rowPtr[u + 1];
|
|
11799
|
+
for (let a = rowPtr[u]; a < end; a++) {
|
|
11800
|
+
const v = colIdx[a];
|
|
11801
|
+
if (v !== u && v !== last) {
|
|
11802
|
+
d++;
|
|
11803
|
+
}
|
|
11804
|
+
last = v;
|
|
11805
|
+
}
|
|
11806
|
+
degree[u] = d;
|
|
11807
|
+
if (d > maxDegree) {
|
|
11808
|
+
maxDegree = d;
|
|
11809
|
+
}
|
|
11810
|
+
}
|
|
11811
|
+
const bin = new Uint32Array(maxDegree + 1);
|
|
11812
|
+
for (let u = 0; u < n; u++) {
|
|
11813
|
+
bin[degree[u]]++;
|
|
11814
|
+
}
|
|
11815
|
+
let start = 0;
|
|
11816
|
+
for (let d = 0; d <= maxDegree; d++) {
|
|
11817
|
+
const count = bin[d];
|
|
11818
|
+
bin[d] = start;
|
|
11819
|
+
start += count;
|
|
11820
|
+
}
|
|
11821
|
+
const vert = new Uint32Array(n);
|
|
11822
|
+
const pos = new Uint32Array(n);
|
|
11823
|
+
for (let u = 0; u < n; u++) {
|
|
11824
|
+
pos[u] = bin[degree[u]];
|
|
11825
|
+
vert[pos[u]] = u;
|
|
11826
|
+
bin[degree[u]]++;
|
|
11827
|
+
}
|
|
11828
|
+
for (let d = maxDegree; d > 0; d--) {
|
|
11829
|
+
bin[d] = bin[d - 1];
|
|
11830
|
+
}
|
|
11831
|
+
bin[0] = 0;
|
|
11832
|
+
let maxCore = 0;
|
|
11833
|
+
for (let i = 0; i < n; i++) {
|
|
11834
|
+
const v = vert[i];
|
|
11835
|
+
const dv = degree[v];
|
|
11836
|
+
if (dv > maxCore) {
|
|
11837
|
+
maxCore = dv;
|
|
11838
|
+
}
|
|
11839
|
+
const end = rowPtr[v + 1];
|
|
11840
|
+
let last = -1;
|
|
11841
|
+
for (let a = rowPtr[v]; a < end; a++) {
|
|
11842
|
+
const u = colIdx[a];
|
|
11843
|
+
const skip = u === v || u === last;
|
|
11844
|
+
last = u;
|
|
11845
|
+
if (skip) {
|
|
11846
|
+
continue;
|
|
11847
|
+
}
|
|
11848
|
+
const du = degree[u];
|
|
11849
|
+
if (du > dv) {
|
|
11850
|
+
const pu = pos[u];
|
|
11851
|
+
const pw = bin[du];
|
|
11852
|
+
const w = vert[pw];
|
|
11853
|
+
if (u !== w) {
|
|
11854
|
+
vert[pu] = w;
|
|
11855
|
+
vert[pw] = u;
|
|
11856
|
+
pos[u] = pw;
|
|
11857
|
+
pos[w] = pu;
|
|
11858
|
+
}
|
|
11859
|
+
bin[du]++;
|
|
11860
|
+
degree[u] = du - 1;
|
|
11861
|
+
}
|
|
11862
|
+
}
|
|
11863
|
+
}
|
|
11864
|
+
let cached = null;
|
|
11865
|
+
return {
|
|
11866
|
+
coreness: degree,
|
|
11867
|
+
maxCore,
|
|
11868
|
+
cores() {
|
|
11869
|
+
if (cached === null) {
|
|
11870
|
+
const sizes = new Uint32Array(maxCore + 1);
|
|
11871
|
+
for (let u = 0; u < n; u++) {
|
|
11872
|
+
sizes[degree[u]]++;
|
|
11873
|
+
}
|
|
11874
|
+
const out = [];
|
|
11875
|
+
for (let k = 0; k <= maxCore; k++) {
|
|
11876
|
+
out.push(new Uint32Array(sizes[k]));
|
|
11877
|
+
}
|
|
11878
|
+
const fill = new Uint32Array(maxCore + 1);
|
|
11879
|
+
for (let u = 0; u < n; u++) {
|
|
11880
|
+
const k = degree[u];
|
|
11881
|
+
out[k][fill[k]++] = u;
|
|
11882
|
+
}
|
|
11883
|
+
cached = out;
|
|
11884
|
+
}
|
|
11885
|
+
return cached;
|
|
11886
|
+
}
|
|
11887
|
+
};
|
|
11888
|
+
}
|
|
11889
|
+
function katzCentrality(s, o = {}) {
|
|
11890
|
+
const n = s.nodeCount;
|
|
11891
|
+
const alpha = o.alpha ?? 0.1;
|
|
11892
|
+
const beta = o.beta ?? 1;
|
|
11893
|
+
const maxIter = o.maxIterations ?? 100;
|
|
11894
|
+
const tol = o.tolerance ?? 1e-6;
|
|
11895
|
+
const rev = s.reverse();
|
|
11896
|
+
const weights = o.weighted === true ? rev.weights : null;
|
|
11897
|
+
let cur = new Float64Array(n).fill(beta);
|
|
11898
|
+
let next = new Float64Array(n);
|
|
11899
|
+
let it = 0;
|
|
11900
|
+
let converged = false;
|
|
11901
|
+
for (; it < maxIter && !converged; it++) {
|
|
11902
|
+
let maxDiff = 0;
|
|
11903
|
+
for (let v = 0; v < n; v++) {
|
|
11904
|
+
let sum = 0;
|
|
11905
|
+
const end = rev.rowPtr[v + 1];
|
|
11906
|
+
for (let a = rev.rowPtr[v]; a < end; a++) {
|
|
11907
|
+
sum += cur[rev.colIdx[a]] * (weights === null ? 1 : weights[a]);
|
|
11908
|
+
}
|
|
11909
|
+
next[v] = alpha * sum + beta;
|
|
11910
|
+
const diff = Math.abs(next[v] - cur[v]);
|
|
11911
|
+
if (diff > maxDiff) {
|
|
11912
|
+
maxDiff = diff;
|
|
11913
|
+
}
|
|
11914
|
+
}
|
|
11915
|
+
[cur, next] = [next, cur];
|
|
11916
|
+
converged = maxDiff < tol;
|
|
11917
|
+
}
|
|
11918
|
+
if (o.normalized !== false) {
|
|
11919
|
+
let min = Infinity;
|
|
11920
|
+
let max = -Infinity;
|
|
11921
|
+
for (let v = 0; v < n; v++) {
|
|
11922
|
+
if (cur[v] < min) {
|
|
11923
|
+
min = cur[v];
|
|
11924
|
+
}
|
|
11925
|
+
if (cur[v] > max) {
|
|
11926
|
+
max = cur[v];
|
|
11927
|
+
}
|
|
11928
|
+
}
|
|
11929
|
+
const range = max - min;
|
|
11930
|
+
if (range > 0) {
|
|
11931
|
+
for (let v = 0; v < n; v++) {
|
|
11932
|
+
cur[v] = (cur[v] - min) / range;
|
|
11933
|
+
}
|
|
11934
|
+
}
|
|
11935
|
+
}
|
|
11936
|
+
return { scores: cur, iterations: it, converged };
|
|
11937
|
+
}
|
|
11938
|
+
function buildLevel0(s) {
|
|
11939
|
+
const n = s.nodeCount;
|
|
11940
|
+
const rowPtr = new Uint32Array(n + 1);
|
|
11941
|
+
for (let u = 0; u < n; u++) {
|
|
11942
|
+
let kept = 0;
|
|
11943
|
+
const end = s.rowPtr[u + 1];
|
|
11944
|
+
for (let a = s.rowPtr[u]; a < end; a++) {
|
|
11945
|
+
if (s.colIdx[a] !== u) {
|
|
11946
|
+
kept++;
|
|
11947
|
+
}
|
|
11948
|
+
}
|
|
11949
|
+
rowPtr[u + 1] = rowPtr[u] + kept;
|
|
11950
|
+
}
|
|
11951
|
+
const arcs = rowPtr[n];
|
|
11952
|
+
const colIdx = new Uint32Array(arcs);
|
|
11953
|
+
const w = new Float64Array(arcs);
|
|
11954
|
+
const loop = new Float64Array(n);
|
|
11955
|
+
const deg = new Float64Array(n);
|
|
11956
|
+
let k = 0;
|
|
11957
|
+
for (let u = 0; u < n; u++) {
|
|
11958
|
+
let rowWeight = 0;
|
|
11959
|
+
const end = s.rowPtr[u + 1];
|
|
11960
|
+
for (let a = s.rowPtr[u]; a < end; a++) {
|
|
11961
|
+
const v = s.colIdx[a];
|
|
11962
|
+
const weight = s.weights === null ? 1 : s.weights[a];
|
|
11963
|
+
if (v === u) {
|
|
11964
|
+
loop[u] += weight;
|
|
11965
|
+
} else {
|
|
11966
|
+
colIdx[k] = v;
|
|
11967
|
+
w[k] = weight;
|
|
11968
|
+
k++;
|
|
11969
|
+
rowWeight += weight;
|
|
11970
|
+
}
|
|
11971
|
+
}
|
|
11972
|
+
deg[u] = rowWeight + 2 * loop[u];
|
|
11973
|
+
}
|
|
11974
|
+
return { n, rowPtr, colIdx, w, loop, deg };
|
|
11975
|
+
}
|
|
11976
|
+
function modularityOf(level, comm, count, resolution, m2) {
|
|
11977
|
+
const inside = new Float64Array(count);
|
|
11978
|
+
const tot = new Float64Array(count);
|
|
11979
|
+
for (let u = 0; u < level.n; u++) {
|
|
11980
|
+
const c = comm[u];
|
|
11981
|
+
tot[c] += level.deg[u];
|
|
11982
|
+
inside[c] += 2 * level.loop[u];
|
|
11983
|
+
const end = level.rowPtr[u + 1];
|
|
11984
|
+
for (let a = level.rowPtr[u]; a < end; a++) {
|
|
11985
|
+
if (comm[level.colIdx[a]] === c) {
|
|
11986
|
+
inside[c] += level.w[a];
|
|
11987
|
+
}
|
|
11988
|
+
}
|
|
11989
|
+
}
|
|
11990
|
+
let q = 0;
|
|
11991
|
+
for (let c = 0; c < count; c++) {
|
|
11992
|
+
const share = tot[c] / m2;
|
|
11993
|
+
q += inside[c] / m2 - resolution * share * share;
|
|
11994
|
+
}
|
|
11995
|
+
return q;
|
|
11996
|
+
}
|
|
11997
|
+
function localMove(level, comm, resolution, m2, maxVisitsPerNode) {
|
|
11998
|
+
const { n } = level;
|
|
11999
|
+
const tot = new Float64Array(n);
|
|
12000
|
+
for (let u = 0; u < n; u++) {
|
|
12001
|
+
comm[u] = u;
|
|
12002
|
+
tot[u] = level.deg[u];
|
|
12003
|
+
}
|
|
12004
|
+
const acc = new Float64Array(n);
|
|
12005
|
+
const stamp = new Int32Array(n).fill(-1);
|
|
12006
|
+
const touched = new Uint32Array(n);
|
|
12007
|
+
const capacity = n + 1;
|
|
12008
|
+
const queue = new Uint32Array(capacity);
|
|
12009
|
+
const queued = new Uint8Array(n);
|
|
12010
|
+
let head = 0;
|
|
12011
|
+
let tail = n;
|
|
12012
|
+
for (let u = 0; u < n; u++) {
|
|
12013
|
+
queue[u] = u;
|
|
12014
|
+
queued[u] = 1;
|
|
12015
|
+
}
|
|
12016
|
+
let mark = 0;
|
|
12017
|
+
let visits = 0;
|
|
12018
|
+
const maxVisits = maxVisitsPerNode * n;
|
|
12019
|
+
let movedAny = false;
|
|
12020
|
+
while (head !== tail && visits < maxVisits) {
|
|
12021
|
+
const u = queue[head];
|
|
12022
|
+
head = head + 1 === capacity ? 0 : head + 1;
|
|
12023
|
+
queued[u] = 0;
|
|
12024
|
+
visits++;
|
|
12025
|
+
const cu = comm[u];
|
|
12026
|
+
const ku = level.deg[u];
|
|
12027
|
+
tot[cu] -= ku;
|
|
12028
|
+
mark++;
|
|
12029
|
+
let cnt = 0;
|
|
12030
|
+
const end = level.rowPtr[u + 1];
|
|
12031
|
+
for (let a = level.rowPtr[u]; a < end; a++) {
|
|
12032
|
+
const c = comm[level.colIdx[a]];
|
|
12033
|
+
if (stamp[c] !== mark) {
|
|
12034
|
+
stamp[c] = mark;
|
|
12035
|
+
acc[c] = 0;
|
|
12036
|
+
touched[cnt++] = c;
|
|
12037
|
+
}
|
|
12038
|
+
acc[c] += level.w[a];
|
|
12039
|
+
}
|
|
12040
|
+
let best = cu;
|
|
12041
|
+
let bestGain = (stamp[cu] === mark ? acc[cu] : 0) - resolution * ku * tot[cu] / m2;
|
|
12042
|
+
for (let i = 0; i < cnt; i++) {
|
|
12043
|
+
const c = touched[i];
|
|
12044
|
+
if (c === cu) {
|
|
12045
|
+
continue;
|
|
12046
|
+
}
|
|
12047
|
+
const gain = acc[c] - resolution * ku * tot[c] / m2;
|
|
12048
|
+
if (gain > bestGain) {
|
|
12049
|
+
bestGain = gain;
|
|
12050
|
+
best = c;
|
|
12051
|
+
}
|
|
12052
|
+
}
|
|
12053
|
+
tot[best] += ku;
|
|
12054
|
+
if (best !== cu) {
|
|
12055
|
+
comm[u] = best;
|
|
12056
|
+
movedAny = true;
|
|
12057
|
+
for (let a = level.rowPtr[u]; a < end; a++) {
|
|
12058
|
+
const v = level.colIdx[a];
|
|
12059
|
+
if (queued[v] === 0 && comm[v] !== best) {
|
|
12060
|
+
queued[v] = 1;
|
|
12061
|
+
queue[tail] = v;
|
|
12062
|
+
tail = tail + 1 === capacity ? 0 : tail + 1;
|
|
12063
|
+
}
|
|
12064
|
+
}
|
|
12065
|
+
}
|
|
12066
|
+
}
|
|
12067
|
+
return movedAny;
|
|
12068
|
+
}
|
|
12069
|
+
function aggregate(level, comm, count) {
|
|
12070
|
+
const start = new Uint32Array(count + 1);
|
|
12071
|
+
for (let u = 0; u < level.n; u++) {
|
|
12072
|
+
start[comm[u] + 1]++;
|
|
12073
|
+
}
|
|
12074
|
+
for (let c = 0; c < count; c++) {
|
|
12075
|
+
start[c + 1] += start[c];
|
|
12076
|
+
}
|
|
12077
|
+
const members = new Uint32Array(level.n);
|
|
12078
|
+
const fill = start.slice(0, count);
|
|
12079
|
+
for (let u = 0; u < level.n; u++) {
|
|
12080
|
+
members[fill[comm[u]]++] = u;
|
|
12081
|
+
}
|
|
12082
|
+
const rowPtr = new Uint32Array(count + 1);
|
|
12083
|
+
const colIdx = new Uint32Array(level.colIdx.length);
|
|
12084
|
+
const w = new Float64Array(level.colIdx.length);
|
|
12085
|
+
const loop = new Float64Array(count);
|
|
12086
|
+
const deg = new Float64Array(count);
|
|
12087
|
+
const acc = new Float64Array(count);
|
|
12088
|
+
const stamp = new Int32Array(count).fill(-1);
|
|
12089
|
+
const touched = new Uint32Array(count);
|
|
12090
|
+
let k = 0;
|
|
12091
|
+
for (let c = 0; c < count; c++) {
|
|
12092
|
+
rowPtr[c] = k;
|
|
12093
|
+
let internalArcs = 0;
|
|
12094
|
+
let cnt = 0;
|
|
12095
|
+
for (let i = start[c]; i < start[c + 1]; i++) {
|
|
12096
|
+
const u = members[i];
|
|
12097
|
+
loop[c] += level.loop[u];
|
|
12098
|
+
const end = level.rowPtr[u + 1];
|
|
12099
|
+
for (let a = level.rowPtr[u]; a < end; a++) {
|
|
12100
|
+
const other = comm[level.colIdx[a]];
|
|
12101
|
+
if (other === c) {
|
|
12102
|
+
internalArcs += level.w[a];
|
|
12103
|
+
continue;
|
|
12104
|
+
}
|
|
12105
|
+
if (stamp[other] !== c) {
|
|
12106
|
+
stamp[other] = c;
|
|
12107
|
+
acc[other] = 0;
|
|
12108
|
+
touched[cnt++] = other;
|
|
12109
|
+
}
|
|
12110
|
+
acc[other] += level.w[a];
|
|
12111
|
+
}
|
|
12112
|
+
}
|
|
12113
|
+
loop[c] += internalArcs / 2;
|
|
12114
|
+
let rowWeight = 0;
|
|
12115
|
+
for (let i = 0; i < cnt; i++) {
|
|
12116
|
+
const other = touched[i];
|
|
12117
|
+
colIdx[k] = other;
|
|
12118
|
+
w[k] = acc[other];
|
|
12119
|
+
rowWeight += acc[other];
|
|
12120
|
+
k++;
|
|
12121
|
+
}
|
|
12122
|
+
deg[c] = rowWeight + 2 * loop[c];
|
|
12123
|
+
}
|
|
12124
|
+
rowPtr[count] = k;
|
|
12125
|
+
return { n: count, rowPtr, colIdx: colIdx.subarray(0, k), w: w.subarray(0, k), loop, deg };
|
|
12126
|
+
}
|
|
12127
|
+
function louvain(s, o = {}) {
|
|
12128
|
+
if (s.directed) {
|
|
12129
|
+
throw new Error("Louvain requires an undirected graph. Pass s.toUndirected().snapshot.");
|
|
12130
|
+
}
|
|
12131
|
+
const resolution = o.resolution ?? 1;
|
|
12132
|
+
const maxIterations = o.maxIterations ?? 100;
|
|
12133
|
+
const tolerance = o.tolerance ?? 1e-6;
|
|
12134
|
+
const n0 = s.nodeCount;
|
|
12135
|
+
const labels = new Uint32Array(n0);
|
|
12136
|
+
for (let u = 0; u < n0; u++) {
|
|
12137
|
+
labels[u] = u;
|
|
12138
|
+
}
|
|
12139
|
+
let level = buildLevel0(s);
|
|
12140
|
+
let m2 = 0;
|
|
12141
|
+
for (let u = 0; u < n0; u++) {
|
|
12142
|
+
m2 += level.deg[u];
|
|
12143
|
+
}
|
|
12144
|
+
if (m2 === 0) {
|
|
12145
|
+
return { ...withGroups(labels, n0), modularity: 0, iterations: 0 };
|
|
12146
|
+
}
|
|
12147
|
+
let q = modularityOf(level, labels, n0, resolution, m2);
|
|
12148
|
+
let iterations = 0;
|
|
12149
|
+
for (let iteration = 0; iteration < maxIterations; iteration++) {
|
|
12150
|
+
const comm = new Uint32Array(level.n);
|
|
12151
|
+
if (!localMove(level, comm, resolution, m2, maxIterations)) {
|
|
12152
|
+
break;
|
|
12153
|
+
}
|
|
12154
|
+
const dense = renumberPartition(comm);
|
|
12155
|
+
const { count } = dense;
|
|
12156
|
+
const packed = dense.labels;
|
|
12157
|
+
const newQ = modularityOf(level, packed, count, resolution, m2);
|
|
12158
|
+
for (let u = 0; u < n0; u++) {
|
|
12159
|
+
labels[u] = packed[labels[u]];
|
|
12160
|
+
}
|
|
12161
|
+
iterations = iteration + 1;
|
|
12162
|
+
const gain = newQ - q;
|
|
12163
|
+
q = newQ;
|
|
12164
|
+
if (gain < tolerance || count === level.n) {
|
|
12165
|
+
break;
|
|
12166
|
+
}
|
|
12167
|
+
level = aggregate(level, packed, count);
|
|
12168
|
+
}
|
|
12169
|
+
const final = renumberPartition(labels);
|
|
12170
|
+
return { ...withGroups(final.labels, final.count), modularity: q, iterations };
|
|
12171
|
+
}
|
|
11711
12172
|
function kruskalMST(s, o = {}) {
|
|
11712
12173
|
const el = s.edgeList();
|
|
11713
12174
|
const m = s.edgeCount;
|
|
@@ -11791,7 +12252,11 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
11791
12252
|
commonNeighborsScore,
|
|
11792
12253
|
connectedComponents,
|
|
11793
12254
|
dijkstra,
|
|
12255
|
+
hits,
|
|
12256
|
+
kCoreDecomposition,
|
|
12257
|
+
katzCentrality,
|
|
11794
12258
|
kruskalMST,
|
|
12259
|
+
louvain,
|
|
11795
12260
|
pageRank,
|
|
11796
12261
|
walkPredArcs,
|
|
11797
12262
|
walkPredEdges,
|
|
@@ -11837,7 +12302,11 @@ function accelerated(acc) {
|
|
|
11837
12302
|
breadthFirstSearch: (s, source, options) => acc?.breadthFirstSearch !== void 0 ? acc.breadthFirstSearch(s, source, options) : Promise.resolve(breadthFirstSearch(s, source, options)),
|
|
11838
12303
|
connectedComponents: (s) => acc?.connectedComponents !== void 0 ? acc.connectedComponents(s) : Promise.resolve(connectedComponents(s)),
|
|
11839
12304
|
weaklyConnectedComponents: (s) => acc?.weaklyConnectedComponents !== void 0 ? acc.weaklyConnectedComponents(s) : Promise.resolve(weaklyConnectedComponents(s)),
|
|
11840
|
-
minimumSpanningTree: (s, options) => acc?.minimumSpanningTree !== void 0 ? acc.minimumSpanningTree(s, options) : Promise.resolve(kruskalMST(s, options))
|
|
12305
|
+
minimumSpanningTree: (s, options) => acc?.minimumSpanningTree !== void 0 ? acc.minimumSpanningTree(s, options) : Promise.resolve(kruskalMST(s, options)),
|
|
12306
|
+
kCoreDecomposition: (s) => acc?.kCoreDecomposition !== void 0 ? acc.kCoreDecomposition(s) : Promise.resolve(kCoreDecomposition(s)),
|
|
12307
|
+
katzCentrality: (s, options) => acc?.katzCentrality !== void 0 ? acc.katzCentrality(s, options) : Promise.resolve(katzCentrality(s, options)),
|
|
12308
|
+
hits: (s, options) => acc?.hits !== void 0 ? acc.hits(s, options) : Promise.resolve(hits(s, options)),
|
|
12309
|
+
louvain: (s, options) => acc?.louvain !== void 0 ? acc.louvain(s, options) : Promise.resolve(louvain(s, options))
|
|
11841
12310
|
};
|
|
11842
12311
|
}
|
|
11843
12312
|
export {
|
|
@@ -11903,7 +12372,7 @@ export {
|
|
|
11903
12372
|
hasNegativeCycle,
|
|
11904
12373
|
heuristics,
|
|
11905
12374
|
hierarchicalClustering,
|
|
11906
|
-
hits,
|
|
12375
|
+
hits$1 as hits,
|
|
11907
12376
|
index as indexed,
|
|
11908
12377
|
isBipartite,
|
|
11909
12378
|
isCSRGraph,
|
|
@@ -11911,16 +12380,16 @@ export {
|
|
|
11911
12380
|
isGraphIsomorphic,
|
|
11912
12381
|
isStronglyConnected,
|
|
11913
12382
|
isWeaklyConnected,
|
|
11914
|
-
kCoreDecomposition,
|
|
12383
|
+
kCoreDecomposition$1 as kCoreDecomposition,
|
|
11915
12384
|
kargerMinCut,
|
|
11916
|
-
katzCentrality,
|
|
12385
|
+
katzCentrality$1 as katzCentrality,
|
|
11917
12386
|
kruskalMST$1 as kruskalMST,
|
|
11918
12387
|
labelPropagation,
|
|
11919
12388
|
labelPropagationAsync,
|
|
11920
12389
|
labelPropagationSemiSupervised,
|
|
11921
12390
|
largestConnectedComponent,
|
|
11922
12391
|
leiden,
|
|
11923
|
-
louvain,
|
|
12392
|
+
louvain$1 as louvain,
|
|
11924
12393
|
markovClustering,
|
|
11925
12394
|
maximumBipartiteMatching,
|
|
11926
12395
|
minSTCut,
|