@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
@@ -1,27 +1,38 @@
1
1
  /**
2
- * The `segmented-reduce` kernel body (spec 6 row 3; contract 4.5), TIER 0 = thread-per-row: one invocation per row
3
- * of [P.start, P.end) folds the VALUE snippet over the row's arcs inside the bound window [P.arcBase, P.arcEnd) and
4
- * writes out[i] as f32; a row with no arcs gets the identity element (0 for sum, F32_MAX for min, -F32_MAX for
5
- * max). The mid / high degree tiers (TIER 1 / 2 over degreeOrder()) land at P4. The body is normative: a sabotage
6
- * mutation (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.
2
+ * The `segmented-reduce` kernel body (spec 6 row 3; contract 4.5) in its three degree tiers (P4-T5, PD-6). Every
3
+ * tier folds the VALUE snippet over a row's arcs inside the bound window [P.arcBase, P.arcEnd) and writes out[i]
4
+ * as f32 (a row with no arcs gets the identity element: 0 for sum, F32_MAX for min, -F32_MAX for max); the row is
5
+ * `perm[row]` under USE_PERM and `row` otherwise, over the rows [P.start, P.end) of the dispatch. TIER 0 is one row
6
+ * per thread (no barrier, so its early return is legal); TIER 1 is 32 lanes per row and WG / 32 rows per workgroup,
7
+ * reduced by a five-step tree in workgroup memory (bitwise the same on every subgroup size); TIER 2 is one row per
8
+ * workgroup through `wg_reduce_f32` of the prelude (the subgroup variant when the feature exists, the workgroup twin
9
+ * otherwise -- hence `needs: ["subgroups"]`). The tier bodies are functions called under `if (TIER == 0u)`, an
10
+ * override, so every barrier is reached in uniform control flow. The body is normative: a sabotage mutation
11
+ * (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.
12
+ *
13
+ * TIER 0 folds its row through `row_fold_dense`, a stride-one copy of `row_fold`, because the shader compiler emits
14
+ * `row_fold(i, 0u, 1u)` as a call and leaves the stride in a parameter: the loop then walks the row with a runtime
15
+ * step, which costs the strength-reduced addressing into colIdx / weights and the unrolling that keeps several loads
16
+ * in flight per thread. PageRank's out-weight pass, the only caller that passes no tiers today, runs TIER 0 alone,
17
+ * and under the tiers TIER 0 still folds the low-degree rows, which are most of them. The two folds spell their
18
+ * locals apart (`lo` / `hi` / `k` against `a0` / `a1`) so that each sabotage row names exactly one of them; the
19
+ * VALUE snippet sees the same `row`, `arc`, `nbr` and `weight` in both.
7
20
  */
8
21
  /**
9
- * Entry point `segmented_reduce`; overrides OP (0 sum, 1 min, 2 max) and TIER (0); snippet slot VALUE: statements
10
- * assigning `v` from `row`, `arc`, `nbr`, `weight` (`target` is a WGSL reserved word, hence `nbr`).
22
+ * Entry point `segmented_reduce`; overrides OP (0 sum, 1 min, 2 max) and TIER (0 thread-per-row, 1 32-lanes-per-row,
23
+ * 2 workgroup-per-row); snippet slot VALUE: statements assigning `v` from `row`, `arc`, `nbr`, `weight` (`target`
24
+ * is a WGSL reserved word, hence `nbr`).
11
25
  */
