@graphty/webgpu-graph-algorithms 0.5.1 → 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 (243) hide show
  1. package/README.md +98 -52
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{context-BR7fx3vR.js → context-BXqgCifx.js} +190 -40
  4. package/dist/chunks/context-BXqgCifx.js.map +1 -0
  5. package/dist/node.js +1 -1
  6. package/dist/src/algorithms/components.d.ts.map +1 -1
  7. package/dist/src/algorithms/components.js +12 -13
  8. package/dist/src/algorithms/components.js.map +1 -1
  9. package/dist/src/algorithms/degree.d.ts +6 -8
  10. package/dist/src/algorithms/degree.d.ts.map +1 -1
  11. package/dist/src/algorithms/degree.js +58 -35
  12. package/dist/src/algorithms/degree.js.map +1 -1
  13. package/dist/src/algorithms/pagerank.d.ts.map +1 -1
  14. package/dist/src/algorithms/pagerank.js +16 -14
  15. package/dist/src/algorithms/pagerank.js.map +1 -1
  16. package/dist/src/algorithms/power-iteration.d.ts +2 -2
  17. package/dist/src/algorithms/power-iteration.d.ts.map +1 -1
  18. package/dist/src/algorithms/power-iteration.js +17 -14
  19. package/dist/src/algorithms/power-iteration.js.map +1 -1
  20. package/dist/src/constants.d.ts +38 -8
  21. package/dist/src/constants.d.ts.map +1 -1
  22. package/dist/src/constants.js +38 -8
  23. package/dist/src/constants.js.map +1 -1
  24. package/dist/src/errors.d.ts +3 -2
  25. package/dist/src/errors.d.ts.map +1 -1
  26. package/dist/src/errors.js +2 -1
  27. package/dist/src/errors.js.map +1 -1
  28. package/dist/src/index.d.ts +6 -4
  29. package/dist/src/index.d.ts.map +1 -1
  30. package/dist/src/index.js +8 -3
  31. package/dist/src/index.js.map +1 -1
  32. package/dist/src/kernel/dispatch.d.ts +8 -3
  33. package/dist/src/kernel/dispatch.d.ts.map +1 -1
  34. package/dist/src/kernel/dispatch.js +18 -7
  35. package/dist/src/kernel/dispatch.js.map +1 -1
  36. package/dist/src/kernel/kernel.d.ts +30 -1
  37. package/dist/src/kernel/kernel.d.ts.map +1 -1
  38. package/dist/src/kernel/kernel.js +49 -5
  39. package/dist/src/kernel/kernel.js.map +1 -1
  40. package/dist/src/kernel/prelude.d.ts.map +1 -1
  41. package/dist/src/kernel/prelude.js +6 -1
  42. package/dist/src/kernel/prelude.js.map +1 -1
  43. package/dist/src/kernel/profiler.d.ts +15 -3
  44. package/dist/src/kernel/profiler.d.ts.map +1 -1
  45. package/dist/src/kernel/profiler.js +27 -4
  46. package/dist/src/kernel/profiler.js.map +1 -1
  47. package/dist/src/kernels.d.ts +17 -7
  48. package/dist/src/kernels.d.ts.map +1 -1
  49. package/dist/src/kernels.js +323 -16
  50. package/dist/src/kernels.js.map +1 -1
  51. package/dist/src/layouts/calibrate.d.ts +51 -0
  52. package/dist/src/layouts/calibrate.d.ts.map +1 -0
  53. package/dist/src/layouts/calibrate.js +172 -0
  54. package/dist/src/layouts/calibrate.js.map +1 -0
  55. package/dist/src/layouts/force-simulation.d.ts +39 -4
  56. package/dist/src/layouts/force-simulation.d.ts.map +1 -1
  57. package/dist/src/layouts/force-simulation.js +71 -19
  58. package/dist/src/layouts/force-simulation.js.map +1 -1
  59. package/dist/src/layouts/forceatlas2.d.ts +107 -36
  60. package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
  61. package/dist/src/layouts/forceatlas2.js +296 -100
  62. package/dist/src/layouts/forceatlas2.js.map +1 -1
  63. package/dist/src/layouts/fruchterman-reingold.d.ts +73 -27
  64. package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -1
  65. package/dist/src/layouts/fruchterman-reingold.js +230 -70
  66. package/dist/src/layouts/fruchterman-reingold.js.map +1 -1
  67. package/dist/src/layouts/model-common.d.ts +41 -3
  68. package/dist/src/layouts/model-common.d.ts.map +1 -1
  69. package/dist/src/layouts/model-common.js +74 -3
  70. package/dist/src/layouts/model-common.js.map +1 -1
  71. package/dist/src/layouts/repulsion-grid.d.ts +152 -0
  72. package/dist/src/layouts/repulsion-grid.d.ts.map +1 -0
  73. package/dist/src/layouts/repulsion-grid.js +318 -0
  74. package/dist/src/layouts/repulsion-grid.js.map +1 -0
  75. package/dist/src/layouts/spring-electrical.d.ts +75 -30
  76. package/dist/src/layouts/spring-electrical.d.ts.map +1 -1
  77. package/dist/src/layouts/spring-electrical.js +231 -74
  78. package/dist/src/layouts/spring-electrical.js.map +1 -1
  79. package/dist/src/memory/residency.d.ts +6 -2
  80. package/dist/src/memory/residency.d.ts.map +1 -1
  81. package/dist/src/memory/residency.js +84 -14
  82. package/dist/src/memory/residency.js.map +1 -1
  83. package/dist/src/primitives/core-shape.d.ts +38 -2
  84. package/dist/src/primitives/core-shape.d.ts.map +1 -1
  85. package/dist/src/primitives/core-shape.js +71 -3
  86. package/dist/src/primitives/core-shape.js.map +1 -1
  87. package/dist/src/primitives/grid-pyramid.d.ts +71 -0
  88. package/dist/src/primitives/grid-pyramid.d.ts.map +1 -0
  89. package/dist/src/primitives/grid-pyramid.js +143 -0
  90. package/dist/src/primitives/grid-pyramid.js.map +1 -0
  91. package/dist/src/primitives/grid.d.ts +118 -0
  92. package/dist/src/primitives/grid.d.ts.map +1 -0
  93. package/dist/src/primitives/grid.js +225 -0
  94. package/dist/src/primitives/grid.js.map +1 -0
  95. package/dist/src/primitives/histogram.d.ts +67 -0
  96. package/dist/src/primitives/histogram.d.ts.map +1 -0
  97. package/dist/src/primitives/histogram.js +190 -0
  98. package/dist/src/primitives/histogram.js.map +1 -0
  99. package/dist/src/primitives/radix-sort.d.ts +75 -0
  100. package/dist/src/primitives/radix-sort.d.ts.map +1 -0
  101. package/dist/src/primitives/radix-sort.js +168 -0
  102. package/dist/src/primitives/radix-sort.js.map +1 -0
  103. package/dist/src/primitives/scan.d.ts +44 -0
  104. package/dist/src/primitives/scan.d.ts.map +1 -0
  105. package/dist/src/primitives/scan.js +151 -0
  106. package/dist/src/primitives/scan.js.map +1 -0
  107. package/dist/src/primitives/segmented-reduce.d.ts +25 -17
  108. package/dist/src/primitives/segmented-reduce.d.ts.map +1 -1
  109. package/dist/src/primitives/segmented-reduce.js +166 -47
  110. package/dist/src/primitives/segmented-reduce.js.map +1 -1
  111. package/dist/src/primitives/spmv.d.ts +18 -14
  112. package/dist/src/primitives/spmv.d.ts.map +1 -1
  113. package/dist/src/primitives/spmv.js +94 -58
  114. package/dist/src/primitives/spmv.js.map +1 -1
  115. package/dist/src/primitives/verify.d.ts +49 -0
  116. package/dist/src/primitives/verify.d.ts.map +1 -0
  117. package/dist/src/primitives/verify.js +229 -0
  118. package/dist/src/primitives/verify.js.map +1 -0
  119. package/dist/src/types/context.d.ts +53 -0
  120. package/dist/src/types/context.d.ts.map +1 -1
  121. package/dist/src/types/layout.d.ts +20 -0
  122. package/dist/src/types/layout.d.ts.map +1 -1
  123. package/dist/src/wgsl/counting-scatter.wgsl.d.ts +8 -0
  124. package/dist/src/wgsl/counting-scatter.wgsl.d.ts.map +1 -0
  125. package/dist/src/wgsl/counting-scatter.wgsl.js +17 -0
  126. package/dist/src/wgsl/counting-scatter.wgsl.js.map +1 -0
  127. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +23 -11
  128. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -1
  129. package/dist/src/wgsl/fa2-attraction.wgsl.js +98 -20
  130. package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -1
  131. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +6 -2
  132. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
  133. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +22 -1
  134. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
  135. package/dist/src/wgsl/grid-cell-key.wgsl.d.ts +8 -0
  136. package/dist/src/wgsl/grid-cell-key.wgsl.d.ts.map +1 -0
  137. package/dist/src/wgsl/grid-cell-key.wgsl.js +30 -0
  138. package/dist/src/wgsl/grid-cell-key.wgsl.js.map +1 -0
  139. package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +8 -0
  140. package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts.map +1 -0
  141. package/dist/src/wgsl/grid-centroid-hub.wgsl.js +29 -0
  142. package/dist/src/wgsl/grid-centroid-hub.wgsl.js.map +1 -0
  143. package/dist/src/wgsl/grid-centroid.wgsl.d.ts +8 -0
  144. package/dist/src/wgsl/grid-centroid.wgsl.d.ts.map +1 -0
  145. package/dist/src/wgsl/grid-centroid.wgsl.js +29 -0
  146. package/dist/src/wgsl/grid-centroid.wgsl.js.map +1 -0
  147. package/dist/src/wgsl/grid-downsample.wgsl.d.ts +7 -0
  148. package/dist/src/wgsl/grid-downsample.wgsl.d.ts.map +1 -0
  149. package/dist/src/wgsl/grid-downsample.wgsl.js +28 -0
  150. package/dist/src/wgsl/grid-downsample.wgsl.js.map +1 -0
  151. package/dist/src/wgsl/grid-far-field.wgsl.d.ts +13 -0
  152. package/dist/src/wgsl/grid-far-field.wgsl.d.ts.map +1 -0
  153. package/dist/src/wgsl/grid-far-field.wgsl.js +98 -0
  154. package/dist/src/wgsl/grid-far-field.wgsl.js.map +1 -0
  155. package/dist/src/wgsl/grid-near-field.wgsl.d.ts +19 -0
  156. package/dist/src/wgsl/grid-near-field.wgsl.d.ts.map +1 -0
  157. package/dist/src/wgsl/grid-near-field.wgsl.js +129 -0
  158. package/dist/src/wgsl/grid-near-field.wgsl.js.map +1 -0
  159. package/dist/src/wgsl/histogram.wgsl.d.ts +7 -0
  160. package/dist/src/wgsl/histogram.wgsl.d.ts.map +1 -0
  161. package/dist/src/wgsl/histogram.wgsl.js +15 -0
  162. package/dist/src/wgsl/histogram.wgsl.js.map +1 -0
  163. package/dist/src/wgsl/indirect-finalize.wgsl.d.ts +8 -0
  164. package/dist/src/wgsl/indirect-finalize.wgsl.d.ts.map +1 -0
  165. package/dist/src/wgsl/indirect-finalize.wgsl.js +26 -0
  166. package/dist/src/wgsl/indirect-finalize.wgsl.js.map +1 -0
  167. package/dist/src/wgsl/radix-hist.wgsl.d.ts +9 -0
  168. package/dist/src/wgsl/radix-hist.wgsl.d.ts.map +1 -0
  169. package/dist/src/wgsl/radix-hist.wgsl.js +31 -0
  170. package/dist/src/wgsl/radix-hist.wgsl.js.map +1 -0
  171. package/dist/src/wgsl/radix-scatter.wgsl.d.ts +9 -0
  172. package/dist/src/wgsl/radix-scatter.wgsl.d.ts.map +1 -0
  173. package/dist/src/wgsl/radix-scatter.wgsl.js +40 -0
  174. package/dist/src/wgsl/radix-scatter.wgsl.js.map +1 -0
  175. package/dist/src/wgsl/scan-add.wgsl.d.ts +6 -0
  176. package/dist/src/wgsl/scan-add.wgsl.d.ts.map +1 -0
  177. package/dist/src/wgsl/scan-add.wgsl.js +14 -0
  178. package/dist/src/wgsl/scan-add.wgsl.js.map +1 -0
  179. package/dist/src/wgsl/scan-block.wgsl.d.ts +8 -0
  180. package/dist/src/wgsl/scan-block.wgsl.d.ts.map +1 -0
  181. package/dist/src/wgsl/scan-block.wgsl.js +30 -0
  182. package/dist/src/wgsl/scan-block.wgsl.js.map +1 -0
  183. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +22 -8
  184. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -1
  185. package/dist/src/wgsl/segmented-reduce.wgsl.js +84 -15
  186. package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -1
  187. package/dist/src/wgsl/spmv-pull.wgsl.d.ts +22 -11
  188. package/dist/src/wgsl/spmv-pull.wgsl.d.ts.map +1 -1
  189. package/dist/src/wgsl/spmv-pull.wgsl.js +110 -36
  190. package/dist/src/wgsl/spmv-pull.wgsl.js.map +1 -1
  191. package/dist/tsconfig.build.tsbuildinfo +1 -1
  192. package/dist/webgpu-graph-algorithms.js +3815 -1003
  193. package/dist/webgpu-graph-algorithms.js.map +1 -1
  194. package/package.json +5 -4
  195. package/src/algorithms/components.ts +12 -16
  196. package/src/algorithms/degree.ts +58 -43
  197. package/src/algorithms/pagerank.ts +20 -18
  198. package/src/algorithms/power-iteration.ts +19 -18
  199. package/src/constants.ts +38 -8
  200. package/src/errors.ts +3 -1
  201. package/src/index.ts +14 -4
  202. package/src/kernel/dispatch.ts +18 -7
  203. package/src/kernel/kernel.ts +59 -5
  204. package/src/kernel/prelude.ts +9 -0
  205. package/src/kernel/profiler.ts +28 -4
  206. package/src/kernels.ts +356 -18
  207. package/src/layouts/calibrate.ts +187 -0
  208. package/src/layouts/force-simulation.ts +91 -23
  209. package/src/layouts/forceatlas2.ts +331 -106
  210. package/src/layouts/fruchterman-reingold.ts +255 -74
  211. package/src/layouts/model-common.ts +98 -3
  212. package/src/layouts/repulsion-grid.ts +451 -0
  213. package/src/layouts/spring-electrical.ts +257 -78
  214. package/src/memory/residency.ts +126 -20
  215. package/src/primitives/core-shape.ts +91 -4
  216. package/src/primitives/grid-pyramid.ts +221 -0
  217. package/src/primitives/grid.ts +349 -0
  218. package/src/primitives/histogram.ts +273 -0
  219. package/src/primitives/radix-sort.ts +246 -0
  220. package/src/primitives/scan.ts +197 -0
  221. package/src/primitives/segmented-reduce.ts +214 -56
  222. package/src/primitives/spmv.ts +125 -65
  223. package/src/primitives/verify.ts +249 -0
  224. package/src/types/context.ts +56 -0
  225. package/src/types/layout.ts +22 -0
  226. package/src/wgsl/counting-scatter.wgsl.ts +16 -0
  227. package/src/wgsl/fa2-attraction.wgsl.ts +98 -20
  228. package/src/wgsl/fa2-stats-finalize.wgsl.ts +22 -1
  229. package/src/wgsl/grid-cell-key.wgsl.ts +29 -0
  230. package/src/wgsl/grid-centroid-hub.wgsl.ts +28 -0
  231. package/src/wgsl/grid-centroid.wgsl.ts +28 -0
  232. package/src/wgsl/grid-downsample.wgsl.ts +27 -0
  233. package/src/wgsl/grid-far-field.wgsl.ts +97 -0
  234. package/src/wgsl/grid-near-field.wgsl.ts +128 -0
  235. package/src/wgsl/histogram.wgsl.ts +14 -0
  236. package/src/wgsl/indirect-finalize.wgsl.ts +25 -0
  237. package/src/wgsl/radix-hist.wgsl.ts +30 -0
  238. package/src/wgsl/radix-scatter.wgsl.ts +39 -0
  239. package/src/wgsl/scan-add.wgsl.ts +13 -0
  240. package/src/wgsl/scan-block.wgsl.ts +29 -0
  241. package/src/wgsl/segmented-reduce.wgsl.ts +84 -15
  242. package/src/wgsl/spmv-pull.wgsl.ts +110 -36
  243. package/dist/chunks/context-BR7fx3vR.js.map +0 -1
