@graphty/webgpu-graph-algorithms 0.5.0 → 0.6.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 (264) hide show
  1. package/README.md +104 -52
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{context-CRbw2Wyo.js → context-BXqgCifx.js} +225 -33
  4. package/dist/chunks/context-BXqgCifx.js.map +1 -0
  5. package/dist/node.js +1 -1
  6. package/dist/src/accelerator.d.ts +12 -10
  7. package/dist/src/accelerator.d.ts.map +1 -1
  8. package/dist/src/accelerator.js +32 -10
  9. package/dist/src/accelerator.js.map +1 -1
  10. package/dist/src/algorithms/components.d.ts.map +1 -1
  11. package/dist/src/algorithms/components.js +12 -13
  12. package/dist/src/algorithms/components.js.map +1 -1
  13. package/dist/src/algorithms/degree.d.ts +6 -8
  14. package/dist/src/algorithms/degree.d.ts.map +1 -1
  15. package/dist/src/algorithms/degree.js +58 -35
  16. package/dist/src/algorithms/degree.js.map +1 -1
  17. package/dist/src/algorithms/pagerank.d.ts.map +1 -1
  18. package/dist/src/algorithms/pagerank.js +16 -14
  19. package/dist/src/algorithms/pagerank.js.map +1 -1
  20. package/dist/src/algorithms/power-iteration.d.ts +2 -2
  21. package/dist/src/algorithms/power-iteration.d.ts.map +1 -1
  22. package/dist/src/algorithms/power-iteration.js +17 -14
  23. package/dist/src/algorithms/power-iteration.js.map +1 -1
  24. package/dist/src/constants.d.ts +85 -8
  25. package/dist/src/constants.d.ts.map +1 -1
  26. package/dist/src/constants.js +85 -8
  27. package/dist/src/constants.js.map +1 -1
  28. package/dist/src/errors.d.ts +3 -2
  29. package/dist/src/errors.d.ts.map +1 -1
  30. package/dist/src/errors.js +2 -1
  31. package/dist/src/errors.js.map +1 -1
  32. package/dist/src/index.d.ts +10 -5
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/index.js +14 -5
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/kernel/dispatch.d.ts +8 -3
  37. package/dist/src/kernel/dispatch.d.ts.map +1 -1
  38. package/dist/src/kernel/dispatch.js +18 -7
  39. package/dist/src/kernel/dispatch.js.map +1 -1
  40. package/dist/src/kernel/kernel.d.ts +30 -1
  41. package/dist/src/kernel/kernel.d.ts.map +1 -1
  42. package/dist/src/kernel/kernel.js +49 -5
  43. package/dist/src/kernel/kernel.js.map +1 -1
  44. package/dist/src/kernel/prelude.d.ts.map +1 -1
  45. package/dist/src/kernel/prelude.js +9 -1
  46. package/dist/src/kernel/prelude.js.map +1 -1
  47. package/dist/src/kernel/profiler.d.ts +15 -3
  48. package/dist/src/kernel/profiler.d.ts.map +1 -1
  49. package/dist/src/kernel/profiler.js +27 -4
  50. package/dist/src/kernel/profiler.js.map +1 -1
  51. package/dist/src/kernels.d.ts +18 -8
  52. package/dist/src/kernels.d.ts.map +1 -1
  53. package/dist/src/kernels.js +345 -22
  54. package/dist/src/kernels.js.map +1 -1
  55. package/dist/src/layouts/calibrate.d.ts +51 -0
  56. package/dist/src/layouts/calibrate.d.ts.map +1 -0
  57. package/dist/src/layouts/calibrate.js +172 -0
  58. package/dist/src/layouts/calibrate.js.map +1 -0
  59. package/dist/src/layouts/force-simulation.d.ts +42 -5
  60. package/dist/src/layouts/force-simulation.d.ts.map +1 -1
  61. package/dist/src/layouts/force-simulation.js +84 -22
  62. package/dist/src/layouts/force-simulation.js.map +1 -1
  63. package/dist/src/layouts/forceatlas2.d.ts +107 -38
  64. package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
  65. package/dist/src/layouts/forceatlas2.js +297 -290
  66. package/dist/src/layouts/forceatlas2.js.map +1 -1
  67. package/dist/src/layouts/fruchterman-reingold.d.ts +241 -0
  68. package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -0
  69. package/dist/src/layouts/fruchterman-reingold.js +739 -0
  70. package/dist/src/layouts/fruchterman-reingold.js.map +1 -0
  71. package/dist/src/layouts/model-common.d.ts +140 -0
  72. package/dist/src/layouts/model-common.d.ts.map +1 -0
  73. package/dist/src/layouts/model-common.js +269 -0
  74. package/dist/src/layouts/model-common.js.map +1 -0
  75. package/dist/src/layouts/repulsion-grid.d.ts +152 -0
  76. package/dist/src/layouts/repulsion-grid.d.ts.map +1 -0
  77. package/dist/src/layouts/repulsion-grid.js +318 -0
  78. package/dist/src/layouts/repulsion-grid.js.map +1 -0
  79. package/dist/src/layouts/spring-electrical.d.ts +224 -0
  80. package/dist/src/layouts/spring-electrical.d.ts.map +1 -0
  81. package/dist/src/layouts/spring-electrical.js +665 -0
  82. package/dist/src/layouts/spring-electrical.js.map +1 -0
  83. package/dist/src/memory/residency.d.ts +6 -2
  84. package/dist/src/memory/residency.d.ts.map +1 -1
  85. package/dist/src/memory/residency.js +84 -14
  86. package/dist/src/memory/residency.js.map +1 -1
  87. package/dist/src/primitives/core-shape.d.ts +38 -2
  88. package/dist/src/primitives/core-shape.d.ts.map +1 -1
  89. package/dist/src/primitives/core-shape.js +71 -3
  90. package/dist/src/primitives/core-shape.js.map +1 -1
  91. package/dist/src/primitives/grid-pyramid.d.ts +71 -0
  92. package/dist/src/primitives/grid-pyramid.d.ts.map +1 -0
  93. package/dist/src/primitives/grid-pyramid.js +143 -0
  94. package/dist/src/primitives/grid-pyramid.js.map +1 -0
  95. package/dist/src/primitives/grid.d.ts +118 -0
  96. package/dist/src/primitives/grid.d.ts.map +1 -0
  97. package/dist/src/primitives/grid.js +225 -0
  98. package/dist/src/primitives/grid.js.map +1 -0
  99. package/dist/src/primitives/histogram.d.ts +67 -0
  100. package/dist/src/primitives/histogram.d.ts.map +1 -0
  101. package/dist/src/primitives/histogram.js +190 -0
  102. package/dist/src/primitives/histogram.js.map +1 -0
  103. package/dist/src/primitives/radix-sort.d.ts +75 -0
  104. package/dist/src/primitives/radix-sort.d.ts.map +1 -0
  105. package/dist/src/primitives/radix-sort.js +168 -0
  106. package/dist/src/primitives/radix-sort.js.map +1 -0
  107. package/dist/src/primitives/scan.d.ts +44 -0
  108. package/dist/src/primitives/scan.d.ts.map +1 -0
  109. package/dist/src/primitives/scan.js +151 -0
  110. package/dist/src/primitives/scan.js.map +1 -0
  111. package/dist/src/primitives/segmented-reduce.d.ts +25 -17
  112. package/dist/src/primitives/segmented-reduce.d.ts.map +1 -1
  113. package/dist/src/primitives/segmented-reduce.js +166 -47
  114. package/dist/src/primitives/segmented-reduce.js.map +1 -1
  115. package/dist/src/primitives/spmv.d.ts +18 -14
  116. package/dist/src/primitives/spmv.d.ts.map +1 -1
  117. package/dist/src/primitives/spmv.js +94 -58
  118. package/dist/src/primitives/spmv.js.map +1 -1
  119. package/dist/src/primitives/verify.d.ts +49 -0
  120. package/dist/src/primitives/verify.d.ts.map +1 -0
  121. package/dist/src/primitives/verify.js +229 -0
  122. package/dist/src/primitives/verify.js.map +1 -0
  123. package/dist/src/types/accelerator.d.ts +7 -3
  124. package/dist/src/types/accelerator.d.ts.map +1 -1
  125. package/dist/src/types/context.d.ts +53 -0
  126. package/dist/src/types/context.d.ts.map +1 -1
  127. package/dist/src/types/layout.d.ts +52 -0
  128. package/dist/src/types/layout.d.ts.map +1 -1
  129. package/dist/src/types/options.d.ts +43 -1
  130. package/dist/src/types/options.d.ts.map +1 -1
  131. package/dist/src/wgsl/counting-scatter.wgsl.d.ts +8 -0
  132. package/dist/src/wgsl/counting-scatter.wgsl.d.ts.map +1 -0
  133. package/dist/src/wgsl/counting-scatter.wgsl.js +17 -0
  134. package/dist/src/wgsl/counting-scatter.wgsl.js.map +1 -0
  135. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +23 -8
  136. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -1
  137. package/dist/src/wgsl/fa2-attraction.wgsl.js +100 -17
  138. package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -1
  139. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts +7 -2
  140. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts.map +1 -1
  141. package/dist/src/wgsl/fa2-integrate.wgsl.js +28 -2
  142. package/dist/src/wgsl/fa2-integrate.wgsl.js.map +1 -1
  143. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +4 -2
  144. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -1
  145. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +14 -5
  146. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -1
  147. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +12 -1
  148. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
  149. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +54 -0
  150. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
  151. package/dist/src/wgsl/grid-cell-key.wgsl.d.ts +8 -0
  152. package/dist/src/wgsl/grid-cell-key.wgsl.d.ts.map +1 -0
  153. package/dist/src/wgsl/grid-cell-key.wgsl.js +30 -0
  154. package/dist/src/wgsl/grid-cell-key.wgsl.js.map +1 -0
  155. package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +8 -0
  156. package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts.map +1 -0
  157. package/dist/src/wgsl/grid-centroid-hub.wgsl.js +29 -0
  158. package/dist/src/wgsl/grid-centroid-hub.wgsl.js.map +1 -0
  159. package/dist/src/wgsl/grid-centroid.wgsl.d.ts +8 -0
  160. package/dist/src/wgsl/grid-centroid.wgsl.d.ts.map +1 -0
  161. package/dist/src/wgsl/grid-centroid.wgsl.js +29 -0
  162. package/dist/src/wgsl/grid-centroid.wgsl.js.map +1 -0
  163. package/dist/src/wgsl/grid-downsample.wgsl.d.ts +7 -0
  164. package/dist/src/wgsl/grid-downsample.wgsl.d.ts.map +1 -0
  165. package/dist/src/wgsl/grid-downsample.wgsl.js +28 -0
  166. package/dist/src/wgsl/grid-downsample.wgsl.js.map +1 -0
  167. package/dist/src/wgsl/grid-far-field.wgsl.d.ts +13 -0
  168. package/dist/src/wgsl/grid-far-field.wgsl.d.ts.map +1 -0
  169. package/dist/src/wgsl/grid-far-field.wgsl.js +98 -0
  170. package/dist/src/wgsl/grid-far-field.wgsl.js.map +1 -0
  171. package/dist/src/wgsl/grid-near-field.wgsl.d.ts +19 -0
  172. package/dist/src/wgsl/grid-near-field.wgsl.d.ts.map +1 -0
  173. package/dist/src/wgsl/grid-near-field.wgsl.js +129 -0
  174. package/dist/src/wgsl/grid-near-field.wgsl.js.map +1 -0
  175. package/dist/src/wgsl/histogram.wgsl.d.ts +7 -0
  176. package/dist/src/wgsl/histogram.wgsl.d.ts.map +1 -0
  177. package/dist/src/wgsl/histogram.wgsl.js +15 -0
  178. package/dist/src/wgsl/histogram.wgsl.js.map +1 -0
  179. package/dist/src/wgsl/indirect-finalize.wgsl.d.ts +8 -0
  180. package/dist/src/wgsl/indirect-finalize.wgsl.d.ts.map +1 -0
  181. package/dist/src/wgsl/indirect-finalize.wgsl.js +26 -0
  182. package/dist/src/wgsl/indirect-finalize.wgsl.js.map +1 -0
  183. package/dist/src/wgsl/radix-hist.wgsl.d.ts +9 -0
  184. package/dist/src/wgsl/radix-hist.wgsl.d.ts.map +1 -0
  185. package/dist/src/wgsl/radix-hist.wgsl.js +31 -0
  186. package/dist/src/wgsl/radix-hist.wgsl.js.map +1 -0
  187. package/dist/src/wgsl/radix-scatter.wgsl.d.ts +9 -0
  188. package/dist/src/wgsl/radix-scatter.wgsl.d.ts.map +1 -0
  189. package/dist/src/wgsl/radix-scatter.wgsl.js +40 -0
  190. package/dist/src/wgsl/radix-scatter.wgsl.js.map +1 -0
  191. package/dist/src/wgsl/scan-add.wgsl.d.ts +6 -0
  192. package/dist/src/wgsl/scan-add.wgsl.d.ts.map +1 -0
  193. package/dist/src/wgsl/scan-add.wgsl.js +14 -0
  194. package/dist/src/wgsl/scan-add.wgsl.js.map +1 -0
  195. package/dist/src/wgsl/scan-block.wgsl.d.ts +8 -0
  196. package/dist/src/wgsl/scan-block.wgsl.d.ts.map +1 -0
  197. package/dist/src/wgsl/scan-block.wgsl.js +30 -0
  198. package/dist/src/wgsl/scan-block.wgsl.js.map +1 -0
  199. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +22 -8
  200. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -1
  201. package/dist/src/wgsl/segmented-reduce.wgsl.js +84 -15
  202. package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -1
  203. package/dist/src/wgsl/spmv-pull.wgsl.d.ts +22 -11
  204. package/dist/src/wgsl/spmv-pull.wgsl.d.ts.map +1 -1
  205. package/dist/src/wgsl/spmv-pull.wgsl.js +110 -36
  206. package/dist/src/wgsl/spmv-pull.wgsl.js.map +1 -1
  207. package/dist/tsconfig.build.tsbuildinfo +1 -1
  208. package/dist/webgpu-graph-algorithms.js +5016 -1130
  209. package/dist/webgpu-graph-algorithms.js.map +1 -1
  210. package/package.json +10 -7
  211. package/src/accelerator.ts +46 -12
  212. package/src/algorithms/components.ts +12 -16
  213. package/src/algorithms/degree.ts +58 -43
  214. package/src/algorithms/pagerank.ts +20 -18
  215. package/src/algorithms/power-iteration.ts +19 -18
  216. package/src/constants.ts +108 -8
  217. package/src/errors.ts +3 -1
  218. package/src/index.ts +25 -5
  219. package/src/kernel/dispatch.ts +18 -7
  220. package/src/kernel/kernel.ts +59 -5
  221. package/src/kernel/prelude.ts +15 -0
  222. package/src/kernel/profiler.ts +28 -4
  223. package/src/kernels.ts +378 -24
  224. package/src/layouts/calibrate.ts +187 -0
  225. package/src/layouts/force-simulation.ts +111 -26
  226. package/src/layouts/forceatlas2.ts +346 -324
  227. package/src/layouts/fruchterman-reingold.ts +918 -0
  228. package/src/layouts/model-common.ts +323 -0
  229. package/src/layouts/repulsion-grid.ts +451 -0
  230. package/src/layouts/spring-electrical.ts +845 -0
  231. package/src/memory/residency.ts +126 -20
  232. package/src/primitives/core-shape.ts +91 -4
  233. package/src/primitives/grid-pyramid.ts +221 -0
  234. package/src/primitives/grid.ts +349 -0
  235. package/src/primitives/histogram.ts +273 -0
  236. package/src/primitives/radix-sort.ts +246 -0
  237. package/src/primitives/scan.ts +197 -0
  238. package/src/primitives/segmented-reduce.ts +214 -56
  239. package/src/primitives/spmv.ts +125 -65
  240. package/src/primitives/verify.ts +249 -0
  241. package/src/types/accelerator.ts +15 -3
  242. package/src/types/context.ts +56 -0
  243. package/src/types/layout.ts +58 -0
  244. package/src/types/options.ts +45 -1
  245. package/src/wgsl/counting-scatter.wgsl.ts +16 -0
  246. package/src/wgsl/fa2-attraction.wgsl.ts +100 -17
  247. package/src/wgsl/fa2-integrate.wgsl.ts +28 -2
  248. package/src/wgsl/fa2-repulsion-exact.wgsl.ts +14 -5
  249. package/src/wgsl/fa2-stats-finalize.wgsl.ts +54 -0
  250. package/src/wgsl/grid-cell-key.wgsl.ts +29 -0
  251. package/src/wgsl/grid-centroid-hub.wgsl.ts +28 -0
  252. package/src/wgsl/grid-centroid.wgsl.ts +28 -0
  253. package/src/wgsl/grid-downsample.wgsl.ts +27 -0
  254. package/src/wgsl/grid-far-field.wgsl.ts +97 -0
  255. package/src/wgsl/grid-near-field.wgsl.ts +128 -0
  256. package/src/wgsl/histogram.wgsl.ts +14 -0
  257. package/src/wgsl/indirect-finalize.wgsl.ts +25 -0
  258. package/src/wgsl/radix-hist.wgsl.ts +30 -0
  259. package/src/wgsl/radix-scatter.wgsl.ts +39 -0
  260. package/src/wgsl/scan-add.wgsl.ts +13 -0
  261. package/src/wgsl/scan-block.wgsl.ts +29 -0
  262. package/src/wgsl/segmented-reduce.wgsl.ts +84 -15
  263. package/src/wgsl/spmv-pull.wgsl.ts +110 -36
  264. package/dist/chunks/context-CRbw2Wyo.js.map +0 -1