12
26
  export const segmentedReduceWgsl = /* wgsl */ `
13
27
  fn identity() -> f32 { if (OP == 1u) { return F32_MAX; } if (OP == 2u) { return -F32_MAX; } return 0.0; }
14
28
  fn comb(a: f32, b: f32) -> f32 { if (OP == 1u) { return min(a, b); } if (OP == 2u) { return max(a, b); } return a + b; }
15
-
16
- @compute @workgroup_size(WG)
17
- fn segmented_reduce(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
18
- let row = linear_id(wid, lid.x) + P.start;
19
- if (row >= P.end) { return; }
20
- let i = select(row, perm[row], USE_PERM);
29
+ fn row_node(row: u32) -> u32 { return select(row, perm[row], USE_PERM); }
30
+ fn row_fold(i: u32, lane: u32, step: u32) -> f32 { // the arcs of row i this lane walks inside the bound window [P.arcBase, P.arcEnd)
31
+ let row = i; // the CSR row the VALUE snippet may name (the node index, under USE_PERM too)
21
32
  let a0 = max(rowPtr[i], P.arcBase);
22
33
  let a1 = min(rowPtr[i + 1u], P.arcEnd);
23
34
  var acc = identity();
24
- for (var arc = a0; arc < a1; arc = arc + 1u) {
35
+ for (var arc = a0 + lane; arc < a1; arc = arc + step) {
25
36
  let nbr = colIdx[arc - P.arcBase]; // the neighbour index (\`target\` is a WGSL reserved word)
26
37
  var weight = 1.0;
27
38
  if (HAS_WEIGHTS) { weight = weights[arc - P.arcBase]; }
@@ -29,7 +40,65 @@ fn segmented_reduce(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invoca
29
40
  //@@VALUE@@
30
41
  acc = comb(acc, v);
31
42
  }
32
- out[i] = select(acc, comb(out[i], acc), P.accumulate == 1u);
43
+ return acc;
44
+ }
45
+ fn row_fold_dense(i: u32) -> f32 { // TIER 0's stride-one twin of row_fold (see the header)
46
+ let row = i; // the CSR row the VALUE snippet may name (as in row_fold)
47
+ let lo = max(rowPtr[i], P.arcBase);
48
+ let hi = min(rowPtr[i + 1u], P.arcEnd);
49
+ var acc = identity();
50
+ for (var arc = lo; arc < hi; arc = arc + 1u) {
51
+ let k = arc - P.arcBase; // the window-local index; this walk is contiguous
52
+ let nbr = colIdx[k];
53
+ var weight = 1.0;
54
+ if (HAS_WEIGHTS) { weight = weights[k]; }
55
+ var v = 0.0;
56
+ //@@VALUE@@
57
+ acc = comb(acc, v);
58
+ }
59
+ return acc;
60
+ }
61
+ fn finish(i: u32, acc: f32) { out[i] = select(acc, comb(out[i], acc), P.accumulate == 1u); }
62
+ fn tier0(wid: vec3<u32>, lane: u32) { // TIER 0: one row per thread over [P.start, P.end); no barrier, so the early return is legal (3.5 rule 1)
63
+ let row = linear_id(wid, lane) + P.start;
64
+ if (row >= P.end) { return; }
65
+ let i = row_node(row);
66
+ finish(i, row_fold_dense(i));
67
+ }
68
+
69
+ var<workgroup> sh: array<f32, WG>;
70
+
71
+ fn tiered(wid: vec3<u32>, lid: u32) { // TIER 1: 32 lanes per row, WG / 32 rows per workgroup; TIER 2: WG lanes per row (PD-6)
72
+ let g = group_id(wid);
73
+ var row = P.start + g;
74
+ var lane = lid;
75
+ var step = WG;
76
+ if (TIER == 1u) { row = P.start + g * (WG / 32u) + lid / 32u; lane = lid % 32u; step = 32u; }
77
+ let valid = row < P.end;
78
+ var i = 0u;
79
+ var acc = identity();
80
+ if (valid) { i = row_node(row); acc = row_fold(i, lane, step); }
81
+ if (TIER == 1u) {
82
+ sh[lid] = acc;
83
+ workgroupBarrier();
84
+ for (var s = 16u; s >= 1u; s = s / 2u) { // the five-step tree over each 32-lane group; every lane runs every step
85
+ var t = identity();
86
+ if (lane < s) { t = sh[lid + s]; }
87
+ workgroupBarrier();
88
+ sh[lid] = comb(sh[lid], t);
89
+ workgroupBarrier();
90
+ }
91
+ if (valid && lane == 0u) { finish(i, sh[lid]); }
92
+ }
93
+ if (TIER == 2u) {
94
+ let t = wg_reduce_f32(acc, lid, OP); // the workgroup tree of the prelude (subgroup variant when available)
95
+ if (valid && lid == 0u) { finish(i, t); }
96
+ }
97
+ }
98
+
99
+ @compute @workgroup_size(WG)
100
+ fn segmented_reduce(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
101
+ if (TIER == 0u) { tier0(wid, lid.x); } else { tiered(wid, lid.x); }
33
102
  }
34
103
  `;
