@graphty/algorithms 2.1.1 → 2.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 (355) hide show
  1. package/README.md +139 -50
  2. package/dist/algorithms.js +15260 -10390
  3. package/dist/algorithms.js.map +1 -1
  4. package/dist/algorithms.standalone.js +26675 -21542
  5. package/dist/algorithms.standalone.js.map +1 -1
  6. package/dist/src/algorithms/centrality/betweenness.d.ts +18 -0
  7. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  8. package/dist/src/algorithms/centrality/betweenness.js +40 -1
  9. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  10. package/dist/src/algorithms/centrality/closeness.d.ts +20 -0
  11. package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
  12. package/dist/src/algorithms/centrality/closeness.js +93 -8
  13. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  14. package/dist/src/algorithms/centrality/degree.d.ts +9 -0
  15. package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
  16. package/dist/src/algorithms/centrality/degree.js +18 -0
  17. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  18. package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -0
  19. package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
  20. package/dist/src/algorithms/centrality/eigenvector.js +29 -0
  21. package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
  22. package/dist/src/algorithms/centrality/hits.d.ts +9 -0
  23. package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
  24. package/dist/src/algorithms/centrality/hits.js +23 -0
  25. package/dist/src/algorithms/centrality/hits.js.map +1 -1
  26. package/dist/src/algorithms/centrality/katz.d.ts +9 -0
  27. package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
  28. package/dist/src/algorithms/centrality/katz.js +31 -0
  29. package/dist/src/algorithms/centrality/katz.js.map +1 -1
  30. package/dist/src/algorithms/centrality/pagerank.d.ts +13 -13
  31. package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
  32. package/dist/src/algorithms/centrality/pagerank.js +47 -10
  33. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  34. package/dist/src/algorithms/community/girvan-newman-legacy.d.ts +27 -0
  35. package/dist/src/algorithms/community/girvan-newman-legacy.d.ts.map +1 -0
  36. package/dist/src/algorithms/community/girvan-newman-legacy.js +335 -0
  37. package/dist/src/algorithms/community/girvan-newman-legacy.js.map +1 -0
  38. package/dist/src/algorithms/community/girvan-newman.d.ts +5 -3
  39. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
  40. package/dist/src/algorithms/community/girvan-newman.js +34 -308
  41. package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
  42. package/dist/src/algorithms/community/label-propagation.d.ts +9 -6
  43. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
  44. package/dist/src/algorithms/community/label-propagation.js +24 -110
  45. package/dist/src/algorithms/community/label-propagation.js.map +1 -1
  46. package/dist/src/algorithms/components/connected.d.ts.map +1 -1
  47. package/dist/src/algorithms/components/connected.js +28 -77
  48. package/dist/src/algorithms/components/connected.js.map +1 -1
  49. package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
  50. package/dist/src/algorithms/mst/kruskal.js +59 -3
  51. package/dist/src/algorithms/mst/kruskal.js.map +1 -1
  52. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
  53. package/dist/src/algorithms/shortest-path/bellman-ford.js +46 -0
  54. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  55. package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
  56. package/dist/src/algorithms/shortest-path/dijkstra.js +27 -0
  57. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  58. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +15 -5
  59. package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
  60. package/dist/src/algorithms/shortest-path/floyd-warshall.js +97 -107
  61. package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
  62. package/dist/src/algorithms/traversal/bfs-unified.d.ts +2 -12
  63. package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -1
  64. package/dist/src/algorithms/traversal/bfs-unified.js +47 -308
  65. package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -1
  66. package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -1
  67. package/dist/src/algorithms/traversal/bfs-variants.js +5 -25
  68. package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -1
  69. package/dist/src/algorithms/traversal/bfs.d.ts +0 -3
  70. package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
  71. package/dist/src/algorithms/traversal/bfs.js +0 -4
  72. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  73. package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
  74. package/dist/src/algorithms/traversal/dfs.js +33 -154
  75. package/dist/src/algorithms/traversal/dfs.js.map +1 -1
  76. package/dist/src/clustering/hierarchical-legacy.d.ts +56 -0
  77. package/dist/src/clustering/hierarchical-legacy.d.ts.map +1 -0
  78. package/dist/src/clustering/hierarchical-legacy.js +441 -0
  79. package/dist/src/clustering/hierarchical-legacy.js.map +1 -0
  80. package/dist/src/clustering/hierarchical.d.ts +7 -39
  81. package/dist/src/clustering/hierarchical.d.ts.map +1 -1
  82. package/dist/src/clustering/hierarchical.js +56 -417
  83. package/dist/src/clustering/hierarchical.js.map +1 -1
  84. package/dist/src/clustering/k-core-legacy.d.ts +30 -0
  85. package/dist/src/clustering/k-core-legacy.d.ts.map +1 -0
  86. package/dist/src/clustering/k-core-legacy.js +191 -0
  87. package/dist/src/clustering/k-core-legacy.js.map +1 -0
  88. package/dist/src/clustering/k-core.d.ts +8 -7
  89. package/dist/src/clustering/k-core.d.ts.map +1 -1
  90. package/dist/src/clustering/k-core.js +33 -174
  91. package/dist/src/clustering/k-core.js.map +1 -1
  92. package/dist/src/clustering/mcl-legacy.d.ts +42 -0
  93. package/dist/src/clustering/mcl-legacy.d.ts.map +1 -0
  94. package/dist/src/clustering/mcl-legacy.js +386 -0
  95. package/dist/src/clustering/mcl-legacy.js.map +1 -0
  96. package/dist/src/clustering/mcl.d.ts +9 -32
  97. package/dist/src/clustering/mcl.d.ts.map +1 -1
  98. package/dist/src/clustering/mcl.js +48 -374
  99. package/dist/src/clustering/mcl.js.map +1 -1
  100. package/dist/src/index.d.ts +29 -3
  101. package/dist/src/index.d.ts.map +1 -1
  102. package/dist/src/index.js +2 -1
  103. package/dist/src/index.js.map +1 -1
  104. package/dist/src/indexed/accelerator.d.ts +141 -11
  105. package/dist/src/indexed/accelerator.d.ts.map +1 -1
  106. package/dist/src/indexed/accelerator.js +319 -5
  107. package/dist/src/indexed/accelerator.js.map +1 -1
  108. package/dist/src/indexed/all-pairs.d.ts +59 -0
  109. package/dist/src/indexed/all-pairs.d.ts.map +1 -0
  110. package/dist/src/indexed/all-pairs.js +274 -0
  111. package/dist/src/indexed/all-pairs.js.map +1 -0
  112. package/dist/src/indexed/bellman-ford.d.ts +25 -0
  113. package/dist/src/indexed/bellman-ford.d.ts.map +1 -0
  114. package/dist/src/indexed/bellman-ford.js +59 -0
  115. package/dist/src/indexed/bellman-ford.js.map +1 -0
  116. package/dist/src/indexed/betweenness.d.ts +85 -0
  117. package/dist/src/indexed/betweenness.d.ts.map +1 -0
  118. package/dist/src/indexed/betweenness.js +188 -0
  119. package/dist/src/indexed/betweenness.js.map +1 -0
  120. package/dist/src/indexed/bfs.d.ts +69 -2
  121. package/dist/src/indexed/bfs.d.ts.map +1 -1
  122. package/dist/src/indexed/bfs.js +148 -1
  123. package/dist/src/indexed/bfs.js.map +1 -1
  124. package/dist/src/indexed/bipartite.d.ts +37 -0
  125. package/dist/src/indexed/bipartite.d.ts.map +1 -0
  126. package/dist/src/indexed/bipartite.js +54 -0
  127. package/dist/src/indexed/bipartite.js.map +1 -0
  128. package/dist/src/indexed/closeness.d.ts +49 -0
  129. package/dist/src/indexed/closeness.d.ts.map +1 -0
  130. package/dist/src/indexed/closeness.js +127 -0
  131. package/dist/src/indexed/closeness.js.map +1 -0
  132. package/dist/src/indexed/common-neighbors.d.ts +14 -1
  133. package/dist/src/indexed/common-neighbors.d.ts.map +1 -1
  134. package/dist/src/indexed/common-neighbors.js +24 -14
  135. package/dist/src/indexed/common-neighbors.js.map +1 -1
  136. package/dist/src/indexed/degree.d.ts +19 -0
  137. package/dist/src/indexed/degree.d.ts.map +1 -0
  138. package/dist/src/indexed/degree.js +45 -0
  139. package/dist/src/indexed/degree.js.map +1 -0
  140. package/dist/src/indexed/delta-pagerank.d.ts +145 -0
  141. package/dist/src/indexed/delta-pagerank.d.ts.map +1 -0
  142. package/dist/src/indexed/delta-pagerank.js +428 -0
  143. package/dist/src/indexed/delta-pagerank.js.map +1 -0
  144. package/dist/src/indexed/dfs.d.ts +55 -0
  145. package/dist/src/indexed/dfs.d.ts.map +1 -0
  146. package/dist/src/indexed/dfs.js +146 -0
  147. package/dist/src/indexed/dfs.js.map +1 -0
  148. package/dist/src/indexed/eigenvector.d.ts +48 -0
  149. package/dist/src/indexed/eigenvector.d.ts.map +1 -0
  150. package/dist/src/indexed/eigenvector.js +162 -0
  151. package/dist/src/indexed/eigenvector.js.map +1 -0
  152. package/dist/src/indexed/facade.d.ts +109 -0
  153. package/dist/src/indexed/facade.d.ts.map +1 -0
  154. package/dist/src/indexed/facade.js +204 -0
  155. package/dist/src/indexed/facade.js.map +1 -0
  156. package/dist/src/indexed/flow.d.ts +120 -0
  157. package/dist/src/indexed/flow.d.ts.map +1 -0
  158. package/dist/src/indexed/flow.js +377 -0
  159. package/dist/src/indexed/flow.js.map +1 -0
  160. package/dist/src/indexed/girvan-newman.d.ts +42 -0
  161. package/dist/src/indexed/girvan-newman.d.ts.map +1 -0
  162. package/dist/src/indexed/girvan-newman.js +90 -0
  163. package/dist/src/indexed/girvan-newman.js.map +1 -0
  164. package/dist/src/indexed/grsbm.d.ts +85 -0
  165. package/dist/src/indexed/grsbm.d.ts.map +1 -0
  166. package/dist/src/indexed/grsbm.js +287 -0
  167. package/dist/src/indexed/grsbm.js.map +1 -0
  168. package/dist/src/indexed/hierarchical.d.ts +69 -0
  169. package/dist/src/indexed/hierarchical.d.ts.map +1 -0
  170. package/dist/src/indexed/hierarchical.js +245 -0
  171. package/dist/src/indexed/hierarchical.js.map +1 -0
  172. package/dist/src/indexed/index.d.ts +29 -3
  173. package/dist/src/indexed/index.d.ts.map +1 -1
  174. package/dist/src/indexed/index.js +29 -3
  175. package/dist/src/indexed/index.js.map +1 -1
  176. package/dist/src/indexed/isomorphism.d.ts +42 -0
  177. package/dist/src/indexed/isomorphism.d.ts.map +1 -0
  178. package/dist/src/indexed/isomorphism.js +269 -0
  179. package/dist/src/indexed/isomorphism.js.map +1 -0
  180. package/dist/src/indexed/label-propagation.d.ts +134 -0
  181. package/dist/src/indexed/label-propagation.d.ts.map +1 -0
  182. package/dist/src/indexed/label-propagation.js +486 -0
  183. package/dist/src/indexed/label-propagation.js.map +1 -0
  184. package/dist/src/indexed/leiden.d.ts +52 -0
  185. package/dist/src/indexed/leiden.d.ts.map +1 -0
  186. package/dist/src/indexed/leiden.js +384 -0
  187. package/dist/src/indexed/leiden.js.map +1 -0
  188. package/dist/src/indexed/link-prediction.d.ts +147 -0
  189. package/dist/src/indexed/link-prediction.d.ts.map +1 -0
  190. package/dist/src/indexed/link-prediction.js +317 -0
  191. package/dist/src/indexed/link-prediction.js.map +1 -0
  192. package/dist/src/indexed/markov.d.ts +54 -0
  193. package/dist/src/indexed/markov.d.ts.map +1 -0
  194. package/dist/src/indexed/markov.js +284 -0
  195. package/dist/src/indexed/markov.js.map +1 -0
  196. package/dist/src/indexed/matching.d.ts +53 -0
  197. package/dist/src/indexed/matching.d.ts.map +1 -0
  198. package/dist/src/indexed/matching.js +139 -0
  199. package/dist/src/indexed/matching.js.map +1 -0
  200. package/dist/src/indexed/min-cut.d.ts +48 -0
  201. package/dist/src/indexed/min-cut.d.ts.map +1 -0
  202. package/dist/src/indexed/min-cut.js +175 -0
  203. package/dist/src/indexed/min-cut.js.map +1 -0
  204. package/dist/src/indexed/modularity.d.ts +34 -0
  205. package/dist/src/indexed/modularity.d.ts.map +1 -0
  206. package/dist/src/indexed/modularity.js +74 -0
  207. package/dist/src/indexed/modularity.js.map +1 -0
  208. package/dist/src/indexed/mst.d.ts +29 -1
  209. package/dist/src/indexed/mst.d.ts.map +1 -1
  210. package/dist/src/indexed/mst.js +62 -0
  211. package/dist/src/indexed/mst.js.map +1 -1
  212. package/dist/src/indexed/pagerank.d.ts +29 -6
  213. package/dist/src/indexed/pagerank.d.ts.map +1 -1
  214. package/dist/src/indexed/pagerank.js +107 -11
  215. package/dist/src/indexed/pagerank.js.map +1 -1
  216. package/dist/src/indexed/point-to-point.d.ts +53 -0
  217. package/dist/src/indexed/point-to-point.d.ts.map +1 -0
  218. package/dist/src/indexed/point-to-point.js +173 -0
  219. package/dist/src/indexed/point-to-point.js.map +1 -0
  220. package/dist/src/indexed/scc.d.ts +53 -0
  221. package/dist/src/indexed/scc.d.ts.map +1 -0
  222. package/dist/src/indexed/scc.js +110 -0
  223. package/dist/src/indexed/scc.js.map +1 -0
  224. package/dist/src/indexed/spectral.d.ts +61 -0
  225. package/dist/src/indexed/spectral.d.ts.map +1 -0
  226. package/dist/src/indexed/spectral.js +476 -0
  227. package/dist/src/indexed/spectral.js.map +1 -0
  228. package/dist/src/indexed/structures/bit-set.d.ts +45 -0
  229. package/dist/src/indexed/structures/bit-set.d.ts.map +1 -0
  230. package/dist/src/indexed/structures/bit-set.js +57 -0
  231. package/dist/src/indexed/structures/bit-set.js.map +1 -0
  232. package/dist/src/indexed/structures/max-heap.d.ts +52 -0
  233. package/dist/src/indexed/structures/max-heap.d.ts.map +1 -0
  234. package/dist/src/indexed/structures/max-heap.js +66 -0
  235. package/dist/src/indexed/structures/max-heap.js.map +1 -0
  236. package/dist/src/indexed/structures/min-heap.d.ts +30 -1
  237. package/dist/src/indexed/structures/min-heap.d.ts.map +1 -1
  238. package/dist/src/indexed/structures/min-heap.js +46 -6
  239. package/dist/src/indexed/structures/min-heap.js.map +1 -1
  240. package/dist/src/indexed/structures/ring-queue.d.ts +41 -0
  241. package/dist/src/indexed/structures/ring-queue.d.ts.map +1 -0
  242. package/dist/src/indexed/structures/ring-queue.js +64 -0
  243. package/dist/src/indexed/structures/ring-queue.js.map +1 -0
  244. package/dist/src/indexed/sync.d.ts +50 -0
  245. package/dist/src/indexed/sync.d.ts.map +1 -0
  246. package/dist/src/indexed/sync.js +175 -0
  247. package/dist/src/indexed/sync.js.map +1 -0
  248. package/dist/src/indexed/terahac.d.ts +58 -0
  249. package/dist/src/indexed/terahac.d.ts.map +1 -0
  250. package/dist/src/indexed/terahac.js +244 -0
  251. package/dist/src/indexed/terahac.js.map +1 -0
  252. package/dist/src/indexed/to-snapshot.d.ts +45 -2
  253. package/dist/src/indexed/to-snapshot.d.ts.map +1 -1
  254. package/dist/src/indexed/to-snapshot.js +140 -6
  255. package/dist/src/indexed/to-snapshot.js.map +1 -1
  256. package/dist/src/link-prediction/common-neighbors-legacy.d.ts +71 -0
  257. package/dist/src/link-prediction/common-neighbors-legacy.d.ts.map +1 -0
  258. package/dist/src/link-prediction/common-neighbors-legacy.js +172 -0
  259. package/dist/src/link-prediction/common-neighbors-legacy.js.map +1 -0
  260. package/dist/src/link-prediction/common-neighbors.d.ts +11 -19
  261. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
  262. package/dist/src/link-prediction/common-neighbors.js +56 -123
  263. package/dist/src/link-prediction/common-neighbors.js.map +1 -1
  264. package/dist/src/optimized/direction-optimized-bfs.d.ts +6 -0
  265. package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -1
  266. package/dist/src/optimized/direction-optimized-bfs.js +6 -0
  267. package/dist/src/optimized/direction-optimized-bfs.js.map +1 -1
  268. package/dist/src/research/grsbm-legacy.d.ts +82 -0
  269. package/dist/src/research/grsbm-legacy.d.ts.map +1 -0
  270. package/dist/src/research/grsbm-legacy.js +416 -0
  271. package/dist/src/research/grsbm-legacy.js.map +1 -0
  272. package/dist/src/research/grsbm.d.ts +9 -66
  273. package/dist/src/research/grsbm.d.ts.map +1 -1
  274. package/dist/src/research/grsbm.js +67 -391
  275. package/dist/src/research/grsbm.js.map +1 -1
  276. package/dist/src/research/sync-legacy.d.ts +48 -0
  277. package/dist/src/research/sync-legacy.d.ts.map +1 -0
  278. package/dist/src/research/sync-legacy.js +337 -0
  279. package/dist/src/research/sync-legacy.js.map +1 -0
  280. package/dist/src/research/sync.d.ts +10 -32
  281. package/dist/src/research/sync.d.ts.map +1 -1
  282. package/dist/src/research/sync.js +28 -316
  283. package/dist/src/research/sync.js.map +1 -1
  284. package/package.json +4 -3
  285. package/src/algorithms/centrality/betweenness.ts +51 -1
  286. package/src/algorithms/centrality/closeness.ts +112 -12
  287. package/src/algorithms/centrality/degree.ts +19 -0
  288. package/src/algorithms/centrality/eigenvector.ts +34 -0
  289. package/src/algorithms/centrality/hits.ts +24 -0
  290. package/src/algorithms/centrality/katz.ts +32 -0
  291. package/src/algorithms/centrality/pagerank.ts +53 -13
  292. package/src/algorithms/community/girvan-newman-legacy.ts +414 -0
  293. package/src/algorithms/community/girvan-newman.ts +36 -386
  294. package/src/algorithms/community/label-propagation.ts +24 -133
  295. package/src/algorithms/components/connected.ts +28 -95
  296. package/src/algorithms/mst/kruskal.ts +65 -4
  297. package/src/algorithms/shortest-path/bellman-ford.ts +49 -0
  298. package/src/algorithms/shortest-path/dijkstra.ts +29 -0
  299. package/src/algorithms/shortest-path/floyd-warshall.ts +106 -136
  300. package/src/algorithms/traversal/bfs-unified.ts +52 -366
  301. package/src/algorithms/traversal/bfs-variants.ts +5 -28
  302. package/src/algorithms/traversal/bfs.ts +0 -4
  303. package/src/algorithms/traversal/dfs.ts +39 -182
  304. package/src/clustering/hierarchical-legacy.ts +551 -0
  305. package/src/clustering/hierarchical.ts +64 -520
  306. package/src/clustering/k-core-legacy.ts +229 -0
  307. package/src/clustering/k-core.ts +38 -209
  308. package/src/clustering/mcl-legacy.ts +498 -0
  309. package/src/clustering/mcl.ts +46 -479
  310. package/src/index.ts +90 -3
  311. package/src/indexed/accelerator.ts +502 -16
  312. package/src/indexed/all-pairs.ts +342 -0
  313. package/src/indexed/bellman-ford.ts +72 -0
  314. package/src/indexed/betweenness.ts +258 -0
  315. package/src/indexed/bfs.ts +189 -3
  316. package/src/indexed/bipartite.ts +77 -0
  317. package/src/indexed/closeness.ts +160 -0
  318. package/src/indexed/common-neighbors.ts +31 -14
  319. package/src/indexed/degree.ts +55 -0
  320. package/src/indexed/delta-pagerank.ts +513 -0
  321. package/src/indexed/dfs.ts +189 -0
  322. package/src/indexed/eigenvector.ts +202 -0
  323. package/src/indexed/facade.ts +229 -0
  324. package/src/indexed/flow.ts +500 -0
  325. package/src/indexed/girvan-newman.ts +120 -0
  326. package/src/indexed/grsbm.ts +390 -0
  327. package/src/indexed/hierarchical.ts +295 -0
  328. package/src/indexed/index.ts +94 -3
  329. package/src/indexed/isomorphism.ts +305 -0
  330. package/src/indexed/label-propagation.ts +582 -0
  331. package/src/indexed/leiden.ts +436 -0
  332. package/src/indexed/link-prediction.ts +399 -0
  333. package/src/indexed/markov.ts +324 -0
  334. package/src/indexed/matching.ts +192 -0
  335. package/src/indexed/min-cut.ts +201 -0
  336. package/src/indexed/modularity.ts +81 -0
  337. package/src/indexed/mst.ts +79 -1
  338. package/src/indexed/pagerank.ts +128 -15
  339. package/src/indexed/point-to-point.ts +220 -0
  340. package/src/indexed/scc.ts +132 -0
  341. package/src/indexed/spectral.ts +550 -0
  342. package/src/indexed/structures/bit-set.ts +65 -0
  343. package/src/indexed/structures/max-heap.ts +74 -0
  344. package/src/indexed/structures/min-heap.ts +51 -6
  345. package/src/indexed/structures/ring-queue.ts +70 -0
  346. package/src/indexed/sync.ts +229 -0
  347. package/src/indexed/terahac.ts +290 -0
  348. package/src/indexed/to-snapshot.ts +156 -6
  349. package/src/link-prediction/common-neighbors-legacy.ts +252 -0
  350. package/src/link-prediction/common-neighbors.ts +65 -168
  351. package/src/optimized/direction-optimized-bfs.ts +6 -1
  352. package/src/research/grsbm-legacy.ts +586 -0
  353. package/src/research/grsbm.ts +76 -555
  354. package/src/research/sync-legacy.ts +456 -0
  355. package/src/research/sync.ts +30 -431
