@graphty/webgpu-graph-algorithms 0.0.0 → 0.2.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 (269) hide show
  1. package/README.md +344 -23
  2. package/dist/browser.d.ts +1 -0
  3. package/dist/browser.js +32 -0
  4. package/dist/browser.js.map +1 -0
  5. package/dist/chunks/context-E6iKaeuJ.js +3136 -0
  6. package/dist/chunks/context-E6iKaeuJ.js.map +1 -0
  7. package/dist/node.d.ts +1 -0
  8. package/dist/node.js +131 -0
  9. package/dist/node.js.map +1 -0
  10. package/dist/src/accelerator.d.ts +26 -0
  11. package/dist/src/accelerator.d.ts.map +1 -0
  12. package/dist/src/accelerator.js +101 -0
  13. package/dist/src/accelerator.js.map +1 -0
  14. package/dist/src/algorithms/degree.d.ts +35 -0
  15. package/dist/src/algorithms/degree.d.ts.map +1 -0
  16. package/dist/src/algorithms/degree.js +119 -0
  17. package/dist/src/algorithms/degree.js.map +1 -0
  18. package/dist/src/browser/index.d.ts +23 -0
  19. package/dist/src/browser/index.d.ts.map +1 -0
  20. package/dist/src/browser/index.js +48 -0
  21. package/dist/src/browser/index.js.map +1 -0
  22. package/dist/src/constants.d.ts +92 -0
  23. package/dist/src/constants.d.ts.map +1 -0
  24. package/dist/src/constants.js +92 -0
  25. package/dist/src/constants.js.map +1 -0
  26. package/dist/src/context.d.ts +84 -0
  27. package/dist/src/context.d.ts.map +1 -0
  28. package/dist/src/context.js +304 -0
  29. package/dist/src/context.js.map +1 -0
  30. package/dist/src/device/acquire.d.ts +57 -0
  31. package/dist/src/device/acquire.d.ts.map +1 -0
  32. package/dist/src/device/acquire.js +232 -0
  33. package/dist/src/device/acquire.js.map +1 -0
  34. package/dist/src/device/caps.d.ts +43 -0
  35. package/dist/src/device/caps.d.ts.map +1 -0
  36. package/dist/src/device/caps.js +104 -0
  37. package/dist/src/device/caps.js.map +1 -0
  38. package/dist/src/device/error-scope.d.ts +75 -0
  39. package/dist/src/device/error-scope.d.ts.map +1 -0
  40. package/dist/src/device/error-scope.js +152 -0
  41. package/dist/src/device/error-scope.js.map +1 -0
  42. package/dist/src/device/lost.d.ts +51 -0
  43. package/dist/src/device/lost.d.ts.map +1 -0
  44. package/dist/src/device/lost.js +130 -0
  45. package/dist/src/device/lost.js.map +1 -0
  46. package/dist/src/device/webgpu-constants.d.ts +31 -0
  47. package/dist/src/device/webgpu-constants.d.ts.map +1 -0
  48. package/dist/src/device/webgpu-constants.js +31 -0
  49. package/dist/src/device/webgpu-constants.js.map +1 -0
  50. package/dist/src/errors.d.ts +56 -0
  51. package/dist/src/errors.d.ts.map +1 -0
  52. package/dist/src/errors.js +57 -0
  53. package/dist/src/errors.js.map +1 -0
  54. package/dist/src/index.d.ts +29 -0
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +27 -0
  57. package/dist/src/index.js.map +1 -0
  58. package/dist/src/kernel/batch.d.ts +116 -0
  59. package/dist/src/kernel/batch.d.ts.map +1 -0
  60. package/dist/src/kernel/batch.js +335 -0
  61. package/dist/src/kernel/batch.js.map +1 -0
  62. package/dist/src/kernel/dispatch.d.ts +59 -0
  63. package/dist/src/kernel/dispatch.d.ts.map +1 -0
  64. package/dist/src/kernel/dispatch.js +139 -0
  65. package/dist/src/kernel/dispatch.js.map +1 -0
  66. package/dist/src/kernel/kernel.d.ts +84 -0
  67. package/dist/src/kernel/kernel.d.ts.map +1 -0
  68. package/dist/src/kernel/kernel.js +239 -0
  69. package/dist/src/kernel/kernel.js.map +1 -0
  70. package/dist/src/kernel/pipeline-cache.d.ts +90 -0
  71. package/dist/src/kernel/pipeline-cache.d.ts.map +1 -0
  72. package/dist/src/kernel/pipeline-cache.js +251 -0
  73. package/dist/src/kernel/pipeline-cache.js.map +1 -0
  74. package/dist/src/kernel/prelude.d.ts +35 -0
  75. package/dist/src/kernel/prelude.d.ts.map +1 -0
  76. package/dist/src/kernel/prelude.js +211 -0
  77. package/dist/src/kernel/prelude.js.map +1 -0
  78. package/dist/src/kernel/profiler.d.ts +64 -0
  79. package/dist/src/kernel/profiler.d.ts.map +1 -0
  80. package/dist/src/kernel/profiler.js +120 -0
  81. package/dist/src/kernel/profiler.js.map +1 -0
  82. package/dist/src/kernel/struct-block.d.ts +122 -0
  83. package/dist/src/kernel/struct-block.d.ts.map +1 -0
  84. package/dist/src/kernel/struct-block.js +353 -0
  85. package/dist/src/kernel/struct-block.js.map +1 -0
  86. package/dist/src/kernel/uniform-ring.d.ts +70 -0
  87. package/dist/src/kernel/uniform-ring.d.ts.map +1 -0
  88. package/dist/src/kernel/uniform-ring.js +146 -0
  89. package/dist/src/kernel/uniform-ring.js.map +1 -0
  90. package/dist/src/kernel/wgsl.d.ts +88 -0
  91. package/dist/src/kernel/wgsl.d.ts.map +1 -0
  92. package/dist/src/kernel/wgsl.js +390 -0
  93. package/dist/src/kernel/wgsl.js.map +1 -0
  94. package/dist/src/kernels.d.ts +81 -0
  95. package/dist/src/kernels.d.ts.map +1 -0
  96. package/dist/src/kernels.js +417 -0
  97. package/dist/src/kernels.js.map +1 -0
  98. package/dist/src/layouts/force-simulation.d.ts +498 -0
  99. package/dist/src/layouts/force-simulation.d.ts.map +1 -0
  100. package/dist/src/layouts/force-simulation.js +1650 -0
  101. package/dist/src/layouts/force-simulation.js.map +1 -0
  102. package/dist/src/layouts/forceatlas2.d.ts +210 -0
  103. package/dist/src/layouts/forceatlas2.d.ts.map +1 -0
  104. package/dist/src/layouts/forceatlas2.js +759 -0
  105. package/dist/src/layouts/forceatlas2.js.map +1 -0
  106. package/dist/src/layouts/inputs.d.ts +40 -0
  107. package/dist/src/layouts/inputs.d.ts.map +1 -0
  108. package/dist/src/layouts/inputs.js +185 -0
  109. package/dist/src/layouts/inputs.js.map +1 -0
  110. package/dist/src/layouts/repulsion-exact.d.ts +85 -0
  111. package/dist/src/layouts/repulsion-exact.d.ts.map +1 -0
  112. package/dist/src/layouts/repulsion-exact.js +134 -0
  113. package/dist/src/layouts/repulsion-exact.js.map +1 -0
  114. package/dist/src/layouts/seed.d.ts +56 -0
  115. package/dist/src/layouts/seed.d.ts.map +1 -0
  116. package/dist/src/layouts/seed.js +173 -0
  117. package/dist/src/layouts/seed.js.map +1 -0
  118. package/dist/src/memory/buffer-pool.d.ts +73 -0
  119. package/dist/src/memory/buffer-pool.d.ts.map +1 -0
  120. package/dist/src/memory/buffer-pool.js +170 -0
  121. package/dist/src/memory/buffer-pool.js.map +1 -0
  122. package/dist/src/memory/lease.d.ts +53 -0
  123. package/dist/src/memory/lease.d.ts.map +1 -0
  124. package/dist/src/memory/lease.js +85 -0
  125. package/dist/src/memory/lease.js.map +1 -0
  126. package/dist/src/memory/readback.d.ts +143 -0
  127. package/dist/src/memory/readback.d.ts.map +1 -0
  128. package/dist/src/memory/readback.js +375 -0
  129. package/dist/src/memory/readback.js.map +1 -0
  130. package/dist/src/memory/residency.d.ts +83 -0
  131. package/dist/src/memory/residency.d.ts.map +1 -0
  132. package/dist/src/memory/residency.js +573 -0
  133. package/dist/src/memory/residency.js.map +1 -0
  134. package/dist/src/memory/upload-plan.d.ts +101 -0
  135. package/dist/src/memory/upload-plan.d.ts.map +1 -0
  136. package/dist/src/memory/upload-plan.js +265 -0
  137. package/dist/src/memory/upload-plan.js.map +1 -0
  138. package/dist/src/node/index.d.ts +64 -0
  139. package/dist/src/node/index.d.ts.map +1 -0
  140. package/dist/src/node/index.js +183 -0
  141. package/dist/src/node/index.js.map +1 -0
  142. package/dist/src/primitives/reduce.d.ts +57 -0
  143. package/dist/src/primitives/reduce.d.ts.map +1 -0
  144. package/dist/src/primitives/reduce.js +161 -0
  145. package/dist/src/primitives/reduce.js.map +1 -0
  146. package/dist/src/primitives/segmented-reduce.d.ts +38 -0
  147. package/dist/src/primitives/segmented-reduce.d.ts.map +1 -0
  148. package/dist/src/primitives/segmented-reduce.js +211 -0
  149. package/dist/src/primitives/segmented-reduce.js.map +1 -0
  150. package/dist/src/types/accelerator.d.ts +209 -0
  151. package/dist/src/types/accelerator.d.ts.map +1 -0
  152. package/dist/src/types/accelerator.js +8 -0
  153. package/dist/src/types/accelerator.js.map +1 -0
  154. package/dist/src/types/context.d.ts +114 -0
  155. package/dist/src/types/context.d.ts.map +1 -0
  156. package/dist/src/types/context.js +7 -0
  157. package/dist/src/types/context.js.map +1 -0
  158. package/dist/src/types/layout.d.ts +95 -0
  159. package/dist/src/types/layout.d.ts.map +1 -0
  160. package/dist/src/types/layout.js +6 -0
  161. package/dist/src/types/layout.js.map +1 -0
  162. package/dist/src/types/memory.d.ts +22 -0
  163. package/dist/src/types/memory.d.ts.map +1 -0
  164. package/dist/src/types/memory.js +7 -0
  165. package/dist/src/types/memory.js.map +1 -0
  166. package/dist/src/types/options.d.ts +78 -0
  167. package/dist/src/types/options.d.ts.map +1 -0
  168. package/dist/src/types/options.js +7 -0
  169. package/dist/src/types/options.js.map +1 -0
  170. package/dist/src/types/run.d.ts +13 -0
  171. package/dist/src/types/run.d.ts.map +1 -0
  172. package/dist/src/types/run.js +6 -0
  173. package/dist/src/types/run.js.map +1 -0
  174. package/dist/src/wgsl/degree.wgsl.d.ts +10 -0
  175. package/dist/src/wgsl/degree.wgsl.d.ts.map +1 -0
  176. package/dist/src/wgsl/degree.wgsl.js +25 -0
  177. package/dist/src/wgsl/degree.wgsl.js.map +1 -0
  178. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +12 -0
  179. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -0
  180. package/dist/src/wgsl/fa2-attraction.wgsl.js +37 -0
  181. package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -0
  182. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts +13 -0
  183. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts.map +1 -0
  184. package/dist/src/wgsl/fa2-integrate.wgsl.js +69 -0
  185. package/dist/src/wgsl/fa2-integrate.wgsl.js.map +1 -0
  186. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +12 -0
  187. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -0
  188. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +79 -0
  189. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -0
  190. package/dist/src/wgsl/fa2-speed-finalize.wgsl.d.ts +15 -0
  191. package/dist/src/wgsl/fa2-speed-finalize.wgsl.d.ts.map +1 -0
  192. package/dist/src/wgsl/fa2-speed-finalize.wgsl.js +54 -0
  193. package/dist/src/wgsl/fa2-speed-finalize.wgsl.js.map +1 -0
  194. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +14 -0
  195. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -0
  196. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +57 -0
  197. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -0
  198. package/dist/src/wgsl/fa2-to-scene.wgsl.d.ts +11 -0
  199. package/dist/src/wgsl/fa2-to-scene.wgsl.d.ts.map +1 -0
  200. package/dist/src/wgsl/fa2-to-scene.wgsl.js +19 -0
  201. package/dist/src/wgsl/fa2-to-scene.wgsl.js.map +1 -0
  202. package/dist/src/wgsl/fill.wgsl.d.ts +7 -0
  203. package/dist/src/wgsl/fill.wgsl.d.ts.map +1 -0
  204. package/dist/src/wgsl/fill.wgsl.js +14 -0
  205. package/dist/src/wgsl/fill.wgsl.js.map +1 -0
  206. package/dist/src/wgsl/reduce.wgsl.d.ts +10 -0
  207. package/dist/src/wgsl/reduce.wgsl.d.ts.map +1 -0
  208. package/dist/src/wgsl/reduce.wgsl.js +63 -0
  209. package/dist/src/wgsl/reduce.wgsl.js.map +1 -0
  210. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +13 -0
  211. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -0
  212. package/dist/src/wgsl/segmented-reduce.wgsl.js +35 -0
  213. package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -0
  214. package/dist/tsconfig.build.tsbuildinfo +1 -0
  215. package/dist/webgpu-graph-algorithms.d.ts +1 -0
  216. package/dist/webgpu-graph-algorithms.js +4454 -0
  217. package/dist/webgpu-graph-algorithms.js.map +1 -0
  218. package/package.json +108 -17
  219. package/src/accelerator.ts +117 -0
  220. package/src/algorithms/degree.ts +142 -0
  221. package/src/browser/index.ts +57 -0
  222. package/src/constants.ts +116 -0
  223. package/src/context.ts +399 -0
  224. package/src/device/acquire.ts +256 -0
  225. package/src/device/caps.ts +122 -0
  226. package/src/device/error-scope.ts +171 -0
  227. package/src/device/lost.ts +142 -0
  228. package/src/device/webgpu-constants.ts +44 -0
  229. package/src/errors.ts +94 -0
  230. package/src/index.ts +102 -0
  231. package/src/kernel/batch.ts +427 -0
  232. package/src/kernel/dispatch.ts +162 -0
  233. package/src/kernel/kernel.ts +311 -0
  234. package/src/kernel/pipeline-cache.ts +288 -0
  235. package/src/kernel/prelude.ts +229 -0
  236. package/src/kernel/profiler.ts +148 -0
  237. package/src/kernel/struct-block.ts +439 -0
  238. package/src/kernel/uniform-ring.ts +184 -0
  239. package/src/kernel/wgsl.ts +490 -0
  240. package/src/kernels.ts +511 -0
  241. package/src/layouts/force-simulation.ts +2111 -0
  242. package/src/layouts/forceatlas2.ts +942 -0
  243. package/src/layouts/inputs.ts +252 -0
  244. package/src/layouts/repulsion-exact.ts +183 -0
  245. package/src/layouts/seed.ts +198 -0
  246. package/src/memory/buffer-pool.ts +204 -0
  247. package/src/memory/lease.ts +93 -0
  248. package/src/memory/readback.ts +429 -0
  249. package/src/memory/residency.ts +753 -0
  250. package/src/memory/upload-plan.ts +350 -0
  251. package/src/node/index.ts +230 -0
  252. package/src/primitives/reduce.ts +233 -0
  253. package/src/primitives/segmented-reduce.ts +270 -0
  254. package/src/types/accelerator.ts +236 -0
  255. package/src/types/context.ts +135 -0
  256. package/src/types/layout.ts +103 -0
  257. package/src/types/memory.ts +23 -0
  258. package/src/types/options.ts +84 -0
  259. package/src/types/run.ts +13 -0
  260. package/src/wgsl/degree.wgsl.ts +24 -0
  261. package/src/wgsl/fa2-attraction.wgsl.ts +37 -0
  262. package/src/wgsl/fa2-integrate.wgsl.ts +69 -0
  263. package/src/wgsl/fa2-repulsion-exact.wgsl.ts +78 -0
  264. package/src/wgsl/fa2-speed-finalize.wgsl.ts +53 -0
  265. package/src/wgsl/fa2-stats-finalize.wgsl.ts +57 -0
  266. package/src/wgsl/fa2-to-scene.wgsl.ts +19 -0
  267. package/src/wgsl/fill.wgsl.ts +13 -0
  268. package/src/wgsl/reduce.wgsl.ts +62 -0
  269. package/src/wgsl/segmented-reduce.wgsl.ts +35 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The `reduce` primitive driver (spec 6 row 1): sum / min / max over f32, u32 or vec4f elements in two or three
