@graphty/algorithms 1.2.0 → 1.4.2

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 (337) hide show
  1. package/README.md +375 -276
  2. package/dist/algorithms.d.ts +42 -2
  3. package/dist/algorithms.js +11402 -2
  4. package/dist/algorithms.js.map +1 -1
  5. package/dist/src/algorithms/centrality/betweenness.d.ts +14 -0
  6. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  7. package/dist/src/algorithms/centrality/betweenness.js +144 -169
  8. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  9. package/dist/src/algorithms/centrality/closeness.d.ts +35 -1
  10. package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
  11. package/dist/src/algorithms/centrality/closeness.js +70 -149
  12. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  13. package/dist/src/algorithms/centrality/degree.d.ts +7 -0
  14. package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
  15. package/dist/src/algorithms/centrality/degree.js +12 -9
  16. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  17. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +57 -0
  18. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
  19. package/dist/src/algorithms/centrality/delta-pagerank-simple.js +304 -0
  20. package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
  21. package/dist/src/algorithms/centrality/delta-pagerank.d.ts +106 -0
  22. package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
  23. package/dist/src/algorithms/centrality/delta-pagerank.js +320 -0
  24. package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
  25. package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -3
  26. package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
  27. package/dist/src/algorithms/centrality/eigenvector.js +11 -4
  28. package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
  29. package/dist/src/algorithms/centrality/hits.d.ts +10 -3
  30. package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
  31. package/dist/src/algorithms/centrality/hits.js +11 -4
  32. package/dist/src/algorithms/centrality/hits.js.map +1 -1
  33. package/dist/src/algorithms/centrality/index.d.ts +3 -1
  34. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  35. package/dist/src/algorithms/centrality/index.js +2 -1
  36. package/dist/src/algorithms/centrality/index.js.map +1 -1
  37. package/dist/src/algorithms/centrality/katz.d.ts +10 -3
  38. package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
  39. package/dist/src/algorithms/centrality/katz.js +13 -8
  40. package/dist/src/algorithms/centrality/katz.js.map +1 -1
  41. package/dist/src/algorithms/centrality/pagerank.d.ts +31 -0
  42. package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
  43. package/dist/src/algorithms/centrality/pagerank.js +61 -1
  44. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  45. package/dist/src/algorithms/community/girvan-newman.d.ts +2 -3
  46. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
  47. package/dist/src/algorithms/community/girvan-newman.js +67 -57
  48. package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
  49. package/dist/src/algorithms/community/index.d.ts +2 -0
  50. package/dist/src/algorithms/community/index.d.ts.map +1 -1
  51. package/dist/src/algorithms/community/index.js.map +1 -1
  52. package/dist/src/algorithms/community/label-propagation.d.ts +11 -4
  53. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
  54. package/dist/src/algorithms/community/label-propagation.js +60 -38
  55. package/dist/src/algorithms/community/label-propagation.js.map +1 -1
  56. package/dist/src/algorithms/community/leiden.d.ts +3 -3
  57. package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
  58. package/dist/src/algorithms/community/leiden.js +70 -44
  59. package/dist/src/algorithms/community/leiden.js.map +1 -1
  60. package/dist/src/algorithms/community/louvain-optimized.d.ts +149 -0
  61. package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
  62. package/dist/src/algorithms/community/louvain-optimized.js +338 -0
  63. package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
  64. package/dist/src/algorithms/community/louvain.d.ts +2 -3
  65. package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
  66. package/dist/src/algorithms/community/louvain.js +35 -81
  67. package/dist/src/algorithms/community/louvain.js.map +1 -1
  68. package/dist/src/algorithms/community/modularity-utils.d.ts +55 -0
  69. package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
  70. package/dist/src/algorithms/community/modularity-utils.js +108 -0
  71. package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
  72. package/dist/src/algorithms/components/connected.d.ts +23 -0
  73. package/dist/src/algorithms/components/connected.d.ts.map +1 -1
  74. package/dist/src/algorithms/components/connected.js +29 -3
  75. package/dist/src/algorithms/components/connected.js.map +1 -1
  76. package/dist/src/algorithms/matching/bipartite.d.ts +10 -0
  77. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
  78. package/dist/src/algorithms/matching/bipartite.js +18 -40
  79. package/dist/src/algorithms/matching/bipartite.js.map +1 -1
  80. package/dist/src/algorithms/matching/index.d.ts.map +1 -1
  81. package/dist/src/algorithms/matching/index.js.map +1 -1
  82. package/dist/src/algorithms/matching/isomorphism.d.ts +8 -0
  83. package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -1
  84. package/dist/src/algorithms/matching/isomorphism.js +36 -2
  85. package/dist/src/algorithms/matching/isomorphism.js.map +1 -1
  86. package/dist/src/algorithms/mst/index.d.ts.map +1 -1
  87. package/dist/src/algorithms/mst/index.js.map +1 -1
  88. package/dist/src/algorithms/mst/kruskal.d.ts +14 -0
  89. package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
  90. package/dist/src/algorithms/mst/kruskal.js +17 -3
  91. package/dist/src/algorithms/mst/kruskal.js.map +1 -1
  92. package/dist/src/algorithms/mst/prim.d.ts +9 -0
  93. package/dist/src/algorithms/mst/prim.d.ts.map +1 -1
  94. package/dist/src/algorithms/mst/prim.js +9 -0
  95. package/dist/src/algorithms/mst/prim.js.map +1 -1
  96. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts +10 -0
  97. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
  98. package/dist/src/algorithms/shortest-path/bellman-ford.js +11 -12
  99. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  100. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +44 -0
  101. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
  102. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +195 -0
  103. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
  104. package/dist/src/algorithms/shortest-path/dijkstra.d.ts +20 -2
  105. package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
  106. package/dist/src/algorithms/shortest-path/dijkstra.js +30 -14
  107. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  108. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +17 -0
  109. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
  110. package/dist/src/algorithms/shortest-path/floyd-warshall.js +17 -0
  111. package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
  112. package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
  113. package/dist/src/algorithms/shortest-path/index.js.map +1 -1
  114. package/dist/src/algorithms/traversal/bfs-unified.d.ts +42 -0
  115. package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
  116. package/dist/src/algorithms/traversal/bfs-unified.js +370 -0
  117. package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
  118. package/dist/src/algorithms/traversal/bfs-variants.d.ts +77 -0
  119. package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
  120. package/dist/src/algorithms/traversal/bfs-variants.js +402 -0
  121. package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
  122. package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
  123. package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
  124. package/dist/src/algorithms/traversal/bfs.js +5 -182
  125. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  126. package/dist/src/algorithms/traversal/dfs.d.ts +10 -0
  127. package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
  128. package/dist/src/algorithms/traversal/dfs.js +48 -0
  129. package/dist/src/algorithms/traversal/dfs.js.map +1 -1
  130. package/dist/src/algorithms/traversal/index.d.ts.map +1 -1
  131. package/dist/src/algorithms/traversal/index.js.map +1 -1
  132. package/dist/src/benchmark-all-algorithms.d.ts +25 -0
  133. package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
  134. package/dist/src/benchmark-all-algorithms.js +491 -0
  135. package/dist/src/benchmark-all-algorithms.js.map +1 -0
  136. package/dist/src/clustering/hierarchical.d.ts +23 -15
  137. package/dist/src/clustering/hierarchical.d.ts.map +1 -1
  138. package/dist/src/clustering/hierarchical.js +226 -224
  139. package/dist/src/clustering/hierarchical.js.map +1 -1
  140. package/dist/src/clustering/index.d.ts +4 -2
  141. package/dist/src/clustering/index.d.ts.map +1 -1
  142. package/dist/src/clustering/index.js +2 -2
  143. package/dist/src/clustering/index.js.map +1 -1
  144. package/dist/src/clustering/k-core.d.ts +17 -19
  145. package/dist/src/clustering/k-core.d.ts.map +1 -1
  146. package/dist/src/clustering/k-core.js +68 -30
  147. package/dist/src/clustering/k-core.js.map +1 -1
  148. package/dist/src/clustering/mcl.d.ts +6 -0
  149. package/dist/src/clustering/mcl.d.ts.map +1 -1
  150. package/dist/src/clustering/mcl.js +34 -3
  151. package/dist/src/clustering/mcl.js.map +1 -1
  152. package/dist/src/clustering/spectral.d.ts +11 -0
  153. package/dist/src/clustering/spectral.d.ts.map +1 -1
  154. package/dist/src/clustering/spectral.js +99 -47
  155. package/dist/src/clustering/spectral.js.map +1 -1
  156. package/dist/src/core/graph.d.ts +45 -0
  157. package/dist/src/core/graph.d.ts.map +1 -1
  158. package/dist/src/core/graph.js +49 -5
  159. package/dist/src/core/graph.js.map +1 -1
  160. package/dist/src/data-structures/index.d.ts.map +1 -1
  161. package/dist/src/data-structures/index.js.map +1 -1
  162. package/dist/src/data-structures/priority-queue.d.ts +18 -1
  163. package/dist/src/data-structures/priority-queue.d.ts.map +1 -1
  164. package/dist/src/data-structures/priority-queue.js +26 -5
  165. package/dist/src/data-structures/priority-queue.js.map +1 -1
  166. package/dist/src/data-structures/union-find.d.ts +21 -0
  167. package/dist/src/data-structures/union-find.d.ts.map +1 -1
  168. package/dist/src/data-structures/union-find.js +21 -0
  169. package/dist/src/data-structures/union-find.js.map +1 -1
  170. package/dist/src/flow/ford-fulkerson.d.ts +20 -12
  171. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
  172. package/dist/src/flow/ford-fulkerson.js +170 -217
  173. package/dist/src/flow/ford-fulkerson.js.map +1 -1
  174. package/dist/src/flow/min-cut.d.ts +6 -8
  175. package/dist/src/flow/min-cut.d.ts.map +1 -1
  176. package/dist/src/flow/min-cut.js +34 -12
  177. package/dist/src/flow/min-cut.js.map +1 -1
  178. package/dist/src/index.d.ts +3 -1
  179. package/dist/src/index.d.ts.map +1 -1
  180. package/dist/src/index.js +6 -1
  181. package/dist/src/index.js.map +1 -1
  182. package/dist/src/link-prediction/adamic-adar.d.ts +26 -0
  183. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
  184. package/dist/src/link-prediction/adamic-adar.js +47 -30
  185. package/dist/src/link-prediction/adamic-adar.js.map +1 -1
  186. package/dist/src/link-prediction/common-neighbors.d.ts +21 -0
  187. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
  188. package/dist/src/link-prediction/common-neighbors.js +31 -14
  189. package/dist/src/link-prediction/common-neighbors.js.map +1 -1
  190. package/dist/src/link-prediction/index.d.ts.map +1 -1
  191. package/dist/src/optimized/bit-packed.d.ts +193 -0
  192. package/dist/src/optimized/bit-packed.d.ts.map +1 -0
  193. package/dist/src/optimized/bit-packed.js +342 -0
  194. package/dist/src/optimized/bit-packed.js.map +1 -0
  195. package/dist/src/optimized/csr-graph.d.ts +149 -0
  196. package/dist/src/optimized/csr-graph.d.ts.map +1 -0
  197. package/dist/src/optimized/csr-graph.js +404 -0
  198. package/dist/src/optimized/csr-graph.js.map +1 -0
  199. package/dist/src/optimized/direction-optimized-bfs.d.ts +95 -0
  200. package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
  201. package/dist/src/optimized/direction-optimized-bfs.js +242 -0
  202. package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
  203. package/dist/src/optimized/graph-adapter.d.ts +111 -0
  204. package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
  205. package/dist/src/optimized/graph-adapter.js +194 -0
  206. package/dist/src/optimized/graph-adapter.js.map +1 -0
  207. package/dist/src/optimized/index.d.ts +14 -0
  208. package/dist/src/optimized/index.d.ts.map +1 -0
  209. package/dist/src/optimized/index.js +30 -0
  210. package/dist/src/optimized/index.js.map +1 -0
  211. package/dist/src/pathfinding/astar.d.ts +25 -9
  212. package/dist/src/pathfinding/astar.d.ts.map +1 -1
  213. package/dist/src/pathfinding/astar.js +25 -10
  214. package/dist/src/pathfinding/astar.js.map +1 -1
  215. package/dist/src/pathfinding/utils.d.ts +15 -6
  216. package/dist/src/pathfinding/utils.d.ts.map +1 -1
  217. package/dist/src/pathfinding/utils.js +19 -7
  218. package/dist/src/pathfinding/utils.js.map +1 -1
  219. package/dist/src/research/grsbm.d.ts +0 -1
  220. package/dist/src/research/grsbm.d.ts.map +1 -1
  221. package/dist/src/research/grsbm.js +28 -23
  222. package/dist/src/research/grsbm.js.map +1 -1
  223. package/dist/src/research/index.d.ts.map +1 -1
  224. package/dist/src/research/index.js.map +1 -1
  225. package/dist/src/research/sync.d.ts +0 -1
  226. package/dist/src/research/sync.d.ts.map +1 -1
  227. package/dist/src/research/sync.js +31 -36
  228. package/dist/src/research/sync.js.map +1 -1
  229. package/dist/src/research/terahac.d.ts +2 -1
  230. package/dist/src/research/terahac.d.ts.map +1 -1
  231. package/dist/src/research/terahac.js +39 -7
  232. package/dist/src/research/terahac.js.map +1 -1
  233. package/dist/src/types/index.d.ts +8 -0
  234. package/dist/src/types/index.d.ts.map +1 -1
  235. package/dist/src/utils/algorithm-utilities.d.ts +2 -0
  236. package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
  237. package/dist/src/utils/algorithm-utilities.js +2 -0
  238. package/dist/src/utils/algorithm-utilities.js.map +1 -0
  239. package/dist/src/utils/graph-converters.d.ts +110 -0
  240. package/dist/src/utils/graph-converters.d.ts.map +1 -0
  241. package/dist/src/utils/graph-converters.js +227 -0
  242. package/dist/src/utils/graph-converters.js.map +1 -0
  243. package/dist/src/utils/graph-utilities.d.ts +62 -0
  244. package/dist/src/utils/graph-utilities.d.ts.map +1 -0
  245. package/dist/src/utils/graph-utilities.js +148 -0
  246. package/dist/src/utils/graph-utilities.js.map +1 -0
  247. package/dist/src/utils/index.d.ts +5 -0
  248. package/dist/src/utils/index.d.ts.map +1 -0
  249. package/dist/src/utils/index.js +5 -0
  250. package/dist/src/utils/index.js.map +1 -0
  251. package/dist/src/utils/math-utilities.d.ts +63 -0
  252. package/dist/src/utils/math-utilities.d.ts.map +1 -0
  253. package/dist/src/utils/math-utilities.js +132 -0
  254. package/dist/src/utils/math-utilities.js.map +1 -0
  255. package/dist/src/utils/matrix-utilities.d.ts +2 -0
  256. package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
  257. package/dist/src/utils/matrix-utilities.js +2 -0
  258. package/dist/src/utils/matrix-utilities.js.map +1 -0
  259. package/dist/src/utils/optimization-helpers.d.ts +42 -0
  260. package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
  261. package/dist/src/utils/optimization-helpers.js +59 -0
  262. package/dist/src/utils/optimization-helpers.js.map +1 -0
  263. package/dist/src/utils/priorityQueue.d.ts +24 -0
  264. package/dist/src/utils/priorityQueue.d.ts.map +1 -1
  265. package/dist/src/utils/priorityQueue.js +34 -4
  266. package/dist/src/utils/priorityQueue.js.map +1 -1
  267. package/package.json +58 -39
  268. package/src/algorithms/centrality/betweenness.ts +185 -200
  269. package/src/algorithms/centrality/closeness.ts +93 -194
  270. package/src/algorithms/centrality/degree.ts +18 -22
  271. package/src/algorithms/centrality/delta-pagerank-simple.ts +374 -0
  272. package/src/algorithms/centrality/delta-pagerank.ts +458 -0
  273. package/src/algorithms/centrality/eigenvector.ts +14 -15
  274. package/src/algorithms/centrality/hits.ts +17 -17
  275. package/src/algorithms/centrality/index.ts +20 -13
  276. package/src/algorithms/centrality/katz.ts +17 -25
  277. package/src/algorithms/centrality/pagerank.ts +91 -16
  278. package/src/algorithms/community/girvan-newman.ts +90 -86
  279. package/src/algorithms/community/index.ts +6 -5
  280. package/src/algorithms/community/label-propagation.ts +69 -48
  281. package/src/algorithms/community/leiden.ts +88 -65
  282. package/src/algorithms/community/louvain-optimized.ts +474 -0
  283. package/src/algorithms/community/louvain.ts +52 -122
  284. package/src/algorithms/community/modularity-utils.ts +134 -0
  285. package/src/algorithms/components/connected.ts +40 -17
  286. package/src/algorithms/matching/bipartite.ts +24 -53
  287. package/src/algorithms/matching/index.ts +4 -4
  288. package/src/algorithms/matching/isomorphism.ts +53 -23
  289. package/src/algorithms/mst/index.ts +3 -4
  290. package/src/algorithms/mst/kruskal.ts +21 -6
  291. package/src/algorithms/mst/prim.ts +13 -4
  292. package/src/algorithms/shortest-path/bellman-ford.ts +16 -28
  293. package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
  294. package/src/algorithms/shortest-path/dijkstra.ts +38 -30
  295. package/src/algorithms/shortest-path/floyd-warshall.ts +21 -4
  296. package/src/algorithms/shortest-path/index.ts +5 -5
  297. package/src/algorithms/traversal/bfs-unified.ts +437 -0
  298. package/src/algorithms/traversal/bfs-variants.ts +520 -0
  299. package/src/algorithms/traversal/bfs.ts +5 -229
  300. package/src/algorithms/traversal/dfs.ts +61 -42
  301. package/src/algorithms/traversal/index.ts +3 -3
  302. package/src/benchmark-all-algorithms.ts +580 -0
  303. package/src/clustering/hierarchical.ts +268 -272
  304. package/src/clustering/index.ts +8 -6
  305. package/src/clustering/k-core.ts +93 -61
  306. package/src/clustering/mcl.ts +53 -23
  307. package/src/clustering/spectral.ts +130 -72
  308. package/src/core/graph.ts +58 -18
  309. package/src/data-structures/index.ts +2 -2
  310. package/src/data-structures/priority-queue.ts +36 -11
  311. package/src/data-structures/union-find.ts +22 -1
  312. package/src/flow/ford-fulkerson.ts +221 -262
  313. package/src/flow/min-cut.ts +59 -51
  314. package/src/index.ts +9 -2
  315. package/src/link-prediction/adamic-adar.ts +75 -74
  316. package/src/link-prediction/common-neighbors.ts +49 -49
  317. package/src/link-prediction/index.ts +1 -1
  318. package/src/optimized/bit-packed.ts +390 -0
  319. package/src/optimized/csr-graph.ts +518 -0
  320. package/src/optimized/direction-optimized-bfs.ts +310 -0
  321. package/src/optimized/graph-adapter.ts +248 -0
  322. package/src/optimized/index.ts +34 -0
  323. package/src/pathfinding/astar.ts +40 -25
  324. package/src/pathfinding/utils.ts +20 -13
  325. package/src/research/grsbm.ts +36 -39
  326. package/src/research/index.ts +4 -4
  327. package/src/research/sync.ts +41 -54
  328. package/src/research/terahac.ts +63 -21
  329. package/src/types/index.ts +8 -0
  330. package/src/utils/algorithm-utilities.ts +2 -0
  331. package/src/utils/graph-converters.ts +269 -0
  332. package/src/utils/graph-utilities.ts +173 -0
  333. package/src/utils/index.ts +4 -0
  334. package/src/utils/math-utilities.ts +149 -0
  335. package/src/utils/matrix-utilities.ts +2 -0
  336. package/src/utils/optimization-helpers.ts +87 -0
  337. package/src/utils/priorityQueue.ts +40 -6