package/src/kernels.ts CHANGED
@@ -7,8 +7,8 @@
7
7
  * and fa2-speed-finalize (K4) together with every generated block of contract 3.10.2; P2-T2 lands
8
8
  * segmented-reduce; P3-T2 adds fa2-stats-finalize (K1), fa2-attraction (K2), fa2-integrate (K5) and
9
9
  * fa2-to-scene; M8b-T3 adds the seven P7 entries: spmv-pull, pr-scale, pr-finalize, wcc-link-sample,
10
- * wcc-link-edges, wcc-compress and wcc-sample. This file is the only importer of src/wgsl/** (spec 3.2;
11
- * test/layers.test.ts).
10
+ * wcc-link-edges, wcc-compress and wcc-sample. P4-T1 adds indirect-finalize; the other P4 entries follow, one task
11
+ * each (the P4 plan, PD-1). This file is the only importer of src/wgsl/** (spec 3.2; test/layers.test.ts).
12
12
  */
13
13
 
14
14
  import { STATE_HEADER_BYTES } from "./constants.js";
@@ -17,6 +17,7 @@ import { UniformBlock } from "./kernel/struct-block.js";
17
17
  import { type BindingDecl, type OverrideDecl, type WgslModuleSpec } from "./kernel/wgsl.js";