35
104
  //# sourceMappingURL=segmented-reduce.wgsl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"segmented-reduce.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/segmented-reduce.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsB7C,CAAC"}
1
+ {"version":3,"file":"segmented-reduce.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/segmented-reduce.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6E7C,CAAC"}
@@ -1,15 +1,26 @@
1
1
  /**
2
- * The `spmv-pull` kernel body (spec 6 row 9, 8.2; PD-1 of the M8b plan): one invocation per row of the REVERSE
3
- * adjacency, grid-stride over `[0, P.n)`, folding `weight * xNorm[nbr]` over the row's in-arcs in chunks of 64
4
- * terms (a two-level f32 sum: the chunk absorbs the rounding of 64 terms, the row total the rounding of the chunk
5
- * count, so a 10,000-arc hub row loses about 200 rounding steps instead of 10,000; Kahan compensation is not used
6
- * because Metal's shader compiler folds `((acc + term) - acc) - term` to zero whatever hides it) and writing
2
+ * The `spmv-pull` kernel body (spec 6 row 9, 8.2; PD-1 of the M8b plan) in its three in-degree tiers (P4-T5, PD-6):
3
+ * every tier folds `weight * xNorm[nbr]` over a row's in-arcs of the REVERSE adjacency in chunks of 64 terms (a
4
+ * two-level f32 sum: the chunk absorbs the rounding of 64 terms, the row total the rounding of the chunk count, so a
5
+ * 10,000-arc hub row loses about 200 rounding steps instead of 10,000; Kahan compensation is not used because
6
+ * Metal's shader compiler folds `((acc + term) - acc) - term` to zero whatever hides it) and writes
7
7
  * `rankOut[v] = beta * pv + alpha * (sum + danglingMass * pv)`, where `pv` is `personalization[v]` when
8
- * HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise. PageRank sets alpha to the
9
- * damping factor, beta to `1 - alpha` and USE_DANGLING; HITS and eigenvector set alpha 1, beta 0, uniformP 0; Katz
10
- * sets alpha to the attenuation, beta to its constant and uniformP 1. The body is normative: a sabotage mutation
11
- * (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.
8
+ * HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise. The rows are [P.start, P.n) of the dispatch, `perm[row]`
9
+ * under USE_PERM: TIER 0 is grid-stride over them (one row per thread, `P.stride` from planGridStride); TIER 1 is 32
10
+ * lanes per row and WG / 32 rows per workgroup with a five-step tree in workgroup memory (each lane keeps its own
11
+ * 64-term chunking); TIER 2 is one row per workgroup through `wg_reduce_f32` (hence `needs: ["subgroups"]`). PageRank
12
+ * sets alpha to the damping factor, beta to `1 - alpha` and USE_DANGLING; HITS and eigenvector set alpha 1, beta 0,
13
+ * uniformP 0; Katz sets alpha to the attenuation, beta to its constant and uniformP 1. The body is normative: a
14
+ * sabotage mutation (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.
15
+ *
16
+ * TIER 0 folds its row through `row_sum_dense`, a stride-one copy of `row_sum`, because the shader compiler emits
17
+ * `row_sum(v, 0u, 1u)` as a call and leaves the stride in a parameter: the loop then walks the row with a runtime
18
+ * step, which costs the strength-reduced addressing into colIdx / weights and the unrolling that keeps several loads
19
+ * in flight per thread. PageRank and every other caller that passes no in-degree tiers runs TIER 0 alone, and under
20
+ * the tiers it still folds the low-degree rows, which are most of them; the shared fold cost 38 per cent more GPU
21
+ * time at 100k nodes and 1M arcs on an RTX 4070 SUPER and about twice the time on a Tesla T4. The two folds spell
22
+ * their locals apart (`lo` / `hi` / `k` against `a0` / `a1`) so that each sabotage row names exactly one of them.
12
23
  */
