graphwise 1.1.1 → 1.2.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 (133) hide show
  1. package/dist/expansion/frontier-balanced.d.ts +12 -0
  2. package/dist/expansion/frontier-balanced.d.ts.map +1 -0
  3. package/dist/expansion/frontier-balanced.unit.test.d.ts +2 -0
  4. package/dist/expansion/frontier-balanced.unit.test.d.ts.map +1 -0
  5. package/dist/expansion/index.d.ts +12 -13
  6. package/dist/expansion/index.d.ts.map +1 -1
  7. package/dist/expansion/random-priority.d.ts +20 -0
  8. package/dist/expansion/random-priority.d.ts.map +1 -0
  9. package/dist/expansion/random-priority.unit.test.d.ts +2 -0
  10. package/dist/expansion/random-priority.unit.test.d.ts.map +1 -0
  11. package/dist/expansion/standard-bfs.d.ts +12 -0
  12. package/dist/expansion/standard-bfs.d.ts.map +1 -0
  13. package/dist/expansion/standard-bfs.unit.test.d.ts +2 -0
  14. package/dist/expansion/standard-bfs.unit.test.d.ts.map +1 -0
  15. package/dist/extraction/index.d.ts +6 -6
  16. package/dist/extraction/index.d.ts.map +1 -1
  17. package/dist/extraction/motif.d.ts.map +1 -1
  18. package/dist/gpu/context.d.ts.map +1 -1
  19. package/dist/gpu/csr.d.ts.map +1 -1
  20. package/dist/gpu/index.cjs +410 -5
  21. package/dist/gpu/index.cjs.map +1 -0
  22. package/dist/gpu/index.d.ts +4 -5
  23. package/dist/gpu/index.d.ts.map +1 -1
  24. package/dist/gpu/index.js +400 -2
  25. package/dist/gpu/index.js.map +1 -0
  26. package/dist/graph/index.cjs +222 -2
  27. package/dist/graph/index.cjs.map +1 -0
  28. package/dist/graph/index.d.ts +3 -3
  29. package/dist/graph/index.d.ts.map +1 -1
  30. package/dist/graph/index.js +221 -1
  31. package/dist/graph/index.js.map +1 -0
  32. package/dist/index/index.cjs +902 -10
  33. package/dist/index/index.cjs.map +1 -1
  34. package/dist/index/index.js +880 -10
  35. package/dist/index/index.js.map +1 -1
  36. package/dist/{kmeans-B0HEOU6k.cjs → kmeans-87ExSUNZ.js} +27 -13
  37. package/dist/{kmeans-DgbsOznU.js.map → kmeans-87ExSUNZ.js.map} +1 -1
  38. package/dist/{kmeans-DgbsOznU.js → kmeans-BIgSyGKu.cjs} +44 -2
  39. package/dist/{kmeans-B0HEOU6k.cjs.map → kmeans-BIgSyGKu.cjs.map} +1 -1
  40. package/dist/ranking/baselines/betweenness.d.ts +13 -0
  41. package/dist/ranking/baselines/betweenness.d.ts.map +1 -0
  42. package/dist/ranking/baselines/betweenness.unit.test.d.ts +2 -0
  43. package/dist/ranking/baselines/betweenness.unit.test.d.ts.map +1 -0
  44. package/dist/ranking/baselines/communicability.d.ts +13 -0
  45. package/dist/ranking/baselines/communicability.d.ts.map +1 -0
  46. package/dist/ranking/baselines/communicability.unit.test.d.ts +2 -0
  47. package/dist/ranking/baselines/communicability.unit.test.d.ts.map +1 -0
  48. package/dist/ranking/baselines/degree-sum.d.ts +13 -0
  49. package/dist/ranking/baselines/degree-sum.d.ts.map +1 -0
  50. package/dist/ranking/baselines/degree-sum.unit.test.d.ts +2 -0
  51. package/dist/ranking/baselines/degree-sum.unit.test.d.ts.map +1 -0
  52. package/dist/ranking/baselines/index.d.ts +20 -0
  53. package/dist/ranking/baselines/index.d.ts.map +1 -0
  54. package/dist/ranking/baselines/jaccard-arithmetic.d.ts +13 -0
  55. package/dist/ranking/baselines/jaccard-arithmetic.d.ts.map +1 -0
  56. package/dist/ranking/baselines/jaccard-arithmetic.unit.test.d.ts +2 -0
  57. package/dist/ranking/baselines/jaccard-arithmetic.unit.test.d.ts.map +1 -0
  58. package/dist/ranking/baselines/katz.d.ts +13 -0
  59. package/dist/ranking/baselines/katz.d.ts.map +1 -0
  60. package/dist/ranking/baselines/katz.unit.test.d.ts +2 -0
  61. package/dist/ranking/baselines/katz.unit.test.d.ts.map +1 -0
  62. package/dist/ranking/baselines/pagerank.d.ts +13 -0
  63. package/dist/ranking/baselines/pagerank.d.ts.map +1 -0
  64. package/dist/ranking/baselines/pagerank.unit.test.d.ts +2 -0
  65. package/dist/ranking/baselines/pagerank.unit.test.d.ts.map +1 -0
  66. package/dist/ranking/baselines/random-ranking.d.ts +21 -0
  67. package/dist/ranking/baselines/random-ranking.d.ts.map +1 -0
  68. package/dist/ranking/baselines/random-ranking.unit.test.d.ts +2 -0
  69. package/dist/ranking/baselines/random-ranking.unit.test.d.ts.map +1 -0
  70. package/dist/ranking/baselines/resistance-distance.d.ts +13 -0
  71. package/dist/ranking/baselines/resistance-distance.d.ts.map +1 -0
  72. package/dist/ranking/baselines/resistance-distance.unit.test.d.ts +2 -0
  73. package/dist/ranking/baselines/resistance-distance.unit.test.d.ts.map +1 -0
  74. package/dist/ranking/baselines/widest-path.d.ts +13 -0
  75. package/dist/ranking/baselines/widest-path.d.ts.map +1 -0
  76. package/dist/ranking/baselines/widest-path.unit.test.d.ts +2 -0
  77. package/dist/ranking/baselines/widest-path.unit.test.d.ts.map +1 -0
  78. package/dist/ranking/index.d.ts +3 -6
  79. package/dist/ranking/index.d.ts.map +1 -1
  80. package/dist/ranking/mi/index.d.ts +9 -9
  81. package/dist/ranking/mi/index.d.ts.map +1 -1
  82. package/dist/schemas/index.d.ts +2 -2
  83. package/dist/schemas/index.d.ts.map +1 -1
  84. package/dist/seeds/index.cjs +398 -3
  85. package/dist/seeds/index.cjs.map +1 -0
  86. package/dist/seeds/index.d.ts +2 -4
  87. package/dist/seeds/index.d.ts.map +1 -1
  88. package/dist/seeds/index.js +396 -1
  89. package/dist/seeds/index.js.map +1 -0
  90. package/dist/seeds/stratified.d.ts.map +1 -1
  91. package/dist/structures/index.cjs +133 -2
  92. package/dist/structures/index.cjs.map +1 -0
  93. package/dist/structures/index.d.ts +1 -2
  94. package/dist/structures/index.d.ts.map +1 -1
  95. package/dist/structures/index.js +132 -1
  96. package/dist/structures/index.js.map +1 -0
  97. package/dist/traversal/index.cjs +152 -5
  98. package/dist/traversal/index.cjs.map +1 -0
  99. package/dist/traversal/index.d.ts +2 -2
  100. package/dist/traversal/index.d.ts.map +1 -1
  101. package/dist/traversal/index.js +148 -1
  102. package/dist/traversal/index.js.map +1 -0
  103. package/dist/utils/index.cjs +172 -9
  104. package/dist/utils/index.cjs.map +1 -0
  105. package/dist/utils/index.d.ts +3 -3
  106. package/dist/utils/index.d.ts.map +1 -1
  107. package/dist/utils/index.js +165 -3
  108. package/dist/utils/index.js.map +1 -0
  109. package/package.json +1 -1
  110. package/dist/gpu-BJRVYBjx.cjs +0 -338
  111. package/dist/gpu-BJRVYBjx.cjs.map +0 -1
  112. package/dist/gpu-BveuXugy.js +0 -315
  113. package/dist/gpu-BveuXugy.js.map +0 -1
  114. package/dist/graph-DLWiziLB.js +0 -222
  115. package/dist/graph-DLWiziLB.js.map +0 -1
  116. package/dist/graph-az06J1YV.cjs +0 -227
  117. package/dist/graph-az06J1YV.cjs.map +0 -1
  118. package/dist/seeds-B6J9oJfU.cjs +0 -404
  119. package/dist/seeds-B6J9oJfU.cjs.map +0 -1
  120. package/dist/seeds-UNZxqm_U.js +0 -393
  121. package/dist/seeds-UNZxqm_U.js.map +0 -1
  122. package/dist/structures-BPfhfqNP.js +0 -133
  123. package/dist/structures-BPfhfqNP.js.map +0 -1
  124. package/dist/structures-CJ_S_7fs.cjs +0 -138
  125. package/dist/structures-CJ_S_7fs.cjs.map +0 -1
  126. package/dist/traversal-CQCjUwUJ.js +0 -149
  127. package/dist/traversal-CQCjUwUJ.js.map +0 -1
  128. package/dist/traversal-QeHaNUWn.cjs +0 -172
  129. package/dist/traversal-QeHaNUWn.cjs.map +0 -1
  130. package/dist/utils-Q_akvlMn.js +0 -164
  131. package/dist/utils-Q_akvlMn.js.map +0 -1
  132. package/dist/utils-spZa1ZvS.cjs +0 -205
  133. package/dist/utils-spZa1ZvS.cjs.map +0 -1