18
18
  import { type CoreBinding } from "./memory/residency.js";
19
19
  import { type Binding } from "./types/memory.js";
20
+ import { countingScatterWgsl } from "./wgsl/counting-scatter.wgsl.js";
20
21
  import { degreeWgsl } from "./wgsl/degree.wgsl.js";
21
22
  import { fa2AttractionWgsl } from "./wgsl/fa2-attraction.wgsl.js";
22
23
  import { fa2IntegrateWgsl } from "./wgsl/fa2-integrate.wgsl.js";
@@ -25,9 +26,21 @@ import { fa2SpeedFinalizeWgsl } from "./wgsl/fa2-speed-finalize.wgsl.js";
25
26
  import { fa2StatsFinalizeWgsl } from "./wgsl/fa2-stats-finalize.wgsl.js";
26
27
  import { fa2ToSceneWgsl } from "./wgsl/fa2-to-scene.wgsl.js";
27
28
  import { fillWgsl } from "./wgsl/fill.wgsl.js";
29
+ import { gridCellKeyWgsl } from "./wgsl/grid-cell-key.wgsl.js";
30
+ import { gridCentroidWgsl } from "./wgsl/grid-centroid.wgsl.js";
31
+ import { gridCentroidHubWgsl } from "./wgsl/grid-centroid-hub.wgsl.js";
32
+ import { gridDownsampleWgsl } from "./wgsl/grid-downsample.wgsl.js";
33
+ import { gridFarFieldWgsl } from "./wgsl/grid-far-field.wgsl.js";
34
+ import { gridNearFieldWgsl } from "./wgsl/grid-near-field.wgsl.js";
35
+ import { histogramWgsl } from "./wgsl/histogram.wgsl.js";
36
+ import { indirectFinalizeWgsl } from "./wgsl/indirect-finalize.wgsl.js";
28
37
  import { prFinalizeWgsl } from "./wgsl/pr-finalize.wgsl.js";
29
38
  import { prScaleWgsl } from "./wgsl/pr-scale.wgsl.js";
39
+ import { radixHistWgsl } from "./wgsl/radix-hist.wgsl.js";
40
+ import { radixScatterWgsl } from "./wgsl/radix-scatter.wgsl.js";
30
41
  import { reduceWgsl } from "./wgsl/reduce.wgsl.js";
42
+ import { scanAddWgsl } from "./wgsl/scan-add.wgsl.js";
43
+ import { scanBlockWgsl } from "./wgsl/scan-block.wgsl.js";
31
44
  import { segmentedReduceWgsl } from "./wgsl/segmented-reduce.wgsl.js";
32
45
  import { spmvPullWgsl } from "./wgsl/spmv-pull.wgsl.js";
33
46
  import { wccCompressWgsl } from "./wgsl/wcc-compress.wgsl.js";
@@ -53,7 +66,20 @@ export type KernelId =
53
66
  | "wcc-link-sample"
54
67
  | "wcc-link-edges"
55
68
  | "wcc-compress"
56
- | "wcc-sample";
69
+ | "wcc-sample"
70
+ | "indirect-finalize"
71
+ | "scan-block"
72
+ | "scan-add"
73
+ | "histogram"
74
+ | "counting-scatter"
75
+ | "radix-hist"
76
+ | "radix-scatter"
77
+ | "grid-cell-key"
78
+ | "grid-centroid"
79
+ | "grid-centroid-hub"
80
+ | "grid-downsample"
81
+ | "grid-far-field"
82
+ | "grid-near-field";
57
83
 
58
84
  /** One registry entry: everything of a WgslModuleSpec except the per-variant overrides and snippets. */
