@graphty/algorithms 2.1.2 → 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,317 @@
1
+ /**
2
+ * Link prediction over a snapshot: common-neighbour and Adamic-Adar scores for one pair, a list of
3
+ * pairs, every pair, or one node's candidates, and the ranking metrics of a held-out evaluation.
4
+ *
5
+ * Every score is a merge of two sorted rows with simple-graph semantics: a neighbour reached by
6
+ * parallel arcs counts once, and a self-loop makes a node its own neighbour. With
7
+ * `{ directed: true }` a pair (u, v) intersects out(u) with in(v) -- the nodes on a path u -> z -> v
8
+ * -- and otherwise the two out rows (the two rows of an undirected snapshot).
9
+ *
10
+ * A node index at or beyond `nodeCount`, `INVALID_INDEX` included, is an absent node: its pairs
11
+ * score 0 and it has no candidates.
12
+ * @module
13
+ */
14
+ import { sortedRowMerge } from "./common-neighbors.js";
15
+ /**
16
+ * Adamic-Adar weights are multiples of 2^-36, so any sum of them below 2^16 is exact and the same in
17
+ * whatever order it is added: two pairs whose common neighbours have the same degrees score
18
+ * bit-identically, and a ranking never splits them by rounding. The snap moves a weight by at most
19
+ * 2^-37, far inside the 1e-9 relative tolerance of a score.
20
+ */
21
+ const WEIGHT_GRID = 2 ** 36;
22
+ /**
23
+ * The Adamic-Adar weight of a common neighbour of the given degree: 1 / ln(degree) snapped to the
24
+ * weight grid, 1 for degree 1 (ln 1 is 0) and 0 for degree 0. The legacy `adamicAdarScore` adds
25
+ * the unsnapped weights in neighbour-visit order, so its scores differ from these in the last bits
26
+ * and it may order two exactly tied pairs either way.
27
+ * @param degree - The neighbour's degree
28
+ * @returns The weight
29
+ */
30
+ function adamicAdarWeight(degree) {
31
+ // ponytail: exact only while a pair's score stays below 2^16 (tens of thousands of hub neighbours);
32
+ // a coarser grid chosen from the graph's largest row sum lifts that ceiling if it is ever reached.
33
+ if (degree > 1) {
34
+ return Math.round(WEIGHT_GRID / Math.log(degree)) / WEIGHT_GRID;
35
+ }
36
+ return degree === 1 ? 1 : 0;
37
+ }
38
+ /**
39
+ * The number of distinct entries of one row of a sorted adjacency.
40
+ * @param view - The adjacency
41
+ * @param z - The row
42
+ * @returns The count
43
+ */
44
+ function distinctRowLength(view, z) {
45
+ const start = view.rowPtr[z];
46
+ const end = view.rowPtr[z + 1];
47
+ let count = 0;
48
+ for (let a = start; a < end; a++) {
49
+ if (a === start || view.colIdx[a] !== view.colIdx[a - 1]) {
50
+ count++;
51
+ }
52
+ }
53
+ return count;
54
+ }
55
+ /**
56
+ * The Adamic-Adar weight of a node as a common neighbour, from its degree in distinct neighbours:
57
+ * out-neighbours for `{ directed: true }` or an undirected snapshot, else out- plus in-neighbours,
58
+ * a self-loop in both. Costs the node's degree, so one pair costs the degrees of its common
59
+ * neighbours, not the whole graph.
60
+ * @param s - The snapshot
61
+ * @param directed - The `directed` option
62
+ * @returns The weight of node z
63
+ */
64
+ function adamicAdarWeightOf(s, directed) {
65
+ const rev = s.directed && !directed ? s.reverse() : undefined;
66
+ return (z) => adamicAdarWeight(distinctRowLength(s, z) + (rev === undefined ? 0 : distinctRowLength(rev, z)));
67
+ }
68
+ /**
69
+ * The pair score: a count of common neighbours, or their weight sum when `weight` is given.
70
+ * @param s - The snapshot
71
+ * @param o - Options
72
+ * @param weight - Optional weight of a common neighbour
73
+ * @returns The score of (u, v); 0 when either is absent
74
+ */
75
+ function scorer(s, o, weight) {
76
+ const bwd = o.directed === true ? s.reverse() : s;
77
+ const n = s.nodeCount;
78
+ return (u, v) => (u < n && v < n ? sortedRowMerge(s, bwd, u, v, weight) : 0);
79
+ }
80
+ /**
81
+ * The Adamic-Adar pair score for many pairs: every node's weight computed once, up front.
82
+ * @param s - The snapshot
83
+ * @param o - Options
84
+ * @returns The score of (u, v)
85
+ */
86
+ function adamicAdarScorer(s, o) {
87
+ const weightOf = adamicAdarWeightOf(s, o.directed === true);
88
+ const w = Float64Array.from({ length: s.nodeCount }, (_, z) => weightOf(z));
89
+ return scorer(s, o, (z) => w[z]);
90
+ }
91
+ /**
92
+ * Sort pairs by score, highest first and stable, and keep `order.slice(0, end)`.
93
+ * @param sources - Pair sources in enumeration order
94
+ * @param targets - Pair targets
95
+ * @param scores - Pair scores
96
+ * @param end - The slice end
97
+ * @returns The ranked pairs
98
+ */
99
+ function ranked(sources, targets, scores, end) {
100
+ const order = Array.from(scores, (_, k) => k)
101
+ .sort((a, b) => scores[b] - scores[a])
102
+ .slice(0, end);
103
+ return {
104
+ sources: Uint32Array.from(order, (k) => sources[k]),
105
+ targets: Uint32Array.from(order, (k) => targets[k]),
106
+ scores: Float64Array.from(order, (k) => scores[k]),
107
+ };
108
+ }
109
+ function predict(s, o, score) {
110
+ const sources = [];
111
+ const targets = [];
112
+ const scores = [];
113
+ // Each unordered pair is scored once as (u, v), u < v; without `directed` the reverse pair is
114
+ // listed too with the same score. Existence is tested on the arc u -> v only.
115
+ const mirror = o.directed !== true;
116
+ for (let u = 0; u < s.nodeCount; u++) {
117
+ for (let v = u + 1; v < s.nodeCount; v++) {
118
+ if (o.includeExisting !== true && s.hasArc(u, v)) {
119
+ continue;
120
+ }
121
+ const x = score(u, v);
122
+ if (x > 0) {
123
+ sources.push(u);
124
+ targets.push(v);
125
+ scores.push(x);
126
+ if (mirror) {
127
+ sources.push(v);
128
+ targets.push(u);
129
+ scores.push(x);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ const { topK } = o;
135
+ return ranked(sources, targets, scores, topK !== undefined && topK > 0 ? topK : scores.length);
136
+ }
137
+ function forPairs(pairs, score) {
138
+ return Float64Array.from(pairs.sources, (u, k) => score(u, pairs.targets[k]));
139
+ }
140
+ function candidatesOf(s, u, o, score) {
141
+ const n = s.nodeCount;
142
+ const sources = [];
143
+ const targets = [];
144
+ const scores = [];
145
+ if (u < n) {
146
+ const list = o.candidates ?? Array.from({ length: n }, (_, i) => i);
147
+ for (let k = 0; k < list.length; k++) {
148
+ const v = list[k];
149
+ if (v === u || (o.includeExisting !== true && v < n && s.hasArc(u, v))) {
150
+ continue;
151
+ }
152
+ const x = score(u, v);
153
+ if (x > 0) {
154
+ sources.push(u);
155
+ targets.push(v);
156
+ scores.push(x);
157
+ }
158
+ }
159
+ }
160
+ return ranked(sources, targets, scores, o.topK ?? 10);
161
+ }
162
+ /**
163
+ * Rank held-out edges against non-edges by score (stable, edges first among equal scores), then
164
+ * report the threshold with the best F1 and the AUC; the AUC is 0.5 when either side is empty.
165
+ * @param edges - The scores of the held-out edges
166
+ * @param nonEdges - The scores of the non-edges
167
+ * @returns The metrics
168
+ */
169
+ function rankingMetrics(edges, nonEdges) {
170
+ const all = [...edges, ...nonEdges];
171
+ const order = Array.from(all, (_, k) => k).sort((a, b) => all[b] - all[a]);
172
+ let tp = 0;
173
+ let fp = 0;
174
+ let bestF1 = 0;
175
+ let bestPrecision = 0;
176
+ let bestRecall = 0;
177
+ let auc = 0;
178
+ for (const k of order) {
179
+ if (k < edges.length) {
180
+ tp++;
181
+ }
182
+ else {
183
+ auc += tp;
184
+ fp++;
185
+ }
186
+ const precision = tp / (tp + fp);
187
+ const recall = tp / edges.length;
188
+ const f1 = precision + recall > 0 ? (2 * (precision * recall)) / (precision + recall) : 0;
189
+ if (f1 > bestF1) {
190
+ bestF1 = f1;
191
+ bestPrecision = precision;
192
+ bestRecall = recall;
193
+ }
194
+ }
195
+ auc = tp > 0 && fp > 0 ? auc / (tp * fp) : 0.5;
196
+ return { precision: bestPrecision, recall: bestRecall, f1Score: bestF1, auc };
197
+ }
198
+ /**
199
+ * Common-neighbour scores of every pair not already joined, ranked.
200
+ * @param s - The snapshot
201
+ * @param o - Options
202
+ * @returns The pairs with a positive score, highest first
203
+ * @public
204
+ */
205
+ export function commonNeighborsPrediction(s, o = {}) {
206
+ return predict(s, o, scorer(s, o));
207
+ }
208
+ /**
209
+ * Common-neighbour scores of the given pairs, in order.
210
+ * @param s - The snapshot
211
+ * @param pairs - The pairs
212
+ * @param o - Options
213
+ * @returns One score per pair
214
+ * @public
215
+ */
216
+ export function commonNeighborsForPairs(s, pairs, o = {}) {
217
+ return forPairs(pairs, scorer(s, o));
218
+ }
219
+ /**
220
+ * One node's best common-neighbour candidates, ranked.
221
+ * @param s - The snapshot
222
+ * @param u - The node index
223
+ * @param o - Options
224
+ * @returns (u, v) pairs with a positive score, highest first
225
+ * @public
226
+ */
227
+ export function getTopCandidatesForNode(s, u, o = {}) {
228
+ return candidatesOf(s, u, o, scorer(s, o));
229
+ }
230
+ /**
231
+ * Ranking metrics of the common-neighbour score on held-out edges against non-edges.
232
+ * @param s - The training snapshot
233
+ * @param edges - The held-out edges
234
+ * @param nonEdges - The non-edges
235
+ * @param o - Options
236
+ * @returns The metrics
237
+ * @public
238
+ */
239
+ export function evaluateCommonNeighbors(s, edges, nonEdges, o = {}) {
240
+ const score = scorer(s, o);
241
+ return rankingMetrics(forPairs(edges, score), forPairs(nonEdges, score));
242
+ }
243
+ /**
244
+ * The Adamic-Adar index of two nodes: the sum over distinct common neighbours z of 1 / ln(degree(z)).
245
+ * @param s - The snapshot
246
+ * @param u - A node index
247
+ * @param v - A node index
248
+ * @param o - Options
249
+ * @returns The score
250
+ * @public
251
+ */
252
+ export function adamicAdarScore(s, u, v, o = {}) {
253
+ return scorer(s, o, adamicAdarWeightOf(s, o.directed === true))(u, v);
254
+ }
255
+ /**
256
+ * Adamic-Adar scores of every pair not already joined, ranked.
257
+ * @param s - The snapshot
258
+ * @param o - Options
259
+ * @returns The pairs with a positive score, highest first
260
+ * @public
261
+ */
262
+ export function adamicAdarPrediction(s, o = {}) {
263
+ return predict(s, o, adamicAdarScorer(s, o));
264
+ }
265
+ /**
266
+ * Adamic-Adar scores of the given pairs, in order.
267
+ * @param s - The snapshot
268
+ * @param pairs - The pairs
269
+ * @param o - Options
270
+ * @returns One score per pair
271
+ * @public
272
+ */
273
+ export function adamicAdarForPairs(s, pairs, o = {}) {
274
+ return forPairs(pairs, adamicAdarScorer(s, o));
275
+ }
276
+ /**
277
+ * One node's best Adamic-Adar candidates, ranked.
278
+ * @param s - The snapshot
279
+ * @param u - The node index
280
+ * @param o - Options
281
+ * @returns (u, v) pairs with a positive score, highest first
282
+ * @public
283
+ */
284
+ export function getTopAdamicAdarCandidatesForNode(s, u, o = {}) {
285
+ return candidatesOf(s, u, o, adamicAdarScorer(s, o));
286
+ }
287
+ /**
288
+ * Ranking metrics of the Adamic-Adar score on held-out edges against non-edges.
289
+ * @param s - The training snapshot
290
+ * @param edges - The held-out edges
291
+ * @param nonEdges - The non-edges
292
+ * @param o - Options
293
+ * @returns The metrics
294
+ * @public
295
+ */
296
+ export function evaluateAdamicAdar(s, edges, nonEdges, o = {}) {
297
+ const score = adamicAdarScorer(s, o);
298
+ return rankingMetrics(forPairs(edges, score), forPairs(nonEdges, score));
299
+ }
300
+ /**
301
+ * Both evaluations on the same held-out sets. The common-neighbour side always intersects the two
302
+ * OUT rows, whatever `directed` says, as the legacy function of this name does; the Adamic-Adar side
303
+ * honours `directed`.
304
+ * @param s - The training snapshot
305
+ * @param edges - The held-out edges
306
+ * @param nonEdges - The non-edges
307
+ * @param o - Options
308
+ * @returns The two sets of metrics
309
+ * @public
310
+ */
311
+ export function compareAdamicAdarWithCommonNeighbors(s, edges, nonEdges, o = {}) {
312
+ return {
313
+ adamicAdar: evaluateAdamicAdar(s, edges, nonEdges, o),
314
+ commonNeighbors: evaluateCommonNeighbors(s, edges, nonEdges),
315
+ };
316
+ }
317
+ //# sourceMappingURL=link-prediction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-prediction.js","sourceRoot":"","sources":["../../../src/indexed/link-prediction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import type { AdjacencyView, NumericVector } from "@graphty/graph-format";
2
+ import { type LabelResult } from "./components.js";
3
+ /** Options of the index-based Markov clustering, with the legacy `markovClustering` defaults. @public */
4
+ export interface MarkovOptions {
5
+ /** Matrix power of each expansion step, an integer of at least 1; default 2. */
6
+ readonly expansion?: number | undefined;
7
+ /** Element-wise power of each inflation step, above 0; default 2. */
8
+ readonly inflation?: number | undefined;
9
+ /** Cap on expansion-inflation rounds; default 100. */
10
+ readonly maxIterations?: number | undefined;
11
+ /** Stop when no matrix entry moved by more than this in a round; default 1e-6. */
12
+ readonly tolerance?: number | undefined;
13
+ /** Entries below this are dropped after each inflation; default 1e-5. */
14
+ readonly pruningThreshold?: number | undefined;
15
+ /** Give every node a self-loop of weight 1 before the first round; default true. */
16
+ readonly selfLoops?: boolean | undefined;
17
+ /** Per-arc weight override, arcCount long -- the facade passes `expandEdges(s, shadow.data)`. */
18
+ readonly weights?: NumericVector | undefined;
19
+ }
20
+ /** Result of the index-based Markov clustering. @public */
21
+ export interface MarkovResult extends LabelResult {
22
+ /** Nodes whose own flow survived (a positive diagonal entry), in index order. */
23
+ readonly attractors: Uint32Array;
24
+ /** Expansion-inflation rounds run. */
25
+ readonly iterations: number;
26
+ /** True when the last round moved no entry by more than `tolerance`. */
27
+ readonly converged: boolean;
28
+ }
29
+ /**
30
+ * Markov clustering (MCL; van Dongen, 2000), the index-based port of the legacy `markovClustering`.
31
+ *
32
+ * The flow matrix starts as the column-normalised adjacency: entry (i, j) is the weight of the arc
33
+ * i -> j, so column j spreads j's flow over the nodes with an arc into it (on an undirected
34
+ * snapshot, its neighbours). With `selfLoops` every diagonal entry is first set to 1, replacing a
35
+ * self-loop's weight. Each round raises the matrix to the `expansion` power, raises every entry to
36
+ * the `inflation` power, renormalises the columns, drops the entries below `pruningThreshold` and
37
+ * renormalises again, until no entry moves by more than `tolerance` or `maxIterations` rounds ran.
38
+ * Node j then joins the attractor with the largest entry in its column, the lowest index on a tie;
39
+ * a node whose column emptied is a community of its own.
40
+ *
41
+ * The matrix is kept sparse, and every sum is taken in the order the legacy dense loops take it, so
42
+ * the rounds are bit-identical to the legacy function's and so are the communities, their order and
43
+ * the attractors. Communities are labelled in the legacy function's order: the flow clusters by
44
+ * their lowest member, then the nodes whose column emptied. Two differences: parallel arcs are
45
+ * summed (a legacy graph has none), and `iterations` counts the rounds run, where the legacy
46
+ * function reports one more than `maxIterations` when it stops at the cap. A negative, NaN or
47
+ * infinite weight throws.
48
+ * @param s - Any snapshot or adjacency view
49
+ * @param options - MCL parameters and the weight override
50
+ * @returns The partition, the attractors, the rounds run and whether they converged
51
+ * @public
52
+ */
53
+ export declare function markovClustering(s: AdjacencyView, options?: MarkovOptions): MarkovResult;
54
+ //# sourceMappingURL=markov.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markov.d.ts","sourceRoot":"","sources":["../../../src/indexed/markov.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,iBAAiB,CAAC;AAE/D,yGAAyG;AACzG,MAAM,WAAW,aAAa;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,sDAAsD;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,yEAAyE;IACzE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,iGAAiG;IACjG,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAChD;AAED,2DAA2D;AAC3D,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC7C,iFAAiF;IACjF,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,sCAAsC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC/B;AAmMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,GAAE,aAAkB,GAAG,YAAY,CA0E5F"}
@@ -0,0 +1,284 @@
1
+ import { withGroups } from "./components.js";
2
+ /**
3
+ * Divide every column by its sum, summed in ascending row order as the legacy dense loop sums it.
4
+ * @param m - The matrix, changed in place
5
+ */
6
+ function normaliseColumns(m) {
7
+ for (let j = 0; j + 1 < m.ptr.length; j++) {
8
+ let sum = 0;
9
+ for (let p = m.ptr[j]; p < m.ptr[j + 1]; p++) {
10
+ sum += m.val[p];
11
+ }
12
+ if (sum > 0) {
13
+ for (let p = m.ptr[j]; p < m.ptr[j + 1]; p++) {
14
+ m.val[p] /= sum;
15
+ }
16
+ }
17
+ }
18
+ }
19
+ /**
20
+ * The product `a * b`. For every entry the products are added in ascending k, the order the legacy
21
+ * dense triple loop adds them in; the zero products it adds as well leave a sum unchanged, so the
22
+ * result is bit-identical to the dense one.
23
+ * @param a - Left factor
24
+ * @param b - Right factor
25
+ * @param acc - n-long scratch, all zero on entry and on exit
26
+ * @param mark - n-long scratch, all zero on entry and on exit
27
+ * @returns The product
28
+ */
29
+ function multiply(a, b, acc, mark) {
30
+ const n = acc.length;
31
+ const ptr = new Uint32Array(n + 1);
32
+ const rows = [];
33
+ const vals = [];
34
+ const touched = [];
35
+ for (let j = 0; j < n; j++) {
36
+ touched.length = 0;
37
+ for (let q = b.ptr[j]; q < b.ptr[j + 1]; q++) {
38
+ const k = b.row[q];
39
+ const bkj = b.val[q];
40
+ for (let p = a.ptr[k]; p < a.ptr[k + 1]; p++) {
41
+ const i = a.row[p];
42
+ if (mark[i] === 0) {
43
+ mark[i] = 1;
44
+ touched.push(i);
45
+ }
46
+ acc[i] += a.val[p] * bkj;
47
+ }
48
+ }
49
+ touched.sort((x, y) => x - y);
50
+ for (const i of touched) {
51
+ rows.push(i);
52
+ vals.push(acc[i]);
53
+ acc[i] = 0;
54
+ mark[i] = 0;
55
+ }
56
+ ptr[j + 1] = rows.length;
57
+ }
58
+ return { ptr, row: Uint32Array.from(rows), val: Float64Array.from(vals) };
59
+ }
60
+ /**
61
+ * Raise every entry to `inflation`, renormalise, drop the entries below `threshold` and renormalise
62
+ * again: the legacy inflate and prune steps.
63
+ * @param m - The expanded matrix
64
+ * @param inflation - The element-wise power
65
+ * @param threshold - The pruning threshold
66
+ * @returns The new matrix
67
+ */
68
+ function inflateAndPrune(m, inflation, threshold) {
69
+ const powered = { ptr: m.ptr, row: m.row, val: m.val.map((v) => Math.pow(v, inflation)) };
70
+ normaliseColumns(powered);
71
+ const n = m.ptr.length - 1;
72
+ const ptr = new Uint32Array(n + 1);
73
+ const rows = [];
74
+ const vals = [];
75
+ for (let j = 0; j < n; j++) {
76
+ for (let p = powered.ptr[j]; p < powered.ptr[j + 1]; p++) {
77
+ if (powered.val[p] >= threshold) {
78
+ rows.push(powered.row[p]);
79
+ vals.push(powered.val[p]);
80
+ }
81
+ }
82
+ ptr[j + 1] = rows.length;
83
+ }
84
+ const out = { ptr, row: Uint32Array.from(rows), val: Float64Array.from(vals) };
85
+ normaliseColumns(out);
86
+ return out;
87
+ }
88
+ /**
89
+ * Whether no entry differs by more than `tolerance` between two matrices, an absent entry being 0.
90
+ * @param a - The previous matrix
91
+ * @param b - The new matrix
92
+ * @param tolerance - The tolerance
93
+ * @returns True when every entry is within tolerance
94
+ */
95
+ function withinTolerance(a, b, tolerance) {
96
+ for (let j = 0; j + 1 < a.ptr.length; j++) {
97
+ let p = a.ptr[j];
98
+ let q = b.ptr[j];
99
+ const pe = a.ptr[j + 1];
100
+ const qe = b.ptr[j + 1];
101
+ while (p < pe || q < qe) {
102
+ let diff;
103
+ if (q >= qe || (p < pe && a.row[p] < b.row[q])) {
104
+ diff = a.val[p++];
105
+ }
106
+ else if (p >= pe || b.row[q] < a.row[p]) {
107
+ diff = b.val[q++];
108
+ }
109
+ else {
110
+ diff = a.val[p++] - b.val[q++];
111
+ }
112
+ if (Math.abs(diff) > tolerance) {
113
+ return false;
114
+ }
115
+ }
116
+ }
117
+ return true;
118
+ }
119
+ /**
120
+ * The starting matrix: entry (i, j) is the weight of the arc i -> j (parallel arcs summed), the
121
+ * diagonal set to 1 when `selfLoops`, every column normalised.
122
+ * @param s - The adjacency
123
+ * @param weights - Per-arc weights, or null for all ones
124
+ * @param selfLoops - Whether to set the diagonal to 1
125
+ * @returns The column-stochastic matrix
126
+ */
127
+ function transitionMatrix(s, weights, selfLoops) {
128
+ const n = s.nodeCount;
129
+ // Column j of the matrix is the set of arcs INTO j: a counting sort of the arcs by target, which
130
+ // keeps each column's rows ascending because the rows are visited in order.
131
+ const ptr = new Uint32Array(n + 1);
132
+ for (let a = 0; a < s.arcCount; a++) {
133
+ ptr[s.colIdx[a] + 1]++;
134
+ }
135
+ if (selfLoops) {
136
+ for (let j = 0; j < n; j++) {
137
+ ptr[j + 1]++;
138
+ }
139
+ }
140
+ for (let j = 0; j < n; j++) {
141
+ ptr[j + 1] += ptr[j];
142
+ }
143
+ const fill = ptr.slice(0, n);
144
+ const row = new Uint32Array(ptr[n]);
145
+ const val = new Float64Array(ptr[n]);
146
+ const put = (i, j, w, replace) => {
147
+ const last = fill[j] - 1;
148
+ if (last >= ptr[j] && row[last] === i) {
149
+ val[last] = replace ? w : val[last] + w;
150
+ }
151
+ else {
152
+ row[fill[j]] = i;
153
+ val[fill[j]++] = w;
154
+ }
155
+ };
156
+ for (let i = 0; i < n; i++) {
157
+ // The diagonal goes in its place in row order: the arcs i -> j with j < i were placed while
158
+ // visiting earlier rows, so for column i this is where row i belongs.
159
+ for (let a = s.rowPtr[i]; a < s.rowPtr[i + 1]; a++) {
160
+ const j = s.colIdx[a];
161
+ const w = weights === null ? 1 : weights[a];
162
+ if (!(w >= 0) || w === Infinity) {
163
+ throw new RangeError(`arc ${a} has weight ${w}; Markov clustering needs finite, non-negative weights`);
164
+ }
165
+ put(i, j, w, false);
166
+ }
167
+ if (selfLoops) {
168
+ put(i, i, 1, true);
169
+ }
170
+ }
171
+ // Compact: merged parallel arcs and a self-loop folded into the diagonal left gaps.
172
+ const outPtr = new Uint32Array(n + 1);
173
+ const rows = [];
174
+ const vals = [];
175
+ for (let j = 0; j < n; j++) {
176
+ for (let p = ptr[j]; p < fill[j]; p++) {
177
+ rows.push(row[p]);
178
+ vals.push(val[p]);
179
+ }
180
+ outPtr[j + 1] = rows.length;
181
+ }
182
+ const m = { ptr: outPtr, row: Uint32Array.from(rows), val: Float64Array.from(vals) };
183
+ normaliseColumns(m);
184
+ return m;
185
+ }
186
+ /**
187
+ * Markov clustering (MCL; van Dongen, 2000), the index-based port of the legacy `markovClustering`.
188
+ *
189
+ * The flow matrix starts as the column-normalised adjacency: entry (i, j) is the weight of the arc
190
+ * i -> j, so column j spreads j's flow over the nodes with an arc into it (on an undirected
191
+ * snapshot, its neighbours). With `selfLoops` every diagonal entry is first set to 1, replacing a
192
+ * self-loop's weight. Each round raises the matrix to the `expansion` power, raises every entry to
193
+ * the `inflation` power, renormalises the columns, drops the entries below `pruningThreshold` and
194
+ * renormalises again, until no entry moves by more than `tolerance` or `maxIterations` rounds ran.
195
+ * Node j then joins the attractor with the largest entry in its column, the lowest index on a tie;
196
+ * a node whose column emptied is a community of its own.
197
+ *
198
+ * The matrix is kept sparse, and every sum is taken in the order the legacy dense loops take it, so
199
+ * the rounds are bit-identical to the legacy function's and so are the communities, their order and
200
+ * the attractors. Communities are labelled in the legacy function's order: the flow clusters by
201
+ * their lowest member, then the nodes whose column emptied. Two differences: parallel arcs are
202
+ * summed (a legacy graph has none), and `iterations` counts the rounds run, where the legacy
203
+ * function reports one more than `maxIterations` when it stops at the cap. A negative, NaN or
204
+ * infinite weight throws.
205
+ * @param s - Any snapshot or adjacency view
206
+ * @param options - MCL parameters and the weight override
207
+ * @returns The partition, the attractors, the rounds run and whether they converged
208
+ * @public
209
+ */
210
+ export function markovClustering(s, options = {}) {
211
+ const expansion = options.expansion ?? 2;
212
+ const inflation = options.inflation ?? 2;
213
+ const maxIterations = options.maxIterations ?? 100;
214
+ const tolerance = options.tolerance ?? 1e-6;
215
+ const pruningThreshold = options.pruningThreshold ?? 1e-5;
216
+ if (!Number.isInteger(expansion) || expansion < 1) {
217
+ throw new RangeError(`expansion must be an integer of at least 1, got ${expansion}`);
218
+ }
219
+ if (!(inflation > 0) || inflation === Infinity) {
220
+ throw new RangeError(`inflation must be finite and above 0, got ${inflation}`);
221
+ }
222
+ if (!Number.isInteger(maxIterations) || maxIterations < 0) {
223
+ throw new RangeError(`maxIterations must be a non-negative integer, got ${maxIterations}`);
224
+ }
225
+ if (!(tolerance >= 0) || !(pruningThreshold >= 0)) {
226
+ throw new RangeError("tolerance and pruningThreshold must be non-negative");
227
+ }
228
+ const weights = options.weights ?? s.weights;
229
+ if (weights !== null && weights.length !== s.arcCount) {
230
+ throw new RangeError(`weights has ${weights.length} entries; the snapshot has ${s.arcCount} arcs`);
231
+ }
232
+ const n = s.nodeCount;
233
+ let m = transitionMatrix(s, weights, options.selfLoops ?? true);
234
+ const acc = new Float64Array(n);
235
+ const mark = new Uint8Array(n);
236
+ let converged = n === 0;
237
+ let iterations = 0;
238
+ while (!converged && iterations < maxIterations) {
239
+ let expanded = m;
240
+ for (let t = 1; t < expansion; t++) {
241
+ expanded = multiply(expanded, m, acc, mark);
242
+ }
243
+ const next = inflateAndPrune(expanded, inflation, pruningThreshold);
244
+ iterations++;
245
+ converged = withinTolerance(m, next, tolerance);
246
+ m = next;
247
+ }
248
+ const attractors = [];
249
+ // Column j's attractor: the row of its largest positive entry, the first on a tie.
250
+ const attractorOf = new Int32Array(n).fill(-1);
251
+ for (let j = 0; j < n; j++) {
252
+ let best = 0;
253
+ for (let p = m.ptr[j]; p < m.ptr[j + 1]; p++) {
254
+ if (m.row[p] === j && m.val[p] > 0) {
255
+ attractors.push(j);
256
+ }
257
+ if (m.val[p] > best) {
258
+ best = m.val[p];
259
+ attractorOf[j] = m.row[p];
260
+ }
261
+ }
262
+ }
263
+ const labels = new Uint32Array(n);
264
+ const labelOfAttractor = new Map();
265
+ for (let j = 0; j < n; j++) {
266
+ const a = attractorOf[j];
267
+ if (a >= 0) {
268
+ let label = labelOfAttractor.get(a);
269
+ if (label === undefined) {
270
+ label = labelOfAttractor.size;
271
+ labelOfAttractor.set(a, label);
272
+ }
273
+ labels[j] = label;
274
+ }
275
+ }
276
+ let count = labelOfAttractor.size;
277
+ for (let j = 0; j < n; j++) {
278
+ if (attractorOf[j] < 0) {
279
+ labels[j] = count++;
280
+ }
281
+ }
282
+ return { ...withGroups(labels, count), attractors: Uint32Array.from(attractors), iterations, converged };
283
+ }
284
+ //# sourceMappingURL=markov.js.map