@optave/codegraph 3.8.0 → 3.9.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 (310) hide show
  1. package/README.md +13 -8
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +137 -86
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/metrics.d.ts +0 -3
  6. package/dist/ast-analysis/metrics.d.ts.map +1 -1
  7. package/dist/ast-analysis/metrics.js +30 -13
  8. package/dist/ast-analysis/metrics.js.map +1 -1
  9. package/dist/ast-analysis/shared.d.ts.map +1 -1
  10. package/dist/ast-analysis/shared.js +24 -19
  11. package/dist/ast-analysis/shared.js.map +1 -1
  12. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  13. package/dist/ast-analysis/visitor-utils.js +55 -39
  14. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  15. package/dist/ast-analysis/visitor.d.ts.map +1 -1
  16. package/dist/ast-analysis/visitor.js +91 -70
  17. package/dist/ast-analysis/visitor.js.map +1 -1
  18. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  19. package/dist/ast-analysis/visitors/ast-store-visitor.js +54 -58
  20. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  21. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  22. package/dist/ast-analysis/visitors/complexity-visitor.js +81 -39
  23. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  24. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  25. package/dist/ast-analysis/visitors/dataflow-visitor.js +57 -38
  26. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  27. package/dist/cli/commands/branch-compare.d.ts.map +1 -1
  28. package/dist/cli/commands/branch-compare.js +4 -0
  29. package/dist/cli/commands/branch-compare.js.map +1 -1
  30. package/dist/cli/commands/diff-impact.d.ts.map +1 -1
  31. package/dist/cli/commands/diff-impact.js +2 -1
  32. package/dist/cli/commands/diff-impact.js.map +1 -1
  33. package/dist/cli/commands/info.d.ts.map +1 -1
  34. package/dist/cli/commands/info.js +3 -2
  35. package/dist/cli/commands/info.js.map +1 -1
  36. package/dist/cli/commands/watch.d.ts.map +1 -1
  37. package/dist/cli/commands/watch.js +16 -2
  38. package/dist/cli/commands/watch.js.map +1 -1
  39. package/dist/db/connection.d.ts.map +1 -1
  40. package/dist/db/connection.js +29 -26
  41. package/dist/db/connection.js.map +1 -1
  42. package/dist/db/query-builder.d.ts.map +1 -1
  43. package/dist/db/query-builder.js +16 -5
  44. package/dist/db/query-builder.js.map +1 -1
  45. package/dist/db/repository/base.d.ts +16 -0
  46. package/dist/db/repository/base.d.ts.map +1 -1
  47. package/dist/db/repository/base.js +31 -0
  48. package/dist/db/repository/base.js.map +1 -1
  49. package/dist/db/repository/native-repository.d.ts +7 -1
  50. package/dist/db/repository/native-repository.d.ts.map +1 -1
  51. package/dist/db/repository/native-repository.js +100 -1
  52. package/dist/db/repository/native-repository.js.map +1 -1
  53. package/dist/db/repository/nodes.d.ts.map +1 -1
  54. package/dist/db/repository/nodes.js +8 -4
  55. package/dist/db/repository/nodes.js.map +1 -1
  56. package/dist/db/repository/sqlite-repository.d.ts +4 -0
  57. package/dist/db/repository/sqlite-repository.d.ts.map +1 -1
  58. package/dist/db/repository/sqlite-repository.js +51 -0
  59. package/dist/db/repository/sqlite-repository.js.map +1 -1
  60. package/dist/domain/analysis/brief.d.ts.map +1 -1
  61. package/dist/domain/analysis/brief.js +13 -17
  62. package/dist/domain/analysis/brief.js.map +1 -1
  63. package/dist/domain/analysis/context.d.ts.map +1 -1
  64. package/dist/domain/analysis/context.js +14 -11
  65. package/dist/domain/analysis/context.js.map +1 -1
  66. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  67. package/dist/domain/analysis/dependencies.js +64 -59
  68. package/dist/domain/analysis/dependencies.js.map +1 -1
  69. package/dist/domain/analysis/fn-impact.d.ts +2 -7
  70. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  71. package/dist/domain/analysis/fn-impact.js +33 -31
  72. package/dist/domain/analysis/fn-impact.js.map +1 -1
  73. package/dist/domain/analysis/implementations.d.ts.map +1 -1
  74. package/dist/domain/analysis/implementations.js +11 -19
  75. package/dist/domain/analysis/implementations.js.map +1 -1
  76. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  77. package/dist/domain/analysis/module-map.js +55 -76
  78. package/dist/domain/analysis/module-map.js.map +1 -1
  79. package/dist/domain/analysis/query-helpers.d.ts +7 -0
  80. package/dist/domain/analysis/query-helpers.d.ts.map +1 -1
  81. package/dist/domain/analysis/query-helpers.js +15 -1
  82. package/dist/domain/analysis/query-helpers.js.map +1 -1
  83. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  84. package/dist/domain/graph/builder/pipeline.js +352 -107
  85. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  86. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  87. package/dist/domain/graph/builder/stages/build-edges.js +49 -18
  88. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  89. package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
  90. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  91. package/dist/domain/graph/builder/stages/finalize.js +2 -2
  92. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  93. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  94. package/dist/domain/graph/builder/stages/insert-nodes.js +32 -21
  95. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  96. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  97. package/dist/domain/graph/builder/stages/resolve-imports.js +95 -84
  98. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  99. package/dist/domain/graph/cycles.d.ts +6 -0
  100. package/dist/domain/graph/cycles.d.ts.map +1 -1
  101. package/dist/domain/graph/cycles.js +114 -22
  102. package/dist/domain/graph/cycles.js.map +1 -1
  103. package/dist/domain/graph/resolve.js +1 -1
  104. package/dist/domain/graph/resolve.js.map +1 -1
  105. package/dist/domain/graph/watcher.d.ts +2 -0
  106. package/dist/domain/graph/watcher.d.ts.map +1 -1
  107. package/dist/domain/graph/watcher.js +170 -75
  108. package/dist/domain/graph/watcher.js.map +1 -1
  109. package/dist/domain/parser.d.ts +3 -4
  110. package/dist/domain/parser.d.ts.map +1 -1
  111. package/dist/domain/parser.js +141 -89
  112. package/dist/domain/parser.js.map +1 -1
  113. package/dist/domain/search/generator.js +1 -1
  114. package/dist/domain/search/generator.js.map +1 -1
  115. package/dist/domain/search/models.d.ts +4 -3
  116. package/dist/domain/search/models.d.ts.map +1 -1
  117. package/dist/domain/search/models.js +23 -8
  118. package/dist/domain/search/models.js.map +1 -1
  119. package/dist/domain/search/search/hybrid.d.ts.map +1 -1
  120. package/dist/domain/search/search/hybrid.js +29 -18
  121. package/dist/domain/search/search/hybrid.js.map +1 -1
  122. package/dist/extractors/go.js +36 -33
  123. package/dist/extractors/go.js.map +1 -1
  124. package/dist/extractors/helpers.d.ts.map +1 -1
  125. package/dist/extractors/helpers.js +40 -29
  126. package/dist/extractors/helpers.js.map +1 -1
  127. package/dist/extractors/java.js +58 -46
  128. package/dist/extractors/java.js.map +1 -1
  129. package/dist/extractors/javascript.js +65 -54
  130. package/dist/extractors/javascript.js.map +1 -1
  131. package/dist/extractors/kotlin.js +84 -78
  132. package/dist/extractors/kotlin.js.map +1 -1
  133. package/dist/extractors/python.js +29 -24
  134. package/dist/extractors/python.js.map +1 -1
  135. package/dist/extractors/rust.js +41 -32
  136. package/dist/extractors/rust.js.map +1 -1
  137. package/dist/extractors/solidity.js +58 -67
  138. package/dist/extractors/solidity.js.map +1 -1
  139. package/dist/extractors/swift.js +83 -81
  140. package/dist/extractors/swift.js.map +1 -1
  141. package/dist/extractors/zig.js +58 -60
  142. package/dist/extractors/zig.js.map +1 -1
  143. package/dist/features/ast.d.ts +16 -14
  144. package/dist/features/ast.d.ts.map +1 -1
  145. package/dist/features/ast.js +83 -81
  146. package/dist/features/ast.js.map +1 -1
  147. package/dist/features/audit.d.ts.map +1 -1
  148. package/dist/features/audit.js +8 -6
  149. package/dist/features/audit.js.map +1 -1
  150. package/dist/features/branch-compare.d.ts.map +1 -1
  151. package/dist/features/branch-compare.js +69 -72
  152. package/dist/features/branch-compare.js.map +1 -1
  153. package/dist/features/communities.d.ts.map +1 -1
  154. package/dist/features/communities.js +19 -7
  155. package/dist/features/communities.js.map +1 -1
  156. package/dist/features/complexity.d.ts.map +1 -1
  157. package/dist/features/complexity.js +120 -125
  158. package/dist/features/complexity.js.map +1 -1
  159. package/dist/features/dataflow.d.ts.map +1 -1
  160. package/dist/features/dataflow.js +136 -137
  161. package/dist/features/dataflow.js.map +1 -1
  162. package/dist/features/flow.d.ts.map +1 -1
  163. package/dist/features/flow.js +84 -79
  164. package/dist/features/flow.js.map +1 -1
  165. package/dist/features/structure-query.d.ts.map +1 -1
  166. package/dist/features/structure-query.js +69 -65
  167. package/dist/features/structure-query.js.map +1 -1
  168. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  169. package/dist/graph/algorithms/leiden/optimiser.js +70 -55
  170. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  171. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  172. package/dist/graph/algorithms/leiden/partition.js +288 -266
  173. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  174. package/dist/graph/model.d.ts.map +1 -1
  175. package/dist/graph/model.js +5 -1
  176. package/dist/graph/model.js.map +1 -1
  177. package/dist/infrastructure/config.d.ts.map +1 -1
  178. package/dist/infrastructure/config.js +6 -4
  179. package/dist/infrastructure/config.js.map +1 -1
  180. package/dist/infrastructure/suppress.d.ts +25 -0
  181. package/dist/infrastructure/suppress.d.ts.map +1 -0
  182. package/dist/infrastructure/suppress.js +43 -0
  183. package/dist/infrastructure/suppress.js.map +1 -0
  184. package/dist/mcp/server.d.ts.map +1 -1
  185. package/dist/mcp/server.js +29 -24
  186. package/dist/mcp/server.js.map +1 -1
  187. package/dist/presentation/dataflow.d.ts.map +1 -1
  188. package/dist/presentation/dataflow.js +47 -38
  189. package/dist/presentation/dataflow.js.map +1 -1
  190. package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -1
  191. package/dist/presentation/diff-impact-mermaid.js +60 -51
  192. package/dist/presentation/diff-impact-mermaid.js.map +1 -1
  193. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  194. package/dist/presentation/queries-cli/exports.js +20 -14
  195. package/dist/presentation/queries-cli/exports.js.map +1 -1
  196. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  197. package/dist/presentation/queries-cli/impact.js +15 -13
  198. package/dist/presentation/queries-cli/impact.js.map +1 -1
  199. package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
  200. package/dist/presentation/queries-cli/inspect.js +101 -79
  201. package/dist/presentation/queries-cli/inspect.js.map +1 -1
  202. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  203. package/dist/presentation/queries-cli/overview.js +25 -16
  204. package/dist/presentation/queries-cli/overview.js.map +1 -1
  205. package/dist/presentation/queries-cli/path.js +26 -20
  206. package/dist/presentation/queries-cli/path.js.map +1 -1
  207. package/dist/presentation/result-formatter.d.ts +10 -0
  208. package/dist/presentation/result-formatter.d.ts.map +1 -1
  209. package/dist/presentation/result-formatter.js +16 -1
  210. package/dist/presentation/result-formatter.js.map +1 -1
  211. package/dist/presentation/viewer.d.ts.map +1 -1
  212. package/dist/presentation/viewer.js +18 -12
  213. package/dist/presentation/viewer.js.map +1 -1
  214. package/dist/shared/errors.d.ts +5 -0
  215. package/dist/shared/errors.d.ts.map +1 -1
  216. package/dist/shared/errors.js +5 -0
  217. package/dist/shared/errors.js.map +1 -1
  218. package/dist/shared/hierarchy.d.ts +8 -2
  219. package/dist/shared/hierarchy.d.ts.map +1 -1
  220. package/dist/shared/hierarchy.js +42 -1
  221. package/dist/shared/hierarchy.js.map +1 -1
  222. package/dist/shared/normalize.d.ts +6 -1
  223. package/dist/shared/normalize.d.ts.map +1 -1
  224. package/dist/shared/normalize.js +20 -12
  225. package/dist/shared/normalize.js.map +1 -1
  226. package/dist/shared/paginate.d.ts +0 -9
  227. package/dist/shared/paginate.d.ts.map +1 -1
  228. package/dist/shared/paginate.js +0 -15
  229. package/dist/shared/paginate.js.map +1 -1
  230. package/dist/types.d.ts +12 -5
  231. package/dist/types.d.ts.map +1 -1
  232. package/grammars/tree-sitter-erlang.wasm +0 -0
  233. package/grammars/tree-sitter-gleam.wasm +0 -0
  234. package/package.json +9 -9
  235. package/src/ast-analysis/engine.ts +176 -104
  236. package/src/ast-analysis/metrics.ts +33 -11
  237. package/src/ast-analysis/shared.ts +33 -24
  238. package/src/ast-analysis/visitor-utils.ts +52 -32
  239. package/src/ast-analysis/visitor.ts +132 -71
  240. package/src/ast-analysis/visitors/ast-store-visitor.ts +53 -50
  241. package/src/ast-analysis/visitors/complexity-visitor.ts +89 -40
  242. package/src/ast-analysis/visitors/dataflow-visitor.ts +87 -43
  243. package/src/cli/commands/branch-compare.ts +4 -0
  244. package/src/cli/commands/diff-impact.ts +2 -1
  245. package/src/cli/commands/info.ts +3 -2
  246. package/src/cli/commands/watch.ts +16 -2
  247. package/src/db/connection.ts +29 -28
  248. package/src/db/query-builder.ts +15 -3
  249. package/src/db/repository/base.ts +34 -0
  250. package/src/db/repository/native-repository.ts +104 -1
  251. package/src/db/repository/nodes.ts +13 -8
  252. package/src/db/repository/sqlite-repository.ts +55 -0
  253. package/src/domain/analysis/brief.ts +15 -25
  254. package/src/domain/analysis/context.ts +17 -10
  255. package/src/domain/analysis/dependencies.ts +77 -81
  256. package/src/domain/analysis/fn-impact.ts +36 -43
  257. package/src/domain/analysis/implementations.ts +11 -17
  258. package/src/domain/analysis/module-map.ts +58 -92
  259. package/src/domain/analysis/query-helpers.ts +18 -1
  260. package/src/domain/graph/builder/pipeline.ts +409 -99
  261. package/src/domain/graph/builder/stages/build-edges.ts +45 -19
  262. package/src/domain/graph/builder/stages/detect-changes.ts +2 -2
  263. package/src/domain/graph/builder/stages/finalize.ts +2 -2
  264. package/src/domain/graph/builder/stages/insert-nodes.ts +59 -34
  265. package/src/domain/graph/builder/stages/resolve-imports.ts +122 -100
  266. package/src/domain/graph/cycles.ts +110 -23
  267. package/src/domain/graph/resolve.ts +1 -1
  268. package/src/domain/graph/watcher.ts +202 -96
  269. package/src/domain/parser.ts +143 -89
  270. package/src/domain/search/generator.ts +1 -1
  271. package/src/domain/search/models.ts +26 -7
  272. package/src/domain/search/search/hybrid.ts +69 -51
  273. package/src/extractors/go.ts +43 -33
  274. package/src/extractors/helpers.ts +37 -23
  275. package/src/extractors/java.ts +66 -47
  276. package/src/extractors/javascript.ts +66 -54
  277. package/src/extractors/kotlin.ts +84 -77
  278. package/src/extractors/python.ts +31 -25
  279. package/src/extractors/rust.ts +37 -29
  280. package/src/extractors/solidity.ts +57 -61
  281. package/src/extractors/swift.ts +81 -80
  282. package/src/extractors/zig.ts +58 -61
  283. package/src/features/ast.ts +130 -110
  284. package/src/features/audit.ts +8 -6
  285. package/src/features/branch-compare.ts +105 -79
  286. package/src/features/communities.ts +25 -10
  287. package/src/features/complexity.ts +171 -134
  288. package/src/features/dataflow.ts +165 -175
  289. package/src/features/flow.ts +129 -92
  290. package/src/features/structure-query.ts +79 -64
  291. package/src/graph/algorithms/leiden/optimiser.ts +99 -55
  292. package/src/graph/algorithms/leiden/partition.ts +359 -294
  293. package/src/graph/model.ts +6 -1
  294. package/src/infrastructure/config.ts +6 -4
  295. package/src/infrastructure/suppress.ts +47 -0
  296. package/src/mcp/server.ts +53 -37
  297. package/src/presentation/dataflow.ts +50 -44
  298. package/src/presentation/diff-impact-mermaid.ts +104 -62
  299. package/src/presentation/queries-cli/exports.ts +21 -13
  300. package/src/presentation/queries-cli/impact.ts +15 -13
  301. package/src/presentation/queries-cli/inspect.ts +100 -81
  302. package/src/presentation/queries-cli/overview.ts +26 -16
  303. package/src/presentation/queries-cli/path.ts +33 -25
  304. package/src/presentation/result-formatter.ts +19 -1
  305. package/src/presentation/viewer.ts +42 -14
  306. package/src/shared/errors.ts +6 -0
  307. package/src/shared/hierarchy.ts +50 -2
  308. package/src/shared/normalize.ts +31 -12
  309. package/src/shared/paginate.ts +0 -17
  310. package/src/types.ts +26 -5