@@ -1,411 +1,49 @@
1
1
  /**
2
2
  * Hierarchical Clustering Algorithm
3
3
  *
4
- * Builds a hierarchy of clusters through agglomeration (bottom-up)
5
- * or division (top-down). Useful for understanding multi-scale
6
- * structure in graphs.
4
+ * Builds a hierarchy of clusters through agglomeration (bottom-up). `hierarchicalClustering`
5
+ * delegates to `indexed.hierarchicalClustering` over an unweighted snapshot of the graph (hop
6
+ * distances never read a weight) and rebuilds the legacy dendrogram from its merges; the result
7
+ * equals the pre-migration implementation in `hierarchical-legacy.ts` exactly.
7
8
  */
8
9
 
9
10
  import type { Graph } from "../core/graph.js";
11
+ import { hierarchicalClustering as indexedHierarchicalClustering } from "../indexed/hierarchical.js";
12
+ import { toTopologySnapshot } from "../indexed/to-snapshot.js";
13
+ import {
14
+ type ClusterNode,
15
+ cutDendrogram,
16
+ hierarchicalClustering as legacyHierarchicalClustering,
17
+ type HierarchicalClusteringResult,
18
+ type LinkageMethod,
19
+ } from "./hierarchical-legacy.js";
10
20
 