59
85
  export interface KernelEntry {
@@ -68,7 +94,7 @@ export interface KernelEntry {
68
94
  /** The snippet marker names the body carries (segmented-reduce: ["VALUE"]). */
69
95
  readonly snippetSlots: readonly string[];
70
96
  /** The phase the entry landed in (documentation and the compile-matrix filter). */
71
- readonly phase: "P1" | "P2" | "P3" | "P7";
97
+ readonly phase: "P1" | "P2" | "P3" | "P4" | "P7";
72
98
  }
73
99
 
74
100
  // ---- the generated blocks (spec 5.3; contract 3.10.2): field order = byte order, offsets in the JSDoc
@@ -101,7 +127,7 @@ export const FILL_PARAMS: UniformBlock = UniformBlock.define("FillParams", [
101
127
  ["pad0", "u32"],
102
128
  ]);
103
129
 
104
- /** `Fa2Params` (uniform, 96 B; spec 7.3): the per-iteration ForceAtlas2 parameters -- `n` @0, `dim` @4, `flags` @8 (bit 0 = FA2_FLAG_FIRST), `tierStart` @12, `tierEnd` @16, `iterationIndex` @20, `seed` @24, `nearMax` @28, `scalingRatio` @32, `gravity` @36, `jitterTolerance` @40, `scale` @44, `center` @48 (xyz, w 0), `settleThreshold` @64, `extentFactor` @68, `gridMax` @72, `levels` @76, `pad` @80 (reserved for the P4 GridSpec). */
130
+ /** `Fa2Params` (uniform, 128 B; spec 7.3): the per-iteration ForceAtlas2 parameters -- `n` @0, `dim` @4, `flags` @8 (bit 0 = FA2_FLAG_FIRST), `tierStart` @12, `tierEnd` @16, `iterationIndex` @20, `seed` @24, `nearMax` @28, `scalingRatio` @32, `gravity` @36, `jitterTolerance` @40, `scale` @44, `center` @48 (xyz, w 0), `settleThreshold` @64, `extentFactor` @68, `gridMax` @72, `levels` @76, `arcBase` @80 / `arcEnd` @84 (the bound arc window of K2, 0 and arcCount in the layout), `accumulate` @88 (1 combines into `force`: the windowed pattern), `hiEnd` @92 / `midEnd` @124 (the degreeOrder tier boundaries, PD-7; both 0 without a permutation); the P5 model fields (PD-3): `frK` @96 (the FR optimal distance), `temperature` @100 (the FR temperature of this iteration), `springLength` @104, `springCoefficient` @108, `coulomb` @112 (ngraph's `gravity`, negative repels), `dragCoefficient` @116, `timeStep` @120; 128 B. */
105
131
  export const FA2_PARAMS: UniformBlock = UniformBlock.define("Fa2Params", [
106
132
  ["n", "u32"],
107
133
  ["dim", "u32"],
@@ -120,10 +146,21 @@ export const FA2_PARAMS: UniformBlock = UniformBlock.define("Fa2Params", [
120
146
  ["extentFactor", "f32"],
121
147
  ["gridMax", "u32"],
122
148
  ["levels", "u32"],
123
- ["pad", "vec4f"],
149
+ ["arcBase", "u32"],
150
+ ["arcEnd", "u32"],
151
+ ["accumulate", "u32"],
152
+ ["hiEnd", "u32"],
153
+ ["frK", "f32"],
154
+ ["temperature", "f32"],
155
+ ["springLength", "f32"],
156
+ ["springCoefficient", "f32"],
157
+ ["coulomb", "f32"],
158
+ ["dragCoefficient", "f32"],
159
+ ["timeStep", "f32"],
160
+ ["midEnd", "u32"],
124
161
  ]);
125
162
 
126
- /** `Fa2State` (storage, padded to STATE_HEADER_BYTES = 256; spec 7.3): the device-resident controller state the finalize kernels write and the host reads back for stats -- `speed` @0, `speedEfficiency` @4, `swing` @8, `traction` @12, `centroid` @16, `rmsRadius` @32, `radius` @36, `meanDisplacement` @40, `iteration` @44, `min` @48, `max` @64, `gridMin` @80 (P4), `eps` @96 (P4), `settledCount` @100, `outsideGrid` @104 (P4), `maxCellOccupancy` @108 (P4), `reserved0` .. `reserved8` @112 .. @240. */
163
+ /** `Fa2State` (storage, padded to STATE_HEADER_BYTES = 256; spec 7.3): the device-resident controller state the finalize kernels write and the host reads back for stats -- `speed` @0, `speedEfficiency` @4, `swing` @8, `traction` @12, `centroid` @16, `rmsRadius` @32, `radius` @36, `meanDisplacement` @40, `iteration` @44, `min` @48, `max` @64, `gridMin` @80 (P4), `eps` @96 (P4), `settledCount` @100, `outsideGrid` @104 (P4), `maxCellOccupancy` @108 (P4), `temperature` @112 (FR, written by K1 under STATS_MODE 1), `kineticEnergy` @116 (the preset, K1 under STATS_MODE 2), `frEnergy` @120 / `frProgress` @124 (the FR adaptive cooling), `invCellSize` @128 (P4, PD-10: `1 / cellSize`, written by K1 beside `cellSize` in `gridMin.w`; G1 multiplies by it so every key is bitwise reproducible), `reserved0` @132 (f32), `reserved1` @136 (vec2f), `reserved2` .. `reserved8` @144 .. @240. */
127
164
  export const FA2_STATE: UniformBlock = UniformBlock.define(
128
165
  "Fa2State",
129
166
  [
@@ -143,8 +180,13 @@ export const FA2_STATE: UniformBlock = UniformBlock.define(
143
180
  ["settledCount", "u32"],
144
181
  ["outsideGrid", "u32"],
145
182
  ["maxCellOccupancy", "u32"],
146
- ["reserved0", "vec4f"],
147
- ["reserved1", "vec4f"],
183
+ ["temperature", "f32"],
184
+ ["kineticEnergy", "f32"],
185
+ ["frEnergy", "f32"],
186
+ ["frProgress", "u32"],
187
+ ["invCellSize", "f32"],
188
+ ["reserved0", "f32"],
189
+ ["reserved1", "vec2f"],
148
190
  ["reserved2", "vec4f"],
149
191
  ["reserved3", "vec4f"],
150
192
  ["reserved4", "vec4f"],
@@ -156,7 +198,7 @@ export const FA2_STATE: UniformBlock = UniformBlock.define(
156
198
  { layout: "storage", padTo: STATE_HEADER_BYTES },
157
199
  );
158
200
 
159
- /** `Fa2Trace` (storage record, 32 B; spec 7.3): one per-iteration trace record -- `swing` @0, `traction` @4, `speed` @8, `speedEfficiency` @12 (written by K4), `meanDisplacement` @16, `settledCount` @20, `iteration` @24 (written by K1), `pad0` @28; the trace region is `array<Fa2Trace>` at byte offset STATE_HEADER_BYTES of the state buffer. */
201
+ /** `Fa2Trace` (storage record, 32 B; spec 7.3): one per-iteration trace record -- `swing` @0, `traction` @4, `speed` @8, `speedEfficiency` @12 (written by K4), `meanDisplacement` @16, `settledCount` @20, `iteration` @24 (written by K1), `modelScalar` @28 (K1: the temperature under STATS_MODE 1, the kinetic energy under 2, 0 under 0); the trace region is `array<Fa2Trace>` at byte offset STATE_HEADER_BYTES of the state buffer. */
160
202
  export const FA2_TRACE: UniformBlock = UniformBlock.define(
161
203
  "Fa2Trace",
162
204
  [
@@ -167,7 +209,7 @@ export const FA2_TRACE: UniformBlock = UniformBlock.define(
167
209
  ["meanDisplacement", "f32"],
168
210
  ["settledCount", "u32"],
169
211
  ["iteration", "u32"],
170
- ["pad0", "u32"],
212
+ ["modelScalar", "f32"],
171
213
  ],
172
214
  { layout: "storage" },
173
215
  );
@@ -185,7 +227,7 @@ export const FA2_PARTIAL: UniformBlock = UniformBlock.define(
185
227
  { layout: "storage" },
186
228
  );
187
229
 
188
- /** `SpmvParams` (uniform, 32 B; spec 8.2): `n` @0 rows of the pull, the bound arc window `[arcBase, arcEnd)` @4 / @8 (0 and arcCount when not windowed), the grid-stride step `stride` @12, `alpha` @16, `beta` @20 (the `1 - alpha` term), `uniformP` @24 (the uniform personalization mass `1 / n`, 0 for a pure SpMV), `pad0` @28. */
230
+ /** `SpmvParams` (uniform, 32 B; spec 8.2): `n` @0 rows of the pull, the bound arc window `[arcBase, arcEnd)` @4 / @8 (0 and arcCount when not windowed), the grid-stride step `stride` @12, `alpha` @16, `beta` @20 (the `1 - alpha` term), `uniformP` @24 (the uniform personalization mass `1 / n`, 0 for a pure SpMV), `start` @28 (the first row of the dispatch; TIER 0 strides from it, the tiers index from it). */
189
231
  export const SPMV_PARAMS: UniformBlock = UniformBlock.define("SpmvParams", [
190
232
  ["n", "u32"],
191
233
  ["arcBase", "u32"],
@@ -194,7 +236,7 @@ export const SPMV_PARAMS: UniformBlock = UniformBlock.define("SpmvParams", [
194
236
  ["alpha", "f32"],
195
237
  ["beta", "f32"],
196
238
  ["uniformP", "f32"],
197
- ["pad0", "u32"],
239
+ ["start", "u32"],
198
240
  ]);
199
241
 
200
242
  /** `PrParams` (uniform, 32 B; spec 8.2): `n` @0, `groups` @4 (the per-workgroup partial count the finalize folds), `iteration` @8 (1-based), `trackConvergence` @12 (1 records firstConverged), `convergeThreshold` @16 (`tolerance * n`, the design's `delta < tol * n`), `pad0` @20, `pad1` @24, `pad2` @28. */
@@ -243,6 +285,50 @@ export const WCC_PARAMS: UniformBlock = UniformBlock.define("WccParams", [
243
285
  ["pad0", "u32"],
244
286
  ]);
245
287
 
288
+ /** `IndirectParams` (uniform, 16 B; spec 5.4): `countIndex` @0 (the word of `counters` holding the count), `wg` @4 (the consumer's workgroup size), `slot` @8 (the 16-byte args slot to write), `pad0` @12. */
289
+ export const INDIRECT_PARAMS: UniformBlock = UniformBlock.define("IndirectParams", [
290
+ ["countIndex", "u32"],
291
+ ["wg", "u32"],
292
+ ["slot", "u32"],
293
+ ["pad0", "u32"],
294
+ ]);
295
+
296
+ /** `ScanParams` (uniform, 16 B; spec 6 row 2): `count` @0 (the u32 words of the level), `pad0` @4, `pad1` @8, `pad2` @12. */
297
+ export const SCAN_PARAMS: UniformBlock = UniformBlock.define("ScanParams", [
298
+ ["count", "u32"],
299
+ ["pad0", "u32"],
300
+ ["pad1", "u32"],
301
+ ["pad2", "u32"],
302
+ ]);
303
+
304
+ /** `GridLevelParams` (uniform, 32 B; spec 7.7 G5, P4-T9): `childBase` @0 and `parentBase` @4 (the first cell of the child / parent level inside the pyramid), `parentSide` @8, `parentCells` @12 (`parentSide^dim`), `depth` @16 (1 in 2D, 2 in 3D), `pad0` @20, `pad1` @24, `pad2` @28. */
305
+ export const GRID_LEVEL_PARAMS: UniformBlock = UniformBlock.define("GridLevelParams", [
306
+ ["childBase", "u32"],
307
+ ["parentBase", "u32"],
308
+ ["parentSide", "u32"],
309
+ ["parentCells", "u32"],
310
+ ["depth", "u32"],
311
+ ["pad0", "u32"],
312
+ ["pad1", "u32"],
313
+ ["pad2", "u32"],
314
+ ]);
315
+
316
+ /** `HistParams` (uniform, 16 B; spec 6 row 5): `count` @0 (the keys), `bins` @4 (a key >= bins is not counted), `pad0` @8, `pad1` @12. */
317
+ export const HIST_PARAMS: UniformBlock = UniformBlock.define("HistParams", [
318
+ ["count", "u32"],
319
+ ["bins", "u32"],
320
+ ["pad0", "u32"],
321
+ ["pad1", "u32"],
322
+ ]);
323
+
324
+ /** `RadixParams` (uniform, 16 B; spec 6 row 6): `count` @0 (the pairs), `shift` @4 (the pass's digit shift, 8 x pass), `groups` @8 (ceil(count / WG), the stride of the digit-major table), `pad0` @12. */
325
+ export const RADIX_PARAMS: UniformBlock = UniformBlock.define("RadixParams", [
326
+ ["count", "u32"],
327
+ ["shift", "u32"],
328
+ ["groups", "u32"],
329
+ ["pad0", "u32"],
330
+ ]);
331
+
246
332
  // ---- the entries (contract 3.10.1; group 0 = graph, 1 = state, 2 = params, 3 = cold)
247
333
 
248
334
  /**
@@ -319,7 +405,7 @@ const FILL: KernelEntry = {
319
405
  phase: "P1",
320
406
  };
321
407
 
322
- /** `segmented-reduce` (3.10.1): the per-row fold of the VALUE snippet over the CSR rows; OP 0 sum / 1 min / 2 max, TIER 0 (thread-per-row; the degreeOrder tiers land at P4) plus the standard USE_PERM / HAS_WEIGHTS; 5 storage bindings; one snippet slot. */
408
+ /** `segmented-reduce` (3.10.1): the per-row fold of the VALUE snippet over the CSR rows; OP 0 sum / 1 min / 2 max, TIER 0 thread-per-row / 1 32-lanes-per-row / 2 workgroup-per-row (the degreeOrder tiers, P4 PD-6) plus the standard USE_PERM / HAS_WEIGHTS; 5 storage bindings; one snippet slot; calls the reduction helpers (TIER 2). */
323
409
  const SEGMENTED_REDUCE: KernelEntry = {
324
410
  id: "segmented-reduce",
325
411
  body: segmentedReduceWgsl,
@@ -330,12 +416,12 @@ const SEGMENTED_REDUCE: KernelEntry = {
330
416
  { name: "TIER", type: "u32", default: 0 },
331
417
  ],
332
418
  uniforms: [RANGE_PARAMS],
333
- needs: [],
419
+ needs: ["subgroups"],
334
420
  snippetSlots: ["VALUE"],
335
421
  phase: "P2",
336
422
  };
337
423
 
338
- /** `fa2-stats-finalize` (K1, 3.10.1): the one-workgroup fold of the previous integrate's partials into the state block and the K1 half of the trace record; 3 storage bindings; calls the reduction helpers. */
424
+ /** `fa2-stats-finalize` (K1, 3.10.1): the one-workgroup fold of the previous integrate's partials into the state block and the K1 half of the trace record; STATS_MODE 0 FA2 / 1 FR temperature / 2 kinetic energy (P5); the grid frame, counts and hub-counter reset under `P.gridMax > 0` (P4-T10, PD-14: `cellHist` and `hubCounters` are bound to dummies on the exact tier); 5 storage bindings; calls the reduction helpers. */
339
425
  const FA2_STATS_FINALIZE: KernelEntry = {
340
426
  id: "fa2-stats-finalize",
341
427
  body: fa2StatsFinalizeWgsl,
@@ -344,16 +430,18 @@ const FA2_STATS_FINALIZE: KernelEntry = {
344
430
  decl(1, 0, "partials", "storage-ro", "array<Fa2Partial>"),
345
431
  decl(1, 1, "S", "storage", "Fa2State"),
346
432
  decl(1, 2, "T", "storage", "array<Fa2Trace>"),
433
+ decl(1, 3, "cellHist", "storage-ro", "array<u32>"),
434
+ decl(1, 4, "hubCounters", "storage", "array<atomic<u32>>"),
347
435
  decl(2, 0, "P", "uniform", "Fa2Params"),
348
436
  ],
349
- overrideDecls: [],
437
+ overrideDecls: [{ name: "STATS_MODE", type: "u32", default: 0 }],
350
438
  uniforms: [FA2_PARAMS, FA2_STATE, FA2_TRACE, FA2_PARTIAL],
351
439
  needs: ["subgroups"],
352
440
  snippetSlots: [],
353
441
  phase: "P3",
354
442
  };
355
443
 
356
- /** `fa2-attraction` (K2, 3.10.1): the thread-per-row attraction gather over the CSR rows (the first writer of `force` each iteration); LINLOG / DISTRIBUTED / TIER 0 plus the standard USE_PERM / HAS_WEIGHTS; 6 storage bindings. */
444
+ /** `fa2-attraction` (K2, 3.10.1): the attraction gather over the CSR rows (the first writer of `force` each iteration); LINLOG / DISTRIBUTED / TIER 0 thread-per-row / 1 32-lanes-per-row / 2 workgroup-per-row (P4 PD-6) plus the standard USE_PERM / HAS_WEIGHTS; LAW 0 FA2 / 1 FR / 2 spring (P5); 6 storage bindings; calls the reduction helpers (TIER 2). */
357
445
  const FA2_ATTRACTION: KernelEntry = {
358
446
  id: "fa2-attraction",
359
447
  body: fa2AttractionWgsl,
@@ -367,14 +455,15 @@ const FA2_ATTRACTION: KernelEntry = {
367
455
  { name: "LINLOG", type: "bool", default: false },
368
456
  { name: "DISTRIBUTED", type: "bool", default: false },
369
457
  { name: "TIER", type: "u32", default: 0 },
458
+ { name: "LAW", type: "u32", default: 0 },
370
459
  ],
371
460
  uniforms: [FA2_PARAMS],
372
- needs: [],
461
+ needs: ["subgroups"],
373
462
  snippetSlots: [],
374
463
  phase: "P3",
375
464
  };
376
465
 
377
- /** `fa2-repulsion-exact` (K3, 3.10.1): the tiled all-pairs repulsion with the gravity and swing / traction epilogue; 6 storage bindings (`oldForce` read-only: it only calls load_old); calls the reduction helpers. */
466
+ /** `fa2-repulsion-exact` (K3, 3.10.1): the tiled all-pairs repulsion with the gravity and swing / traction epilogue; LAW 0 FA2 / 1 FR / 2 coulomb (P5); 6 storage bindings (`oldForce` read-only: it only calls load_old); calls the reduction helpers. */
378
467
  const FA2_REPULSION_EXACT: KernelEntry = {
379
468
  id: "fa2-repulsion-exact",
380
469
  body: fa2RepulsionExactWgsl,
@@ -392,6 +481,7 @@ const FA2_REPULSION_EXACT: KernelEntry = {
392
481
  { name: "SWING_MODE", type: "u32", default: 0 },
393
482
  { name: "STRONG_GRAVITY", type: "bool", default: false },
394
483
  { name: "GRAVITY_CENTER", type: "u32", default: 0 },
484
+ { name: "LAW", type: "u32", default: 0 },
395
485
  ],
396
486
  uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],
397
487
  needs: ["subgroups"],
@@ -417,7 +507,7 @@ const FA2_SPEED_FINALIZE: KernelEntry = {
417
507
  phase: "P1",
418
508
  };
419
509
 
420
- /** `fa2-integrate` (K5, 3.10.1): the per-node speed factor and position update (no clamp, D25), `oldForce` stored in SWING_MODE 0, and the partials A / C of the next K1; 6 storage bindings; calls the reduction helpers. */
510
+ /** `fa2-integrate` (K5, 3.10.1): the per-node speed factor and position update (no clamp, D25), `oldForce` stored in SWING_MODE 0, and the partials A / C of the next K1; APPLY 0 FA2 / 1 FR temperature cap / 2 ngraph Euler (P5); 6 storage bindings; calls the reduction helpers. */
421
511
  const FA2_INTEGRATE: KernelEntry = {
422
512
  id: "fa2-integrate",
423
513
  body: fa2IntegrateWgsl,
@@ -431,7 +521,10 @@ const FA2_INTEGRATE: KernelEntry = {
431
521
  decl(1, 5, "partials", "storage", "array<Fa2Partial>"),
432
522
  decl(2, 0, "P", "uniform", "Fa2Params"),
433
523
  ],
434
- overrideDecls: [{ name: "SWING_MODE", type: "u32", default: 0 }],
524
+ overrideDecls: [
525
+ { name: "SWING_MODE", type: "u32", default: 0 },
526
+ { name: "APPLY", type: "u32", default: 0 },
527
+ ],
435
528
  uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],
436
529
  needs: ["subgroups"],
437
530
  snippetSlots: [],
@@ -455,7 +548,7 @@ const FA2_TO_SCENE: KernelEntry = {
455
548
  phase: "P3",
456
549
  };
457
550
 
458
- /** `spmv-pull` (spec 8.10): the grid-stride pull SpMV over the reverse adjacency; HAS_PERSONALIZATION / USE_DANGLING plus the standard USE_PERM / HAS_WEIGHTS; 8 storage bindings (the design's count). */
551
+ /** `spmv-pull` (spec 8.10): the pull SpMV over the reverse adjacency; HAS_PERSONALIZATION / USE_DANGLING / TIER 0 grid-stride / 1 32-lanes-per-row / 2 workgroup-per-row (the reverseDegreeOrder tiers, P4 PD-6) plus the standard USE_PERM / HAS_WEIGHTS; 8 storage bindings (the design's count); calls the reduction helpers (TIER 2). */
459
552
  const SPMV_PULL: KernelEntry = {
460
553
  id: "spmv-pull",
461
554
  body: spmvPullWgsl,
@@ -470,9 +563,10 @@ const SPMV_PULL: KernelEntry = {
470
563
  overrideDecls: [
471
564
  { name: "HAS_PERSONALIZATION", type: "bool", default: false },
472
565
  { name: "USE_DANGLING", type: "bool", default: false },
566
+ { name: "TIER", type: "u32", default: 0 },
473
567
  ],
474
568
  uniforms: [SPMV_PARAMS, PR_PARTIAL],
475
- needs: [],
569
+ needs: ["subgroups"],
476
570
  snippetSlots: [],
477
571
  phase: "P7",
478
572
  };
@@ -574,6 +668,253 @@ const WCC_SAMPLE: KernelEntry = {
574
668
  phase: "P7",
575
669
  };
576
670
 
671
+ /** `indirect-finalize` (spec 5.4; P4-T1): the one-lane count -> (x, y, 1, count) finalize; 2 storage bindings. */
672
+ const INDIRECT_FINALIZE: KernelEntry = {
673
+ id: "indirect-finalize",
674
+ body: indirectFinalizeWgsl,
675
+ entryPoint: "indirect_finalize",
676
+ bindings: [
677
+ decl(1, 0, "counters", "storage-ro", "array<u32>"),
678
+ decl(1, 1, "args", "storage", "array<u32>"),
679
+ decl(2, 0, "P", "uniform", "IndirectParams"),
680
+ ],
681
+ overrideDecls: [],
682
+ uniforms: [INDIRECT_PARAMS],
683
+ needs: [],
684
+ snippetSlots: [],
685
+ phase: "P4",
686
+ };
687
+
688
+ /** `scan-block` (spec 6 row 2 steps (a) / (b); P4-T2, PD-3): the Hillis-Steele exclusive scan of one WG-wide block into `out` and its total into `blockSums[group]`; 3 storage bindings; no subgroup variant. */
689
+ const SCAN_BLOCK: KernelEntry = {
690
+ id: "scan-block",
691
+ body: scanBlockWgsl,
692
+ entryPoint: "scan_block",
693
+ bindings: [
694
+ decl(1, 0, "src", "storage-ro", "array<u32>"),
695
+ decl(1, 1, "out", "storage", "array<u32>"),
696
+ decl(1, 2, "blockSums", "storage", "array<u32>"),
697
+ decl(2, 0, "P", "uniform", "ScanParams"),
698
+ ],
699
+ overrideDecls: [],
700
+ uniforms: [SCAN_PARAMS],
701
+ needs: [],
702
+ snippetSlots: [],
703
+ phase: "P4",
704
+ };
705
+
706
+ /** `scan-add` (spec 6 row 2 step (c); P4-T2): adds `blockOffsets[group]` to every element of the block; 2 storage bindings. */
707
+ const SCAN_ADD: KernelEntry = {
708
+ id: "scan-add",
709
+ body: scanAddWgsl,
710
+ entryPoint: "scan_add",
711
+ bindings: [
712
+ decl(1, 0, "out", "storage", "array<u32>"),
713
+ decl(1, 1, "blockOffsets", "storage-ro", "array<u32>"),
714
+ decl(2, 0, "P", "uniform", "ScanParams"),
715
+ ],
716
+ overrideDecls: [],
717
+ uniforms: [SCAN_PARAMS],
718
+ needs: [],
719
+ snippetSlots: [],
720
+ phase: "P4",
721
+ };
722
+
723
+ /** `histogram` (spec 6 row 5; P4-T3, PD-4): one global atomicAdd per key into `hist` (zeroed by a `fill` dispatch earlier in the pass); 2 storage bindings; one path, no PRIVATE override. */
724
+ const HISTOGRAM: KernelEntry = {
725
+ id: "histogram",
726
+ body: histogramWgsl,
727
+ entryPoint: "histogram",
728
+ bindings: [
729
+ decl(1, 0, "keys", "storage-ro", "array<u32>"),
730
+ decl(1, 1, "hist", "storage", "array<atomic<u32>>"),
731
+ decl(2, 0, "P", "uniform", "HistParams"),
732
+ ],
733
+ overrideDecls: [],
734
+ uniforms: [HIST_PARAMS],
735
+ needs: [],
736
+ snippetSlots: [],
737
+ phase: "P4",
738
+ };
739
+
740
+ /** `counting-scatter` (spec 6 row 5; P4-T3): the scatter of a counting sort, `outIndex[start[k] + atomicAdd(&cursor[k], 1u)] = i`; 4 storage bindings; set-deterministic (the order inside a bin follows the schedule). */
741
+ const COUNTING_SCATTER: KernelEntry = {
742
+ id: "counting-scatter",
743
+ body: countingScatterWgsl,
744
+ entryPoint: "counting_scatter",
745
+ bindings: [
746
+ decl(1, 0, "keys", "storage-ro", "array<u32>"),
747
+ decl(1, 1, "start", "storage-ro", "array<u32>"),
748
+ decl(1, 2, "cursor", "storage", "array<atomic<u32>>"),
749
+ decl(1, 3, "outIndex", "storage", "array<u32>"),
750
+ decl(2, 0, "P", "uniform", "HistParams"),
751
+ ],
752
+ overrideDecls: [],
753
+ uniforms: [HIST_PARAMS],
754
+ needs: [],
755
+ snippetSlots: [],
756
+ phase: "P4",
757
+ };
758
+
759
+ /** `radix-hist` (spec 6 row 6; P4-T4, PD-5): the per-workgroup 256-bin digit histogram, privatised in workgroup memory and stored digit-major `hist[digit * groups + group]`; 2 storage bindings. */
760
+ const RADIX_HIST: KernelEntry = {
761
+ id: "radix-hist",
762
+ body: radixHistWgsl,
763
+ entryPoint: "radix_hist",
764
+ bindings: [
765
+ decl(1, 0, "keys", "storage-ro", "array<u32>"),
766
+ decl(1, 1, "hist", "storage", "array<u32>"),
767
+ decl(2, 0, "P", "uniform", "RadixParams"),
768
+ ],
769
+ overrideDecls: [],
770
+ uniforms: [RADIX_PARAMS],
771
+ needs: [],
772
+ snippetSlots: [],
773
+ phase: "P4",
774
+ };
775
+
776
+ /** `radix-scatter` (spec 6 row 6; P4-T4, PD-5): the stable scatter of one LSD pass, ranked serially by lane 0, written at `offsets[digit * groups + group] + rank`; 5 storage bindings. */
777
+ const RADIX_SCATTER: KernelEntry = {
778
+ id: "radix-scatter",
779
+ body: radixScatterWgsl,
780
+ entryPoint: "radix_scatter",
781
+ bindings: [
782
+ decl(1, 0, "keys", "storage-ro", "array<u32>"),
783
+ decl(1, 1, "vals", "storage-ro", "array<u32>"),
784
+ decl(1, 2, "offsets", "storage-ro", "array<u32>"),
785
+ decl(1, 3, "keysOut", "storage", "array<u32>"),
786
+ decl(1, 4, "valsOut", "storage", "array<u32>"),
787
+ decl(2, 0, "P", "uniform", "RadixParams"),
788
+ ],
789
+ overrideDecls: [],
790
+ uniforms: [RADIX_PARAMS],
791
+ needs: [],
792
+ snippetSlots: [],
793
+ phase: "P4",
794
+ };
795
+
796
+ /** `grid-cell-key` (G1, spec 7.7; P4-T8, PD-10): the finest cell key of every node, `floor((p - gridMin) * invCellSize)` linearised, or the outside pseudo-cell `G^dim`; `cellVal[i] = i`; 4 storage bindings (the state read-only: K1 writes it). */
797
+ const GRID_CELL_KEY: KernelEntry = {
798
+ id: "grid-cell-key",
799
+ body: gridCellKeyWgsl,
800
+ entryPoint: "grid_cell_key",
801
+ bindings: [
802
+ decl(1, 0, "pos", "storage-ro", "array<vec4f>"),
803
+ decl(1, 1, "S", "storage-ro", "Fa2State"),
804
+ decl(1, 2, "cellKey", "storage", "array<u32>"),
805
+ decl(1, 3, "cellVal", "storage", "array<u32>"),
806
+ decl(2, 0, "P", "uniform", "Fa2Params"),
807
+ ],
808
+ overrideDecls: [],
809
+ uniforms: [FA2_PARAMS, FA2_STATE],
810
+ needs: [],
811
+ snippetSlots: [],
812
+ phase: "P4",
813
+ };
814
+
815
+ /** `grid-centroid` (G4, spec 7.7; P4-T9, PD-13): thread per finest cell (the pseudo-cell included), the serial mass-weighted sum in sorted order into level 0, the occupancy max into `hubCounters[1]`, hub cells (> GRID_HUB_CELL) appended to `hubList`; 6 storage bindings. */
816
+ const GRID_CENTROID: KernelEntry = {
817
+ id: "grid-centroid",
818
+ body: gridCentroidWgsl,
819
+ entryPoint: "grid_centroid",
820
+ bindings: [
821
+ decl(1, 0, "sortedIdx", "storage-ro", "array<u32>"),
822
+ decl(1, 1, "cellStart", "storage-ro", "array<u32>"),
823
+ decl(1, 2, "pos", "storage-ro", "array<vec4f>"),
824
+ decl(1, 3, "pyramid", "storage", "array<vec4f>"),
825
+ decl(1, 4, "hubList", "storage", "array<u32>"),
826
+ decl(1, 5, "hubCounters", "storage", "array<atomic<u32>>"),
827
+ decl(2, 0, "P", "uniform", "Fa2Params"),
828
+ ],
829
+ overrideDecls: [],
830
+ uniforms: [FA2_PARAMS],
831
+ needs: [],
832
+ snippetSlots: [],
833
+ phase: "P4",
834
+ };
835
+
836
+ /** `grid-centroid-hub` (G4b, spec 7.7; P4-T9, PD-13, DEP-P4-L): one workgroup per hub cell, dispatched indirectly, a WG-strided sum through `wg_reduce_vec4` guarded by `h < hubCount[0]`; 6 storage bindings (`hubCount` is a read-only view of `hubCounters`). */
837
+ const GRID_CENTROID_HUB: KernelEntry = {
838
+ id: "grid-centroid-hub",
839
+ body: gridCentroidHubWgsl,
840
+ entryPoint: "grid_centroid_hub",
841
+ bindings: [
842
+ decl(1, 0, "sortedIdx", "storage-ro", "array<u32>"),
843
+ decl(1, 1, "cellStart", "storage-ro", "array<u32>"),
844
+ decl(1, 2, "pos", "storage-ro", "array<vec4f>"),
845
+ decl(1, 3, "pyramid", "storage", "array<vec4f>"),
846
+ decl(1, 4, "hubList", "storage-ro", "array<u32>"),
847
+ decl(1, 5, "hubCount", "storage-ro", "array<u32>"),
848
+ decl(2, 0, "P", "uniform", "Fa2Params"),
849
+ ],
850
+ overrideDecls: [],
851
+ uniforms: [FA2_PARAMS],
852
+ needs: ["subgroups"],
853
+ snippetSlots: [],
854
+ phase: "P4",
855
+ };
856
+
857
+ /** `grid-downsample` (G5, spec 7.7; P4-T9): one dispatch per coarser level, every parent the sum of its 4 / 8 children at `P.childBase`, written at `P.parentBase`; 1 storage binding. */
858
+ const GRID_DOWNSAMPLE: KernelEntry = {
859
+ id: "grid-downsample",
860
+ body: gridDownsampleWgsl,
861
+ entryPoint: "grid_downsample",
862
+ bindings: [decl(1, 0, "pyramid", "storage", "array<vec4f>"), decl(2, 0, "P", "uniform", "GridLevelParams")],
863
+ overrideDecls: [],
864
+ uniforms: [GRID_LEVEL_PARAMS],
865
+ needs: [],
866
+ snippetSlots: [],
867
+ phase: "P4",
868
+ };
869
+
870
+ /** `grid-far-field` (G6, spec 7.7; P4-T10, PD-16, DEP-P4-G): per node in sorted order, the coarsest level minus its 3x3 (3x3x3) and, per finer level, the parent's 3x3 refined minus the level's own 3x3, plus the pseudo-cell; the loop bounds are `P.levels` / `P.gridMax`; LAW 0 FA2 / 1 FR / 2 coulomb per cell (P4-T13, PD-22); 5 storage bindings. */
871
+ const GRID_FAR_FIELD: KernelEntry = {
872
+ id: "grid-far-field",
873
+ body: gridFarFieldWgsl,
874
+ entryPoint: "grid_far_field",
875
+ bindings: [
876
+ decl(1, 0, "pos", "storage-ro", "array<vec4f>"),
877
+ decl(1, 1, "sortedIdx", "storage-ro", "array<u32>"),
878
+ decl(1, 2, "pyramid", "storage-ro", "array<vec4f>"),
879
+ decl(1, 3, "S", "storage-ro", "Fa2State"),
880
+ decl(1, 4, "force", "storage", "array<f32>"),
881
+ decl(2, 0, "P", "uniform", "Fa2Params"),
882
+ ],
883
+ overrideDecls: [{ name: "LAW", type: "u32", default: 0 }],
884
+ uniforms: [FA2_PARAMS, FA2_STATE],
885
+ needs: [],
886
+ snippetSlots: [],
887
+ phase: "P4",
888
+ };
889
+
890
+ /** `grid-near-field` (G7, spec 7.7; P4-T10, PD-15): per node in sorted order, K3's exact pair law over the 9 (27) finest cells, a cell above `nearMax` sampled through the hashed window and scaled by `others / sampled`, then K3's fused epilogue (gravity, `force +=`, the swing / traction reduction); SWING_MODE / STRONG_GRAVITY / GRAVITY_CENTER / LAW as K3 (LAW 0 FA2 / 1 FR / 2 coulomb, P4-T13, PD-22); 8 storage bindings; calls the reduction helpers. */
891
+ const GRID_NEAR_FIELD: KernelEntry = {
892
+ id: "grid-near-field",
893
+ body: gridNearFieldWgsl,
894
+ entryPoint: "grid_near_field",
895
+ bindings: [
896
+ decl(1, 0, "pos", "storage-ro", "array<vec4f>"),
897
+ decl(1, 1, "sortedIdx", "storage-ro", "array<u32>"),
898
+ decl(1, 2, "cellStart", "storage-ro", "array<u32>"),
899
+ decl(1, 3, "S", "storage", "Fa2State"),
900
+ decl(1, 4, "force", "storage", "array<f32>"),
901
+ decl(1, 5, "oldForce", "storage-ro", "array<f32>"),
902
+ decl(1, 6, "fixedMask", "storage-ro", "array<u32>"),
903
+ decl(1, 7, "partials", "storage", "array<Fa2Partial>"),
904
+ decl(2, 0, "P", "uniform", "Fa2Params"),
905
+ ],
906
+ overrideDecls: [
907
+ { name: "SWING_MODE", type: "u32", default: 0 },
908
+ { name: "STRONG_GRAVITY", type: "bool", default: false },
909
+ { name: "GRAVITY_CENTER", type: "u32", default: 0 },
910
+ { name: "LAW", type: "u32", default: 0 },
911
+ ],
912
+ uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],
913
+ needs: ["subgroups"],
914
+ snippetSlots: [],
915
+ phase: "P4",
916
+ };
917
+
577
918
  /**
578
919
  * The entries by id, in dispatch order. PLAN DECISION: `KernelId` is declared in full (contract 3.10) while the
579
920
  * entries landed phase by phase, so the table is built as a Partial record and exported below through the
@@ -601,6 +942,19 @@ const REGISTRY: Readonly<Partial<Record<KernelId, KernelEntry>>> = Object.freeze
601
942
  "wcc-link-edges": WCC_LINK_EDGES,
602
943
  "wcc-compress": WCC_COMPRESS,
603
944
  "wcc-sample": WCC_SAMPLE,
945
+ "indirect-finalize": INDIRECT_FINALIZE,
946
+ "scan-block": SCAN_BLOCK,
947
+ "scan-add": SCAN_ADD,
948
+ histogram: HISTOGRAM,
949
+ "counting-scatter": COUNTING_SCATTER,
950
+ "radix-hist": RADIX_HIST,
951
+ "radix-scatter": RADIX_SCATTER,
952
+ "grid-cell-key": GRID_CELL_KEY,
953
+ "grid-centroid": GRID_CENTROID,
954
+ "grid-centroid-hub": GRID_CENTROID_HUB,
955
+ "grid-downsample": GRID_DOWNSAMPLE,
956
+ "grid-far-field": GRID_FAR_FIELD,
957
+ "grid-near-field": GRID_NEAR_FIELD,
604
958
  });
605
959
 
606
960
  /** THE registry (spec 3.5): every entry, keyed by id. */