@@ -1,11 +1,11 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_graph = require("../graph-az06J1YV.cjs");
3
- const require_traversal = require("../traversal-QeHaNUWn.cjs");
4
- const require_structures = require("../structures-CJ_S_7fs.cjs");
5
- const require_kmeans = require("../kmeans-B0HEOU6k.cjs");
6
- const require_seeds = require("../seeds-B6J9oJfU.cjs");
7
- const require_utils = require("../utils-spZa1ZvS.cjs");
8
- const require_gpu = require("../gpu-BJRVYBjx.cjs");
2
+ const require_graph = require("../graph/index.cjs");
3
+ const require_traversal = require("../traversal/index.cjs");
4
+ const require_structures = require("../structures/index.cjs");
5
+ const require_kmeans = require("../kmeans-BIgSyGKu.cjs");
6
+ const require_seeds = require("../seeds/index.cjs");
7
+ const require_utils = require("../utils/index.cjs");
8
+ const require_gpu = require("../gpu/index.cjs");
9
9
  //#region src/expansion/base.ts
10
10
  /**
11
11
  * Default priority function - degree-ordered (DOME).
@@ -243,6 +243,18 @@ function dome(graph, seeds, config) {
243
243
  priority: domePriority
244
244
  });
245
245
  }
246
+ /**
247
+ * DOME with reverse priority (high degree first).
248
+ */
249
+ function domeHighDegree(graph, seeds, config) {
250
+ const domePriority = (nodeId, context) => {
251
+ return -graph.degree(nodeId);
252
+ };
253
+ return base(graph, seeds, {
254
+ ...config,
255
+ priority: domePriority
256
+ });
257
+ }
246
258
  //#endregion
247
259
  //#region src/expansion/edge.ts
248
260
  /**
@@ -521,6 +533,80 @@ function maze(graph, seeds, config) {
521
533
  });
522
534
  }
523
535
  //#endregion
536
+ //#region src/expansion/standard-bfs.ts
537
+ /**
538
+ * Run standard BFS expansion (FIFO discovery order).
539
+ *
540
+ * @param graph - Source graph
541
+ * @param seeds - Seed nodes for expansion
542
+ * @param config - Expansion configuration
543
+ * @returns Expansion result with discovered paths
544
+ */
545
+ function standardBfs(graph, seeds, config) {
546
+ const bfsPriority = (_nodeId, context) => {
547
+ return context.iteration;
548
+ };
549
+ return base(graph, seeds, {
550
+ ...config,
551
+ priority: bfsPriority
552
+ });
553
+ }
554
+ //#endregion
555
+ //#region src/expansion/frontier-balanced.ts
556
+ /**
557
+ * Run frontier-balanced expansion (round-robin across frontiers).
558
+ *
559
+ * @param graph - Source graph
560
+ * @param seeds - Seed nodes for expansion
561
+ * @param config - Expansion configuration
562
+ * @returns Expansion result with discovered paths
563
+ */
564
+ function frontierBalanced(graph, seeds, config) {
565
+ const balancedPriority = (_nodeId, context) => {
566
+ return context.frontierIndex * 1e9 + context.iteration;
567
+ };
568
+ return base(graph, seeds, {
569
+ ...config,
570
+ priority: balancedPriority
571
+ });
572
+ }
573
+ //#endregion
574
+ //#region src/expansion/random-priority.ts
575
+ /**
576
+ * Deterministic seeded random number generator.
577
+ * Uses FNV-1a-like hash for input → [0, 1] output.
578
+ *
579
+ * @param input - String to hash
580
+ * @param seed - Random seed for reproducibility
581
+ * @returns Deterministic random value in [0, 1]
582
+ */
583
+ function seededRandom$1(input, seed = 0) {
584
+ let h = seed;
585
+ for (let i = 0; i < input.length; i++) {
586
+ h = Math.imul(h ^ input.charCodeAt(i), 2654435769);
587
+ h ^= h >>> 16;
588
+ }
589
+ return (h >>> 0) / 4294967295;
590
+ }
591
+ /**
592
+ * Run random-priority expansion (null hypothesis baseline).
593
+ *
594
+ * @param graph - Source graph
595
+ * @param seeds - Seed nodes for expansion
596
+ * @param config - Expansion configuration
597
+ * @returns Expansion result with discovered paths
598
+ */
599
+ function randomPriority(graph, seeds, config) {
600
+ const { seed = 0 } = config ?? {};
601
+ const randomPriorityFn = (nodeId, context) => {
602
+ return seededRandom$1(nodeId, seed);
603
+ };
604
+ return base(graph, seeds, {
605
+ ...config,
606
+ priority: randomPriorityFn
607
+ });
608
+ }
609
+ //#endregion
524
610
  //#region src/ranking/parse.ts