@@ -1,5 +1,6 @@
1
- import type {Graph} from "../core/graph.js";
2
- import type {NodeId} from "../types/index.js";
1
+ import type { Graph } from "../core/graph.js";
2
+ import type { NodeId } from "../types/index.js";
3
+ import { getCommonNeighbors, getIntermediateNodes } from "../utils/graph-utilities.js";
3
4
 
4
5
  /**
5
6
  * Common Neighbors link prediction implementation
@@ -26,6 +27,11 @@ export interface LinkPredictionOptions {
26
27
 
27
28
  /**
28
29
  * Calculate common neighbors score for a pair of nodes
30
+ * @param graph - The input graph
31
+ * @param source - The source node ID
32
+ * @param target - The target node ID
33
+ * @param options - Link prediction options
34
+ * @returns The number of common neighbors
29
35
  */
30
36
  export function commonNeighborsScore(
31
37
  graph: Graph,
@@ -37,39 +43,25 @@ export function commonNeighborsScore(
37
43
  return 0;
38
44
  }
39
45
 
40
- const {directed = false} = options;
41
-
42
- // Get neighbors
43
- const sourceNeighbors = new Set(
44
- directed ? Array.from(graph.outNeighbors(source)) : Array.from(graph.neighbors(source)),
45
- );
46
- const targetNeighbors = new Set(
47
- directed ? Array.from(graph.inNeighbors(target)) : Array.from(graph.neighbors(target)),
48
- );
49
-
50
- // Count common neighbors
51
- let commonCount = 0;
52
- for (const neighbor of sourceNeighbors) {
53
- if (targetNeighbors.has(neighbor)) {
54
- commonCount++;
55
- }
56
- }
46
+ const { directed = false } = options;
47
+
48
+ // Use utility function to get common neighbors
49
+ // For directed graphs, we want intermediate nodes that form paths source->X->target
50
+ const commonNeighborsSet = directed
51
+ ? getIntermediateNodes(graph, source, target)
52
+ : getCommonNeighbors(graph, source, target, false);
57
53
 
58
- return commonCount;
54
+ return commonNeighborsSet.size;
59
55
  }