13
- /** Entry point `spmv_pull`; overrides HAS_PERSONALIZATION and USE_DANGLING plus the standard USE_PERM / HAS_WEIGHTS. */
14
- export declare const spmvPullWgsl = "\n@compute @workgroup_size(WG)\nfn spmv_pull(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n var dangling = 0.0;\n if (USE_DANGLING) { dangling = partials[0].danglingMass; }\n let first = linear_id(wid, lid.x);\n for (var row = first; row < P.n; row = row + P.stride) {\n let v = select(row, perm[row], USE_PERM);\n let a0 = max(rowPtr[v], P.arcBase);\n let a1 = min(rowPtr[v + 1u], P.arcEnd);\n var acc = 0.0;\n var chunk = 0.0;\n var inChunk = 0u;\n for (var arc = a0; arc < a1; arc = arc + 1u) {\n let nbr = colIdx[arc - P.arcBase]; // `target` is a WGSL reserved word (spec 16.2)\n var weight = 1.0;\n if (HAS_WEIGHTS) { weight = weights[arc - P.arcBase]; }\n // two-level sum: 64 terms into chunk, chunk into acc (see the header; no compensation, no select)\n chunk = chunk + (weight * xNorm[nbr]);\n inChunk = inChunk + 1u;\n if (inChunk == 64u) {\n acc = acc + chunk;\n chunk = 0.0;\n inChunk = 0u;\n }\n }\n acc = acc + chunk;\n var pv = P.uniformP;\n if (HAS_PERSONALIZATION) { pv = personalization[v]; }\n rankOut[v] = (P.beta * pv) + (P.alpha * (acc + (dangling * pv)));\n }\n}\n";
24
+ /** Entry point `spmv_pull`; overrides HAS_PERSONALIZATION, USE_DANGLING and TIER (0 / 1 / 2) plus the standard USE_PERM / HAS_WEIGHTS. */
25
+ export declare const spmvPullWgsl = "\nfn row_node(row: u32) -> u32 { return select(row, perm[row], USE_PERM); }\nfn row_sum(v: u32, lane: u32, step: u32) -> f32 { // this lane's arcs of row v inside the bound window, the two-level 64-term fold of the header\n let a0 = max(rowPtr[v], P.arcBase);\n let a1 = min(rowPtr[v + 1u], P.arcEnd);\n var acc = 0.0;\n var chunk = 0.0;\n var inChunk = 0u;\n for (var arc = a0 + lane; arc < a1; arc = arc + step) {\n let nbr = colIdx[arc - P.arcBase]; // `target` is a WGSL reserved word (spec 16.2)\n var weight = 1.0;\n if (HAS_WEIGHTS) { weight = weights[arc - P.arcBase]; }\n // two-level sum: 64 terms into chunk, chunk into acc (see the header; no compensation, no select)\n chunk = chunk + (weight * xNorm[nbr]);\n inChunk = inChunk + 1u;\n if (inChunk == 64u) {\n acc = acc + chunk;\n chunk = 0.0;\n inChunk = 0u;\n }\n }\n acc = acc + chunk;\n return acc;\n}\nfn row_sum_dense(v: u32) -> f32 { // TIER 0's stride-one twin of row_sum (see the header)\n let lo = max(rowPtr[v], P.arcBase);\n let hi = min(rowPtr[v + 1u], P.arcEnd);\n var acc = 0.0;\n var chunk = 0.0;\n var inChunk = 0u;\n for (var arc = lo; arc < hi; arc = arc + 1u) {\n let k = arc - P.arcBase; // the window-local index; this walk is contiguous\n let nbr = colIdx[k]; // `target` is a WGSL reserved word (spec 16.2)\n var weight = 1.0;\n if (HAS_WEIGHTS) { weight = weights[k]; }\n // two-level sum: 64 terms into chunk, chunk into acc (see the header; no compensation, no select)\n chunk = chunk + (weight * xNorm[nbr]);\n inChunk = inChunk + 1u;\n if (inChunk == 64u) {\n acc = acc + chunk;\n chunk = 0.0;\n inChunk = 0u;\n }\n }\n acc = acc + chunk;\n return acc;\n}\nfn finish(v: u32, acc: f32) {\n var dangling = 0.0;\n if (USE_DANGLING) { dangling = partials[0].danglingMass; }\n var pv = P.uniformP;\n if (HAS_PERSONALIZATION) { pv = personalization[v]; }\n rankOut[v] = (P.beta * pv) + (P.alpha * (acc + (dangling * pv)));\n}\nfn tier0(wid: vec3<u32>, lane: u32) { // TIER 0: grid-stride over the rows [P.start, P.n); no barrier\n for (var row = linear_id(wid, lane) + P.start; row < P.n; row = row + P.stride) {\n let v = row_node(row);\n finish(v, row_sum_dense(v));\n }\n}\n\nvar<workgroup> sh: array<f32, WG>;\n\nfn tiered(wid: vec3<u32>, lid: u32) { // TIER 1: 32 lanes per row; TIER 2: WG lanes per row; rows [P.start, P.n) (PD-6)\n let g = group_id(wid);\n var row = P.start + g;\n var lane = lid;\n var step = WG;\n if (TIER == 1u) { row = P.start + g * (WG / 32u) + lid / 32u; lane = lid % 32u; step = 32u; }\n let valid = row < P.n;\n var v = 0u;\n var acc = 0.0;\n if (valid) { v = row_node(row); acc = row_sum(v, lane, step); }\n if (TIER == 1u) {\n sh[lid] = acc;\n workgroupBarrier();\n for (var s = 16u; s >= 1u; s = s / 2u) { // the five-step tree over each 32-lane group; every lane runs every step\n var t = 0.0;\n if (lane < s) { t = sh[lid + s]; }\n workgroupBarrier();\n sh[lid] = sh[lid] + t;\n workgroupBarrier();\n }\n if (valid && lane == 0u) { finish(v, sh[lid]); }\n }\n if (TIER == 2u) {\n let t = wg_reduce_f32(acc, lid, 0u);\n if (valid && lid == 0u) { finish(v, t); }\n }\n}\n\n@compute @workgroup_size(WG)\nfn spmv_pull(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n if (TIER == 0u) { tier0(wid, lid.x); } else { tiered(wid, lid.x); }\n}\n";
15
26
  //# sourceMappingURL=spmv-pull.wgsl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spmv-pull.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/spmv-pull.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wHAAwH;AACxH,eAAO,MAAM,YAAY,s2CAgCxB,CAAC"}
