@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,399 @@
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
+
15
+ import type { AdjacencyView, F64, GraphSnapshot, U32 } from "@graphty/graph-format";
16
+
17
+ import { type CommonNeighborsOptions, sortedRowMerge } from "./common-neighbors.js";
18
+
19
+ /** Options of the link prediction functions. @public */
20
+ export interface LinkPredictionOptions extends CommonNeighborsOptions {
21
+ /** Also score pairs already joined by an arc u -> v. Default false. */
22
+ readonly includeExisting?: boolean | undefined;
23
+ /**
24
+ * Keep only the first `topK` ranked pairs. For the whole-graph predictions a value that is not
25
+ * positive keeps them all; for a node's candidates the default is 10 and the value is a slice
26
+ * end, so 0 keeps none and -2 drops the last two.
27
+ */
28
+ readonly topK?: number | undefined;
29
+ }
30
+
31
+ /** Options of the per-node candidate functions. @public */
32
+ export interface CandidateOptions extends LinkPredictionOptions {
33
+ /** The node indices to consider, in this order; default every node in index order. */
34
+ readonly candidates?: ArrayLike<number> | undefined;
35
+ }
36
+
37
+ /** Node pairs as two parallel index lists: pair k is (sources[k], targets[k]). @public */
38
+ export interface NodePairs {
39
+ readonly sources: ArrayLike<number>;
40
+ readonly targets: ArrayLike<number>;
41
+ }
42
+
43
+ /** Ranked pairs, highest score first, ties in enumeration order. @public */
44
+ export interface LinkPredictionResult extends NodePairs {
45
+ readonly sources: U32;
46
+ readonly targets: U32;
47
+ readonly scores: F64;
48
+ }
49
+
50
+ /** The best-F1 threshold's precision and recall, that F1, and the ranking AUC. @public */
51
+ export interface LinkPredictionMetrics {
52
+ readonly precision: number;
53
+ readonly recall: number;
54
+ readonly f1Score: number;
55
+ readonly auc: number;
56
+ }
57
+
58
+ type PairScore = (u: number, v: number) => number;
59
+
60
+ /**
61
+ * Adamic-Adar weights are multiples of 2^-36, so any sum of them below 2^16 is exact and the same in
62
+ * whatever order it is added: two pairs whose common neighbours have the same degrees score
63
+ * bit-identically, and a ranking never splits them by rounding. The snap moves a weight by at most
64
+ * 2^-37, far inside the 1e-9 relative tolerance of a score.
65
+ */
66
+ const WEIGHT_GRID = 2 ** 36;
67
+
68
+ /**
69
+ * The Adamic-Adar weight of a common neighbour of the given degree: 1 / ln(degree) snapped to the
70
+ * weight grid, 1 for degree 1 (ln 1 is 0) and 0 for degree 0. The legacy `adamicAdarScore` adds
71
+ * the unsnapped weights in neighbour-visit order, so its scores differ from these in the last bits
72
+ * and it may order two exactly tied pairs either way.
73
+ * @param degree - The neighbour's degree
74
+ * @returns The weight
75
+ */
76
+ function adamicAdarWeight(degree: number): number {
77
+ // ponytail: exact only while a pair's score stays below 2^16 (tens of thousands of hub neighbours);
78
+ // a coarser grid chosen from the graph's largest row sum lifts that ceiling if it is ever reached.
79
+ if (degree > 1) {
80
+ return Math.round(WEIGHT_GRID / Math.log(degree)) / WEIGHT_GRID;
81
+ }
82
+ return degree === 1 ? 1 : 0;
83
+ }
84
+
85
+ /**
86
+ * The number of distinct entries of one row of a sorted adjacency.
87
+ * @param view - The adjacency
88
+ * @param z - The row
89
+ * @returns The count
90
+ */
91
+ function distinctRowLength(view: AdjacencyView, z: number): number {
92
+ const start = view.rowPtr[z];
93
+ const end = view.rowPtr[z + 1];
94
+ let count = 0;
95
+ for (let a = start; a < end; a++) {
96
+ if (a === start || view.colIdx[a] !== view.colIdx[a - 1]) {
97
+ count++;
98
+ }
99
+ }
100
+ return count;
101
+ }
102
+
103
+ /**
104
+ * The Adamic-Adar weight of a node as a common neighbour, from its degree in distinct neighbours:
105
+ * out-neighbours for `{ directed: true }` or an undirected snapshot, else out- plus in-neighbours,
106
+ * a self-loop in both. Costs the node's degree, so one pair costs the degrees of its common
107
+ * neighbours, not the whole graph.
108
+ * @param s - The snapshot
109
+ * @param directed - The `directed` option
110
+ * @returns The weight of node z
111
+ */
112
+ function adamicAdarWeightOf(s: GraphSnapshot, directed: boolean): (z: number) => number {
113
+ const rev = s.directed && !directed ? s.reverse() : undefined;
114
+ return (z) => adamicAdarWeight(distinctRowLength(s, z) + (rev === undefined ? 0 : distinctRowLength(rev, z)));
115
+ }
116
+
117
+ /**
118
+ * The pair score: a count of common neighbours, or their weight sum when `weight` is given.
119
+ * @param s - The snapshot
120
+ * @param o - Options
121
+ * @param weight - Optional weight of a common neighbour
122
+ * @returns The score of (u, v); 0 when either is absent
123
+ */
124
+ function scorer(s: GraphSnapshot, o: CommonNeighborsOptions, weight?: (z: number) => number): PairScore {
125
+ const bwd = o.directed === true ? s.reverse() : s;
126
+ const n = s.nodeCount;
127
+ return (u, v) => (u < n && v < n ? sortedRowMerge(s, bwd, u, v, weight) : 0);
128
+ }
129
+
130
+ /**
131
+ * The Adamic-Adar pair score for many pairs: every node's weight computed once, up front.
132
+ * @param s - The snapshot
133
+ * @param o - Options
134
+ * @returns The score of (u, v)
135
+ */
136
+ function adamicAdarScorer(s: GraphSnapshot, o: CommonNeighborsOptions): PairScore {
137
+ const weightOf = adamicAdarWeightOf(s, o.directed === true);
138
+ const w = Float64Array.from({ length: s.nodeCount }, (_, z) => weightOf(z));
139
+ return scorer(s, o, (z) => w[z]);
140
+ }
141
+
142
+ /**
143
+ * Sort pairs by score, highest first and stable, and keep `order.slice(0, end)`.
144
+ * @param sources - Pair sources in enumeration order
145
+ * @param targets - Pair targets
146
+ * @param scores - Pair scores
147
+ * @param end - The slice end
148
+ * @returns The ranked pairs
149
+ */
150
+ function ranked(sources: number[], targets: number[], scores: number[], end: number): LinkPredictionResult {
151
+ const order = Array.from(scores, (_, k) => k)
152
+ .sort((a, b) => scores[b] - scores[a])
153
+ .slice(0, end);
154
+ return {
155
+ sources: Uint32Array.from(order, (k) => sources[k]),
156
+ targets: Uint32Array.from(order, (k) => targets[k]),
157
+ scores: Float64Array.from(order, (k) => scores[k]),
158
+ };
159
+ }
160
+
161
+ function predict(s: GraphSnapshot, o: LinkPredictionOptions, score: PairScore): LinkPredictionResult {
162
+ const sources: number[] = [];
163
+ const targets: number[] = [];
164
+ const scores: number[] = [];
165
+ // Each unordered pair is scored once as (u, v), u < v; without `directed` the reverse pair is
166
+ // listed too with the same score. Existence is tested on the arc u -> v only.
167
+ const mirror = o.directed !== true;
168
+ for (let u = 0; u < s.nodeCount; u++) {
169
+ for (let v = u + 1; v < s.nodeCount; v++) {
170
+ if (o.includeExisting !== true && s.hasArc(u, v)) {
171
+ continue;
172
+ }
173
+ const x = score(u, v);
174
+ if (x > 0) {
175
+ sources.push(u);
176
+ targets.push(v);
177
+ scores.push(x);
178
+ if (mirror) {
179
+ sources.push(v);
180
+ targets.push(u);
181
+ scores.push(x);
182
+ }
183
+ }
184
+ }
185
+ }
186
+ const { topK } = o;
187
+ return ranked(sources, targets, scores, topK !== undefined && topK > 0 ? topK : scores.length);
188
+ }
189
+
190
+ function forPairs(pairs: NodePairs, score: PairScore): F64 {
191
+ return Float64Array.from(pairs.sources, (u, k) => score(u, pairs.targets[k]));
192
+ }
193
+
194
+ function candidatesOf(s: GraphSnapshot, u: number, o: CandidateOptions, score: PairScore): LinkPredictionResult {
195
+ const n = s.nodeCount;
196
+ const sources: number[] = [];
197
+ const targets: number[] = [];
198
+ const scores: number[] = [];
199
+ if (u < n) {
200
+ const list = o.candidates ?? Array.from({ length: n }, (_, i) => i);
201
+ for (let k = 0; k < list.length; k++) {
202
+ const v = list[k];
203
+ if (v === u || (o.includeExisting !== true && v < n && s.hasArc(u, v))) {
204
+ continue;
205
+ }
206
+ const x = score(u, v);
207
+ if (x > 0) {
208
+ sources.push(u);
209
+ targets.push(v);
210
+ scores.push(x);
211
+ }
212
+ }
213
+ }
214
+ return ranked(sources, targets, scores, o.topK ?? 10);
215
+ }
216
+
217
+ /**
218
+ * Rank held-out edges against non-edges by score (stable, edges first among equal scores), then
219
+ * report the threshold with the best F1 and the AUC; the AUC is 0.5 when either side is empty.
220
+ * @param edges - The scores of the held-out edges
221
+ * @param nonEdges - The scores of the non-edges
222
+ * @returns The metrics
223
+ */
224
+ function rankingMetrics(edges: F64, nonEdges: F64): LinkPredictionMetrics {
225
+ const all = [...edges, ...nonEdges];
226
+ const order = Array.from(all, (_, k) => k).sort((a, b) => all[b] - all[a]);
227
+ let tp = 0;
228
+ let fp = 0;
229
+ let bestF1 = 0;
230
+ let bestPrecision = 0;
231
+ let bestRecall = 0;
232
+ let auc = 0;
233
+ for (const k of order) {
234
+ if (k < edges.length) {
235
+ tp++;
236
+ } else {
237
+ auc += tp;
238
+ fp++;
239
+ }
240
+ const precision = tp / (tp + fp);
241
+ const recall = tp / edges.length;
242
+ const f1 = precision + recall > 0 ? (2 * (precision * recall)) / (precision + recall) : 0;
243
+ if (f1 > bestF1) {
244
+ bestF1 = f1;
245
+ bestPrecision = precision;
246
+ bestRecall = recall;
247
+ }
248
+ }
249
+ auc = tp > 0 && fp > 0 ? auc / (tp * fp) : 0.5;
250
+ return { precision: bestPrecision, recall: bestRecall, f1Score: bestF1, auc };
251
+ }
252
+
253
+ /**
254
+ * Common-neighbour scores of every pair not already joined, ranked.
255
+ * @param s - The snapshot
256
+ * @param o - Options
257
+ * @returns The pairs with a positive score, highest first
258
+ * @public
259
+ */
260
+ export function commonNeighborsPrediction(s: GraphSnapshot, o: LinkPredictionOptions = {}): LinkPredictionResult {
261
+ return predict(s, o, scorer(s, o));
262
+ }
263
+
264
+ /**
265
+ * Common-neighbour scores of the given pairs, in order.
266
+ * @param s - The snapshot
267
+ * @param pairs - The pairs
268
+ * @param o - Options
269
+ * @returns One score per pair
270
+ * @public
271
+ */
272
+ export function commonNeighborsForPairs(s: GraphSnapshot, pairs: NodePairs, o: CommonNeighborsOptions = {}): F64 {
273
+ return forPairs(pairs, scorer(s, o));
274
+ }
275
+
276
+ /**
277
+ * One node's best common-neighbour 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 getTopCandidatesForNode(s: GraphSnapshot, u: number, o: CandidateOptions = {}): LinkPredictionResult {
285
+ return candidatesOf(s, u, o, scorer(s, o));
286
+ }
287
+
288
+ /**
289
+ * Ranking metrics of the common-neighbour score on held-out edges against non-edges.
290
+ * @param s - The training snapshot
291
+ * @param edges - The held-out edges
292
+ * @param nonEdges - The non-edges
293
+ * @param o - Options
294
+ * @returns The metrics
295
+ * @public
296
+ */
297
+ export function evaluateCommonNeighbors(
298
+ s: GraphSnapshot,
299
+ edges: NodePairs,
300
+ nonEdges: NodePairs,
301
+ o: CommonNeighborsOptions = {},
302
+ ): LinkPredictionMetrics {
303
+ const score = scorer(s, o);
304
+ return rankingMetrics(forPairs(edges, score), forPairs(nonEdges, score));
305
+ }
306
+
307
+ /**
308
+ * The Adamic-Adar index of two nodes: the sum over distinct common neighbours z of 1 / ln(degree(z)).
309
+ * @param s - The snapshot
310
+ * @param u - A node index
311
+ * @param v - A node index
312
+ * @param o - Options
313
+ * @returns The score
314
+ * @public
315
+ */
316
+ export function adamicAdarScore(s: GraphSnapshot, u: number, v: number, o: CommonNeighborsOptions = {}): number {
317
+ return scorer(s, o, adamicAdarWeightOf(s, o.directed === true))(u, v);
318
+ }
319
+
320
+ /**
321
+ * Adamic-Adar scores of every pair not already joined, ranked.
322
+ * @param s - The snapshot
323
+ * @param o - Options
324
+ * @returns The pairs with a positive score, highest first
325
+ * @public
326
+ */
327
+ export function adamicAdarPrediction(s: GraphSnapshot, o: LinkPredictionOptions = {}): LinkPredictionResult {
328
+ return predict(s, o, adamicAdarScorer(s, o));
329
+ }
330
+
331
+ /**
332
+ * Adamic-Adar scores of the given pairs, in order.
333
+ * @param s - The snapshot
334
+ * @param pairs - The pairs
335
+ * @param o - Options
336
+ * @returns One score per pair
337
+ * @public
338
+ */
339
+ export function adamicAdarForPairs(s: GraphSnapshot, pairs: NodePairs, o: CommonNeighborsOptions = {}): F64 {
340
+ return forPairs(pairs, adamicAdarScorer(s, o));
341
+ }
342
+
343
+ /**
344
+ * One node's best Adamic-Adar candidates, ranked.
345
+ * @param s - The snapshot
346
+ * @param u - The node index
347
+ * @param o - Options
348
+ * @returns (u, v) pairs with a positive score, highest first
349
+ * @public
350
+ */
351
+ export function getTopAdamicAdarCandidatesForNode(
352
+ s: GraphSnapshot,
353
+ u: number,
354
+ o: CandidateOptions = {},
355
+ ): LinkPredictionResult {
356
+ return candidatesOf(s, u, o, adamicAdarScorer(s, o));
357
+ }
358
+
359
+ /**
360
+ * Ranking metrics of the Adamic-Adar score on held-out edges against non-edges.
361
+ * @param s - The training snapshot
362
+ * @param edges - The held-out edges
363
+ * @param nonEdges - The non-edges
364
+ * @param o - Options
365
+ * @returns The metrics
366
+ * @public
367
+ */
368
+ export function evaluateAdamicAdar(
369
+ s: GraphSnapshot,
370
+ edges: NodePairs,
371
+ nonEdges: NodePairs,
372
+ o: CommonNeighborsOptions = {},
373
+ ): LinkPredictionMetrics {
374
+ const score = adamicAdarScorer(s, o);
375
+ return rankingMetrics(forPairs(edges, score), forPairs(nonEdges, score));
376
+ }
377
+
378
+ /**
379
+ * Both evaluations on the same held-out sets. The common-neighbour side always intersects the two
380
+ * OUT rows, whatever `directed` says, as the legacy function of this name does; the Adamic-Adar side
381
+ * honours `directed`.
382
+ * @param s - The training snapshot
383
+ * @param edges - The held-out edges
384
+ * @param nonEdges - The non-edges
385
+ * @param o - Options
386
+ * @returns The two sets of metrics
387
+ * @public
388
+ */
389
+ export function compareAdamicAdarWithCommonNeighbors(
390
+ s: GraphSnapshot,
391
+ edges: NodePairs,
392
+ nonEdges: NodePairs,
393
+ o: CommonNeighborsOptions = {},
394
+ ): { adamicAdar: LinkPredictionMetrics; commonNeighbors: LinkPredictionMetrics } {
395
+ return {
396
+ adamicAdar: evaluateAdamicAdar(s, edges, nonEdges, o),
397
+ commonNeighbors: evaluateCommonNeighbors(s, edges, nonEdges),
398
+ };
399
+ }