@graphty/algorithms 1.1.0 → 1.3.1

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 (237) hide show
  1. package/README.md +820 -235
  2. package/dist/algorithms.d.ts +42 -2
  3. package/dist/algorithms.js +11099 -2
  4. package/dist/algorithms.js.map +1 -1
  5. package/dist/src/algorithms/centrality/betweenness.d.ts +4 -0
  6. package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
  7. package/dist/src/algorithms/centrality/betweenness.js +124 -170
  8. package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
  9. package/dist/src/algorithms/centrality/closeness.d.ts +26 -1
  10. package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
  11. package/dist/src/algorithms/centrality/closeness.js +56 -149
  12. package/dist/src/algorithms/centrality/closeness.js.map +1 -1
  13. package/dist/src/algorithms/centrality/degree.js +3 -3
  14. package/dist/src/algorithms/centrality/degree.js.map +1 -1
  15. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +39 -0
  16. package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
  17. package/dist/src/algorithms/centrality/delta-pagerank-simple.js +286 -0
  18. package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
  19. package/dist/src/algorithms/centrality/delta-pagerank.d.ts +80 -0
  20. package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
  21. package/dist/src/algorithms/centrality/delta-pagerank.js +294 -0
  22. package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
  23. package/dist/src/algorithms/centrality/index.d.ts +2 -0
  24. package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
  25. package/dist/src/algorithms/centrality/index.js +1 -0
  26. package/dist/src/algorithms/centrality/index.js.map +1 -1
  27. package/dist/src/algorithms/centrality/pagerank.d.ts +17 -0
  28. package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
  29. package/dist/src/algorithms/centrality/pagerank.js +45 -0
  30. package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
  31. package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
  32. package/dist/src/algorithms/community/girvan-newman.js +47 -54
  33. package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
  34. package/dist/src/algorithms/community/index.d.ts +2 -0
  35. package/dist/src/algorithms/community/index.d.ts.map +1 -1
  36. package/dist/src/algorithms/community/index.js.map +1 -1
  37. package/dist/src/algorithms/community/label-propagation.d.ts +13 -3
  38. package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
  39. package/dist/src/algorithms/community/label-propagation.js +50 -35
  40. package/dist/src/algorithms/community/label-propagation.js.map +1 -1
  41. package/dist/src/algorithms/community/leiden.d.ts +3 -2
  42. package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
  43. package/dist/src/algorithms/community/leiden.js +34 -39
  44. package/dist/src/algorithms/community/leiden.js.map +1 -1
  45. package/dist/src/algorithms/community/louvain-optimized.d.ts +112 -0
  46. package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
  47. package/dist/src/algorithms/community/louvain-optimized.js +303 -0
  48. package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
  49. package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
  50. package/dist/src/algorithms/community/louvain.js +17 -76
  51. package/dist/src/algorithms/community/louvain.js.map +1 -1
  52. package/dist/src/algorithms/community/modularity-utils.d.ts +59 -0
  53. package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
  54. package/dist/src/algorithms/community/modularity-utils.js +112 -0
  55. package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
  56. package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
  57. package/dist/src/algorithms/matching/bipartite.js +8 -40
  58. package/dist/src/algorithms/matching/bipartite.js.map +1 -1
  59. package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
  60. package/dist/src/algorithms/shortest-path/bellman-ford.js +1 -12
  61. package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
  62. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +37 -0
  63. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
  64. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +193 -0
  65. package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
  66. package/dist/src/algorithms/shortest-path/dijkstra.d.ts +5 -2
  67. package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
  68. package/dist/src/algorithms/shortest-path/dijkstra.js +15 -14
  69. package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
  70. package/dist/src/algorithms/traversal/bfs-unified.d.ts +29 -0
  71. package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
  72. package/dist/src/algorithms/traversal/bfs-unified.js +333 -0
  73. package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
  74. package/dist/src/algorithms/traversal/bfs-variants.d.ts +54 -0
  75. package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
  76. package/dist/src/algorithms/traversal/bfs-variants.js +368 -0
  77. package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
  78. package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
  79. package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
  80. package/dist/src/algorithms/traversal/bfs.js +5 -182
  81. package/dist/src/algorithms/traversal/bfs.js.map +1 -1
  82. package/dist/src/benchmark-all-algorithms.d.ts +23 -0
  83. package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
  84. package/dist/src/benchmark-all-algorithms.js +462 -0
  85. package/dist/src/benchmark-all-algorithms.js.map +1 -0
  86. package/dist/src/clustering/hierarchical.d.ts +16 -15
  87. package/dist/src/clustering/hierarchical.d.ts.map +1 -1
  88. package/dist/src/clustering/hierarchical.js +209 -223
  89. package/dist/src/clustering/hierarchical.js.map +1 -1
  90. package/dist/src/clustering/index.d.ts +4 -2
  91. package/dist/src/clustering/index.d.ts.map +1 -1
  92. package/dist/src/clustering/index.js +2 -2
  93. package/dist/src/clustering/index.js.map +1 -1
  94. package/dist/src/clustering/k-core.d.ts +16 -15
  95. package/dist/src/clustering/k-core.d.ts.map +1 -1
  96. package/dist/src/clustering/k-core.js +57 -21
  97. package/dist/src/clustering/k-core.js.map +1 -1
  98. package/dist/src/clustering/spectral.d.ts +8 -0
  99. package/dist/src/clustering/spectral.d.ts.map +1 -1
  100. package/dist/src/clustering/spectral.js +158 -35
  101. package/dist/src/clustering/spectral.js.map +1 -1
  102. package/dist/src/core/graph.js +4 -4
  103. package/dist/src/core/graph.js.map +1 -1
  104. package/dist/src/flow/ford-fulkerson.d.ts +17 -11
  105. package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
  106. package/dist/src/flow/ford-fulkerson.js +141 -217
  107. package/dist/src/flow/ford-fulkerson.js.map +1 -1
  108. package/dist/src/flow/min-cut.d.ts +6 -5
  109. package/dist/src/flow/min-cut.d.ts.map +1 -1
  110. package/dist/src/flow/min-cut.js +17 -8
  111. package/dist/src/flow/min-cut.js.map +1 -1
  112. package/dist/src/index.d.ts +2 -0
  113. package/dist/src/index.d.ts.map +1 -1
  114. package/dist/src/index.js +6 -0
  115. package/dist/src/index.js.map +1 -1
  116. package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
  117. package/dist/src/link-prediction/adamic-adar.js +17 -26
  118. package/dist/src/link-prediction/adamic-adar.js.map +1 -1
  119. package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
  120. package/dist/src/link-prediction/common-neighbors.js +7 -11
  121. package/dist/src/link-prediction/common-neighbors.js.map +1 -1
  122. package/dist/src/optimized/bit-packed.d.ts +143 -0
  123. package/dist/src/optimized/bit-packed.d.ts.map +1 -0
  124. package/dist/src/optimized/bit-packed.js +292 -0
  125. package/dist/src/optimized/bit-packed.js.map +1 -0
  126. package/dist/src/optimized/csr-graph.d.ts +86 -0
  127. package/dist/src/optimized/csr-graph.d.ts.map +1 -0
  128. package/dist/src/optimized/csr-graph.js +341 -0
  129. package/dist/src/optimized/csr-graph.js.map +1 -0
  130. package/dist/src/optimized/direction-optimized-bfs.d.ts +74 -0
  131. package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
  132. package/dist/src/optimized/direction-optimized-bfs.js +223 -0
  133. package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
  134. package/dist/src/optimized/graph-adapter.d.ts +62 -0
  135. package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
  136. package/dist/src/optimized/graph-adapter.js +146 -0
  137. package/dist/src/optimized/graph-adapter.js.map +1 -0
  138. package/dist/src/optimized/index.d.ts +14 -0
  139. package/dist/src/optimized/index.d.ts.map +1 -0
  140. package/dist/src/optimized/index.js +28 -0
  141. package/dist/src/optimized/index.js.map +1 -0
  142. package/dist/src/research/grsbm.d.ts +83 -0
  143. package/dist/src/research/grsbm.d.ts.map +1 -0
  144. package/dist/src/research/grsbm.js +403 -0
  145. package/dist/src/research/grsbm.js.map +1 -0
  146. package/dist/src/research/index.d.ts +12 -0
  147. package/dist/src/research/index.d.ts.map +1 -0
  148. package/dist/src/research/index.js +14 -0
  149. package/dist/src/research/index.js.map +1 -0
  150. package/dist/src/research/sync.d.ts +49 -0
  151. package/dist/src/research/sync.d.ts.map +1 -0
  152. package/dist/src/research/sync.js +316 -0
  153. package/dist/src/research/sync.js.map +1 -0
  154. package/dist/src/research/terahac.d.ts +65 -0
  155. package/dist/src/research/terahac.d.ts.map +1 -0
  156. package/dist/src/research/terahac.js +379 -0
  157. package/dist/src/research/terahac.js.map +1 -0
  158. package/dist/src/types/index.d.ts +8 -0
  159. package/dist/src/types/index.d.ts.map +1 -1
  160. package/dist/src/utils/algorithm-utilities.d.ts +2 -0
  161. package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
  162. package/dist/src/utils/algorithm-utilities.js +2 -0
  163. package/dist/src/utils/algorithm-utilities.js.map +1 -0
  164. package/dist/src/utils/graph-converters.d.ts +79 -0
  165. package/dist/src/utils/graph-converters.d.ts.map +1 -0
  166. package/dist/src/utils/graph-converters.js +196 -0
  167. package/dist/src/utils/graph-converters.js.map +1 -0
  168. package/dist/src/utils/graph-utilities.d.ts +62 -0
  169. package/dist/src/utils/graph-utilities.d.ts.map +1 -0
  170. package/dist/src/utils/graph-utilities.js +148 -0
  171. package/dist/src/utils/graph-utilities.js.map +1 -0
  172. package/dist/src/utils/index.d.ts +5 -0
  173. package/dist/src/utils/index.d.ts.map +1 -0
  174. package/dist/src/utils/index.js +5 -0
  175. package/dist/src/utils/index.js.map +1 -0
  176. package/dist/src/utils/math-utilities.d.ts +52 -0
  177. package/dist/src/utils/math-utilities.d.ts.map +1 -0
  178. package/dist/src/utils/math-utilities.js +123 -0
  179. package/dist/src/utils/math-utilities.js.map +1 -0
  180. package/dist/src/utils/matrix-utilities.d.ts +2 -0
  181. package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
  182. package/dist/src/utils/matrix-utilities.js +2 -0
  183. package/dist/src/utils/matrix-utilities.js.map +1 -0
  184. package/dist/src/utils/optimization-helpers.d.ts +33 -0
  185. package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
  186. package/dist/src/utils/optimization-helpers.js +47 -0
  187. package/dist/src/utils/optimization-helpers.js.map +1 -0
  188. package/package.json +28 -4
  189. package/src/algorithms/centrality/betweenness.ts +167 -199
  190. package/src/algorithms/centrality/closeness.ts +73 -191
  191. package/src/algorithms/centrality/degree.ts +3 -3
  192. package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
  193. package/src/algorithms/centrality/delta-pagerank.ts +435 -0
  194. package/src/algorithms/centrality/index.ts +2 -0
  195. package/src/algorithms/centrality/pagerank.ts +66 -0
  196. package/src/algorithms/community/girvan-newman.ts +52 -59
  197. package/src/algorithms/community/index.ts +2 -0
  198. package/src/algorithms/community/label-propagation.ts +64 -35
  199. package/src/algorithms/community/leiden.ts +40 -41
  200. package/src/algorithms/community/louvain-optimized.ts +445 -0
  201. package/src/algorithms/community/louvain.ts +24 -104
  202. package/src/algorithms/community/modularity-utils.ts +146 -0
  203. package/src/algorithms/matching/bipartite.ts +8 -44
  204. package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
  205. package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
  206. package/src/algorithms/shortest-path/dijkstra.ts +17 -15
  207. package/src/algorithms/traversal/bfs-unified.ts +433 -0
  208. package/src/algorithms/traversal/bfs-variants.ts +496 -0
  209. package/src/algorithms/traversal/bfs.ts +10 -228
  210. package/src/benchmark-all-algorithms.ts +548 -0
  211. package/src/clustering/hierarchical.ts +241 -251
  212. package/src/clustering/index.ts +4 -2
  213. package/src/clustering/k-core.ts +87 -39
  214. package/src/clustering/spectral.ts +185 -34
  215. package/src/core/graph.ts +4 -4
  216. package/src/flow/ford-fulkerson.ts +186 -254
  217. package/src/flow/min-cut.ts +21 -11
  218. package/src/index.ts +9 -0
  219. package/src/link-prediction/adamic-adar.ts +17 -30
  220. package/src/link-prediction/common-neighbors.ts +7 -16
  221. package/src/optimized/bit-packed.ts +340 -0
  222. package/src/optimized/csr-graph.ts +455 -0
  223. package/src/optimized/direction-optimized-bfs.ts +291 -0
  224. package/src/optimized/graph-adapter.ts +200 -0
  225. package/src/optimized/index.ts +36 -0
  226. package/src/research/grsbm.ts +580 -0
  227. package/src/research/index.ts +17 -0
  228. package/src/research/sync.ts +440 -0
  229. package/src/research/terahac.ts +514 -0
  230. package/src/types/index.ts +8 -0
  231. package/src/utils/algorithm-utilities.ts +2 -0
  232. package/src/utils/graph-converters.ts +241 -0
  233. package/src/utils/graph-utilities.ts +199 -0
  234. package/src/utils/index.ts +4 -0
  235. package/src/utils/math-utilities.ts +140 -0
  236. package/src/utils/matrix-utilities.ts +2 -0
  237. package/src/utils/optimization-helpers.ts +81 -0