3
+ * dispatches of the `reduce` module (3.10.1). Level 1 folds WG elements per workgroup into per-workgroup partials
4
+ * (the prelude's tree helpers, 4.3); a third level folds the partials again when the level-1 grid needed a 2D
5
+ * dispatch (more than MAX_WORKGROUPS_PER_DIM workgroups, i.e. more than MAX_1D_ITEMS elements); the FINAL level --
6
+ * ONE workgroup whose lanes walk the remaining partials sequentially in index order -- writes one element
7
+ * (4 or 16 bytes) at out[outOffset]. Every level reduces in a fixed order, so two runs are bitwise identical on one
8
+ * device (spec 11.9 item 4); the subgroup twin (4.3) agrees to summation-order noise on f32 and bitwise on u32.
9
+ * `count === 0` records level 1 over an empty plan (Kernel.dispatch records nothing, spec 5.6) and the FINAL level
10
+ * over 0 partials, which writes the identity element.
11
+ *
12
+ * The driver owns no device objects: the caller supplies a ReduceScope (P1: the tests build one over a GpuContext and
13
+ * release its scratch in a finally; P2: CommandBatch supplies the same record with a Lease) and the compute pass to
14
+ * record into. `src/primitives/**` never imports `src/context.ts` (the eslint zone of 2.4).
15
+ */
16
+ import { type PipelineCache } from "../kernel/pipeline-cache.js";
17
+ import { type UniformBlock, type UniformValues } from "../kernel/struct-block.js";
18
+ import { type BufferPool } from "../memory/buffer-pool.js";
19
+ import { type PlanCaps } from "../types/context.js";
20
+ import { type Binding } from "../types/memory.js";
21
+ /** The reduction operator (4.5 OP override: sum, min, max). */
22
+ export type ReduceOp = "sum" | "min" | "max";
23
+ /** The element type (4.5 DTYPE override: f32, u32, or vec4f lanes of f32). */
24
+ export type ReduceDtype = "f32" | "u32" | "vec4f";
25
+ /** What reduce() needs of its caller: a pass to record into, scratch, the ring and the cache (P1 has no CommandBatch yet; P2's batch supplies the same record). */
26
+ export interface ReduceScope {
27
+ readonly device: GPUDevice;
28
+ readonly caps: PlanCaps;
29
+ readonly pipelines: PipelineCache;
30
+ readonly pool: BufferPool;
31
+ readonly workgroupSize: number;
32
+ /** Acquires scratch released by the caller's scope (a Lease from P2; P1 releases in a finally). */
33
+ scratch(byteLength: number, label: string): GPUBuffer;
34
+ /** The uniform-slot writer: returns the binding and dynamic offset for a params record. */
35
+ params(block: UniformBlock, values: UniformValues): {
36
+ readonly binding: Binding;
37
+ readonly offset: number;
38
+ };
39
+ }
40
+ /** A prepared reduce: records the 2-3 dispatches of spec 6 row 1 into a pass. */
41
+ export interface ReducePlanner {
42
+ readonly op: ReduceOp;
43
+ readonly dtype: ReduceDtype;
44
+ /** Records: level 1 over `count` elements of `src` into partials; a third level when groups > MAX_WORKGROUPS_PER_DIM; the FINAL one-workgroup level writing one element (4 or 16 bytes) at out[outOffset] (element index). Deterministic order. count 0 writes the identity element. */
45
+ record(pass: GPUComputePassEncoder, src: Binding, count: number, out: Binding, outOffset: number): void;
46
+ /** Dispatches the last record() issued (tests bound it: 2 or 3). */
47
+ readonly lastDispatches: number;
48
+ }
49
+ /**
50
+ * Prepares the reduce pipelines of a scope (compiles once) so record() is synchronous.
51
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
52
+ * @param op - the operator
53
+ * @param dtype - the element type
54
+ * @returns the planner, with the level and FINAL pipelines resolved
55
+ */
56
+ export declare function prepareReduce(scope: ReduceScope, op: ReduceOp, dtype: ReduceDtype): Promise<ReducePlanner>;
57
+ //# sourceMappingURL=reduce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduce.d.ts","sourceRoot":"","sources":["../../../src/primitives/reduce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAElF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,+DAA+D;AAC/D,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAC7C,8EAA8E;AAC9E,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;AAElD,mKAAmK;AACnK,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,mGAAmG;IACnG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACtD,2FAA2F;IAC3F,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,GAAG;QAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9G;AAED,iFAAiF;AACjF,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,wRAAwR;IACxR,MAAM,CAAC,IAAI,EAAE,qBAAqB,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACxG,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AASD;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAKhH"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * The `reduce` primitive driver (spec 6 row 1): sum / min / max over f32, u32 or vec4f elements in two or three
3
+ * dispatches of the `reduce` module (3.10.1). Level 1 folds WG elements per workgroup into per-workgroup partials
4
+ * (the prelude's tree helpers, 4.3); a third level folds the partials again when the level-1 grid needed a 2D
5
+ * dispatch (more than MAX_WORKGROUPS_PER_DIM workgroups, i.e. more than MAX_1D_ITEMS elements); the FINAL level --
6
+ * ONE workgroup whose lanes walk the remaining partials sequentially in index order -- writes one element
7
+ * (4 or 16 bytes) at out[outOffset]. Every level reduces in a fixed order, so two runs are bitwise identical on one
8
+ * device (spec 11.9 item 4); the subgroup twin (4.3) agrees to summation-order noise on f32 and bitwise on u32.
9
+ * `count === 0` records level 1 over an empty plan (Kernel.dispatch records nothing, spec 5.6) and the FINAL level
10
+ * over 0 partials, which writes the identity element.
11
+ *
12
+ * The driver owns no device objects: the caller supplies a ReduceScope (P1: the tests build one over a GpuContext and
13
+ * release its scratch in a finally; P2: CommandBatch supplies the same record with a Lease) and the compute pass to
14
+ * record into. `src/primitives/**` never imports `src/context.ts` (the eslint zone of 2.4).
15
+ */
16
+ import { MAX_WORKGROUPS_PER_DIM } from "../constants.js";
17
+ import { WebGpuGraphError } from "../errors.js";
18
+ import { groupsOf, plan1d } from "../kernel/dispatch.js";
19
+ import { kernelSpec, REDUCE_PARAMS } from "../kernels.js";
20
+ /** The OP override values of the reduce module (4.5: 0 = sum, 1 = min, 2 = max). */
21
+ const OP_CODE = Object.freeze({ sum: 0, min: 1, max: 2 });
22
+ /** The DTYPE override values (4.5: 0 = f32, 1 = u32, 2 = vec4f). */
23
+ const DTYPE_CODE = Object.freeze({ f32: 0, u32: 1, vec4f: 2 });
24
+ /** Bytes of one element per dtype. */
25
+ const ELEMENT_BYTES = Object.freeze({ f32: 4, u32: 4, vec4f: 16 });
26
+ /**
27
+ * Prepares the reduce pipelines of a scope (compiles once) so record() is synchronous.
28
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
29
+ * @param op - the operator
30
+ * @param dtype - the element type
31
+ * @returns the planner, with the level and FINAL pipelines resolved
32
+ */
33
+ export async function prepareReduce(scope, op, dtype) {
34
+ const overrides = { OP: OP_CODE[op], DTYPE: DTYPE_CODE[dtype] };
35
+ const level = await scope.pipelines.kernel(kernelSpec("reduce", { ...overrides, FINAL: false }));
36
+ const final = await scope.pipelines.kernel(kernelSpec("reduce", { ...overrides, FINAL: true }));
37
+ return new ReducePlannerImpl(scope, op, dtype, level, final);
38
+ }
39
+ /**
40
+ * The argument checks of record() (E_INVALID_ARGUMENT before anything is recorded).
41
+ * @param src - the input binding
42
+ * @param count - the element count
43
+ * @param out - the output binding
44
+ * @param outOffset - the output element index
45
+ * @param elementBytes - bytes per element of the planner's dtype
46
+ */
47
+ function checkRecordArguments(src, count, out, outOffset, elementBytes) {
48
+ if (!Number.isSafeInteger(count) || count < 0) {
49
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", "reduce: count must be a non-negative integer", {
50
+ argument: "count",
51
+ value: count,
52
+ });
53
+ }
54
+ if (!Number.isSafeInteger(outOffset) || outOffset < 0) {
55
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", "reduce: outOffset must be a non-negative integer", {
56
+ argument: "outOffset",
57
+ value: outOffset,
58
+ });
59
+ }
60
+ if (src.size < count * elementBytes) {
61
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", "reduce: src is smaller than count x element size", {
62
+ argument: "src",
63
+ value: src.size,
64
+ expected: count * elementBytes,
65
+ });
66
+ }
67
+ if (out.size < (outOffset + 1) * elementBytes) {
68
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", "reduce: out cannot hold the element at outOffset", {
69
+ argument: "out",
70
+ value: out.size,
71
+ expected: (outOffset + 1) * elementBytes,
72
+ });
73
+ }
74
+ }
75
+ /** The planner: two resolved kernels (FINAL false / true) over one scope. */
76
+ class ReducePlannerImpl {
77
+ /**
78
+ * Wraps the resolved kernels; use prepareReduce().
79
+ * @param scope - the caller's scope
80
+ * @param op - the operator
81
+ * @param dtype - the element type
82
+ * @param level - the per-workgroup level pipeline (FINAL = false)
83
+ * @param final - the one-workgroup pipeline (FINAL = true)
84
+ */
85
+ constructor(scope, op, dtype, level, final) {
86
+ this.dispatches = 0;
87
+ this.scope = scope;
88
+ this.op = op;
89
+ this.dtype = dtype;
90
+ this.level = level;
91
+ this.final = final;
92
+ }
93
+ /**
94
+ * Dispatches the last record() issued (2, or 3 above MAX_1D_ITEMS elements).
95
+ * @returns the count
96
+ */
97
+ get lastDispatches() {
98
+ return this.dispatches;
99
+ }
100
+ /**
101
+ * Records the levels into the pass (see the interface).
102
+ * @param pass - the compute pass
103
+ * @param src - the elements (count x element bytes at least)
104
+ * @param count - the element count
105
+ * @param out - the output range
106
+ * @param outOffset - the element index written
107
+ */
108
+ record(pass, src, count, out, outOffset) {
109
+ const elementBytes = ELEMENT_BYTES[this.dtype];
110
+ checkRecordArguments(src, count, out, outOffset, elementBytes);
111
+ const { scope } = this;
112
+ const wg = scope.workgroupSize;
113
+ let dispatches = 0;
114
+ const plan1 = plan1d(count, wg, scope.caps);
115
+ const groups1 = groupsOf(plan1);
116
+ let partials = this.partialsBinding(Math.max(groups1, 1), "reduce/partials-1");
117
+ this.dispatchLevel(pass, this.level, src, count, partials, 0, plan1, 1);
118
+ dispatches += 1;
119
+ let partialCount = groups1;
120
+ if (groups1 > MAX_WORKGROUPS_PER_DIM) {
121
+ const plan2 = plan1d(groups1, wg, scope.caps);
122
+ const groups2 = groupsOf(plan2);
123
+ const partials2 = this.partialsBinding(groups2, "reduce/partials-2");
124
+ this.dispatchLevel(pass, this.level, partials, groups1, partials2, 0, plan2, 2);
125
+ dispatches += 1;
126
+ partials = partials2;
127
+ partialCount = groups2;
128
+ }
129
+ this.dispatchLevel(pass, this.final, partials, partialCount, out, outOffset, plan1d(1, wg, scope.caps), dispatches + 1);
130
+ dispatches += 1;
131
+ this.dispatches = dispatches;
132
+ }
133
+ /**
134
+ * A partials scratch of `elements` elements from the scope, bound whole (never zero-length).
135
+ * @param elements - the partial count (>= 1)
136
+ * @param label - the scratch label
137
+ * @returns the binding
138
+ */
139
+ partialsBinding(elements, label) {
140
+ const size = elements * ELEMENT_BYTES[this.dtype];
141
+ const buffer = this.scope.scratch(size, label);
142
+ return { buffer, offset: 0, size, window: null };
143
+ }
144
+ /**
145
+ * One level: a params record, the bind groups, one dispatch.
146
+ * @param pass - the compute pass
147
+ * @param kernel - the level or FINAL kernel
148
+ * @param src - the elements of this level
149
+ * @param count - how many
150
+ * @param out - where the partials (or the result) go
151
+ * @param outOffset - the element index (0 for partials)
152
+ * @param plan - the dispatch plan
153
+ * @param level - the level number written into the params (informational)
154
+ */
155
+ dispatchLevel(pass, kernel, src, count, out, outOffset, plan, level) {
156
+ const params = this.scope.params(REDUCE_PARAMS, { count, outOffset, level });
157
+ const bound = kernel.bind({ src, out, P: params.binding });
158
+ kernel.dispatch(pass, bound, plan, [params.offset]);
159
+ }
160
+ }
161
+ //# sourceMappingURL=reduce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduce.js","sourceRoot":"","sources":["../../../src/primitives/reduce.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The segmented (per-row) reduction primitive of spec 6 row 3 in its thread-per-row tier (P2-P3): one invocation per
3
+ * CSR row folds the caller's VALUE snippet over the row's arcs into `out[row]` (f32), a row with no arcs receiving
4
+ * the identity element. The degree tiers of degreeOrder() (subgroup-per-row for the mid tier, workgroup-per-row for
5
+ * the high tier) land at P4; until then `tiers !== null` is E_UNSUPPORTED and USE_PERM is always false (the perm
6
+ * slot carries the rowPtr dummy of graphBindings). The row and arc counts come from the core's binding sizes: the
7
+ * residency binds every array at its exact byte length (contract 3.8), so rowPtr is 4(n + 1) bytes and colIdx
8
+ * 4 x arcCount.
9
+ */
10
+ import { type CoreBinding } from "../memory/residency.js";
11
+ import { type Binding } from "../types/memory.js";
12
+ import { type ReduceOp, type ReduceScope } from "./reduce.js";
13
+ /** The degree tiers of degreeOrder(): the permutation binding and the CPU-side segmentOffsets [0, hiEnd, midEnd, lowEnd, n]. */
14
+ export interface DegreeTiers {
15
+ readonly perm: Binding;
16
+ readonly segmentOffsets: readonly [number, number, number, number, number];
17
+ }
18
+ /** Options of segmentedReduce. `valueSnippet` is the Gunrock-style functor: WGSL statements assigning `v` from (row, arc, nbr, weight) (4.5; `nbr` because `target` is a WGSL reserved word). */
19
+ export interface SegmentedReduceOptions {
20
+ readonly op: ReduceOp;
21
+ readonly valueSnippet: string;
22
+ readonly tiers: DegreeTiers | null;
23
+ readonly accumulate?: boolean | undefined;
24
+ }
25
+ /** A prepared segmented reduce (P2-P3: the thread-per-row tier only; `tiers !== null` -> E_UNSUPPORTED { feature: "segmentedReduce.tiers" } until P4). */
26
+ export interface SegmentedReducePlanner {
27
+ /** Records one dispatch over rows [0, n) (tiers null) writing out[i] (f32) per row; a row with no arcs gets the identity element. */
28
+ record(pass: GPUComputePassEncoder, core: CoreBinding, out: Binding): void;
29
+ }
30
+ /**
31
+ * Prepares the thread-per-row pipeline for a snapshot's dummy pattern (USE_PERM, HAS_WEIGHTS) and snippet.
32
+ * @param scope - the reduce scope (pipelines, pool, params writer)
33
+ * @param core - the core whose weights pattern selects HAS_WEIGHTS (USE_PERM is false: no tiers at P2)
34
+ * @param options - operator, snippet, tiers (must be null), accumulate
35
+ * @returns the planner
36
+ */
37
+ export declare function prepareSegmentedReduce(scope: ReduceScope, core: CoreBinding, options: SegmentedReduceOptions): Promise<SegmentedReducePlanner>;
38
+ //# sourceMappingURL=segmented-reduce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segmented-reduce.d.ts","sourceRoot":"","sources":["../../../src/primitives/segmented-reduce.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE9D,gIAAgI;AAChI,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9E;AAED,iMAAiM;AACjM,MAAM,WAAW,sBAAsB;IACnC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7C;AAED,0JAA0J;AAC1J,MAAM,WAAW,sBAAsB;IACnC,qIAAqI;IACrI,MAAM,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9E;AAiND;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CACxC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,sBAAsB,GAChC,OAAO,CAAC,sBAAsB,CAAC,CAajC"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * The segmented (per-row) reduction primitive of spec 6 row 3 in its thread-per-row tier (P2-P3): one invocation per
3
+ * CSR row folds the caller's VALUE snippet over the row's arcs into `out[row]` (f32), a row with no arcs receiving
4
+ * the identity element. The degree tiers of degreeOrder() (subgroup-per-row for the mid tier, workgroup-per-row for
5
+ * the high tier) land at P4; until then `tiers !== null` is E_UNSUPPORTED and USE_PERM is always false (the perm
6
+ * slot carries the rowPtr dummy of graphBindings). The row and arc counts come from the core's binding sizes: the
7
+ * residency binds every array at its exact byte length (contract 3.8), so rowPtr is 4(n + 1) bytes and colIdx
8
+ * 4 x arcCount.
9
+ */
10
+ import { WebGpuGraphError } from "../errors.js";
11
+ import { plan1d } from "../kernel/dispatch.js";
12
+ import { graphBindings, graphOverrides, kernelSpec, RANGE_PARAMS } from "../kernels.js";
13
+ /** The identifiers a VALUE snippet may name (contract 3.11, 4.5); every other identifier is rejected textually before compose. */
14
+ const VALUE_SNIPPET_VOCABULARY = new Set(["row", "arc", "nbr", "weight", "v"]);
15
+ /**
16
+ * The WGSL words a snippet statement may use that are not identifiers: the statement keywords (never the flow
17
+ * keywords `return` / `break` / `continue`, which would leave the fold), the scalar type constructors and the
18
+ * builtin math functions a value expression may call (a bounded list; a binding, a uniform or a module function such
19
+ * as `identity` / `comb` / `linear_id` is NOT in it and is rejected as an identifier).
20
+ */
21
+ const VALUE_SNIPPET_WGSL_WORDS = new Set([
22
+ "if",
23
+ "else",
24
+ "let",
25
+ "var",
26
+ "const",
27
+ "true",
28
+ "false",
29
+ "f32",
30
+ "u32",
31
+ "i32",
32
+ "bool",
33
+ "abs",
34
+ "ceil",
35
+ "clamp",
36
+ "exp",
37
+ "exp2",
38
+ "floor",
39
+ "fract",
40
+ "inverseSqrt",
41
+ "log",
42
+ "log2",
43
+ "max",
44
+ "min",
45
+ "mix",
46
+ "pow",
47
+ "round",
48
+ "select",
49
+ "sign",
50
+ "sqrt",
51
+ "step",
52
+ "trunc",
53
+ ]);
54
+ /**
55
+ * The OP override value of an operator (the body's `OP == 1u` / `OP == 2u` tests, contract 4.5).
56
+ * @param op - the operator
57
+ * @returns 0 for sum, 1 for min, 2 for max
58
+ */
59
+ function opCode(op) {
60
+ switch (op) {
61
+ case "sum":
62
+ return 0;
63
+ case "min":
64
+ return 1;
65
+ case "max":
66
+ return 2;
67
+ default:
68
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", `segmentedReduce: unknown op ${String(op)}`, {
69
+ argument: "op",
70
+ value: op,
71
+ expected: "sum | min | max",
72
+ });
73
+ }
74
+ }
75
+ /**
76
+ * WGSL comments removed (a comment may mention `target` or any other word).
77
+ * @param text - WGSL text
78
+ * @returns the text with block and line comments replaced by spaces
79
+ */
80
+ function stripComments(text) {
81
+ return text.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/\/\/[^\n]*/g, " ");
82
+ }
83
+ /**
84
+ * The textual vocabulary check of contract 3.11: the snippet must assign `v` (`=`, `+=`, `-=`, `*=` or `/=`) and its
85
+ * identifiers may be only row, arc, nbr, weight and v; numeric literals and the WGSL words of
86
+ * VALUE_SNIPPET_WGSL_WORDS are not identifiers and pass; anything else -- a binding, a uniform, a module function,
87
+ * a locally declared name, a flow keyword, a reserved word such as `target` -- is E_SHADER_COMPILE { stage:
88
+ * "compose", slot: "VALUE", identifier } on every device, before any shader is created.
89
+ * @param snippet - the VALUE snippet text
90
+ */
91
+ function validateValueSnippet(snippet) {
92
+ const code = stripComments(snippet);
93
+ if (!/\bv\s*[-+*/]?=(?!=)/.test(code)) {
94
+ throw new WebGpuGraphError("E_SHADER_COMPILE", "segmentedReduce: the VALUE snippet never assigns v", {
95
+ id: "segmented-reduce",
96
+ stage: "compose",
97
+ slot: "VALUE",
98
+ });
99
+ }
100
+ const tokens = code.match(/[A-Za-z_][A-Za-z0-9_]*|[0-9][0-9A-Za-z_.]*/g) ?? [];
101
+ for (const token of tokens) {
102
+ if (/^[0-9]/.test(token) || VALUE_SNIPPET_VOCABULARY.has(token) || VALUE_SNIPPET_WGSL_WORDS.has(token)) {
103
+ continue;
104
+ }
105
+ throw new WebGpuGraphError("E_SHADER_COMPILE", `segmentedReduce: the VALUE snippet names "${token}"; the only identifiers allowed are row, arc, nbr, weight and v`, { id: "segmented-reduce", stage: "compose", slot: "VALUE", identifier: token });
106
+ }
107
+ }
108
+ /**
109
+ * The row count of a core from its rowPtr binding (4(n + 1) bytes).
110
+ * @param core - the core
111
+ * @returns n
112
+ */
113
+ function rowCountOf(core) {
114
+ const bytes = core.rowPtr.size;
115
+ if (bytes < 4 || bytes % 4 !== 0) {
116
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", `segmentedReduce: a rowPtr binding of ${bytes} bytes is not 4(n + 1)`, {
117
+ argument: "core.rowPtr",
118
+ value: bytes,
119
+ expected: "a positive multiple of 4",
120
+ });
121
+ }
122
+ return bytes / 4 - 1;
123
+ }
124
+ /**
125
+ * Rejects a windowed core (executed at P4).
126
+ * @param core - the core
127
+ */
128
+ function assertNotWindowed(core) {
129
+ if (core.plan === "windowed" || core.windows !== null) {
130
+ throw new WebGpuGraphError("E_UNSUPPORTED", "segmentedReduce: windowed cores are executed at P4", {
131
+ feature: "segmentedReduce.windowed",
132
+ });
133
+ }
134
+ }
135
+ /** The thread-per-row planner: ONE `segmented-reduce` dispatch with TIER 0 over every row. */
136
+ class ThreadPerRowPlanner {
137
+ /**
138
+ * Wraps a compiled thread-per-row pipeline with the pattern it was compiled for.
139
+ * @param scope - the scope the pipeline was prepared in
140
+ * @param kernel - the compiled kernel
141
+ * @param hasWeights - the HAS_WEIGHTS the pipeline was compiled with
142
+ * @param accumulate - whether record() combines into out instead of overwriting
143
+ */
144
+ constructor(scope, kernel, hasWeights, accumulate) {
145
+ this.scope = scope;
146
+ this.kernel = kernel;
147
+ this.hasWeights = hasWeights;
148
+ this.accumulate = accumulate;
149
+ }
150
+ /**
151
+ * Records the dispatch: rows [0, n), arcs [0, arcCount), plan1d(n); nothing for n = 0 (no zero-length binding is
152
+ * ever created).
153
+ * @param pass - the pass to record into
154
+ * @param core - a core with the SAME weights pattern as the one prepared (any snapshot)
155
+ * @param out - at least 4n bytes of f32
156
+ */
157
+ record(pass, core, out) {
158
+ assertNotWindowed(core);
159
+ if ((core.weights !== null) !== this.hasWeights) {
160
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", "segmentedReduce: the core's weights pattern differs from the one prepared", {
161
+ argument: "core",
162
+ value: core.weights !== null,
163
+ expected: this.hasWeights,
164
+ });
165
+ }
166
+ const n = rowCountOf(core);
167
+ if (n === 0) {
168
+ return;
169
+ }
170
+ const arcCount = core.colIdx === null ? 0 : core.colIdx.size / 4;
171
+ if (out.size < 4 * n) {
172
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", `segmentedReduce: out holds ${out.size} bytes, ${4 * n} needed`, {
173
+ argument: "out",
174
+ value: out.size,
175
+ expected: `>= ${4 * n}`,
176
+ });
177
+ }
178
+ const params = this.scope.params(RANGE_PARAMS, {
179
+ start: 0,
180
+ end: n,
181
+ arcBase: 0,
182
+ arcEnd: arcCount,
183
+ accumulate: this.accumulate ? 1 : 0,
184
+ n,
185
+ });
186
+ const bound = this.kernel.bind({ ...graphBindings(core, null), out, P: params.binding });
187
+ this.kernel.dispatch(pass, bound, plan1d(n, this.scope.workgroupSize, this.scope.caps), [params.offset]);
188
+ }
189
+ }
190
+ /**
191
+ * Prepares the thread-per-row pipeline for a snapshot's dummy pattern (USE_PERM, HAS_WEIGHTS) and snippet.
192
+ * @param scope - the reduce scope (pipelines, pool, params writer)
193
+ * @param core - the core whose weights pattern selects HAS_WEIGHTS (USE_PERM is false: no tiers at P2)
194
+ * @param options - operator, snippet, tiers (must be null), accumulate
195
+ * @returns the planner
196
+ */
197
+ export async function prepareSegmentedReduce(scope, core, options) {
198
+ if (options.tiers !== null) {
199
+ throw new WebGpuGraphError("E_UNSUPPORTED", "segmentedReduce: the degree tiers land at P4; pass tiers: null", {
200
+ feature: "segmentedReduce.tiers",
201
+ });
202
+ }
203
+ assertNotWindowed(core);
204
+ const op = opCode(options.op);
205
+ validateValueSnippet(options.valueSnippet);
206
+ const overrides = { ...graphOverrides(core, null), OP: op, TIER: 0 };
207
+ const spec = kernelSpec("segmented-reduce", overrides, { VALUE: options.valueSnippet });
208
+ const kernel = await scope.pipelines.kernel(spec);
209
+ return new ThreadPerRowPlanner(scope, kernel, core.weights !== null, options.accumulate === true);
210
+ }
211
+ //# sourceMappingURL=segmented-reduce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segmented-reduce.js","sourceRoot":"","sources":["../../../src/primitives/segmented-reduce.ts"],"names":[],"mappings":"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"}