@graphty/algorithms 1.2.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 (230) hide show
  1. package/README.md +490 -336
  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 +40 -21
  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 +1 -0
  113. package/dist/src/index.d.ts.map +1 -1
  114. package/dist/src/index.js +4 -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.map +1 -1
  143. package/dist/src/research/grsbm.js +6 -14
  144. package/dist/src/research/grsbm.js.map +1 -1
  145. package/dist/src/research/sync.d.ts.map +1 -1
  146. package/dist/src/research/sync.js +3 -29
  147. package/dist/src/research/sync.js.map +1 -1
  148. package/dist/src/research/terahac.d.ts +2 -0
  149. package/dist/src/research/terahac.d.ts.map +1 -1
  150. package/dist/src/research/terahac.js +7 -3
  151. package/dist/src/research/terahac.js.map +1 -1
  152. package/dist/src/types/index.d.ts +8 -0
  153. package/dist/src/types/index.d.ts.map +1 -1
  154. package/dist/src/utils/algorithm-utilities.d.ts +2 -0
  155. package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
  156. package/dist/src/utils/algorithm-utilities.js +2 -0
  157. package/dist/src/utils/algorithm-utilities.js.map +1 -0
  158. package/dist/src/utils/graph-converters.d.ts +79 -0
  159. package/dist/src/utils/graph-converters.d.ts.map +1 -0
  160. package/dist/src/utils/graph-converters.js +196 -0
  161. package/dist/src/utils/graph-converters.js.map +1 -0
  162. package/dist/src/utils/graph-utilities.d.ts +62 -0
  163. package/dist/src/utils/graph-utilities.d.ts.map +1 -0
  164. package/dist/src/utils/graph-utilities.js +148 -0
  165. package/dist/src/utils/graph-utilities.js.map +1 -0
  166. package/dist/src/utils/index.d.ts +5 -0
  167. package/dist/src/utils/index.d.ts.map +1 -0
  168. package/dist/src/utils/index.js +5 -0
  169. package/dist/src/utils/index.js.map +1 -0
  170. package/dist/src/utils/math-utilities.d.ts +52 -0
  171. package/dist/src/utils/math-utilities.d.ts.map +1 -0
  172. package/dist/src/utils/math-utilities.js +123 -0
  173. package/dist/src/utils/math-utilities.js.map +1 -0
  174. package/dist/src/utils/matrix-utilities.d.ts +2 -0
  175. package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
  176. package/dist/src/utils/matrix-utilities.js +2 -0
  177. package/dist/src/utils/matrix-utilities.js.map +1 -0
  178. package/dist/src/utils/optimization-helpers.d.ts +33 -0
  179. package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
  180. package/dist/src/utils/optimization-helpers.js +47 -0
  181. package/dist/src/utils/optimization-helpers.js.map +1 -0
  182. package/package.json +18 -3
  183. package/src/algorithms/centrality/betweenness.ts +167 -199
  184. package/src/algorithms/centrality/closeness.ts +73 -191
  185. package/src/algorithms/centrality/degree.ts +3 -3
  186. package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
  187. package/src/algorithms/centrality/delta-pagerank.ts +435 -0
  188. package/src/algorithms/centrality/index.ts +2 -0
  189. package/src/algorithms/centrality/pagerank.ts +66 -0
  190. package/src/algorithms/community/girvan-newman.ts +52 -59
  191. package/src/algorithms/community/index.ts +2 -0
  192. package/src/algorithms/community/label-propagation.ts +64 -35
  193. package/src/algorithms/community/leiden.ts +40 -41
  194. package/src/algorithms/community/louvain-optimized.ts +445 -0
  195. package/src/algorithms/community/louvain.ts +24 -104
  196. package/src/algorithms/community/modularity-utils.ts +146 -0
  197. package/src/algorithms/matching/bipartite.ts +8 -44
  198. package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
  199. package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
  200. package/src/algorithms/shortest-path/dijkstra.ts +17 -15
  201. package/src/algorithms/traversal/bfs-unified.ts +433 -0
  202. package/src/algorithms/traversal/bfs-variants.ts +496 -0
  203. package/src/algorithms/traversal/bfs.ts +10 -228
  204. package/src/benchmark-all-algorithms.ts +548 -0
  205. package/src/clustering/hierarchical.ts +241 -251
  206. package/src/clustering/index.ts +4 -2
  207. package/src/clustering/k-core.ts +87 -39
  208. package/src/clustering/spectral.ts +44 -20
  209. package/src/core/graph.ts +4 -4
  210. package/src/flow/ford-fulkerson.ts +186 -254
  211. package/src/flow/min-cut.ts +21 -11
  212. package/src/index.ts +6 -0
  213. package/src/link-prediction/adamic-adar.ts +17 -30
  214. package/src/link-prediction/common-neighbors.ts +7 -16
  215. package/src/optimized/bit-packed.ts +340 -0
  216. package/src/optimized/csr-graph.ts +455 -0
  217. package/src/optimized/direction-optimized-bfs.ts +291 -0
  218. package/src/optimized/graph-adapter.ts +200 -0
  219. package/src/optimized/index.ts +36 -0
  220. package/src/research/grsbm.ts +7 -16
  221. package/src/research/sync.ts +3 -32
  222. package/src/research/terahac.ts +10 -2
  223. package/src/types/index.ts +8 -0
  224. package/src/utils/algorithm-utilities.ts +2 -0
  225. package/src/utils/graph-converters.ts +241 -0
  226. package/src/utils/graph-utilities.ts +199 -0
  227. package/src/utils/index.ts +4 -0
  228. package/src/utils/math-utilities.ts +140 -0
  229. package/src/utils/matrix-utilities.ts +2 -0
  230. package/src/utils/optimization-helpers.ts +81 -0