525
611
  /**
526
612
  * Rank paths using PARSE (Path-Aware Ranking via Salience Estimation).
@@ -813,6 +899,712 @@ function shortest(_graph, paths, config) {
813
899
  };
814
900
  }
815
901
  //#endregion
902
+ //#region src/ranking/baselines/degree-sum.ts
903
+ /**
904
+ * Rank paths by sum of node degrees.
905
+ *
906
+ * @param graph - Source graph
907
+ * @param paths - Paths to rank
908
+ * @param config - Configuration options
909
+ * @returns Ranked paths (highest degree-sum first)
910
+ */
911
+ function degreeSum(graph, paths, config) {
912
+ const { includeScores = true } = config ?? {};
913
+ if (paths.length === 0) return {
914
+ paths: [],
915
+ method: "degree-sum"
916
+ };
917
+ const scored = paths.map((path) => {
918
+ let degreeSum = 0;
919
+ for (const nodeId of path.nodes) degreeSum += graph.degree(nodeId);
920
+ return {
921
+ path,
922
+ score: degreeSum
923
+ };
924
+ });
925
+ const maxScore = Math.max(...scored.map((s) => s.score));
926
+ if (maxScore === 0) return {
927
+ paths: paths.map((path) => ({
928
+ ...path,
929
+ score: 0
930
+ })),
931
+ method: "degree-sum"
932
+ };
933
+ return {
934
+ paths: scored.map(({ path, score }) => ({
935
+ ...path,
936
+ score: includeScores ? score / maxScore : score / maxScore
937
+ })).sort((a, b) => b.score - a.score),
938
+ method: "degree-sum"
939
+ };
940
+ }
941
+ //#endregion
942
+ //#region src/ranking/baselines/widest-path.ts
943
+ /**
944
+ * Rank paths by widest bottleneck (minimum edge similarity).
945
+ *
946
+ * @param graph - Source graph
947
+ * @param paths - Paths to rank
948
+ * @param config - Configuration options
949
+ * @returns Ranked paths (highest bottleneck first)
950
+ */
951
+ function widestPath(graph, paths, config) {
952
+ const { includeScores = true } = config ?? {};
953
+ if (paths.length === 0) return {
954
+ paths: [],
955
+ method: "widest-path"
956
+ };
957
+ const scored = paths.map((path) => {
958
+ if (path.nodes.length < 2) return {
959
+ path,
960
+ score: 1
961
+ };
962
+ let minSimilarity = Number.POSITIVE_INFINITY;
963
+ for (let i = 0; i < path.nodes.length - 1; i++) {
964
+ const source = path.nodes[i];
965
+ const target = path.nodes[i + 1];
966
+ if (source === void 0 || target === void 0) continue;
967
+ const edgeSimilarity = jaccard(graph, source, target);
968
+ minSimilarity = Math.min(minSimilarity, edgeSimilarity);
969
+ }
970
+ return {
971
+ path,
972
+ score: minSimilarity === Number.POSITIVE_INFINITY ? 1 : minSimilarity
973
+ };
974
+ });
975
+ const maxScore = Math.max(...scored.map((s) => s.score));
976
+ if (maxScore === 0) return {
977
+ paths: paths.map((path) => ({
978
+ ...path,
979
+ score: 0
980
+ })),
981
+ method: "widest-path"
982
+ };
983
+ return {
984
+ paths: scored.map(({ path, score }) => ({
985
+ ...path,
986
+ score: includeScores ? score / maxScore : score / maxScore
987
+ })).sort((a, b) => b.score - a.score),
988
+ method: "widest-path"
989
+ };
990
+ }
991
+ //#endregion
992
+ //#region src/ranking/baselines/jaccard-arithmetic.ts
993
+ /**
994
+ * Rank paths by arithmetic mean of edge Jaccard similarities.
995
+ *
996
+ * @param graph - Source graph
997
+ * @param paths - Paths to rank
998
+ * @param config - Configuration options
999
+ * @returns Ranked paths (highest arithmetic mean first)
1000
+ */
1001
+ function jaccardArithmetic(graph, paths, config) {
1002
+ const { includeScores = true } = config ?? {};
1003
+ if (paths.length === 0) return {
1004
+ paths: [],
1005
+ method: "jaccard-arithmetic"
1006
+ };
1007
+ const scored = paths.map((path) => {
1008
+ if (path.nodes.length < 2) return {
1009
+ path,
1010
+ score: 1
1011
+ };
1012
+ let similaritySum = 0;
1013
+ let edgeCount = 0;
1014
+ for (let i = 0; i < path.nodes.length - 1; i++) {
1015
+ const source = path.nodes[i];
1016
+ const target = path.nodes[i + 1];
1017
+ if (source === void 0 || target === void 0) continue;
1018
+ const edgeSimilarity = jaccard(graph, source, target);
1019
+ similaritySum += edgeSimilarity;
1020
+ edgeCount++;
1021
+ }
1022
+ return {
1023
+ path,
1024
+ score: edgeCount > 0 ? similaritySum / edgeCount : 1
1025
+ };
1026
+ });
1027
+ const maxScore = Math.max(...scored.map((s) => s.score));
1028
+ if (maxScore === 0) return {
1029
+ paths: paths.map((path) => ({
1030
+ ...path,
1031
+ score: 0
1032
+ })),
1033
+ method: "jaccard-arithmetic"
1034
+ };
1035
+ return {
1036
+ paths: scored.map(({ path, score }) => ({
1037
+ ...path,
1038
+ score: includeScores ? score / maxScore : score / maxScore
1039
+ })).sort((a, b) => b.score - a.score),
1040
+ method: "jaccard-arithmetic"
1041
+ };
1042
+ }
1043
+ //#endregion
1044
+ //#region src/ranking/baselines/pagerank.ts
1045
+ /**
1046
+ * Compute PageRank centrality for all nodes using power iteration.
1047
+ *
1048
+ * @param graph - Source graph
1049
+ * @param damping - Damping factor (default 0.85)
1050
+ * @param tolerance - Convergence tolerance (default 1e-6)
1051
+ * @param maxIterations - Maximum iterations (default 100)
1052
+ * @returns Map of node ID to PageRank value
1053
+ */
1054
+ function computePageRank(graph, damping = .85, tolerance = 1e-6, maxIterations = 100) {
1055
+ const nodes = Array.from(graph.nodeIds());
1056
+ const n = nodes.length;
1057
+ if (n === 0) return /* @__PURE__ */ new Map();
1058
+ const ranks = /* @__PURE__ */ new Map();
1059
+ const newRanks = /* @__PURE__ */ new Map();
1060
+ for (const nodeId of nodes) {
1061
+ ranks.set(nodeId, 1 / n);
1062
+ newRanks.set(nodeId, 0);
1063
+ }
1064
+ let isCurrentRanks = true;
1065
+ for (let iteration = 0; iteration < maxIterations; iteration++) {
1066
+ let maxChange = 0;
1067
+ const currMap = isCurrentRanks ? ranks : newRanks;
1068
+ const nextMap = isCurrentRanks ? newRanks : ranks;
1069
+ for (const nodeId of nodes) {
1070
+ let incomingSum = 0;
1071
+ for (const incomingId of graph.neighbours(nodeId, "in")) {
1072
+ const incomingRank = currMap.get(incomingId) ?? 0;
1073
+ const outDegree = graph.degree(incomingId);
1074
+ if (outDegree > 0) incomingSum += incomingRank / outDegree;
1075
+ }
1076
+ const newRank = (1 - damping) / n + damping * incomingSum;
1077
+ nextMap.set(nodeId, newRank);
1078
+ const oldRank = currMap.get(nodeId) ?? 0;
1079
+ maxChange = Math.max(maxChange, Math.abs(newRank - oldRank));
1080
+ }
1081
+ if (maxChange < tolerance) break;
1082
+ isCurrentRanks = !isCurrentRanks;
1083
+ currMap.clear();
1084
+ }
1085
+ return isCurrentRanks ? ranks : newRanks;
1086
+ }
1087
+ /**
1088
+ * Rank paths by sum of PageRank scores.
1089
+ *
1090
+ * @param graph - Source graph
1091
+ * @param paths - Paths to rank
1092
+ * @param config - Configuration options
1093
+ * @returns Ranked paths (highest PageRank sum first)
1094
+ */
1095
+ function pagerank(graph, paths, config) {
1096
+ const { includeScores = true } = config ?? {};
1097
+ if (paths.length === 0) return {
1098
+ paths: [],
1099
+ method: "pagerank"
1100
+ };
1101
+ const ranks = computePageRank(graph);
1102
+ const scored = paths.map((path) => {
1103
+ let prSum = 0;
1104
+ for (const nodeId of path.nodes) prSum += ranks.get(nodeId) ?? 0;
1105
+ return {
1106
+ path,
1107
+ score: prSum
1108
+ };
1109
+ });
1110
+ const maxScore = Math.max(...scored.map((s) => s.score));
1111
+ if (maxScore === 0) return {
1112
+ paths: paths.map((path) => ({
1113
+ ...path,
1114
+ score: 0
1115
+ })),
1116
+ method: "pagerank"
1117
+ };
1118
+ return {
1119
+ paths: scored.map(({ path, score }) => ({
1120
+ ...path,
1121
+ score: includeScores ? score / maxScore : score / maxScore
1122
+ })).sort((a, b) => b.score - a.score),
1123
+ method: "pagerank"
1124
+ };
1125
+ }
1126
+ //#endregion
1127
+ //#region src/ranking/baselines/betweenness.ts
1128
+ /**
1129
+ * Compute betweenness centrality for all nodes using Brandes algorithm.
1130
+ *
1131
+ * @param graph - Source graph
1132
+ * @returns Map of node ID to betweenness value
1133
+ */
1134
+ function computeBetweenness(graph) {
1135
+ const nodes = Array.from(graph.nodeIds());
1136
+ const betweenness = /* @__PURE__ */ new Map();
1137
+ for (const nodeId of nodes) betweenness.set(nodeId, 0);
1138
+ for (const source of nodes) {
1139
+ const predecessors = /* @__PURE__ */ new Map();
1140
+ const distance = /* @__PURE__ */ new Map();
1141
+ const sigma = /* @__PURE__ */ new Map();
1142
+ const queue = [];
1143
+ for (const nodeId of nodes) {
1144
+ predecessors.set(nodeId, []);
1145
+ distance.set(nodeId, -1);
1146
+ sigma.set(nodeId, 0);
1147
+ }
1148
+ distance.set(source, 0);
1149
+ sigma.set(source, 1);
1150
+ queue.push(source);
1151
+ for (const v of queue) {
1152
+ const vDist = distance.get(v) ?? -1;
1153
+ const neighbours = graph.neighbours(v);
1154
+ for (const w of neighbours) {
1155
+ const wDist = distance.get(w) ?? -1;
1156
+ if (wDist < 0) {
1157
+ distance.set(w, vDist + 1);
1158
+ queue.push(w);
1159
+ }
1160
+ if (wDist === vDist + 1) {
1161
+ const wSigma = sigma.get(w) ?? 0;
1162
+ const vSigma = sigma.get(v) ?? 0;
1163
+ sigma.set(w, wSigma + vSigma);
1164
+ const wPred = predecessors.get(w) ?? [];
1165
+ wPred.push(v);
1166
+ predecessors.set(w, wPred);
1167
+ }
1168
+ }
1169
+ }
1170
+ const delta = /* @__PURE__ */ new Map();
1171
+ for (const nodeId of nodes) delta.set(nodeId, 0);
1172
+ const sorted = [...nodes].sort((a, b) => {
1173
+ const aD = distance.get(a) ?? -1;
1174
+ return (distance.get(b) ?? -1) - aD;
1175
+ });
1176
+ for (const w of sorted) {
1177
+ if (w === source) continue;
1178
+ const wDelta = delta.get(w) ?? 0;
1179
+ const wSigma = sigma.get(w) ?? 0;
1180
+ const wPred = predecessors.get(w) ?? [];
1181
+ for (const v of wPred) {
1182
+ const vSigma = sigma.get(v) ?? 0;
1183
+ const vDelta = delta.get(v) ?? 0;
1184
+ if (wSigma > 0) delta.set(v, vDelta + vSigma / wSigma * (1 + wDelta));
1185
+ }
1186
+ if (w !== source) {
1187
+ const current = betweenness.get(w) ?? 0;
1188
+ betweenness.set(w, current + wDelta);
1189
+ }
1190
+ }
1191
+ }
1192
+ return betweenness;
1193
+ }
1194
+ /**
1195
+ * Rank paths by sum of betweenness scores.
1196
+ *
1197
+ * @param graph - Source graph
1198
+ * @param paths - Paths to rank
1199
+ * @param config - Configuration options
1200
+ * @returns Ranked paths (highest betweenness sum first)
1201
+ */
1202
+ function betweenness(graph, paths, config) {
1203
+ const { includeScores = true } = config ?? {};
1204
+ if (paths.length === 0) return {
1205
+ paths: [],
1206
+ method: "betweenness"
1207
+ };
1208
+ const bcMap = computeBetweenness(graph);
1209
+ const scored = paths.map((path) => {
1210
+ let bcSum = 0;
1211
+ for (const nodeId of path.nodes) bcSum += bcMap.get(nodeId) ?? 0;
1212
+ return {
1213
+ path,
1214
+ score: bcSum
1215
+ };
1216
+ });
1217
+ const maxScore = Math.max(...scored.map((s) => s.score));
1218
+ if (maxScore === 0) return {
1219
+ paths: paths.map((path) => ({
1220
+ ...path,
1221
+ score: 0
1222
+ })),
1223
+ method: "betweenness"
1224
+ };
1225
+ return {
1226
+ paths: scored.map(({ path, score }) => ({
1227
+ ...path,
1228
+ score: includeScores ? score / maxScore : score / maxScore
1229
+ })).sort((a, b) => b.score - a.score),
1230
+ method: "betweenness"
1231
+ };
1232
+ }
1233
+ //#endregion
1234
+ //#region src/ranking/baselines/katz.ts
1235
+ /**
1236
+ * Compute truncated Katz centrality between two nodes.
1237
+ *
1238
+ * Uses iterative matrix-vector products to avoid full matrix powers.
1239
+ * score(s,t) = sum_{k=1}^{K} beta^k * walks_k(s,t)
1240
+ *
1241
+ * @param graph - Source graph
1242
+ * @param source - Source node ID
1243
+ * @param target - Target node ID
1244
+ * @param k - Truncation depth (default 5)
1245
+ * @param beta - Attenuation factor (default 0.005)
1246
+ * @returns Katz score
1247
+ */
1248
+ function computeKatz(graph, source, target, k = 5, beta = .005) {
1249
+ const nodes = Array.from(graph.nodeIds());
1250
+ const nodeToIdx = /* @__PURE__ */ new Map();
1251
+ nodes.forEach((nodeId, idx) => {
1252
+ nodeToIdx.set(nodeId, idx);
1253
+ });
1254
+ const n = nodes.length;
1255
+ if (n === 0) return 0;
1256
+ const sourceIdx = nodeToIdx.get(source);
1257
+ const targetIdx = nodeToIdx.get(target);
1258
+ if (sourceIdx === void 0 || targetIdx === void 0) return 0;
1259
+ let walks = new Float64Array(n);
1260
+ walks[targetIdx] = 1;
1261
+ let katzScore = 0;
1262
+ for (let depth = 1; depth <= k; depth++) {
1263
+ const walksNext = new Float64Array(n);
1264
+ for (const sourceNode of nodes) {
1265
+ const srcIdx = nodeToIdx.get(sourceNode);
1266
+ if (srcIdx === void 0) continue;
1267
+ const neighbours = graph.neighbours(sourceNode);
1268
+ for (const neighbourId of neighbours) {
1269
+ const nIdx = nodeToIdx.get(neighbourId);
1270
+ if (nIdx === void 0) continue;
1271
+ walksNext[srcIdx] = (walksNext[srcIdx] ?? 0) + (walks[nIdx] ?? 0);
1272
+ }
1273
+ }
1274
+ const walkCount = walksNext[sourceIdx] ?? 0;
1275
+ katzScore += Math.pow(beta, depth) * walkCount;
1276
+ walks = walksNext;
1277
+ }
1278
+ return katzScore;
1279
+ }
1280
+ /**
1281
+ * Rank paths by Katz centrality between endpoints.
1282
+ *
1283
+ * @param graph - Source graph
1284
+ * @param paths - Paths to rank
1285
+ * @param config - Configuration options
1286
+ * @returns Ranked paths (highest Katz score first)
1287
+ */
1288
+ function katz(graph, paths, config) {
1289
+ const { includeScores = true } = config ?? {};
1290
+ if (paths.length === 0) return {
1291
+ paths: [],
1292
+ method: "katz"
1293
+ };
1294
+ const scored = paths.map((path) => {
1295
+ const source = path.nodes[0];
1296
+ const target = path.nodes[path.nodes.length - 1];
1297
+ if (source === void 0 || target === void 0) return {
1298
+ path,
1299
+ score: 0
1300
+ };
1301
+ return {
1302
+ path,
1303
+ score: computeKatz(graph, source, target)
1304
+ };
1305
+ });
1306
+ const maxScore = Math.max(...scored.map((s) => s.score));
1307
+ if (maxScore === 0) return {
1308
+ paths: paths.map((path) => ({
1309
+ ...path,
1310
+ score: 0
1311
+ })),
1312
+ method: "katz"
1313
+ };
1314
+ return {
1315
+ paths: scored.map(({ path, score }) => ({
1316
+ ...path,
1317
+ score: includeScores ? score / maxScore : score / maxScore
1318
+ })).sort((a, b) => b.score - a.score),
1319
+ method: "katz"
1320
+ };
1321
+ }
1322
+ //#endregion
1323
+ //#region src/ranking/baselines/communicability.ts
1324
+ /**
1325
+ * Compute truncated communicability between two nodes.
1326
+ *
1327
+ * Uses Taylor series expansion: (e^A)_{s,t} ≈ sum_{k=0}^{K} A^k_{s,t} / k!
1328
+ *
1329
+ * @param graph - Source graph
1330
+ * @param source - Source node ID
1331
+ * @param target - Target node ID
1332
+ * @param k - Truncation depth (default 15)
1333
+ * @returns Communicability score
1334
+ */
1335
+ function computeCommunicability(graph, source, target, k = 15) {
1336
+ const nodes = Array.from(graph.nodeIds());
1337
+ const nodeToIdx = /* @__PURE__ */ new Map();
1338
+ nodes.forEach((nodeId, idx) => {
1339
+ nodeToIdx.set(nodeId, idx);
1340
+ });
1341
+ const n = nodes.length;
1342
+ if (n === 0) return 0;
1343
+ const sourceIdx = nodeToIdx.get(source);
1344
+ const targetIdx = nodeToIdx.get(target);
1345
+ if (sourceIdx === void 0 || targetIdx === void 0) return 0;
1346
+ let walks = new Float64Array(n);
1347
+ walks[targetIdx] = 1;
1348
+ let commScore = walks[sourceIdx] ?? 0;
1349
+ let factorial = 1;
1350
+ for (let depth = 1; depth <= k; depth++) {
1351
+ const walksNext = new Float64Array(n);
1352
+ for (const fromNode of nodes) {
1353
+ const fromIdx = nodeToIdx.get(fromNode);
1354
+ if (fromIdx === void 0) continue;
1355
+ const neighbours = graph.neighbours(fromNode);
1356
+ for (const toNodeId of neighbours) {
1357
+ const toIdx = nodeToIdx.get(toNodeId);
1358
+ if (toIdx === void 0) continue;
1359
+ walksNext[fromIdx] = (walksNext[fromIdx] ?? 0) + (walks[toIdx] ?? 0);
1360
+ }
1361
+ }
1362
+ factorial *= depth;
1363
+ commScore += (walksNext[sourceIdx] ?? 0) / factorial;
1364
+ walks = walksNext;
1365
+ }
1366
+ return commScore;
1367
+ }
1368
+ /**
1369
+ * Rank paths by communicability between endpoints.
1370
+ *
1371
+ * @param graph - Source graph
1372
+ * @param paths - Paths to rank
1373
+ * @param config - Configuration options
1374
+ * @returns Ranked paths (highest communicability first)
1375
+ */
1376
+ function communicability(graph, paths, config) {
1377
+ const { includeScores = true } = config ?? {};
1378
+ if (paths.length === 0) return {
1379
+ paths: [],
1380
+ method: "communicability"
1381
+ };
1382
+ const scored = paths.map((path) => {
1383
+ const source = path.nodes[0];
1384
+ const target = path.nodes[path.nodes.length - 1];
1385
+ if (source === void 0 || target === void 0) return {
1386
+ path,
1387
+ score: 0
1388
+ };
1389
+ return {
1390
+ path,
1391
+ score: computeCommunicability(graph, source, target)
1392
+ };
1393
+ });
1394
+ const maxScore = Math.max(...scored.map((s) => s.score));
1395
+ if (maxScore === 0) return {
1396
+ paths: paths.map((path) => ({
1397
+ ...path,
1398
+ score: 0
1399
+ })),
1400
+ method: "communicability"
1401
+ };
1402
+ return {
1403
+ paths: scored.map(({ path, score }) => ({
1404
+ ...path,
1405
+ score: includeScores ? score / maxScore : score / maxScore
1406
+ })).sort((a, b) => b.score - a.score),
1407
+ method: "communicability"
1408
+ };
1409
+ }
1410
+ //#endregion
1411
+ //#region src/ranking/baselines/resistance-distance.ts
1412
+ /**
1413
+ * Compute effective resistance between two nodes via Laplacian pseudoinverse.
1414
+ *
1415
+ * Resistance = L^+_{s,s} + L^+_{t,t} - 2*L^+_{s,t}
1416
+ * where L^+ is the pseudoinverse of the Laplacian matrix.
1417
+ *
1418
+ * @param graph - Source graph
1419
+ * @param source - Source node ID
1420
+ * @param target - Target node ID
1421
+ * @returns Effective resistance
1422
+ */
1423
+ function computeResistance(graph, source, target) {
1424
+ const nodes = Array.from(graph.nodeIds());
1425
+ const nodeToIdx = /* @__PURE__ */ new Map();
1426
+ nodes.forEach((nodeId, idx) => {
1427
+ nodeToIdx.set(nodeId, idx);
1428
+ });
1429
+ const n = nodes.length;
1430
+ if (n === 0 || n > 5e3) throw new Error(`Cannot compute resistance distance: graph too large (${String(n)} nodes). Maximum 5000.`);
1431
+ const sourceIdx = nodeToIdx.get(source);
1432
+ const targetIdx = nodeToIdx.get(target);
1433
+ if (sourceIdx === void 0 || targetIdx === void 0) return 0;
1434
+ const L = Array.from({ length: n }, () => Array.from({ length: n }, () => 0));
1435
+ for (let i = 0; i < n; i++) {
1436
+ const nodeId = nodes[i];
1437
+ if (nodeId === void 0) continue;
1438
+ const degree = graph.degree(nodeId);
1439
+ const row = L[i];
1440
+ if (row !== void 0) row[i] = degree;
1441
+ const neighbours = graph.neighbours(nodeId);
1442
+ for (const neighbourId of neighbours) {
1443
+ const j = nodeToIdx.get(neighbourId);
1444
+ if (j !== void 0 && row !== void 0) row[j] = -1;
1445
+ }
1446
+ }
1447
+ const Lpinv = pinv(L);
1448
+ const resistance = (Lpinv[sourceIdx]?.[sourceIdx] ?? 0) + (Lpinv[targetIdx]?.[targetIdx] ?? 0) - 2 * (Lpinv[sourceIdx]?.[targetIdx] ?? 0);
1449
+ return Math.max(resistance, 1e-10);
1450
+ }
1451
+ /**
1452
+ * Compute Moore-Penrose pseudoinverse of a matrix.
1453
+ * Simplified implementation for small dense matrices.
1454
+ *
1455
+ * @param A - Square matrix
1456
+ * @returns Pseudoinverse A^+
1457
+ */
1458
+ function pinv(A) {
1459
+ const n = A.length;
1460
+ if (n === 0) return [];
1461
+ const M = A.map((row) => [...row]);
1462
+ const epsilon = 1e-10;
1463
+ for (let i = 0; i < n; i++) {
1464
+ const row = M[i];
1465
+ if (row !== void 0) row[i] = (row[i] ?? 0) + epsilon;
1466
+ }
1467
+ return gaussianInverse(M);
1468
+ }
1469
+ /**
1470
+ * Compute matrix inverse using Gaussian elimination with partial pivoting.
1471
+ *
1472
+ * @param A - Matrix to invert
1473
+ * @returns Inverted matrix
1474
+ */
1475
+ function gaussianInverse(A) {
1476
+ const n = A.length;
1477
+ const aug = A.map((row, i) => {
1478
+ const identity = Array.from({ length: n }, (_, j) => i === j ? 1 : 0);
1479
+ return [...row, ...identity];
1480
+ });
1481
+ for (let col = 0; col < n; col++) {
1482
+ let maxRow = col;
1483
+ for (let row = col + 1; row < n; row++) {
1484
+ const currentRow = aug[row];
1485
+ const maxRowRef = aug[maxRow];
1486
+ if (currentRow !== void 0 && maxRowRef !== void 0 && Math.abs(currentRow[col] ?? 0) > Math.abs(maxRowRef[col] ?? 0)) maxRow = row;
1487
+ }
1488
+ const currentCol = aug[col];
1489
+ const maxRowAug = aug[maxRow];
1490
+ if (currentCol !== void 0 && maxRowAug !== void 0) {
1491
+ aug[col] = maxRowAug;
1492
+ aug[maxRow] = currentCol;
1493
+ }
1494
+ const pivotRow = aug[col];
1495
+ const pivot = pivotRow?.[col];
1496
+ if (pivot === void 0 || Math.abs(pivot) < 1e-12) continue;
1497
+ if (pivotRow !== void 0) for (let j = col; j < 2 * n; j++) pivotRow[j] = (pivotRow[j] ?? 0) / pivot;
1498
+ for (let row = 0; row < n; row++) {
1499
+ if (row === col) continue;
1500
+ const eliminationRow = aug[row];
1501
+ const factor = eliminationRow?.[col] ?? 0;
1502
+ if (eliminationRow !== void 0 && pivotRow !== void 0) for (let j = col; j < 2 * n; j++) eliminationRow[j] = (eliminationRow[j] ?? 0) - factor * (pivotRow[j] ?? 0);
1503
+ }
1504
+ }
1505
+ const Ainv = [];
1506
+ for (let i = 0; i < n; i++) Ainv[i] = (aug[i]?.slice(n) ?? []).map((v) => v);
1507
+ return Ainv;
1508
+ }
1509
+ /**
1510
+ * Rank paths by reciprocal of resistance distance between endpoints.
1511
+ *
1512
+ * @param graph - Source graph
1513
+ * @param paths - Paths to rank
1514
+ * @param config - Configuration options
1515
+ * @returns Ranked paths (highest conductance first)
1516
+ */
1517
+ function resistanceDistance(graph, paths, config) {
1518
+ const { includeScores = true } = config ?? {};
1519
+ if (paths.length === 0) return {
1520
+ paths: [],
1521
+ method: "resistance-distance"
1522
+ };
1523
+ const nodeCount = Array.from(graph.nodeIds()).length;
1524
+ if (nodeCount > 5e3) throw new Error(`Cannot rank paths: graph too large (${String(nodeCount)} nodes). Resistance distance requires O(n^3) computation; maximum 5000 nodes.`);
1525
+ const scored = paths.map((path) => {
1526
+ const source = path.nodes[0];
1527
+ const target = path.nodes[path.nodes.length - 1];
1528
+ if (source === void 0 || target === void 0) return {
1529
+ path,
1530
+ score: 0
1531
+ };
1532
+ return {
1533
+ path,
1534
+ score: 1 / computeResistance(graph, source, target)
1535
+ };
1536
+ });
1537
+ const maxScore = Math.max(...scored.map((s) => s.score));
1538
+ if (maxScore === 0) return {
1539
+ paths: paths.map((path) => ({
1540
+ ...path,
1541
+ score: 0
1542
+ })),
1543
+ method: "resistance-distance"
1544
+ };
1545
+ return {
1546
+ paths: scored.map(({ path, score }) => ({
1547
+ ...path,
1548
+ score: includeScores ? score / maxScore : score / maxScore
1549
+ })).sort((a, b) => b.score - a.score),
1550
+ method: "resistance-distance"
1551
+ };
1552
+ }
1553
+ //#endregion
1554
+ //#region src/ranking/baselines/random-ranking.ts
1555
+ /**
1556
+ * Deterministic seeded random number generator.
1557
+ * Uses FNV-1a-like hash for input → [0, 1] output.
1558
+ *
1559
+ * @param input - String to hash
1560
+ * @param seed - Random seed for reproducibility
1561
+ * @returns Deterministic random value in [0, 1]
1562
+ */
1563
+ function seededRandom(input, seed = 0) {
1564
+ let h = seed;
1565
+ for (let i = 0; i < input.length; i++) {
1566
+ h = Math.imul(h ^ input.charCodeAt(i), 2654435769);
1567
+ h ^= h >>> 16;
1568
+ }
1569
+ return (h >>> 0) / 4294967295;
1570
+ }
1571
+ /**
1572
+ * Rank paths randomly (null hypothesis baseline).
1573
+ *
1574
+ * @param _graph - Source graph (unused)
1575
+ * @param paths - Paths to rank
1576
+ * @param config - Configuration options
1577
+ * @returns Ranked paths (randomly ordered)
1578
+ */
1579
+ function randomRanking(_graph, paths, config) {
1580
+ const { includeScores = true, seed = 0 } = config ?? {};
1581
+ if (paths.length === 0) return {
1582
+ paths: [],
1583
+ method: "random"
1584
+ };
1585
+ const scored = paths.map((path) => {
1586
+ return {
1587
+ path,
1588
+ score: seededRandom(path.nodes.join(","), seed)
1589
+ };
1590
+ });
1591
+ const maxScore = Math.max(...scored.map((s) => s.score));
1592
+ if (maxScore === 0) return {
1593
+ paths: paths.map((path) => ({
1594
+ ...path,
1595
+ score: 0
1596
+ })),
1597
+ method: "random"
1598
+ };
1599
+ return {
1600
+ paths: scored.map(({ path, score }) => ({
1601
+ ...path,
1602
+ score: includeScores ? score / maxScore : score / maxScore
1603
+ })).sort((a, b) => b.score - a.score),
1604
+ method: "random"
1605
+ };
1606
+ }
1607
+ //#endregion
816
1608
  //#region src/extraction/ego-network.ts