@@ -56,6 +56,34 @@ function u8get(a: Uint8Array, i: number): number {
56
56
  return a[i] as number;
57
57
  }
58
58
 
59
+ /* ------------------------------------------------------------------ */
60
+ /* Internal mutable state bucket shared by all extracted functions */
61
+ /* ------------------------------------------------------------------ */
62
+
63
+ interface PartitionState {
64
+ graph: GraphAdapter;
65
+ n: number;
66
+ nodeCommunity: Int32Array;
67
+ communityCount: number;
68
+ communityTotalSize: Float64Array;
69
+ communityNodeCount: Int32Array;
70
+ communityInternalEdgeWeight: Float64Array;
71
+ communityTotalStrength: Float64Array;
72
+ communityTotalOutStrength: Float64Array;
73
+ communityTotalInStrength: Float64Array;
74
+ /* scratch arrays for neighbor accumulation */
75
+ candidateCommunities: Int32Array;
76
+ candidateCommunityCount: number;
77
+ neighborEdgeWeightToCommunity: Float64Array;
78
+ outEdgeWeightToCommunity: Float64Array;
79
+ inEdgeWeightFromCommunity: Float64Array;
80
+ isCandidateCommunity: Uint8Array;
81
+ }
82
+
83
+ /* ------------------------------------------------------------------ */
84
+ /* Aggregate helpers (shared by initializeAggregates & compact) */
85
+ /* ------------------------------------------------------------------ */
86
+
59
87
  /**
60
88
  * Accumulate per-community node-level totals (size, count, strength) into the
61
89
  * provided aggregate arrays. Both `initializeAggregates` and `compactCommunityIds`
@@ -159,343 +187,380 @@ function buildSortedCommunityIds(
159
187
  }
160
188
  }
161
189
 
162
- export function makePartition(graph: GraphAdapter): Partition {
163
- const n: number = graph.n;
164
- const nodeCommunity = new Int32Array(n);
165
- for (let i = 0; i < n; i++) nodeCommunity[i] = i;
166
- let communityCount: number = n;
167
-
168
- let communityTotalSize = new Float64Array(communityCount);
169
- let communityNodeCount = new Int32Array(communityCount);
170
- let communityInternalEdgeWeight = new Float64Array(communityCount);
171
- let communityTotalStrength = new Float64Array(communityCount);
172
- let communityTotalOutStrength = new Float64Array(communityCount);
173
- let communityTotalInStrength = new Float64Array(communityCount);
174
-
175
- const candidateCommunities = new Int32Array(n);
176
- let candidateCommunityCount: number = 0;
177
- const neighborEdgeWeightToCommunity = new Float64Array(n);
178
- const outEdgeWeightToCommunity = new Float64Array(n);
179
- const inEdgeWeightFromCommunity = new Float64Array(n);
180
- const isCandidateCommunity = new Uint8Array(n);
181
-
182
- function ensureCommCapacity(newCount: number): void {
183
- if (newCount <= communityTotalSize.length) return;
184
- const growTo: number = Math.max(newCount, Math.ceil(communityTotalSize.length * 1.5));
185
- communityTotalSize = growFloat(communityTotalSize, growTo);
186
- communityNodeCount = growInt(communityNodeCount, growTo);
187
- communityInternalEdgeWeight = growFloat(communityInternalEdgeWeight, growTo);
188
- communityTotalStrength = growFloat(communityTotalStrength, growTo);
189
- communityTotalOutStrength = growFloat(communityTotalOutStrength, growTo);
190
- communityTotalInStrength = growFloat(communityTotalInStrength, growTo);
191
- }
190
+ /* ------------------------------------------------------------------ */
191
+ /* Extracted: capacity management */
192
+ /* ------------------------------------------------------------------ */
192
193
 