@@ -1,5 +1,6 @@
1
1
  import type {Graph} from "../core/graph.js";
2
2
  import type {NodeId} from "../types/index.js";
3
+ import {getCommonNeighbors, getIntermediateNodes} from "../utils/graph-utilities.js";
3
4
 
4
5
  /**
5
6
  * Common Neighbors link prediction implementation
@@ -39,23 +40,13 @@ export function commonNeighborsScore(
39
40
 
40
41
  const {directed = false} = options;
41
42
 
42
- // Get neighbors
43
- const sourceNeighbors = new Set(
44
- directed ? Array.from(graph.outNeighbors(source)) : Array.from(graph.neighbors(source)),
45
- );
46
- const targetNeighbors = new Set(
47
- directed ? Array.from(graph.inNeighbors(target)) : Array.from(graph.neighbors(target)),
48
- );
49
-
50
- // Count common neighbors
51
- let commonCount = 0;
52
- for (const neighbor of sourceNeighbors) {
53
- if (targetNeighbors.has(neighbor)) {
54
- commonCount++;
55
- }
56
- }
43
+ // Use utility function to get common neighbors
44
+ // For directed graphs, we want intermediate nodes that form paths source->X->target
45
+ const commonNeighborsSet = directed ?
46
+ getIntermediateNodes(graph, source, target) :
47
+ getCommonNeighbors(graph, source, target, false);
57
48
 
58
- return commonCount;
49
+ return commonNeighborsSet.size;
59
50
  }
60
51
 
61
52
  /**
@@ -0,0 +1,340 @@
1
+ import {TypedFastBitSet} from "typedfastbitset";
2
+
3
+ /**
4
+ * Wrapper around TypedFastBitSet with graph-specific optimizations
5
+ *
6
+ * Provides efficient bit-packed set operations optimized for graph algorithms
7
+ * with 8x memory reduction compared to standard JavaScript Set for boolean values.
8
+ */
9
+ export class GraphBitSet {
10
+ private bitset: TypedFastBitSet;
11
+ private _cardinality = 0;
12
+
13
+ constructor(capacity?: number) {
14
+ this.bitset = new TypedFastBitSet();
15
+ if (capacity) {
16
+ // Pre-allocate for known size
17
+ this.bitset.resize(capacity);
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Add a single element
23
+ */
24
+ add(index: number): void {
25
+ if (!this.bitset.has(index)) {
26
+ this.bitset.add(index);
27
+ this._cardinality++;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Remove a single element
33
+ */
34
+ remove(index: number): void {
35
+ if (this.bitset.has(index)) {
36
+ this.bitset.remove(index);
37
+ this._cardinality--;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Check if element exists
43
+ */
44
+ has(index: number): boolean {
45
+ return this.bitset.has(index);
46
+ }
47
+
48
+ /**
49
+ * Clear all elements
50
+ */
51
+ clear(): void {
52
+ this.bitset.clear();
53
+ this._cardinality = 0;
54
+ }
55
+
56
+ /**
57
+ * Check if empty
58
+ */
59
+ isEmpty(): boolean {
60
+ return this._cardinality === 0;
61
+ }
62
+
63
+ /**
64
+ * Optimized for graph algorithms - add range of indices
65
+ */
66
+ addRange(start: number, end: number): void {
67
+ for (let i = start; i < end; i++) {
68
+ if (!this.bitset.has(i)) {
69
+ this.bitset.add(i);
70
+ this._cardinality++;
71
+ }
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Fast cardinality tracking
77
+ */
78
+ size(): number {
79
+ return this._cardinality;
80
+ }
81
+
82
+ /**
83
+ * Batch operations for frontier management - swap contents
84
+ */
85
+ swap(other: GraphBitSet): void {
86
+ [this.bitset, other.bitset] = [other.bitset, this.bitset];
87
+ [this._cardinality, other._cardinality] = [other._cardinality, this._cardinality];
88
+ }
89
+
90
+ /**
91
+ * Efficient iteration
92
+ */
93
+ *[Symbol.iterator](): Generator<number> {
94
+ // Use TypedFastBitSet's optimized iteration
95
+ yield* this.bitset;
96
+ }
97
+
98
+ /**
99
+ * Set operations with cardinality tracking
100
+ */
101
+ union(other: GraphBitSet): void {
102
+ const result = this.bitset.union(other.bitset);
103
+ this.bitset = result;
104
+
105
+ const size = this.bitset.size();
106
+ this._cardinality = size;
107
+ }
108
+
109
+ intersection(other: GraphBitSet): void {
110
+ const result = this.bitset.intersection(other.bitset);
111
+ this.bitset = result;
112
+
113
+ const size = this.bitset.size();
114
+ this._cardinality = size;
115
+ }
116
+
117
+ difference(other: GraphBitSet): void {
118
+ const result = this.bitset.difference(other.bitset);
119
+ this.bitset = result;
120
+
121
+ const size = this.bitset.size();
122
+ this._cardinality = size;
123
+ }
124
+
125
+ /**
126
+ * Clone the bitset
127
+ */
128
+ clone(): GraphBitSet {
129
+ const cloned = new GraphBitSet();
130
+ cloned.bitset = this.bitset.clone();
131
+
132
+ cloned._cardinality = this._cardinality;
133
+ return cloned;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Specialized bit array for visited tracking
139
+ *
140
+ * More memory efficient than GraphBitSet for simple boolean arrays
141
+ * that don't need set operations.
142
+ */
143
+ export class VisitedBitArray {
144
+ private words: Uint32Array;
145
+ private wordCount: number;
146
+ private _size: number;
147
+
148
+ constructor(size: number) {
149
+ this._size = size;
150
+ this.wordCount = Math.ceil(size / 32);
151
+ this.words = new Uint32Array(this.wordCount);
152
+ }
153
+
154
+ /**
155
+ * Set bit at index
156
+ */
157
+ set(index: number): void {
158
+ if (index < 0 || index >= this._size) {
159
+ throw new Error(`Index ${String(index)} out of bounds [0, ${String(this._size)})`);
160
+ }
161
+
162
+ const wordIndex = index >>> 5; // divide by 32
163
+ const bitIndex = index & 31; // modulo 32
164
+ const word = this.words[wordIndex];
165
+ if (word !== undefined) {
166
+ this.words[wordIndex] = word | (1 << bitIndex);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Get bit at index
172
+ */
173
+ get(index: number): boolean {
174
+ if (index < 0 || index >= this._size) {
175
+ return false;
176
+ }
177
+
178
+ const wordIndex = index >>> 5;
179
+ const bitIndex = index & 31;
180
+ const word = this.words[wordIndex];
181
+ return word !== undefined && (word & (1 << bitIndex)) !== 0;
182
+ }
183
+
184
+ /**
185
+ * Clear all bits
186
+ */
187
+ clear(): void {
188
+ this.words.fill(0);
189
+ }
190
+
191
+ /**
192
+ * Toggle bit at index
193
+ */
194
+ toggle(index: number): void {
195
+ if (index < 0 || index >= this._size) {
196
+ throw new Error(`Index ${String(index)} out of bounds [0, ${String(this._size)})`);
197
+ }
198
+
199
+ const wordIndex = index >>> 5;
200
+ const bitIndex = index & 31;
201
+ const word = this.words[wordIndex];
202
+ if (word !== undefined) {
203
+ this.words[wordIndex] = word ^ (1 << bitIndex);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Population count for statistics
209
+ */
210
+ popcount(): number {
211
+ let count = 0;
212
+ for (let i = 0; i < this.wordCount; i++) {
213
+ const word = this.words[i];
214
+ if (word !== undefined) {
215
+ count += this.popcountWord(word);
216
+ }
217
+ }
218
+ return count;
219
+ }
220
+
221
+ /**
222
+ * Efficient population count for a single word
223
+ * Uses bit manipulation tricks for fast counting
224
+ */
225
+ private popcountWord(n: number): number {
226
+ let x = n;
227
+ x = x - ((x >>> 1) & 0x55555555);
228
+ x = (x & 0x33333333) + ((x >>> 2) & 0x33333333);
229
+ return (((x + (x >>> 4)) & 0xF0F0F0F) * 0x1010101) >>> 24;
230
+ }
231
+
232
+ /**
233
+ * Get size of the bit array
234
+ */
235
+ size(): number {
236
+ return this._size;
237
+ }
238
+
239
+ /**
240
+ * Check if all bits are zero
241
+ */
242
+ isEmpty(): boolean {
243
+ for (let i = 0; i < this.wordCount; i++) {
244
+ if (this.words[i] !== 0) {
245
+ return false;
246
+ }
247
+ }
248
+ return true;
249
+ }
250
+
251
+ /**
252
+ * Set multiple bits from array
253
+ */
254
+ setMultiple(indices: number[]): void {
255
+ for (const index of indices) {
256
+ this.set(index);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Get indices of all set bits
262
+ */
263
+ getSetIndices(): number[] {
264
+ const indices: number[] = [];
265
+ for (let wordIndex = 0; wordIndex < this.wordCount; wordIndex++) {
266
+ const word = this.words[wordIndex];
267
+ if (!word || word === 0) {
268
+ continue;
269
+ }
270
+
271
+ for (let bitIndex = 0; bitIndex < 32; bitIndex++) {
272
+ if (word & (1 << bitIndex)) {
273
+ const index = (wordIndex << 5) + bitIndex;
274
+ if (index < this._size) {
275
+ indices.push(index);
276
+ }
277
+ }
278
+ }
279
+ }
280
+ return indices;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Bit-packed distance array for BFS
286
+ *
287
+ * Optimized for storing distances using 16-bit integers (up to 65,535 levels)
288
+ * Still provides 2x memory savings compared to standard 32-bit numbers
289
+ */
290
+ export class CompactDistanceArray {
291
+ private data: Uint16Array;
292
+ private _size: number;
293
+ private static readonly INFINITY = 65535;
294
+
295
+ constructor(size: number) {
296
+ this._size = size;
297
+ this.data = new Uint16Array(size);
298
+ this.data.fill(CompactDistanceArray.INFINITY); // Initialize with max value (unvisited)
299
+ }
300
+
301
+ /**
302
+ * Set distance at index
303
+ */
304
+ set(index: number, distance: number): void {
305
+ if (distance >= CompactDistanceArray.INFINITY) {
306
+ throw new Error(`Distance exceeds maximum value (${String(CompactDistanceArray.INFINITY - 1)})`);
307
+ }
308
+
309
+ this.data[index] = distance;
310
+ }
311
+
312
+ /**
313
+ * Get distance at index
314
+ */
315
+ get(index: number): number {
316
+ const value = this.data[index];
317
+ return value ?? CompactDistanceArray.INFINITY; // Default to unvisited
318
+ }
319
+
320
+ /**
321
+ * Check if node has been visited
322
+ */
323
+ isVisited(index: number): boolean {
324
+ return this.data[index] !== CompactDistanceArray.INFINITY;
325
+ }
326
+
327
+ /**
328
+ * Reset all distances
329
+ */
330
+ clear(): void {
331
+ this.data.fill(CompactDistanceArray.INFINITY);
332
+ }
333
+
334
+ /**
335
+ * Get size
336
+ */
337
+ size(): number {
338
+ return this._size;
339
+ }
340
+ }