817
1609
  /**
818
1610
  * Extract the ego-network (k-hop neighbourhood) of a centre node.
@@ -1023,6 +1815,82 @@ function extractKTruss(graph, k) {
1023
1815
  }
1024
1816
  return result;
1025
1817
  }
1818
+ /**
1819
+ * Compute the truss number for each edge.
1820
+ *
1821
+ * The truss number of an edge is the largest k such that the edge
1822
+ * belongs to the k-truss.
1823
+ *
1824
+ * @param graph - The source graph
1825
+ * @returns Map from edge key (canonical "u::v") to truss number
1826
+ *
1827
+ * @example
1828
+ * ```typescript
1829
+ * const trussNumbers = computeTrussNumbers(graph);
1830
+ * const edgeKey = 'A::B'; // where A < B lexicographically
1831
+ * console.log(`Edge A-B is in the ${trussNumbers.get(edgeKey)}-truss`);
1832
+ * ```
1833
+ */
1834
+ function computeTrussNumbers(graph) {
1835
+ const adjacency = /* @__PURE__ */ new Map();
1836
+ const edgeData = /* @__PURE__ */ new Map();
1837
+ const remainingEdges = /* @__PURE__ */ new Set();
1838
+ for (const nodeId of graph.nodeIds()) adjacency.set(nodeId, /* @__PURE__ */ new Set());
1839
+ for (const edge of graph.edges()) {
1840
+ const { source, target } = edge;
1841
+ adjacency.get(source)?.add(target);
1842
+ adjacency.get(target)?.add(source);
1843
+ const key = source < target ? `${source}::${target}` : `${target}::${source}`;
1844
+ edgeData.set(key, edge);
1845
+ remainingEdges.add(key);
1846
+ }
1847
+ const triangleCounts = /* @__PURE__ */ new Map();
1848
+ for (const key of remainingEdges) {
1849
+ const edge = edgeData.get(key);
1850
+ if (edge !== void 0) triangleCounts.set(key, countEdgeTriangles(graph, edge.source, edge.target));
1851
+ }
1852
+ const trussNumbers = /* @__PURE__ */ new Map();
1853
+ const edgesByTriangleCount = /* @__PURE__ */ new Map();
1854
+ for (const [key, count] of triangleCounts) {
1855
+ if (!edgesByTriangleCount.has(count)) edgesByTriangleCount.set(count, /* @__PURE__ */ new Set());
1856
+ edgesByTriangleCount.get(count)?.add(key);
1857
+ }
1858
+ const sortedCounts = [...edgesByTriangleCount.keys()].sort((a, b) => a - b);
1859
+ for (const currentCount of sortedCounts) {
1860
+ const bucket = edgesByTriangleCount.get(currentCount);
1861
+ if (bucket === void 0) continue;
1862
+ while (bucket.size > 0) {
1863
+ const edgeKey = bucket.values().next().value;
1864
+ if (edgeKey === void 0) break;
1865
+ bucket.delete(edgeKey);
1866
+ if (!remainingEdges.has(edgeKey)) continue;
1867
+ const trussNumber = currentCount + 2;
1868
+ trussNumbers.set(edgeKey, trussNumber);
1869
+ remainingEdges.delete(edgeKey);
1870
+ const edge = edgeData.get(edgeKey);
1871
+ if (edge === void 0) continue;
1872
+ const { source, target } = edge;
1873
+ adjacency.get(source)?.delete(target);
1874
+ adjacency.get(target)?.delete(source);
1875
+ const sourceNeighbours = adjacency.get(source);
1876
+ if (sourceNeighbours !== void 0) {
1877
+ for (const w of adjacency.get(target) ?? []) if (sourceNeighbours.has(w)) {
1878
+ const keySw = source < w ? `${source}::${w}` : `${w}::${source}`;
1879
+ const keyTw = target < w ? `${target}::${w}` : `${w}::${target}`;
1880
+ for (const keyToUpdate of [keySw, keyTw]) if (remainingEdges.has(keyToUpdate)) {
1881
+ const oldCount = triangleCounts.get(keyToUpdate) ?? 0;
1882
+ const newCount = oldCount - 1;
1883
+ triangleCounts.set(keyToUpdate, newCount);
1884
+ edgesByTriangleCount.get(oldCount)?.delete(keyToUpdate);
1885
+ if (!edgesByTriangleCount.has(newCount)) edgesByTriangleCount.set(newCount, /* @__PURE__ */ new Set());
1886
+ edgesByTriangleCount.get(newCount)?.add(keyToUpdate);
1887
+ }
1888
+ }
1889
+ }
1890
+ }
1891
+ }
1892
+ return trussNumbers;
1893
+ }
1026
1894
  //#endregion