@@ -0,0 +1,143 @@
1
+ /**
2
+ * The grid pyramid (spec 6 row 12, 7.7 G4-G5; P4-T9): the planner that records, into the caller's pass, the finest
3
+ * centroids (G4, `grid-centroid`: thread per cell over `cells + 1`, the pseudo-cell included), the hub-cell
4
+ * completion (G4a: the T1 `indirect-finalize` over `hubCounters[0]` into `hubArgs` with `wg = 1`, so the finalize's
5
+ * `ceil(count / wg)` is ONE workgroup per hub cell; G4b: `grid-centroid-hub`, one workgroup per hub cell, dispatched
6
+ * indirectly; PD-13, DEP-P4-I) and one `grid-downsample` dispatch per coarser
7
+ * level (G5). Level 0 holds `[sum m x, sum m y, sum m z, sum m]` per cell; every parent is the sum of its 2^dim
8
+ * children; the pseudo-cell (index `cells` of level 0) is never a child. No atomics touch the sums (design 6 row 12:
9
+ * bitwise reproducible); the only atomics are the hub append and the occupancy max.
10
+ *
11
+ * The named grid buffers (`pyramid`, `hubList`, `hubCounters`, `hubArgs`) are the caller's (the model's
12
+ * `BufferSpec`s, so `inspect(name)` reaches them); the static params of the finalize and of every level are written
13
+ * ONCE at bind() through the scope's params writer (PD-11), so record() writes no uniform. `src/primitives/**` never
14
+ * imports `src/context.ts`.
15
+ */
16
+ import { WebGpuGraphError } from "../errors.js";
17
+ import { plan1d } from "../kernel/dispatch.js";
18
+ import { GRID_LEVEL_PARAMS, INDIRECT_PARAMS, kernelSpec } from "../kernels.js";
19
+ /**
20
+ * Prepares the pyramid's pipelines over a scope (G4, the finalize, G4b and G5; compiles once) so bind() and record()
21
+ * are synchronous. The planner lives exactly as long as the scope.
22
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
23
+ * @param spec - the grid
24
+ * @returns the planner
25
+ */
26
+ export async function preparePyramid(scope, spec) {
27
+ const centroid = await scope.pipelines.kernel(kernelSpec("grid-centroid"));
28
+ const finalize = await scope.pipelines.kernel(kernelSpec("indirect-finalize"));
29
+ const hub = await scope.pipelines.kernel(kernelSpec("grid-centroid-hub"));
30
+ const downsample = await scope.pipelines.kernel(kernelSpec("grid-downsample"));
31
+ return new GridPyramidPlannerImpl(scope, spec, { centroid, finalize, hub, downsample });
32
+ }
33
+ /** The planner: G4, G4a, G4b and G5 over one scope. */
34
+ class GridPyramidPlannerImpl {
35
+ /**
36
+ * Wraps the resolved kernels; use preparePyramid().
37
+ * @param scope - the caller's scope
38
+ * @param spec - the grid
39
+ * @param kernels - the four kernels
40
+ */
41
+ constructor(scope, spec, kernels) {
42
+ this.bound = null;
43
+ this.dispatches = 0;
44
+ this.scope = scope;
45
+ this.spec = spec;
46
+ this.kernels = kernels;
47
+ }
48
+ /**
49
+ * Dispatches the last record() issued.
50
+ * @returns the count
51
+ */
52
+ get lastDispatches() {
53
+ return this.dispatches;
54
+ }
55
+ /**
56
+ * Binds the buffers and writes the static params (see the interface).
57
+ * @param bindings - the buffers
58
+ */
59
+ bind(bindings) {
60
+ const { centroid, finalize, hub, downsample } = this.kernels;
61
+ const { spec, scope } = this;
62
+ const b = bindings;
63
+ const finalizeParams = scope.params(INDIRECT_PARAMS, {
64
+ countIndex: 0,
65
+ wg: 1, // the finalize plans ceil(count / wg) workgroups over ITEMS; G4b's item is a hub cell, one workgroup each
66
+ slot: 0,
67
+ pad0: 0,
68
+ });
69
+ const levels = [];
70
+ let parentSide = spec.g;
71
+ for (let level = 0; level + 1 < spec.levels; level++) {
72
+ parentSide /= 2;
73
+ const parentCells = parentSide ** spec.dim;
74
+ const params = scope.params(GRID_LEVEL_PARAMS, {
75
+ childBase: spec.levelOffsets[level],
76
+ parentBase: spec.levelOffsets[level + 1],
77
+ parentSide,
78
+ parentCells,
79
+ depth: spec.dim === 3 ? 2 : 1,
80
+ pad0: 0,
81
+ pad1: 0,
82
+ pad2: 0,
83
+ });
84
+ levels.push({
85
+ bound: downsample.bind({ pyramid: b.pyramid, P: params.binding }),
86
+ offset: params.offset,
87
+ parentCells,
88
+ });
89
+ }
90
+ this.bound = {
91
+ hubArgs: b.hubArgs,
92
+ centroid: centroid.bind({
93
+ sortedIdx: b.sortedIdx,
94
+ cellStart: b.cellStart,
95
+ pos: b.pos,
96
+ pyramid: b.pyramid,
97
+ hubList: b.hubList,
98
+ hubCounters: b.hubCounters,
99
+ P: b.params,
100
+ }),
101
+ finalize: finalize.bind({ counters: b.hubCounters, args: b.hubArgs, P: finalizeParams.binding }),
102
+ finalizeOffset: finalizeParams.offset,
103
+ hub: hub.bind({
104
+ sortedIdx: b.sortedIdx,
105
+ cellStart: b.cellStart,
106
+ pos: b.pos,
107
+ pyramid: b.pyramid,
108
+ hubList: b.hubList,
109
+ hubCount: b.hubCounters,
110
+ P: b.params,
111
+ }),
112
+ levels,
113
+ };
114
+ }
115
+ /**
116
+ * Records the stages (see the interface).
117
+ * @param pass - the compute pass
118
+ * @param paramsOffset - the `Fa2Params` dynamic offset
119
+ * @param upTo - the last stage
120
+ */
121
+ record(pass, paramsOffset, upTo) {
122
+ const { bound, scope, spec } = this;
123
+ if (bound === null) {
124
+ throw new WebGpuGraphError("E_NOT_LOADED", "gridPyramid: record() before bind()", { argument: "bind" });
125
+ }
126
+ const { centroid, finalize, hub, downsample } = this.kernels;
127
+ const one = { x: 1, y: 1, z: 1, items: 1, stride: null };
128
+ centroid.dispatch(pass, bound.centroid, plan1d(spec.cells + 1, scope.workgroupSize, scope.caps), [paramsOffset]);
129
+ finalize.dispatch(pass, bound.finalize, one, [bound.finalizeOffset]);
130
+ hub.dispatchIndirect(pass, bound.hub, bound.hubArgs, 0, [paramsOffset]);
131
+ this.dispatches = 3;
132
+ if ((upTo ?? "G5") === "G4") {
133
+ return;
134
+ }
135
+ for (const level of bound.levels) {
136
+ downsample.dispatch(pass, level.bound, plan1d(level.parentCells, scope.workgroupSize, scope.caps), [
137
+ level.offset,
138
+ ]);
139
+ this.dispatches += 1;
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=grid-pyramid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-pyramid.js","sourceRoot":"","sources":["../../../src/primitives/grid-pyramid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * The grid build (spec 6 row 12, 7.7 G1-G3; P4-T8): `GridSpec` on the host (PD-9) and the planner that records, into
3
+ * the caller's pass, the cell keys (G1, `grid-cell-key`), the stable sort by key (G2: `radixSort` at GRID_SORT_BITS,
4
+ * or `countingSortByKey` when the caller asks for the set-deterministic path) and the per-cell histogram with its
5
+ * exclusive scan (G3: the `histogram` kernel over `cellKey` and the `scan` of it; DEP-P4-I names no grid-specific
6
+ * id). `cellHist` and `cellStart` hold `cells + 2` words: every real cell, the outside pseudo-cell at index `cells`
7
+ * and one more so `cellStart[cells + 1] === n` closes the last range. Every zeroing is a `fill` dispatch inside the
8
+ * pass (PD-12), never an encoder clear.
9
+ *
10
+ * The named grid buffers (`cellKey`, `cellVal`, `sortedKey`, `sortedIdx`, `cellHist`, `cellStart`) are the caller's
11
+ * (the model's `BufferSpec`s, so `inspect(name)` reaches them); the anonymous scratch of the sort (the digit-major
12
+ * table and its scan, the counting-sort cursor) is taken from the scope ONCE at bind() so the sub-kernels bind the
13
+ * same buffers every iteration and `Kernel.bind`'s identity cache holds (PD-11). `src/primitives/**` never imports
14
+ * `src/context.ts`.
15
+ */
16
+ import { type ResolvedLayoutTuning } from "../types/layout.js";
17
+ import { type Binding } from "../types/memory.js";
18
+ import { type ReduceScope } from "./reduce.js";
19
+ /** The grid's geometry (spec 7.7 geometry table; PD-9), computed on the host once per load. */
20
+ export interface GridSpec {
21
+ /** 2 or 3. */
22
+ readonly dim: 2 | 3;
23
+ /** The finest side `G` per axis: a power of two in [GRID_MIN_SIDE, floorPow2(gridMax)]. */
24
+ readonly g: number;
25
+ /** `log2(G / GRID_COARSEST_SIDE) + 1`. */
26
+ readonly levels: number;
27
+ /** `G^dim` finest cells; the outside pseudo-cell is index `cells`. */
28
+ readonly cells: number;
29
+ /** `cells + 2`: the length of `cellHist` / `cellStart`. */
30
+ readonly histWords: number;
31
+ /** The first cell of every level inside the pyramid: `levelOffsets[0] = 0`, level 0 holds `cells + 1` (the pseudo-cell), level L `(G / 2^L)^dim`. */
32
+ readonly levelOffsets: readonly number[];
33
+ /** Every level's cells together: `levelOffsets[levels - 1] + GRID_COARSEST_SIDE^dim`. */
34
+ readonly pyramidCells: number;
35
+ /** Whether G2 is the stable radix sort (true) or the set-deterministic counting sort (false). */
36
+ readonly deterministic: boolean;
37
+ }
38
+ /**
39
+ * The grid of `n` nodes in `dim` dimensions under the tuning (spec 7.7 geometry table; PD-9): `G = clamp(nextPow2(2 *
40
+ * ceil(n^(1 / dim))), GRID_MIN_SIDE, floorPow2(gridMax))` where `gridMax` is `gridMax2D` or `gridMax3D`, rounded DOWN
41
+ * to a power of two so every level's side is an integer (512 and 128 stay; 100 becomes 64); `levels = log2(G /
42
+ * GRID_COARSEST_SIDE) + 1`. At the caps: 349,521 pyramid cells in 2D, 2,396,737 in 3D (the design's counts plus the
43
+ * pseudo-cell).
44
+ * @param n - the node count (>= 0)
45
+ * @param dim - 2 or 3
46
+ * @param tuning - the resolved layout tuning (`gridMax2D`, `gridMax3D`, `deterministic`)
47
+ * @returns the spec
48
+ */
49
+ export declare function gridSpecFor(n: number, dim: 2 | 3, tuning: Pick<ResolvedLayoutTuning, "gridMax2D" | "gridMax3D" | "deterministic">): GridSpec;
50
+ /**
51
+ * The bytes of the pyramid (spec 7.7: 16 B per cell, every level, the pseudo-cell included): 38,347,792 at the 3D cap.
52
+ * @param spec - the grid
53
+ * @returns the byte length
54
+ */
55
+ export declare function gridPyramidBytes(spec: GridSpec): number;
56
+ /**
57
+ * The buffers the build reads and writes (the model's named buffers; `state` and `params` are the blocks G1 reads).
58
+ * The parameter type of GridBuildPlanner.bind (knip: exported for the signature, not imported by name).
59
+ * @public
60
+ */
61
+ export interface GridBuildBindings {
62
+ /** `array<vec4f>` positions (xyz, mass). */
63
+ readonly pos: Binding;
64
+ /** The `Fa2State` block (`gridMin`, `invCellSize`), read-only here. */
65
+ readonly state: Binding;
66
+ /** The `Fa2Params` uniform ring (`n`, `dim`, `gridMax`); `record()` takes the iteration's dynamic offset. */
67
+ readonly params: Binding;
68
+ /**
69
+ * `n` words: G1's keys, node-indexed until G2. On the deterministic path the radix sort ping-pongs through this
70
+ * pair (PD-5: three passes, the even one writes the input pair), so after G2 `cellKey` / `cellVal` hold the
71
+ * sort's last even-pass intermediate -- a permutation of the keys, which is why the histogram recorded after it
72
+ * counts the same multiset; the node-indexed keys of an iteration are read through `upTo: "G1"`. The counting
73
+ * path never writes them.
74
+ */
75
+ readonly cellKey: Binding;
76
+ /** `n` words: G1's values (`i`); the sort's working pair with `cellKey`. */
77
+ readonly cellVal: Binding;
78
+ /** `n` words: the sorted keys (the radix path's result pair; unused by the counting path). */
79
+ readonly sortedKey: Binding;
80
+ /** `n` words: the sorted node indices. */
81
+ readonly sortedIdx: Binding;
82
+ /** `cells + 2` words: the per-cell counts. */
83
+ readonly cellHist: Binding;
84
+ /** `cells + 2` words: the exclusive scan of `cellHist`. */
85
+ readonly cellStart: Binding;
86
+ }
87
+ /** Where `record()` stops: after the keys (G1), after the sort (G2) or after the histogram and its scan (G3, the default). */
88
+ export type GridBuildStage = "G1" | "G2" | "G3";
89
+ /** A prepared grid build (spec 7.7 G1-G3): binds once per load, records the stages of one iteration into a pass. */
90
+ export interface GridBuildPlanner {
91
+ /**
92
+ * Binds the named buffers and takes the sort's scratch from the scope, sized by `cellKey` (its word count is the
93
+ * node capacity; PD-11); called once per load (a second call rebinds and takes fresh scratch, so it belongs to a
94
+ * reload, never to an iteration).
95
+ * @param bindings - the buffers
96
+ */
97
+ bind(bindings: GridBuildBindings): void;
98
+ /**
99
+ * Records G1, G2 and G3 for `n` nodes at the `Fa2Params` slot `paramsOffset`; `upTo` stops after the named
100
+ * stage (the counting path has no separate G2 stop: its sort and histogram are one sequence, so "G2" runs it all).
101
+ * @param pass - the compute pass
102
+ * @param n - the node count (in [1, the capacity]; the caller never records a grid iteration for an empty graph)
103
+ * @param paramsOffset - the dynamic offset of this iteration's `Fa2Params`
104
+ * @param upTo - the last stage to record (default "G3")
105
+ */
106
+ record(pass: GPUComputePassEncoder, n: number, paramsOffset: number, upTo?: GridBuildStage): void;
107
+ /** Dispatches the last record() issued. */
108
+ readonly lastDispatches: number;
109
+ }
110
+ /**
111
+ * Prepares the grid build's pipelines over a scope (G1 and the sort / histogram / scan planners it composes; compiles
112
+ * once) so bind() and record() are synchronous. The planner lives exactly as long as the scope.
113
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
114
+ * @param spec - the grid
115
+ * @returns the planner
116
+ */
117
+ export declare function prepareGridBuild(scope: ReduceScope, spec: GridSpec): Promise<GridBuildPlanner>;
118
+ //# sourceMappingURL=grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/primitives/grid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAQlD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,+FAA+F;AAC/F,MAAM,WAAW,QAAQ;IACrB,cAAc;IACd,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACpB,2FAA2F;IAC3F,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qJAAqJ;IACrJ,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,yFAAyF;IACzF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iGAAiG;IACjG,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACnC;AA4BD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACvB,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,CAAC,GAAG,CAAC,EACV,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,WAAW,GAAG,eAAe,CAAC,GAChF,QAAQ,CA0BV;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,4CAA4C;IAC5C,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,6GAA6G;IAC7G,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC/B;AAED,8HAA8H;AAC9H,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,oHAAoH;AACpH,MAAM,WAAW,gBAAgB;IAC7B;;;;;OAKG;IACH,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACxC;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,qBAAqB,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAClG,2CAA2C;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AAYD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAWpG"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * The grid build (spec 6 row 12, 7.7 G1-G3; P4-T8): `GridSpec` on the host (PD-9) and the planner that records, into
3
+ * the caller's pass, the cell keys (G1, `grid-cell-key`), the stable sort by key (G2: `radixSort` at GRID_SORT_BITS,
4
+ * or `countingSortByKey` when the caller asks for the set-deterministic path) and the per-cell histogram with its
5
+ * exclusive scan (G3: the `histogram` kernel over `cellKey` and the `scan` of it; DEP-P4-I names no grid-specific
6
+ * id). `cellHist` and `cellStart` hold `cells + 2` words: every real cell, the outside pseudo-cell at index `cells`
7
+ * and one more so `cellStart[cells + 1] === n` closes the last range. Every zeroing is a `fill` dispatch inside the
8
+ * pass (PD-12), never an encoder clear.
9
+ *
10
+ * The named grid buffers (`cellKey`, `cellVal`, `sortedKey`, `sortedIdx`, `cellHist`, `cellStart`) are the caller's
11
+ * (the model's `BufferSpec`s, so `inspect(name)` reaches them); the anonymous scratch of the sort (the digit-major
12
+ * table and its scan, the counting-sort cursor) is taken from the scope ONCE at bind() so the sub-kernels bind the
13
+ * same buffers every iteration and `Kernel.bind`'s identity cache holds (PD-11). `src/primitives/**` never imports
14
+ * `src/context.ts`.
15
+ */
16
+ import { GRID_COARSEST_SIDE, GRID_MIN_SIDE, GRID_SORT_BITS } from "../constants.js";
17
+ import { WebGpuGraphError } from "../errors.js";
18
+ import { plan1d } from "../kernel/dispatch.js";
19
+ import { kernelSpec } from "../kernels.js";
20
+ import { prepareCountingSort, prepareHistogram, } from "./histogram.js";
21
+ import { prepareRadixSort, radixHistBytes } from "./radix-sort.js";
22
+ import { prepareScan } from "./scan.js";
23
+ /**
24
+ * The smallest power of two >= x (by doubling; 1 for x <= 1).
25
+ * @param x - a non-negative number
26
+ * @returns the power of two
27
+ */
28
+ function nextPow2(x) {
29
+ let p = 1;
30
+ while (p < x) {
31
+ p *= 2;
32
+ }
33
+ return p;
34
+ }
35
+ /**
36
+ * The largest power of two <= x (by doubling; 1 for x < 2).
37
+ * @param x - a number >= 1
38
+ * @returns the power of two
39
+ */
40
+ function floorPow2(x) {
41
+ let p = 1;
42
+ while (p * 2 <= x) {
43
+ p *= 2;
44
+ }
45
+ return p;
46
+ }
47
+ /**
48
+ * The grid of `n` nodes in `dim` dimensions under the tuning (spec 7.7 geometry table; PD-9): `G = clamp(nextPow2(2 *
49
+ * ceil(n^(1 / dim))), GRID_MIN_SIDE, floorPow2(gridMax))` where `gridMax` is `gridMax2D` or `gridMax3D`, rounded DOWN
50
+ * to a power of two so every level's side is an integer (512 and 128 stay; 100 becomes 64); `levels = log2(G /
51
+ * GRID_COARSEST_SIDE) + 1`. At the caps: 349,521 pyramid cells in 2D, 2,396,737 in 3D (the design's counts plus the
52
+ * pseudo-cell).
53
+ * @param n - the node count (>= 0)
54
+ * @param dim - 2 or 3
55
+ * @param tuning - the resolved layout tuning (`gridMax2D`, `gridMax3D`, `deterministic`)
56
+ * @returns the spec
57
+ */
58
+ export function gridSpecFor(n, dim, tuning) {
59
+ const gridMax = dim === 3 ? tuning.gridMax3D : tuning.gridMax2D;
60
+ const side = dim === 3 ? Math.cbrt(n) : Math.sqrt(n);
61
+ const cap = Math.max(GRID_MIN_SIDE, floorPow2(Math.max(1, gridMax)));
62
+ const g = Math.min(cap, Math.max(GRID_MIN_SIDE, nextPow2(2 * Math.ceil(side))));
63
+ let levels = 1;
64
+ for (let s = g; s > GRID_COARSEST_SIDE; s /= 2) {
65
+ levels++;
66
+ }
67
+ const cells = g ** dim;
68
+ const levelOffsets = [0];
69
+ let s = g;
70
+ for (let level = 0; level + 1 < levels; level++) {
71
+ levelOffsets.push(levelOffsets[level] + s ** dim + (level === 0 ? 1 : 0));
72
+ s /= 2;
73
+ }
74
+ return {
75
+ dim,
76
+ g,
77
+ levels,
78
+ cells,
79
+ histWords: cells + 2,
80
+ levelOffsets: Object.freeze(levelOffsets),
81
+ pyramidCells: levelOffsets[levels - 1] + GRID_COARSEST_SIDE ** dim,
82
+ deterministic: tuning.deterministic,
83
+ };
84
+ }
85
+ /**
86
+ * The bytes of the pyramid (spec 7.7: 16 B per cell, every level, the pseudo-cell included): 38,347,792 at the 3D cap.
87
+ * @param spec - the grid
88
+ * @returns the byte length
89
+ */
90
+ export function gridPyramidBytes(spec) {
91
+ return 16 * spec.pyramidCells;
92
+ }
93
+ /**
94
+ * Prepares the grid build's pipelines over a scope (G1 and the sort / histogram / scan planners it composes; compiles
95
+ * once) so bind() and record() are synchronous. The planner lives exactly as long as the scope.
96
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
97
+ * @param spec - the grid
98
+ * @returns the planner
99
+ */
100
+ export async function prepareGridBuild(scope, spec) {
101
+ const cellKey = await scope.pipelines.kernel(kernelSpec("grid-cell-key"));
102
+ const path = spec.deterministic
103
+ ? {
104
+ kind: "radix",
105
+ radix: await prepareRadixSort(scope),
106
+ histogram: await prepareHistogram(scope),
107
+ scan: await prepareScan(scope),
108
+ }
109
+ : { kind: "counting", counting: await prepareCountingSort(scope) };
110
+ return new GridBuildPlannerImpl(scope, spec, cellKey, path);
111
+ }
112
+ /** The planner: G1 and the composed sort / histogram / scan over one scope. */
113
+ class GridBuildPlannerImpl {
114
+ /**
115
+ * Wraps the resolved kernel and planners; use prepareGridBuild().
116
+ * @param scope - the caller's scope
117
+ * @param spec - the grid
118
+ * @param cellKey - the `grid-cell-key` kernel
119
+ * @param path - the sort path
120
+ */
121
+ constructor(scope, spec, cellKey, path) {
122
+ this.bound = null;
123
+ this.dispatches = 0;
124
+ this.scope = scope;
125
+ this.spec = spec;
126
+ this.cellKey = cellKey;
127
+ this.path = path;
128
+ }
129
+ /**
130
+ * Dispatches the last record() issued.
131
+ * @returns the count
132
+ */
133
+ get lastDispatches() {
134
+ return this.dispatches;
135
+ }
136
+ /**
137
+ * Binds the buffers and takes the sort's scratch (see the interface).
138
+ * @param bindings - the buffers
139
+ */
140
+ bind(bindings) {
141
+ const capacity = Math.floor(bindings.cellKey.size / 4);
142
+ if (capacity < 1) {
143
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", "gridBuild: cellKey must hold at least one word", {
144
+ argument: "cellKey",
145
+ value: bindings.cellKey.size,
146
+ expected: 4,
147
+ });
148
+ }
149
+ const words = this.path.kind === "radix" ? radixHistBytes(capacity, this.scope.workgroupSize) / 4 : this.spec.histWords;
150
+ this.bound = {
151
+ bindings,
152
+ capacity,
153
+ scratchA: this.scratch(words, "grid/sort-scratch-a"),
154
+ scratchB: this.scratch(words, "grid/sort-scratch-b"),
155
+ };
156
+ }
157
+ /**
158
+ * Records the stages (see the interface).
159
+ * @param pass - the compute pass
160
+ * @param n - the node count
161
+ * @param paramsOffset - the `Fa2Params` dynamic offset
162
+ * @param upTo - the last stage
163
+ */
164
+ record(pass, n, paramsOffset, upTo) {
165
+ const { bound } = this;
166
+ if (bound === null) {
167
+ throw new WebGpuGraphError("E_NOT_LOADED", "gridBuild: record() before bind()", { argument: "bind" });
168
+ }
169
+ if (!Number.isSafeInteger(n) || n < 1 || n > bound.capacity) {
170
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", "gridBuild: n must be an integer in [1, the capacity]", {
171
+ argument: "n",
172
+ value: n,
173
+ expected: bound.capacity,
174
+ });
175
+ }
176
+ const stop = upTo ?? "G3";
177
+ const b = bound.bindings;
178
+ const keyBound = this.cellKey.bind({
179
+ pos: b.pos,
180
+ S: b.state,
181
+ cellKey: b.cellKey,
182
+ cellVal: b.cellVal,
183
+ P: b.params,
184
+ });
185
+ this.cellKey.dispatch(pass, keyBound, plan1d(n, this.scope.workgroupSize, this.scope.caps), [paramsOffset]);
186
+ this.dispatches = 1;
187
+ if (stop === "G1") {
188
+ return;
189
+ }
190
+ const { histWords: bins } = this.spec;
191
+ if (this.path.kind === "counting") {
192
+ const { counting } = this.path;
193
+ const scratch = { hist: b.cellHist, cursor: bound.scratchA };
194
+ counting.record(pass, b.cellKey, n, bins, scratch, b.sortedIdx, b.cellStart);
195
+ this.dispatches += counting.lastDispatches;
196
+ return;
197
+ }
198
+ const { radix, histogram, scan } = this.path;
199
+ radix.record(pass, b.cellKey, b.cellVal, n, GRID_SORT_BITS, {
200
+ keys: b.sortedKey,
201
+ vals: b.sortedIdx,
202
+ hist: bound.scratchA,
203
+ offsets: bound.scratchB,
204
+ });
205
+ this.dispatches += radix.lastDispatches;
206
+ if (stop === "G2") {
207
+ return;
208
+ }
209
+ histogram.record(pass, b.cellKey, n, bins, b.cellHist);
210
+ scan.record(pass, b.cellHist, bins, b.cellStart);
211
+ this.dispatches += histogram.lastDispatches + scan.lastDispatches;
212
+ }
213
+ /**
214
+ * A scratch of `words` u32 from the scope, bound whole.
215
+ * @param words - the word count (>= 1)
216
+ * @param label - the scratch label
217
+ * @returns the binding
218
+ */
219
+ scratch(words, label) {
220
+ const size = 4 * Math.max(1, words);
221
+ const buffer = this.scope.scratch(size, label);
222
+ return { buffer, offset: 0, size, window: null };
223
+ }
224
+ }
225
+ //# sourceMappingURL=grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.js","sourceRoot":"","sources":["../../../src/primitives/grid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The `histogram` and `countingSortByKey` primitive drivers (spec 6 row 5; P4-T3, PD-4). `histogram` zeroes `hist`
3
+ * with a `fill` dispatch and then adds one per key in global memory: order-independent, so bitwise deterministic on
4
+ * every adapter. `countingSortByKey` is the histogram, an exclusive scan of it into `outStart`, a zeroed per-bin
5
+ * `cursor`, and the scatter `outIndex[outStart[k] + atomicAdd(&cursor[k], 1)] = i`: the SET of indices inside a bin
6
+ * is fixed, their order follows the schedule (set-deterministic, design 6). Every zeroing is a dispatch inside the
7
+ * caller's pass (PD-12), never an encoder clear.
8
+ *
9
+ * The drivers own no device objects: the caller supplies a ReduceScope (the same record `reduce` takes) and the
10
+ * compute pass to record into. `src/primitives/**` never imports `src/context.ts`.
11
+ */
12
+ import { type Binding } from "../types/memory.js";
13
+ import { type ReduceScope } from "./reduce.js";
14
+ /** A prepared histogram (spec 6 row 5): records the fill and the one counting dispatch into a pass. */
15
+ export interface HistogramPlanner {
16
+ /**
17
+ * Records the histogram of `count` u32 keys of `keys` over `bins` bins into `hist` (zeroed first by a `fill`
18
+ * dispatch); a key >= bins is not counted. For count 0 only the fill is recorded, so `hist` is all zero.
19
+ * @param pass - the compute pass
20
+ * @param keys - the keys (at least 4 x count bytes)
21
+ * @param count - the key count (a non-negative integer below 2^32)
22
+ * @param bins - the bin count (an integer in [1, 2^32))
23
+ * @param hist - the counts (at least 4 x bins bytes)
24
+ */
25
+ record(pass: GPUComputePassEncoder, keys: Binding, count: number, bins: number, hist: Binding): void;
26
+ /** Dispatches the last record() issued: 1 (the fill) for count 0, else 2. */
27
+ readonly lastDispatches: number;
28
+ }
29
+ /** The two per-bin scratch arrays of a counting sort: the histogram and the scatter cursor, each at least 4 x bins bytes. */
30
+ interface CountingSortScratch {
31
+ readonly hist: Binding;
32
+ readonly cursor: Binding;
33
+ }
34
+ /** A prepared counting sort by key (spec 6 row 5): records the histogram, the scan, the cursor fill and the scatter into a pass. */
35
+ export interface CountingSortPlanner {
36
+ /**
37
+ * Records the counting sort of `count` keys of `keys` (every key < bins) into `outIndex` (the indices in key
38
+ * order; the order inside a bin follows the schedule) and `outStart` (the exclusive scan of the histogram, so bin
39
+ * k holds `outIndex[outStart[k] .. outStart[k + 1])` when outStart has bins + 1 words, as the grid's does).
40
+ * For count 0 the two fills and the scan run and `outStart` is all zero.
41
+ * @param pass - the compute pass
42
+ * @param keys - the keys (at least 4 x count bytes)
43
+ * @param count - the key count (a non-negative integer below 2^32)
44
+ * @param bins - the bin count (an integer in [1, 2^32))
45
+ * @param scratch - the per-bin histogram and cursor (each at least 4 x bins bytes)
46
+ * @param outIndex - the sorted indices (at least 4 x count bytes)
47
+ * @param outStart - the bin starts (at least 4 x bins bytes)
48
+ */
49
+ record(pass: GPUComputePassEncoder, keys: Binding, count: number, bins: number, scratch: CountingSortScratch, outIndex: Binding, outStart: Binding): void;
50
+ /** Dispatches the last record() issued: the histogram's + the scan's + 1 (the cursor fill) + 1 (the scatter, count > 0 only). */
51
+ readonly lastDispatches: number;
52
+ }
53
+ /**
54
+ * Prepares the histogram pipelines of a scope (compiles `histogram` and `fill` once) so record() is synchronous.
55
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
56
+ * @returns the planner
57
+ */
58
+ export declare function prepareHistogram(scope: ReduceScope): Promise<HistogramPlanner>;
59
+ /**
60
+ * Prepares the counting-sort pipelines of a scope (the histogram's, the scan's and `counting-scatter`) so record()
61
+ * is synchronous. The planner lives exactly as long as the scope (the scan keeps a scratch word of it).
62
+ * @param scope - the caller's scope
63
+ * @returns the planner
64
+ */
65
+ export declare function prepareCountingSort(scope: ReduceScope): Promise<CountingSortPlanner>;
66
+ export {};
67
+ //# sourceMappingURL=histogram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"histogram.d.ts","sourceRoot":"","sources":["../../../src/primitives/histogram.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,uGAAuG;AACvG,MAAM,WAAW,gBAAgB;IAC7B;;;;;;;;OAQG;IACH,MAAM,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IACrG,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AAED,6HAA6H;AAC7H,UAAU,mBAAmB;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC5B;AAED,oIAAoI;AACpI,MAAM,WAAW,mBAAmB;IAChC;;;;;;;;;;;;OAYG;IACH,MAAM,CACF,IAAI,EAAE,qBAAqB,EAC3B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,OAAO,GAClB,IAAI,CAAC;IACR,iIAAiI;IACjI,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AAKD;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEpF;AAaD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAK1F"}