11
- /**
12
- * Convert Graph to adjacency set representation for clustering
13
- * @param graph - The input graph to convert
14
- * @returns Map of node IDs to sets of neighbor node IDs
15
- */
16
- function graphToAdjacencySet(graph: Graph): Map<string, Set<string>> {
17
- const adjacency = new Map<string, Set<string>>();
18
-
19
- // Initialize all nodes
20
- for (const node of graph.nodes()) {
21
- adjacency.set(String(node.id), new Set());
22
- }
23
-
24
- // Add edges
25
- for (const edge of graph.edges()) {
26
- const source = String(edge.source);
27
- const target = String(edge.target);
28
-
29
- const sourceSet = adjacency.get(source);
30
- if (sourceSet) {
31
- sourceSet.add(target);
32
- }
21
+ export type { ClusterNode, HierarchicalClusteringResult, LinkageMethod } from "./hierarchical-legacy.js";
22
+ export { cutDendrogram, cutDendrogramKClusters, modularityHierarchicalClustering } from "./hierarchical-legacy.js";
33
23
 
34
- // For undirected graphs, add reverse edge
35
- if (!graph.isDirected) {
36
- const targetSet = adjacency.get(target);
37
- if (targetSet) {
38
- targetSet.add(source);
39
- }
40
- }
41
- }
42
-
43
- return adjacency;
44
- }
45
-
46
- export interface ClusterNode<T> {
47
- id: string;
48
- members: Set<T>;
49
- left?: ClusterNode<T> | undefined;
50
- right?: ClusterNode<T> | undefined;
51
- distance: number;
52
- height: number;
53
- // For forest roots, store the individual trees
54
- trees?: ClusterNode<T>[] | undefined;
55
- }
56
-
57
- export interface HierarchicalClusteringResult<T> {
58
- root: ClusterNode<T>;
59
- dendrogram: ClusterNode<T>[];
60
- clusters: Map<number, Set<T>[]>;
61
- }
62
-
63
- export type LinkageMethod = "single" | "complete" | "average" | "ward";
24
+ const LINKAGES: readonly string[] = ["single", "complete", "average", "ward"];
64
25
 