60
56
 
61
57
  /**
62
58
  * Calculate common neighbors scores for all possible node pairs
59
+ * @param graph - The input graph
60
+ * @param options - Link prediction options
61
+ * @returns Array of link prediction scores sorted by score descending
63
62
  */
64
- export function commonNeighborsPrediction(
65
- graph: Graph,
66
- options: LinkPredictionOptions = {},
67
- ): LinkPredictionScore[] {
68
- const {
69
- directed = false,
70
- includeExisting = false,
71
- topK,
72
- } = options;
63
+ export function commonNeighborsPrediction(graph: Graph, options: LinkPredictionOptions = {}): LinkPredictionScore[] {
64
+ const { directed = false, includeExisting = false, topK } = options;
73
65
 
74
66
  const scores: LinkPredictionScore[] = [];
75
67
  const nodes = Array.from(graph.nodes()).map((n) => n.id);
@@ -88,14 +80,14 @@ export function commonNeighborsPrediction(
88
80
  continue;
89
81
  }
90
82
 
91
- const score = commonNeighborsScore(graph, source, target, {directed});
83
+ const score = commonNeighborsScore(graph, source, target, { directed });
92
84
 
93
85
  if (score > 0) {
94
- scores.push({source, target, score});
86
+ scores.push({ source, target, score });
95
87
 
96
88
  // For undirected graphs, also add the reverse pair
97
89
  if (!directed && source !== target) {
98
- scores.push({source: target, target: source, score});
90
+ scores.push({ source: target, target: source, score });
99
91
  }
100
92
  }
101
93
  }
@@ -114,6 +106,10 @@ export function commonNeighborsPrediction(
114
106
 
115
107
  /**
116
108
  * Calculate common neighbors scores for specific node pairs
109
+ * @param graph - The input graph
110
+ * @param pairs - Array of node ID pairs to calculate scores for
111
+ * @param options - Link prediction options
112
+ * @returns Array of link prediction scores for the specified pairs
117
113
  */
118
114
  export function commonNeighborsForPairs(
119
115
  graph: Graph,
@@ -129,22 +125,21 @@ export function commonNeighborsForPairs(
129
125
 
130
126
  /**
131
127
  * Get top candidates for link prediction for a specific node
128
+ * @param graph - The input graph
129
+ * @param node - The node ID to get candidates for
130
+ * @param options - Link prediction options with optional candidate list
131
+ * @returns Array of top link prediction candidates sorted by score descending
132
132
  */
133
133
  export function getTopCandidatesForNode(
134
134
  graph: Graph,
135
135
  node: NodeId,
136
- options: LinkPredictionOptions & {candidates?: NodeId[]} = {},
136
+ options: LinkPredictionOptions & { candidates?: NodeId[] } = {},
137
137
  ): LinkPredictionScore[] {
138
138
  if (!graph.hasNode(node)) {
139
139
  return [];
140
140
  }
141
141
 
142
- const {
143
- directed = false,
144
- includeExisting = false,
145
- topK = 10,
146
- candidates,
147
- } = options;
142
+ const { directed = false, includeExisting = false, topK = 10, candidates } = options;
148
143
 
149
144
  const scores: LinkPredictionScore[] = [];
150
145
  const targetNodes = candidates ?? Array.from(graph.nodes()).map((n) => n.id);
@@ -159,10 +154,10 @@ export function getTopCandidatesForNode(
159
154
  continue;
160
155
  }
161
156
 
162
- const score = commonNeighborsScore(graph, node, target, {directed});
157
+ const score = commonNeighborsScore(graph, node, target, { directed });
163
158
 
164
159
  if (score > 0) {
165
- scores.push({source: node, target, score});
160
+ scores.push({ source: node, target, score });
166
161
  }
167
162
  }
168
163
 
@@ -174,6 +169,11 @@ export function getTopCandidatesForNode(
174
169
 
175
170
  /**
176
171
  * Calculate precision and recall for link prediction evaluation
172
+ * @param trainingGraph - The training graph without test edges
173
+ * @param testEdges - Array of node pairs that are actual edges
174
+ * @param nonEdges - Array of node pairs that are not edges
175
+ * @param options - Link prediction options
176
+ * @returns Evaluation metrics including precision, recall, F1 score, and AUC
177
177
  */
178
178
  export function evaluateCommonNeighbors(
179
179
  trainingGraph: Graph,
@@ -181,19 +181,19 @@ export function evaluateCommonNeighbors(
181
181
  nonEdges: [NodeId, NodeId][],
182
182
  options: LinkPredictionOptions = {},
183
183
  ): {
184
- precision: number;
185
- recall: number;
186
- f1Score: number;
187
- auc: number;
188
- } {
184
+ precision: number;
185
+ recall: number;
186
+ f1Score: number;
187
+ auc: number;
188
+ } {
189
189
  // Get scores for test edges and non-edges
190
190
  const testScores = commonNeighborsForPairs(trainingGraph, testEdges, options);
191
191
  const nonEdgeScores = commonNeighborsForPairs(trainingGraph, nonEdges, options);
192
192
 
193
193
  // Combine and sort all scores
194
194
  const allScores = [
195
- ... testScores.map((s) => ({... s, isActualEdge: true})),
196
- ... nonEdgeScores.map((s) => ({... s, isActualEdge: false})),
195
+ ...testScores.map((s) => ({ ...s, isActualEdge: true })),
196
+ ...nonEdgeScores.map((s) => ({ ...s, isActualEdge: false })),
197
197
  ].sort((a, b) => b.score - a.score);
198
198
 
199
199
  // Calculate precision and recall at different thresholds
@@ -214,7 +214,7 @@ export function evaluateCommonNeighbors(
214
214
 
215
215
  const precision = truePositives / (truePositives + falsePositives);
216
216
  const recall = truePositives / totalPositives;
217
- const f1 = precision + recall > 0 ? 2 * (precision * recall) / (precision + recall) : 0;
217
+ const f1 = precision + recall > 0 ? (2 * (precision * recall)) / (precision + recall) : 0;
218
218
 
219
219
  if (f1 > bestF1) {
220
220
  bestF1 = f1;
@@ -10,7 +10,7 @@ export {
10
10
  evaluateAdamicAdar,
11
11
  getTopAdamicAdarCandidatesForNode,
12
12
  } from "./adamic-adar.js";
13
- export type {LinkPredictionOptions, LinkPredictionScore} from "./common-neighbors.js";
13
+ export type { LinkPredictionOptions, LinkPredictionScore } from "./common-neighbors.js";
14
14
  export {
15
15
  commonNeighborsForPairs,
16
16
  commonNeighborsPrediction,
@@ -0,0 +1,390 @@
1
+ import { TypedFastBitSet } from "typedfastbitset";
2
+
3
+ /**
4
+ * Wrapper around TypedFastBitSet with graph-specific optimizations
5
+ *
6
+ * Provides efficient bit-packed set operations optimized for graph algorithms
7
+ * with 8x memory reduction compared to standard JavaScript Set for boolean values.
8
+ */
9
+ export class GraphBitSet {
10
+ private bitset: TypedFastBitSet;
11
+ private _cardinality = 0;
12
+
13
+ /**
14
+ * Creates a new GraphBitSet with optional pre-allocated capacity.
15
+ * @param capacity - The initial capacity to pre-allocate for the bitset
16
+ */
17
+ constructor(capacity?: number) {
18
+ this.bitset = new TypedFastBitSet();
19
+ if (capacity) {
20
+ // Pre-allocate for known size
21
+ this.bitset.resize(capacity);
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Add a single element to the set.
27
+ * @param index - The element index to add
28
+ */
29
+ add(index: number): void {
30
+ if (!this.bitset.has(index)) {
31
+ this.bitset.add(index);
32
+ this._cardinality++;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Remove a single element from the set.
38
+ * @param index - The element index to remove
39
+ */
40
+ remove(index: number): void {
41
+ if (this.bitset.has(index)) {
42
+ this.bitset.remove(index);
43
+ this._cardinality--;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Check if an element exists in the set.
49
+ * @param index - The element index to check
50
+ * @returns True if the element exists, false otherwise
51
+ */
52
+ has(index: number): boolean {
53
+ return this.bitset.has(index);
54
+ }
55
+
56
+ /**
57
+ * Clear all elements
58
+ */
59
+ clear(): void {
60
+ this.bitset.clear();
61
+ this._cardinality = 0;
62
+ }
63
+
64
+ /**
65
+ * Check if the set is empty.
66
+ * @returns True if the set contains no elements, false otherwise
67
+ */
68
+ isEmpty(): boolean {
69
+ return this._cardinality === 0;
70
+ }
71
+
72
+ /**
73
+ * Optimized for graph algorithms - add a range of indices.
74
+ * @param start - The starting index (inclusive)
75
+ * @param end - The ending index (exclusive)
76
+ */
77
+ addRange(start: number, end: number): void {
78
+ for (let i = start; i < end; i++) {
79
+ if (!this.bitset.has(i)) {
80
+ this.bitset.add(i);
81
+ this._cardinality++;
82
+ }
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Fast cardinality tracking - get the number of elements in the set.
88
+ * @returns The number of elements in the set
89
+ */
90
+ size(): number {
91
+ return this._cardinality;
92
+ }
93
+
94
+ /**
95
+ * Batch operations for frontier management - swap contents with another GraphBitSet.
96
+ * @param other - The GraphBitSet to swap contents with
97
+ */
98
+ swap(other: GraphBitSet): void {
99
+ [this.bitset, other.bitset] = [other.bitset, this.bitset];
100
+ [this._cardinality, other._cardinality] = [other._cardinality, this._cardinality];
101
+ }
102
+
103
+ /**
104
+ * Efficient iteration over all elements in the set.
105
+ * @yields The indices of elements in the set
106
+ */
107
+ *[Symbol.iterator](): Generator<number> {
108
+ // Use TypedFastBitSet's optimized iteration
109
+ yield* this.bitset;
110
+ }
111
+
112
+ /**
113
+ * Perform union operation with another GraphBitSet, updating this set in place.
114
+ * @param other - The GraphBitSet to union with
115
+ */
116
+ union(other: GraphBitSet): void {
117
+ const result = this.bitset.union(other.bitset);
118
+ this.bitset = result;
119
+
120
+ const size = this.bitset.size();
121
+ this._cardinality = size;
122
+ }
123
+
124
+ /**
125
+ * Perform intersection operation with another GraphBitSet, updating this set in place.
126
+ * @param other - The GraphBitSet to intersect with
127
+ */
128
+ intersection(other: GraphBitSet): void {
129
+ const result = this.bitset.intersection(other.bitset);
130
+ this.bitset = result;
131
+
132
+ const size = this.bitset.size();
133
+ this._cardinality = size;
134
+ }
135
+
136
+ /**
137
+ * Perform difference operation with another GraphBitSet, updating this set in place.
138
+ * @param other - The GraphBitSet to subtract from this set
139
+ */
140
+ difference(other: GraphBitSet): void {
141
+ const result = this.bitset.difference(other.bitset);
142
+ this.bitset = result;
143
+
144
+ const size = this.bitset.size();
145
+ this._cardinality = size;
146
+ }
147
+
148
+ /**
149
+ * Clone the bitset.
150
+ * @returns A new GraphBitSet with the same elements
151
+ */
152
+ clone(): GraphBitSet {
153
+ const cloned = new GraphBitSet();
154
+ cloned.bitset = this.bitset.clone();
155
+
156
+ cloned._cardinality = this._cardinality;
157
+ return cloned;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Specialized bit array for visited tracking
163
+ *
164
+ * More memory efficient than GraphBitSet for simple boolean arrays
165
+ * that don't need set operations.
166
+ */
167
+ export class VisitedBitArray {
168
+ private words: Uint32Array;
169
+ private wordCount: number;
170
+ private _size: number;
171
+
172
+ /**
173
+ * Creates a new VisitedBitArray with the specified size.
174
+ * @param size - The number of bits to allocate
175
+ */
176
+ constructor(size: number) {
177
+ this._size = size;
178
+ this.wordCount = Math.ceil(size / 32);
179
+ this.words = new Uint32Array(this.wordCount);
180
+ }
181
+
182
+ /**
183
+ * Set bit at the specified index.
184
+ * @param index - The bit index to set
185
+ */
186
+ set(index: number): void {
187
+ if (index < 0 || index >= this._size) {
188
+ throw new Error(`Index ${String(index)} out of bounds [0, ${String(this._size)})`);
189
+ }
190
+
191
+ const wordIndex = index >>> 5; // divide by 32
192
+ const bitIndex = index & 31; // modulo 32
193
+ const word = this.words[wordIndex];
194
+ if (word !== undefined) {
195
+ this.words[wordIndex] = word | (1 << bitIndex);
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Get bit value at the specified index.
201
+ * @param index - The bit index to get
202
+ * @returns True if the bit is set, false otherwise
203
+ */
204
+ get(index: number): boolean {
205
+ if (index < 0 || index >= this._size) {
206
+ return false;
207
+ }
208
+
209
+ const wordIndex = index >>> 5;
210
+ const bitIndex = index & 31;
211
+ const word = this.words[wordIndex];
212
+ return word !== undefined && (word & (1 << bitIndex)) !== 0;
213
+ }
214
+
215
+ /**
216
+ * Clear all bits
217
+ */
218
+ clear(): void {
219
+ this.words.fill(0);
220
+ }
221
+
222
+ /**
223
+ * Toggle bit at the specified index.
224
+ * @param index - The bit index to toggle
225
+ */
226
+ toggle(index: number): void {
227
+ if (index < 0 || index >= this._size) {
228
+ throw new Error(`Index ${String(index)} out of bounds [0, ${String(this._size)})`);
229
+ }
230
+
231
+ const wordIndex = index >>> 5;
232
+ const bitIndex = index & 31;
233
+ const word = this.words[wordIndex];
234
+ if (word !== undefined) {
235
+ this.words[wordIndex] = word ^ (1 << bitIndex);
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Population count for statistics - count the number of set bits.
241
+ * @returns The number of bits set to 1
242
+ */
243
+ popcount(): number {
244
+ let count = 0;
245
+ for (let i = 0; i < this.wordCount; i++) {
246
+ const word = this.words[i];
247
+ if (word !== undefined) {
248
+ count += this.popcountWord(word);
249
+ }
250
+ }
251
+ return count;
252
+ }
253
+
254
+ /**
255
+ * Efficient population count for a single word.
256
+ * Uses bit manipulation tricks for fast counting.
257
+ * @param n - The 32-bit word to count
258
+ * @returns The number of bits set to 1 in the word
259
+ */
260
+ private popcountWord(n: number): number {
261
+ let x = n;
262
+ x = x - ((x >>> 1) & 0x55555555);
263
+ x = (x & 0x33333333) + ((x >>> 2) & 0x33333333);
264
+ return (((x + (x >>> 4)) & 0xf0f0f0f) * 0x1010101) >>> 24;
265
+ }
266
+
267
+ /**
268
+ * Get size of the bit array.
269
+ * @returns The total number of bits in the array
270
+ */
271
+ size(): number {
272
+ return this._size;
273
+ }
274
+
275
+ /**
276
+ * Check if all bits are zero.
277
+ * @returns True if no bits are set, false otherwise
278
+ */
279
+ isEmpty(): boolean {
280
+ for (let i = 0; i < this.wordCount; i++) {
281
+ if (this.words[i] !== 0) {
282
+ return false;
283
+ }
284
+ }
285
+ return true;
286
+ }
287
+
288
+ /**
289
+ * Set multiple bits from an array of indices.
290
+ * @param indices - Array of bit indices to set
291
+ */
292
+ setMultiple(indices: number[]): void {
293
+ for (const index of indices) {
294
+ this.set(index);
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Get indices of all set bits.
300
+ * @returns Array containing the indices of all bits that are set to 1
301
+ */
302
+ getSetIndices(): number[] {
303
+ const indices: number[] = [];
304
+ for (let wordIndex = 0; wordIndex < this.wordCount; wordIndex++) {
305
+ const word = this.words[wordIndex];
306
+ if (!word || word === 0) {
307
+ continue;
308
+ }
309
+
310
+ for (let bitIndex = 0; bitIndex < 32; bitIndex++) {
311
+ if (word & (1 << bitIndex)) {
312
+ const index = (wordIndex << 5) + bitIndex;
313
+ if (index < this._size) {
314
+ indices.push(index);
315
+ }
316
+ }
317
+ }
318
+ }
319
+ return indices;
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Bit-packed distance array for BFS
325
+ *
326
+ * Optimized for storing distances using 16-bit integers (up to 65,535 levels)
327
+ * Still provides 2x memory savings compared to standard 32-bit numbers
328
+ */
329
+ export class CompactDistanceArray {
330
+ private data: Uint16Array;
331
+ private _size: number;
332
+ private static readonly INFINITY = 65535;
333
+
334
+ /**
335
+ * Creates a new CompactDistanceArray with the specified size.
336
+ * @param size - The number of distance values to store
337
+ */
338
+ constructor(size: number) {
339
+ this._size = size;
340
+ this.data = new Uint16Array(size);
341
+ this.data.fill(CompactDistanceArray.INFINITY); // Initialize with max value (unvisited)
342
+ }
343
+
344
+ /**
345
+ * Set distance at the specified index.
346
+ * @param index - The node index to set the distance for
347
+ * @param distance - The distance value to set
348
+ */
349
+ set(index: number, distance: number): void {
350
+ if (distance >= CompactDistanceArray.INFINITY) {
351
+ throw new Error(`Distance exceeds maximum value (${String(CompactDistanceArray.INFINITY - 1)})`);
352
+ }
353
+
354
+ this.data[index] = distance;
355
+ }
356
+
357
+ /**
358
+ * Get distance at the specified index.
359
+ * @param index - The node index to get the distance for
360
+ * @returns The distance value, or INFINITY if not set
361
+ */
362
+ get(index: number): number {
363
+ const value = this.data[index];
364
+ return value ?? CompactDistanceArray.INFINITY; // Default to unvisited
365
+ }
366
+
367
+ /**
368
+ * Check if a node has been visited (has a valid distance).
369
+ * @param index - The node index to check
370
+ * @returns True if the node has been visited, false otherwise
371
+ */
372
+ isVisited(index: number): boolean {
373
+ return this.data[index] !== CompactDistanceArray.INFINITY;
374
+ }
375
+
376
+ /**
377
+ * Reset all distances to unvisited state.
378
+ */
379
+ clear(): void {
380
+ this.data.fill(CompactDistanceArray.INFINITY);
381
+ }
382
+
383
+ /**
384
+ * Get the size of the distance array.
385
+ * @returns The number of elements in the array
386
+ */
387
+ size(): number {
388
+ return this._size;
389
+ }
390
+ }