193
- function initializeAggregates(): void {
194
- communityTotalSize.fill(0);
195
- communityNodeCount.fill(0);
196
- communityInternalEdgeWeight.fill(0);
197
- communityTotalStrength.fill(0);
198
- communityTotalOutStrength.fill(0);
199
- communityTotalInStrength.fill(0);
200
- accumulateNodeAggregates(
201
- graph,
202
- nodeCommunity,
203
- n,
204
- communityTotalSize,
205
- communityNodeCount,
206
- communityInternalEdgeWeight,
207
- communityTotalStrength,
208
- communityTotalOutStrength,
209
- communityTotalInStrength,
210
- );
211
- accumulateInternalEdgeWeights(graph, nodeCommunity, n, communityInternalEdgeWeight);
194
+ function ensureCommCapacity(s: PartitionState, newCount: number): void {
195
+ if (newCount <= s.communityTotalSize.length) return;
196
+ const growTo: number = Math.max(newCount, Math.ceil(s.communityTotalSize.length * 1.5));
197
+ s.communityTotalSize = growFloat(s.communityTotalSize, growTo);
198
+ s.communityNodeCount = growInt(s.communityNodeCount, growTo);
199
+ s.communityInternalEdgeWeight = growFloat(s.communityInternalEdgeWeight, growTo);
200
+ s.communityTotalStrength = growFloat(s.communityTotalStrength, growTo);
201
+ s.communityTotalOutStrength = growFloat(s.communityTotalOutStrength, growTo);
202
+ s.communityTotalInStrength = growFloat(s.communityTotalInStrength, growTo);
203
+ }
204
+
205
+ /* ------------------------------------------------------------------ */
206
+ /* Extracted: aggregate initialization */
207
+ /* ------------------------------------------------------------------ */
208
+
209
+ function initAggregates(s: PartitionState): void {
210
+ s.communityTotalSize.fill(0);
211
+ s.communityNodeCount.fill(0);
212
+ s.communityInternalEdgeWeight.fill(0);
213
+ s.communityTotalStrength.fill(0);
214
+ s.communityTotalOutStrength.fill(0);
215
+ s.communityTotalInStrength.fill(0);
216
+ accumulateNodeAggregates(
217
+ s.graph,
218
+ s.nodeCommunity,
219
+ s.n,
220
+ s.communityTotalSize,
221
+ s.communityNodeCount,
222
+ s.communityInternalEdgeWeight,
223
+ s.communityTotalStrength,
224
+ s.communityTotalOutStrength,
225
+ s.communityTotalInStrength,
226
+ );
227
+ accumulateInternalEdgeWeights(s.graph, s.nodeCommunity, s.n, s.communityInternalEdgeWeight);
228
+ }
229
+
230
+ /* ------------------------------------------------------------------ */
231
+ /* Extracted: neighbor accumulation */
232
+ /* ------------------------------------------------------------------ */
233
+
234
+ function resetScratch(s: PartitionState): void {
235
+ for (let i = 0; i < s.candidateCommunityCount; i++) {
236
+ const c: number = iget(s.candidateCommunities, i);
237
+ s.isCandidateCommunity[c] = 0;
238
+ s.neighborEdgeWeightToCommunity[c] = 0;
239
+ s.outEdgeWeightToCommunity[c] = 0;
240
+ s.inEdgeWeightFromCommunity[c] = 0;
212
241
  }
242
+ s.candidateCommunityCount = 0;
243
+ }
213
244
 
214
- function resetScratch(): void {
215
- for (let i = 0; i < candidateCommunityCount; i++) {
216
- const c: number = iget(candidateCommunities, i);
217
- isCandidateCommunity[c] = 0;
218
- neighborEdgeWeightToCommunity[c] = 0;
219
- outEdgeWeightToCommunity[c] = 0;
220
- inEdgeWeightFromCommunity[c] = 0;
245
+ function touchCandidate(s: PartitionState, c: number): void {
246
+ if (u8get(s.isCandidateCommunity, c)) return;
247
+ s.isCandidateCommunity[c] = 1;
248
+ s.candidateCommunities[s.candidateCommunityCount++] = c;
249
+ }
250
+
251
+ function accumulateNeighborWeights(s: PartitionState, v: number): number {
252
+ resetScratch(s);
253
+ const ci: number = iget(s.nodeCommunity, v);
254
+ touchCandidate(s, ci);
255
+ if (s.graph.directed) {
256
+ const outL = s.graph.outEdges[v]!;
257
+ for (let k = 0; k < outL.length; k++) {
258
+ const j: number = outL[k]!.to;
259
+ const w: number = outL[k]!.w;
260
+ const cj: number = iget(s.nodeCommunity, j);
261
+ touchCandidate(s, cj);
262
+ s.outEdgeWeightToCommunity[cj] = fget(s.outEdgeWeightToCommunity, cj) + w;
263
+ }
264
+ const inL = s.graph.inEdges[v]!;
265
+ for (let k = 0; k < inL.length; k++) {
266
+ const i2: number = inL[k]!.from;
267
+ const w: number = inL[k]!.w;
268
+ const ci2: number = iget(s.nodeCommunity, i2);
269
+ touchCandidate(s, ci2);
270
+ s.inEdgeWeightFromCommunity[ci2] = fget(s.inEdgeWeightFromCommunity, ci2) + w;
271
+ }
272
+ } else {
273
+ const list = s.graph.outEdges[v]!;
274
+ for (let k = 0; k < list.length; k++) {
275
+ const j: number = list[k]!.to;
276
+ const w: number = list[k]!.w;
277
+ const cj: number = iget(s.nodeCommunity, j);
278
+ touchCandidate(s, cj);
279
+ s.neighborEdgeWeightToCommunity[cj] = fget(s.neighborEdgeWeightToCommunity, cj) + w;
221
280
  }
222
- candidateCommunityCount = 0;
223
281
  }
282
+ return s.candidateCommunityCount;
283
+ }
284
+
285
+ /* ------------------------------------------------------------------ */
286
+ /* Extracted: modularity delta computations */
287
+ /* ------------------------------------------------------------------ */
224
288
 
225
- function touch(c: number): void {
226
- if (u8get(isCandidateCommunity, c)) return;
227
- isCandidateCommunity[c] = 1;
228
- candidateCommunities[candidateCommunityCount++] = c;
289
+ function computeDeltaModularityUndirected(
290
+ s: PartitionState,
291
+ v: number,
292
+ newC: number,
293
+ gamma: number = 1.0,
294
+ ): number {
295
+ const oldC: number = iget(s.nodeCommunity, v);
296
+ if (newC === oldC) return 0;
297
+ const twoM: number = s.graph.totalWeight;
298
+ const strengthV: number = fget(s.graph.strengthOut, v);
299
+ const weightToNew: number =
300
+ newC < s.neighborEdgeWeightToCommunity.length
301
+ ? fget(s.neighborEdgeWeightToCommunity, newC) || 0
302
+ : 0;
303
+ const weightToOld: number = fget(s.neighborEdgeWeightToCommunity, oldC) || 0;
304
+ const totalStrengthNew: number =
305
+ newC < s.communityTotalStrength.length ? fget(s.communityTotalStrength, newC) : 0;
306
+ const totalStrengthOld: number = fget(s.communityTotalStrength, oldC);
307
+ const gain_remove: number = -(
308
+ weightToOld / twoM -
309
+ (gamma * (strengthV * totalStrengthOld)) / (twoM * twoM)
310
+ );
311
+ const gain_add: number =
312
+ weightToNew / twoM - (gamma * (strengthV * totalStrengthNew)) / (twoM * twoM);
313
+ return gain_remove + gain_add;
314
+ }
315
+
316
+ function computeDeltaModularityDirected(
317
+ s: PartitionState,
318
+ v: number,
319
+ newC: number,
320
+ gamma: number = 1.0,
321
+ ): number {
322
+ const oldC: number = iget(s.nodeCommunity, v);
323
+ if (newC === oldC) return 0;
324
+ const totalEdgeWeight: number = s.graph.totalWeight;
325
+ const strengthOutV: number = fget(s.graph.strengthOut, v);
326
+ const strengthInV: number = fget(s.graph.strengthIn, v);
327
+ const inFromNew: number =
328
+ newC < s.inEdgeWeightFromCommunity.length ? fget(s.inEdgeWeightFromCommunity, newC) || 0 : 0;
329
+ const outToNew: number =
330
+ newC < s.outEdgeWeightToCommunity.length ? fget(s.outEdgeWeightToCommunity, newC) || 0 : 0;
331
+ const inFromOld: number = fget(s.inEdgeWeightFromCommunity, oldC) || 0;
332
+ const outToOld: number = fget(s.outEdgeWeightToCommunity, oldC) || 0;
333
+ const totalInStrengthNew: number =
334
+ newC < s.communityTotalInStrength.length ? fget(s.communityTotalInStrength, newC) : 0;
335
+ const totalOutStrengthNew: number =
336
+ newC < s.communityTotalOutStrength.length ? fget(s.communityTotalOutStrength, newC) : 0;
337
+ const totalInStrengthOld: number = fget(s.communityTotalInStrength, oldC);
338
+ const totalOutStrengthOld: number = fget(s.communityTotalOutStrength, oldC);
339
+ // Self-loop correction + constant term (see modularity.ts diffModularityDirected)
340
+ const selfW: number = fget(s.graph.selfLoop, v) || 0;
341
+ const deltaInternal: number =
342
+ (inFromNew + outToNew - inFromOld - outToOld + 2 * selfW) / totalEdgeWeight;
343
+ const deltaExpected: number =
344
+ (gamma *
345
+ (strengthOutV * (totalInStrengthNew - totalInStrengthOld) +
346
+ strengthInV * (totalOutStrengthNew - totalOutStrengthOld) +
347
+ 2 * strengthOutV * strengthInV)) /
348
+ (totalEdgeWeight * totalEdgeWeight);
349
+ return deltaInternal - deltaExpected;
350
+ }
351
+
352
+ function computeDeltaCPM(s: PartitionState, v: number, newC: number, gamma: number = 1.0): number {
353
+ const oldC: number = iget(s.nodeCommunity, v);
354
+ if (newC === oldC) return 0;
355
+ let w_old: number;
356
+ let w_new: number;
357
+ let selfCorrection: number = 0;
358
+ if (s.graph.directed) {
359
+ w_old =
360
+ (fget(s.outEdgeWeightToCommunity, oldC) || 0) +
361
+ (fget(s.inEdgeWeightFromCommunity, oldC) || 0);
362
+ w_new =
363
+ newC < s.outEdgeWeightToCommunity.length
364
+ ? (fget(s.outEdgeWeightToCommunity, newC) || 0) +
365
+ (fget(s.inEdgeWeightFromCommunity, newC) || 0)
366
+ : 0;
367
+ // Self-loop correction (see cpm.ts diffCPM)
368
+ selfCorrection = 2 * (fget(s.graph.selfLoop, v) || 0);
369
+ } else {
370
+ w_old = fget(s.neighborEdgeWeightToCommunity, oldC) || 0;
371
+ w_new =
372
+ newC < s.neighborEdgeWeightToCommunity.length
373
+ ? fget(s.neighborEdgeWeightToCommunity, newC) || 0
374
+ : 0;
229
375
  }
376
+ const nodeSz: number = fget(s.graph.size, v) || 1;
377
+ const sizeOld: number = fget(s.communityTotalSize, oldC) || 0;
378
+ const sizeNew: number = newC < s.communityTotalSize.length ? fget(s.communityTotalSize, newC) : 0;
379
+ return w_new - w_old + selfCorrection - gamma * nodeSz * (sizeNew - sizeOld + nodeSz);
380
+ }
230
381
 
231
- function accumulateNeighborCommunityEdgeWeights(v: number): number {
232
- resetScratch();
233
- const ci: number = iget(nodeCommunity, v);
234
- touch(ci);
235
- if (graph.directed) {
236
- const outL = graph.outEdges[v]!;
237
- for (let k = 0; k < outL.length; k++) {
238
- const j: number = outL[k]!.to;
239
- const w: number = outL[k]!.w;
240
- const cj: number = iget(nodeCommunity, j);
241
- touch(cj);
242
- outEdgeWeightToCommunity[cj] = fget(outEdgeWeightToCommunity, cj) + w;
243
- }
244
- const inL = graph.inEdges[v]!;
245
- for (let k = 0; k < inL.length; k++) {
246
- const i2: number = inL[k]!.from;
247
- const w: number = inL[k]!.w;
248
- const ci2: number = iget(nodeCommunity, i2);
249
- touch(ci2);
250
- inEdgeWeightFromCommunity[ci2] = fget(inEdgeWeightFromCommunity, ci2) + w;
251
- }
252
- } else {
253
- const list = graph.outEdges[v]!;
254
- for (let k = 0; k < list.length; k++) {
255
- const j: number = list[k]!.to;
256
- const w: number = list[k]!.w;
257
- const cj: number = iget(nodeCommunity, j);
258
- touch(cj);
259
- neighborEdgeWeightToCommunity[cj] = fget(neighborEdgeWeightToCommunity, cj) + w;
260
- }
261
- }
262
- return candidateCommunityCount;
382
+ /* ------------------------------------------------------------------ */
383
+ /* Extracted: node move */
384
+ /* ------------------------------------------------------------------ */
385
+
386
+ function moveNode(s: PartitionState, v: number, newC: number): boolean {
387
+ const oldC: number = iget(s.nodeCommunity, v);
388
+ if (oldC === newC) return false;
389
+ if (newC >= s.communityCount) {
390
+ ensureCommCapacity(s, newC + 1);
391
+ s.communityCount = newC + 1;
263
392
  }
393
+ const strengthOutV: number = fget(s.graph.strengthOut, v);
394
+ const strengthInV: number = fget(s.graph.strengthIn, v);
395
+ const selfLoopWeight: number = fget(s.graph.selfLoop, v);
396
+ const nodeSz: number = fget(s.graph.size, v);
264
397
 
265
- const twoMUndirected: number = graph.totalWeight;
266
- function deltaModularityUndirected(v: number, newC: number, gamma: number = 1.0): number {
267
- const oldC: number = iget(nodeCommunity, v);
268
- if (newC === oldC) return 0;
269
- const strengthV: number = fget(graph.strengthOut, v);
270
- const weightToNew: number =
271
- newC < neighborEdgeWeightToCommunity.length
272
- ? fget(neighborEdgeWeightToCommunity, newC) || 0
273
- : 0;
274
- const weightToOld: number = fget(neighborEdgeWeightToCommunity, oldC) || 0;
275
- const totalStrengthNew: number =
276
- newC < communityTotalStrength.length ? fget(communityTotalStrength, newC) : 0;
277
- const totalStrengthOld: number = fget(communityTotalStrength, oldC);
278
- const gain_remove: number = -(
279
- weightToOld / twoMUndirected -
280
- (gamma * (strengthV * totalStrengthOld)) / (twoMUndirected * twoMUndirected)
281
- );
282
- const gain_add: number =
283
- weightToNew / twoMUndirected -
284
- (gamma * (strengthV * totalStrengthNew)) / (twoMUndirected * twoMUndirected);
285
- return gain_remove + gain_add;
398
+ s.communityNodeCount[oldC] = iget(s.communityNodeCount, oldC) - 1;
399
+ s.communityNodeCount[newC] = iget(s.communityNodeCount, newC) + 1;
400
+ s.communityTotalSize[oldC] = fget(s.communityTotalSize, oldC) - nodeSz;
401
+ s.communityTotalSize[newC] = fget(s.communityTotalSize, newC) + nodeSz;
402
+ if (s.graph.directed) {
403
+ s.communityTotalOutStrength[oldC] = fget(s.communityTotalOutStrength, oldC) - strengthOutV;
404
+ s.communityTotalOutStrength[newC] = fget(s.communityTotalOutStrength, newC) + strengthOutV;
405
+ s.communityTotalInStrength[oldC] = fget(s.communityTotalInStrength, oldC) - strengthInV;
406
+ s.communityTotalInStrength[newC] = fget(s.communityTotalInStrength, newC) + strengthInV;
407
+ } else {
408
+ s.communityTotalStrength[oldC] = fget(s.communityTotalStrength, oldC) - strengthOutV;
409
+ s.communityTotalStrength[newC] = fget(s.communityTotalStrength, newC) + strengthOutV;
286
410
  }
287
411
 
288
- function deltaModularityDirected(v: number, newC: number, gamma: number = 1.0): number {
289
- const oldC: number = iget(nodeCommunity, v);
290
- if (newC === oldC) return 0;
291
- const totalEdgeWeight: number = graph.totalWeight;
292
- const strengthOutV: number = fget(graph.strengthOut, v);
293
- const strengthInV: number = fget(graph.strengthIn, v);
294
- const inFromNew: number =
295
- newC < inEdgeWeightFromCommunity.length ? fget(inEdgeWeightFromCommunity, newC) || 0 : 0;
412
+ if (s.graph.directed) {
413
+ const outToOld: number = fget(s.outEdgeWeightToCommunity, oldC) || 0;
414
+ const inFromOld: number = fget(s.inEdgeWeightFromCommunity, oldC) || 0;
296
415
  const outToNew: number =
297
- newC < outEdgeWeightToCommunity.length ? fget(outEdgeWeightToCommunity, newC) || 0 : 0;
298
- const inFromOld: number = fget(inEdgeWeightFromCommunity, oldC) || 0;
299
- const outToOld: number = fget(outEdgeWeightToCommunity, oldC) || 0;
300
- const totalInStrengthNew: number =
301
- newC < communityTotalInStrength.length ? fget(communityTotalInStrength, newC) : 0;
302
- const totalOutStrengthNew: number =
303
- newC < communityTotalOutStrength.length ? fget(communityTotalOutStrength, newC) : 0;
304
- const totalInStrengthOld: number = fget(communityTotalInStrength, oldC);
305
- const totalOutStrengthOld: number = fget(communityTotalOutStrength, oldC);
306
- // Self-loop correction + constant term (see modularity.ts diffModularityDirected)
307
- const selfW: number = fget(graph.selfLoop, v) || 0;
308
- const deltaInternal: number =
309
- (inFromNew + outToNew - inFromOld - outToOld + 2 * selfW) / totalEdgeWeight;
310
- const deltaExpected: number =
311
- (gamma *
312
- (strengthOutV * (totalInStrengthNew - totalInStrengthOld) +
313
- strengthInV * (totalOutStrengthNew - totalOutStrengthOld) +
314
- 2 * strengthOutV * strengthInV)) /
315
- (totalEdgeWeight * totalEdgeWeight);
316
- return deltaInternal - deltaExpected;
416
+ newC < s.outEdgeWeightToCommunity.length ? fget(s.outEdgeWeightToCommunity, newC) || 0 : 0;
417
+ const inFromNew: number =
418
+ newC < s.inEdgeWeightFromCommunity.length ? fget(s.inEdgeWeightFromCommunity, newC) || 0 : 0;
419
+ // outToOld/inFromOld already include the self-loop weight (self-loops are
420
+ // in outEdges/inEdges), so subtract it once to avoid triple-counting.
421
+ s.communityInternalEdgeWeight[oldC] =
422
+ fget(s.communityInternalEdgeWeight, oldC) - (outToOld + inFromOld - selfLoopWeight);
423
+ s.communityInternalEdgeWeight[newC] =
424
+ fget(s.communityInternalEdgeWeight, newC) + (outToNew + inFromNew + selfLoopWeight);
425
+ } else {
426
+ const weightToOld: number = fget(s.neighborEdgeWeightToCommunity, oldC) || 0;
427
+ const weightToNew: number = fget(s.neighborEdgeWeightToCommunity, newC) || 0;
428
+ s.communityInternalEdgeWeight[oldC] =
429
+ fget(s.communityInternalEdgeWeight, oldC) - (2 * weightToOld + selfLoopWeight);
430
+ s.communityInternalEdgeWeight[newC] =
431
+ fget(s.communityInternalEdgeWeight, newC) + (2 * weightToNew + selfLoopWeight);
317
432
  }
318
433
 
319
- function deltaCPM(v: number, newC: number, gamma: number = 1.0): number {
320
- const oldC: number = iget(nodeCommunity, v);
321
- if (newC === oldC) return 0;
322
- let w_old: number;
323
- let w_new: number;
324
- let selfCorrection: number = 0;
325
- if (graph.directed) {
326
- w_old =
327
- (fget(outEdgeWeightToCommunity, oldC) || 0) + (fget(inEdgeWeightFromCommunity, oldC) || 0);
328
- w_new =
329
- newC < outEdgeWeightToCommunity.length
330
- ? (fget(outEdgeWeightToCommunity, newC) || 0) +
331
- (fget(inEdgeWeightFromCommunity, newC) || 0)
332
- : 0;
333
- // Self-loop correction (see cpm.ts diffCPM)
334
- selfCorrection = 2 * (fget(graph.selfLoop, v) || 0);
335
- } else {
336
- w_old = fget(neighborEdgeWeightToCommunity, oldC) || 0;
337
- w_new =
338
- newC < neighborEdgeWeightToCommunity.length
339
- ? fget(neighborEdgeWeightToCommunity, newC) || 0
340
- : 0;
341
- }
342
- const nodeSz: number = fget(graph.size, v) || 1;
343
- const sizeOld: number = fget(communityTotalSize, oldC) || 0;
344
- const sizeNew: number = newC < communityTotalSize.length ? fget(communityTotalSize, newC) : 0;
345
- return w_new - w_old + selfCorrection - gamma * nodeSz * (sizeNew - sizeOld + nodeSz);
346
- }
434
+ s.nodeCommunity[v] = newC;
435
+ return true;
436
+ }
347
437
 
348
- function moveNodeToCommunity(v: number, newC: number): boolean {
349
- const oldC: number = iget(nodeCommunity, v);
350
- if (oldC === newC) return false;
351
- if (newC >= communityCount) {
352
- ensureCommCapacity(newC + 1);
353
- communityCount = newC + 1;
354
- }
355
- const strengthOutV: number = fget(graph.strengthOut, v);
356
- const strengthInV: number = fget(graph.strengthIn, v);
357
- const selfLoopWeight: number = fget(graph.selfLoop, v);
358
- const nodeSz: number = fget(graph.size, v);
359
-
360
- communityNodeCount[oldC] = iget(communityNodeCount, oldC) - 1;
361
- communityNodeCount[newC] = iget(communityNodeCount, newC) + 1;
362
- communityTotalSize[oldC] = fget(communityTotalSize, oldC) - nodeSz;
363
- communityTotalSize[newC] = fget(communityTotalSize, newC) + nodeSz;
364
- if (graph.directed) {
365
- communityTotalOutStrength[oldC] = fget(communityTotalOutStrength, oldC) - strengthOutV;
366
- communityTotalOutStrength[newC] = fget(communityTotalOutStrength, newC) + strengthOutV;
367
- communityTotalInStrength[oldC] = fget(communityTotalInStrength, oldC) - strengthInV;
368
- communityTotalInStrength[newC] = fget(communityTotalInStrength, newC) + strengthInV;
369
- } else {
370
- communityTotalStrength[oldC] = fget(communityTotalStrength, oldC) - strengthOutV;
371
- communityTotalStrength[newC] = fget(communityTotalStrength, newC) + strengthOutV;
372
- }
438
+ /* ------------------------------------------------------------------ */
439
+ /* Extracted: community compaction */
440
+ /* ------------------------------------------------------------------ */
373
441
 
374
- if (graph.directed) {
375
- const outToOld: number = fget(outEdgeWeightToCommunity, oldC) || 0;
376
- const inFromOld: number = fget(inEdgeWeightFromCommunity, oldC) || 0;
377
- const outToNew: number =
378
- newC < outEdgeWeightToCommunity.length ? fget(outEdgeWeightToCommunity, newC) || 0 : 0;
379
- const inFromNew: number =
380
- newC < inEdgeWeightFromCommunity.length ? fget(inEdgeWeightFromCommunity, newC) || 0 : 0;
381
- // outToOld/inFromOld already include the self-loop weight (self-loops are
382
- // in outEdges/inEdges), so subtract it once to avoid triple-counting.
383
- communityInternalEdgeWeight[oldC] =
384
- fget(communityInternalEdgeWeight, oldC) - (outToOld + inFromOld - selfLoopWeight);
385
- communityInternalEdgeWeight[newC] =
386
- fget(communityInternalEdgeWeight, newC) + (outToNew + inFromNew + selfLoopWeight);
387
- } else {
388
- const weightToOld: number = fget(neighborEdgeWeightToCommunity, oldC) || 0;
389
- const weightToNew: number = fget(neighborEdgeWeightToCommunity, newC) || 0;
390
- communityInternalEdgeWeight[oldC] =
391
- fget(communityInternalEdgeWeight, oldC) - (2 * weightToOld + selfLoopWeight);
392
- communityInternalEdgeWeight[newC] =
393
- fget(communityInternalEdgeWeight, newC) + (2 * weightToNew + selfLoopWeight);
394
- }
442
+ function compactIds(s: PartitionState, opts: CompactOptions = {}): void {
443
+ const ids: number[] = [];
444
+ for (let c = 0; c < s.communityCount; c++) if (iget(s.communityNodeCount, c) > 0) ids.push(c);
445
+ buildSortedCommunityIds(ids, opts, s.communityTotalSize, s.communityNodeCount);
395
446
 
396
- nodeCommunity[v] = newC;
397
- return true;
398
- }
447
+ const newId = new Int32Array(s.communityCount).fill(-1);
448
+ ids.forEach((c, i) => {
449
+ newId[c] = i;
450
+ });
451
+ for (let i = 0; i < s.nodeCommunity.length; i++)
452
+ s.nodeCommunity[i] = iget(newId, iget(s.nodeCommunity, i));
399
453
 
400
- function compactCommunityIds(opts: CompactOptions = {}): void {
401
- const ids: number[] = [];
402
- for (let c = 0; c < communityCount; c++) if (iget(communityNodeCount, c) > 0) ids.push(c);
403
- buildSortedCommunityIds(ids, opts, communityTotalSize, communityNodeCount);
454
+ const remappedCount: number = ids.length;
455
+ const newTotalSize = new Float64Array(remappedCount);
456
+ const newNodeCount = new Int32Array(remappedCount);
457
+ const newInternalEdgeWeight = new Float64Array(remappedCount);
458
+ const newTotalStrength = new Float64Array(remappedCount);
459
+ const newTotalOutStrength = new Float64Array(remappedCount);
460
+ const newTotalInStrength = new Float64Array(remappedCount);
461
+ accumulateNodeAggregates(
462
+ s.graph,
463
+ s.nodeCommunity,
464
+ s.n,
465
+ newTotalSize,
466
+ newNodeCount,
467
+ newInternalEdgeWeight,
468
+ newTotalStrength,
469
+ newTotalOutStrength,
470
+ newTotalInStrength,
471
+ );
472
+ accumulateInternalEdgeWeights(s.graph, s.nodeCommunity, s.n, newInternalEdgeWeight);
404
473
 
405
- const newId = new Int32Array(communityCount).fill(-1);
406
- ids.forEach((c, i) => {
407
- newId[c] = i;
408
- });
409
- for (let i = 0; i < nodeCommunity.length; i++)
410
- nodeCommunity[i] = iget(newId, iget(nodeCommunity, i));
411
-
412
- const remappedCount: number = ids.length;
413
- const newTotalSize = new Float64Array(remappedCount);
414
- const newNodeCount = new Int32Array(remappedCount);
415
- const newInternalEdgeWeight = new Float64Array(remappedCount);
416
- const newTotalStrength = new Float64Array(remappedCount);
417
- const newTotalOutStrength = new Float64Array(remappedCount);
418
- const newTotalInStrength = new Float64Array(remappedCount);
419
- accumulateNodeAggregates(
420
- graph,
421
- nodeCommunity,
422
- n,
423
- newTotalSize,
424
- newNodeCount,
425
- newInternalEdgeWeight,
426
- newTotalStrength,
427
- newTotalOutStrength,
428
- newTotalInStrength,
429
- );
430
- accumulateInternalEdgeWeights(graph, nodeCommunity, n, newInternalEdgeWeight);
431
-
432
- communityCount = remappedCount;
433
- communityTotalSize = newTotalSize;
434
- communityNodeCount = newNodeCount;
435
- communityInternalEdgeWeight = newInternalEdgeWeight;
436
- communityTotalStrength = newTotalStrength;
437
- communityTotalOutStrength = newTotalOutStrength;
438
- communityTotalInStrength = newTotalInStrength;
439
- }
474
+ s.communityCount = remappedCount;
475
+ s.communityTotalSize = newTotalSize;
476
+ s.communityNodeCount = newNodeCount;
477
+ s.communityInternalEdgeWeight = newInternalEdgeWeight;
478
+ s.communityTotalStrength = newTotalStrength;
479
+ s.communityTotalOutStrength = newTotalOutStrength;
480
+ s.communityTotalInStrength = newTotalInStrength;
481
+ }
440
482
 
441
- function getCommunityMembers(): number[][] {
442
- const comms: number[][] = new Array(communityCount);
443
- for (let i = 0; i < communityCount; i++) comms[i] = [];
444
- for (let i = 0; i < n; i++) comms[iget(nodeCommunity, i)]!.push(i);
445
- return comms;
446
- }
483
+ /* ------------------------------------------------------------------ */
484
+ /* Factory: thin wrapper that wires state to extracted functions */
485
+ /* ------------------------------------------------------------------ */
447
486
 
448
- function getCommunityTotalSizeFn(c: number): number {
449
- return c < communityTotalSize.length ? fget(communityTotalSize, c) : 0;
450
- }
451
- function getCommunityNodeCountFn(c: number): number {
452
- return c < communityNodeCount.length ? iget(communityNodeCount, c) : 0;
453
- }
487
+ export function makePartition(graph: GraphAdapter): Partition {
488
+ const n: number = graph.n;
489
+ const nodeCommunity = new Int32Array(n);
490
+ for (let i = 0; i < n; i++) nodeCommunity[i] = i;
491
+
492
+ const s: PartitionState = {
493
+ graph,
494
+ n,
495
+ nodeCommunity,
496
+ communityCount: n,
497
+ communityTotalSize: new Float64Array(n),
498
+ communityNodeCount: new Int32Array(n),
499
+ communityInternalEdgeWeight: new Float64Array(n),
500
+ communityTotalStrength: new Float64Array(n),
501
+ communityTotalOutStrength: new Float64Array(n),
502
+ communityTotalInStrength: new Float64Array(n),
503
+ candidateCommunities: new Int32Array(n),
504
+ candidateCommunityCount: 0,
505
+ neighborEdgeWeightToCommunity: new Float64Array(n),
506
+ outEdgeWeightToCommunity: new Float64Array(n),
507
+ inEdgeWeightFromCommunity: new Float64Array(n),
508
+ isCandidateCommunity: new Uint8Array(n),
509
+ };
454
510
 
455
511
  return {
456
512
  n,
457
513
  get communityCount() {
458
- return communityCount;
514
+ return s.communityCount;
459
515
  },
460
516
  nodeCommunity,
461
517
  get communityTotalSize() {
462
- return communityTotalSize;
518
+ return s.communityTotalSize;
463
519
  },
464
520
  get communityNodeCount() {
465
- return communityNodeCount;
521
+ return s.communityNodeCount;
466
522
  },
467
523
  get communityInternalEdgeWeight() {
468
- return communityInternalEdgeWeight;
524
+ return s.communityInternalEdgeWeight;
469
525
  },
470
526
  get communityTotalStrength() {
471
- return communityTotalStrength;
527
+ return s.communityTotalStrength;
472
528
  },
473
529
  get communityTotalOutStrength() {
474
- return communityTotalOutStrength;
530
+ return s.communityTotalOutStrength;
475
531
  },
476
532
  get communityTotalInStrength() {
477
- return communityTotalInStrength;
533
+ return s.communityTotalInStrength;
478
534
  },
479
535
  resizeCommunities(newCount: number): void {
480
- ensureCommCapacity(newCount);
481
- communityCount = newCount;
536
+ ensureCommCapacity(s, newCount);
537
+ s.communityCount = newCount;
482
538
  },
483
- initializeAggregates,
484
- accumulateNeighborCommunityEdgeWeights,
485
- getCandidateCommunityCount: (): number => candidateCommunityCount,
486
- getCandidateCommunityAt: (i: number): number => iget(candidateCommunities, i),
539
+ initializeAggregates: () => initAggregates(s),
540
+ accumulateNeighborCommunityEdgeWeights: (v: number) => accumulateNeighborWeights(s, v),
541
+ getCandidateCommunityCount: (): number => s.candidateCommunityCount,
542
+ getCandidateCommunityAt: (i: number): number => iget(s.candidateCommunities, i),
487
543
  getNeighborEdgeWeightToCommunity: (c: number): number =>
488
- fget(neighborEdgeWeightToCommunity, c) || 0,
489
- getOutEdgeWeightToCommunity: (c: number): number => fget(outEdgeWeightToCommunity, c) || 0,
490
- getInEdgeWeightFromCommunity: (c: number): number => fget(inEdgeWeightFromCommunity, c) || 0,
491
- deltaModularityUndirected,
492
- deltaModularityDirected,
493
- deltaCPM,
494
- moveNodeToCommunity,
495
- compactCommunityIds,
496
- getCommunityMembers,
497
- getCommunityTotalSize: getCommunityTotalSizeFn,
498
- getCommunityNodeCount: getCommunityNodeCountFn,
544
+ fget(s.neighborEdgeWeightToCommunity, c) || 0,
545
+ getOutEdgeWeightToCommunity: (c: number): number => fget(s.outEdgeWeightToCommunity, c) || 0,
546
+ getInEdgeWeightFromCommunity: (c: number): number => fget(s.inEdgeWeightFromCommunity, c) || 0,
547
+ deltaModularityUndirected: (v: number, newC: number, gamma?: number) =>
548
+ computeDeltaModularityUndirected(s, v, newC, gamma),
549
+ deltaModularityDirected: (v: number, newC: number, gamma?: number) =>
550
+ computeDeltaModularityDirected(s, v, newC, gamma),
551
+ deltaCPM: (v: number, newC: number, gamma?: number) => computeDeltaCPM(s, v, newC, gamma),
552
+ moveNodeToCommunity: (v: number, newC: number) => moveNode(s, v, newC),
553
+ compactCommunityIds: (opts?: CompactOptions) => compactIds(s, opts),
554
+ getCommunityMembers(): number[][] {
555
+ const comms: number[][] = new Array(s.communityCount);
556
+ for (let i = 0; i < s.communityCount; i++) comms[i] = [];
557
+ for (let i = 0; i < n; i++) comms[iget(nodeCommunity, i)]!.push(i);
558
+ return comms;
559
+ },
560
+ getCommunityTotalSize: (c: number): number =>
561
+ c < s.communityTotalSize.length ? fget(s.communityTotalSize, c) : 0,
562
+ getCommunityNodeCount: (c: number): number =>
563
+ c < s.communityNodeCount.length ? iget(s.communityNodeCount, c) : 0,
499
564
  graph: undefined,
500
565
  };
501
566
  }