65
26
  /**
66
- * Compute distance between two nodes based on graph structure
67
- * @param graph - Adjacency map representation of the graph
68
- * @param distances - Map to store computed distances between nodes
69
- */
70
- function computeGraphDistance<T>(graph: Map<T, Set<T>>, distances: Map<T, Map<T, number>>): void {
71
- // Use BFS to compute shortest path distances
72
- for (const start of graph.keys()) {
73
- const dist = new Map<T, number>();
74
- const queue: T[] = [start];
75
- dist.set(start, 0);
76
-
77
- while (queue.length > 0) {
78
- const node = queue.shift();
79
- if (!node) {
80
- continue;
81
- }
82
-
83
- const neighbors = graph.get(node);
84
-
85
- if (neighbors) {
86
- for (const neighbor of neighbors) {
87
- if (!dist.has(neighbor)) {
88
- dist.set(neighbor, (dist.get(node) ?? 0) + 1);
89
- queue.push(neighbor);
90
- }
91
- }
92
- }
93
- }
94
-
95
- distances.set(start, dist);
96
- }
97
- }
98
-
99
- /**
100
- * Compute distance between two clusters based on linkage method
101
- * @param cluster1 - First cluster node
102
- * @param cluster2 - Second cluster node
103
- * @param distances - Precomputed distance matrix between nodes
104
- * @param linkage - Linkage method to use for computing cluster distance
105
- * @returns The distance between the two clusters
106
- */
107
- function clusterDistance<T>(
108
- cluster1: ClusterNode<T>,
109
- cluster2: ClusterNode<T>,
110
- distances: Map<T, Map<T, number>>,
111
- linkage: LinkageMethod,
112
- ): number {
113
- const allDistances: number[] = [];
114
-
115
- for (const node1 of cluster1.members) {
116
- const node1Distances = distances.get(node1);
117
- if (!node1Distances) {
118
- continue;
119
- }
120
-
121
- for (const node2 of cluster2.members) {
122
- const dist = node1Distances.get(node2);
123
- if (dist !== undefined) {
124
- allDistances.push(dist);
125
- }
126
- }
127
- }
128
-
129
- if (allDistances.length === 0) {
130
- return Infinity;
131
- }
132
-
133
- switch (linkage) {
134
- case "single":
135
- return Math.min(...allDistances);
136
- case "complete":
137
- return Math.max(...allDistances);
138
- case "average":
139
- return allDistances.reduce((a, b) => a + b, 0) / allDistances.length;
140
- case "ward": {
141
- // Simplified Ward's method - minimize within-cluster variance
142
- const size1 = cluster1.members.size;
143
- const size2 = cluster2.members.size;
144
- const avgDist = allDistances.reduce((a, b) => a + b, 0) / allDistances.length;
145
- return avgDist * ((size1 * size2) / (size1 + size2));
146
- }
147
- default:
148
- return Math.min(...allDistances);
149
- }
150
- }
151
-
152
- /**
153
- * Internal implementation of agglomerative hierarchical clustering
154
- * @param graph - Adjacency map representation of the graph
155
- * @param linkage - Linkage method for cluster distance computation
156
- * @returns Hierarchical clustering result with dendrogram and cluster assignments
27
+ * Agglomerative hierarchical clustering
28
+ * Builds clusters bottom-up by merging closest pairs
29
+ * @param graph - Undirected graph - accepts Graph class or Map<T, Set<T>>
30
+ * @param linkage - Linkage method for cluster distance
31
+ * @returns Hierarchical clustering result
32
+ *
33
+ * Time Complexity: O(n³) naive, O(n² log n) with heap
34
+ * Space Complexity: O(n²)
157
35
  */