1
+ {"version":3,"file":"spmv-pull.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/spmv-pull.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,0IAA0I;AAC1I,eAAO,MAAM,YAAY,i0HA+FxB,CAAC"}
@@ -1,47 +1,121 @@
1
1
  /**
2
- * The `spmv-pull` kernel body (spec 6 row 9, 8.2; PD-1 of the M8b plan): one invocation per row of the REVERSE
3
- * adjacency, grid-stride over `[0, P.n)`, folding `weight * xNorm[nbr]` over the row's in-arcs in chunks of 64
4
- * terms (a two-level f32 sum: the chunk absorbs the rounding of 64 terms, the row total the rounding of the chunk
5
- * count, so a 10,000-arc hub row loses about 200 rounding steps instead of 10,000; Kahan compensation is not used
6
- * because Metal's shader compiler folds `((acc + term) - acc) - term` to zero whatever hides it) and writing
2
+ * The `spmv-pull` kernel body (spec 6 row 9, 8.2; PD-1 of the M8b plan) in its three in-degree tiers (P4-T5, PD-6):
3
+ * every tier folds `weight * xNorm[nbr]` over a row's in-arcs of the REVERSE adjacency in chunks of 64 terms (a
4
+ * two-level f32 sum: the chunk absorbs the rounding of 64 terms, the row total the rounding of the chunk count, so a
5
+ * 10,000-arc hub row loses about 200 rounding steps instead of 10,000; Kahan compensation is not used because
6
+ * Metal's shader compiler folds `((acc + term) - acc) - term` to zero whatever hides it) and writes
7
7
  * `rankOut[v] = beta * pv + alpha * (sum + danglingMass * pv)`, where `pv` is `personalization[v]` when
8
- * HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise. PageRank sets alpha to the
9
- * damping factor, beta to `1 - alpha` and USE_DANGLING; HITS and eigenvector set alpha 1, beta 0, uniformP 0; Katz
10
- * sets alpha to the attenuation, beta to its constant and uniformP 1. The body is normative: a sabotage mutation
11
- * (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.
8
+ * HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise. The rows are [P.start, P.n) of the dispatch, `perm[row]`
9
+ * under USE_PERM: TIER 0 is grid-stride over them (one row per thread, `P.stride` from planGridStride); TIER 1 is 32
10
+ * lanes per row and WG / 32 rows per workgroup with a five-step tree in workgroup memory (each lane keeps its own
11
+ * 64-term chunking); TIER 2 is one row per workgroup through `wg_reduce_f32` (hence `needs: ["subgroups"]`). PageRank
12
+ * sets alpha to the damping factor, beta to `1 - alpha` and USE_DANGLING; HITS and eigenvector set alpha 1, beta 0,
13
+ * uniformP 0; Katz sets alpha to the attenuation, beta to its constant and uniformP 1. The body is normative: a
14
+ * sabotage mutation (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.
15
+ *
16
+ * TIER 0 folds its row through `row_sum_dense`, a stride-one copy of `row_sum`, because the shader compiler emits
17
+ * `row_sum(v, 0u, 1u)` as a call and leaves the stride in a parameter: the loop then walks the row with a runtime
18
+ * step, which costs the strength-reduced addressing into colIdx / weights and the unrolling that keeps several loads
19
+ * in flight per thread. PageRank and every other caller that passes no in-degree tiers runs TIER 0 alone, and under
20
+ * the tiers it still folds the low-degree rows, which are most of them; the shared fold cost 38 per cent more GPU
21
+ * time at 100k nodes and 1M arcs on an RTX 4070 SUPER and about twice the time on a Tesla T4. The two folds spell
22
+ * their locals apart (`lo` / `hi` / `k` against `a0` / `a1`) so that each sabotage row names exactly one of them.
12
23
  */
