@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
@@ -0,0 +1,586 @@
1
+ import type { Graph } from "../core/graph.js";
2
+ import type { NodeId } from "../types/index.js";
3
+ import { SeededRandom } from "../utils/math-utilities.js";
4
+
5
+ /**
6
+ * Configuration options for the GRSBM (Greedy Recursive Spectral Bisection) algorithm
7
+ */
8
+ export interface GRSBMConfig {
9
+ /** Maximum depth of recursive bisection */
10
+ maxDepth?: number;
11
+ /** Minimum cluster size to continue splitting */
12
+ minClusterSize?: number;
13
+ /** Number of eigenvectors to use for spectral embedding */
14
+ numEigenvectors?: number;
15
+ /** Convergence tolerance for eigenvalue computation */
16
+ tolerance?: number;
17
+ /** Maximum number of power iterations for eigenvalue computation */
18
+ maxIterations?: number;
19
+ /** Random seed for reproducibility */
20
+ seed?: number;
21
+ }
22
+
23
+ /**
24
+ * Represents a cluster in the hierarchical structure
25
+ */
26
+ export interface GRSBMCluster {
27
+ /** Unique identifier for this cluster */
28
+ id: string;
29
+ /** Node IDs in this cluster */
30
+ members: Set<NodeId>;
31
+ /** Left child cluster (if split) */
32
+ left?: GRSBMCluster;
33
+ /** Right child cluster (if split) */
34
+ right?: GRSBMCluster;
35
+ /** Modularity score of this cluster */
36
+ modularity: number;
37
+ /** Depth in the hierarchy */
38
+ depth: number;
39
+ /** Spectral embedding quality score */
40
+ spectralScore: number;
41
+ }
42
+
43
+ /**
44
+ * Result of the GRSBM clustering algorithm
45
+ */
46
+ export interface GRSBMResult {
47
+ /** Root of the cluster hierarchy */
48
+ root: GRSBMCluster;
49
+ /** Flat clustering at leaf level */
50
+ clusters: Map<NodeId, number>;
51
+ /** Number of final clusters */
52
+ numClusters: number;
53
+ /** Modularity scores for each level */
54
+ modularityScores: number[];
55
+ /** Explanation of the clustering structure */
56
+ explanation: ClusterExplanation[];
57
+ }
58
+
59
+ /**
60
+ * Explanation for a cluster split decision
61
+ */
62
+ export interface ClusterExplanation {
63
+ /** Cluster that was split */
64
+ clusterId: string;
65
+ /** Reason for the split */
66
+ reason: string;
67
+ /** Modularity improvement from the split */
68
+ modularityImprovement: number;
69
+ /** Key nodes that influenced the split */
70
+ keyNodes: NodeId[];
71
+ /** Spectral embedding values */
72
+ spectralValues: number[];
73
+ }
74
+
75
+ /**
76
+ * GRSBM - Greedy Recursive Spectral Bisection with Modularity
77
+ *
78
+ * This algorithm performs hierarchical community detection using spectral
79
+ * bisection guided by modularity optimization. It provides explainable
80
+ * community structure by tracking the reasoning behind each split.
81
+ *
82
+ * Based on: "Explainable Community Detection via Hierarchical Spectral Clustering" (2024)
83
+ * @param graph - Input graph to cluster
84
+ * @param config - Configuration options
85
+ * @returns Hierarchical clustering result with explanations
86
+ */
87
+ export function grsbm(graph: Graph, config: GRSBMConfig = {}): GRSBMResult {
88
+ const {
89
+ maxDepth = 10,
90
+ minClusterSize = 2, // Reduced default to allow more splits
91
+ numEigenvectors = 2,
92
+ tolerance = 1e-6,
93
+ maxIterations = 100,
94
+ seed = 42,
95
+ } = config;
96
+
97
+ // Set random seed for reproducibility
98
+ const rng = SeededRandom.createGenerator(seed);
99
+ const originalRandom = Math.random;
100
+ Math.random = rng;
101
+
102
+ const nodes = Array.from(graph.nodes());
103
+ const nodeCount = nodes.length;
104
+
105
+ if (nodeCount === 0) {
106
+ throw new Error("Cannot cluster empty graph");
107
+ }
108
+
109
+ // Initialize root cluster with all nodes
110
+ const rootMembers = new Set(nodes.map((node) => node.id));
111
+ const initialModularity = calculateModularity(graph, new Map([...rootMembers].map((id) => [id, 0])));
112
+
113
+ const root: GRSBMCluster = {
114
+ id: "root",
115
+ members: rootMembers,
116
+ modularity: initialModularity,
117
+ depth: 0,
118
+ spectralScore: 0,
119
+ };
120
+
121
+ const explanations: ClusterExplanation[] = [];
122
+ const modularityScores: number[] = [initialModularity];
123
+
124
+ // Perform recursive bisection
125
+ const clusterQueue: GRSBMCluster[] = [root];
126
+ let nextClusterId = 1;
127
+
128
+ while (clusterQueue.length > 0) {
129
+ const currentCluster = clusterQueue.shift();
130
+ if (!currentCluster) {
131
+ continue;
132
+ }
133
+
134
+ // Check stopping criteria
135
+ if (currentCluster.depth >= maxDepth || currentCluster.members.size < minClusterSize * 2) {
136
+ continue;
137
+ }
138
+
139
+ // Attempt spectral bisection
140
+ const bisectionResult = spectralBisection(graph, currentCluster, numEigenvectors, tolerance, maxIterations);
141
+
142
+ if (!bisectionResult) {
143
+ continue; // Could not split this cluster
144
+ }
145
+
146
+ const { leftMembers, rightMembers, spectralScore, keyNodes, spectralValues, reason } = bisectionResult;
147
+
148
+ // Create child clusters
149
+ const leftCluster: GRSBMCluster = {
150
+ id: `cluster_${String(nextClusterId++)}`,
151
+ members: leftMembers,
152
+ modularity: 0, // Will be calculated below
153
+ depth: currentCluster.depth + 1,
154
+ spectralScore,
155
+ };
156
+
157
+ const rightCluster: GRSBMCluster = {
158
+ id: `cluster_${String(nextClusterId++)}`,
159
+ members: rightMembers,
160
+ modularity: 0, // Will be calculated below
161
+ depth: currentCluster.depth + 1,
162
+ spectralScore,
163
+ };
164
+
165
+ // Calculate modularity improvement
166
+ const newAssignment = new Map<NodeId, number>();
167
+ for (const nodeId of leftMembers) {
168
+ newAssignment.set(nodeId, 0);
169
+ }
170
+ for (const nodeId of rightMembers) {
171
+ newAssignment.set(nodeId, 1);
172
+ }
173
+
174
+ const newModularity = calculateModularity(graph, newAssignment);
175
+ const modularityImprovement = newModularity - currentCluster.modularity;
176
+
177
+ // Only split if modularity improves or is neutral (allow small splits)
178
+ if (modularityImprovement >= -0.01) {
179
+ // Small tolerance for neutral splits
180
+ leftCluster.modularity = newModularity;
181
+ rightCluster.modularity = newModularity;
182
+
183
+ currentCluster.left = leftCluster;
184
+ currentCluster.right = rightCluster;
185
+
186
+ // Add explanation
187
+ explanations.push({
188
+ clusterId: currentCluster.id,
189
+ reason,
190
+ modularityImprovement,
191
+ keyNodes,
192
+ spectralValues,
193
+ });
194
+
195
+ modularityScores.push(newModularity);
196
+
197
+ // Add children to queue for further processing
198
+ clusterQueue.push(leftCluster, rightCluster);
199
+ }
200
+ }
201
+
202
+ // Extract flat clustering from leaf nodes
203
+ const clusters = new Map<NodeId, number>();
204
+ let clusterId = 0;
205
+
206
+ function assignClusterIds(cluster: GRSBMCluster): void {
207
+ if (!cluster.left && !cluster.right) {
208
+ // Leaf node
209
+ for (const nodeId of cluster.members) {
210
+ clusters.set(nodeId, clusterId);
211
+ }
212
+ clusterId++;
213
+ } else {
214
+ // Internal node - traverse children
215
+ if (cluster.left) {
216
+ assignClusterIds(cluster.left);
217
+ }
218
+
219
+ if (cluster.right) {
220
+ assignClusterIds(cluster.right);
221
+ }
222
+ }
223
+ }
224
+
225
+ assignClusterIds(root);
226
+
227
+ // Restore original random function
228
+ Math.random = originalRandom;
229
+
230
+ return {
231
+ root,
232
+ clusters,
233
+ numClusters: clusterId,
234
+ modularityScores,
235
+ explanation: explanations,
236
+ };
237
+ }
238
+
239
+ /**
240
+ * Perform spectral bisection on a cluster
241
+ * @param graph - The input graph
242
+ * @param cluster - The cluster to bisect
243
+ * @param _numEigenvectors - Number of eigenvectors to compute (reserved for future use)
244
+ * @param tolerance - Convergence tolerance
245
+ * @param maxIterations - Maximum number of iterations
246
+ * @returns Bisection result with left/right members, scores, and explanation, or null if bisection failed
247
+ */
248
+ function spectralBisection(
249
+ graph: Graph,
250
+ cluster: GRSBMCluster,
251
+ _numEigenvectors: number,
252
+ tolerance: number,
253
+ maxIterations: number,
254
+ ): {
255
+ leftMembers: Set<NodeId>;
256
+ rightMembers: Set<NodeId>;
257
+ spectralScore: number;
258
+ keyNodes: NodeId[];
259
+ spectralValues: number[];
260
+ reason: string;
261
+ } | null {
262
+ const members = Array.from(cluster.members);
263
+ const n = members.length;
264
+
265
+ if (n < 4) {
266
+ return null; // Too small to split meaningfully
267
+ }
268
+
269
+ // Create subgraph Laplacian matrix
270
+ const laplacian = createLaplacianMatrix(graph, members);
271
+
272
+ // Compute the second smallest eigenvector (Fiedler vector)
273
+ const eigenvector = computeFiedlerVector(laplacian, tolerance, maxIterations);
274
+
275
+ if (!eigenvector) {
276
+ return null; // Could not compute eigenvector
277
+ }
278
+
279
+ // Find optimal split point
280
+ const sortedIndices = eigenvector.map((value, index) => ({ value, index })).sort((a, b) => a.value - b.value);
281
+
282
+ let bestSplitIndex = Math.floor(n / 2);
283
+ let bestModularity = -Infinity;
284
+
285
+ // Try different split points
286
+ for (let splitIndex = Math.floor(n * 0.2); splitIndex <= Math.floor(n * 0.8); splitIndex++) {
287
+ const leftIndices = sortedIndices.slice(0, splitIndex).map((item) => item.index);
288
+ const rightIndices = sortedIndices.slice(splitIndex).map((item) => item.index);
289
+
290
+ const assignment = new Map<NodeId, number>();
291
+ for (const idx of leftIndices) {
292
+ const nodeId = members[idx];
293
+ if (nodeId !== undefined) {
294
+ assignment.set(nodeId, 0);
295
+ }
296
+ }
297
+ for (const idx of rightIndices) {
298
+ const nodeId = members[idx];
299
+ if (nodeId !== undefined) {
300
+ assignment.set(nodeId, 1);
301
+ }
302
+ }
303
+
304
+ const modularity = calculateModularity(graph, assignment);
305
+
306
+ if (modularity > bestModularity) {
307
+ bestModularity = modularity;
308
+ bestSplitIndex = splitIndex;
309
+ }
310
+ }
311
+
312
+ // Create final split
313
+ const leftIndices = sortedIndices.slice(0, bestSplitIndex).map((item) => item.index);
314
+ const rightIndices = sortedIndices.slice(bestSplitIndex).map((item) => item.index);
315
+
316
+ const leftMembers = new Set<NodeId>();
317
+ const rightMembers = new Set<NodeId>();
318
+
319
+ for (const idx of leftIndices) {
320
+ const nodeId = members[idx];
321
+ if (nodeId !== undefined) {
322
+ leftMembers.add(nodeId);
323
+ }
324
+ }
325
+
326
+ for (const idx of rightIndices) {
327
+ const nodeId = members[idx];
328
+ if (nodeId !== undefined) {
329
+ rightMembers.add(nodeId);
330
+ }
331
+ }
332
+
333
+ // Identify key nodes (those with extreme spectral values)
334
+ const extremeThreshold = 0.1;
335
+ const sortedValues = [...eigenvector].sort((a, b) => Math.abs(b) - Math.abs(a));
336
+ const threshold = sortedValues[Math.floor(sortedValues.length * extremeThreshold)] ?? 0;
337
+
338
+ const keyNodes: NodeId[] = [];
339
+ for (let i = 0; i < eigenvector.length; i++) {
340
+ const eigenValue = eigenvector[i];
341
+ if (eigenValue !== undefined && Math.abs(eigenValue) >= Math.abs(threshold)) {
342
+ const nodeId = members[i];
343
+ if (nodeId !== undefined) {
344
+ keyNodes.push(nodeId);
345
+ }
346
+ }
347
+ }
348
+
349
+ // Calculate spectral score (based on eigenvalue gap)
350
+ const firstValue = sortedValues[0] ?? 0;
351
+ const lastValue = sortedValues[sortedValues.length - 1] ?? 0;
352
+ const spectralScore = Math.abs(firstValue - lastValue);
353
+
354
+ // Generate explanation
355
+ const reason = `Spectral bisection based on Fiedler vector with modularity ${bestModularity.toFixed(3)}. Split creates clusters of sizes ${String(leftMembers.size)} and ${String(rightMembers.size)}.`;
356
+
357
+ return {
358
+ leftMembers,
359
+ rightMembers,
360
+ spectralScore,
361
+ keyNodes: keyNodes.slice(0, 5), // Top 5 key nodes
362
+ spectralValues: eigenvector,
363
+ reason,
364
+ };
365
+ }
366
+
367
+ /**
368
+ * Create Laplacian matrix for a subgraph
369
+ * @param graph - The input graph
370
+ * @param nodes - The nodes to include in the subgraph
371
+ * @returns The Laplacian matrix as a 2D array
372
+ */
373
+ function createLaplacianMatrix(graph: Graph, nodes: NodeId[]): number[][] {
374
+ const n = nodes.length;
375
+ const nodeIndex = new Map<NodeId, number>();
376
+
377
+ // Create node index mapping
378
+ for (let i = 0; i < n; i++) {
379
+ const node = nodes[i];
380
+ if (node !== undefined) {
381
+ nodeIndex.set(node, i);
382
+ }
383
+ }
384
+
385
+ // Initialize Laplacian matrix
386
+ const laplacian = Array.from({ length: n }, () => new Array<number>(n).fill(0));
387
+
388
+ // Fill adjacency part and calculate degrees
389
+ const degrees = new Array<number>(n).fill(0);
390
+
391
+ for (let i = 0; i < n; i++) {
392
+ const nodeId = nodes[i];
393
+ if (nodeId === undefined) {
394
+ continue;
395
+ }
396
+
397
+ for (const neighbor of graph.neighbors(nodeId)) {
398
+ const neighborIdx = nodeIndex.get(neighbor);
399
+ if (neighborIdx !== undefined && i < laplacian.length && i < degrees.length) {
400
+ const row = laplacian[i];
401
+ if (row) {
402
+ row[neighborIdx] = -1;
403
+ degrees[i] = (degrees[i] ?? 0) + 1;
404
+ }
405
+ }
406
+ }
407
+ }
408
+
409
+ // Set diagonal (degree) values
410
+ for (let i = 0; i < n; i++) {
411
+ const row = laplacian[i];
412
+ const degree = degrees[i];
413
+ if (row && degree !== undefined) {
414
+ row[i] = degree;
415
+ }
416
+ }
417
+
418
+ return laplacian;
419
+ }
420
+
421
+ /**
422
+ * Compute the Fiedler vector (second smallest eigenvector) using power iteration
423
+ * @param laplacian - The Laplacian matrix
424
+ * @param tolerance - Convergence tolerance
425
+ * @param maxIterations - Maximum number of iterations
426
+ * @returns The Fiedler vector, or null if computation failed
427
+ */
428
+ function computeFiedlerVector(laplacian: number[][], tolerance: number, maxIterations: number): number[] | null {
429
+ const n = laplacian.length;
430
+ if (n < 2) {
431
+ return null;
432
+ }
433
+
434
+ // Initialize random vector orthogonal to the all-ones vector
435
+ let vector = new Array<number>(n).fill(0);
436
+ for (let i = 0; i < n; i++) {
437
+ vector[i] = Math.random() - 0.5;
438
+ }
439
+
440
+ // Make orthogonal to all-ones vector
441
+ const mean = vector.reduce((sum: number, val: number) => sum + val, 0) / n;
442
+ for (let i = 0; i < n; i++) {
443
+ const val = vector[i];
444
+ if (val !== undefined) {
445
+ vector[i] = val - mean;
446
+ }
447
+ }
448
+
449
+ // Normalize
450
+ const norm = Math.sqrt(vector.reduce((sum: number, val: number) => sum + val * val, 0));
451
+ if (norm > 0) {
452
+ for (let i = 0; i < n; i++) {
453
+ const val = vector[i];
454
+ if (val !== undefined) {
455
+ vector[i] = val / norm;
456
+ }
457
+ }
458
+ }
459
+
460
+ // Power iteration with deflation for second smallest eigenvalue
461
+ for (let iter = 0; iter < maxIterations; iter++) {
462
+ const newVector = new Array<number>(n).fill(0);
463
+
464
+ // Matrix-vector multiplication: newVector = L * vector
465
+ for (let i = 0; i < n; i++) {
466
+ let sum = 0;
467
+ const row = laplacian[i];
468
+ if (row) {
469
+ for (let j = 0; j < n; j++) {
470
+ const matrixVal = row[j];
471
+ const vectorVal = vector[j];
472
+ if (matrixVal !== undefined && vectorVal !== undefined) {
473
+ sum += matrixVal * vectorVal;
474
+ }
475
+ }
476
+ }
477
+
478
+ newVector[i] = sum;
479
+ }
480
+
481
+ // For smallest eigenvalue, we actually want inverse iteration
482
+ // This is simplified - in practice would solve (L - shift*I)x = vector
483
+ // For now, use power iteration on -L (approximately)
484
+ for (let i = 0; i < n; i++) {
485
+ const val = newVector[i];
486
+ if (val !== undefined) {
487
+ newVector[i] = -val;
488
+ }
489
+ }
490
+
491
+ // Orthogonalize against all-ones vector
492
+ const newMean = newVector.reduce((sum, val) => sum + val, 0) / n;
493
+ for (let i = 0; i < n; i++) {
494
+ const val = newVector[i];
495
+ if (val !== undefined) {
496
+ newVector[i] = val - newMean;
497
+ }
498
+ }
499
+
500
+ // Normalize
501
+ const newNorm = Math.sqrt(newVector.reduce((sum, val) => sum + val * val, 0));
502
+ if (newNorm < tolerance) {
503
+ break; // Converged to zero vector
504
+ }
505
+
506
+ for (let i = 0; i < n; i++) {
507
+ const val = newVector[i];
508
+ if (val !== undefined) {
509
+ newVector[i] = val / newNorm;
510
+ }
511
+ }
512
+
513
+ // Check convergence
514
+ let diff = 0;
515
+ for (let i = 0; i < n; i++) {
516
+ const newVal = newVector[i];
517
+ const oldVal = vector[i];
518
+ if (newVal !== undefined && oldVal !== undefined) {
519
+ diff += Math.abs(newVal - oldVal);
520
+ }
521
+ }
522
+
523
+ vector = newVector;
524
+
525
+ if (diff < tolerance) {
526
+ break;
527
+ }
528
+ }
529
+
530
+ return vector;
531
+ }
532
+
533
+ /**
534
+ * Calculate modularity of a graph partitioning
535
+ * @param graph - The input graph
536
+ * @param assignment - Map from node ID to community ID
537
+ * @returns The modularity score
538
+ */
539
+ function calculateModularity(graph: Graph, assignment: Map<NodeId, number>): number {
540
+ const totalEdges = graph.uniqueEdgeCount;
541
+ if (totalEdges === 0) {
542
+ return 0;
543
+ }
544
+
545
+ let modularity = 0;
546
+ const communities = new Map<number, Set<NodeId>>();
547
+
548
+ // Group nodes by community
549
+ for (const [nodeId, communityId] of assignment) {
550
+ if (!communities.has(communityId)) {
551
+ communities.set(communityId, new Set());
552
+ }
553
+
554
+ const community = communities.get(communityId);
555
+ if (community) {
556
+ community.add(nodeId);
557
+ }
558
+ }
559
+
560
+ // Calculate modularity for each community
561
+ for (const [, members] of communities) {
562
+ let internalEdges = 0;
563
+ let totalDegree = 0;
564
+
565
+ for (const nodeId of members) {
566
+ const nodeDegree = graph.degree(nodeId);
567
+ totalDegree += nodeDegree;
568
+
569
+ // Count internal edges
570
+ for (const neighbor of graph.neighbors(nodeId)) {
571
+ if (members.has(neighbor)) {
572
+ internalEdges++;
573
+ }
574
+ }
575
+ }
576
+
577
+ // Each edge is counted twice in undirected graphs
578
+ internalEdges /= 2;
579
+
580
+ // Modularity contribution for this community
581
+ const expectedEdges = (totalDegree * totalDegree) / (4 * totalEdges);
582
+ modularity += (internalEdges - expectedEdges) / totalEdges;
583
+ }
584
+
585
+ return modularity;
586
+ }