158
- function hierarchicalClusteringImpl<T>(
159
- graph: Map<T, Set<T>>,
36
+ export function hierarchicalClustering(
37
+ graph: Graph,
160
38
  linkage: LinkageMethod = "single",
161
- ): HierarchicalClusteringResult<T> {
162
- const nodes = Array.from(graph.keys());
163
- const n = nodes.length;
164
-
165
- if (n === 0) {
166
- return {
167
- root: { id: "empty", members: new Set(), distance: 0, height: 0 },
168
- dendrogram: [],
169
- clusters: new Map(),
170
- };
171
- }
172
-
173
- // Compute pairwise distances
174
- const distances = new Map<T, Map<T, number>>();
175
- computeGraphDistance(graph, distances);
176
-
177
- // Initialize clusters - each node is its own cluster
178
- const clusters: ClusterNode<T>[] = nodes.map((node, i) => ({
179
- id: `leaf-${String(i)}`,
180
- members: new Set([node]),
181
- distance: 0,
182
- height: 0,
183
- }));
184
-
185
- const dendrogram: ClusterNode<T>[] = [...clusters];
186
- let clusterCount = n;
187
-
188
- // Distance matrix between clusters
189
- const clusterDistances = new Map<string, Map<string, number>>();
190
-
191
- // Initialize cluster distances
192
- for (let i = 0; i < clusters.length; i++) {
193
- const cluster1 = clusters[i];
194
- if (!cluster1) {
195
- continue;
196
- }
197
-
198
- const distMap = new Map<string, number>();
199
- for (let j = i + 1; j < clusters.length; j++) {
200
- const cluster2 = clusters[j];
201
- if (!cluster2) {
202
- continue;
203
- }
204
-
205
- const dist = clusterDistance(cluster1, cluster2, distances, linkage);
206
- distMap.set(cluster2.id, dist);
207
- }
208
- clusterDistances.set(cluster1.id, distMap);
209
- }
210
-
211
- // Active clusters
212
- const activeClusters = new Set(clusters);
213
-
214
- // Merge clusters until only one remains
215
- while (activeClusters.size > 1) {
216
- // Find closest pair of clusters
217
- let minDist = Infinity;
218
- let mergeCluster1: ClusterNode<T> | null = null;
219
- let mergeCluster2: ClusterNode<T> | null = null;
220
-
221
- for (const cluster1 of activeClusters) {
222
- const distMap = clusterDistances.get(cluster1.id);
223
- if (!distMap) {
224
- continue;
225
- }
226
-
227
- for (const cluster2 of activeClusters) {
228
- if (cluster1.id >= cluster2.id) {
229
- continue;
230
- }
231
-
232
- const dist =
233
- distMap.get(cluster2.id) ?? clusterDistances.get(cluster2.id)?.get(cluster1.id) ?? Infinity;
234
-
235
- if (dist < minDist) {
236
- minDist = dist;
237
- mergeCluster1 = cluster1;
238
- mergeCluster2 = cluster2;
239
- }
240
- }
241
- }
242
-
243
- if (!mergeCluster1 || !mergeCluster2 || minDist === Infinity) {
244
- // No valid merge found - create forest
245
- const trees = Array.from(activeClusters);
246
- const forestRoot: ClusterNode<T> = {
247
- id: `forest-${String(clusterCount++)}`,
248
- members: new Set(nodes),
249
- distance: Infinity,
250
- height: Math.max(...trees.map((t) => t.height)) + 1,
251
- trees,
252
- };
253
- dendrogram.push(forestRoot);
254
- activeClusters.clear();
255
- activeClusters.add(forestRoot);
256
- break;
257
- }
258
-
259
- // Create new cluster
260
- const newCluster: ClusterNode<T> = {
261
- id: `cluster-${String(clusterCount++)}`,
262
- members: new Set([...mergeCluster1.members, ...mergeCluster2.members]),
263
- left: mergeCluster1,
264
- right: mergeCluster2,
265
- distance: minDist,
266
- height: Math.max(mergeCluster1.height, mergeCluster2.height) + 1,
267
- };
268
-
269
- dendrogram.push(newCluster);
270
-
271
- // Update distances to new cluster
272
- const newDistMap = new Map<string, number>();
273
- for (const cluster of activeClusters) {
274
- if (cluster.id === mergeCluster1.id || cluster.id === mergeCluster2.id) {
275
- continue;
276
- }
277
-
278
- const dist = clusterDistance(newCluster, cluster, distances, linkage);
279
- newDistMap.set(cluster.id, dist);
280
-
281
- // Update reverse direction
282
- const clusterDistMap = clusterDistances.get(cluster.id);
283
- if (clusterDistMap) {
284
- clusterDistMap.set(newCluster.id, dist);
285
- }
286
- }
287
- clusterDistances.set(newCluster.id, newDistMap);
288
-
289
- // Remove merged clusters
290
- activeClusters.delete(mergeCluster1);
291
- activeClusters.delete(mergeCluster2);
292
- clusterDistances.delete(mergeCluster1.id);
293
- clusterDistances.delete(mergeCluster2.id);
294
-
295
- // Clean up references
296
- for (const distMap of clusterDistances.values()) {
297
- distMap.delete(mergeCluster1.id);
298
- distMap.delete(mergeCluster2.id);
299
- }
300
-
301
- activeClusters.add(newCluster);
302
- }
303
-
304
- // Root is the last remaining cluster
305
- const root = activeClusters.size > 0 ? Array.from(activeClusters)[0] : dendrogram[dendrogram.length - 1];
306
-
307
- // Generate clusters at different heights
308
- const clustersByLevel = new Map<number, Set<T>[]>();
309
-
310
- if (!root) {
311
- return {
312
- root: { id: "empty", members: new Set(), distance: 0, height: 0 },
313
- dendrogram: [],
314
- clusters: new Map(),
315
- };
316
- }
317
-
318
- for (let h = 0; h <= root.height; h++) {
319
- clustersByLevel.set(h, cutDendrogram(root, h));
320
- }
321
-
322
- return {
323
- root,
324
- dendrogram,
325
- clusters: clustersByLevel,
326
- };
327
- }
328
-
329
- /**
330
- * Cut dendrogram at specific height to get clusters
331
- * @param root - Root node of the dendrogram
332
- * @param height - Height at which to cut the dendrogram
333
- * @returns Array of sets representing clusters at the specified height
334
- */
335
- export function cutDendrogram<T>(root: ClusterNode<T>, height: number): Set<T>[] {
336
- const clusters: Set<T>[] = [];
337
-
338
- function traverse(node: ClusterNode<T>): void {
339
- if (node.height <= height || (!node.left && !node.right)) {
340
- clusters.push(node.members);
341
- } else {
342
- if (node.trees) {
343
- // Handle forest nodes
344
- for (const tree of node.trees) {
345
- traverse(tree);
346
- }
347
- } else {
348
- if (node.left) {
349
- traverse(node.left);
350
- }
351
-
352
- if (node.right) {
353
- traverse(node.right);
354
- }
355
- }
356
- }
357
- }
358
-
359
- traverse(root);
360
- return clusters;
361
- }
362
-
363
- /**
364
- * Cut dendrogram to get exactly k clusters
365
- * @param root - Root node of the dendrogram
366
- * @param k - Target number of clusters
367
- * @returns Array of sets representing exactly k clusters
368
- */
369
- export function cutDendrogramKClusters<T>(root: ClusterNode<T>, k: number): Set<T>[] {
370
- if (k <= 0) {
371
- return [];
372
- }
373
-
374
- if (k === 1) {
375
- return [root.members];
376
- }
377
-
378
- // Binary search for the right height
379
- let low = 0;
380
- let high = root.height;
381
-
382
- while (low < high) {
383
- const mid = Math.floor((low + high) / 2);
384
- const clusters = cutDendrogram(root, mid);
385
-
386
- if (clusters.length === k) {
387
- return clusters;
388
- } else if (clusters.length < k) {
389
- high = mid;
390
- } else {
391
- low = mid + 1;
392
- }
39
+ ): HierarchicalClusteringResult<string> {
40
+ const s = toTopologySnapshot(graph);
41
+ const n = s.nodeCount;
42
+ const names = Array.from({ length: n }, (_, i) => String(s.ids.idOf(i)));
43
+ // The old code keys nodes by String(id), so ids spelled alike (1 and "1") are one node to it.
44
+ if (new Set(names).size !== n) {
45
+ return legacyHierarchicalClustering(graph, linkage);
393
46
  }
394
-
395
- return cutDendrogram(root, low);
396
- }
397
-
398
- /**
399
- * Compute modularity-based hierarchical clustering
400
- * Uses modularity gain to decide merges
401
- * @param graph - The input graph to cluster
402
- * @returns Hierarchical clustering result with dendrogram and cluster assignments
403
- */
404
- export function modularityHierarchicalClustering(graph: Graph): HierarchicalClusteringResult<string> {
405
- const adjacencySet = graphToAdjacencySet(graph);
406
- const nodes = Array.from(adjacencySet.keys());
407
- const n = nodes.length;
408
-
409
47
  if (n === 0) {
410
48
  return {
411
49
  root: { id: "empty", members: new Set(), distance: 0, height: 0 },
@@ -413,139 +51,45 @@ export function modularityHierarchicalClustering(graph: Graph): HierarchicalClus
413
51
  clusters: new Map(),
414
52
  };
415
53
  }
54
+ // An unknown linkage falls through to single linkage, as it always has.
55
+ const r = indexedHierarchicalClustering(s, { linkage: LINKAGES.includes(linkage) ? linkage : "single" });
416
56
 
417
- // Compute degrees
418
- const degrees = new Map<string, number>();
419
- let totalEdges = 0;
420
-
421
- for (const [node, neighbors] of adjacencySet) {
422
- degrees.set(node, neighbors.size);
423
- totalEdges += neighbors.size;
424
- }
425
-
426
- // For undirected graphs
427
- totalEdges = totalEdges / 2;
428
-
429
- // Initialize clusters
430
- const clusters: ClusterNode<string>[] = nodes.map((node, i) => ({
57
+ const dendrogram: ClusterNode<string>[] = names.map((name, i) => ({
431
58
  id: `leaf-${String(i)}`,
432
- members: new Set([node]),
59
+ members: new Set([name]),
433
60
  distance: 0,
434
61
  height: 0,
435
62
  }));
436
-
437
- const dendrogram: ClusterNode<string>[] = [...clusters];
438
- let clusterCount = n;
439
-
440
- // Active clusters
441
- const activeClusters = new Set(clusters);
442
-
443
- // Community assignments
444
- const communities = new Map<string, number>();
445
- nodes.forEach((node, i) => communities.set(node, i));
446
-
447
- // Merge clusters based on modularity gain
448
- while (activeClusters.size > 1) {
449
- let maxGain = -Infinity;
450
- let mergeCluster1: ClusterNode<string> | null = null;
451
- let mergeCluster2: ClusterNode<string> | null = null;
452
-
453
- for (const cluster1 of activeClusters) {
454
- for (const cluster2 of activeClusters) {
455
- if (cluster1.id >= cluster2.id) {
456
- continue;
457
- }
458
-
459
- // Calculate modularity gain
460
- let edgesBetween = 0;
461
- let degreeProduct = 0;
462
-
463
- for (const node1 of cluster1.members) {
464
- const neighbors = adjacencySet.get(node1);
465
- const degree1 = degrees.get(node1) ?? 0;
466
-
467
- for (const node2 of cluster2.members) {
468
- if (neighbors?.has(node2)) {
469
- edgesBetween++;
470
- }
471
-
472
- const degree2 = degrees.get(node2) ?? 0;
473
- degreeProduct += degree1 * degree2;
474
- }
475
- }
476
-
477
- const gain = edgesBetween / totalEdges - degreeProduct / (4 * totalEdges * totalEdges);
478
-
479
- if (gain > maxGain) {
480
- maxGain = gain;
481
- mergeCluster1 = cluster1;
482
- mergeCluster2 = cluster2;
483
- }
484
- }
485
- }
486
-
487
- if (!mergeCluster1 || !mergeCluster2) {
488
- break;
489
- }
490
-
491
- // Create new cluster
492
- const newCluster: ClusterNode<string> = {
493
- id: `cluster-${String(clusterCount++)}`,
494
- members: new Set([...mergeCluster1.members, ...mergeCluster2.members]),
495
- left: mergeCluster1,
496
- right: mergeCluster2,
497
- distance: -maxGain, // Use negative gain as distance
498
- height: Math.max(mergeCluster1.height, mergeCluster2.height) + 1,
499
- };
500
-
501
- dendrogram.push(newCluster);
502
-
503
- // Remove old and add new
504
- activeClusters.delete(mergeCluster1);
505
- activeClusters.delete(mergeCluster2);
506
- activeClusters.add(newCluster);
507
- }
508
-
509
- // Root is the last remaining cluster
510
- const root = Array.from(activeClusters)[0] ?? dendrogram[dendrogram.length - 1];
511
-
512
- // Generate clusters at different heights
513
- const clustersByLevel = new Map<number, Set<string>[]>();
514
-
515
- if (!root) {
516
- return {
517
- root: { id: "empty", members: new Set(), distance: 0, height: 0 },
518
- dendrogram: [],
519
- clusters: new Map(),
63
+ for (let k = 0; k < r.left.length; k++) {
64
+ const left = dendrogram[r.left[k]];
65
+ const right = dendrogram[r.right[k]];
66
+ dendrogram.push({
67
+ id: `cluster-${String(n + k)}`,
68
+ members: new Set([...left.members, ...right.members]),
69
+ left,
70
+ right,
71
+ distance: r.distance[k],
72
+ height: r.height[n + k],
73
+ });
74
+ }
75
+ let root: ClusterNode<string>;
76
+ if (r.roots.length === 1) {
77
+ root = dendrogram[r.roots[0]];
78
+ } else {
79
+ const trees = Array.from(r.roots, (c) => dendrogram[c]);
80
+ root = {
81
+ id: `forest-${String(dendrogram.length)}`,
82
+ members: new Set(names),
83
+ distance: Infinity,
84
+ height: Math.max(...trees.map((t) => t.height)) + 1,
85
+ trees,
520
86
  };
87
+ dendrogram.push(root);
521
88
  }
522
89
 
90
+ const clusters = new Map<number, Set<string>[]>();
523
91
  for (let h = 0; h <= root.height; h++) {
524
- clustersByLevel.set(h, cutDendrogram(root, h));
92
+ clusters.set(h, cutDendrogram(root, h));
525
93
  }
526
-
527
- return {
528
- root,
529
- dendrogram,
530
- clusters: clustersByLevel,
531
- };
532
- }
533
-
534
- /**
535
- * Agglomerative hierarchical clustering
536
- * Builds clusters bottom-up by merging closest pairs
537
- * @param graph - Undirected graph - accepts Graph class or Map<T, Set<T>>
538
- * @param linkage - Linkage method for cluster distance
539
- * @returns Hierarchical clustering result
540
- *
541
- * Time Complexity: O(n³) naive, O(n² log n) with heap
542
- * Space Complexity: O(n²)
543
- */
544
- export function hierarchicalClustering(
545
- graph: Graph,
546
- linkage: LinkageMethod = "single",
547
- ): HierarchicalClusteringResult<string> {
548
- // Convert Graph to adjacency set representation
549
- const adjacencySet = graphToAdjacencySet(graph);
550
- return hierarchicalClusteringImpl(adjacencySet, linkage);
94
+ return { root, dendrogram, clusters };
551
95
  }