@@ -0,0 +1,291 @@
1
+ import type {NodeId} from "../types/index.js";
2
+ import {CompactDistanceArray, GraphBitSet} from "./bit-packed.js";
3
+ import {CSRGraph} from "./csr-graph.js";
4
+
5
+ /**
6
+ * Options for Direction-Optimized BFS
7
+ */
8
+ export interface DirectionOptimizedBFSOptions {
9
+ alpha?: number; // Default: 15 - Controls top-down to bottom-up switch
10
+ beta?: number; // Default: 18 - Controls bottom-up to top-down switch
11
+ }
12
+
13
+ /**
14
+ * Result of BFS traversal
15
+ */
16
+ export interface BFSResult<TNodeId> {
17
+ distances: Map<TNodeId, number>;
18
+ parents: Map<TNodeId, TNodeId | null>;
19
+ visitedCount: number;
20
+ }
21
+
22
+ /**
23
+ * Direction-Optimized Breadth-First Search
24
+ *
25
+ * Dynamically switches between top-down and bottom-up search strategies
26
+ * based on the size of the frontier. Particularly effective for low-diameter
27
+ * graphs like social networks.
28
+ *
29
+ * Based on: Beamer, S., Asanović, K., & Patterson, D. (2012).
30
+ * "Direction-optimizing breadth-first search." SC'12.
31
+ */
32
+ export class DirectionOptimizedBFS<TNodeId = NodeId> {
33
+ private graph: CSRGraph<TNodeId>;
34
+ private alpha: number;
35
+ private beta: number;
36
+
37
+ // Data structures
38
+ private parent: Int32Array; // -1 = unvisited, -2 = source, else parent ID
39
+ private frontier: GraphBitSet; // Current frontier bitmap
40
+ private nextFrontier: GraphBitSet; // Next level frontier
41
+ private distances: CompactDistanceArray;
42
+
43
+ constructor(graph: CSRGraph<TNodeId>, options?: DirectionOptimizedBFSOptions) {
44
+ this.graph = graph;
45
+ this.alpha = options?.alpha ?? 15;
46
+ this.beta = options?.beta ?? 18;
47
+
48
+ const nodeCount = graph.nodeCount();
49
+ this.parent = new Int32Array(nodeCount).fill(-1);
50
+ this.frontier = new GraphBitSet(nodeCount);
51
+ this.nextFrontier = new GraphBitSet(nodeCount);
52
+ this.distances = new CompactDistanceArray(nodeCount);
53
+ }
54
+
55
+ /**
56
+ * Perform BFS from a single source
57
+ */
58
+ search(source: TNodeId): BFSResult<TNodeId> {
59
+ const sourceIndex = this.graph.nodeToIndex(source);
60
+ this.parent[sourceIndex] = -2; // Mark as source
61
+ this.frontier.add(sourceIndex);
62
+ this.distances.set(sourceIndex, 0);
63
+
64
+ // let currentDistance = 0; // Variable not used
65
+ // Initialize edgesToCheck to total edges to prevent immediate switch to bottom-up
66
+ let edgesToCheck = this.graph.edgeCount();
67
+ let scoutCount = 0; // Will be set after first top-down step
68
+ let awakeCount = 1; // Number of nodes in current frontier
69
+ let oldAwakeCount = 0;
70
+
71
+ // Direction tracking
72
+ let useBottomUp = false;
73
+
74
+ while (!this.frontier.isEmpty()) {
75
+ oldAwakeCount = awakeCount;
76
+
77
+ if (useBottomUp) {
78
+ // Check if we should switch back to top-down
79
+ if (awakeCount >= oldAwakeCount ||
80
+ awakeCount > this.graph.nodeCount() / this.beta) {
81
+ useBottomUp = false;
82
+ }
83
+ } else {
84
+ // Check if we should switch to bottom-up
85
+ if (scoutCount > edgesToCheck / this.alpha) {
86
+ useBottomUp = true;
87
+ }
88
+ }
89
+
90
+ if (useBottomUp) {
91
+ awakeCount = this.bottomUpStep();
92
+ } else {
93
+ scoutCount = this.topDownStep();
94
+ awakeCount = this.nextFrontier.size();
95
+ }
96
+
97
+ // Swap frontiers
98
+ this.frontier.swap(this.nextFrontier);
99
+ this.nextFrontier.clear();
100
+
101
+ // currentDistance++; // Variable not used
102
+ edgesToCheck = this.calculateEdgesToCheck();
103
+ }
104
+
105
+ return this.buildResult();
106
+ }
107
+
108
+ /**
109
+ * Top-down BFS step - explore from frontier
110
+ */
111
+ private topDownStep(): number {
112
+ let scoutCount = 0;
113
+
114
+ // Iterate through frontier nodes
115
+ for (const node of this.frontier) {
116
+ const currentDistance = this.distances.get(node);
117
+
118
+ for (const neighbor of this.graph.iterateNeighborIndices(node)) {
119
+ if (this.parent[neighbor] === -1) {
120
+ this.parent[neighbor] = node;
121
+ this.distances.set(neighbor, currentDistance + 1);
122
+ this.nextFrontier.add(neighbor);
123
+ scoutCount += this.graph.outDegreeByIndex(neighbor);
124
+ }
125
+ }
126
+ }
127
+
128
+ return scoutCount;
129
+ }
130
+
131
+ /**
132
+ * Bottom-up BFS step - check unvisited nodes
133
+ */
134
+ private bottomUpStep(): number {
135
+ const nodeCount = this.graph.nodeCount();
136
+ let awakeCount = 0;
137
+
138
+ // Check all unvisited nodes
139
+ for (let node = 0; node < nodeCount; node++) {
140
+ if (this.parent[node] === -1) {
141
+ // Use incoming edges for bottom-up traversal
142
+ for (const neighbor of this.graph.iterateIncomingNeighborIndices(node)) {
143
+ if (this.frontier.has(neighbor)) {
144
+ this.parent[node] = neighbor;
145
+ const neighborDist = this.distances.get(neighbor);
146
+ this.distances.set(node, neighborDist + 1);
147
+ this.nextFrontier.add(node);
148
+ awakeCount++;
149
+ break; // Found a parent, no need to check more
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ return awakeCount;
156
+ }
157
+
158
+ /**
159
+ * Calculate edges to check for switching heuristic
160
+ */
161
+ private calculateEdgesToCheck(): number {
162
+ let count = 0;
163
+ for (const node of this.frontier) {
164
+ count += this.graph.outDegreeByIndex(node);
165
+ }
166
+ return count;
167
+ }
168
+
169
+ /**
170
+ * Build result map from internal data structures
171
+ */
172
+ private buildResult(): BFSResult<TNodeId> {
173
+ const distances = new Map<TNodeId, number>();
174
+ const parents = new Map<TNodeId, TNodeId | null>();
175
+ let visitedCount = 0;
176
+
177
+ for (let i = 0; i < this.graph.nodeCount(); i++) {
178
+ if (this.parent[i] !== -1) {
179
+ const nodeId = this.graph.indexToNodeId(i);
180
+ distances.set(nodeId, this.distances.get(i));
181
+
182
+ if (this.parent[i] === -2) {
183
+ // Source node
184
+ parents.set(nodeId, null);
185
+ } else {
186
+ // Regular node with parent
187
+ const parentIndex = this.parent[i];
188
+ if (parentIndex !== undefined && parentIndex >= 0) {
189
+ parents.set(nodeId, this.graph.indexToNodeId(parentIndex));
190
+ }
191
+ }
192
+
193
+ visitedCount++;
194
+ }
195
+ }
196
+
197
+ return {distances, parents, visitedCount};
198
+ }
199
+
200
+ /**
201
+ * Perform multi-source BFS
202
+ */
203
+ searchMultiple(sources: TNodeId[]): BFSResult<TNodeId> {
204
+ // Initialize multiple sources
205
+ for (const source of sources) {
206
+ const sourceIndex = this.graph.nodeToIndex(source);
207
+ this.parent[sourceIndex] = -2; // Mark as source
208
+ this.frontier.add(sourceIndex);
209
+ this.distances.set(sourceIndex, 0);
210
+ }
211
+
212
+ // let currentDistance = 0; // Variable not used
213
+ let edgesToCheck = 0;
214
+ let scoutCount = 0;
215
+
216
+ // Calculate initial edges to check
217
+ for (const node of this.frontier) {
218
+ const degree = this.graph.outDegreeByIndex(node);
219
+ edgesToCheck += degree;
220
+ scoutCount += degree;
221
+ }
222
+
223
+ let awakeCount = sources.length;
224
+ let oldAwakeCount = 0;
225
+ let useBottomUp = false;
226
+
227
+ while (!this.frontier.isEmpty()) {
228
+ oldAwakeCount = awakeCount;
229
+
230
+ if (useBottomUp) {
231
+ if (awakeCount >= oldAwakeCount ||
232
+ awakeCount > this.graph.nodeCount() / this.beta) {
233
+ useBottomUp = false;
234
+ }
235
+ } else {
236
+ if (scoutCount > edgesToCheck / this.alpha) {
237
+ useBottomUp = true;
238
+ }
239
+ }
240
+
241
+ if (useBottomUp) {
242
+ awakeCount = this.bottomUpStep();
243
+ } else {
244
+ scoutCount = this.topDownStep();
245
+ awakeCount = this.nextFrontier.size();
246
+ }
247
+
248
+ this.frontier.swap(this.nextFrontier);
249
+ this.nextFrontier.clear();
250
+
251
+ // currentDistance++; // Variable not used
252
+ edgesToCheck = this.calculateEdgesToCheck();
253
+ }
254
+
255
+ return this.buildResult();
256
+ }
257
+
258
+ /**
259
+ * Reset internal state for reuse
260
+ */
261
+ reset(): void {
262
+ this.parent.fill(-1);
263
+ this.frontier.clear();
264
+ this.nextFrontier.clear();
265
+ this.distances.clear();
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Convenience function for single-source BFS
271
+ */
272
+ export function directionOptimizedBFS<TNodeId = NodeId>(
273
+ graph: CSRGraph<TNodeId>,
274
+ source: TNodeId,
275
+ options?: DirectionOptimizedBFSOptions,
276
+ ): BFSResult<TNodeId> {
277
+ const bfs = new DirectionOptimizedBFS(graph, options);
278
+ return bfs.search(source);
279
+ }
280
+
281
+ /**
282
+ * Convenience function for multi-source BFS
283
+ */
284
+ export function directionOptimizedBFSMultiple<TNodeId = NodeId>(
285
+ graph: CSRGraph<TNodeId>,
286
+ sources: TNodeId[],
287
+ options?: DirectionOptimizedBFSOptions,
288
+ ): BFSResult<TNodeId> {
289
+ const bfs = new DirectionOptimizedBFS(graph, options);
290
+ return bfs.searchMultiple(sources);
291
+ }
@@ -0,0 +1,200 @@
1
+ import type {Graph} from "../core/graph.js";
2
+ import type {NodeId} from "../types/index.js";
3
+ import {CSRGraph, type ReadonlyGraph} from "./csr-graph.js";
4
+
5
+ /**
6
+ * Adapter to convert standard Graph to CSR format
7
+ *
8
+ * Provides transparent conversion while maintaining API compatibility
9
+ */
10
+ export class GraphAdapter<TNodeId = NodeId> implements ReadonlyGraph<TNodeId> {
11
+ private csrGraph: CSRGraph<TNodeId>;
12
+
13
+ constructor(graph: Graph | ReadonlyGraph<TNodeId>) {
14
+ // Check if already a CSRGraph
15
+ if (graph instanceof CSRGraph) {
16
+ this.csrGraph = graph as CSRGraph<TNodeId>;
17
+ } else {
18
+ // Convert to CSR format
19
+ this.csrGraph = this.convertToCSR(graph);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Convert standard graph to CSR format
25
+ */
26
+ private convertToCSR(graph: Graph | ReadonlyGraph<TNodeId>): CSRGraph<TNodeId> {
27
+ const adjacencyList = new Map<TNodeId, TNodeId[]>();
28
+ const weights = new Map<string, number>();
29
+
30
+ // Handle both Graph and ReadonlyGraph interfaces
31
+ if ("nodes" in graph && typeof graph.nodes === "function") {
32
+ // Build adjacency list from Graph
33
+ for (const node of graph.nodes()) {
34
+ const nodeId = (node as {id: TNodeId}).id;
35
+ const neighbors: TNodeId[] = [];
36
+
37
+ const graphTyped = graph as Graph;
38
+ for (const neighborId of graphTyped.neighbors(nodeId as NodeId)) {
39
+ neighbors.push(neighborId as TNodeId);
40
+
41
+ // Get edge weight if available
42
+ if ("getEdge" in graph && typeof graph.getEdge === "function") {
43
+ const edge = graphTyped.getEdge(nodeId as NodeId, neighborId);
44
+ if (edge?.weight !== undefined) {
45
+ weights.set(`${String(nodeId)}-${String(neighborId)}`, edge.weight);
46
+ }
47
+ }
48
+ }
49
+
50
+ adjacencyList.set(nodeId, neighbors);
51
+ }
52
+ } else if ("nodeIds" in graph && typeof graph.nodeIds === "function") {
53
+ // Handle ReadonlyGraph with nodeIds method
54
+ interface ReadonlyGraphWithNodeIds {
55
+ nodeIds(): Iterable<TNodeId>;
56
+ edges?(): Iterable<{source: TNodeId, target: TNodeId, weight?: number}>;
57
+ }
58
+ const readonlyGraph = graph as ReadonlyGraphWithNodeIds;
59
+ for (const nodeId of readonlyGraph.nodeIds()) {
60
+ adjacencyList.set(nodeId, []);
61
+ }
62
+
63
+ // Build adjacency from edges
64
+ if ("edges" in readonlyGraph && typeof readonlyGraph.edges === "function") {
65
+ for (const edge of readonlyGraph.edges()) {
66
+ const neighbors = adjacencyList.get(edge.source);
67
+ if (neighbors) {
68
+ neighbors.push(edge.target);
69
+ if (edge.weight !== undefined) {
70
+ weights.set(`${String(edge.source)}-${String(edge.target)}`, edge.weight);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+
77
+ return new CSRGraph(adjacencyList, weights.size > 0 ? weights : undefined);
78
+ }
79
+
80
+ // Delegate all methods to CSR implementation
81
+ nodeCount(): number {
82
+ return this.csrGraph.nodeCount();
83
+ }
84
+
85
+ edgeCount(): number {
86
+ return this.csrGraph.edgeCount();
87
+ }
88
+
89
+ hasNode(nodeId: TNodeId): boolean {
90
+ return this.csrGraph.hasNode(nodeId);
91
+ }
92
+
93
+ hasEdge(source: TNodeId, target: TNodeId): boolean {
94
+ return this.csrGraph.hasEdge(source, target);
95
+ }
96
+
97
+ neighbors(nodeId: TNodeId): IterableIterator<TNodeId> {
98
+ return this.csrGraph.neighbors(nodeId);
99
+ }
100
+
101
+ outDegree(nodeId: TNodeId): number {
102
+ return this.csrGraph.outDegree(nodeId);
103
+ }
104
+
105
+ nodes(): IterableIterator<TNodeId> {
106
+ return this.csrGraph.nodes();
107
+ }
108
+
109
+ /**
110
+ * Get the underlying CSR graph
111
+ */
112
+ getCSRGraph(): CSRGraph<TNodeId> {
113
+ return this.csrGraph;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Configuration for graph algorithm optimizations
119
+ */
120
+ export interface GraphAlgorithmConfig {
121
+ // Enable optimizations
122
+ useDirectionOptimizedBFS?: boolean;
123
+ useCSRFormat?: boolean;
124
+ useBitPackedStructures?: boolean;
125
+
126
+ // Algorithm-specific parameters
127
+ bfsAlpha?: number;
128
+ bfsBeta?: number;
129
+
130
+ // Memory vs speed tradeoffs
131
+ preallocateSize?: number;
132
+ enableCaching?: boolean;
133
+ }
134
+
135
+ /**
136
+ * Configure optimizations globally
137
+ * @deprecated This function is a no-op and will be removed in a future version
138
+ */
139
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
140
+ export function configureOptimizations(_config: GraphAlgorithmConfig): void {
141
+ // No-op for backward compatibility
142
+ }
143
+
144
+ /**
145
+ * Get current configuration
146
+ * @deprecated This function returns empty config and will be removed in a future version
147
+ */
148
+ export function getOptimizationConfig(): GraphAlgorithmConfig {
149
+ return {};
150
+ }
151
+
152
+ /**
153
+ * Check if a graph is already in CSR format
154
+ */
155
+ export function isCSRGraph<TNodeId = NodeId>(graph: unknown): graph is CSRGraph<TNodeId> {
156
+ return graph instanceof CSRGraph;
157
+ }
158
+
159
+ /**
160
+ * Convert any graph to CSR format
161
+ */
162
+ export function toCSRGraph<TNodeId = NodeId>(
163
+ graph: Graph | ReadonlyGraph<TNodeId> | CSRGraph<TNodeId>,
164
+ ): CSRGraph<TNodeId> {
165
+ if (isCSRGraph<TNodeId>(graph)) {
166
+ return graph;
167
+ }
168
+
169
+ const adapter = new GraphAdapter<TNodeId>(graph);
170
+ return adapter.getCSRGraph();
171
+ }
172
+
173
+ /**
174
+ * Create an optimized graph from nodes and edges
175
+ */
176
+ export function createOptimizedGraph<TNodeId = NodeId>(
177
+ nodes: TNodeId[],
178
+ edges: [TNodeId, TNodeId, number?][],
179
+ ): CSRGraph<TNodeId> {
180
+ const adjacencyList = new Map<TNodeId, TNodeId[]>();
181
+ const weights = new Map<string, number>();
182
+
183
+ // Initialize nodes
184
+ for (const node of nodes) {
185
+ adjacencyList.set(node, []);
186
+ }
187
+
188
+ // Add edges
189
+ for (const [source, target, weight] of edges) {
190
+ const neighbors = adjacencyList.get(source);
191
+ if (neighbors) {
192
+ neighbors.push(target);
193
+ if (weight !== undefined) {
194
+ weights.set(`${String(source)}-${String(target)}`, weight);
195
+ }
196
+ }
197
+ }
198
+
199
+ return new CSRGraph(adjacencyList, weights.size > 0 ? weights : undefined);
200
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Optimized graph algorithm implementations
3
+ *
4
+ * High-performance implementations using:
5
+ * - Direction-Optimized BFS
6
+ * - Compressed Sparse Row (CSR) format
7
+ * - Bit-packed data structures
8
+ */
9
+
10
+ // Configuration and optimization control
11
+ export {
12
+ configureOptimizations,
13
+ getOptimizationConfig,
14
+ type GraphAlgorithmConfig,
15
+ } from "./graph-adapter.js";
16
+
17
+ // Note: The main BFS functions in algorithms/traversal/bfs.ts automatically
18
+ // use these optimizations for large graphs (>10k nodes) when optimizations are enabled.
19
+ // No manual configuration needed - just use breadthFirstSearch, shortestPathBFS, etc.
20
+ //
21
+ // The previously exported bfsOptimized, shortestPathBFSOptimized, and
22
+ // singleSourceShortestPathBFSOptimized functions have been removed since they
23
+ // are no longer needed. All optimization happens automatically.
24
+
25
+ // BFS optimization functions have been removed. The main BFS functions
26
+ // (breadthFirstSearch, shortestPathBFS, singleSourceShortestPathBFS)
27
+ // in algorithms/traversal/bfs.ts now automatically use optimizations
28
+ // for large graphs without requiring manual configuration.
29
+
30
+ // Export data structures for advanced users
31
+ export {CompactDistanceArray, GraphBitSet, VisitedBitArray} from "./bit-packed.js";
32
+ export {CSRGraph} from "./csr-graph.js";
33
+ export {DirectionOptimizedBFS} from "./direction-optimized-bfs.js";
34
+
35
+ // Export utilities
36
+ export {createOptimizedGraph, isCSRGraph, toCSRGraph} from "./graph-adapter.js";