1027
1895
  //#region src/extraction/motif.ts
1028
1896
  /**
@@ -1133,10 +2001,11 @@ function enumerate3NodeMotifs(graph, includeInstances) {
1133
2001
  }
1134
2002
  }
1135
2003
  }
1136
- return {
2004
+ if (instances !== void 0) return {
1137
2005
  counts,
1138
2006
  instances
1139
2007
  };
2008
+ return { counts };
1140
2009
  }
1141
2010
  /**
1142
2011
  * Enumerate all 4-node motifs in the graph.
@@ -1204,10 +2073,11 @@ function enumerate4NodeMotifs(graph, includeInstances) {
1204
2073
  }
1205
2074
  }
1206
2075
  }
1207
- return {
2076
+ if (instances !== void 0) return {
1208
2077
  counts,
1209
2078
  instances
1210
2079
  };
2080
+ return { counts };
1211
2081
  }
1212
2082
  /**
1213
2083
  * Human-readable names for common 3-node motifs.
@@ -1354,19 +2224,29 @@ function filterSubgraph(graph, options) {
1354
2224
  //#endregion
1355
2225
  exports.AdjacencyMapGraph = require_graph.AdjacencyMapGraph;
1356
2226
  exports.GPUContext = require_gpu.GPUContext;
2227
+ exports.GPUNotAvailableError = require_gpu.GPUNotAvailableError;
1357
2228
  exports.PriorityQueue = require_structures.PriorityQueue;
2229
+ exports._computeMean = require_kmeans._computeMean;
1358
2230
  exports.adamicAdar = adamicAdar;
1359
2231
  exports.adaptive = adaptive;
1360
2232
  exports.approximateClusteringCoefficient = require_utils.approximateClusteringCoefficient;
2233
+ exports.assertWebGPUAvailable = require_gpu.assertWebGPUAvailable;
1361
2234
  exports.base = base;
1362
2235
  exports.batchClusteringCoefficients = require_utils.batchClusteringCoefficients;
2236
+ exports.betweenness = betweenness;
1363
2237
  exports.bfs = require_traversal.bfs;
1364
2238
  exports.bfsWithPath = require_traversal.bfsWithPath;
2239
+ exports.communicability = communicability;
2240
+ exports.computeTrussNumbers = computeTrussNumbers;
2241
+ exports.createGPUContext = require_gpu.createGPUContext;
2242
+ exports.createResultBuffer = require_gpu.createResultBuffer;
1365
2243
  exports.csrToGPUBuffers = require_gpu.csrToGPUBuffers;
2244
+ exports.degreeSum = degreeSum;
1366
2245
  exports.detectWebGPU = require_gpu.detectWebGPU;
1367
2246
  exports.dfs = require_traversal.dfs;
1368
2247
  exports.dfsWithPath = require_traversal.dfsWithPath;
1369
2248
  exports.dome = dome;
2249
+ exports.domeHighDegree = domeHighDegree;
1370
2250
  exports.edge = edge;
1371
2251
  exports.entropyFromCounts = require_utils.entropyFromCounts;
1372
2252
  exports.enumerateMotifs = enumerateMotifs;
@@ -1377,28 +2257,40 @@ exports.extractInducedSubgraph = extractInducedSubgraph;
1377
2257
  exports.extractKCore = extractKCore;
1378
2258
  exports.extractKTruss = extractKTruss;
1379
2259
  exports.filterSubgraph = filterSubgraph;
2260
+ exports.frontierBalanced = frontierBalanced;
2261
+ exports.getGPUContext = require_gpu.getGPUContext;
1380
2262
  exports.getMotifName = getMotifName;
1381
2263
  exports.graphToCSR = require_gpu.graphToCSR;
1382
2264
  exports.grasp = require_seeds.grasp;
1383
2265
  exports.hae = hae;
2266
+ exports.isWebGPUAvailable = require_gpu.isWebGPUAvailable;
1384
2267
  exports.jaccard = jaccard;
2268
+ exports.jaccardArithmetic = jaccardArithmetic;
2269
+ exports.katz = katz;
1385
2270
  exports.localClusteringCoefficient = require_utils.localClusteringCoefficient;
1386
2271
  exports.localTypeEntropy = require_utils.localTypeEntropy;
1387
2272
  exports.maze = maze;
1388
2273
  exports.miniBatchKMeans = require_kmeans.miniBatchKMeans;
1389
2274
  exports.normaliseFeatures = require_kmeans.normaliseFeatures;
2275
+ exports.zScoreNormalise = require_kmeans.normaliseFeatures;
1390
2276
  exports.normalisedEntropy = require_utils.normalisedEntropy;
1391
2277
  exports.notch = notch;
2278
+ exports.pagerank = pagerank;
1392
2279
  exports.parse = parse;
1393
2280
  exports.pipe = pipe;
2281
+ exports.randomPriority = randomPriority;
2282
+ exports.randomRanking = randomRanking;
1394
2283
  exports.reach = reach;
2284
+ exports.readBufferToCPU = require_gpu.readBufferToCPU;
2285
+ exports.resistanceDistance = resistanceDistance;
1395
2286
  exports.sage = sage;
1396
2287
  exports.scale = scale;
1397
2288
  exports.shannonEntropy = require_utils.shannonEntropy;
1398
2289
  exports.shortest = shortest;
1399
2290
  exports.skew = skew;
1400
2291
  exports.span = span;
2292
+ exports.standardBfs = standardBfs;
1401
2293
  exports.stratified = require_seeds.stratified;
1402
- exports.zScoreNormalise = require_kmeans.normaliseFeatures;
2294
+ exports.widestPath = widestPath;
1403
2295
 
1404
2296
  //# sourceMappingURL=index.cjs.map