13
- /** Entry point `spmv_pull`; overrides HAS_PERSONALIZATION and USE_DANGLING plus the standard USE_PERM / HAS_WEIGHTS. */
24
+ /** Entry point `spmv_pull`; overrides HAS_PERSONALIZATION, USE_DANGLING and TIER (0 / 1 / 2) plus the standard USE_PERM / HAS_WEIGHTS. */
14
25
  export const spmvPullWgsl = /* wgsl */ `
15
- @compute @workgroup_size(WG)
16
- fn spmv_pull(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
26
+ fn row_node(row: u32) -> u32 { return select(row, perm[row], USE_PERM); }
27
+ fn row_sum(v: u32, lane: u32, step: u32) -> f32 { // this lane's arcs of row v inside the bound window, the two-level 64-term fold of the header
28
+ let a0 = max(rowPtr[v], P.arcBase);
29
+ let a1 = min(rowPtr[v + 1u], P.arcEnd);
30
+ var acc = 0.0;
31
+ var chunk = 0.0;
32
+ var inChunk = 0u;
33
+ for (var arc = a0 + lane; arc < a1; arc = arc + step) {
34
+ let nbr = colIdx[arc - P.arcBase]; // \`target\` is a WGSL reserved word (spec 16.2)
35
+ var weight = 1.0;
36
+ if (HAS_WEIGHTS) { weight = weights[arc - P.arcBase]; }
37
+ // two-level sum: 64 terms into chunk, chunk into acc (see the header; no compensation, no select)
38
+ chunk = chunk + (weight * xNorm[nbr]);
39
+ inChunk = inChunk + 1u;
40
+ if (inChunk == 64u) {
41
+ acc = acc + chunk;
42
+ chunk = 0.0;
43
+ inChunk = 0u;
44
+ }
45
+ }
46
+ acc = acc + chunk;
47
+ return acc;
48
+ }
49
+ fn row_sum_dense(v: u32) -> f32 { // TIER 0's stride-one twin of row_sum (see the header)
50
+ let lo = max(rowPtr[v], P.arcBase);
51
+ let hi = min(rowPtr[v + 1u], P.arcEnd);
52
+ var acc = 0.0;
53
+ var chunk = 0.0;
54
+ var inChunk = 0u;
55
+ for (var arc = lo; arc < hi; arc = arc + 1u) {
56
+ let k = arc - P.arcBase; // the window-local index; this walk is contiguous
57
+ let nbr = colIdx[k]; // \`target\` is a WGSL reserved word (spec 16.2)
58
+ var weight = 1.0;
59
+ if (HAS_WEIGHTS) { weight = weights[k]; }
60
+ // two-level sum: 64 terms into chunk, chunk into acc (see the header; no compensation, no select)
61
+ chunk = chunk + (weight * xNorm[nbr]);
62
+ inChunk = inChunk + 1u;
63
+ if (inChunk == 64u) {
64
+ acc = acc + chunk;
65
+ chunk = 0.0;
66
+ inChunk = 0u;
67
+ }
68
+ }
69
+ acc = acc + chunk;
70
+ return acc;
71
+ }
72
+ fn finish(v: u32, acc: f32) {
17
73
  var dangling = 0.0;
18
74
  if (USE_DANGLING) { dangling = partials[0].danglingMass; }
19
- let first = linear_id(wid, lid.x);
20
- for (var row = first; row < P.n; row = row + P.stride) {
21
- let v = select(row, perm[row], USE_PERM);
22
- let a0 = max(rowPtr[v], P.arcBase);
23
- let a1 = min(rowPtr[v + 1u], P.arcEnd);
24
- var acc = 0.0;
25
- var chunk = 0.0;
26
- var inChunk = 0u;
27
- for (var arc = a0; arc < a1; arc = arc + 1u) {
28
- let nbr = colIdx[arc - P.arcBase]; // \`target\` is a WGSL reserved word (spec 16.2)
29
- var weight = 1.0;
30
- if (HAS_WEIGHTS) { weight = weights[arc - P.arcBase]; }
31
- // two-level sum: 64 terms into chunk, chunk into acc (see the header; no compensation, no select)
32
- chunk = chunk + (weight * xNorm[nbr]);
33
- inChunk = inChunk + 1u;
34
- if (inChunk == 64u) {
35
- acc = acc + chunk;
36
- chunk = 0.0;
37
- inChunk = 0u;
38
- }
75
+ var pv = P.uniformP;
76
+ if (HAS_PERSONALIZATION) { pv = personalization[v]; }
77
+ rankOut[v] = (P.beta * pv) + (P.alpha * (acc + (dangling * pv)));
78
+ }
79
+ fn tier0(wid: vec3<u32>, lane: u32) { // TIER 0: grid-stride over the rows [P.start, P.n); no barrier
80
+ for (var row = linear_id(wid, lane) + P.start; row < P.n; row = row + P.stride) {
81
+ let v = row_node(row);
82
+ finish(v, row_sum_dense(v));
83
+ }
84
+ }
85
+
86
+ var<workgroup> sh: array<f32, WG>;
87
+
88
+ fn tiered(wid: vec3<u32>, lid: u32) { // TIER 1: 32 lanes per row; TIER 2: WG lanes per row; rows [P.start, P.n) (PD-6)
89
+ let g = group_id(wid);
90
+ var row = P.start + g;
91
+ var lane = lid;
92
+ var step = WG;
93
+ if (TIER == 1u) { row = P.start + g * (WG / 32u) + lid / 32u; lane = lid % 32u; step = 32u; }
94
+ let valid = row < P.n;
95
+ var v = 0u;
96
+ var acc = 0.0;
97
+ if (valid) { v = row_node(row); acc = row_sum(v, lane, step); }
98
+ if (TIER == 1u) {
99
+ sh[lid] = acc;
100
+ workgroupBarrier();
101
+ for (var s = 16u; s >= 1u; s = s / 2u) { // the five-step tree over each 32-lane group; every lane runs every step
102
+ var t = 0.0;
103
+ if (lane < s) { t = sh[lid + s]; }
104
+ workgroupBarrier();
105
+ sh[lid] = sh[lid] + t;
106
+ workgroupBarrier();
39
107
  }
40
- acc = acc + chunk;
41
- var pv = P.uniformP;
42
- if (HAS_PERSONALIZATION) { pv = personalization[v]; }
43
- rankOut[v] = (P.beta * pv) + (P.alpha * (acc + (dangling * pv)));
108
+ if (valid && lane == 0u) { finish(v, sh[lid]); }
109
+ }
110
+ if (TIER == 2u) {
111
+ let t = wg_reduce_f32(acc, lid, 0u);
112
+ if (valid && lid == 0u) { finish(v, t); }
44
113
  }
45
114
  }
115
+
116
+ @compute @workgroup_size(WG)
117
+ fn spmv_pull(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
118
+ if (TIER == 0u) { tier0(wid, lid.x); } else { tiered(wid, lid.x); }
119
+ }
46
120
  `;
47
121
  //# sourceMappingURL=spmv-pull.wgsl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spmv-pull.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/spmv-pull.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wHAAwH;AACxH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCtC,CAAC"}
1
+ {"version":3,"file":"spmv-pull.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/spmv-pull.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,0IAA0I;AAC1I,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+FtC,CAAC"}