@graphty/webgpu-graph-algorithms 0.6.27 → 0.6.28
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.
- package/README.md +56 -6
- package/dist/acquire.d.ts +2 -0
- package/dist/browser.js +18 -1
- package/dist/browser.js.map +1 -1
- package/dist/chunks/accelerator-B-FjQwaA.js +19173 -0
- package/dist/chunks/accelerator-B-FjQwaA.js.map +1 -0
- package/dist/chunks/managed-D_GdQtnu.js +98 -0
- package/dist/chunks/managed-D_GdQtnu.js.map +1 -0
- package/dist/node.js +18 -1
- package/dist/node.js.map +1 -1
- package/dist/src/accelerator.d.ts.map +1 -1
- package/dist/src/accelerator.js +5 -3
- package/dist/src/accelerator.js.map +1 -1
- package/dist/src/algorithms/all-pairs.d.ts.map +1 -1
- package/dist/src/algorithms/all-pairs.js +72 -47
- package/dist/src/algorithms/all-pairs.js.map +1 -1
- package/dist/src/algorithms/betweenness.d.ts +1 -1
- package/dist/src/algorithms/betweenness.js +2 -2
- package/dist/src/algorithms/closeness.d.ts +45 -42
- package/dist/src/algorithms/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/closeness.js +295 -226
- package/dist/src/algorithms/closeness.js.map +1 -1
- package/dist/src/browser/index.d.ts +10 -0
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +22 -0
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/constants.d.ts +13 -3
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +13 -3
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernels.d.ts +14 -4
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +62 -28
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/force-simulation.d.ts.map +1 -1
- package/dist/src/layouts/force-simulation.js +0 -1
- package/dist/src/layouts/force-simulation.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +0 -1
- package/dist/src/layouts/forceatlas2.js.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.js +0 -1
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -1
- package/dist/src/layouts/repulsion-grid.d.ts +1 -3
- package/dist/src/layouts/repulsion-grid.d.ts.map +1 -1
- package/dist/src/layouts/repulsion-grid.js +1 -6
- package/dist/src/layouts/repulsion-grid.js.map +1 -1
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -1
- package/dist/src/layouts/spring-electrical.js +0 -1
- package/dist/src/layouts/spring-electrical.js.map +1 -1
- package/dist/src/managed.d.ts +11 -0
- package/dist/src/managed.d.ts.map +1 -0
- package/dist/src/managed.js +129 -0
- package/dist/src/managed.js.map +1 -0
- package/dist/src/node/index.d.ts +11 -0
- package/dist/src/node/index.d.ts.map +1 -1
- package/dist/src/node/index.js +21 -0
- package/dist/src/node/index.js.map +1 -1
- package/dist/src/primitives/grid-pyramid.d.ts +16 -15
- package/dist/src/primitives/grid-pyramid.d.ts.map +1 -1
- package/dist/src/primitives/grid-pyramid.js +20 -28
- package/dist/src/primitives/grid-pyramid.js.map +1 -1
- package/dist/src/types/accelerator.d.ts +2 -0
- package/dist/src/types/accelerator.d.ts.map +1 -1
- package/dist/src/types/managed.d.ts +81 -0
- package/dist/src/types/managed.d.ts.map +1 -0
- package/dist/src/types/managed.js +7 -0
- package/dist/src/types/managed.js.map +1 -0
- package/dist/src/wgsl/bc-forward.wgsl.d.ts +1 -1
- package/dist/src/wgsl/bc-forward.wgsl.js +1 -1
- package/dist/src/wgsl/closeness-level.wgsl.d.ts +37 -0
- package/dist/src/wgsl/closeness-level.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-level.wgsl.js +204 -0
- package/dist/src/wgsl/closeness-level.wgsl.js.map +1 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.d.ts +11 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.js +42 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +2 -2
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js +2 -2
- package/dist/webgpu-graph-algorithms.js +142 -15586
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +10 -4
- package/src/accelerator.ts +5 -3
- package/src/algorithms/all-pairs.ts +86 -56
- package/src/algorithms/betweenness.ts +2 -2
- package/src/algorithms/closeness.ts +353 -256
- package/src/browser/index.ts +37 -0
- package/src/constants.ts +13 -3
- package/src/kernels.ts +65 -36
- package/src/layouts/force-simulation.ts +0 -1
- package/src/layouts/forceatlas2.ts +0 -1
- package/src/layouts/fruchterman-reingold.ts +0 -1
- package/src/layouts/repulsion-grid.ts +2 -7
- package/src/layouts/spring-electrical.ts +0 -1
- package/src/managed.ts +172 -0
- package/src/node/index.ts +36 -0
- package/src/primitives/grid-pyramid.ts +29 -41
- package/src/types/accelerator.ts +2 -0
- package/src/types/managed.ts +86 -0
- package/src/wgsl/bc-forward.wgsl.ts +1 -1
- package/src/wgsl/closeness-level.wgsl.ts +203 -0
- package/src/wgsl/closeness-rowsum.wgsl.ts +41 -0
- package/src/wgsl/grid-centroid-hub.wgsl.ts +2 -2
- package/dist/chunks/context-BZY6SMsM.js +0 -3615
- package/dist/chunks/context-BZY6SMsM.js.map +0 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts +0 -20
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts.map +0 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.js +0 -69
- package/dist/src/wgsl/closeness-reduce.wgsl.js.map +0 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts +0 -22
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts.map +0 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.js +0 -106
- package/dist/src/wgsl/closeness-sweep.wgsl.js.map +0 -1
- package/src/wgsl/closeness-reduce.wgsl.ts +0 -68
- package/src/wgsl/closeness-sweep.wgsl.ts +0 -105
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accelerator-B-FjQwaA.js","sources":["../../src/constants.ts","../../src/errors.ts","../../src/device/acquire.ts","../../src/device/caps.ts","../../src/device/error-scope.ts","../../src/device/lost.ts","../../src/kernel/kernel.ts","../../src/device/webgpu-constants.ts","../../src/kernel/prelude.ts","../../src/kernel/wgsl.ts","../../src/kernel/pipeline-cache.ts","../../src/kernel/profiler.ts","../../src/memory/lease.ts","../../src/memory/buffer-pool.ts","../../src/memory/readback.ts","../../src/memory/upload-plan.ts","../../src/memory/residency.ts","../../src/context.ts","../../src/kernel/batch.ts","../../src/kernel/dispatch.ts","../../src/kernel/struct-block.ts","../../src/wgsl/advance-expand.wgsl.ts","../../src/wgsl/apsp-fw.wgsl.ts","../../src/wgsl/apsp-init.wgsl.ts","../../src/wgsl/bc-backward.wgsl.ts","../../src/wgsl/bc-count.wgsl.ts","../../src/wgsl/bc-edge-gather.wgsl.ts","../../src/wgsl/bc-finalize.wgsl.ts","../../src/wgsl/bc-forward.wgsl.ts","../../src/wgsl/bc-forward-edge.wgsl.ts","../../src/wgsl/bc-gather.wgsl.ts","../../src/wgsl/bf-relax.wgsl.ts","../../src/wgsl/bfs-bitset-build.wgsl.ts","../../src/wgsl/bfs-bottom-up.wgsl.ts","../../src/wgsl/bfs-contract.wgsl.ts","../../src/wgsl/bfs-fused.wgsl.ts","../../src/wgsl/bfs-next-degree.wgsl.ts","../../src/wgsl/bfs-unvisited-flags.wgsl.ts","../../src/wgsl/closeness-level.wgsl.ts","../../src/wgsl/closeness-rowsum.wgsl.ts","../../src/wgsl/compact-scatter.wgsl.ts","../../src/wgsl/coo-emit.wgsl.ts","../../src/wgsl/coo-scatter.wgsl.ts","../../src/wgsl/counting-scatter.wgsl.ts","../../src/wgsl/dedupe-claim.wgsl.ts","../../src/wgsl/dedupe-filter.wgsl.ts","../../src/wgsl/degree.wgsl.ts","../../src/wgsl/fa2-attraction.wgsl.ts","../../src/wgsl/fa2-integrate.wgsl.ts","../../src/wgsl/fa2-repulsion-exact.wgsl.ts","../../src/wgsl/fa2-speed-finalize.wgsl.ts","../../src/wgsl/fa2-stats-finalize.wgsl.ts","../../src/wgsl/fa2-to-scene.wgsl.ts","../../src/wgsl/fill.wgsl.ts","../../src/wgsl/frontier-finalize.wgsl.ts","../../src/wgsl/grid-cell-key.wgsl.ts","../../src/wgsl/grid-centroid.wgsl.ts","../../src/wgsl/grid-centroid-hub.wgsl.ts","../../src/wgsl/grid-downsample.wgsl.ts","../../src/wgsl/grid-far-field.wgsl.ts","../../src/wgsl/grid-near-field.wgsl.ts","../../src/wgsl/group-by-key-row.wgsl.ts","../../src/wgsl/histogram.wgsl.ts","../../src/wgsl/indirect-finalize.wgsl.ts","../../src/wgsl/lpa-step.wgsl.ts","../../src/wgsl/mst-best.wgsl.ts","../../src/wgsl/mst-link.wgsl.ts","../../src/wgsl/orient-flags.wgsl.ts","../../src/wgsl/pr-finalize.wgsl.ts","../../src/wgsl/pr-scale.wgsl.ts","../../src/wgsl/radix-hist.wgsl.ts","../../src/wgsl/radix-scatter.wgsl.ts","../../src/wgsl/reduce.wgsl.ts","../../src/wgsl/run-flags.wgsl.ts","../../src/wgsl/scan-add.wgsl.ts","../../src/wgsl/scan-block.wgsl.ts","../../src/wgsl/segmented-reduce.wgsl.ts","../../src/wgsl/spmv-pull.wgsl.ts","../../src/wgsl/sssp-pred.wgsl.ts","../../src/wgsl/sssp-relax.wgsl.ts","../../src/wgsl/tri-intersect.wgsl.ts","../../src/wgsl/wcc-compress.wgsl.ts","../../src/wgsl/wcc-link-edges.wgsl.ts","../../src/wgsl/wcc-link-sample.wgsl.ts","../../src/wgsl/wcc-sample.wgsl.ts","../../src/kernels.ts","../../src/primitives/core-shape.ts","../../src/kernel/uniform-ring.ts","../../src/primitives/scan.ts","../../src/primitives/verify.ts","../../src/algorithms/scope.ts","../../src/primitives/compact.ts","../../src/primitives/frontier.ts","../../src/primitives/advance.ts","../../src/primitives/radix-sort.ts","../../src/algorithms/bfs.ts","../../src/algorithms/sssp.ts","../../src/algorithms/all-pairs.ts","../../src/algorithms/bellman-ford.ts","../../src/primitives/spmv.ts","../../src/algorithms/power-iteration.ts","../../src/algorithms/betweenness.ts","../../src/algorithms/closeness.ts","../../src/algorithms/components.ts","../../src/primitives/group-by-key.ts","../../src/primitives/histogram.ts","../../src/primitives/coo-to-csr.ts","../../src/primitives/segmented-reduce.ts","../../src/algorithms/simple-symmetric.ts","../../src/algorithms/label-propagation.ts","../../src/algorithms/mst.ts","../../src/algorithms/pagerank.ts","../../src/algorithms/spectral.ts","../../src/algorithms/triangles.ts","../../src/primitives/grid.ts","../../src/layouts/seed.ts","../../src/layouts/force-simulation.ts","../../src/layouts/inputs.ts","../../src/layouts/model-common.ts","../../src/layouts/repulsion-exact.ts","../../src/primitives/grid-pyramid.ts","../../src/layouts/repulsion-grid.ts","../../src/layouts/forceatlas2.ts","../../src/layouts/fruchterman-reingold.ts","../../src/layouts/spring-electrical.ts","../../src/accelerator.ts"],"sourcesContent":["/**\n * Every numeric constant the package and the WGSL prelude share (spec 3.1, 3.5, 5.2, 7.8, 7.14, 7.17;\n * contract 3.2). The prelude (src/kernel/prelude.ts, P1-T3) interpolates these values and never retypes them\n * as literals (the literal grep of spec 3.5 enforces it); the planners read them; test/device/constants.test.ts\n * pins them. graph-format's INVALID_INDEX is imported by the prelude directly and is deliberately not copied.\n */\n\n/** Workgroup size of every 1D kernel; `WG = min(WORKGROUP_SIZE, caps.limits.maxComputeInvocationsPerWorkgroup)` at runtime (spec 5.1). */\nexport const WORKGROUP_SIZE = 256;\n/** The spec minimum of maxComputeWorkgroupsPerDimension; asserted equal to the device limit at create() (spec 2.2, 5.2). */\nexport const MAX_WORKGROUPS_PER_DIM = 65535;\n/** Items a 1D dispatch of WORKGROUP_SIZE covers: 65535 x 256 = 16,776,960, NOT 2^24 (design 10.6). */\nexport const MAX_1D_ITEMS = MAX_WORKGROUPS_PER_DIM * WORKGROUP_SIZE;\n/** The largest u32 (the `min` identity of the u32 reduce); interpolated into the prelude as `U32_MAX` so no body types the literal (contract 4.1). */\nexport const U32_MAX = 0xffffffff;\n/** The bins of one radix-sort pass, 2^8 (spec 6 row 6; P4 PD-5: 8 bits per pass); interpolated into the prelude as `RADIX_BINS` and `RADIX_DIGIT_MASK` (= bins - 1) so no body types the literal. */\nexport const RADIX_BINS = 256;\n/** Arc-window boundaries are multiples of 64 arcs = 256 bytes (design 10.6). */\nexport const ARC_WINDOW_ALIGN = 64;\n/** Storage-binding offset alignment the package always honours (spec 2.6): the graph-format arena is 256-aligned. */\nexport const STORAGE_ALIGN = 256;\n/** Stride of one UniformRing slot: minUniformBufferOffsetAlignment is 256 on every runtime the package targets (spec 5.3). */\nexport const UNIFORM_SLOT_BYTES = 256;\n/**\n * Exact-tier crossover default, re-fixed at G4 by the spec 7.8 rule in full (spec Q-6; docs/decisions/G3.md section 3\n * for the budget clause, docs/decisions/G4.md section 7 for the re-check): the largest rung of the T-4 ladder (1k / 4k /\n * 8k / 16k / 32k / 65k, E = 10n, 2D) with <= 4 ms per iteration AND not slower than the grid tier at the same n (the\n * `layout-grid` 2D rows: the shared rungs 32k / 65k and the re-check rungs 1k / 4k / 8k / 16k the group runs so every\n * exact rung has a grid row), rounded down to a power of two. Measured on the RTX 4070 SUPER under Dawn-node:\n * benchmarks/results/nvidia-lovelace-driver580.json, session 2026-09-21T06:15:17.027Z, the \"ms/iteration (profiler)\"\n * rows of layout-exact and the \"grid ms/iteration (profiler) ... 2D\" rows of layout-grid (the GPU time of the\n * iteration's passes at the card's working clock), exact / grid ms per iteration: 1k 0.102 / 0.290, 4k 0.262 / 0.188,\n * 8k 0.484 / 0.211, 16k 1.064 / 0.225, 32k 2.579 / 0.298, 65k 8.450 / 0.409. The grid tier's cost is a near-constant\n * ~0.19-0.3 ms floor (its sort, scan and pyramid passes) up to 32k, so the exact tier wins only at 1k and the rule's\n * answer is 1024 (32768 under the budget clause alone, the G3 value; 16384 was the P4-T14 draft's value, which only\n * evaluated the grid clause at 32k / 65k and was not a measurement). calibrateLayout's finer probe on the same card\n * (tmp/p4/t14-review/calibrate-defaults.log: exact 0.150 vs grid 0.190 ms at 2048) puts the true crossover between\n * 2k and 4k; the ladder has no 2k rung, and the design's basis (cosmos switches at 4,096) is within 0.07 ms per\n * iteration of the rule's value, so the choice among 1k / 2k / 4k is an accuracy preference (the exact tier is the\n * oracle), not a speed one. OWNER DECISION G4-D1 (docs/decisions/G4.md section 7, rows G4-D1 / G4-F9): the constant\n * KEEPS the G3 value 32768 while the accuracy work G4-F1 leaves is open -- G4-F1 (the grid tier's exact-vs-grid RMS\n * on the clumpy and degenerate fixtures) closed on 2026-09-21 by the owner's asserted / printed split, G4-F2 (the\n * unbiasedness item) the same day by its re-scope to the whole-field ratio, and the far field's accuracy on those\n * fixtures is the follow-up -- because \"auto\" is the default every consumer sees and the exact tier is the accurate\n * one; the rule's answer on the dev box (1024) is recorded, not shipped, until that work closes and the value is\n * re-fixed. Re-measured on 2026-10-02 after the grid tier's hub-cell centroid became a direct dispatch (issue #732):\n * the rule still answers 1024 (exact 0.26 against grid 0.18 ms per iteration at 4,096 nodes), because the indirect\n * dispatch's cost was Dawn's validation pass, which the profiler's per-pass times never included. A\n * consumer whose GPU differs (integrated, Apple, T4) passes its own value through\n * createAccelerator(ctx, { layout: { exactMaxNodes } }); calibrateLayout(ctx) measures it.\n */\nexport const EXACT_MAX_NODES = 32768;\n/** Default number of MAP_READ staging buffers in the Readback ring (spec 4.4). */\nexport const DEFAULT_STAGING_SLOTS = 3;\n/** Timestamp query-set size of the Profiler (spec 5.5: \"a query set of 256 slots\"; 2 slots per pass). */\nexport const PROFILER_QUERY_SLOTS = 256;\n/** Byte size above which createBuffer runs inside an \"out-of-memory\" error scope (spec 5.7). */\nexport const OOM_SCOPE_THRESHOLD_BYTES = 16 * 1024 * 1024;\n/** Idle buffers kept per (size class, usage) by the BufferPool (spec 4.4). */\nexport const POOL_MAX_IDLE_PER_CLASS = 4;\n/** Smallest power-of-two pool class (spec 4.4). */\nexport const POOL_MIN_CLASS_BYTES = 4 * 1024;\n/** Largest power-of-two pool class; above it the classes grow linearly (spec 4.4). */\nexport const POOL_MAX_POW2_CLASS_BYTES = 64 * 1024 * 1024;\n/** The linear step of the pool classes above the largest power of two (spec 4.4). */\nexport const POOL_LINEAR_STEP_BYTES = 16 * 1024 * 1024;\n/** Default `warnUnreleasedSnapshots` (spec 2.2, 4.1). */\nexport const DEFAULT_WARN_UNRELEASED_SNAPSHOTS = 2;\n/** CONTRACT DECISION: the largest `iterations` a single step() records (the trace region and the uniform ring are sized by it); larger values are E_INVALID_ARGUMENT. */\nexport const MAX_ITERATIONS_PER_STEP = 256;\n/** Bytes of one Fa2Trace record (spec 7.3: 32-byte records). */\nexport const TRACE_RECORD_BYTES = 32;\n/** CONTRACT DECISION: the state header is padded to 256 bytes so the trace region that follows it in the same buffer starts at a legal 256-aligned binding offset (spec 7.3 says \"128 + k x 32\"; 128 is not a legal storage offset). */\nexport const STATE_HEADER_BYTES = 256;\n/** Bytes of one per-workgroup partials record (spec 7.3: exactly 64 B). */\nexport const PARTIAL_BYTES = 64;\n/** ForceAtlas2 defaults (spec 7.14, 7.17, 7.19). */\nexport const FA2_DEFAULTS: Readonly<{\n maxIter: 100;\n jitterTolerance: 1;\n scalingRatio: 2;\n gravity: 1;\n strongGravity: false;\n distributedAction: false;\n linlog: false;\n dissuadeHubs: false;\n dim: 2;\n scale: 1;\n settleThreshold: 0.001;\n settleWindow: 10;\n iterationsPerStep: 1;\n maxInFlight: 2;\n}> = Object.freeze({\n maxIter: 100,\n jitterTolerance: 1,\n scalingRatio: 2,\n gravity: 1,\n strongGravity: false,\n distributedAction: false,\n linlog: false,\n dissuadeHubs: false,\n dim: 2,\n scale: 1,\n settleThreshold: 0.001,\n settleWindow: 10,\n iterationsPerStep: 1,\n maxInFlight: 2,\n});\n/** GPU-only layout tuning defaults (spec 7.14): repulsion \"auto\", exactMaxNodes EXACT_MAX_NODES, nearMax 64, deterministic true, gridMax2D 512, gridMax3D 128, extentFactor 6, compat \"paper\". */\nexport const LAYOUT_TUNING_DEFAULTS: Readonly<{\n repulsion: \"auto\";\n exactMaxNodes: number;\n nearMax: 64;\n deterministic: true;\n gridMax2D: 512;\n gridMax3D: 128;\n extentFactor: 6;\n compat: \"paper\";\n}> = Object.freeze({\n repulsion: \"auto\",\n exactMaxNodes: EXACT_MAX_NODES,\n nearMax: 64,\n deterministic: true,\n gridMax2D: 512,\n gridMax3D: 128,\n extentFactor: 6,\n compat: \"paper\",\n});\n/** The distance floor `max(d, 0.01)` of spec 7.2; interpolated into the prelude (contract 4.1). */\nexport const FA2_DISTANCE_FLOOR = 0.01;\n/** The square of FA2_DISTANCE_FLOOR. */\nexport const FA2_DISTANCE_FLOOR_SQ = 0.0001;\n/** The coincident threshold `d^2 < 1e-8` of spec 7.2. */\nexport const FA2_COINCIDENT_SQ = 1e-8;\n/**\n * The most WG-node tiles one K3 (`fa2-repulsion-exact`) dispatch sums per invocation (issue #87). llvmpipe runs at\n * most 65,535 loop iterations per shader invocation, counted over every loop together, and then quietly breaks\n * out of each loop; one tile costs WG + 2 of them (258 at WG 256), so a single pass lost every node past\n * j = 65,027. 128 tiles is 33,024 iterations, half the budget; a larger exact run records ceil(tiles / 128) passes.\n */\nexport const EXACT_TILES_PER_PASS = 128;\n/** Bits of Fa2Params.flags (contract 4.4). */\nexport const FA2_FLAG_FIRST = 1;\n/** Fa2Params.flags bit: the Fruchterman-Reingold temperature is the adaptive one in the state block, not the uniform's (the `cooling: \"adaptive\"` option). */\nexport const FA2_FLAG_ADAPTIVE = 2;\n/** The Fruchterman-Reingold loop's starting temperature (spec 7.20; `layout/src/simulation/fruchterman-reingold.ts:30`). */\nexport const FR_START_TEMPERATURE = 0.1;\n/** The reheat point of spec 7.20: the temperature index a reheat restarts at, as a fraction of `iterations`. */\nexport const FR_REHEAT_FRACTION = 0.7;\n/** Adaptive cooling (Yifan Hu 2005, section 3.2): the temperature is multiplied by this when the force energy rose, divided by it after FR_COOLING_PATIENCE consecutive falls. */\nexport const FR_COOLING_STEP = 0.9;\n/** Adaptive cooling: consecutive iterations of falling energy before the temperature grows. */\nexport const FR_COOLING_PATIENCE = 5;\n/** Adaptive cooling: the iteration budget when `iterations` is not given (the schedule no longer needs one; this is the cap on a run that never settles). */\nexport const FR_ADAPTIVE_MAX_ITERATIONS = 10_000;\n/** Fruchterman-Reingold defaults (spec 7.20, 9.3; the CPU simulation's, `layout/src/simulation/fruchterman-reingold.ts:32`): `k` null = `1 / sqrt(n)`. */\nexport const FR_DEFAULTS: Readonly<{\n k: null;\n iterations: 50;\n fixed: null;\n dim: 2;\n scale: 1;\n settleThreshold: 0.001;\n settleWindow: 10;\n iterationsPerStep: 1;\n maxInFlight: 2;\n cooling: \"linear\";\n}> = Object.freeze({\n k: null,\n iterations: 50,\n fixed: null,\n dim: 2,\n scale: 1,\n settleThreshold: 0.001,\n settleWindow: 10,\n iterationsPerStep: 1,\n maxInFlight: 2,\n cooling: \"linear\",\n});\n/**\n * Spring-electrical size scaling: when `gravity` or `springCoefficient` is left to its default, ngraph's constant is\n * multiplied by min(1, SE_SCALE_REFERENCE_NODES / n). ngraph's values were tuned for graphs of a few hundred nodes;\n * on tens of thousands the per-node forces are so large that every node moves at the unit speed clamp and the layout\n * never comes to rest (measured on the 58k-node Brightkite graph: 3,350 iterations to the settle rule with the\n * kinetic energy still at the clamp; a uniform 1/1000 factor settled in 1,000 with the energy decayed 25x).\n */\nexport const SE_SCALE_REFERENCE_NODES = 300;\n/** Spring-electrical defaults: ngraph.forcelayout 3.3.1's (`lib/createPhysicsSimulator.js:29,34,40,54,59`; spec 7.20), plus the shared simulation defaults. `gravity` is ngraph's Coulomb constant: negative repels. */\nexport const SE_DEFAULTS: Readonly<{\n springLength: 10;\n springCoefficient: 0.8;\n gravity: -12;\n dragCoefficient: 0.9;\n timeStep: 0.5;\n dim: 2;\n scale: 1;\n settleThreshold: 0.001;\n settleWindow: 10;\n iterationsPerStep: 1;\n maxInFlight: 2;\n}> = Object.freeze({\n springLength: 10,\n springCoefficient: 0.8,\n gravity: -12,\n dragCoefficient: 0.9,\n timeStep: 0.5,\n dim: 2,\n scale: 1,\n settleThreshold: 0.001,\n settleWindow: 10,\n iterationsPerStep: 1,\n maxInFlight: 2,\n});\n/**\n * The absolute settle floor of the shared settle rule (spec 7.17; issue #97): an iteration counts toward `settled` only\n * when its mean displacement is at most `settleThreshold x rmsRadius` AND at most this fraction of the model's length\n * unit -- `springLength` for spring-electrical (scaled by node count, see SETTLE_FLOOR_REFERENCE_NODES), `k` for\n * Fruchterman-Reingold. The relative rule alone reported a spring\n * layout settled while it still grew (6 % over 1,000 iterations at 10k nodes). ForceAtlas2 writes\n * `SETTLE_FLOOR_UNBOUNDED` instead: it does not drift after settling, and its per-iteration jitter grows with n, so any\n * fixed floor only delays or blocks its stop. The values are measured:\n * design/decisions/2026-09-24-settle-rule-has-an-absolute-floor.md.\n */\nexport const SETTLE_FLOOR_FRACTION: Readonly<{ springElectrical: number; fruchtermanReingold: number }> = Object.freeze(\n {\n springElectrical: 3e-3,\n fruchtermanReingold: 2e-3,\n },\n);\n/**\n * The node count at which the spring-electrical floor is exactly `SETTLE_FLOOR_FRACTION.springElectrical x\n * springLength`; at `n` nodes it is that times `(SETTLE_FLOOR_REFERENCE_NODES / n)^(1/4)`. A spring layout's rms radius\n * grows about as n^(1/4) in springLengths (3.4 at 150 nodes, 6.4 at 2,000, 10.4 at 10,000), so the relative half of the\n * rule loosens with size while the floor tightens with it: on a small graph the floor sits above the relative threshold\n * and the relative rule decides alone, as before issue #97; on a large one the floor binds, which is where the relative\n * rule let an expanding layout stop. A fixed floor bound the 150-node story graph too, where the grid tier's jitter sits\n * at the relative threshold, and nearly doubled its settle (427 -> 829 iterations on the RTX 4070 SUPER).\n */\nexport const SETTLE_FLOOR_REFERENCE_NODES = 2000;\n/** The settle floor that never binds: the largest finite f32, 0x1.fffffep+127 (ForceAtlas2's `settleFloor`, issue #97). */\nexport const SETTLE_FLOOR_UNBOUNDED = 2 ** 128 - 2 ** 104;\n/** The smallest finest grid side `G` (spec 7.7 geometry table: `clamp(nextPow2(2 n^(1/dim)), 8, gridMax)`; P4 PD-9). */\nexport const GRID_MIN_SIDE = 8;\n/** The coarsest pyramid level's side (spec 7.7: \"levels (coarsest 4 per axis)\", `levels = log2(G / 4) + 1`). */\nexport const GRID_COARSEST_SIDE = 4;\n/** A cell with more than this many entries is summed by a workgroup (G4b) instead of the thread-per-cell loop of G4 (spec 7.7 G4: `count > 1024`). */\nexport const GRID_HUB_CELL = 1024;\n/** The extent floor of spec 7.7: `cellSize = max(extent, 1e-6) / G`, so an all-coincident load never divides by zero. */\nexport const GRID_EXTENT_FLOOR = 1e-6;\n/** The bbox margin of spec 7.7: `bboxExtent` is the largest axis of `state.min / max` \"with a 1% margin\". */\nexport const GRID_BBOX_MARGIN = 1.01;\n/** The key width the grid always sorts with (P4 PD-5): three 8-bit passes cover the 19-bit 2D keys at G = 512 and the 22-bit 3D keys at G = 128, and an odd pass count leaves `sortedIdx` in the scratch pair. */\nexport const GRID_SORT_BITS = 24;\n/** Design 8.4 (P8 PD-7): traversal levels recorded per submit -- one four-byte readback per 32 BFS levels, SSSP rounds or closeness levels. */\nexport const MAX_LEVELS_PER_SUBMIT = 32;\n/** Design 8.4 and 6 row 8 (P8): a frontier at most this long runs the fused expand-contract kernel (Merrill's \"fleeting iterations\"); the default of the `fusedMax` uniform, which a test may set to 0 or `U32_MAX`. */\nexport const FUSED_FRONTIER_MAX = 4096;\n/** Design 8.4 (P8 PD-21): Beamer's beta -- switch back to top-down when `frontierCount * BEAMER_BETA < unvisitedCount` and the frontier is shrinking; alpha is derived from the graph, so it has no constant. */\nexport const BEAMER_BETA = 24;\n/** Design 8.4 (P8 PD-22): the near-far split `delta = SSSP_DELTA_FACTOR * avgWeight / avgDegree`, computed on the host from the weight vector the run uses. */\nexport const SSSP_DELTA_FACTOR = 32;\n/** The bit pattern of +Infinity, the unreached sentinel of `dist` (P8 PD-9); interpolated into the prelude as `F32_INF_BITS` so no body types the literal. */\nexport const F32_INF_BITS = 0x7f800000;\n/** Design 8.4 \"k planned from maxBufferSize and a 25% budget\": the share of `maxBufferSize` one betweenness source batch may hold. WebGPU exposes no device memory size, so this is a fraction of the largest buffer, not a memory measurement. */\nexport const BC_BATCH_BUDGET_FRACTION = 0.25;\n/**\n * The most sources one betweenness batch runs together. 256 rather than design 10.1's 64 (issue #733): a batch's\n * cost is dominated by its per-level submits and readbacks, not by its width, so a quarter of the batches runs an\n * exact call on random graphs of 1k / 2k / 4k nodes (4 edges per node, RTX 4070 SUPER) 2.8x / 2.5x / 1.8x faster\n * with the frontier forward form and 1.9x / 1.6x / 1.5x with the per-batch choice, with bit-identical vertex and\n * edge scores (the gathers add every source's dependency in source order whatever the batching). The memory budget\n * still decides k above about 16k nodes at default limits, so large graphs are unchanged. Forward levels per submit\n * stay at `MAX_LEVELS_PER_SUBMIT`: the parameter ring is sized for it.\n */\nexport const BC_MAX_BATCH = 256;\n/** Design 8.4 (McLaughlin-Bader): a betweenness batch runs the edge-parallel forward pass when the previous batch's level count is below `BC_EDGE_PARALLEL_GAMMA * log2(n)`. The design names the rule and no value; 2 is unmeasured and a benchmark run re-fixes it. */\nexport const BC_EDGE_PARALLEL_GAMMA = 2;\n/**\n * Betweenness path counts that wrapped u32 are recounted as f32, rescaled per depth by a power of two (`bc-count`):\n * when the largest count at one depth has a binary exponent above this cap, the next depth's counts are scaled down so\n * that largest count lands at 2^cap. A count then never exceeds 2^cap x 2 x (in-degree), below f32's 2^128 for any\n * in-degree a binding can hold (2^25), and the counts at one depth may span 2^(cap + 126) before the smallest leaves\n * f32's normal range, which is when the overflow flag rises (measured: a corner of a 235 x 235 grid, not of a 230 x 230\n * one). Powers of two scale without rounding, so the scores do not depend on the cap.\n */\nexport const BC_SIGMA_EXPONENT_CAP = 100;\n/** The most workgroups one `bc-count` dispatch launches (it grid-strides over the level): sized for the largest level, a dispatch of n x k lanes costs every level a mostly idle launch, which doubled a 100 x 100 grid's run on an RTX 4070 SUPER; 256 measured 1.3 s against 2.0 s there. */\nexport const BC_COUNT_MAX_GROUPS = 256;\n/** Backward-pass levels recorded per submit: each level is one dispatch with its own parameter record, so this bounds the uniform ring. */\nexport const BC_BACKWARD_LEVELS_PER_SUBMIT = 64;\n/**\n * Design 8.7: all-pairs shortest paths is a blocked Floyd-Warshall over `APSP_TILE x APSP_TILE` tiles. One tile of\n * f32 is 4 KiB of workgroup memory and a workgroup stages at most two (8 KiB), inside the 16 KiB\n * `maxComputeWorkgroupStorageSize` every WebGPU device reports. Interpolated into the prelude as `APSP_TILE`.\n */\nexport const APSP_TILE = 32;\n/**\n * The blocked sweep records `3 x ceil(n / APSP_TILE)` dispatches (543 at the 5,792-node ceiling of a 128 MiB binding,\n * 2,175 at a 2 GiB binding's 23,170, 3,072 at a 4 GiB binding's 32,767); above this many the driver splits the sweep\n * into further submits. No binding offered today reaches it, so every sweep is one submit; the cap only stops a\n * device with a binding above 4 GiB (`maxStorageBufferBindingSize` is a GPUSize64) from building one unbounded\n * command buffer.\n */\nexport const APSP_MAX_DISPATCHES_PER_SUBMIT = 4096;\n/**\n * Label propagation (design 8.6): passes recorded per submit, with ONE readback of the per-pass changed counts at the\n * end of the submit. A readback costs about 2 ms in Chromium whatever it carries, so at one readback per pass a\n * 10,000-node call spends more on synchronisation than the CPU spends on the whole algorithm\n * (design/decisions/2026-09-26-which-algorithms-earn-the-gpu.md: 101 passes x 2 ms, 0.79x); eight passes per\n * submit is the floor that decision sets. Even, so every submit holds as many descending as ascending passes of the\n * alternating direction rule.\n */\nexport const LABEL_PROP_PASSES_PER_SUBMIT = 8;\n/**\n * Boruvka's minimum spanning tree (design 8.5): rounds recorded per submit, with one readback of the counters block\n * per submit. Each readback is a device-to-host synchronisation that costs about 2 ms in Chromium, and at one per\n * round the syncs are 61 % of the 100,000-node call; four rounds per submit amortise them over O(log n) rounds, moving\n * the Chromium crossover from 6,000 to 4,600 nodes (design/decisions/2026-09-26-which-algorithms-earn-the-gpu.md).\n * `src/algorithms/mst.ts` reads it.\n */\nexport const BORUVKA_ROUNDS_PER_SUBMIT = 4;\n/**\n * The sign bit of an f32 bit pattern; interpolated into the prelude as `F32_SIGN_BIT` for `order_key`, the\n * order-preserving u32 key of an f32 that Boruvka's `atomicMin` over edge weights runs on (P11 PD-6).\n */\nexport const F32_SIGN_BIT = 0x80000000;\n/** The per-row group-by-key (design 8.6): a row of at most this many arcs is grouped by one thread in registers; a longer row by a workgroup over a global open-addressing region. */\nexport const GROUP_ROW_THREAD_MAX = 32;\n/** The largest row the thread tier accepts when a caller forces the tier: its pairwise scan is about d^2 / 2 loop steps, and llvmpipe stops every loop of an invocation after 65,535 steps in total. */\nexport const GROUP_ROW_THREAD_LIMIT = 128;\n/**\n * The most parallel arcs the simple symmetric graph build merges into one weighted arc. The merge sums each run of\n * parallel arcs in one invocation, and llvmpipe stops every loop of an invocation after 65,535 steps in total and\n * then quietly returns a short sum; a weighted build whose pair repeats more often is refused on every adapter.\n */\nexport const PARALLEL_MERGE_LIMIT = 65_000;\n/** The per-row group-by-key (design 8.6): the global open-addressing region of a workgroup-tier row holds this many slots per arc. */\nexport const GROUP_HASH_LOAD_FACTOR = 2;\n/** Triangle counting (design 8.5): intersect two oriented rows by merge, but binary-search each element of the shorter row into the longer when their lengths differ by more than this factor. */\nexport const TRIANGLE_BINARY_SEARCH_RATIO = 32;\n","/**\n * The error class and the closed code set of @graphty/webgpu-graph-algorithms (spec 3.3, 5.7; contract 3.1).\n *\n * Every condition the package detects itself is thrown as a WebGpuGraphError carrying a stable `code` and a\n * frozen shallow copy of the `details` the thrower supplied. Errors raised by @graphty/graph-format accessors\n * the package calls on the caller's behalf pass through unchanged (D12); PASSTHROUGH_FORMAT_CODES lists the\n * codes a public call may let escape. Constructors never throw. Messages are plain ASCII.\n *\n * `details` keys per code (contract 3.1, so tests can assert them): E_NO_WEBGPU { reason, hint };\n * E_NO_ADAPTER { reason }; E_NO_DEVICE { reason, adapter, limit?, requested?, available? } (reason \"consumed\" |\n * \"requestDevice\" | \"limit\" | \"feature\" | \"maxComputeWorkgroupsPerDimension\"); E_SOFTWARE_ONLY { adapter };\n * E_DEVICE_LOST { reason, message }; E_DEVICE_INCORRECT { check, where, expected, actual, poison, count, blocks,\n * workgroupSize, adapter, hint? }; E_DISPOSED { label }; E_VALIDATION { label, message, batchId? };\n * E_SHADER_COMPILE { id, stage: \"compose\" | \"compile\", slot?, messages? }; E_OUT_OF_MEMORY { requested, resident,\n * label }; E_TOO_LARGE { needed, limit, path, algorithm }; E_UNSUPPORTED { feature? | option?, hint? } (exactly\n * one of feature / option); E_INVALID_ARGUMENT { argument, value, expected? }; E_SNAPSHOT { reason, serial };\n * E_RELEASED { serial }; E_NOT_LOADED { state }; E_ABORTED { batchId? }.\n */\n\n/** Every condition the package detects itself carries one of these codes (spec 3.3). */\nexport type WebGpuGraphErrorCode =\n | \"E_NO_WEBGPU\"\n | \"E_NO_ADAPTER\"\n | \"E_NO_DEVICE\"\n | \"E_SOFTWARE_ONLY\"\n | \"E_DEVICE_LOST\"\n | \"E_DEVICE_INCORRECT\"\n | \"E_DISPOSED\"\n | \"E_VALIDATION\"\n | \"E_SHADER_COMPILE\"\n | \"E_OUT_OF_MEMORY\"\n | \"E_TOO_LARGE\"\n | \"E_UNSUPPORTED\"\n | \"E_INVALID_ARGUMENT\"\n | \"E_SNAPSHOT\"\n | \"E_RELEASED\"\n | \"E_NOT_LOADED\"\n | \"E_ABORTED\";\n\n/** The graph-format error codes a public call lets propagate unchanged (D12, spec 5.7): raised by accessors the package calls on the caller's behalf. */\nexport const PASSTHROUGH_FORMAT_CODES: readonly [\n \"E_GPU_INELIGIBLE\",\n \"E_UNKNOWN_NODE\",\n \"E_UNKNOWN_COLUMN\",\n \"E_COLUMN_LENGTH\",\n] = Object.freeze([\"E_GPU_INELIGIBLE\", \"E_UNKNOWN_NODE\", \"E_UNKNOWN_COLUMN\", \"E_COLUMN_LENGTH\"] as const);\n\nconst EMPTY_DETAILS: Readonly<Record<string, unknown>> = Object.freeze({});\n\n/** The one error class the package throws for conditions it detects itself: a stable `code` and frozen `details` (spec 3.3). */\nexport class WebGpuGraphError extends Error {\n /** The stable code. */\n readonly code: WebGpuGraphErrorCode;\n\n /** Frozen shallow copy of the details given to the constructor (`{}` when none). */\n readonly details: Readonly<Record<string, unknown>>;\n\n /** `name` is always \"WebGpuGraphError\". */\n override readonly name: \"WebGpuGraphError\";\n\n /**\n * Create a WebGpuGraphError.\n * @param code - the stable code the caller can branch on\n * @param message - a plain-ASCII human-readable message naming the offending label, limit or value\n * @param details - optional machine-readable context; copied shallowly and frozen\n */\n constructor(code: WebGpuGraphErrorCode, message: string, details?: Record<string, unknown>) {\n super(message);\n this.name = \"WebGpuGraphError\";\n this.code = code;\n this.details = details === undefined ? EMPTY_DETAILS : Object.freeze({ ...details });\n }\n}\n\n/**\n * Brand check that survives two package copies: `name === \"WebGpuGraphError\"` and a string `code`.\n * @param x - anything, typically a caught value\n * @returns true when `x` is structurally a WebGpuGraphError (instanceof is NOT required)\n */\nexport function isWebGpuGraphError(x: unknown): x is WebGpuGraphError {\n if (typeof x !== \"object\" || x === null) {\n return false;\n }\n const candidate = x as { readonly name?: unknown; readonly code?: unknown };\n return candidate.name === \"WebGpuGraphError\" && typeof candidate.code === \"string\";\n}\n\n/**\n * Brand check that survives two package copies: `code === x.code` for an `isWebGpuGraphError(x)`.\n * @param x - anything, typically a caught value\n * @param code - the code to test for\n * @returns true when `x` is a WebGpuGraphError carrying `code`\n */\nexport function hasErrorCode(x: unknown, code: WebGpuGraphErrorCode): boolean {\n return isWebGpuGraphError(x) && x.code === code;\n}\n","/**\n * Device acquisition (spec 2.2 steps 1-3, 2.6; contract 3.4): the adapter request, the software-adapter\n * test, the adapter summary, the requiredLimits / requiredFeatures builders and the device request. Nothing\n * above the device layer is constructed here (D26); src/context.ts sequences these calls. An adapter is\n * consumed by its first requestDevice (WebGPU 3.5.1; Dawn-node rejects the second call with\n * `OperationError: adapter is \"consumed\"`), so every device the package creates comes from a fresh adapter.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport type { AdapterInfoLike, AdapterSummary, LimitPolicy, RaisableLimit } from \"../types/context.js\";\n\n/** The six raisable limits in the order create() requests them (spec 2.2). */\nexport const RAISABLE_LIMITS: readonly RaisableLimit[] = Object.freeze([\n \"maxBufferSize\",\n \"maxStorageBufferBindingSize\",\n \"maxStorageBuffersPerShaderStage\",\n \"maxComputeWorkgroupStorageSize\",\n \"maxComputeInvocationsPerWorkgroup\",\n \"maxComputeWorkgroupSizeX\",\n]);\n\n/**\n * The WebGPU limit names summarizeAdapter reads (the GPUSupportedLimits members of @webgpu/types 0.1.72).\n * A fixed list because Chromium exposes the limits as prototype getters (Object.keys is empty) and Dawn-node as an\n * addon object; reading each name works identically on both, and a name the runtime lacks is simply absent.\n */\nconst LIMIT_NAMES: readonly string[] = [\n \"maxTextureDimension1D\",\n \"maxTextureDimension2D\",\n \"maxTextureDimension3D\",\n \"maxTextureArrayLayers\",\n \"maxBindGroups\",\n \"maxBindGroupsPlusVertexBuffers\",\n \"maxBindingsPerBindGroup\",\n \"maxDynamicUniformBuffersPerPipelineLayout\",\n \"maxDynamicStorageBuffersPerPipelineLayout\",\n \"maxSampledTexturesPerShaderStage\",\n \"maxSamplersPerShaderStage\",\n \"maxStorageBuffersPerShaderStage\",\n \"maxStorageBuffersInVertexStage\",\n \"maxStorageBuffersInFragmentStage\",\n \"maxStorageTexturesPerShaderStage\",\n \"maxStorageTexturesInVertexStage\",\n \"maxStorageTexturesInFragmentStage\",\n \"maxUniformBuffersPerShaderStage\",\n \"maxUniformBufferBindingSize\",\n \"maxStorageBufferBindingSize\",\n \"minUniformBufferOffsetAlignment\",\n \"minStorageBufferOffsetAlignment\",\n \"maxVertexBuffers\",\n \"maxBufferSize\",\n \"maxVertexAttributes\",\n \"maxVertexBufferArrayStride\",\n \"maxInterStageShaderVariables\",\n \"maxColorAttachments\",\n \"maxColorAttachmentBytesPerSample\",\n \"maxComputeWorkgroupStorageSize\",\n \"maxComputeInvocationsPerWorkgroup\",\n \"maxComputeWorkgroupSizeX\",\n \"maxComputeWorkgroupSizeY\",\n \"maxComputeWorkgroupSizeZ\",\n \"maxComputeWorkgroupsPerDimension\",\n \"maxImmediateSize\",\n];\n\n/** Adapters that created a device through requestDevice(): a second create({ adapter }) fails without a round trip. */\nconst consumedAdapters = new WeakSet<GPUAdapter>();\n\n/**\n * The message of a thrown value.\n * @param err - what was caught\n * @returns the Error message, or the value as a string\n */\nfunction messageOf(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * Software adapter test (spec 2.2 step 2): architecture \"software\" (Dawn llvmpipe) or \"swiftshader\", or\n * isFallbackAdapter === true (Chromium); the ONE reader of these fields.\n * @param info - the adapter info (structural, so tests can fake it)\n * @returns true for a software adapter\n */\nexport function isSoftwareAdapter(info: AdapterInfoLike): boolean {\n // \"software\" = Dawn-node on llvmpipe, \"swiftshader\" = Chromium's fallback, \"warp\" = Dawn's D3D12 backend on\n // Microsoft's WARP rasterizer (the Windows host lane: vendor \"microsoft\", isFallbackAdapter absent under Dawn-node).\n return (\n info.architecture === \"software\" ||\n info.architecture === \"swiftshader\" ||\n info.architecture === \"warp\" ||\n info.isFallbackAdapter === true\n );\n}\n\n/**\n * The AdapterSummary of an adapter (info + features + limits); never requests a device.\n * @param adapter - an adapter (unused or not; only its info, features and limits are read)\n * @returns a frozen summary; `subgroupMinSize` / `subgroupMaxSize` are 0 when the info lacks them\n */\nexport function summarizeAdapter(adapter: GPUAdapter): AdapterSummary {\n const { info } = adapter;\n const source = adapter.limits as unknown as Readonly<Record<string, unknown>>;\n const limits: Record<string, number> = {};\n for (const name of LIMIT_NAMES) {\n const value = source[name];\n if (typeof value === \"number\") {\n limits[name] = value;\n }\n }\n return Object.freeze({\n vendor: info.vendor,\n architecture: info.architecture,\n device: info.device,\n description: info.description,\n software: isSoftwareAdapter(info),\n subgroupMinSize: info.subgroupMinSize ?? 0,\n subgroupMaxSize: info.subgroupMaxSize ?? 0,\n features: Object.freeze(Array.from(adapter.features).sort()),\n limits: Object.freeze(limits),\n });\n}\n\n/**\n * Step 1 of create(): requestAdapter with the power preference; null -> E_NO_ADAPTER.\n * @param gpu - navigator.gpu or the Dawn handle\n * @param powerPreference - honoured by browsers, ignored by Dawn-node (spec 2.6)\n * @returns an UNUSED adapter\n */\nexport async function requestAdapter(gpu: GPU, powerPreference: GPUPowerPreference): Promise<GPUAdapter> {\n let adapter: GPUAdapter | null;\n try {\n adapter = await gpu.requestAdapter({ powerPreference });\n } catch (err) {\n const reason = `requestAdapter() threw: ${messageOf(err)}`;\n throw new WebGpuGraphError(\"E_NO_ADAPTER\", reason, { reason });\n }\n if (adapter === null) {\n const reason = \"requestAdapter() returned null: no usable WebGPU adapter\";\n throw new WebGpuGraphError(\"E_NO_ADAPTER\", reason, { reason });\n }\n return adapter;\n}\n\n/**\n * Step 3 of create(): the requiredLimits record for a policy, clamped to the adapter; an explicit value\n * above the adapter -> E_NO_DEVICE { reason: \"limit\" } before any requestDevice call, so the failure is\n * diagnosable.\n * @param adapter - the adapter the device will come from\n * @param policy - \"default\" (nothing), \"raise\" (every raisable limit at the adapter's value) or explicit values\n * @returns the record to pass as requiredLimits\n */\nexport function buildRequiredLimits(adapter: GPUAdapter, policy: LimitPolicy): Record<string, number> {\n const limits: Record<string, number> = {};\n if (policy === \"default\") {\n return limits;\n }\n if (policy === \"raise\") {\n for (const name of RAISABLE_LIMITS) {\n limits[name] = adapter.limits[name];\n }\n return limits;\n }\n for (const name of RAISABLE_LIMITS) {\n const requested = policy[name];\n if (requested === undefined) {\n continue;\n }\n const available = adapter.limits[name];\n if (requested > available) {\n throw new WebGpuGraphError(\n \"E_NO_DEVICE\",\n `requested ${name} = ${requested} exceeds the adapter's ${available}`,\n { reason: \"limit\", adapter: summarizeAdapter(adapter), limit: name, requested, available },\n );\n }\n limits[name] = requested;\n }\n return limits;\n}\n\n/**\n * Step 3 of create(): the requiredFeatures list = required + (optional intersect adapter.features); a missing\n * required feature -> E_NO_DEVICE { reason: \"feature\", requested: <name> }.\n * @param adapter - the adapter the device will come from\n * @param required - features the caller cannot do without\n * @param optional - features requested only when the adapter has them\n * @returns the deduplicated list, required first\n */\nexport function buildRequiredFeatures(\n adapter: GPUAdapter,\n required: readonly GPUFeatureName[],\n optional: readonly GPUFeatureName[],\n): GPUFeatureName[] {\n const features: GPUFeatureName[] = [];\n for (const feature of required) {\n if (!adapter.features.has(feature)) {\n throw new WebGpuGraphError(\"E_NO_DEVICE\", `required feature \"${feature}\" is not supported by the adapter`, {\n reason: \"feature\",\n adapter: summarizeAdapter(adapter),\n requested: feature,\n });\n }\n if (!features.includes(feature)) {\n features.push(feature);\n }\n }\n for (const feature of optional) {\n if (adapter.features.has(feature) && !features.includes(feature)) {\n features.push(feature);\n }\n }\n return features;\n}\n\n/**\n * The E_NO_DEVICE of a consumed adapter; the runtime's text lives in the error message only (contract 3.1\n * documents `details` as { reason, adapter, limit?, requested?, available? }).\n * @param adapter - the adapter that already created a device\n * @param message - the runtime's rejection message when there was a round trip\n * @returns E_NO_DEVICE { reason: \"consumed\", adapter }\n */\nfunction consumedError(adapter: GPUAdapter, message: string): WebGpuGraphError {\n return new WebGpuGraphError(\n \"E_NO_DEVICE\",\n `the adapter already created a device (an adapter is consumed by one requestDevice, spec 2.2 step 1): ${message}`,\n { reason: \"consumed\", adapter: summarizeAdapter(adapter) },\n );\n}\n\n/**\n * Step 3 of create(): requestDevice; a rejection -> E_NO_DEVICE with the adapter summary (\"consumed\" when\n * the adapter already created a device, detected by the OperationError message or a prior-use record).\n * @param adapter - an UNUSED adapter\n * @param descriptor - requiredLimits, requiredFeatures and the label\n * @returns the device\n */\nexport async function requestDevice(adapter: GPUAdapter, descriptor: GPUDeviceDescriptor): Promise<GPUDevice> {\n if (consumedAdapters.has(adapter)) {\n throw consumedError(adapter, \"recorded by this package\");\n }\n let device: GPUDevice;\n try {\n device = await adapter.requestDevice(descriptor);\n } catch (err) {\n const message = messageOf(err);\n if (/consumed|already been used/i.test(message)) {\n throw consumedError(adapter, message);\n }\n throw new WebGpuGraphError(\"E_NO_DEVICE\", `requestDevice() rejected: ${message}`, {\n reason: \"requestDevice\",\n adapter: summarizeAdapter(adapter),\n });\n }\n consumedAdapters.add(adapter);\n return device;\n}\n","/**\n * Capability capture (spec 2.2 step 4, 3.3, 5.1, 5.2; contract 3.4): the GpuCaps record of a DEVICE (its\n * limits and features, never the adapter's), the zero-cost variant for an adopted device, the two planner\n * facts asserted at create(), and the workgroup size a device runs.\n */\n\nimport { MAX_WORKGROUPS_PER_DIM, WORKGROUP_SIZE } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport type { AdapterInfoLike, GpuCaps, PlanCaps } from \"../types/context.js\";\nimport { isSoftwareAdapter } from \"./acquire.js\";\n\n/**\n * Step 4 of create(): the GpuCaps of a DEVICE (device.limits, never adapter.limits) with the adapter info\n * and the runtime tag. The subgroup sizes are the adapter's only when the device has the \"subgroups\"\n * feature, else 0 (spec 3.3).\n * @param device - the device the caps describe\n * @param info - the adapter's info (vendor, architecture, subgroup sizes)\n * @param runtime - the tag the creating entry sets (\"unknown\" for consumers of the core)\n * @param wgslFeatures - navigator.gpu.wgslLanguageFeatures or the Dawn equivalent (informational)\n * @returns the capability record\n */\nexport function captureCaps(\n device: GPUDevice,\n info: AdapterInfoLike,\n runtime: \"browser\" | \"node\" | \"unknown\",\n wgslFeatures: Iterable<string>,\n): GpuCaps {\n const features: ReadonlySet<string> = new Set(device.features);\n const subgroups = features.has(\"subgroups\");\n return {\n limits: device.limits,\n features,\n wgslFeatures: new Set(wgslFeatures),\n subgroupMinSize: subgroups ? (info.subgroupMinSize ?? 0) : 0,\n subgroupMaxSize: subgroups ? (info.subgroupMaxSize ?? 0) : 0,\n software: isSoftwareAdapter(info),\n runtime,\n vendor: info.vendor,\n architecture: info.architecture,\n device: info.device,\n description: info.description,\n };\n}\n\n/**\n * GpuContext.from(device, info?): caps from device.limits / device.features and the partial info given;\n * software false and runtime \"unknown\" unless given; the subgroup sizes are honoured only when the device\n * has the feature.\n * @param device - the adopted device\n * @param info - what the caller knows about the adapter, if anything\n * @returns the capability record\n */\nexport function capsFromDevice(device: GPUDevice, info: Partial<GpuCaps> | undefined): GpuCaps {\n const features: ReadonlySet<string> = new Set(device.features);\n const subgroups = features.has(\"subgroups\");\n return {\n limits: device.limits,\n features,\n wgslFeatures: info?.wgslFeatures ?? new Set<string>(),\n subgroupMinSize: subgroups ? (info?.subgroupMinSize ?? 0) : 0,\n subgroupMaxSize: subgroups ? (info?.subgroupMaxSize ?? 0) : 0,\n software: info?.software ?? false,\n runtime: info?.runtime ?? \"unknown\",\n vendor: info?.vendor ?? \"\",\n architecture: info?.architecture ?? \"\",\n device: info?.device ?? \"\",\n description: info?.description ?? \"\",\n };\n}\n\n/**\n * The workgroup size a device runs: min(WORKGROUP_SIZE, caps.limits.maxComputeInvocationsPerWorkgroup) rounded\n * down to a power of two (spec 5.1; the formula of contract 3.2 / 3.4). maxComputeWorkgroupSizeX is not a term:\n * every adapter supports its 256 default (WebGPU 3.6.2), so the result never exceeds it. Rounds down by doubling\n * (no bitwise operator).\n * @param caps - the capability record (a GpuCaps is a PlanCaps)\n * @returns the workgroup size\n */\nexport function workgroupSizeFor(caps: PlanCaps): number {\n const cap = Math.min(WORKGROUP_SIZE, caps.limits.maxComputeInvocationsPerWorkgroup);\n let size = 1;\n while (size * 2 <= cap) {\n size *= 2;\n }\n return size;\n}\n\n/**\n * Asserts the two facts the planners bake in: maxComputeWorkgroupsPerDimension === MAX_WORKGROUPS_PER_DIM\n * (the prelude's linear_id and plan1d / plan2d use the constant) and WG is a power of two >= 64 (spec 2.2,\n * 5.2). The limit is never requested, so a device reports the spec default whatever its adapter says.\n * @param caps - the capability record of the device\n */\nexport function assertPlanLimits(caps: GpuCaps): void {\n const perDim = caps.limits.maxComputeWorkgroupsPerDimension;\n if (perDim !== MAX_WORKGROUPS_PER_DIM) {\n throw new WebGpuGraphError(\n \"E_NO_DEVICE\",\n `maxComputeWorkgroupsPerDimension is ${perDim}; the dispatch planner and the WGSL prelude bake ${MAX_WORKGROUPS_PER_DIM}`,\n {\n reason: \"maxComputeWorkgroupsPerDimension\",\n adapter: null,\n requested: MAX_WORKGROUPS_PER_DIM,\n available: perDim,\n },\n );\n }\n const wg = workgroupSizeFor(caps);\n if (wg < 64) {\n throw new WebGpuGraphError(\n \"E_NO_DEVICE\",\n `the device allows a workgroup of ${wg} invocations; the kernels need a power of two >= 64`,\n {\n reason: \"limit\",\n adapter: null,\n limit: \"maxComputeInvocationsPerWorkgroup\",\n requested: 64,\n available: wg,\n },\n );\n }\n}\n","/**\n * Error scopes (spec 5.7; contract 3.4): a validation scope that turns a captured GPUValidationError into\n * E_VALIDATION { label, message }, the compilation-info formatter with body-relative line numbers, and the\n * AllocationTracker that wraps large createBuffer calls in an out-of-memory scope and keeps the resident-byte\n * bookkeeping the residency, the pool and the staging ring share (it is owned by the context).\n */\n\nimport { OOM_SCOPE_THRESHOLD_BYTES } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\n\n/**\n * Runs `fn` inside pushErrorScope(\"validation\"); a captured error becomes E_VALIDATION { label, message }\n * thrown from the returned promise (spec 5.7). An error `fn` itself throws is rethrown unchanged after the\n * scope is popped, so the device's scope stack stays balanced.\n * @param device - the device\n * @param label - names the operation in the error (every object the package creates is labelled)\n * @param fn - the work; may return a promise\n * @returns the value of `fn`\n */\nexport async function withValidationScope<T>(device: GPUDevice, label: string, fn: () => Promise<T> | T): Promise<T> {\n device.pushErrorScope(\"validation\");\n let result: T;\n try {\n result = await fn();\n } catch (err) {\n await device.popErrorScope().catch(() => null);\n throw err;\n }\n const error = await device.popErrorScope();\n if (error !== null) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${label}: ${error.message}`, { label, message: error.message });\n }\n return result;\n}\n\n/**\n * Formats GPUCompilationInfo messages with line numbers relative to the kernel BODY: `preludeLines` (the\n * lines the composer emitted before the body) is subtracted, a message located inside those lines is\n * reported as `prelude:<line>`, and a message without a location (lineNum 0) carries no position (spec 5.1).\n * @param info - the compilation info of the shader module\n * @param preludeLines - the number of emitted lines before the body's first line\n * @returns one string per message: `<type> <line>:<column> <message>`\n */\nexport function formatCompilationInfo(info: GPUCompilationInfo, preludeLines: number): string[] {\n return info.messages.map((m) => {\n if (m.lineNum === 0) {\n return `${m.type} ${m.message}`;\n }\n const line = m.lineNum - preludeLines;\n if (line >= 1) {\n return `${m.type} ${line}:${m.linePos} ${m.message}`;\n }\n return `${m.type} prelude:${m.lineNum}:${m.linePos} ${m.message}`;\n });\n}\n\n/**\n * Creates buffers, wrapping sizes >= OOM_SCOPE_THRESHOLD_BYTES in an \"out-of-memory\" scope whose pop is\n * collected; `check()` surfaces the first OOM (spec 4.4, 5.7). Owned by the context, shared by the\n * residency and the pool.\n */\nexport class AllocationTracker {\n private readonly device: GPUDevice;\n private readonly threshold: number;\n private readonly live = new Map<GPUBuffer, number>();\n private residentBytes = 0;\n private pending: Promise<void>[] = [];\n private failure: WebGpuGraphError | null = null;\n private serial = 0;\n\n /**\n * Creates a tracker over one device.\n * @param device - the device buffers are created on\n * @param thresholdBytes - the byte size from which createBuffer runs inside an out-of-memory scope (default OOM_SCOPE_THRESHOLD_BYTES)\n */\n constructor(device: GPUDevice, thresholdBytes?: number) {\n this.device = device;\n this.threshold = thresholdBytes ?? OOM_SCOPE_THRESHOLD_BYTES;\n }\n\n /**\n * createBuffer with the scope rule; every buffer is labelled (an unlabelled descriptor becomes `buffer-<n>`).\n * @param descriptor - the buffer descriptor\n * @returns the buffer\n */\n createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer {\n this.serial += 1;\n const label =\n descriptor.label === undefined || descriptor.label === \"\" ? `buffer-${this.serial}` : descriptor.label;\n const { size } = descriptor;\n const scoped = size >= this.threshold;\n if (scoped) {\n this.device.pushErrorScope(\"out-of-memory\");\n }\n const buffer = this.device.createBuffer({ ...descriptor, label });\n this.live.set(buffer, size);\n this.residentBytes += size;\n if (scoped) {\n const pop = this.device.popErrorScope().then(\n (error) => {\n if (error === null) {\n return;\n }\n if (this.live.has(buffer)) {\n this.live.delete(buffer);\n this.residentBytes -= size;\n }\n if (this.failure === null) {\n this.failure = new WebGpuGraphError(\n \"E_OUT_OF_MEMORY\",\n `out of memory creating \"${label}\" (${size} bytes, ${this.residentBytes} resident): ${error.message}`,\n { requested: size, resident: this.residentBytes, label },\n );\n }\n },\n () => undefined,\n );\n this.pending.push(pop);\n }\n return buffer;\n }\n\n /**\n * Destroys a buffer created here and decrements `resident`; a buffer the tracker does not know is destroyed\n * without touching the bookkeeping, so destroying twice is harmless.\n * @param buffer - the buffer to destroy\n */\n destroy(buffer: GPUBuffer): void {\n const size = this.live.get(buffer);\n if (size !== undefined) {\n this.live.delete(buffer);\n this.residentBytes -= size;\n }\n buffer.destroy();\n }\n\n /**\n * Awaits every outstanding scope pop; the first OOM -> E_OUT_OF_MEMORY { requested, resident, label }; later\n * calls after a failure throw the same error again until `reset()`.\n */\n async check(): Promise<void> {\n while (this.pending.length > 0) {\n const batch = this.pending.splice(0);\n await Promise.all(batch);\n }\n if (this.failure !== null) {\n throw this.failure;\n }\n }\n\n /** Forgets a recorded OOM after the caller released what it allocated. */\n reset(): void {\n this.failure = null;\n }\n\n /**\n * Bytes of live buffers created through this tracker.\n * @returns the resident byte count\n */\n get resident(): number {\n return this.residentBytes;\n }\n\n /**\n * Number of live buffers created through this tracker.\n * @returns the live buffer count\n */\n get liveBuffers(): number {\n return this.live.size;\n }\n}\n","/**\n * Device-loss and uncaptured-error plumbing (spec 5.7, 2.2 step 5; contract 3.4): the pending-error slot a\n * context throws from its next public call, the uncapturederror listener that routes each event to the\n * caller's sink or to the slot, the device.lost watcher and the E_DEVICE_LOST constructor. Nothing here\n * throws; errors are constructed and handed on.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\n\n/** The context's pending-error slot (spec 5.7): the last uncaptured error not yet delivered; `take()` clears it. */\nexport class PendingErrorSlot {\n private readonly queue: WebGpuGraphError[] = [];\n\n /**\n * Stores an error; a second error before `take()` is kept as `details.next` of the first.\n * @param error - the error to hold until the next public call\n */\n set(error: WebGpuGraphError): void {\n this.queue.push(error);\n }\n\n /**\n * Returns and clears the pending error, or null. With several errors queued the FIRST is returned and\n * each later one is chained as `details.next` of its predecessor (a copy: `details` is frozen).\n * @returns the first pending error with the chain attached, or null\n */\n take(): WebGpuGraphError | null {\n if (this.queue.length === 0) {\n return null;\n }\n const errors = this.queue.splice(0);\n let chained: WebGpuGraphError | null = null;\n for (let i = errors.length - 1; i >= 0; i -= 1) {\n const error = errors[i];\n chained =\n chained === null\n ? error\n : new WebGpuGraphError(error.code, error.message, { ...error.details, next: chained });\n }\n return chained;\n }\n\n /**\n * True when an error is pending.\n * @returns whether `take()` would return an error\n */\n get pending(): boolean {\n return this.queue.length > 0;\n }\n}\n\n/**\n * The WebGpuGraphError for one uncaptured GPUError: E_OUT_OF_MEMORY for a GPUOutOfMemoryError (recognised\n * by its class name so no global is read, spec 2.1 rule 1), E_VALIDATION otherwise.\n * @param error - the event's error\n * @param label - the device label the error is attributed to\n * @returns the wrapped error\n */\nfunction uncapturedError(error: GPUError, label: string): WebGpuGraphError {\n const { message } = error;\n if (error.constructor.name === \"GPUOutOfMemoryError\") {\n // the documented shape is { requested, resident, label } (contract 3.1); the event names no size and the\n // sink tracks no residency, so both are 0 and the runtime's text lives in the message only\n return new WebGpuGraphError(\"E_OUT_OF_MEMORY\", `uncaptured out-of-memory error on \"${label}\": ${message}`, {\n requested: 0,\n resident: 0,\n label,\n });\n }\n return new WebGpuGraphError(\"E_VALIDATION\", `uncaptured validation error on \"${label}\": ${message}`, {\n label,\n message,\n });\n}\n\n/**\n * Installs the uncapturederror listener: each event becomes E_VALIDATION { label, message } (or\n * E_OUT_OF_MEMORY for GPUOutOfMemoryError) routed to `onError`, else stored in `slot`. Returns the\n * uninstaller. `label` is the device's label (the descriptor label create() gave it).\n * @param device - the device to listen on\n * @param slot - where errors go when no sink is given\n * @param onError - the caller's sink, or null\n * @returns a function that removes the listener\n */\nexport function installUncapturedErrorSink(\n device: GPUDevice,\n slot: PendingErrorSlot,\n onError: ((error: WebGpuGraphError) => void) | null,\n): () => void {\n let installed = true;\n const label = device.label ?? \"\";\n const listener = (event: GPUUncapturedErrorEvent): void => {\n if (!installed) {\n return;\n }\n const wrapped = uncapturedError(event.error, label);\n if (onError !== null) {\n onError(wrapped);\n } else {\n slot.set(wrapped);\n }\n };\n device.addEventListener(\"uncapturederror\", listener);\n return () => {\n installed = false;\n if (typeof device.removeEventListener === \"function\") {\n device.removeEventListener(\"uncapturederror\", listener);\n }\n };\n}\n\n/**\n * Chains device.lost into `onLost` exactly once; returns the promise the context exposes as `ctx.lost`.\n * @param device - the device whose loss is watched\n * @param onLost - called once with the lost info\n * @returns the lost info, after `onLost` ran\n */\nexport function watchDeviceLost(\n device: GPUDevice,\n onLost: (info: GPUDeviceLostInfo) => void,\n): Promise<GPUDeviceLostInfo> {\n let delivered = false;\n return device.lost.then((info) => {\n if (!delivered) {\n delivered = true;\n onLost(info);\n }\n return info;\n });\n}\n\n/**\n * The E_DEVICE_LOST error for a lost-info record.\n * @param info - the device.lost result\n * @returns E_DEVICE_LOST { reason, message }\n */\nexport function deviceLostError(info: GPUDeviceLostInfo): WebGpuGraphError {\n return new WebGpuGraphError(\"E_DEVICE_LOST\", `device lost (${info.reason}): ${info.message}`, {\n reason: info.reason,\n message: info.message,\n });\n}\n","/**\n * Kernel (spec 5.1; contract 3.9): a compiled pipeline bound to the binding list of its spec. `bind()` creates the\n * bind groups from a `Record<name, Binding>` keyed by the declared names and caches them by the identity of the\n * buffers, offsets and sizes (a layout's bind groups are created once per load(), not per iteration); `dispatch()`\n * records setPipeline / setBindGroup / dispatchWorkgroups and skips an empty plan (spec 5.6); `dispatchIndirect()`\n * (P4, spec 5.4) records the same prefix and a dispatchWorkgroupsIndirect over one 16-byte slot of an args buffer.\n */\n\nimport { STORAGE_ALIGN } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type DispatchPlan } from \"./dispatch.js\";\nimport { type BindingDecl, type ComposedModule, type WgslModuleSpec } from \"./wgsl.js\";\n\n/** The resources of one bind(): one Binding per BindingDecl name; a uniform decl takes the ring's whole-buffer binding (the slot is chosen by the dynamic offset at dispatch). */\nexport type KernelBindings = Readonly<Record<string, Binding>>;\n/** A kernel with its bind groups created (spec 5.1: cached per set of buffers and offsets). */\nexport interface BoundKernel {\n readonly kernel: Kernel;\n readonly bindGroups: readonly GPUBindGroup[];\n /** Group indices whose bind group takes a dynamic offset (the uniform groups), in group order. */\n readonly dynamicGroups: readonly number[];\n}\n\n/** Bytes of one indirect args slot: (x, y, 1, count) as four u32 (spec 5.4; P4 PD-2). */\nexport const INDIRECT_ARGS_STRIDE = 16;\n\n/**\n * The most buffer sets one Kernel keeps bind groups for; binding one more forgets the least recently bound. A\n * Kernel lives as long as its context (the PipelineCache holds it), so an unbounded cache kept the bind groups --\n * and, on Dawn, the native memory behind them -- of every simulation and scratch lease ever bound, disposed or not\n * (issue #162). A caller keeps the BoundKernel it was given, so eviction only costs a later bind() of the same\n * buffers a new createBindGroup. One simulation binds at most a dozen sets per kernel (the scan's levels).\n * ponytail: a count bound, not a lifetime one; a per-buffer destroy hook would free a set as soon as its buffer goes.\n */\nexport const BIND_GROUP_CACHE_LIMIT = 32;\n\n/** Buffer identities for the bind-group cache key: every GPUBuffer seen by any Kernel gets one number, once. */\nconst bufferIds = new WeakMap<GPUBuffer, number>();\nlet nextBufferId = 1;\n\n/**\n * The identity number of a buffer.\n * @param buffer - the buffer\n * @returns its number\n */\nfunction bufferId(buffer: GPUBuffer): number {\n let id = bufferIds.get(buffer);\n if (id === undefined) {\n id = nextBufferId;\n nextBufferId += 1;\n bufferIds.set(buffer, id);\n }\n return id;\n}\n\n/**\n * True when two byte ranges intersect.\n * @param a - one binding\n * @param b - the other binding\n * @returns whether [a.offset, a.offset + a.size) and [b.offset, b.offset + b.size) overlap\n */\nfunction rangesIntersect(a: Binding, b: Binding): boolean {\n return a.offset < b.offset + b.size && b.offset < a.offset + a.size;\n}\n\n/** A compiled pipeline plus the binding list of its spec (spec 5.1). */\nexport class Kernel {\n /** The module spec the pipeline was compiled from (its bindings drive bind()). */\n readonly spec: WgslModuleSpec;\n /** The compiled compute pipeline. */\n readonly pipeline: GPUComputePipeline;\n /** The explicit bind group layouts, one per group index (an empty layout for an unused index). */\n readonly layouts: readonly GPUBindGroupLayout[];\n /** The workgroup size the pipeline was compiled with (the effective WG override). */\n readonly workgroupSize: number;\n /** The entry point name the pipeline was compiled with. */\n readonly entryPoint: string;\n private readonly device: GPUDevice;\n /** The declarations of each group in binding order (index = group). */\n private readonly groups: readonly (readonly BindingDecl[])[];\n /** The uniform-binding count of each group (the dynamic offsets a setBindGroup takes). */\n private readonly dynamicCounts: readonly number[];\n /** Cached bind groups by buffer identity + offset + size, least recently bound first (at most BIND_GROUP_CACHE_LIMIT). */\n private readonly cache = new Map<string, BoundKernel>();\n\n /**\n * Wraps a compiled pipeline.\n * @param device - the device the bind groups are created on\n * @param spec - the module\n * @param composed - the composed text (workgroup size and entry point)\n * @param pipeline - the compiled pipeline\n * @param layouts - the explicit bind-group layouts, one per group 0..maxGroup\n */\n constructor(\n device: GPUDevice,\n spec: WgslModuleSpec,\n composed: ComposedModule,\n pipeline: GPUComputePipeline,\n layouts: readonly GPUBindGroupLayout[],\n ) {\n this.device = device;\n this.spec = spec;\n this.pipeline = pipeline;\n this.layouts = layouts;\n this.workgroupSize = composed.overrides.WG as number;\n this.entryPoint = composed.entryPoint;\n const groups: BindingDecl[][] = layouts.map(() => []);\n for (const decl of spec.bindings) {\n groups[decl.group].push(decl);\n }\n for (const group of groups) {\n group.sort((a, b) => a.binding - b.binding);\n }\n this.groups = groups;\n this.dynamicCounts = groups.map((group) => group.filter((decl) => decl.kind === \"uniform\").length);\n }\n\n /**\n * Creates (or reuses, keyed by every buffer identity + offset + size) the bind groups, each labelled\n * `<spec.id>/<group>`; a missing or extra name is E_INVALID_ARGUMENT; two bindings of one call whose ranges\n * intersect on one buffer while either slot is `storage` (read_write) is E_INVALID_ARGUMENT\n * { argument: \"aliasing\" } (the host-side mirror of WebGPU's writable buffer-binding-aliasing rule, 3.10.1, so\n * the failure is synchronous and labelled). CONTRACT DECISION: bind() is synchronous, so a createBindGroup\n * validation error (a wrong-size uniform binding, a usage mismatch) is NOT thrown here -- it reaches the\n * pending-error slot as E_VALIDATION { label: \"<spec.id>/<group>\" } and is thrown by the batch's readback\n * (Dawn-node) or the next assertReady() (browser), spec 5.7. An empty bind group is created for every empty\n * layout index so setBindGroup is called for 0..maxGroup.\n * PLAN DECISION (verified on Dawn 0.4.0 / lavapipe): one buffer bound with two DIFFERENT access modes when one is\n * `storage` is also E_INVALID_ARGUMENT { argument: \"aliasing\", reason: \"usage\" } even with disjoint ranges, because\n * WebGPU's usage-scope rule rejects \"writable usage and another usage in the same synchronization scope\" per\n * BUFFER; two `storage` slots with disjoint ranges (the state header / trace pattern) are accepted; a zero-size\n * binding (never bind a zero-length buffer, spec 3.6) and an offset that is not a multiple of STORAGE_ALIGN = 256\n * (spec 2.6; Dawn: \"does not satisfy the minimum ... alignment (256)\") are E_INVALID_ARGUMENT.\n * @param resources - one Binding per declared name\n * @returns the bound kernel (the same object for the same buffers, offsets and sizes until invalidate())\n */\n bind(resources: KernelBindings): BoundKernel {\n const { id } = this.spec;\n const declared = new Map(this.spec.bindings.map((decl) => [decl.name, decl] as const));\n for (const name of Object.keys(resources)) {\n if (!declared.has(name)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${id}: no binding named \"${name}\"`, {\n argument: \"bindings\",\n value: name,\n expected: [...declared.keys()].join(\", \"),\n });\n }\n }\n const resolved: { readonly decl: BindingDecl; readonly binding: Binding }[] = [];\n for (const decl of this.spec.bindings) {\n const binding = resources[decl.name] as Binding | undefined;\n if (binding === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${id}: binding \"${decl.name}\" is missing`, {\n argument: \"bindings\",\n value: decl.name,\n expected: \"a Binding for every declared name\",\n });\n }\n if (!(Number.isInteger(binding.size) && binding.size > 0)) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${id}: binding \"${decl.name}\" has size ${binding.size}`,\n {\n argument: decl.name,\n value: binding.size,\n expected: \"size > 0 (a zero-length buffer is never bound)\",\n },\n );\n }\n if (!(Number.isInteger(binding.offset) && binding.offset >= 0 && binding.offset % STORAGE_ALIGN === 0)) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${id}: binding \"${decl.name}\" has offset ${binding.offset}`,\n {\n argument: decl.name,\n value: binding.offset,\n expected: `a multiple of ${STORAGE_ALIGN} (spec 2.6: the offset alignment the package always honours)`,\n },\n );\n }\n resolved.push({ decl, binding });\n }\n for (let i = 0; i < resolved.length; i++) {\n for (let j = i + 1; j < resolved.length; j++) {\n const a = resolved[i];\n const b = resolved[j];\n if (a.binding.buffer !== b.binding.buffer) {\n continue;\n }\n const writable = a.decl.kind === \"storage\" || b.decl.kind === \"storage\";\n if (!writable) {\n continue;\n }\n if (a.decl.kind !== b.decl.kind) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${id}: \"${a.decl.name}\" and \"${b.decl.name}\" bind one buffer with different access modes (writable usage next to another usage)`,\n {\n argument: \"aliasing\",\n value: [a.decl.name, b.decl.name],\n expected: \"one access mode per buffer when a slot is read_write\",\n reason: \"usage\",\n },\n );\n }\n if (rangesIntersect(a.binding, b.binding)) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${id}: \"${a.decl.name}\" and \"${b.decl.name}\" bind intersecting ranges of one read_write buffer`,\n {\n argument: \"aliasing\",\n value: [a.decl.name, b.decl.name],\n expected: \"disjoint ranges\",\n reason: \"range\",\n },\n );\n }\n }\n }\n const key = resolved\n .map(({ binding }) => `${bufferId(binding.buffer)}:${binding.offset}:${binding.size}`)\n .join(\"|\");\n const cached = this.cache.get(key);\n if (cached !== undefined) {\n // re-insert: the Map's insertion order is the recency order the eviction below reads\n this.cache.delete(key);\n this.cache.set(key, cached);\n return cached;\n }\n const byName = new Map(resolved.map(({ decl, binding }) => [decl.name, binding] as const));\n const bindGroups = this.layouts.map((layout, group) =>\n this.device.createBindGroup({\n label: `${id}/${group}`,\n layout,\n entries: this.groups[group].map((decl) => {\n const binding = byName.get(decl.name) as Binding;\n return {\n binding: decl.binding,\n resource: { buffer: binding.buffer, offset: binding.offset, size: binding.size },\n };\n }),\n }),\n );\n const dynamicGroups: number[] = [];\n this.dynamicCounts.forEach((count, group) => {\n if (count > 0) {\n dynamicGroups.push(group);\n }\n });\n const bound: BoundKernel = Object.freeze({\n kernel: this,\n bindGroups: Object.freeze(bindGroups),\n dynamicGroups: Object.freeze(dynamicGroups),\n });\n this.cache.set(key, bound);\n if (this.cache.size > BIND_GROUP_CACHE_LIMIT) {\n this.cache.delete(this.cache.keys().next().value as string);\n }\n return bound;\n }\n\n /**\n * setPipeline + setBindGroup for every group (dynamic offsets in dynamicGroups order) + dispatchWorkgroups(plan.x, plan.y, plan.z); a plan with x === 0 records nothing (spec 5.6).\n * PLAN DECISION: one dynamic offset per dynamic GROUP, replicated over every uniform binding of that group (every\n * P1-P3 kernel has exactly one params uniform per group); absent offsets mean 0; a BoundKernel of another kernel\n * or an offset list of the wrong length is E_INVALID_ARGUMENT.\n * PLAN DECISION: `dynamicOffsets?` is spelled `?: readonly number[]` rather than the contract's\n * `?: readonly number[] | undefined` because the root ESLint rule no-duplicate-type-constituents rejects the\n * explicit undefined on an optional parameter (the call signature is identical).\n * @param pass - the open compute pass\n * @param bound - a BoundKernel of THIS kernel\n * @param plan - the dispatch shape\n * @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups\n */\n dispatch(\n pass: GPUComputePassEncoder,\n bound: BoundKernel,\n plan: DispatchPlan,\n dynamicOffsets?: readonly number[],\n ): void {\n this.check(bound, dynamicOffsets);\n if (plan.x === 0) {\n return;\n }\n this.setUp(pass, bound, dynamicOffsets);\n pass.dispatchWorkgroups(plan.x, plan.y, plan.z);\n }\n\n /**\n * setPipeline + the bind groups exactly as dispatch(), then dispatchWorkgroupsIndirect(args.buffer, args.offset +\n * INDIRECT_ARGS_STRIDE * slot) (spec 5.4): the (x, y, 1) of the slot were written by the indirect-finalize kernel\n * earlier in the same pass. A slot beyond the binding is E_INVALID_ARGUMENT.\n * @param pass - the open compute pass\n * @param bound - a BoundKernel of THIS kernel\n * @param args - the args buffer range (usage INDIRECT | STORAGE)\n * @param slot - the 16-byte slot index inside the range\n * @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups\n */\n dispatchIndirect(\n pass: GPUComputePassEncoder,\n bound: BoundKernel,\n args: Binding,\n slot: number,\n dynamicOffsets?: readonly number[],\n ): void {\n this.check(bound, dynamicOffsets);\n if (!Number.isInteger(slot) || slot < 0 || (slot + 1) * INDIRECT_ARGS_STRIDE > args.size) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${this.spec.id}: args slot ${slot} is outside the binding`,\n {\n argument: \"slot\",\n value: slot,\n expected: `0 <= slot < ${Math.floor(args.size / INDIRECT_ARGS_STRIDE)}`,\n },\n );\n }\n this.setUp(pass, bound, dynamicOffsets);\n pass.dispatchWorkgroupsIndirect(args.buffer, args.offset + INDIRECT_ARGS_STRIDE * slot);\n }\n\n /**\n * The argument checks dispatch() and dispatchIndirect() share: a BoundKernel of another kernel or an offset list\n * of the wrong length is E_INVALID_ARGUMENT.\n * @param bound - the bound kernel\n * @param dynamicOffsets - the offsets, if any\n */\n private check(bound: BoundKernel, dynamicOffsets: readonly number[] | undefined): void {\n const { id } = this.spec;\n if (bound.kernel !== this) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${id}: the bound kernel belongs to \"${bound.kernel.spec.id}\"`,\n {\n argument: \"bound\",\n value: bound.kernel.spec.id,\n expected: id,\n },\n );\n }\n if (dynamicOffsets !== undefined && dynamicOffsets.length !== bound.dynamicGroups.length) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${id}: ${dynamicOffsets.length} dynamic offsets for ${bound.dynamicGroups.length} dynamic groups`,\n {\n argument: \"dynamicOffsets\",\n value: dynamicOffsets.length,\n expected: bound.dynamicGroups.length,\n },\n );\n }\n }\n\n /**\n * setPipeline + setBindGroup for every group (the dynamic offsets replicated over the uniform bindings of each\n * dynamic group), the prefix dispatch() and dispatchIndirect() share.\n * @param pass - the open compute pass\n * @param bound - a BoundKernel of this kernel\n * @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups (absent = 0)\n */\n private setUp(\n pass: GPUComputePassEncoder,\n bound: BoundKernel,\n dynamicOffsets: readonly number[] | undefined,\n ): void {\n pass.setPipeline(this.pipeline);\n let next = 0;\n bound.bindGroups.forEach((bindGroup, group) => {\n const count = this.dynamicCounts[group];\n if (count > 0) {\n const offset = dynamicOffsets?.[next] ?? 0;\n next += 1;\n const offsets: number[] = [];\n for (let k = 0; k < count; k++) {\n offsets.push(offset);\n }\n pass.setBindGroup(group, bindGroup, offsets);\n } else {\n pass.setBindGroup(group, bindGroup);\n }\n });\n }\n\n /** Drops cached bind groups (a layout's buffers changed). */\n invalidate(): void {\n this.cache.clear();\n }\n}\n","/**\n * GPUBufferUsage / GPUMapMode / GPUShaderStage as numbers (spec 2.1 rule 1; contract 3.4): under Dawn-node the\n * global namespaces do not exist until `Object.assign(globalThis, dawn.globals)` has run, so the core never reads\n * them at module top level and keeps its own copies here. Each field names the WebGPU spec constant it mirrors;\n * test/device/constants.test.ts compares every field with the runtime globals so a drift is caught.\n */\n\n/** GPUBufferUsage bits as numbers so the core never reads the global at module top level (spec 2.1 rule 1). */\nexport const BufferUsage: Readonly<{\n MAP_READ: 0x0001;\n MAP_WRITE: 0x0002;\n COPY_SRC: 0x0004;\n COPY_DST: 0x0008;\n INDEX: 0x0010;\n VERTEX: 0x0020;\n UNIFORM: 0x0040;\n STORAGE: 0x0080;\n INDIRECT: 0x0100;\n QUERY_RESOLVE: 0x0200;\n}> = Object.freeze({\n MAP_READ: 0x0001, // GPUBufferUsage.MAP_READ\n MAP_WRITE: 0x0002, // GPUBufferUsage.MAP_WRITE\n COPY_SRC: 0x0004, // GPUBufferUsage.COPY_SRC\n COPY_DST: 0x0008, // GPUBufferUsage.COPY_DST\n INDEX: 0x0010, // GPUBufferUsage.INDEX\n VERTEX: 0x0020, // GPUBufferUsage.VERTEX\n UNIFORM: 0x0040, // GPUBufferUsage.UNIFORM\n STORAGE: 0x0080, // GPUBufferUsage.STORAGE\n INDIRECT: 0x0100, // GPUBufferUsage.INDIRECT\n QUERY_RESOLVE: 0x0200, // GPUBufferUsage.QUERY_RESOLVE\n});\n\n/** GPUMapMode bits. */\nexport const MapMode: Readonly<{ READ: 0x0001; WRITE: 0x0002 }> = Object.freeze({\n READ: 0x0001, // GPUMapMode.READ\n WRITE: 0x0002, // GPUMapMode.WRITE\n});\n\n/** GPUShaderStage bits. */\nexport const ShaderStage: Readonly<{ VERTEX: 0x1; FRAGMENT: 0x2; COMPUTE: 0x4 }> = Object.freeze({\n VERTEX: 0x1, // GPUShaderStage.VERTEX\n FRAGMENT: 0x2, // GPUShaderStage.FRAGMENT\n COMPUTE: 0x4, // GPUShaderStage.COMPUTE\n});\n","/**\n * The WGSL prelude every composed module receives first (contract 4.1), the two reduction-helper blocks the\n * composer splices for a body whose spec lists `needs: [\"subgroups\"]` (contract 4.3, D16), and the WGSL\n * reserved-word list the composer rejects identifiers from (contract 3.9).\n *\n * CONTRACT DECISION (3.9): this text lives in the kernel layer, not in `src/wgsl/`, because the composer must own\n * what it splices and `src/wgsl/` then holds kernel BODIES only. Every numeric constant is interpolated from\n * `constants.ts` and graph-format's `INVALID_INDEX`; the literal-grep test of spec 3.5 (`test/kernel/wgsl.test.ts`)\n * covers this file's template, so no u32 sentinel or workgroup-size literal is ever typed here.\n */\n\nimport { INVALID_INDEX } from \"@graphty/graph-format\";\n\nimport {\n APSP_TILE,\n BC_SIGMA_EXPONENT_CAP,\n EXACT_TILES_PER_PASS,\n F32_INF_BITS,\n F32_SIGN_BIT,\n FA2_COINCIDENT_SQ,\n FA2_DISTANCE_FLOOR,\n FA2_DISTANCE_FLOOR_SQ,\n FA2_FLAG_ADAPTIVE,\n FA2_FLAG_FIRST,\n FR_COOLING_PATIENCE,\n FR_COOLING_STEP,\n GRID_BBOX_MARGIN,\n GRID_EXTENT_FLOOR,\n GRID_HUB_CELL,\n GROUP_HASH_LOAD_FACTOR,\n MAX_WORKGROUPS_PER_DIM,\n RADIX_BINS,\n TRIANGLE_BINARY_SEARCH_RATIO,\n U32_MAX,\n WORKGROUP_SIZE,\n} from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\n\n/**\n * Formats a finite number as a WGSL f32 literal that always carries a decimal point or an exponent (`0.01`,\n * `1e-8`, `2.0`), so an integral value never becomes an abstract-int literal (contract 4.1).\n * @param value - the number to format\n * @returns the literal text\n */\nexport function wgslF32Literal(value: number): string {\n if (!Number.isFinite(value)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `wgslF32Literal: ${value} is not a finite number`, {\n argument: \"value\",\n value,\n expected: \"a finite number\",\n });\n }\n const text = String(value);\n return /[.e]/.test(text) ? text : `${text}.0`;\n}\n\n/** The prelude text with the constants interpolated from constants.ts and graph-format's INVALID_INDEX (4.1). */\nexport const PRELUDE_WGSL: string = /* wgsl */ `// ---- prelude: constants, standard overrides, helpers (every module receives this text first)\nconst INVALID_INDEX: u32 = ${INVALID_INDEX}u;\nconst U32_MAX: u32 = ${U32_MAX}u;\nconst F32_INF_BITS: u32 = ${F32_INF_BITS}u;\nconst F32_SIGN_BIT: u32 = ${F32_SIGN_BIT}u;\nconst MAX_WORKGROUPS_PER_DIM: u32 = ${MAX_WORKGROUPS_PER_DIM}u;\nconst EXACT_TILES_PER_PASS: u32 = ${EXACT_TILES_PER_PASS}u;\nconst FA2_DIST_FLOOR: f32 = ${wgslF32Literal(FA2_DISTANCE_FLOOR)};\nconst FA2_DIST_FLOOR_SQ: f32 = ${wgslF32Literal(FA2_DISTANCE_FLOOR_SQ)};\nconst FA2_COINCIDENT_SQ: f32 = ${wgslF32Literal(FA2_COINCIDENT_SQ)};\nconst FA2_FLAG_FIRST: u32 = ${FA2_FLAG_FIRST}u;\nconst FA2_FLAG_ADAPTIVE: u32 = ${FA2_FLAG_ADAPTIVE}u;\nconst FR_COOLING_STEP: f32 = ${wgslF32Literal(FR_COOLING_STEP)};\nconst FR_COOLING_PATIENCE: u32 = ${FR_COOLING_PATIENCE}u;\nconst GRID_HUB_CELL: u32 = ${GRID_HUB_CELL}u;\nconst GRID_EXTENT_FLOOR: f32 = ${wgslF32Literal(GRID_EXTENT_FLOOR)};\nconst GRID_BBOX_MARGIN: f32 = ${wgslF32Literal(GRID_BBOX_MARGIN)};\nconst RADIX_BINS: u32 = ${RADIX_BINS}u;\nconst RADIX_DIGIT_MASK: u32 = ${RADIX_BINS - 1}u;\nconst APSP_TILE: u32 = ${APSP_TILE}u;\nconst GROUP_HASH_LOAD_FACTOR: u32 = ${GROUP_HASH_LOAD_FACTOR}u;\nconst TRIANGLE_BINARY_SEARCH_RATIO: u32 = ${TRIANGLE_BINARY_SEARCH_RATIO}u;\nconst BC_SIGMA_EXPONENT_CAP: i32 = ${BC_SIGMA_EXPONENT_CAP}i;\nconst F32_MAX: f32 = 0x1.fffffep+127;\noverride WG: u32 = ${WORKGROUP_SIZE}u;\noverride USE_PERM: bool = false;\noverride HAS_WEIGHTS: bool = false;\noverride SUBGROUP_MIN: u32 = 4u;\noverride SUBGROUP_MAX: u32 = 0u;\n\nfn linear_id(wid: vec3<u32>, lid: u32) -> u32 { return (wid.x + wid.y * MAX_WORKGROUPS_PER_DIM) * WG + lid; }\nfn group_id(wid: vec3<u32>) -> u32 { return wid.x + wid.y * MAX_WORKGROUPS_PER_DIM; }\n// betweenness: the power of two the counts of depth L + 1 are divided by, from the f32 bits of depth L's largest count\nfn sigma_shift(maxBits: u32) -> i32 { return max(0i, i32((maxBits >> 23u) & 0xffu) - 127i - BC_SIGMA_EXPONENT_CAP); }\nfn lowbias32(x0: u32) -> u32 {\n var x = x0;\n x = x ^ (x >> 16u);\n x = x * 0x7feb352du;\n x = x ^ (x >> 15u);\n x = x * 0x846ca68bu;\n x = x ^ (x >> 16u);\n return x;\n}\nfn mask_bit(w: u32, i: u32) -> bool { return ((w >> (i & 31u)) & 1u) == 1u; }\nfn unpack_u8(w: u32, i: u32) -> u32 { return (w >> (8u * (i & 3u))) & 0xFFu; }\nfn pair_hash(i: u32, j: u32) -> u32 { return lowbias32((min(i, j) * 0x9E3779B9u) ^ max(i, j)); }\nfn order_key(w: f32) -> u32 {\n let raw = bitcast<u32>(w);\n let bits = select(raw, 0u, raw == F32_SIGN_BIT);\n return select(bits | F32_SIGN_BIT, ~bits, (bits & F32_SIGN_BIT) != 0u);\n}\nfn hash_unit(h: u32) -> f32 { return f32(h >> 8u) * (1.0 / 16777216.0); }\nfn hash_dir(h: u32, dim: u32) -> vec3f {\n let phi = 6.283185307179586 * hash_unit(h);\n if (dim == 2u) { return vec3f(cos(phi), sin(phi), 0.0); }\n let z = 2.0 * hash_unit(lowbias32(h ^ 0x5bd1e995u)) - 1.0;\n let r = sqrt(max(0.0, 1.0 - z * z));\n return vec3f(r * cos(phi), r * sin(phi), z);\n}\nfn kick_dir(i: u32, j: u32, dim: u32) -> vec3f {\n let d = hash_dir(pair_hash(i, j), dim);\n return select(d, -d, i > j);\n}`;\n\n/** Line count of PRELUDE_WGSL (the compilation-info formatter subtracts it plus the emitted declarations). */\nexport const PRELUDE_LINES: number = PRELUDE_WGSL.split(\"\\n\").length;\n\n/** The workgroup-memory reduction helpers (the twin) (4.3), plus the workgroup-memory form of the P8 scan helper. */\nexport const REDUCE_HELPERS_WORKGROUP_WGSL: string = /* wgsl */ `var<workgroup> wg_scratch_v: array<vec4f, WG>;\nvar<workgroup> wg_scratch_u: array<u32, WG>;\nfn combine_v(a: vec4f, b: vec4f, op: u32) -> vec4f {\n if (op == 1u) { return min(a, b); }\n if (op == 2u) { return max(a, b); }\n return a + b;\n}\nfn combine_u(a: u32, b: u32, op: u32) -> u32 {\n if (op == 1u) { return min(a, b); }\n if (op == 2u) { return max(a, b); }\n return a + b;\n}\nfn wg_reduce_vec4(v: vec4f, lid: u32, op: u32) -> vec4f {\n workgroupBarrier();\n wg_scratch_v[lid] = v;\n workgroupBarrier();\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\n if (lid < s) { wg_scratch_v[lid] = combine_v(wg_scratch_v[lid], wg_scratch_v[lid + s], op); }\n workgroupBarrier();\n }\n let total = wg_scratch_v[0];\n workgroupBarrier();\n return total;\n}\nfn wg_reduce_u32(v: u32, lid: u32, op: u32) -> u32 {\n workgroupBarrier();\n wg_scratch_u[lid] = v;\n workgroupBarrier();\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\n if (lid < s) { wg_scratch_u[lid] = combine_u(wg_scratch_u[lid], wg_scratch_u[lid + s], op); }\n workgroupBarrier();\n }\n let total = wg_scratch_u[0];\n workgroupBarrier();\n return total;\n}\nfn wg_scan_u32(v: u32, lid: u32) -> u32 {\n workgroupBarrier();\n wg_scratch_u[lid] = v;\n workgroupBarrier();\n for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan (scan-block's body); uniform: every lane runs every round\n var t = 0u;\n if (lid >= s) { t = wg_scratch_u[lid - s]; }\n workgroupBarrier();\n wg_scratch_u[lid] = wg_scratch_u[lid] + t;\n workgroupBarrier();\n }\n let inclusive = wg_scratch_u[lid];\n workgroupBarrier(); // the scratch is free for the next call\n return inclusive;\n}\nfn wg_reduce_f32(v: f32, lid: u32, op: u32) -> f32 { return wg_reduce_vec4(vec4f(v, 0.0, 0.0, 0.0), lid, op).x; }`;\n\n/** The subgroup reduction helpers, spliced only with `enable subgroups;` (4.3), plus the subgroup form of the P8 scan helper. */\nexport const REDUCE_HELPERS_SUBGROUP_WGSL: string = /* wgsl */ `override SG_SLOTS: u32 = (WG + SUBGROUP_MIN - 1u) / SUBGROUP_MIN; // one slot per subgroup; the count is largest when the compiler picks the SMALLEST size\nvar<workgroup> sg_counter: atomic<u32>;\nvar<workgroup> sg_val_v: array<vec4f, SG_SLOTS>;\nvar<workgroup> sg_val_u: array<u32, SG_SLOTS>;\nvar<workgroup> sg_key: array<u32, SG_SLOTS>;\nvar<workgroup> sg_sorted_v: array<vec4f, SG_SLOTS>;\nvar<workgroup> sg_sorted_u: array<u32, SG_SLOTS>;\nfn combine_v(a: vec4f, b: vec4f, op: u32) -> vec4f {\n if (op == 1u) { return min(a, b); }\n if (op == 2u) { return max(a, b); }\n return a + b;\n}\nfn combine_u(a: u32, b: u32, op: u32) -> u32 {\n if (op == 1u) { return min(a, b); }\n if (op == 2u) { return max(a, b); }\n return a + b;\n}\nfn wg_reduce_vec4(v: vec4f, lid: u32, op: u32) -> vec4f {\n workgroupBarrier();\n if (lid == 0u) { atomicStore(&sg_counter, 0u); }\n workgroupBarrier();\n let s_add = subgroupAdd(v);\n let s_min = subgroupMin(v);\n let s_max = subgroupMax(v);\n var partial = s_add;\n if (op == 1u) { partial = s_min; }\n if (op == 2u) { partial = s_max; }\n let key = subgroupMin(lid); // the smallest local id of this subgroup: a stable identity without @builtin(subgroup_id)\n var slot = 0u;\n if (subgroupElect()) { slot = atomicAdd(&sg_counter, 1u); } // D16: the elected lane takes a slot from the counter\n slot = subgroupBroadcast(slot, 0u); // and broadcasts it (lane 0 is the elected lane in uniform control flow)\n if (subgroupElect()) { sg_val_v[slot] = partial; sg_key[slot] = key; }\n workgroupBarrier();\n let count = atomicLoad(&sg_counter);\n if (lid < count) { // rank the slots by key so the final sum has a fixed order (11.9 item 4)\n let mine = sg_key[lid];\n var rank = 0u;\n for (var k = 0u; k < count; k = k + 1u) { if (sg_key[k] < mine) { rank = rank + 1u; } }\n sg_sorted_v[rank] = sg_val_v[lid];\n }\n workgroupBarrier();\n var total = sg_sorted_v[0];\n for (var k = 1u; k < count; k = k + 1u) { total = combine_v(total, sg_sorted_v[k], op); }\n workgroupBarrier();\n return total;\n}\nfn wg_reduce_u32(v: u32, lid: u32, op: u32) -> u32 {\n workgroupBarrier();\n if (lid == 0u) { atomicStore(&sg_counter, 0u); }\n workgroupBarrier();\n let s_add = subgroupAdd(v);\n let s_min = subgroupMin(v);\n let s_max = subgroupMax(v);\n var partial = s_add;\n if (op == 1u) { partial = s_min; }\n if (op == 2u) { partial = s_max; }\n let key = subgroupMin(lid);\n var slot = 0u;\n if (subgroupElect()) { slot = atomicAdd(&sg_counter, 1u); }\n slot = subgroupBroadcast(slot, 0u);\n if (subgroupElect()) { sg_val_u[slot] = partial; sg_key[slot] = key; }\n workgroupBarrier();\n let count = atomicLoad(&sg_counter);\n if (lid < count) {\n let mine = sg_key[lid];\n var rank = 0u;\n for (var k = 0u; k < count; k = k + 1u) { if (sg_key[k] < mine) { rank = rank + 1u; } }\n sg_sorted_u[rank] = sg_val_u[lid];\n }\n workgroupBarrier();\n var total = sg_sorted_u[0];\n for (var k = 1u; k < count; k = k + 1u) { total = combine_u(total, sg_sorted_u[k], op); }\n workgroupBarrier();\n return total;\n}\nfn wg_scan_u32(v: u32, lid: u32) -> u32 {\n workgroupBarrier();\n if (lid == 0u) { atomicStore(&sg_counter, 0u); }\n workgroupBarrier();\n let inSub = subgroupExclusiveAdd(v) + v; // the lane's inclusive sum within its subgroup\n let total = subgroupAdd(v);\n let key = subgroupMin(lid); // the subgroup's identity: its smallest local id (D16)\n var slot = 0u;\n if (subgroupElect()) { slot = atomicAdd(&sg_counter, 1u); }\n slot = subgroupBroadcast(slot, 0u);\n if (subgroupElect()) { sg_val_u[slot] = total; sg_key[slot] = key; }\n workgroupBarrier();\n let count = atomicLoad(&sg_counter);\n var carry = 0u; // the totals of every subgroup whose key is below this lane's: LANE order, whatever order the slots were taken in\n for (var k = 0u; k < count; k = k + 1u) { if (sg_key[k] < key) { carry = carry + sg_val_u[k]; } }\n workgroupBarrier(); // the slots are free for the next call\n return inSub + carry;\n}\nfn wg_reduce_f32(v: f32, lid: u32, op: u32) -> f32 { return wg_reduce_vec4(vec4f(v, 0.0, 0.0, 0.0), lid, op).x; }`;\n\n/** The helper function names a body may call when its spec lists needs: [\"subgroups\"]; `wg_scan_u32(v, lid)` is an INCLUSIVE prefix sum over the workgroup in lane order (P8-T1), bitwise the same in both forms. */\nexport const REDUCE_HELPER_NAMES = [\"wg_reduce_f32\", \"wg_reduce_u32\", \"wg_reduce_vec4\", \"wg_scan_u32\"] as const;\n\n/**\n * The WGSL reserved words of spec section 16.2 (the `_reserved` production), frozen; composeWgsl rejects a body or\n * snippet that uses one (3.9). PLAN DECISION: the list is the 146 words of the W3C Candidate Recommendation Draft\n * of 2026-08-31 (identical to the editor's draft of 2026-09-01); the contract's count of 147 predates the removal\n * of `binding_array`. `free`, `valid`, `tile`, `slot`, `key` and `count` are NOT reserved.\n */\nexport const WGSL_RESERVED_WORDS: readonly string[] = Object.freeze(\n `NULL Self abstract active alignas alignof as asm asm_fragment async attribute auto await become cast catch class\n co_await co_return co_yield coherent column_major common compile compile_fragment concept const_cast consteval\n constexpr constinit crate debugger decltype delete demote demote_to_helper do dynamic_cast enum explicit export\n extends extern external fallthrough filter final finally friend from fxgroup get goto groupshared highp impl\n implements import inline instanceof interface layout lowp macro macro_rules match mediump meta mod module move\n mut mutable namespace new nil noexcept noinline nointerpolation non_coherent noncoherent noperspective null\n nullptr of operator package packoffset partition pass patch pixelfragment precise precision premerge priv\n protected pub public readonly ref regardless register reinterpret_cast require resource restrict self set shared\n sizeof smooth snorm static static_assert static_cast std subroutine super target template this thread_local\n throw trait try type typedef typeid typename typeof union unless unorm unsafe unsized use using varying virtual\n volatile wgsl where with writeonly yield`\n .trim()\n .split(/\\s+/),\n);\n","/**\n * The WGSL composer (spec 3.5; contract 3.9, 4.2): ONE declaration per module (`WgslModuleSpec`) generates\n * everything the host and the shader must agree on -- the `@group / @binding` block, the `override` lines, the\n * struct texts, the explicit bind-group layouts and the bind() record keys -- by string concatenation in the fixed\n * order of contract 4.2. Every disagreement that would otherwise be a GPUPipelineError on the first device that\n * creates the variant is a compose-time `E_SHADER_COMPILE { stage: \"compose\" }` on every device.\n *\n * PLAN DECISION: this file imports `workgroupSizeFor` from `../device/caps.js` (one copy of the WG rule) and\n * `ShaderStage` from `../device/webgpu-constants.js` (spec 2.1 rule 1: the core never reads the `GPUShaderStage`\n * global at module top level); `../constants.js` is not imported because every constant the composer emits reaches\n * it through `./prelude.js`. The layer rule (contract 2.4: device < context < memory < kernel) allows both edges.\n */\n\nimport { workgroupSizeFor } from \"../device/caps.js\";\nimport { ShaderStage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type PlanCaps } from \"../types/context.js\";\nimport {\n PRELUDE_WGSL,\n REDUCE_HELPER_NAMES,\n REDUCE_HELPERS_SUBGROUP_WGSL,\n REDUCE_HELPERS_WORKGROUP_WGSL,\n WGSL_RESERVED_WORDS,\n wgslF32Literal,\n} from \"./prelude.js\";\nimport { type UniformBlock } from \"./struct-block.js\";\n\n/** One storage or uniform binding of a module (spec 3.5). `wgslType` is the element / struct type text (\"array<u32>\", \"array<vec4f>\", \"Fa2State\"). */\nexport interface BindingDecl {\n readonly group: 0 | 1 | 2 | 3;\n readonly binding: number;\n readonly name: string;\n readonly kind: \"storage\" | \"storage-ro\" | \"uniform\";\n readonly wgslType: string;\n}\n/** One module-specific override (spec 3.5); the five standard ones (WG, USE_PERM, HAS_WEIGHTS, SUBGROUP_MIN, SUBGROUP_MAX) come from the prelude and are never listed here. */\nexport interface OverrideDecl {\n readonly name: string;\n readonly type: \"u32\" | \"bool\" | \"f32\";\n readonly default: number | boolean;\n}\n/** Spec 3.5 WgslModuleSpec, verbatim. `needs: [\"subgroups\"]` means \"this body calls a wg_reduce_* helper\": the composer splices the subgroup helper block when the device has the feature and the workgroup-memory twin otherwise. */\nexport interface WgslModuleSpec {\n readonly id: string;\n readonly body: string;\n readonly bindings: readonly BindingDecl[];\n readonly overrideDecls: readonly OverrideDecl[];\n readonly overrides: Readonly<Record<string, number | boolean>>;\n readonly needs: readonly \"subgroups\"[];\n readonly uniforms: readonly UniformBlock[];\n readonly snippets?: Readonly<Record<string, string>> | undefined;\n}\n/** The names the prelude declares as overrides; spec.overrides may set them without an OverrideDecl. */\nexport const STANDARD_OVERRIDES = [\"WG\", \"USE_PERM\", \"HAS_WEIGHTS\", \"SUBGROUP_MIN\", \"SUBGROUP_MAX\"] as const;\n/** What composeWgsl returns: the text, the body's first line in it (for compilation-info formatting), the effective overrides (WG, SUBGROUP_MIN, SUBGROUP_MAX filled) and the features to enable. */\nexport interface ComposedModule {\n readonly id: string;\n readonly code: string;\n readonly bodyLine: number;\n readonly overrides: Readonly<Record<string, number | boolean>>;\n /**\n * The subset of `overrides` the composed code REFERENCES outside its own declaration -- what the pipeline\n * descriptor's `constants` carries. WebKit (Safari) fails pipeline creation with \"Compute library failed\n * creation\" when a constant is supplied for an override the entry point never reads (HAS_WEIGHTS in `degree`,\n * TIER in the thread-per-row tiers); Dawn tolerates it. The cache key still uses `overrides` (contract 3.9).\n */\n readonly constants: Readonly<Record<string, number | boolean>>;\n readonly entryPoint: string;\n readonly subgroups: boolean;\n}\n\n/** The type of each standard override (the prelude's declarations). */\nconst STANDARD_OVERRIDE_TYPES: Readonly<Record<(typeof STANDARD_OVERRIDES)[number], OverrideDecl[\"type\"]>> =\n Object.freeze({\n WG: \"u32\",\n USE_PERM: \"bool\",\n HAS_WEIGHTS: \"bool\",\n SUBGROUP_MIN: \"u32\",\n SUBGROUP_MAX: \"u32\",\n });\n/** The only feature a body may need (spec 3.5). */\nconst KNOWN_NEEDS: readonly string[] = Object.freeze([\"subgroups\"]);\n/** The smallest legal subgroup size; the scratch of 4.3 is sized by the MINIMUM size. */\nconst SUBGROUP_FLOOR = 4;\n/** Builtin WGSL element types a binding may name without a struct declaration. */\nconst BUILTIN_TYPES: ReadonlySet<string> = new Set([\n \"u32\",\n \"i32\",\n \"f32\",\n \"f16\",\n \"bool\",\n \"vec2f\",\n \"vec3f\",\n \"vec4f\",\n \"vec2u\",\n \"vec3u\",\n \"vec4u\",\n \"vec2i\",\n \"vec3i\",\n \"vec4i\",\n \"vec2h\",\n \"vec3h\",\n \"vec4h\",\n]);\nconst TEMPLATED_BUILTIN = /^(vec[234]|mat[234]x[234]|atomic|array)</;\nconst IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;\n/** The `var<...>` form of each binding kind (contract 4.2). */\nconst ADDRESS_SPACE: Readonly<Record<BindingDecl[\"kind\"], string>> = Object.freeze({\n storage: \"var<storage, read_write>\",\n \"storage-ro\": \"var<storage, read>\",\n uniform: \"var<uniform>\",\n});\n/** The reserved words as a set (the frozen list stays the public form). */\nconst RESERVED: ReadonlySet<string> = new Set(WGSL_RESERVED_WORDS);\nconst MARKER = /\\/\\/@@([A-Za-z0-9_]+)@@/;\nconst IDENTIFIER_TOKENS = /(?<![A-Za-z0-9_])[A-Za-z_][A-Za-z0-9_]*/g;\nconst COMPUTE_ATTRIBUTE = /@compute\\b/g;\nconst ENTRY_FN = /\\bfn\\s+([A-Za-z_][A-Za-z0-9_]*)/;\n\n/**\n * The compose-time error of contract 3.9.\n * @param id - the module id\n * @param slot - what failed (`override:<key>`, `snippet:<key>`, `marker:<name>`, `body:<text>`, `binding:<name>`, `type:<name>`, `needs:<feature>`, `helper:<name>`, `reserved:<word>`, `entry`)\n * @param message - the human-readable reason\n * @returns the error (thrown by the caller)\n */\nfunction composeError(id: string, slot: string, message: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_SHADER_COMPILE\", `${id}: ${message}`, { id, stage: \"compose\", slot });\n}\n\n/**\n * Removes block and line comments so a word inside a comment is never taken for an identifier.\n * @param text - WGSL text\n * @returns the text without comments\n */\nfunction stripComments(text: string): string {\n return text.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \").replace(/\\/\\/[^\\n]*/g, \"\");\n}\n\n/**\n * The struct a binding's element type names, or null for a builtin type.\n * @param wgslType - the binding's type text (\"array<u32>\", \"array<Fa2Partial>\", \"Fa2State\")\n * @returns the struct name or null\n */\nfunction structNameOf(wgslType: string): string | null {\n const trimmed = wgslType.trim();\n const inner = trimmed.startsWith(\"array<\")\n ? trimmed.slice(\"array<\".length).replace(/\\s*(,[^>]*)?>\\s*$/, \"\")\n : trimmed;\n if (BUILTIN_TYPES.has(inner) || TEMPLATED_BUILTIN.test(inner)) {\n return null;\n }\n return inner;\n}\n\n/**\n * Checks that an override value matches its declared type.\n * PLAN DECISION: a value of the wrong type (a number for a bool, a bool / negative / fractional for a u32) is a\n * compose-time `E_SHADER_COMPILE { slot: \"override:<name>\" }` instead of a GPUPipelineError on the first device.\n * @param id - the module id\n * @param name - the override name\n * @param type - the declared type\n * @param value - the value\n */\nfunction assertOverrideValue(id: string, name: string, type: OverrideDecl[\"type\"], value: number | boolean): void {\n const ok =\n type === \"bool\"\n ? typeof value === \"boolean\"\n : typeof value === \"number\" &&\n Number.isFinite(value) &&\n (type === \"f32\" || (Number.isInteger(value) && value >= 0));\n if (!ok) {\n throw composeError(id, `override:${name}`, `override ${name} (${type}) cannot take the value ${String(value)}`);\n }\n}\n\n/**\n * The WGSL literal of an override default (u32 literals carry the `u` suffix, f32 literals a decimal point, bools true / false).\n * @param decl - the override\n * @returns the literal text\n */\nfunction overrideLiteral(decl: OverrideDecl): string {\n if (decl.type === \"bool\") {\n return decl.default ? \"true\" : \"false\";\n }\n const value = decl.default as number;\n return decl.type === \"u32\" ? `${value}u` : wgslF32Literal(value);\n}\n\n/**\n * The `var<...>` declaration of one binding (contract 4.2).\n * @param decl - the binding\n * @returns the declaration line\n */\nfunction bindingLine(decl: BindingDecl): string {\n const space = ADDRESS_SPACE[decl.kind];\n return `@group(${decl.group}) @binding(${decl.binding}) ${space} ${decl.name}: ${decl.wgslType};`;\n}\n\n/**\n * The entry-point name of a body, or null when the body does not carry exactly one `@compute` attribute followed by `fn <name>`.\n * @param body - the kernel body\n * @returns the name or null\n */\nfunction findEntryPoint(body: string): string | null {\n const stripped = stripComments(body);\n const matches = [...stripped.matchAll(COMPUTE_ATTRIBUTE)];\n if (matches.length !== 1 || matches[0].index === undefined) {\n return null;\n }\n const fn = ENTRY_FN.exec(stripped.slice(matches[0].index));\n return fn === null ? null : fn[1];\n}\n\n/**\n * The entry-point name of a body: the identifier after `fn` on the line following `@compute` (every body has exactly one entry point).\n * PLAN DECISION: a body without exactly one `@compute` entry point is `E_SHADER_COMPILE { stage: \"compose\", slot: \"entry\" }`.\n * @param body - the kernel body\n * @returns the entry-point function name\n */\nexport function entryPointOf(body: string): string {\n const name = findEntryPoint(body);\n if (name === null) {\n throw new WebGpuGraphError(\n \"E_SHADER_COMPILE\",\n \"a body must carry exactly one @compute attribute followed by `fn <name>`\",\n {\n id: null,\n stage: \"compose\",\n slot: \"entry\",\n },\n );\n }\n return name;\n}\n\n/**\n * The bind-group-layout descriptors derived from spec.bindings: one per group 0..maxGroup (empty groups get an empty entry list); uniform decls carry hasDynamicOffset true (spec 5.1).\n * PLAN DECISION: a uniform decl whose struct is one of `spec.uniforms` also carries `minBindingSize = block.byteLength`,\n * so a wrong-size uniform binding fails at createBindGroup (synchronously, with the bind group's label in the message)\n * instead of at the first dispatch (verified on Dawn 0.4.0: without it the error names only the pipeline).\n * @param spec - the module\n * @returns the descriptors in group order\n */\nexport function bindGroupLayoutDescriptors(spec: WgslModuleSpec): GPUBindGroupLayoutDescriptor[] {\n const maxGroup = spec.bindings.reduce((acc, b) => Math.max(acc, b.group), -1);\n const blocks = new Map(spec.uniforms.map((block) => [block.name, block] as const));\n const descriptors: GPUBindGroupLayoutDescriptor[] = [];\n for (let group = 0; group <= maxGroup; group++) {\n const entries: GPUBindGroupLayoutEntry[] = spec.bindings\n .filter((b) => b.group === group)\n .sort((a, b) => a.binding - b.binding)\n .map((b) => {\n if (b.kind === \"uniform\") {\n const block = blocks.get(b.wgslType);\n const buffer: GPUBufferBindingLayout = { type: \"uniform\", hasDynamicOffset: true };\n if (block !== undefined) {\n buffer.minBindingSize = block.byteLength;\n }\n return { binding: b.binding, visibility: ShaderStage.COMPUTE, buffer };\n }\n return {\n binding: b.binding,\n visibility: ShaderStage.COMPUTE,\n buffer: { type: b.kind === \"storage\" ? \"storage\" : \"read-only-storage\" },\n };\n });\n descriptors.push({ entries });\n }\n return descriptors;\n}\n\n/**\n * The names of the bindings of one group in binding order.\n * @param spec - the module\n * @param group - the group index\n * @returns the names\n */\nexport function bindingNames(spec: WgslModuleSpec, group: number): readonly string[] {\n return spec.bindings\n .filter((b) => b.group === group)\n .sort((a, b) => a.binding - b.binding)\n .map((b) => b.name);\n}\n\n/**\n * Validates `spec.needs`, `spec.overrideDecls`, `spec.overrides` and `spec.bindings` (contract 3.9's compose-time checks).\n * PLAN DECISION: an `overrideDecls` entry that redeclares a standard override, repeats a name or names a reserved\n * word is `E_SHADER_COMPILE { slot: \"override:<name>\" }` (otherwise a duplicate-declaration error on the first device).\n * @param spec - the module\n */\nfunction validateDeclarations(spec: WgslModuleSpec): void {\n const { id } = spec;\n for (const need of spec.needs) {\n if (!KNOWN_NEEDS.includes(need)) {\n throw composeError(id, `needs:${need}`, `unknown feature \"${need}\" in needs`);\n }\n }\n const declared = new Map<string, OverrideDecl[\"type\"]>();\n for (const decl of spec.overrideDecls) {\n if (!IDENTIFIER.test(decl.name) || RESERVED.has(decl.name)) {\n throw composeError(id, `override:${decl.name}`, `override name \"${decl.name}\" is not a usable identifier`);\n }\n if ((STANDARD_OVERRIDES as readonly string[]).includes(decl.name) || declared.has(decl.name)) {\n throw composeError(\n id,\n `override:${decl.name}`,\n `override \"${decl.name}\" is declared twice (the prelude declares the standard ones)`,\n );\n }\n assertOverrideValue(id, decl.name, decl.type, decl.default);\n declared.set(decl.name, decl.type);\n }\n for (const [key, value] of Object.entries(spec.overrides)) {\n const standard = (STANDARD_OVERRIDE_TYPES as Readonly<Record<string, OverrideDecl[\"type\"] | undefined>>)[key];\n const type = standard ?? declared.get(key);\n if (type === undefined) {\n throw composeError(\n id,\n `override:${key}`,\n `override \"${key}\" is neither a standard override nor declared in overrideDecls`,\n );\n }\n assertOverrideValue(id, key, type, value);\n }\n const slots = new Set<string>();\n const names = new Set<string>();\n const blocks = new Set(spec.uniforms.map((block) => block.name));\n for (const b of spec.bindings) {\n if (!IDENTIFIER.test(b.name) || RESERVED.has(b.name)) {\n throw composeError(id, `binding:${b.name}`, `binding name \"${b.name}\" is not a usable identifier`);\n }\n const slot = `${b.group}.${b.binding}`;\n if (slots.has(slot)) {\n throw composeError(id, `binding:${b.name}`, `two bindings share group ${b.group} binding ${b.binding}`);\n }\n if (names.has(b.name)) {\n throw composeError(id, `binding:${b.name}`, `two bindings share the name \"${b.name}\"`);\n }\n slots.add(slot);\n names.add(b.name);\n const struct = structNameOf(b.wgslType);\n if (struct !== null && !blocks.has(struct)) {\n throw composeError(\n id,\n `type:${struct}`,\n `binding \"${b.name}\" names struct \"${struct}\" but no block in spec.uniforms declares it`,\n );\n }\n }\n}\n\n/**\n * Substitutes the snippets into the body (every `//@@NAME@@` marker replaced by `spec.snippets[NAME]`) and checks the markers.\n * @param spec - the module\n * @returns the substituted body\n */\nfunction substituteSnippets(spec: WgslModuleSpec): string {\n const { id } = spec;\n let { body } = spec;\n for (const [key, snippet] of Object.entries(spec.snippets ?? {})) {\n const marker = `//@@${key}@@`;\n if (!body.includes(marker)) {\n throw composeError(id, `snippet:${key}`, `snippet \"${key}\" has no ${marker} marker in the body`);\n }\n body = body.split(marker).join(snippet);\n }\n const left = MARKER.exec(body);\n if (left !== null) {\n throw composeError(id, `marker:${left[1]}`, `marker //@@${left[1]}@@ is not filled by any snippet`);\n }\n return body;\n}\n\n/**\n * The textual checks on the substituted body: no `@group(`, no `override `, no reserved identifier, no helper call without `needs`.\n * PLAN DECISION: a body calling a `wg_reduce_*` helper without `needs: [\"subgroups\"]` is\n * `E_SHADER_COMPILE { slot: \"helper:<name>\" }` (otherwise an unresolved identifier on the first device).\n * @param spec - the module\n * @param body - the substituted body\n */\nfunction validateBody(spec: WgslModuleSpec, body: string): void {\n const { id } = spec;\n for (const forbidden of [\"@group(\", \"override \"]) {\n if (body.includes(forbidden)) {\n throw composeError(\n id,\n `body:${forbidden}`,\n `a body must not contain \"${forbidden}\" (the composer emits those lines)`,\n );\n }\n }\n const stripped = stripComments(body);\n const helpers = REDUCE_HELPER_NAMES as readonly string[];\n for (const match of stripped.matchAll(IDENTIFIER_TOKENS)) {\n const word = match[0];\n if (RESERVED.has(word)) {\n throw composeError(\n id,\n `reserved:${word}`,\n `\"${word}\" is a WGSL reserved word (spec 16.2) and cannot be an identifier`,\n );\n }\n if (helpers.includes(word) && !spec.needs.includes(\"subgroups\")) {\n throw composeError(id, `helper:${word}`, `the body calls ${word} but spec.needs does not list \"subgroups\"`);\n }\n }\n}\n\n/**\n * String concatenation of spec 3.5: prelude (constants, standard overrides, helpers), module overrides, struct texts, the bind declarations, then the body with snippets substituted (4.2 gives the exact emitted format).\n * @param spec - the module\n * @param caps - the device capabilities (WG, the subgroup sizes and the feature set)\n * @returns the composed module\n */\nexport function composeWgsl(spec: WgslModuleSpec, caps: PlanCaps): ComposedModule {\n validateDeclarations(spec);\n const entryPoint = findEntryPoint(spec.body);\n if (entryPoint === null) {\n throw composeError(\n spec.id,\n \"entry\",\n \"a body must carry exactly one @compute attribute followed by `fn <name>`\",\n );\n }\n const body = substituteSnippets(spec);\n validateBody(spec, body);\n const wantsHelpers = spec.needs.includes(\"subgroups\");\n const subgroups = wantsHelpers && caps.features.has(\"subgroups\");\n const overrides: Record<string, number | boolean> = { ...spec.overrides };\n if (overrides.WG === undefined) {\n overrides.WG = workgroupSizeFor(caps);\n }\n if (subgroups) {\n overrides.SUBGROUP_MAX = caps.subgroupMaxSize;\n overrides.SUBGROUP_MIN = Math.max(SUBGROUP_FLOOR, caps.subgroupMinSize);\n }\n const parts: string[] = [];\n if (subgroups) {\n parts.push(\"enable subgroups;\");\n }\n parts.push(PRELUDE_WGSL);\n for (const decl of spec.overrideDecls) {\n parts.push(`override ${decl.name}: ${decl.type} = ${overrideLiteral(decl)};`);\n }\n for (const block of spec.uniforms) {\n parts.push(block.wgsl);\n }\n if (wantsHelpers) {\n parts.push(subgroups ? REDUCE_HELPERS_SUBGROUP_WGSL : REDUCE_HELPERS_WORKGROUP_WGSL);\n }\n for (const decl of spec.bindings) {\n parts.push(bindingLine(decl));\n }\n const head = parts.join(\"\\n\");\n const code = `${head}\\n${body}`;\n return Object.freeze({\n id: spec.id,\n code,\n bodyLine: head.split(\"\\n\").length + 1,\n overrides: Object.freeze(overrides),\n constants: Object.freeze(referencedOverrides(code, overrides)),\n entryPoint,\n subgroups,\n });\n}\n\n/**\n * The overrides whose names occur in the code outside comments and outside their own `override` declaration lines\n * (the constants a pipeline may carry on every backend, see ComposedModule.constants).\n * @param code - the composed module text\n * @param overrides - the effective override values\n * @returns the referenced subset, in the same order\n */\nfunction referencedOverrides(\n code: string,\n overrides: Readonly<Record<string, number | boolean>>,\n): Record<string, number | boolean> {\n const stripped = code\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \")\n .replace(/\\/\\/[^\\n]*/g, \" \")\n .replace(/^\\s*override\\s+\\w+\\s*:[^\\n]*$/gm, \" \");\n const referenced: Record<string, number | boolean> = {};\n for (const [name, value] of Object.entries(overrides)) {\n if (new RegExp(`\\\\b${name}\\\\b`).test(stripped)) {\n referenced[name] = value;\n }\n }\n return referenced;\n}\n","/**\n * PipelineCache (spec 5.1; contract 3.9): compile-once compute pipelines keyed by\n * `(id, overrides, needs present on the device, snippets)` with EXPLICIT bind-group layouts derived from\n * `spec.bindings` (never `layout: \"auto\"`, so one layout serves every dummy-binding variant and bind groups are\n * reused across variants). A WGSL error is `E_SHADER_COMPILE { stage: \"compile\", messages, lines }` with\n * body-relative line numbers; a pipeline error that is not a compilation message (an oversized workgroup, an\n * invalid layout) is `E_VALIDATION`.\n */\n\nimport { formatCompilationInfo } from \"../device/error-scope.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type PlanCaps } from \"../types/context.js\";\nimport { Kernel } from \"./kernel.js\";\nimport { bindGroupLayoutDescriptors, type ComposedModule, composeWgsl, type WgslModuleSpec } from \"./wgsl.js\";\n\n/** One cached entry: the pipeline, its layouts and the Kernel built on them. */\ninterface CacheEntry {\n readonly key: string;\n readonly composed: ComposedModule;\n readonly pipeline: GPUComputePipeline;\n readonly layouts: readonly GPUBindGroupLayout[];\n readonly kernel: Kernel;\n}\n\n/**\n * JSON with the keys of every (nested) object sorted, so two override records with the same content give one key.\n * @param value - a JSON-compatible value\n * @returns the canonical text\n */\nfunction stableJson(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map((item: unknown) => stableJson(item)).join(\",\")}]`;\n }\n if (typeof value === \"object\" && value !== null) {\n const record = value as Record<string, unknown>;\n const keys = Object.keys(record).sort();\n return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(\",\")}}`;\n }\n return JSON.stringify(value);\n}\n\n/**\n * FNV-1a (32-bit) of a text as 8 hex digits; \"0\" for an absent or empty snippet record. Hashes text, never an arc\n * index or a byte offset, so the bitwise operators are within the house rule.\n * @param snippets - the snippet record\n * @returns the hash text\n */\nfunction hashSnippets(snippets: Readonly<Record<string, string>> | undefined): string {\n if (snippets === undefined || Object.keys(snippets).length === 0) {\n return \"0\";\n }\n const text = stableJson(snippets);\n let hash = 0x811c9dc5;\n for (let i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n\n/**\n * The cache key of a spec on a device (pure; PLAN DECISION: exported so the override-matrix helper of P2-T2 can\n * compute keys without a device): `id + \"|\" + stableJson(overrides) + \"|\" + needs.filter(present).join(\",\") + \"|\" + hash(snippets)`.\n * @param spec - the module\n * @param caps - the device capabilities (the feature set decides which needs are present)\n * @returns the key\n */\nexport function pipelineKey(spec: WgslModuleSpec, caps: PlanCaps): string {\n const present = spec.needs.filter((need) => caps.features.has(need)).join(\",\");\n return `${spec.id}|${stableJson(spec.overrides)}|${present}|${hashSnippets(spec.snippets)}`;\n}\n\n/**\n * The message of an unknown error value.\n * @param err - the thrown value\n * @returns its message text\n */\nfunction messageOf(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** Compile-once pipelines keyed by (id, overrides, needs present on the device, snippets) with explicit bind-group layouts (spec 5.1). */\nexport class PipelineCache {\n private readonly device: GPUDevice;\n private readonly caps: PlanCaps;\n /** In-flight and finished compiles by key (a promise, so two concurrent get() calls share one compile). */\n private readonly pending = new Map<string, Promise<CacheEntry>>();\n /** Finished compiles by key. */\n private readonly entries = new Map<string, CacheEntry>();\n /** Keys in the order their compiles were started (a failed compile is removed again). */\n private readonly order: string[] = [];\n private disposed = false;\n\n /**\n * Builds a cache over a device.\n * @param device - the device pipelines are created on\n * @param caps - its capabilities (WG, subgroup sizes, features)\n */\n constructor(device: GPUDevice, caps: PlanCaps) {\n this.device = device;\n this.caps = caps;\n }\n\n /**\n * The cache key of a spec on this device: `id + \"|\" + stableJson(overrides) + \"|\" + needs.filter(present).join(\",\") + \"|\" + hash(snippets)`.\n * @param spec - the module\n * @returns the key\n */\n key(spec: WgslModuleSpec): string {\n return pipelineKey(spec, this.caps);\n }\n\n /**\n * createComputePipelineAsync inside a validation scope with the layouts derived from spec.bindings; compilation messages become E_SHADER_COMPILE { id, stage: \"compile\", messages } with body-relative lines.\n * @param spec - the module\n * @returns the pipeline (the same object for the same key)\n */\n async get(spec: WgslModuleSpec): Promise<GPUComputePipeline> {\n return (await this.entry(spec)).pipeline;\n }\n\n /**\n * The Kernel (pipeline + layouts + binding names) for a spec; cached with the pipeline.\n * @param spec - the module\n * @returns the kernel (the same object for the same key)\n */\n async kernel(spec: WgslModuleSpec): Promise<Kernel> {\n return (await this.entry(spec)).kernel;\n }\n\n /**\n * Compiles every spec not yet cached (load() calls it so the first step() does not compile).\n * @param specs - the modules\n */\n async warm(specs: readonly WgslModuleSpec[]): Promise<void> {\n await Promise.all(specs.map((spec) => this.entry(spec)));\n }\n\n /**\n * Number of cached pipelines.\n * @returns the count of finished compiles\n */\n get size(): number {\n return this.entries.size;\n }\n\n /**\n * Every key created so far, in creation order (the override-matrix coverage test reads it).\n * PLAN DECISION: keys are listed in compile-START order and only those whose compile finished (warm() compiles\n * concurrently, so completion order is not deterministic; a failed compile is removed).\n * @returns the keys\n * @internal\n */\n keys(): readonly string[] {\n return this.order.filter((key) => this.entries.has(key));\n }\n\n /**\n * The bind-group layouts of a cached kernel by key.\n * @param key - a key from keys()\n * @returns the layouts, or null when the key is not cached\n * @internal\n */\n layoutsOf(key: string): readonly GPUBindGroupLayout[] | null {\n return this.entries.get(key)?.layouts ?? null;\n }\n\n /**\n * PLAN DECISION: forgets every pipeline and refuses further compiles with E_DISPOSED (the context's dispose()\n * may call it; a GPUComputePipeline has no destroy(), so the objects are simply released).\n */\n dispose(): void {\n this.disposed = true;\n this.pending.clear();\n this.entries.clear();\n this.order.length = 0;\n }\n\n /**\n * The cached entry of a spec, compiling it once per key.\n * @param spec - the module\n * @returns the entry\n */\n private entry(spec: WgslModuleSpec): Promise<CacheEntry> {\n if (this.disposed) {\n return Promise.reject(\n new WebGpuGraphError(\"E_DISPOSED\", \"PipelineCache: disposed\", { label: \"PipelineCache\" }),\n );\n }\n const key = this.key(spec);\n const inFlight = this.pending.get(key);\n if (inFlight !== undefined) {\n return inFlight;\n }\n this.order.push(key);\n const compile = this.compile(spec, key).then(\n (entry) => {\n if (!this.disposed) {\n this.entries.set(key, entry);\n }\n return entry;\n },\n (err: unknown) => {\n this.pending.delete(key);\n const at = this.order.indexOf(key);\n if (at >= 0) {\n this.order.splice(at, 1);\n }\n throw err;\n },\n );\n this.pending.set(key, compile);\n return compile;\n }\n\n /**\n * One compile: compose, create the shader module inside a synchronous push / pop validation pair (so concurrent\n * compiles never interleave scopes), check the compilation info, create the layouts and the pipeline.\n * PLAN DECISION: `E_SHADER_COMPILE` at stage \"compile\" also carries `lines` (the body-relative 1-based line of every\n * error message, from `composed.bodyLine`) next to the contract's `messages`; a `createComputePipelineAsync`\n * rejection (a GPUPipelineError, which pushes nothing into a validation scope on Dawn 0.4.0) is\n * `E_VALIDATION { label: \"<id>|pipeline\", message }`; bool overrides travel as the pipeline constants 1 / 0\n * because dawn.node's WebIDL layer rejects a boolean constant.\n * @param spec - the module\n * @param key - its key (the pipeline label)\n * @returns the entry\n */\n private async compile(spec: WgslModuleSpec, key: string): Promise<CacheEntry> {\n const composed = composeWgsl(spec, this.caps);\n const { device } = this;\n const label = `${spec.id}|pipeline`;\n device.pushErrorScope(\"validation\");\n const module = device.createShaderModule({ code: composed.code, label: spec.id });\n const layouts = bindGroupLayoutDescriptors(spec).map((descriptor, group) =>\n device.createBindGroupLayout({ ...descriptor, label: `${spec.id}/layout${group}` }),\n );\n const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: layouts, label: `${spec.id}|layout` });\n const popped = device.popErrorScope();\n const info = await module.getCompilationInfo();\n const scopeError = await popped;\n const errors = info.messages.filter((message) => message.type === \"error\");\n if (errors.length > 0) {\n const preludeLines = composed.bodyLine - 1;\n throw new WebGpuGraphError(\n \"E_SHADER_COMPILE\",\n `${spec.id}: WGSL compilation failed (${errors.length} error(s))`,\n {\n id: spec.id,\n stage: \"compile\",\n messages: formatCompilationInfo(info, preludeLines),\n lines: errors.map((message) => message.lineNum - preludeLines),\n },\n );\n }\n if (scopeError !== null) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${spec.id}: ${scopeError.message}`, {\n label,\n message: scopeError.message,\n });\n }\n // dawn.node's WebIDL layer rejects a boolean pipeline constant (\"value is not a number\"), so bools travel as 1 / 0;\n // only the REFERENCED overrides are supplied (composed.constants): WebKit rejects a constant for an unread override\n const constants: Record<string, number> = {};\n for (const [name, value] of Object.entries(composed.constants)) {\n if (typeof value === \"boolean\") {\n constants[name] = value ? 1 : 0;\n } else {\n constants[name] = value;\n }\n }\n let pipeline: GPUComputePipeline;\n try {\n pipeline = await device.createComputePipelineAsync({\n label: key,\n layout: pipelineLayout,\n compute: { module, entryPoint: composed.entryPoint, constants },\n });\n } catch (err: unknown) {\n const message = messageOf(err);\n throw new WebGpuGraphError(\"E_VALIDATION\", `${spec.id}: pipeline creation failed: ${message}`, {\n label,\n message,\n });\n }\n const kernel = new Kernel(device, spec, composed, pipeline, layouts);\n return { key, composed, pipeline, layouts, kernel };\n }\n}\n","/**\n * Timestamp profiling of spec 5.5: when \"timestamp-query\" was granted the context owns a Profiler\n * whose query set (PROFILER_QUERY_SLOTS slots, two per pass) is written by the timestampWrites of\n * every CommandBatch pass; `resolveInto(batch)` records the resolve plus a copy into the batch's\n * staging slot and `timings(bytes, request)` decodes `{ label, ns }` per pass from the batch's\n * readback bytes. Chromium quantises timestamps to 100 us (`quantised: true`); Dawn-node reports\n * 1,024 ns ticks (spec 2.6). The profiler never throws: a full query set drops the timings of the\n * passes past the budget and marks the batch's request `partial(request)` so a caller summing the\n * rows into a duration falls back to wall time; a device without the feature disables it. Slot\n * pairs are handed out in order and the cursor restarts at 0\n * after every resolve: queue order guarantees the resolve of batch A reads its slots before batch B\n * overwrites them, and one resolve buffer suffices for the same reason.\n */\n\nimport { PROFILER_QUERY_SLOTS } from \"../constants.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport type { CommandBatch, ReadbackRequest } from \"./batch.js\";\n\n/** One resolved pass timing. */\nexport interface PassTiming {\n readonly label: string;\n readonly ns: number;\n}\n\n/** A pass whose begin / end slots were handed out and not yet resolved. */\ninterface PendingPass {\n readonly label: string;\n readonly begin: number;\n}\n\n/** Timestamp profiling when \"timestamp-query\" was granted (spec 5.5). */\nexport class Profiler {\n /** True when the feature was granted and a query set exists. */\n readonly enabled: boolean;\n /** True in browsers (100 us quantisation), false under Dawn-node (spec 2.6). */\n readonly quantised: boolean;\n private readonly slots: number;\n private readonly querySet: GPUQuerySet | null;\n private readonly resolveBuffer: GPUBuffer | null;\n private readonly labels = new WeakMap<ReadbackRequest, readonly string[]>();\n private readonly partialRequests = new WeakSet<ReadbackRequest>();\n private pending: PendingPass[] = [];\n private cursor = 0;\n private refused = 0;\n private destroyed = false;\n\n /**\n * Creates the query set and the resolve buffer when usable; `slots` defaults to PROFILER_QUERY_SLOTS = 256\n * (spec 5.5); 2 query slots per pass. `enabled` is also false when the device lacks \"timestamp-query\" or\n * `slots < 2`, so no caller can make the profiler raise a validation error.\n * @param device - the device the query set is created on\n * @param enabled - whether the caller wants profiling (the context passes `features.has(\"timestamp-query\")`)\n * @param quantised - true in browsers\n * @param slots - query slots, two per pass (default PROFILER_QUERY_SLOTS)\n */\n constructor(device: GPUDevice, enabled: boolean, quantised: boolean, slots?: number) {\n const count = slots ?? PROFILER_QUERY_SLOTS;\n this.quantised = quantised;\n this.slots = count;\n const usable = enabled && count >= 2 && device.features.has(\"timestamp-query\");\n this.enabled = usable;\n if (usable) {\n this.querySet = device.createQuerySet({ label: \"profiler/timestamps\", type: \"timestamp\", count });\n this.resolveBuffer = device.createBuffer({\n label: \"profiler/resolve\",\n size: count * 8,\n usage: BufferUsage.QUERY_RESOLVE | BufferUsage.COPY_SRC,\n });\n } else {\n this.querySet = null;\n this.resolveBuffer = null;\n }\n }\n\n /**\n * The timestampWrites descriptor for a new pass, or undefined when disabled / out of slots. A pass refused for\n * want of slots is counted, and the next `resolveInto()` marks its request partial.\n * @param label - the pass name reported by `timings()`\n * @returns the descriptor a CommandBatch puts on beginComputePass, or undefined\n */\n beginPass(label: string): GPUComputePassTimestampWrites | undefined {\n if (this.querySet === null || this.destroyed) {\n return undefined;\n }\n if (this.cursor + 2 > this.slots) {\n this.refused++;\n return undefined;\n }\n const begin = this.cursor;\n this.cursor += 2;\n this.pending.push({ label, begin });\n return { querySet: this.querySet, beginningOfPassWriteIndex: begin, endOfPassWriteIndex: begin + 1 };\n }\n\n /**\n * Records the resolve + copy into the batch's staging slot; returns the request's byte range, or null when\n * nothing was written (disabled, destroyed, or no pass begun since the last resolve).\n * @param batch - the batch whose passes were timed (it must still be open)\n * @returns the readback request `timings()` decodes, or null\n */\n resolveInto(batch: CommandBatch): ReadbackRequest | null {\n if (this.querySet === null || this.resolveBuffer === null || this.destroyed || this.pending.length === 0) {\n return null;\n }\n const count = this.cursor;\n batch.resolveQuerySet(this.querySet, 0, count, this.resolveBuffer);\n const request = batch.readback(this.resolveBuffer, 0, count * 8);\n this.labels.set(\n request,\n this.pending.map((pass) => pass.label),\n );\n if (this.refused > 0) {\n this.partialRequests.add(request);\n }\n this.pending = [];\n this.cursor = 0;\n this.refused = 0;\n return request;\n }\n\n /**\n * Whether a pass of the batch was refused a slot pair, so `timings()` covers only its first slots / 2 passes\n * and their sum is not the batch's duration.\n * @param request - the request `resolveInto()` returned\n * @returns true when at least one pass of that batch went untimed\n */\n partial(request: ReadbackRequest): boolean {\n return this.partialRequests.has(request);\n }\n\n /**\n * Decodes the timings of a batch from its readback bytes.\n * @param bytes - the resolved readback of the batch\n * @param request - the request `resolveInto()` returned for it\n * @returns one timing per pass in pass order (empty for a request this profiler did not create)\n */\n timings(bytes: ArrayBuffer, request: ReadbackRequest): readonly PassTiming[] {\n const labels = this.labels.get(request);\n if (labels === undefined) {\n return [];\n }\n const view = new DataView(bytes);\n const out: PassTiming[] = [];\n for (let i = 0; i < labels.length; i++) {\n const at = request.offset + i * 16;\n if (at + 16 > bytes.byteLength) {\n break;\n }\n const begin = view.getBigUint64(at, true);\n const end = view.getBigUint64(at + 8, true);\n out.push({ label: labels[i], ns: Number(end - begin) });\n }\n return out;\n }\n\n /** Destroys the query set and the resolve buffer; idempotent. */\n destroy(): void {\n if (this.destroyed) {\n return;\n }\n this.destroyed = true;\n this.pending = [];\n this.cursor = 0;\n this.refused = 0;\n if (this.querySet !== null) {\n this.querySet.destroy();\n }\n if (this.resolveBuffer !== null) {\n this.resolveBuffer.destroy();\n }\n }\n}\n","/**\n * The Lease scope object of spec 4.4: every buffer an algorithm acquires through it goes back to the\n * BufferPool in ONE `release()` call placed in the algorithm's `finally` block, so scratch never\n * outlives the call that took it (a `try / finally`, not `Symbol.dispose`, until the monorepo's\n * TypeScript target supports `using`). Persistent buffers (layout state) are owned by the simulation\n * object instead and freed by its `dispose()`.\n */\n\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { hasErrorCode, WebGpuGraphError } from \"../errors.js\";\nimport type { BufferPool } from \"./buffer-pool.js\";\n\n/** Scope object algorithms use: every buffer acquired through it is released by `release()` in a finally block (spec 4.4). */\nexport class Lease {\n private readonly pool: BufferPool;\n private readonly buffers = new Set<GPUBuffer>();\n private released = false;\n\n /**\n * Creates a lease over a pool; `pool.lease()` is the usual way to get one.\n * @param pool - the pool every acquisition of this lease goes through\n */\n constructor(pool: BufferPool) {\n this.pool = pool;\n }\n\n /**\n * pool.acquire(byteLength, STORAGE | COPY_SRC | COPY_DST, label).\n * @param byteLength - bytes needed; the pool rounds up to its size class\n * @param label - the buffer label\n * @returns the buffer, returned to the pool by `release()`\n */\n storage(byteLength: number, label: string): GPUBuffer {\n return this.acquire(byteLength, BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST, label);\n }\n\n /**\n * pool.acquire(byteLength, UNIFORM | COPY_DST, label).\n * @param byteLength - bytes needed; the pool rounds up to its size class\n * @param label - the buffer label\n * @returns the buffer, returned to the pool by `release()`\n */\n uniform(byteLength: number, label: string): GPUBuffer {\n return this.acquire(byteLength, BufferUsage.UNIFORM | BufferUsage.COPY_DST, label);\n }\n\n /**\n * pool.acquire with explicit usage.\n * @param byteLength - bytes needed; the pool rounds up to its size class\n * @param usage - the GPUBufferUsage bits\n * @param label - the buffer label\n * @returns the buffer, returned to the pool by `release()`\n */\n acquire(byteLength: number, usage: number, label: string): GPUBuffer {\n if (this.released) {\n throw new WebGpuGraphError(\"E_DISPOSED\", `lease already released: cannot acquire \"${label}\"`, { label });\n }\n const buffer = this.pool.acquire(byteLength, usage, label);\n this.buffers.add(buffer);\n return buffer;\n }\n\n /**\n * Releases every buffer acquired through this lease; idempotent. A pool that `ctx.dispose()` already\n * destroyed has nothing left to take back, so its E_DISPOSED is swallowed here: the lease sits in a\n * `finally` block and must never mask the error that unwound the algorithm.\n */\n release(): void {\n if (this.released) {\n return;\n }\n this.released = true;\n const owned = [...this.buffers];\n this.buffers.clear();\n for (const buffer of owned) {\n try {\n this.pool.release(buffer);\n } catch (error) {\n if (!hasErrorCode(error, \"E_DISPOSED\")) {\n throw error;\n }\n }\n }\n }\n\n /**\n * Live buffers of this lease.\n * @returns the number of buffers acquired through the lease and not yet released\n */\n get count(): number {\n return this.buffers.size;\n }\n}\n","/**\n * Size-class pool of GPUBuffers by usage (spec 4.4): a request rounds up to a class (powers of two from 4 KiB to\n * 64 MiB, then 16 MiB steps), an idle buffer of that (class, usage) is reused, otherwise one is created through the\n * context's AllocationTracker (so the OOM scope of spec 5.7 and the resident accounting are shared with the\n * residency); `release` keeps at most maxIdlePerClass idle buffers per (class, usage); `trim` destroys the idle\n * ones (ctx.release and layouts on dispose); `destroyAll` everything (ctx.dispose). The Lease scope object arrives\n * with P2-T1 (`lease()`, PLAN DECISION 1). Classes above maxBufferSize are never created: a request that fits the\n * device but whose class overshoots gets the capped class (PLAN DECISION 14).\n */\n\nimport {\n POOL_LINEAR_STEP_BYTES,\n POOL_MAX_IDLE_PER_CLASS,\n POOL_MAX_POW2_CLASS_BYTES,\n POOL_MIN_CLASS_BYTES,\n} from \"../constants.js\";\nimport { type AllocationTracker } from \"../device/error-scope.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { Lease } from \"./lease.js\";\n\n/** What the pool remembers about a live buffer. */\ninterface LiveEntry {\n readonly sizeClass: number;\n readonly usage: number;\n}\n\n/**\n * The idle-list key of a (class, usage) pair.\n * @param sizeClass - the class in bytes\n * @param usage - the GPUBufferUsage flags\n * @returns the map key\n */\nfunction classKey(sizeClass: number, usage: number): string {\n return `${sizeClass}:${usage}`;\n}\n\n/** Size-class pool of GPUBuffers by usage (spec 4.4). */\nexport class BufferPool {\n private readonly allocator: AllocationTracker;\n private readonly maxBufferSize: number;\n private readonly maxIdlePerClass: number;\n private readonly idle = new Map<string, GPUBuffer[]>();\n private readonly live = new Map<GPUBuffer, LiveEntry>();\n private liveBytesValue = 0;\n private idleBytesValue = 0;\n private disposed = false;\n\n /**\n * Creates an empty pool.\n * @param _device - the device (buffers are created through the allocator, which owns it; the parameter keeps\n * the contract's constructor shape)\n * @param allocator - the context's OOM-scoped allocator\n * @param maxBufferSize - the device's maxBufferSize (classes above it are never created)\n * @param options - pool options\n * @param options.maxIdlePerClass - idle buffers kept per (class, usage); default POOL_MAX_IDLE_PER_CLASS\n */\n constructor(\n _device: GPUDevice,\n allocator: AllocationTracker,\n maxBufferSize: number,\n options?: { readonly maxIdlePerClass?: number | undefined },\n ) {\n this.allocator = allocator;\n this.maxBufferSize = maxBufferSize - (maxBufferSize % 4);\n this.maxIdlePerClass = options?.maxIdlePerClass ?? POOL_MAX_IDLE_PER_CLASS;\n }\n\n /**\n * The size class a byte length rounds up to: powers of two from 4 KiB to 64 MiB, then 16 MiB steps (pure).\n * @param byteLength - a positive integer\n * @returns the class in bytes\n */\n static sizeClass(byteLength: number): number {\n if (!Number.isInteger(byteLength) || byteLength <= 0) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"byteLength: expected a positive integer\", {\n argument: \"byteLength\",\n value: byteLength,\n expected: \"a positive integer\",\n });\n }\n if (byteLength > POOL_MAX_POW2_CLASS_BYTES) {\n return Math.ceil(byteLength / POOL_LINEAR_STEP_BYTES) * POOL_LINEAR_STEP_BYTES;\n }\n let sizeClass = POOL_MIN_CLASS_BYTES;\n while (sizeClass < byteLength) {\n sizeClass *= 2;\n }\n return sizeClass;\n }\n\n /**\n * Acquires a buffer of at least byteLength (an idle one of the class and usage, else a new one through the\n * allocator); E_TOO_LARGE above maxBufferSize.\n * @param byteLength - the bytes needed\n * @param usage - the GPUBufferUsage flags\n * @param label - the buffer label (a reused buffer is relabelled)\n * @returns a buffer of the class size\n */\n acquire(byteLength: number, usage: number, label: string): GPUBuffer {\n if (this.disposed) {\n throw new WebGpuGraphError(\"E_DISPOSED\", \"the buffer pool was disposed\", { label: \"pool\" });\n }\n const rounded = BufferPool.sizeClass(byteLength);\n if (byteLength > this.maxBufferSize) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `pool: ${byteLength} bytes exceed the device maxBufferSize of ${this.maxBufferSize} bytes`,\n { needed: byteLength, limit: this.maxBufferSize, path: \"pool\", algorithm: null },\n );\n }\n const sizeClass = Math.min(rounded, this.maxBufferSize);\n const key = classKey(sizeClass, usage);\n const idle = this.idle.get(key);\n let buffer = idle?.pop();\n if (buffer === undefined) {\n buffer = this.allocator.createBuffer({ label, size: sizeClass, usage });\n } else {\n this.idleBytesValue -= sizeClass;\n buffer.label = label;\n }\n this.live.set(buffer, { sizeClass, usage });\n this.liveBytesValue += sizeClass;\n return buffer;\n }\n\n /**\n * Returns a buffer to its class; destroys it when the class already holds maxIdlePerClass idle buffers. A no-op\n * after destroyAll() (so a `finally` never masks the original error).\n * @param buffer - a buffer acquired from this pool and not yet released\n */\n release(buffer: GPUBuffer): void {\n if (this.disposed) {\n return;\n }\n const entry = this.live.get(buffer);\n if (entry === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"buffer: not a live buffer of this pool\", {\n argument: \"buffer\",\n value: buffer.label,\n expected: \"a buffer acquired from this pool and not yet released\",\n });\n }\n this.live.delete(buffer);\n this.liveBytesValue -= entry.sizeClass;\n const key = classKey(entry.sizeClass, entry.usage);\n let idle = this.idle.get(key);\n if (idle === undefined) {\n idle = [];\n this.idle.set(key, idle);\n }\n if (idle.length >= this.maxIdlePerClass) {\n this.allocator.destroy(buffer);\n return;\n }\n idle.push(buffer);\n this.idleBytesValue += entry.sizeClass;\n }\n\n /** Destroys every idle buffer. */\n trim(): void {\n for (const buffers of this.idle.values()) {\n for (const buffer of buffers) {\n this.allocator.destroy(buffer);\n }\n }\n this.idle.clear();\n this.idleBytesValue = 0;\n }\n\n /** Destroys everything, idle and live (ctx.dispose()); idempotent. @internal */\n destroyAll(): void {\n this.trim();\n for (const buffer of this.live.keys()) {\n this.allocator.destroy(buffer);\n }\n this.live.clear();\n this.liveBytesValue = 0;\n this.disposed = true;\n }\n\n /**\n * A scope object that releases everything acquired through it (spec 4.4, P2).\n * @returns a fresh lease over this pool\n */\n lease(): Lease {\n return new Lease(this);\n }\n\n /**\n * Bytes of buffers acquired and not yet released (class sizes).\n * @returns the live byte count\n */\n get liveBytes(): number {\n return this.liveBytesValue;\n }\n\n /**\n * Bytes of idle buffers (class sizes).\n * @returns the idle byte count\n */\n get idleBytes(): number {\n return this.idleBytesValue;\n }\n}\n","/**\n * The staging ring of spec 4.4: a ring of MAP_READ | COPY_DST buffers (default DEFAULT_STAGING_SLOTS slots of 4 MiB,\n * PLAN DECISION 15) through which every readback of the package flows. `read()` copies with its own encoder and\n * submit, awaits mapAsync, copies out of the mapped range BEFORE unmap (the range is detached at unmap, design 10.7)\n * and never polls onSubmittedWorkDone; requests above the slot size are chunked. Ownership is one-directional: the\n * ring owns its buffers; a CommandBatch (P2) BORROWS one slot through borrowSlot, maps it through mapSlot and always\n * returns it through returnSlot, which unmaps it. Slots at or above OOM_SCOPE_THRESHOLD_BYTES are created through the\n * AllocationTracker (the out-of-memory scope of spec 5.7), the default-size ones directly on the device, so the\n * allocator counts residency and pool buffers only. A mapAsync rejection is E_DEVICE_LOST (or E_DISPOSED after\n * destroyAll).\n *\n * The one invariant every path keeps: a staging buffer whose mapAsync is PENDING is never unmapped and never\n * destroyed. dawn-node 0.4.0 settles the pending promise synchronously on unmap() / destroy() and settles it a\n * second time when Dawn's map callback arrives (a SIGSEGV in AsyncRunner::Reject); on the Vulkan backends the\n * callback has already run inside device.destroy(), on Dawn's Metal backend it arrives after the device-lost\n * fan-out, which is where the macOS host lane lost its vitest worker (CLAUDE.md \"Verified Platform Facts\"). The\n * ring therefore tracks every map on its slots (mapPending) and defers an unmap, a return or a destroy that\n * arrives during one to the moment the map settles.\n */\n\nimport { DEFAULT_STAGING_SLOTS, OOM_SCOPE_THRESHOLD_BYTES } from \"../constants.js\";\nimport { type AllocationTracker } from \"../device/error-scope.js\";\nimport { BufferUsage, MapMode } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\n\n/** Default capacity of one staging slot (PLAN DECISION 15). */\nconst DEFAULT_SLOT_BYTES = 4 * 1024 * 1024;\n\n/** Every staging buffer is MAP_READ | COPY_DST. */\nconst STAGING_USAGE = BufferUsage.MAP_READ | BufferUsage.COPY_DST;\n\n/** Grown slots are sized in 256-byte steps. */\nconst SLOT_GRANULE = 256;\n\n/**\n * One MAP_READ | COPY_DST staging buffer of the ring. Exported for the borrowers of borrowSlot / returnSlot\n * (contract 3.8): P2-T1's CommandBatch imports it as a type; nothing at P1 imports it by name.\n * @public\n */\nexport interface StagingSlot {\n readonly index: number;\n readonly buffer: GPUBuffer;\n readonly capacity: number;\n}\n\n/** The ring's bookkeeping of one slot. */\ninterface SlotEntry {\n readonly slot: StagingSlot;\n borrowed: boolean;\n /** True between a successful mapAsync through the ring and the unmap of returnSlot (a fallback when mapState is absent). */\n mapped: boolean;\n /** True while a mapAsync through the ring (read() or mapSlot) is pending: returnSlot and destroyAll defer to the settle. */\n mapPending: boolean;\n /** True when returnSlot ran during a pending map: the settle finishes the return. */\n returnRequested: boolean;\n /** True when the buffer was created through the allocator (and is destroyed through it). */\n readonly tracked: boolean;\n}\n\n/**\n * Whether an ArrayBuffer-like is a SharedArrayBuffer (checked by tag so the global need not exist).\n * @param buffer - the buffer to test\n * @returns true for a SharedArrayBuffer\n */\nfunction isSharedBuffer(buffer: ArrayBufferLike): boolean {\n return Object.prototype.toString.call(buffer) === \"[object SharedArrayBuffer]\";\n}\n\n/**\n * The E_INVALID_ARGUMENT error of a bad readback argument.\n * @param argument - the argument name\n * @param value - the value given\n * @param expected - what was expected\n * @returns the error to throw\n */\nfunction invalid(argument: string, value: unknown, expected: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${argument}: expected ${expected}`, {\n argument,\n value,\n expected,\n });\n}\n\n/** The staging ring (spec 4.4): default 3 slots; grows when every slot is busy; always unmaps and destroys its own buffers. */\nexport class Readback {\n private readonly device: GPUDevice;\n private readonly allocator: AllocationTracker;\n private readonly slotBytes: number;\n private readonly ring: SlotEntry[] = [];\n private disposed = false;\n\n /**\n * Creates the ring with `slots` slots of `slotBytes` each.\n * @param device - the device the copies run on\n * @param allocator - the context's OOM-scoped allocator (used for slots at or above OOM_SCOPE_THRESHOLD_BYTES)\n * @param options - ring options\n * @param options.slots - slots created up front; default DEFAULT_STAGING_SLOTS\n * @param options.slotBytes - capacity of each slot and the chunk size of read(); default 4 MiB; a positive multiple of 4\n */\n constructor(\n device: GPUDevice,\n allocator: AllocationTracker,\n options?: { readonly slots?: number | undefined; readonly slotBytes?: number | undefined },\n ) {\n const slotBytes = options?.slotBytes ?? DEFAULT_SLOT_BYTES;\n if (!Number.isInteger(slotBytes) || slotBytes <= 0 || slotBytes % 4 !== 0) {\n throw invalid(\"slotBytes\", slotBytes, \"a positive multiple of 4\");\n }\n const slots = options?.slots ?? DEFAULT_STAGING_SLOTS;\n if (!Number.isInteger(slots) || slots < 0) {\n throw invalid(\"slots\", slots, \"a non-negative integer\");\n }\n this.device = device;\n this.allocator = allocator;\n this.slotBytes = slotBytes;\n for (let i = 0; i < slots; i++) {\n this.addSlot(slotBytes);\n }\n }\n\n /**\n * Copies `byteLength` bytes from `src` at `srcOffset` (own encoder, own submit), maps, copies out BEFORE unmap;\n * resolves the bytes (a fresh ArrayBuffer, or `dest.buffer` after `dest.set` when given). Requests above the slot\n * size are chunked.\n * @param src - a COPY_SRC buffer\n * @param byteLength - bytes to read (a positive multiple of 4, within src)\n * @param dest - an optional destination view of at least byteLength bytes over a plain ArrayBuffer\n * @param srcOffset - the byte offset in src (default 0; a multiple of 4)\n * @returns the bytes read\n */\n async read(src: GPUBuffer, byteLength: number, dest?: ArrayBufferView, srcOffset?: number): Promise<ArrayBuffer> {\n this.assertLive();\n const offset = srcOffset ?? 0;\n if (!Number.isInteger(byteLength) || byteLength <= 0 || byteLength % 4 !== 0) {\n throw invalid(\"byteLength\", byteLength, \"a positive multiple of 4\");\n }\n if (!Number.isInteger(offset) || offset < 0 || offset % 4 !== 0) {\n throw invalid(\"srcOffset\", offset, \"a non-negative multiple of 4\");\n }\n if (offset + byteLength > src.size) {\n throw invalid(\"byteLength\", byteLength, `srcOffset + byteLength <= src.size (${src.size})`);\n }\n if ((src.usage & BufferUsage.COPY_SRC) === 0) {\n throw invalid(\"src\", src.label, \"a buffer with COPY_SRC usage\");\n }\n let out: ArrayBuffer;\n let outBytes: Uint8Array;\n if (dest === undefined) {\n out = new ArrayBuffer(byteLength);\n outBytes = new Uint8Array(out);\n } else {\n if (isSharedBuffer(dest.buffer)) {\n throw invalid(\"dest\", \"SharedArrayBuffer\", \"a view over a plain ArrayBuffer\");\n }\n if (dest.byteLength < byteLength) {\n throw invalid(\"dest\", dest.byteLength, `at least ${byteLength} bytes`);\n }\n out = dest.buffer as ArrayBuffer;\n outBytes = new Uint8Array(out, dest.byteOffset, byteLength);\n }\n let done = 0;\n while (done < byteLength) {\n const chunk = Math.min(this.slotBytes, byteLength - done);\n const slot = this.borrowSlot(chunk);\n const entry = this.ring[slot.index];\n try {\n const encoder = this.device.createCommandEncoder({ label: \"readback\" });\n encoder.copyBufferToBuffer(src, offset + done, slot.buffer, 0, chunk);\n this.device.queue.submit([encoder.finish()]);\n await this.map(entry, chunk);\n outBytes.set(new Uint8Array(slot.buffer.getMappedRange(0, chunk)), done);\n } finally {\n this.returnSlot(slot);\n }\n done += chunk;\n }\n return out;\n }\n\n /**\n * Reads one u32 counter through the same ring.\n * @param src - a COPY_SRC buffer\n * @param byteOffset - the counter's byte offset (a multiple of 4)\n * @returns the counter value\n */\n async readU32(src: GPUBuffer, byteOffset: number): Promise<number> {\n const bytes = await this.read(src, 4, undefined, byteOffset);\n return new Uint32Array(bytes)[0];\n }\n\n /**\n * Borrows an unmapped slot of at least byteLength (grows the ring when none is free); the borrower ALWAYS\n * returns it (spec 4.4).\n * @param byteLength - the bytes the borrower will copy into the slot\n * @returns the slot\n */\n borrowSlot(byteLength: number): StagingSlot {\n this.assertLive();\n if (!Number.isInteger(byteLength) || byteLength <= 0) {\n throw invalid(\"byteLength\", byteLength, \"a positive integer\");\n }\n // a free slot is unmapped by construction: returnSlot unmaps, and only a borrower maps\n for (const entry of this.ring) {\n if (!entry.borrowed && entry.slot.capacity >= byteLength) {\n entry.borrowed = true;\n return entry.slot;\n }\n }\n const capacity = Math.max(this.slotBytes, Math.ceil(byteLength / SLOT_GRANULE) * SLOT_GRANULE);\n const entry = this.addSlot(capacity);\n entry.borrowed = true;\n return entry.slot;\n }\n\n /**\n * mapAsync(READ) on a borrowed slot, tracked by the ring: the slot counts as borrowed, and is neither unmapped\n * nor destroyed, until the map settles (see the file comment). Returns the runtime's own promise, untranslated:\n * the borrower classifies a rejection (a CommandBatch races it against device loss, spec 5.7).\n * @param slot - a slot borrowed from this ring and not yet returned\n * @param byteLength - the bytes to map from offset 0\n * @returns the mapAsync promise\n */\n mapSlot(slot: StagingSlot, byteLength: number): Promise<void> {\n this.assertLive();\n const entry = this.borrowedEntry(slot);\n if (entry.mapPending || entry.mapped) {\n throw invalid(\"slot\", slot.index, \"a borrowed slot that is not mapped and has no map pending\");\n }\n return this.track(entry, slot.buffer.mapAsync(MapMode.READ, 0, byteLength));\n }\n\n /**\n * Returns a borrowed slot (unmapping it if mapped). A slot whose map through the ring is still pending stays\n * borrowed until the map settles, when the ring unmaps and returns it; a borrower that maps a slot itself must\n * unmap it before returning it (spec 4.4; `mapState` decides when the runtime exposes it, otherwise the ring's\n * own record does). A no-op after destroyAll() (the ring is gone; a borrower's finally must never mask the\n * E_DISPOSED / E_DEVICE_LOST of the read it was serving).\n * @param slot - a slot borrowed from this ring and not yet returned\n */\n returnSlot(slot: StagingSlot): void {\n if (this.disposed) {\n return;\n }\n const entry = this.borrowedEntry(slot);\n if (entry.mapPending) {\n entry.returnRequested = true;\n return;\n }\n this.finishReturn(entry);\n }\n\n /**\n * The entry of a slot borrowed from this ring and not yet returned.\n * @param slot - the slot\n * @returns its entry\n */\n private borrowedEntry(slot: StagingSlot): SlotEntry {\n const entry = this.ring[slot.index];\n if (entry === undefined || entry.slot !== slot || !entry.borrowed) {\n throw invalid(\"slot\", slot.index, \"a slot borrowed from this ring and not yet returned\");\n }\n return entry;\n }\n\n /**\n * Unmaps a returned slot when it is mapped and frees it.\n * @param entry - the slot's entry (no map pending)\n */\n private finishReturn(entry: SlotEntry): void {\n const state: string | undefined = entry.slot.buffer.mapState;\n const mapped = state === undefined ? entry.mapped : state !== \"unmapped\";\n if (mapped) {\n entry.slot.buffer.unmap();\n }\n entry.mapped = false;\n entry.borrowed = false;\n entry.returnRequested = false;\n }\n\n /**\n * Tracks one mapAsync on a slot: mapPending until it settles, then the deferred work -- the destruction\n * destroyAll() left to the settle, or the return returnSlot() left to it. The handler is attached before the\n * promise is handed out, so it runs before any borrower's continuation.\n * @param entry - the slot's entry\n * @param pending - the runtime's mapAsync promise\n * @returns the same promise\n */\n private track(entry: SlotEntry, pending: Promise<void>): Promise<void> {\n entry.mapPending = true;\n const settle = (mapped: boolean): void => {\n entry.mapPending = false;\n entry.mapped = mapped;\n if (this.disposed) {\n if (mapped) {\n entry.slot.buffer.unmap();\n }\n this.destroySlot(entry);\n entry.mapped = false;\n return;\n }\n if (entry.returnRequested) {\n this.finishReturn(entry);\n }\n };\n void pending.then(\n () => {\n settle(true);\n },\n () => {\n settle(false);\n },\n );\n return pending;\n }\n\n /**\n * Number of slots (grows).\n * @returns the slot count\n */\n get slots(): number {\n return this.ring.length;\n }\n\n /**\n * Slots currently borrowed.\n * @returns the borrowed count\n */\n get borrowed(): number {\n let count = 0;\n for (const entry of this.ring) {\n if (entry.borrowed) {\n count++;\n }\n }\n return count;\n }\n\n /**\n * Destroys every staging buffer (ctx.dispose()); idempotent. A slot whose mapAsync is still pending is NOT\n * destroyed here (the file comment: dawn-node 0.4.0 settles the promise twice); its destruction is deferred to\n * the moment the map settles (track()), where a pending read() still rejects with E_DISPOSED as the contract\n * promises.\n * @internal\n */\n destroyAll(): void {\n for (const entry of this.ring) {\n if (entry.mapPending) {\n continue;\n }\n this.destroySlot(entry);\n }\n this.ring.length = 0;\n this.disposed = true;\n }\n\n /**\n * Destroys one slot's buffer through the allocator when it was created there.\n * @param entry - the slot\n */\n private destroySlot(entry: SlotEntry): void {\n if (entry.tracked) {\n this.allocator.destroy(entry.slot.buffer);\n } else {\n entry.slot.buffer.destroy();\n }\n }\n\n /**\n * Creates one slot at the end of the ring.\n * @param capacity - the slot's byte capacity\n * @returns the new entry\n */\n private addSlot(capacity: number): SlotEntry {\n const index = this.ring.length;\n const descriptor: GPUBufferDescriptor = {\n label: `readback:slot:${index}`,\n size: capacity,\n usage: STAGING_USAGE,\n };\n const tracked = capacity >= OOM_SCOPE_THRESHOLD_BYTES;\n const buffer = tracked ? this.allocator.createBuffer(descriptor) : this.device.createBuffer(descriptor);\n const entry: SlotEntry = {\n slot: Object.freeze({ index, buffer, capacity }),\n borrowed: false,\n mapped: false,\n mapPending: false,\n returnRequested: false,\n tracked,\n };\n this.ring.push(entry);\n return entry;\n }\n\n /**\n * mapAsync(READ) on a slot for read(); a rejection becomes E_DISPOSED (after destroyAll) or E_DEVICE_LOST.\n * @param entry - the ring entry of the borrowed slot\n * @param byteLength - the bytes to map\n */\n private async map(entry: SlotEntry, byteLength: number): Promise<void> {\n let mapped = false;\n let failure: unknown = null;\n try {\n await this.track(entry, entry.slot.buffer.mapAsync(MapMode.READ, 0, byteLength));\n mapped = true;\n } catch (err: unknown) {\n failure = err;\n }\n if (this.disposed) {\n // destroyAll() ran while the map was pending: track() finished the deferred destruction just before this\n throw new WebGpuGraphError(\"E_DISPOSED\", \"the readback ring was disposed while a read was pending\", {\n label: \"readback\",\n });\n }\n if (!mapped) {\n const message = failure instanceof Error ? failure.message : String(failure);\n throw new WebGpuGraphError(\"E_DEVICE_LOST\", `mapAsync rejected: ${message}`, {\n reason: \"mapAsync\",\n message,\n });\n }\n }\n\n /** Throws E_DISPOSED after destroyAll(). */\n private assertLive(): void {\n if (this.disposed) {\n throw new WebGpuGraphError(\"E_DISPOSED\", \"the readback ring was disposed\", { label: \"readback\" });\n }\n }\n}\n","/**\n * The pure upload planner of spec 4.2: from a snapshot's shape, the device limits and the core arrays a kernel\n * needs, choose the one-buffer arena upload (the hot prefix, or the full arena when a cold segment is needed and\n * fits), one buffer per array, or arc windows over the arc-indexed arrays. No GPU object is touched here:\n * GraphResidency (./residency.ts) executes arena and perArray plans and P4 executes windowed plans (P1-P3 only\n * plan them). Every byte length comes from counts and flags, so an identity permutation is never materialised\n * (spec 4.1), and every arithmetic step uses `%` and Math.floor, never a bitwise operator: arc indices and byte\n * offsets exceed 2^31 at the 10M / 100M tier (graph-format invariant I3, spec 4.2).\n */\n\nimport { type CoreArrayName, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { ARC_WINDOW_ALIGN } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type PlanCaps, type PlanLimits } from \"../types/context.js\";\nimport { type ArcWindow } from \"../types/memory.js\";\n\n/** The five core arrays in arena (hot-to-cold) order. */\nconst CORE_ORDER: readonly CoreArrayName[] = Object.freeze([\"rowPtr\", \"colIdx\", \"weights\", \"arcToEdge\", \"edgeToArc\"]);\n\n/** The arc-indexed arrays: the only ones a window can cover (rowPtr is row-indexed, edgeToArc edge-indexed). */\nconst ARC_INDEXED: ReadonlySet<CoreArrayName> = new Set<CoreArrayName>([\"colIdx\", \"weights\", \"arcToEdge\"]);\n\n/**\n * Where one core array's bytes go: one or more buffers (split at window boundaries only when the array exceeds\n * maxBufferSize). Exported with the plan union (contract 3.8): P4's windowed execution reads it; nothing at P1\n * imports it by name.\n * @public\n */\nexport interface PlannedArray {\n readonly name: CoreArrayName;\n readonly byteLength: number;\n readonly buffers: readonly { readonly byteOffset: number; readonly byteLength: number }[];\n}\n\n/**\n * The arena path: ONE buffer of `bytes`, one writeBuffer, per-segment bindings at `segment.byteOffset - arena.byteOffset`.\n * A member of the exported UploadPlan union (contract 3.8 exports the three plan shapes by name); nothing imports it\n * by name, which knip 5.77 reports.\n * @public\n */\nexport interface ArenaPlan {\n readonly kind: \"arena\";\n readonly bytes: number;\n readonly includesCold: boolean;\n readonly segments: Readonly<Record<CoreArrayName, { readonly offset: number; readonly size: number } | null>>;\n}\n\n/**\n * The per-array path: one buffer per needed array, whole-buffer bindings.\n * A member of the exported UploadPlan union (contract 3.8 exports the three plan shapes by name); nothing imports it\n * by name, which knip 5.77 reports.\n * @public\n */\nexport interface PerArrayPlan {\n readonly kind: \"perArray\";\n readonly arrays: readonly PlannedArray[];\n}\n\n/**\n * The windowed path: per-array buffers plus the arc windows kernels iterate (P4 executes; P1-P3 only plan).\n * A member of the exported UploadPlan union (contract 3.8 exports the three plan shapes by name); nothing imports it\n * by name, which knip 5.77 reports.\n * @public\n */\nexport interface WindowedPlan {\n readonly kind: \"windowed\";\n readonly arrays: readonly PlannedArray[];\n readonly windows: readonly ArcWindow[];\n readonly arcsPerWindow: number;\n}\n\n/** One of the three plans. */\nexport type UploadPlan = ArenaPlan | PerArrayPlan | WindowedPlan;\n\n/** One buffer range of a PlannedArray. */\ninterface BufferRange {\n readonly byteOffset: number;\n readonly byteLength: number;\n}\n\n/**\n * Byte length of every core array from the counts and flags alone; 0 means absent (unweighted, an identity\n * permutation, or zero length: spec 5.6 never binds a zero-length array). No array is read.\n * @param s - the snapshot\n * @returns the byte lengths keyed by core array name\n */\nfunction coreByteLengths(s: GraphSnapshot): Readonly<Record<CoreArrayName, number>> {\n const arcs = s.arcCount;\n const identity = s.flags.arcToEdgeIsIdentity;\n return {\n rowPtr: 4 * (s.nodeCount + 1),\n colIdx: 4 * arcs,\n weights: s.flags.weighted && arcs > 0 ? 4 * arcs : 0,\n arcToEdge: !identity && arcs > 0 ? 4 * arcs : 0,\n edgeToArc: !identity && s.edgeCount > 0 ? 4 * s.edgeCount : 0,\n };\n}\n\n/**\n * rowPtr always, then every requested PRESENT array, in arena order (absent names are dropped, never an error).\n * @param need - the requested names\n * @param lengths - the byte lengths of coreByteLengths\n * @returns the names to plan\n */\nfunction neededNames(\n need: readonly CoreArrayName[],\n lengths: Readonly<Record<CoreArrayName, number>>,\n): CoreArrayName[] {\n const wanted = new Set<CoreArrayName>(need);\n wanted.add(\"rowPtr\");\n return CORE_ORDER.filter((name) => wanted.has(name) && lengths[name] > 0);\n}\n\n/**\n * Rounds an arc count down to a multiple of ARC_WINDOW_ALIGN with `%` (a bitwise `& ~63` breaks above 2^31).\n * @param value - an arc count\n * @returns the largest multiple of 64 not above it\n */\nfunction alignDown(value: number): number {\n return value - (value % ARC_WINDOW_ALIGN);\n}\n\n/**\n * The E_TOO_LARGE error of spec 5.7 for a plan that cannot exist.\n * @param needed - the bytes that do not fit\n * @param limit - the limit they exceed\n * @param path - \"rowPtr\" (no window can hold rowPtr) or \"binding\" (an edge-indexed array cannot be windowed)\n * @returns the error to throw\n */\nfunction tooLarge(needed: number, limit: number, path: \"rowPtr\" | \"binding\"): WebGpuGraphError {\n return new WebGpuGraphError(\"E_TOO_LARGE\", `${path}: ${needed} bytes exceed the device limit of ${limit} bytes`, {\n needed,\n limit,\n path,\n algorithm: null,\n });\n}\n\n/**\n * The E_INVALID_ARGUMENT error of a bad planner input.\n * @param argument - the argument name\n * @param value - the value given\n * @param expected - what was expected\n * @returns the error to throw\n */\nfunction invalid(argument: string, value: unknown, expected: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${argument}: expected ${expected}`, {\n argument,\n value,\n expected,\n });\n}\n\n/**\n * The largest 64-aligned arc count one binding holds: floor(maxStorageBufferBindingSize / 4) rounded down to a\n * multiple of ARC_WINDOW_ALIGN.\n * @param limits - the device limits\n * @returns the arcs per window (0 when the binding limit is below 256 bytes)\n */\nexport function arcsPerWindowFor(limits: PlanLimits): number {\n return alignDown(Math.floor(limits.maxStorageBufferBindingSize / 4));\n}\n\n/**\n * The window list for a rowPtr (pure; unit-tested with a synthetic rowPtr above 2^31 arcs): start = rowPtr[v0] -\n * rowPtr[v0] % ARC_WINDOW_ALIGN, at most `arcsPerWindow` arcs per window, a row longer than a window split across\n * windows. Whole rows first: a window ends at the last row boundary within `start + arcsPerWindow`; a row that does\n * not fit a window opened at its own aligned start is split into aligned chunks whose `rowFirst === rowLast` is that\n * row, and the next window continues the row at the chunk end. Every row belongs to a window (leading and trailing\n * empty rows included); every window is placed in buffer 0 at offset 4 x start (planUpload re-places them when an\n * array is split across buffers).\n * @param rowPtr - nodeCount + 1 row offsets (rowPtr[nodeCount] === arcCount)\n * @param arcCount - the arc count\n * @param arcsPerWindow - a positive multiple of ARC_WINDOW_ALIGN\n * @returns the windows in arc order (empty for arcCount 0)\n */\nexport function planArcWindows(rowPtr: Uint32Array, arcCount: number, arcsPerWindow: number): ArcWindow[] {\n if (rowPtr.length === 0) {\n throw invalid(\"rowPtr\", rowPtr.length, \"nodeCount + 1 entries\");\n }\n if (\n !Number.isInteger(arcsPerWindow) ||\n arcsPerWindow < ARC_WINDOW_ALIGN ||\n arcsPerWindow % ARC_WINDOW_ALIGN !== 0\n ) {\n throw invalid(\"arcsPerWindow\", arcsPerWindow, `a positive multiple of ${ARC_WINDOW_ALIGN}`);\n }\n const n = rowPtr.length - 1;\n if (rowPtr[n] !== arcCount) {\n throw invalid(\"arcCount\", arcCount, `rowPtr[${n}] === ${rowPtr[n]}`);\n }\n const windows: ArcWindow[] = [];\n if (arcCount === 0) {\n return windows;\n }\n let pos = 0;\n let v = 0;\n let rowFirst = 0;\n while (pos < arcCount) {\n while (rowPtr[v + 1] <= pos) {\n v++;\n }\n const start = alignDown(pos);\n const limit = start + arcsPerWindow;\n if (rowPtr[v + 1] > limit) {\n windows.push({ start, end: limit, rowFirst, rowLast: v, bufferIndex: 0, offset: 4 * start });\n pos = limit;\n rowFirst = v;\n } else {\n let u = v;\n while (u + 1 < n && rowPtr[u + 2] <= limit) {\n u++;\n }\n const end = rowPtr[u + 1];\n windows.push({ start, end, rowFirst, rowLast: u, bufferIndex: 0, offset: 4 * start });\n pos = end;\n rowFirst = u + 1;\n }\n }\n return windows;\n}\n\n/**\n * Groups consecutive windows into buffers of at most `bufferLimit` bytes (spec 4.2: an array above maxBufferSize is\n * split across buffers at window boundaries) and re-places every window with its buffer index and offset.\n * @param windows - the windows of planArcWindows\n * @param arcBytes - the byte length of one arc-indexed array\n * @param bufferLimit - maxBufferSize\n * @returns the buffer ranges shared by every arc-indexed array and the placed windows\n */\nfunction placeWindows(\n windows: readonly ArcWindow[],\n arcBytes: number,\n bufferLimit: number,\n): { readonly buffers: BufferRange[]; readonly placed: ArcWindow[] } {\n if (arcBytes <= bufferLimit) {\n return { buffers: [{ byteOffset: 0, byteLength: arcBytes }], placed: [...windows] };\n }\n const buffers: BufferRange[] = [];\n const placed: ArcWindow[] = [];\n let first = 0;\n while (first < windows.length) {\n let last = first;\n while (last + 1 < windows.length && 4 * (windows[last + 1].end - windows[first].start) <= bufferLimit) {\n last++;\n }\n const base = windows[first].start;\n const bufferIndex = buffers.length;\n buffers.push({ byteOffset: 4 * base, byteLength: 4 * (windows[last].end - base) });\n for (let i = first; i <= last; i++) {\n const w = windows[i];\n placed.push({\n start: w.start,\n end: w.end,\n rowFirst: w.rowFirst,\n rowLast: w.rowLast,\n bufferIndex,\n offset: 4 * (w.start - base),\n });\n }\n first = last + 1;\n }\n return { buffers, placed };\n}\n\n/**\n * The pure planner of spec 4.2: arena (hot prefix unless `need` names a cold segment and the full arena fits) ->\n * perArray -> windowed, in that order. `need` always contains \"rowPtr\" (it is added when absent); absent arrays\n * (unweighted `weights`, identity permutations, zero-length arrays) are dropped; a snapshot with arcCount === 0\n * plans rowPtr only. The arena path needs `bytes <= maxBufferSize` and every needed segment within both limits;\n * ArenaPlan.segments lists every non-null segment inside the uploaded bytes (a needed cold segment outside them is\n * null: the residency uploads it as its own buffer). The perArray path needs every needed array within both limits;\n * otherwise the arc-indexed arrays are windowed (rowPtr and edgeToArc must fit, else E_TOO_LARGE).\n * @param s - the snapshot (only arena, the counts, the flags and rowPtr are read)\n * @param caps - the device capabilities (only `limits` is read)\n * @param need - the core arrays the kernel binds\n * @returns the plan\n */\nexport function planUpload(s: GraphSnapshot, caps: PlanCaps, need: readonly CoreArrayName[]): UploadPlan {\n const { limits } = caps;\n const binding = limits.maxStorageBufferBindingSize;\n const bufferLimit = limits.maxBufferSize;\n const fits = (bytes: number): boolean => bytes <= binding && bytes <= bufferLimit;\n const violated = (bytes: number): number => (bytes > binding ? binding : bufferLimit);\n const lengths = coreByteLengths(s);\n const names = neededNames(need, lengths);\n if (!fits(lengths.rowPtr)) {\n throw tooLarge(lengths.rowPtr, violated(lengths.rowPtr), \"rowPtr\");\n }\n const { arena } = s;\n if (arena !== null) {\n const coldNeeded = names.some(\n (name) => (name === \"arcToEdge\" || name === \"edgeToArc\") && arena.segments[name] !== null,\n );\n const includesCold = coldNeeded && arena.byteLength <= bufferLimit;\n const bytes = includesCold ? arena.byteLength : arena.hotByteLength;\n const bindable = names.every((name) => {\n const segment = arena.segments[name];\n return segment === null || fits(segment.byteLength);\n });\n if (bytes <= bufferLimit && bindable) {\n const segmentOf = (name: CoreArrayName): { readonly offset: number; readonly size: number } | null => {\n const segment = arena.segments[name];\n if (segment === null) {\n return null;\n }\n const offset = segment.byteOffset - arena.byteOffset;\n return offset + segment.byteLength <= bytes ? { offset, size: segment.byteLength } : null;\n };\n return {\n kind: \"arena\",\n bytes,\n includesCold,\n segments: {\n rowPtr: segmentOf(\"rowPtr\"),\n colIdx: segmentOf(\"colIdx\"),\n weights: segmentOf(\"weights\"),\n arcToEdge: segmentOf(\"arcToEdge\"),\n edgeToArc: segmentOf(\"edgeToArc\"),\n },\n };\n }\n }\n if (names.every((name) => fits(lengths[name]))) {\n return {\n kind: \"perArray\",\n arrays: names.map((name) => ({\n name,\n byteLength: lengths[name],\n buffers: [{ byteOffset: 0, byteLength: lengths[name] }],\n })),\n };\n }\n if (names.includes(\"edgeToArc\") && !fits(lengths.edgeToArc)) {\n throw tooLarge(lengths.edgeToArc, violated(lengths.edgeToArc), \"binding\");\n }\n const arcsPerWindow = Math.min(arcsPerWindowFor(limits), alignDown(Math.floor(bufferLimit / 4)));\n if (arcsPerWindow < ARC_WINDOW_ALIGN) {\n throw tooLarge(4 * ARC_WINDOW_ALIGN, binding, \"binding\");\n }\n const windows = planArcWindows(s.rowPtr, s.arcCount, arcsPerWindow);\n const { buffers, placed } = placeWindows(windows, 4 * s.arcCount, bufferLimit);\n const arrays: PlannedArray[] = names.map((name) =>\n ARC_INDEXED.has(name)\n ? { name, byteLength: lengths[name], buffers }\n : { name, byteLength: lengths[name], buffers: [{ byteOffset: 0, byteLength: lengths[name] }] },\n );\n return { kind: \"windowed\", arrays, windows: placed, arcsPerWindow };\n}\n","/**\n * The upload cache of spec 4.1 / 4.3 / 4.5: every core array, view array, column and ad hoc array a kernel binds\n * lives on the device exactly once per snapshot core, keyed on the typed-array object (or the Column object for\n * columns, PLAN DECISION 8), recorded per serial so `release(snapshot)` destroys every buffer of a snapshot and its\n * withColumns() siblings, and tombstoned so a live user learns of the release through `isReleased` (spec 4.5).\n * Uploads follow the pure planner of ./upload-plan.ts: the arena path writes ONE buffer with ONE writeBuffer of the\n * hot prefix (or the full arena when a cold segment is needed and fits) and binds segments at\n * `segment.byteOffset - arena.byteOffset`; the perArray path writes one buffer per array; the windowed path (P4-T7,\n * PD-8) writes one buffer per PlannedArray range of every arc-indexed array and binds window 0 as the default\n * colIdx / weights, the whole window list and the per-array buffers riding on the CoreBinding for the row-walking\n * primitives to bind per window. Identity permutations are never materialised: presence is\n * decided from counts and flags, and the arcToEdge / edgeToArc getters are read only when a segment exists. Nothing\n * is freed by garbage collection; the once-only warning above warnUnreleasedSnapshots names the missing release.\n */\n\nimport {\n type AttributeTable,\n type Column,\n type CoreArrayName,\n type GpuEligibility,\n type GraphSnapshot,\n type TypedArrayData,\n} from \"@graphty/graph-format\";\n\nimport { STORAGE_ALIGN } from \"../constants.js\";\nimport { type AllocationTracker } from \"../device/error-scope.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type PlanCaps } from \"../types/context.js\";\nimport { type ArcWindow, type Binding } from \"../types/memory.js\";\nimport { planUpload } from \"./upload-plan.js\";\n\n/** The core arrays a kernel binds by default (spec 4.1); the cold segments are named explicitly by the caller. */\nconst DEFAULT_NEED: readonly CoreArrayName[] = Object.freeze([\"rowPtr\", \"colIdx\", \"weights\"]);\n\n/** The five core arrays in arena (hot-to-cold) order. */\nconst CORE_ORDER: readonly CoreArrayName[] = Object.freeze([\"rowPtr\", \"colIdx\", \"weights\", \"arcToEdge\", \"edgeToArc\"]);\n\n/** The arc-indexed core arrays: the ones a windowed plan splits into window buffers (upload-plan.ts ARC_INDEXED). */\nconst ARC_INDEXED: readonly (\"colIdx\" | \"weights\" | \"arcToEdge\")[] = Object.freeze([\"colIdx\", \"weights\", \"arcToEdge\"]);\n\n/** Every resident buffer is bound by kernels, filled by writeBuffer and readable back (tests, readbacks of state). */\nconst RESIDENT_USAGE = BufferUsage.STORAGE | BufferUsage.COPY_DST | BufferUsage.COPY_SRC;\n\n/**\n * The core arrays of a snapshot on the device (spec 4.1); a null member is absent (zero-length, unweighted or an\n * identity permutation) and is bound as a dummy by the kernel layer (3.9). `Binding` itself is declared in\n * src/types/memory.ts (3.3). Exported by contract 3.8: P1-T4's graphBindings / graphOverrides and every later\n * kernel driver take it; nothing at P1-T2 imports it by name.\n * @public\n */\nexport interface CoreBinding {\n readonly serial: number;\n readonly plan: \"arena\" | \"perArray\" | \"windowed\";\n readonly rowPtr: Binding;\n readonly colIdx: Binding | null;\n readonly weights: Binding | null;\n readonly arcToEdge: Binding | null;\n readonly edgeToArc: Binding | null;\n readonly windows: readonly ArcWindow[] | null;\n /** The buffers each arc-indexed array was split into by the windowed plan (indexed by ArcWindow.bufferIndex; an absent array has none); non-null iff `plan === \"windowed\"`. */\n readonly arcBuffers: Readonly<Record<\"colIdx\" | \"weights\" | \"arcToEdge\", readonly GPUBuffer[]>> | null;\n readonly hasWeights: boolean;\n}\n\n/**\n * A view's arrays on the device plus the CPU-side scalars (degreeOrder's segmentOffsets) (spec 4.3). Exported by\n * contract 3.8: the degreeOrder permutation of P4's kernels is a ViewBinding; nothing at P1-T2 imports it by name.\n * @public\n */\nexport interface ViewBinding {\n readonly view:\n | \"reverse\"\n | \"coo\"\n | \"edgeList\"\n | \"outDegree\"\n | \"inDegree\"\n | \"degreeOrder\"\n | \"reverseDegreeOrder\"\n | \"mate\";\n readonly bindings: Readonly<Record<string, Binding>>;\n readonly scalars: Readonly<Record<string, readonly number[]>>;\n}\n\n/**\n * A column's gpuView() on the device (spec 4.3). Exported by contract 3.8: P3's layout inputs register columns\n * through it; nothing at P1-T2 imports it by name.\n * @public\n */\nexport interface ColumnBinding {\n readonly binding: Binding;\n readonly column: Column;\n readonly version: number;\n readonly eligibility: GpuEligibility;\n readonly components: number;\n}\n\n/**\n * An ad hoc array on the device (spec 4.1 last row); `destroy()` is the caller's when no owner was given. Exported\n * by contract 3.8: P3's model resolves column inputs to a registered ArrayBinding; nothing at P1-T2 imports it by\n * name.\n * @public\n */\nexport interface ArrayBinding {\n readonly binding: Binding;\n readonly byteLength: number;\n readonly owner: GraphSnapshot | null;\n destroy(): void;\n}\n\n/**\n * stats() shape (spec 4.1). Exported by contract 3.8 for the callers of ctx.residency.stats(); nothing at P1-T2\n * imports it by name.\n * @public\n */\nexport interface ResidencyStats {\n readonly buffers: number;\n readonly bytes: number;\n readonly snapshots: number;\n readonly perSnapshot: readonly {\n readonly serial: number;\n readonly label: string | null;\n readonly bytes: number;\n readonly buffers: number;\n }[];\n}\n\n/** One buffer the residency owns. */\ninterface Resident {\n /** The typed-array object or the Column object the buffer was uploaded for. */\n readonly key: object;\n readonly buffer: GPUBuffer;\n readonly byteLength: number;\n /** The owning record's serial, or null for an owner-less ad hoc array. */\n readonly serial: number | null;\n /** For columns: the column.version the buffer holds. */\n version: number;\n destroyed: boolean;\n}\n\n/** One uploaded segment of the arena buffer. */\ninterface ArenaSegmentBinding {\n readonly offset: number;\n readonly size: number;\n}\n\n/** Everything recorded for one serial (a snapshot and its withColumns() siblings). */\ninterface ResidencyRecord {\n readonly serial: number;\n readonly label: string | null;\n readonly entries: Resident[];\n plan: \"arena\" | \"perArray\" | \"windowed\" | null;\n arena: {\n readonly buffer: GPUBuffer;\n readonly segments: Readonly<Record<CoreArrayName, ArenaSegmentBinding | null>>;\n } | null;\n readonly bindings: Map<CoreArrayName, Binding>;\n /** Memo of the P7 views by `name` or `name + \":packed\"`, so a second view() call uploads nothing (spec 4.3). */\n readonly views: Map<string, ViewBinding>;\n /**\n * One fresh marker object per PACKED view, keyed the same way as `views`. It is the `key` argument of\n * upload(): a packed view must never be keyed on one of the snapshot's own arrays, because upload()\n * memoises on the key object and does NOT compare byte lengths, and `s.reverse()` is cached\n * (graph-format `graph-snapshot.ts:600-601`) so the packed and the unpacked builder see the same\n * `rev.rowPtr` object.\n */\n readonly packKeys: Map<string, object>;\n /** One marker object per window buffer, keyed `<name>:<bufferIndex>` (the packKey pattern: never one of the snapshot's own arrays). */\n readonly windowKeys: Map<string, object>;\n /** The windowed plan's windows, or null on the arena / perArray plans. */\n windows: readonly ArcWindow[] | null;\n /** The window buffers of every arc-indexed array uploaded so far (windowed plan only). */\n readonly arcBuffers: Map<CoreArrayName, GPUBuffer[]>;\n released: boolean;\n}\n\n/**\n * Whether a core array is arc-indexed (split into window buffers by a windowed plan).\n * @param name - the core array\n * @returns true for colIdx, weights and arcToEdge\n */\nfunction isArcIndexed(name: CoreArrayName): name is \"colIdx\" | \"weights\" | \"arcToEdge\" {\n return (ARC_INDEXED as readonly CoreArrayName[]).includes(name);\n}\n\n/**\n * Whether an ArrayBuffer-like is a SharedArrayBuffer (checked by tag so the global need not exist).\n * @param buffer - the buffer to test\n * @returns true for a SharedArrayBuffer\n */\nfunction isSharedBuffer(buffer: ArrayBufferLike): boolean {\n return Object.prototype.toString.call(buffer) === \"[object SharedArrayBuffer]\";\n}\n\n/**\n * The E_INVALID_ARGUMENT error of a bad residency argument.\n * @param argument - the argument name\n * @param value - the value given\n * @param expected - what was expected\n * @returns the error to throw\n */\nfunction invalid(argument: string, value: unknown, expected: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${argument}: expected ${expected}`, {\n argument,\n value,\n expected,\n });\n}\n\n/**\n * Throws E_SNAPSHOT { reason: \"detached\" } for a snapshot whose core was transferred away.\n * @param s - the snapshot\n */\nfunction assertAttached(s: GraphSnapshot): void {\n if (s.detached) {\n throw new WebGpuGraphError(\"E_SNAPSHOT\", `snapshot ${s.serial} is detached (its core was transferred away)`, {\n reason: \"detached\",\n serial: s.serial,\n });\n }\n}\n\n/**\n * Whether a core array exists on the snapshot, from counts and flags alone (mirrors coreByteLengths of\n * ./upload-plan.ts; spec 5.6: zero-length arrays are never uploaded; spec 4.1: identity permutations never\n * materialised).\n * @param s - the snapshot\n * @param name - the core array\n * @returns true when the array has bytes to upload\n */\nfunction isPresent(s: GraphSnapshot, name: CoreArrayName): boolean {\n switch (name) {\n case \"rowPtr\":\n return true;\n case \"colIdx\":\n return s.arcCount > 0;\n case \"weights\":\n return s.flags.weighted && s.arcCount > 0;\n case \"arcToEdge\":\n return !s.flags.arcToEdgeIsIdentity && s.arcCount > 0;\n case \"edgeToArc\":\n return !s.flags.arcToEdgeIsIdentity && s.edgeCount > 0;\n default:\n return false;\n }\n}\n\n/**\n * The array object of a PRESENT core array (the caller checked isPresent, so the two getters never materialise).\n * @param s - the snapshot\n * @param name - the core array\n * @returns the array\n */\nfunction coreArray(s: GraphSnapshot, name: CoreArrayName): TypedArrayData {\n switch (name) {\n case \"rowPtr\":\n return s.rowPtr;\n case \"colIdx\":\n return s.colIdx;\n case \"weights\": {\n const { weights } = s;\n if (weights === null) {\n throw invalid(\"weights\", null, \"a weighted snapshot\");\n }\n return weights;\n }\n case \"arcToEdge\":\n return s.arcToEdge;\n case \"edgeToArc\":\n return s.edgeToArc;\n default:\n throw invalid(\"name\", name, \"a core array name\");\n }\n}\n\n/** The upload cache (spec 4.1): WeakMap on array objects, WeakMap on snapshots, a strong Map by serial; @internal (reached as ctx.residency). */\nexport class GraphResidency {\n private readonly device: GPUDevice;\n private readonly caps: PlanCaps;\n private readonly allocator: AllocationTracker;\n private readonly warnUnreleasedSnapshots: number;\n private readonly warn: (message: string) => void;\n /** Fast lookup by the uploaded object (a typed array or a Column). */\n private readonly residents = new WeakMap<object, Resident>();\n /** Fast lookup of a snapshot's record (entries of released records are recognised by `released`). */\n private readonly records = new WeakMap<GraphSnapshot, ResidencyRecord>();\n /** The strong map by serial: withColumns() siblings share one record; cleared by release. */\n private readonly bySerial = new Map<number, ResidencyRecord>();\n /** Owner-less ad hoc arrays. */\n private readonly orphans = new Set<Resident>();\n /** Serials released and not re-uploaded. */\n private readonly tombstones = new Set<number>();\n private liveCount = 0;\n private liveBytesValue = 0;\n private warned = false;\n private disposed = false;\n\n /**\n * Creates an empty residency over a device.\n * @param device - the device (queue.writeBuffer)\n * @param caps - the device capabilities the planner reads\n * @param allocator - the context's OOM-scoped allocator (every buffer is created and destroyed through it)\n * @param options - the once-only warning\n * @param options.warnUnreleasedSnapshots - the resident-snapshot count above which the warning fires once\n * @param options.warn - the warning sink; default console.warn\n */\n constructor(\n device: GPUDevice,\n caps: PlanCaps,\n allocator: AllocationTracker,\n options: { readonly warnUnreleasedSnapshots: number; readonly warn?: ((message: string) => void) | undefined },\n ) {\n this.device = device;\n this.caps = caps;\n this.allocator = allocator;\n this.warnUnreleasedSnapshots = options.warnUnreleasedSnapshots;\n this.warn =\n options.warn ??\n ((message: string): void => {\n console.warn(message);\n });\n }\n\n /**\n * Uploads (or finds) the core; `need` defaults to [\"rowPtr\", \"colIdx\", \"weights\"]; cold segments on demand\n * (spec 4.2). Never materialises an identity permutation. A windowed plan (spec 4.2, PD-8) uploads every\n * arc-indexed array as the plan's buffer ranges and binds window 0 as its default binding; rowPtr and edgeToArc\n * stay whole. A tombstoned serial is lifted and re-uploaded (PLAN DECISION 7).\n * @param s - the snapshot\n * @param need - the core arrays to bind (rowPtr is always included; absent arrays are ignored)\n * @returns the core binding (a frozen object; grows as cold segments are added)\n */\n core(s: GraphSnapshot, need?: readonly CoreArrayName[]): CoreBinding {\n this.assertLive();\n assertAttached(s);\n const wanted = need ?? DEFAULT_NEED;\n const names = CORE_ORDER.filter((name) => (name === \"rowPtr\" || wanted.includes(name)) && isPresent(s, name));\n const plan = planUpload(s, this.caps, names);\n const record = this.ensureRecord(s);\n if (record.plan === null) {\n record.plan = plan.kind;\n if (plan.kind === \"arena\" && s.arena !== null) {\n const { arena } = s;\n const resident = this.upload(\n record,\n s.rowPtr,\n new Uint8Array(arena.buffer, arena.byteOffset, plan.bytes),\n `residency:core:${record.serial}:arena`,\n );\n record.arena = { buffer: resident.buffer, segments: plan.segments };\n }\n if (plan.kind === \"windowed\") {\n record.windows = plan.windows;\n }\n }\n for (const name of names) {\n if (!record.bindings.has(name)) {\n const planned = plan.kind === \"windowed\" ? plan.arrays.find((a) => a.name === name) : undefined;\n record.bindings.set(\n name,\n planned !== undefined && planned.buffers.length > 0 && record.windows !== null && isArcIndexed(name)\n ? this.bindWindowed(record, s, name, planned.buffers, record.windows[0])\n : this.bindCore(record, s, name),\n );\n }\n }\n const rowPtr = record.bindings.get(\"rowPtr\");\n if (rowPtr === undefined) {\n throw invalid(\"rowPtr\", null, \"a bound rowPtr (internal invariant)\");\n }\n const weights = record.bindings.get(\"weights\") ?? null;\n return Object.freeze({\n serial: record.serial,\n plan: plan.kind,\n rowPtr,\n colIdx: record.bindings.get(\"colIdx\") ?? null,\n weights,\n arcToEdge: record.bindings.get(\"arcToEdge\") ?? null,\n edgeToArc: record.bindings.get(\"edgeToArc\") ?? null,\n windows: record.windows,\n arcBuffers:\n record.windows === null\n ? null\n : Object.freeze({\n colIdx: Object.freeze([...(record.arcBuffers.get(\"colIdx\") ?? [])]),\n weights: Object.freeze([...(record.arcBuffers.get(\"weights\") ?? [])]),\n arcToEdge: Object.freeze([...(record.arcBuffers.get(\"arcToEdge\") ?? [])]),\n }),\n hasWeights: weights !== null,\n });\n }\n\n /**\n * Uploads (or finds) a view: outDegree / inDegree / degreeOrder / reverseDegreeOrder upload one array each;\n * reverse and edgeList (P7) upload their arrays perArray, never into the arena, and are memoised per record so\n * a second call uploads nothing (spec 4.3). coo uploads its per-arc `src` (P11; the rest aliases the core); mate ->\n * E_UNSUPPORTED. packViews concatenates a\n * reverse or edgeList view into ONE buffer at STORAGE_ALIGN offsets; on any other view `true` is E_UNSUPPORTED\n * { option: \"packViews\" }.\n * @param s - the snapshot\n * @param name - the view\n * @param options - view options\n * @param options.packViews - pack the reverse / edgeList arrays into one buffer (a no-op on an undirected reverse)\n * @returns the view binding\n */\n view(\n s: GraphSnapshot,\n name: \"reverse\" | \"coo\" | \"edgeList\" | \"outDegree\" | \"inDegree\" | \"degreeOrder\" | \"reverseDegreeOrder\" | \"mate\",\n options?: { readonly packViews?: boolean | undefined },\n ): ViewBinding {\n this.assertLive();\n assertAttached(s);\n const packed = options?.packViews === true;\n if (name === \"reverse\" || name === \"edgeList\") {\n this.assertNotReleased(s);\n this.assertNonEmpty(s);\n const memoKey = packed ? `${name}:packed` : name;\n const record = this.ensureRecord(s);\n const memo = record.views.get(memoKey);\n if (memo !== undefined) {\n return memo;\n }\n const built =\n name === \"reverse\" ? this.buildReverse(s, record, packed) : this.buildEdgeList(s, record, packed);\n record.views.set(memoKey, built);\n return built;\n }\n if (packed) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"packViews applies to the reverse and edgeList views only\", {\n option: \"packViews\",\n hint: `the ${name} view uploads one array`,\n });\n }\n let array: TypedArrayData;\n let bindingName: string;\n let scalars: Readonly<Record<string, readonly number[]>> = {};\n switch (name) {\n case \"outDegree\":\n this.assertNotReleased(s);\n this.assertNonEmpty(s);\n array = s.outDegree();\n bindingName = \"outDegree\";\n break;\n case \"inDegree\":\n this.assertNotReleased(s);\n this.assertNonEmpty(s);\n array = s.inDegree();\n bindingName = \"inDegree\";\n break;\n case \"degreeOrder\": {\n this.assertNotReleased(s);\n this.assertNonEmpty(s);\n const order = s.degreeOrder();\n array = order.perm;\n bindingName = \"perm\";\n scalars = { segmentOffsets: Array.from(order.segmentOffsets) };\n break;\n }\n case \"reverseDegreeOrder\": {\n this.assertNotReleased(s);\n this.assertNonEmpty(s);\n const order = s.degreeOrder({ of: \"reverse\" });\n array = order.perm;\n bindingName = \"perm\";\n scalars = { segmentOffsets: Array.from(order.segmentOffsets) };\n break;\n }\n case \"coo\":\n // dst, arcToEdge and weights alias the core's colIdx / arcToEdge / weights (graph-format design 7.2):\n // only the per-arc source is new, and a kernel binds the rest from core()\n this.assertNotReleased(s);\n this.assertNonEmpty(s);\n if (s.arcCount === 0) {\n return Object.freeze({ view: name, bindings: Object.freeze({}), scalars: Object.freeze({}) });\n }\n array = s.coo().src;\n bindingName = \"src\";\n break;\n case \"mate\":\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"the mate view is not uploaded: no kernel reads it\", {\n feature: \"view:mate\",\n hint: \"outDegree, inDegree, degreeOrder, reverseDegreeOrder, coo, reverse and edgeList are uploaded\",\n });\n default:\n throw invalid(\"name\", name, \"a view name\");\n }\n const record = this.ensureRecord(s);\n const resident = this.upload(record, array, array, `residency:view:${record.serial}:${name}`);\n const binding: Binding = { buffer: resident.buffer, offset: 0, size: resident.byteLength, window: null };\n return Object.freeze({\n view: name,\n bindings: Object.freeze({ [bindingName]: binding }),\n scalars: Object.freeze(scalars),\n });\n }\n\n /**\n * The reverse adjacency's bindings. On an UNDIRECTED snapshot graph-format invariant I7 makes reverse() return\n * the FORWARD arrays, so the core bindings ARE the reverse bindings and nothing is uploaded -- delegating to\n * core() rather than re-uploading the arrays is what makes that true on the arena plan as well, where the\n * per-array WeakMap key resolves to the whole-arena resident (spec 4.3 lines 1182-1186). `fwdArc` is never\n * uploaded (spec 13 row P7). `packed` is ignored when undirected: there is nothing to pack.\n * @param s - the snapshot\n * @param record - its residency record\n * @param packed - concatenate the arrays into one buffer (directed only)\n * @returns the view binding\n */\n private buildReverse(s: GraphSnapshot, record: ResidencyRecord, packed: boolean): ViewBinding {\n const rev = s.reverse();\n if (!s.directed) {\n const core = this.core(s, [\"rowPtr\", \"colIdx\", \"weights\"]);\n if (core.plan === \"windowed\") {\n // a view is never windowed (spec 4.3): window 0's colIdx must not pose as the whole reverse adjacency\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `snapshot ${s.serial}: the undirected reverse view is the core, which needs arc windows (${core.windows?.length ?? 0}) that no view executes`,\n {\n needed: 4 * s.arcCount,\n limit: this.caps.limits.maxStorageBufferBindingSize,\n path: \"windowed\",\n algorithm: null,\n },\n );\n }\n const bindings: Record<string, Binding> = { rowPtr: core.rowPtr };\n if (core.colIdx !== null) {\n bindings.colIdx = core.colIdx;\n }\n if (core.weights !== null) {\n bindings.weights = core.weights;\n }\n return Object.freeze({\n view: \"reverse\",\n bindings: Object.freeze(bindings),\n scalars: Object.freeze({ arcCount: [rev.arcCount], directed: [0] }),\n });\n }\n const arrays: [string, TypedArrayData][] = [\n [\"rowPtr\", rev.rowPtr],\n [\"colIdx\", rev.colIdx],\n ];\n if (rev.weights !== null) {\n arrays.push([\"weights\", rev.weights]);\n }\n const bindings = packed\n ? this.packArrays(\n record,\n arrays,\n this.packKey(record, \"reverse:packed\"),\n `residency:view:${record.serial}:reverse:packed`,\n )\n : this.separateArrays(record, arrays, `residency:view:${record.serial}:reverse`);\n return Object.freeze({\n view: \"reverse\",\n bindings,\n scalars: Object.freeze({ arcCount: [rev.arcCount], directed: [1] }),\n });\n }\n\n /**\n * The each-edge-once binding an edge-parallel kernel uses on directed and undirected snapshots alike (spec 8.1\n * row 2); `arc` is not uploaded (no kernel of P7 reads it).\n * @param s - the snapshot\n * @param record - its residency record\n * @param packed - concatenate into one buffer\n * @returns the view binding\n */\n private buildEdgeList(s: GraphSnapshot, record: ResidencyRecord, packed: boolean): ViewBinding {\n const list = s.edgeList();\n const arrays: [string, TypedArrayData][] = [\n [\"src\", list.src],\n [\"dst\", list.dst],\n ];\n if (list.weights !== null) {\n arrays.push([\"weights\", list.weights]);\n }\n const bindings = packed\n ? this.packArrays(\n record,\n arrays,\n this.packKey(record, \"edgeList:packed\"),\n `residency:view:${record.serial}:edgeList:packed`,\n )\n : this.separateArrays(record, arrays, `residency:view:${record.serial}:edgeList`);\n return Object.freeze({\n view: \"edgeList\",\n bindings,\n scalars: Object.freeze({ edgeCount: [s.edgeCount] }),\n });\n }\n\n /**\n * One resident per array (spec 4.3: views upload in perArray mode, never into the arena). An empty array (the\n * colIdx of an edgeless directed reverse view, the src / dst of an edgeless edgeList) is skipped: spec 5.6 never\n * uploads a zero-length array, and Kernel.bind rejects a zero-size binding, so it is absent as in core().\n * @param record - the owning record\n * @param arrays - the named arrays\n * @param label - the buffer label prefix\n * @returns the bindings by name\n */\n private separateArrays(\n record: ResidencyRecord,\n arrays: readonly (readonly [string, TypedArrayData])[],\n label: string,\n ): Readonly<Record<string, Binding>> {\n const bindings: Record<string, Binding> = {};\n for (const [name, array] of arrays) {\n if (array.byteLength === 0) {\n continue;\n }\n const resident = this.upload(record, array, array, `${label}:${name}`);\n bindings[name] = { buffer: resident.buffer, offset: 0, size: resident.byteLength, window: null };\n }\n return Object.freeze(bindings);\n }\n\n /**\n * The arrays concatenated into ONE buffer at STORAGE_ALIGN-aligned offsets (spec 4.3 packViews): one\n * createBuffer and one writeBuffer instead of three of each, which is what the option buys. The resident is\n * keyed on `key`, a marker object owned by the record (packKey), NOT on one of the snapshot's arrays: upload()\n * returns an existing resident whenever the key matches and the serial matches, without comparing byte\n * lengths, so keying the packed buffer on `rev.rowPtr` would make the packed and the unpacked view of one\n * snapshot collide -- whichever was built second would get the other's buffer. The record still owns the\n * resident, so release(s) destroys it with the rest. Offsets are STORAGE_ALIGN-aligned because Kernel.bind\n * rejects any other offset synchronously (E_INVALID_ARGUMENT { argument: \"offset\" }). Empty arrays are left\n * out as in separateArrays; when nothing is left, nothing is uploaded.\n * @param record - the owning record\n * @param all - the named arrays, in buffer order\n * @param key - the marker object the resident is keyed on\n * @param label - the buffer label\n * @returns the bindings by name, all into the one buffer\n */\n private packArrays(\n record: ResidencyRecord,\n all: readonly (readonly [string, TypedArrayData])[],\n key: object,\n label: string,\n ): Readonly<Record<string, Binding>> {\n const arrays = all.filter(([, array]) => array.byteLength > 0);\n if (arrays.length === 0) {\n return Object.freeze({});\n }\n const offsets: number[] = [];\n let total = 0;\n for (const [, array] of arrays) {\n offsets.push(total);\n total += Math.ceil(array.byteLength / STORAGE_ALIGN) * STORAGE_ALIGN;\n }\n const staging = new Uint8Array(total);\n arrays.forEach(([, array], i) => {\n staging.set(new Uint8Array(array.buffer, array.byteOffset, array.byteLength), offsets[i]);\n });\n const resident = this.upload(record, key, staging, label);\n const bindings: Record<string, Binding> = {};\n arrays.forEach(([name, array], i) => {\n bindings[name] = { buffer: resident.buffer, offset: offsets[i], size: array.byteLength, window: null };\n });\n return Object.freeze(bindings);\n }\n\n /**\n * The upload key of a packed view: a marker object allocated once per record and memo name, never one of the\n * snapshot's arrays.\n * @param record - the owning record\n * @param memoKey - the `views` memo key of this packed view\n * @returns the stable marker object\n */\n private packKey(record: ResidencyRecord, memoKey: string): object {\n const existing = record.packKeys.get(memoKey);\n if (existing !== undefined) {\n return existing;\n }\n const created = {};\n record.packKeys.set(memoKey, created);\n return created;\n }\n\n /**\n * gpuView(name) + column.version; re-uploads in place when the version changed and the byte length did not\n * (spec 4.3). CONTRACT DECISION: `owner` is required so release(owner) can find the buffer (a table has no\n * back-reference to its snapshot). The key is the Column object (PLAN DECISION 8). E_GPU_INELIGIBLE and\n * E_UNKNOWN_COLUMN from the format pass through unchanged.\n * @param table - the table holding the column\n * @param name - the column name\n * @param owner - the snapshot the buffer is recorded against\n * @returns the column binding\n */\n column(table: AttributeTable, name: string, owner: GraphSnapshot): ColumnBinding {\n this.assertLive();\n assertAttached(owner);\n this.assertNotReleased(owner);\n const column = table.require(name);\n const data = table.gpuView(name);\n if (data.byteLength === 0) {\n throw invalid(\"column\", name, \"a column with at least one row (zero-length arrays are never uploaded)\");\n }\n const record = this.ensureRecord(owner);\n const label = `residency:column:${record.serial}:${column.meta.domain}.${name}`;\n const existing = this.residents.get(column);\n let resident: Resident;\n if (\n existing !== undefined &&\n !existing.destroyed &&\n existing.serial === record.serial &&\n existing.byteLength === data.byteLength\n ) {\n resident = existing;\n if (resident.version !== column.version) {\n this.device.queue.writeBuffer(resident.buffer, 0, data);\n resident.version = column.version;\n }\n } else {\n if (existing !== undefined) {\n // the stale buffer stays in its record until release (spec 4.1: no leak, no stale read)\n this.residents.delete(column);\n }\n resident = this.upload(record, column, data, label);\n resident.version = column.version;\n }\n return Object.freeze({\n binding: { buffer: resident.buffer, offset: 0, size: resident.byteLength, window: null },\n column,\n version: resident.version,\n eligibility: column.gpu,\n components: column.meta.components,\n });\n }\n\n /**\n * Any format array keyed on the object; registered against `owner` when given (spec 4.1).\n * @param key - the array (a non-empty, 4-byte-multiple array over a plain ArrayBuffer)\n * @param label - the buffer label suffix\n * @param owner - the snapshot to record the buffer against, or undefined for a caller-owned buffer\n * @returns the array binding; `destroy()` is idempotent (PLAN DECISION 12)\n */\n array(key: TypedArrayData, label: string, owner?: GraphSnapshot): ArrayBinding {\n this.assertLive();\n if (key.byteLength === 0 || key.byteLength % 4 !== 0) {\n throw invalid(\"key\", key.byteLength, \"a non-empty array whose byteLength is a multiple of 4\");\n }\n if (isSharedBuffer(key.buffer)) {\n throw invalid(\"key\", \"SharedArrayBuffer\", \"an array over a plain ArrayBuffer\");\n }\n let record: ResidencyRecord | null = null;\n if (owner !== undefined) {\n assertAttached(owner);\n this.assertNotReleased(owner);\n record = this.ensureRecord(owner);\n }\n const resident = this.upload(record, key, key, `residency:array:${label}`);\n const binding: Binding = { buffer: resident.buffer, offset: 0, size: resident.byteLength, window: null };\n return {\n binding,\n byteLength: resident.byteLength,\n owner: owner ?? null,\n destroy: (): void => {\n this.destroyResident(resident, record);\n },\n };\n }\n\n /**\n * Destroys every buffer recorded for s.serial (siblings included, Q-27) and tombstones the serial; idempotent\n * (spec 4.5); safe on a snapshot never uploaded (nothing to tombstone, PLAN DECISION 7).\n * @param s - the snapshot (or any withColumns() sibling)\n */\n release(s: GraphSnapshot): void {\n const record = this.bySerial.get(s.serial);\n if (record === undefined) {\n return;\n }\n for (const resident of [...record.entries]) {\n this.destroyResident(resident, record);\n }\n this.forget(record);\n this.tombstones.add(s.serial);\n }\n\n /** Drops every record WITHOUT destroying (device lost: the buffers are gone). @internal */\n clearOnLoss(): void {\n for (const record of [...this.bySerial.values()]) {\n for (const resident of record.entries) {\n resident.destroyed = true;\n if (this.residents.get(resident.key) === resident) {\n this.residents.delete(resident.key);\n }\n }\n record.entries.length = 0;\n this.forget(record);\n }\n for (const resident of this.orphans) {\n resident.destroyed = true;\n if (this.residents.get(resident.key) === resident) {\n this.residents.delete(resident.key);\n }\n }\n this.orphans.clear();\n this.liveCount = 0;\n this.liveBytesValue = 0;\n }\n\n /** Destroys everything (ctx.dispose()); idempotent. @internal */\n destroyAll(): void {\n for (const record of [...this.bySerial.values()]) {\n for (const resident of [...record.entries]) {\n this.destroyResident(resident, record);\n }\n this.forget(record);\n }\n for (const resident of [...this.orphans]) {\n this.destroyResident(resident, null);\n }\n this.disposed = true;\n }\n\n /**\n * The resident buffers, bytes and snapshots (spec 4.1).\n * @returns the statistics\n */\n stats(): ResidencyStats {\n const perSnapshot = [...this.bySerial.values()].map((record) => ({\n serial: record.serial,\n label: record.label,\n bytes: record.entries.reduce((sum, resident) => sum + resident.byteLength, 0),\n buffers: record.entries.length,\n }));\n return { buffers: this.liveCount, bytes: this.liveBytesValue, snapshots: this.bySerial.size, perSnapshot };\n }\n\n /**\n * Bytes of every resident buffer (graft: C R-18).\n * @returns the resident byte count\n */\n get residentBytes(): number {\n return this.liveBytesValue;\n }\n\n /**\n * True when the serial was released and not re-uploaded. @internal\n * @param serial - a snapshot serial\n * @returns whether a live user holding bindings of that serial must stop\n */\n isReleased(serial: number): boolean {\n return this.tombstones.has(serial);\n }\n\n /**\n * Binds one core array: a segment of the arena buffer when the buffer holds it, else its own buffer keyed on\n * the array object (the cold-segment-on-demand path of spec 4.2, and the whole perArray path).\n * @param record - the snapshot's record\n * @param s - the snapshot\n * @param name - a PRESENT core array\n * @returns the binding\n */\n private bindCore(record: ResidencyRecord, s: GraphSnapshot, name: CoreArrayName): Binding {\n if (record.arena !== null) {\n const segment = record.arena.segments[name];\n if (segment !== null) {\n return { buffer: record.arena.buffer, offset: segment.offset, size: segment.size, window: null };\n }\n }\n const array = coreArray(s, name);\n const resident = this.upload(record, array, array, `residency:core:${record.serial}:${name}`);\n return { buffer: resident.buffer, offset: 0, size: resident.byteLength, window: null };\n }\n\n /**\n * Uploads one arc-indexed array as the windowed plan's buffer ranges (spec 4.2: an array above maxBufferSize is\n * split across buffers at window boundaries), each keyed on a marker object of the record (windowKey), and\n * returns window 0's binding so a caller that ignores windows still binds something valid (PD-8).\n * @param record - the snapshot's record\n * @param s - the snapshot\n * @param name - a PRESENT arc-indexed core array\n * @param ranges - the plan's buffer ranges of the array\n * @param first - window 0\n * @returns the binding of window 0\n */\n private bindWindowed(\n record: ResidencyRecord,\n s: GraphSnapshot,\n name: \"colIdx\" | \"weights\" | \"arcToEdge\",\n ranges: readonly { readonly byteOffset: number; readonly byteLength: number }[],\n first: ArcWindow,\n ): Binding {\n const array = coreArray(s, name);\n const buffers = ranges.map(\n (range, index) =>\n this.upload(\n record,\n this.windowKey(record, `${name}:${index}`),\n new Uint8Array(array.buffer, array.byteOffset + range.byteOffset, range.byteLength),\n `residency:core:${record.serial}:${name}:w${index}`,\n ).buffer,\n );\n record.arcBuffers.set(name, buffers);\n return {\n buffer: buffers[first.bufferIndex],\n offset: first.offset,\n size: 4 * (first.end - first.start),\n window: first,\n };\n }\n\n /**\n * The upload key of one window buffer: a marker object allocated once per record and `<name>:<bufferIndex>`.\n * @param record - the owning record\n * @param memoKey - `<name>:<bufferIndex>`\n * @returns the stable marker object\n */\n private windowKey(record: ResidencyRecord, memoKey: string): object {\n const existing = record.windowKeys.get(memoKey);\n if (existing !== undefined) {\n return existing;\n }\n const created = {};\n record.windowKeys.set(memoKey, created);\n return created;\n }\n\n /**\n * Uploads `data` into a new buffer keyed on `key`, or returns the resident already uploaded for that key by\n * the same owner (PLAN DECISION 11: a resident belongs to one record).\n * @param record - the owning record, or null for an owner-less array\n * @param key - the object the buffer is keyed on\n * @param data - the bytes (byteLength a multiple of 4, graph-format invariant I10; a view over a plain\n * ArrayBuffer, which is what writeBuffer's GPUAllowSharedBufferSource accepts under @webgpu/types 0.1.72)\n * @param label - the buffer label\n * @returns the resident\n */\n private upload(\n record: ResidencyRecord | null,\n key: object,\n data: ArrayBufferView<ArrayBuffer>,\n label: string,\n ): Resident {\n const serial = record === null ? null : record.serial;\n const existing = this.residents.get(key);\n if (existing !== undefined && !existing.destroyed && existing.serial === serial) {\n return existing;\n }\n const buffer = this.allocator.createBuffer({ label, size: data.byteLength, usage: RESIDENT_USAGE });\n this.device.queue.writeBuffer(buffer, 0, data);\n const resident: Resident = { key, buffer, byteLength: data.byteLength, serial, version: 0, destroyed: false };\n this.residents.set(key, resident);\n if (record === null) {\n this.orphans.add(resident);\n } else {\n record.entries.push(resident);\n }\n this.liveCount++;\n this.liveBytesValue += data.byteLength;\n return resident;\n }\n\n /**\n * Destroys one resident buffer and unregisters it; idempotent.\n * @param resident - the resident\n * @param record - its owning record, or null for an orphan\n */\n private destroyResident(resident: Resident, record: ResidencyRecord | null): void {\n if (resident.destroyed) {\n return;\n }\n resident.destroyed = true;\n this.allocator.destroy(resident.buffer);\n if (this.residents.get(resident.key) === resident) {\n this.residents.delete(resident.key);\n }\n if (record === null) {\n this.orphans.delete(resident);\n } else {\n const index = record.entries.indexOf(resident);\n if (index >= 0) {\n record.entries.splice(index, 1);\n }\n }\n this.liveCount--;\n this.liveBytesValue -= resident.byteLength;\n }\n\n /**\n * Marks a record released and drops it from the serial map (the snapshot WeakMap entries recognise it by the flag).\n * @param record - the record\n */\n private forget(record: ResidencyRecord): void {\n record.released = true;\n record.bindings.clear();\n record.views.clear();\n record.packKeys.clear();\n record.windowKeys.clear();\n record.arcBuffers.clear();\n record.windows = null;\n record.arena = null;\n record.plan = null;\n this.bySerial.delete(record.serial);\n }\n\n /**\n * The record of a snapshot's serial, created when absent (which lifts a tombstone and may fire the warning).\n * @param s - the snapshot\n * @returns the record\n */\n private ensureRecord(s: GraphSnapshot): ResidencyRecord {\n let record = this.records.get(s);\n if (record !== undefined && record.released) {\n record = undefined;\n }\n if (record === undefined) {\n record = this.bySerial.get(s.serial);\n }\n if (record === undefined) {\n record = {\n serial: s.serial,\n label: s.label,\n entries: [],\n plan: null,\n arena: null,\n bindings: new Map<CoreArrayName, Binding>(),\n views: new Map<string, ViewBinding>(),\n packKeys: new Map<string, object>(),\n windowKeys: new Map<string, object>(),\n windows: null,\n arcBuffers: new Map<CoreArrayName, GPUBuffer[]>(),\n released: false,\n };\n this.bySerial.set(s.serial, record);\n this.tombstones.delete(s.serial);\n if (!this.warned && this.bySerial.size > this.warnUnreleasedSnapshots) {\n this.warned = true;\n this.warn(\n `[webgpu-graph-algorithms] ${this.bySerial.size} snapshots are resident on the device (warnUnreleasedSnapshots = ${this.warnUnreleasedSnapshots}); call ctx.release(snapshot) for superseded snapshots -- GPU memory is never freed by garbage collection (spec 4.1)`,\n );\n }\n }\n this.records.set(s, record);\n return record;\n }\n\n /**\n * Throws E_RELEASED for a tombstoned serial (a bind without a fresh core()).\n * @param s - the snapshot\n */\n private assertNotReleased(s: GraphSnapshot): void {\n if (this.tombstones.has(s.serial)) {\n throw new WebGpuGraphError(\n \"E_RELEASED\",\n `snapshot ${s.serial} was released; upload it again through core() before binding views, columns or arrays`,\n { serial: s.serial },\n );\n }\n }\n\n /**\n * Throws E_INVALID_ARGUMENT for an empty snapshot (a view of it would be a zero-length array, spec 5.6).\n * @param s - the snapshot\n */\n private assertNonEmpty(s: GraphSnapshot): void {\n if (s.nodeCount === 0) {\n throw invalid(\"snapshot\", 0, \"nodeCount > 0 (an empty snapshot has no per-node view to upload)\");\n }\n }\n\n /** Throws E_DISPOSED after destroyAll() (PLAN DECISION 13). */\n private assertLive(): void {\n if (this.disposed) {\n throw new WebGpuGraphError(\"E_DISPOSED\", \"the residency was disposed\", { label: \"residency\" });\n }\n }\n}\n","/**\n * GpuContext (spec 2.2, 2.8, 3.3, 5.7; contract 3.5): one device, its caps and the singletons built on it --\n * the composition root of D26. probe() never creates a device; create() runs the six steps of spec 2.2 in\n * order; from() adopts a device the caller owns. Step 5 (the uncapturederror sink and the device.lost\n * watcher) and step 6 (the AllocationTracker, GraphResidency, BufferPool, Readback and PipelineCache) run\n * in the private constructor. The Profiler is constructed when \"timestamp-query\" is on the device (contract\n * 3.5; P2-T1) with `quantised` = runtime !== \"node\" (Dawn-node is the only runtime whose ticks are known\n * unquantised, spec 2.6). This file never imports ./kernels.js or ./wgsl/**.\n */\n\nimport type { GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { DEFAULT_WARN_UNRELEASED_SNAPSHOTS } from \"./constants.js\";\nimport {\n buildRequiredFeatures,\n buildRequiredLimits,\n requestAdapter,\n requestDevice,\n summarizeAdapter,\n} from \"./device/acquire.js\";\nimport { assertPlanLimits, capsFromDevice, captureCaps, workgroupSizeFor } from \"./device/caps.js\";\nimport { AllocationTracker } from \"./device/error-scope.js\";\nimport { deviceLostError, installUncapturedErrorSink, PendingErrorSlot, watchDeviceLost } from \"./device/lost.js\";\nimport { isWebGpuGraphError, WebGpuGraphError } from \"./errors.js\";\nimport { PipelineCache } from \"./kernel/pipeline-cache.js\";\nimport { Profiler } from \"./kernel/profiler.js\";\nimport { BufferPool } from \"./memory/buffer-pool.js\";\nimport { Readback } from \"./memory/readback.js\";\nimport { GraphResidency } from \"./memory/residency.js\";\nimport type { GpuCaps, GpuContextOptions, GpuDebugFlags, ProbeOptions, ProbeResult } from \"./types/context.js\";\n\n/** The label a context and its device carry when create() is given none. */\nconst DEFAULT_LABEL = \"webgpu-graph-algorithms\";\n/** The optionalFeatures default of spec 2.2. */\nconst DEFAULT_OPTIONAL_FEATURES: readonly GPUFeatureName[] = Object.freeze([\"subgroups\", \"timestamp-query\"]);\n/** The powerPreference default of spec 2.2 (Chrome 145 needs it; Dawn-node ignores it). */\nconst DEFAULT_POWER_PREFERENCE: GPUPowerPreference = \"high-performance\";\n\n/** What the private constructor takes: the device, its caps and the create-time choices. */\ninterface ContextInit {\n readonly device: GPUDevice;\n readonly caps: GpuCaps;\n readonly ownsDevice: boolean;\n readonly label: string;\n readonly onError: ((error: WebGpuGraphError) => void) | null;\n readonly warnUnreleasedSnapshots: number;\n}\n\n/**\n * Step 1 of create(): the caller's UNUSED adapter, else one requested from `gpu`; neither -> E_NO_WEBGPU.\n * @param options - the create options\n * @returns an adapter no device was requested from\n */\nasync function adapterOf(options: GpuContextOptions): Promise<GPUAdapter> {\n if (options.adapter !== undefined) {\n return options.adapter;\n }\n if (options.gpu !== undefined) {\n return requestAdapter(options.gpu, options.powerPreference ?? DEFAULT_POWER_PREFERENCE);\n }\n throw new WebGpuGraphError(\"E_NO_WEBGPU\", \"GpuContext.create needs one of gpu, adapter or device\", {\n reason: \"no gpu, adapter or device given\",\n hint: \"pass navigator.gpu (browser) or the gpu of createNodeGpu() (Node), or use the ./browser and ./node entries\",\n });\n}\n\n/** One device, its caps and the singletons built on it (spec 3.3; the composition root of D26). */\nexport class GpuContext {\n /** The device (owned when create() made it, adopted otherwise). */\n readonly device: GPUDevice;\n /** The capability record captured from device.limits / device.features (spec 3.3). */\n readonly caps: GpuCaps;\n /** Resolves with the lost info once the device is lost or destroyed (spec 2.8). */\n readonly lost: Promise<GPUDeviceLostInfo>;\n /**\n * The upload cache (spec 3.3).\n * @internal\n */\n readonly residency: GraphResidency;\n /** Non-null when \"timestamp-query\" was granted (P2-T1 makes it functional; P1 always null). */\n readonly profiler: Profiler | null;\n /**\n * The compile-once pipeline cache.\n * @internal\n */\n readonly pipelines: PipelineCache;\n /**\n * The scratch pool.\n * @internal\n */\n readonly pool: BufferPool;\n /**\n * The staging ring.\n * @internal\n */\n readonly readback: Readback;\n /**\n * The OOM-scoped allocator shared by residency and pool.\n * @internal\n */\n readonly allocator: AllocationTracker;\n /**\n * The workgroup size of this device (spec 5.1).\n * @internal\n */\n readonly workgroupSize: number;\n /**\n * True when create() made the device (dispose() destroys it).\n * @internal\n */\n readonly ownsDevice: boolean;\n /**\n * The label given to create().\n * @internal\n */\n readonly label: string;\n /**\n * Mutable test-build flags (GpuDebugFlags).\n * @internal\n */\n readonly debug: GpuDebugFlags;\n\n private currentState: \"ready\" | \"lost\" | \"disposed\" = \"ready\";\n private lostError: WebGpuGraphError | null = null;\n private readonly slot = new PendingErrorSlot();\n private readonly uninstallSink: () => void;\n private readonly lostListeners = new Set<(info: GPUDeviceLostInfo) => void>();\n private readonly disposers: (() => void)[] = [];\n private batchCounter = 0;\n\n /**\n * Steps 5 and 6 of create() (spec 2.2): the sink, the loss watcher and the singletons.\n * @param init - the device, its caps and the create-time choices\n */\n private constructor(init: ContextInit) {\n this.device = init.device;\n this.caps = init.caps;\n this.ownsDevice = init.ownsDevice;\n this.label = init.label;\n this.debug = { inspect: false };\n this.workgroupSize = workgroupSizeFor(init.caps);\n this.allocator = new AllocationTracker(init.device);\n this.residency = new GraphResidency(init.device, init.caps, this.allocator, {\n warnUnreleasedSnapshots: init.warnUnreleasedSnapshots,\n });\n this.pool = new BufferPool(init.device, this.allocator, init.caps.limits.maxBufferSize);\n this.readback = new Readback(init.device, this.allocator);\n this.pipelines = new PipelineCache(init.device, init.caps);\n this.profiler = init.device.features.has(\"timestamp-query\")\n ? new Profiler(init.device, true, init.caps.runtime !== \"node\")\n : null;\n this.uninstallSink = installUncapturedErrorSink(init.device, this.slot, init.onError);\n this.lost = watchDeviceLost(init.device, (info) => {\n this.handleLost(info);\n });\n }\n\n /**\n * Probe without creating a device (spec 2.2); never throws. `gpu === undefined` -> E_NO_WEBGPU;\n * requestAdapter() null or a throw -> E_NO_ADAPTER; `rejectSoftware && software` -> E_SOFTWARE_ONLY (the\n * adapter and its summary are still reported); else OK with the UNUSED adapter and its summary.\n * @param options - the GPU object, the power preference and the software policy\n * @returns the probe result\n */\n static async probe(options: ProbeOptions): Promise<ProbeResult> {\n const { gpu } = options;\n if (gpu === undefined) {\n return {\n ok: false,\n code: \"E_NO_WEBGPU\",\n reason: \"no GPU object: navigator.gpu is undefined (no WebGPU in this runtime)\",\n adapter: null,\n summary: null,\n };\n }\n let adapter: GPUAdapter;\n try {\n adapter = await requestAdapter(gpu, options.powerPreference ?? DEFAULT_POWER_PREFERENCE);\n } catch (err) {\n const reason = isWebGpuGraphError(err) ? err.message : String(err);\n return { ok: false, code: \"E_NO_ADAPTER\", reason, adapter: null, summary: null };\n }\n const summary = summarizeAdapter(adapter);\n if (options.rejectSoftware === true && summary.software) {\n return {\n ok: false,\n code: \"E_SOFTWARE_ONLY\",\n reason: `software adapter rejected: ${summary.vendor}/${summary.architecture}`,\n adapter,\n summary,\n };\n }\n return { ok: true, code: \"OK\", reason: null, adapter, summary };\n }\n\n /**\n * The six-step acquisition of spec 2.2: adopt `device`, else take `adapter`, else request one from `gpu`\n * (step 1); the software test (step 2); the limits / features and requestDevice (step 3); the caps from\n * device.limits plus assertPlanLimits (step 4); the sink, the loss watcher and the singletons (steps 5-6,\n * in the constructor).\n * @param options - see GpuContextOptions\n * @returns the context\n */\n static async create(options: GpuContextOptions): Promise<GpuContext> {\n const runtime = options.runtime ?? \"unknown\";\n const label = options.label ?? DEFAULT_LABEL;\n const onError = options.onError ?? null;\n const warnUnreleasedSnapshots = options.warnUnreleasedSnapshots ?? DEFAULT_WARN_UNRELEASED_SNAPSHOTS;\n if (options.device !== undefined) {\n const adopted = capsFromDevice(options.device, { runtime });\n assertPlanLimits(adopted);\n return new GpuContext({\n device: options.device,\n caps: adopted,\n ownsDevice: false,\n label,\n onError,\n warnUnreleasedSnapshots,\n });\n }\n const adapter = await adapterOf(options);\n const summary = summarizeAdapter(adapter);\n if (options.rejectSoftware === true && summary.software) {\n throw new WebGpuGraphError(\n \"E_SOFTWARE_ONLY\",\n `software adapter rejected by rejectSoftware: ${summary.vendor}/${summary.architecture}`,\n { adapter: summary },\n );\n }\n const requiredLimits = buildRequiredLimits(adapter, options.limits ?? \"raise\");\n const requiredFeatures = buildRequiredFeatures(\n adapter,\n options.requiredFeatures ?? [],\n options.optionalFeatures ?? DEFAULT_OPTIONAL_FEATURES,\n );\n const device = await requestDevice(adapter, { label, requiredLimits, requiredFeatures });\n const caps = captureCaps(device, adapter.info, runtime, options.gpu?.wgslLanguageFeatures ?? []);\n try {\n assertPlanLimits(caps);\n } catch (err) {\n device.destroy();\n throw err;\n }\n return new GpuContext({ device, caps, ownsDevice: true, label, onError, warnUnreleasedSnapshots });\n }\n\n /**\n * Zero-cost adoption of a device the caller owns (ownsDevice false, runtime \"unknown\" unless info says\n * otherwise). The context is labelled with the device's label, or \"GpuContext.from\" when it has none.\n * @param device - the device to adopt\n * @param info - what the caller knows about the adapter, if anything\n * @returns the context\n */\n static from(device: GPUDevice, info?: Partial<GpuCaps>): GpuContext {\n const caps = capsFromDevice(device, info);\n assertPlanLimits(caps);\n const deviceLabel: string = device.label ?? \"\";\n return new GpuContext({\n device,\n caps,\n ownsDevice: false,\n label: deviceLabel === \"\" ? \"GpuContext.from\" : deviceLabel,\n onError: null,\n warnUnreleasedSnapshots: DEFAULT_WARN_UNRELEASED_SNAPSHOTS,\n });\n }\n\n /**\n * \"ready\" | \"lost\" | \"disposed\".\n * @returns the lifecycle state\n */\n get state(): \"ready\" | \"lost\" | \"disposed\" {\n return this.currentState;\n }\n\n /**\n * Throws E_DEVICE_LOST / E_DISPOSED by state and rethrows a pending uncaptured error (spec 5.7: \"thrown\n * from the next public call\").\n * @internal\n */\n assertReady(): void {\n if (this.currentState === \"disposed\") {\n throw new WebGpuGraphError(\"E_DISPOSED\", `GpuContext \"${this.label}\" is disposed`, { label: this.label });\n }\n if (this.lostError !== null) {\n throw this.lostError;\n }\n const pending = this.slot.take();\n if (pending !== null) {\n throw pending;\n }\n }\n\n /**\n * Takes the pending uncaptured error (used by CommandBatch right after submit).\n * @internal\n * @returns the error, or null\n */\n takePendingError(): WebGpuGraphError | null {\n return this.slot.take();\n }\n\n /**\n * Monotonically increasing batch ids, starting at 1.\n * @internal\n * @returns the next id\n */\n nextBatchId(): number {\n this.batchCounter += 1;\n return this.batchCounter;\n }\n\n /**\n * Registers a device-loss listener (simulations enter \"disposed\"); returns the unregister function.\n * @internal\n * @param listener - called once with the lost info\n * @returns removes the listener\n */\n onLost(listener: (info: GPUDeviceLostInfo) => void): () => void {\n this.lostListeners.add(listener);\n return () => {\n this.lostListeners.delete(listener);\n };\n }\n\n /**\n * A disposer run by dispose() (the Node entry attaches the GPU handle's dispose); attached after\n * dispose() it runs immediately.\n * @internal\n * @param dispose - the disposer\n */\n attachDisposer(dispose: () => void): void {\n if (this.currentState === \"disposed\") {\n dispose();\n return;\n }\n this.disposers.push(dispose);\n }\n\n /**\n * Destroys every buffer recorded for the snapshot (spec 4.5), then `pool.trim()` (spec 4.4: idle scratch\n * goes with the graph); idempotent; safe on a snapshot never uploaded; a no-op after dispose().\n * @param snapshot - the snapshot whose buffers are released\n */\n release(snapshot: GraphSnapshot): void {\n if (this.currentState === \"disposed\") {\n return;\n }\n this.residency.release(snapshot);\n this.pool.trim();\n }\n\n /**\n * Rejects pending work with E_DISPOSED (every later public call), destroys residency, pool and staging\n * ring, destroys the device when owned, runs attached disposers; idempotent (spec 2.8).\n */\n dispose(): void {\n if (this.currentState === \"disposed\") {\n return;\n }\n this.currentState = \"disposed\";\n this.uninstallSink();\n this.residency.destroyAll();\n this.pool.destroyAll();\n this.readback.destroyAll();\n if (this.profiler !== null) {\n this.profiler.destroy();\n }\n if (this.ownsDevice) {\n this.device.destroy();\n }\n const disposers = this.disposers.splice(0);\n for (const dispose of disposers) {\n dispose();\n }\n }\n\n /**\n * Step 5 of spec 2.2 on loss: state \"lost\", the residency cleared without destroying (the buffers are\n * gone with the device), every registered listener run once; a loss reported after dispose() (the owned\n * device was destroyed by dispose) changes nothing.\n * @param info - the device.lost result\n */\n private handleLost(info: GPUDeviceLostInfo): void {\n if (this.currentState === \"disposed\") {\n return;\n }\n this.currentState = \"lost\";\n this.lostError = deviceLostError(info);\n this.residency.clearOnLoss();\n for (const listener of Array.from(this.lostListeners)) {\n try {\n listener(info);\n } catch {\n // a throwing listener must not stop the fan-out; the others still learn of the loss\n }\n }\n }\n}\n","/**\n * The CommandBatch of spec 5.8: one GPUCommandEncoder, one compute pass per \"phase\" (a pass may hold\n * many dispatches; dispatches inside a pass are ordered), the staging copies of every readback\n * request at the end, and ONE queue.submit. The batch borrows one slot of the Readback ring for its\n * lifetime (spec 4.4) and returns it when its readback settles -- resolved, discarded or rejected --\n * so the ring never grows because of a slot left pending. mapAsync on that slot is the completion\n * signal; a batch never calls onSubmittedWorkDone.\n *\n * Errors (spec 5.7): under Dawn-node an uncapturederror is delivered SYNCHRONOUSLY inside the API\n * call that fails, so an error pending in the context's slot when submit() runs belongs to this batch\n * and rejects ITS OWN readback (an invalid command buffer is a no-op submit; the staging bytes would be\n * stale). In browsers delivery is asynchronous: the batch takes the slot again after its map completes,\n * and whatever arrives later is thrown by the context's next public call. Device loss is raced against\n * the map, so a readback rejects E_DEVICE_LOST whether the runtime rejects, resolves or never settles\n * the pending map of a destroyed buffer; the slot goes back only once the map has settled (or the grace\n * ran out), because a staging buffer is never unmapped while its map is pending (readback.ts).\n */\n\nimport type { AllocationTracker } from \"../device/error-scope.js\";\nimport { deviceLostError } from \"../device/lost.js\";\nimport { isWebGpuGraphError, WebGpuGraphError } from \"../errors.js\";\nimport type { Readback, StagingSlot } from \"../memory/readback.js\";\nimport type { Binding } from \"../types/memory.js\";\nimport type { Profiler } from \"./profiler.js\";\n\n/** How long a batch waits for the context's loss fan-out after its map rejected with a foreign error (a destroyed buffer rejects before device.lost settles), and for the runtime to settle a pending map after the loss won the race. */\nconst LOSS_GRACE_MS = 2000;\n\n/**\n * Resolves when the promise settles either way, or after the grace (a runtime that never settles a pending map).\n * @param pending - the promise\n * @param graceMs - the ceiling\n */\nasync function settled(pending: Promise<unknown>, graceMs: number): Promise<void> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const grace = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, graceMs);\n });\n await Promise.race([\n pending.then(\n () => undefined,\n () => undefined,\n ),\n grace,\n ]);\n clearTimeout(timer);\n}\n\n/**\n * A plain message for a thrown value (the house pattern of graph-io's report.ts).\n * @param error - whatever the runtime rejected with\n * @returns the Error message, the string itself, or a typeof note\n */\nfunction messageOf(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n return `non-error thrown (${typeof error})`;\n}\n\n/** What a CommandBatch needs of its owner (GpuContext satisfies it structurally; kernel/ never imports context.ts). */\nexport interface BatchHost {\n readonly device: GPUDevice;\n readonly readback: Readback;\n readonly profiler: Profiler | null;\n readonly allocator: AllocationTracker;\n assertReady(): void;\n takePendingError(): WebGpuGraphError | null;\n nextBatchId(): number;\n /** Registers a device-loss listener and returns the unregister function (GpuContext.onLost, contract 3.5): the batch races its map against loss. PLAN DECISION 1: an amendment to contract 3.9, which declares the seven members above. */\n onLost(listener: (info: GPUDeviceLostInfo) => void): () => void;\n}\n\n/** A readback scheduled into the batch's staging slot: `offset` is the slot-relative byte offset the caller reads at. */\nexport interface ReadbackRequest {\n readonly src: GPUBuffer;\n readonly srcOffset: number;\n readonly byteLength: number;\n readonly offset: number;\n}\n\n/** What submit() returns (spec 5.8). `readback` resolves with the mapped bytes COPIED out (one ArrayBuffer holding every request at its offset) after allocator.check(); it rejects with E_VALIDATION { batchId } when the pending-error slot held an error right after submit and with E_DEVICE_LOST after loss; a discarded batch resolves an empty ArrayBuffer (see discard()). */\nexport interface SubmittedBatch {\n readonly id: number;\n readonly generation: number;\n readonly readback: Promise<ArrayBuffer>;\n /** Marks the batch stale: its readback still awaits mapAsync (so the slot is returned) but resolves with an empty ArrayBuffer and the caller ignores it (spec 7.19 item 6). */\n discard(): void;\n}\n\n/** The discard flag shared by a handle and its readback. */\ninterface DiscardState {\n discarded: boolean;\n}\n\n/** Records dispatches / copies into one encoder and submits once (spec 5.8). */\nexport class CommandBatch {\n readonly id: number;\n readonly generation: number;\n readonly label: string;\n private readonly host: BatchHost;\n private readonly encoder: GPUCommandEncoder;\n private readonly requests: ReadbackRequest[] = [];\n private openPass: GPUComputePassEncoder | null = null;\n private dispatchCount = 0;\n private stagingBytes = 0;\n private slot: StagingSlot | null = null;\n private submitted = false;\n\n /**\n * Creates the encoder; the id comes from host.nextBatchId().\n * @param host - the owner (the GpuContext)\n * @param label - names the encoder, its passes and the E_VALIDATION details\n * @param generation - the simulation generation the batch carries (default 0)\n */\n constructor(host: BatchHost, label: string, generation?: number) {\n this.host = host;\n this.id = host.nextBatchId();\n this.generation = generation ?? 0;\n this.label = label;\n this.encoder = host.device.createCommandEncoder({ label: `batch/${label}#${this.id}` });\n }\n\n /**\n * Dispatch count recorded so far (tests bound it).\n * @returns the number of dispatchWorkgroups / dispatchWorkgroupsIndirect calls on this batch's passes\n */\n get dispatches(): number {\n return this.dispatchCount;\n }\n\n /**\n * Begins a compute pass (ending the previous one); with a profiler present the pass carries timestampWrites and\n * `label` names it in Profiler.resolveInto / timings.\n * @param label - the pass name\n * @returns the pass encoder kernels dispatch into\n */\n pass(label: string): GPUComputePassEncoder {\n this.assertOpen(\"pass\");\n this.endPass();\n const descriptor: GPUComputePassDescriptor = { label: `batch/${this.label}#${this.id}/${label}` };\n const timestampWrites = this.host.profiler?.beginPass(label);\n if (timestampWrites !== undefined) {\n descriptor.timestampWrites = timestampWrites;\n }\n const pass = this.encoder.beginComputePass(descriptor);\n this.countDispatches(pass);\n this.openPass = pass;\n return pass;\n }\n\n /** Ends the open pass, if any. */\n endPass(): void {\n if (this.openPass !== null) {\n this.openPass.end();\n this.openPass = null;\n }\n }\n\n /**\n * copyBufferToBuffer between two bindings (after endPass).\n * @param src - the source range\n * @param dst - the destination range\n * @param byteLength - a positive multiple of 4 no larger than either binding\n */\n copy(src: Binding, dst: Binding, byteLength: number): void {\n this.assertOpen(\"copy\");\n this.checkByteLength(byteLength);\n if (byteLength > src.size || byteLength > dst.size) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `copy of ${byteLength} bytes exceeds a binding (src ${src.size}, dst ${dst.size})`,\n {\n argument: \"byteLength\",\n value: byteLength,\n expected: `<= ${Math.min(src.size, dst.size)}`,\n },\n );\n }\n this.endPass();\n this.encoder.copyBufferToBuffer(src.buffer, src.offset, dst.buffer, dst.offset, byteLength);\n }\n\n /**\n * Schedules a copy of `byteLength` bytes from `src` into the borrowed staging slot; the slot is borrowed at the\n * first request and re-borrowed larger when the sum of requests outgrows it (nothing is recorded before submit).\n * @param src - the source buffer\n * @param srcOffset - a non-negative multiple of 4\n * @param byteLength - a positive multiple of 4 with srcOffset + byteLength <= src.size\n * @returns the request; `offset` is where the caller reads inside the readback bytes\n */\n readback(src: GPUBuffer, srcOffset: number, byteLength: number): ReadbackRequest {\n this.assertOpen(\"readback\");\n this.checkByteLength(byteLength);\n if (!Number.isInteger(srcOffset) || srcOffset < 0 || srcOffset % 4 !== 0 || srcOffset + byteLength > src.size) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `readback of [${srcOffset}, ${srcOffset + byteLength}) is outside the ${src.size}-byte source or not 4-aligned`,\n {\n argument: \"srcOffset\",\n value: srcOffset,\n expected: `a multiple of 4 with srcOffset + byteLength <= ${src.size}`,\n },\n );\n }\n const request: ReadbackRequest = { src, srcOffset, byteLength, offset: this.stagingBytes };\n this.requests.push(request);\n this.stagingBytes += byteLength;\n this.ensureSlot(this.stagingBytes);\n return request;\n }\n\n /**\n * Records `resolveQuerySet` after ending the open pass; used by Profiler.resolveInto only.\n * @internal\n * @param querySet - the timestamp query set\n * @param firstQuery - first query index\n * @param queryCount - number of queries\n * @param destination - a QUERY_RESOLVE | COPY_SRC buffer written at offset 0\n */\n resolveQuerySet(querySet: GPUQuerySet, firstQuery: number, queryCount: number, destination: GPUBuffer): void {\n this.assertOpen(\"resolveQuerySet\");\n this.endPass();\n this.encoder.resolveQuerySet(querySet, firstQuery, queryCount, destination, 0);\n }\n\n /**\n * Ends passes, records the staging copies, submits, checks the pending-error slot (spec 5.7), returns the handle.\n * A batch can be submitted once; submit() after device loss throws E_DEVICE_LOST.\n * @returns the submitted-batch handle\n */\n submit(): SubmittedBatch {\n this.assertOpen(\"submit\");\n this.submitted = true;\n this.endPass();\n const { slot } = this;\n const pendingBefore = this.host.takePendingError();\n try {\n this.host.assertReady();\n } catch (error) {\n this.releaseSlot();\n throw error;\n }\n if (slot !== null) {\n for (const request of this.requests) {\n this.encoder.copyBufferToBuffer(\n request.src,\n request.srcOffset,\n slot.buffer,\n request.offset,\n request.byteLength,\n );\n }\n }\n const commandBuffer = this.encoder.finish({ label: `batch/${this.label}#${this.id}` });\n this.host.device.queue.submit([commandBuffer]);\n // the slot is drained a second time so a finish() / submit() error raised by a command buffer the first error\n // already invalidated never leaks to the next public call; the FIRST error is the one reported\n const pendingAfter = this.host.takePendingError();\n const pending = pendingBefore ?? pendingAfter;\n const state: DiscardState = { discarded: false };\n const readback = pending === null ? this.awaitReadback(slot, state) : this.rejectReadback(pending);\n return {\n id: this.id,\n generation: this.generation,\n readback,\n discard: (): void => {\n state.discarded = true;\n },\n };\n }\n\n private rejectReadback(pending: WebGpuGraphError): Promise<ArrayBuffer> {\n this.releaseSlot();\n return Promise.reject(this.attribute(pending));\n }\n\n private async awaitReadback(slot: StagingSlot | null, state: DiscardState): Promise<ArrayBuffer> {\n if (slot === null) {\n await this.host.allocator.check();\n return new ArrayBuffer(0);\n }\n const total = this.stagingBytes;\n let unregister: () => void = (): void => undefined;\n const lost = new Promise<never>((_resolve, reject) => {\n unregister = this.host.onLost((info) => {\n reject(deviceLostError(info));\n });\n });\n void lost.catch(() => undefined);\n const mapped = this.host.readback.mapSlot(slot, total);\n void mapped.catch(() => undefined);\n let bytes: ArrayBuffer;\n try {\n await Promise.race([mapped, lost]);\n this.host.assertReady();\n bytes = state.discarded ? new ArrayBuffer(0) : slot.buffer.getMappedRange(0, total).slice(0);\n } catch (error) {\n // the loss may have won the race: let the runtime settle the map before the slot is unmapped and returned\n await settled(mapped, LOSS_GRACE_MS);\n this.releaseSlot();\n throw await this.classify(error, lost);\n } finally {\n unregister();\n }\n this.releaseSlot();\n await this.host.allocator.check();\n return bytes;\n }\n\n private async classify(error: unknown, lost: Promise<never>): Promise<WebGpuGraphError> {\n if (isWebGpuGraphError(error)) {\n return error.code === \"E_DEVICE_LOST\" || error.code === \"E_DISPOSED\" ? error : this.attribute(error);\n }\n try {\n this.host.assertReady();\n } catch (state) {\n if (isWebGpuGraphError(state)) {\n return state.code === \"E_DEVICE_LOST\" || state.code === \"E_DISPOSED\" ? state : this.attribute(state);\n }\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const grace = new Promise<null>((resolve) => {\n timer = setTimeout(() => {\n resolve(null);\n }, LOSS_GRACE_MS);\n });\n const late = await Promise.race([\n lost.then(\n () => null,\n (reason: unknown) => reason,\n ),\n grace,\n ]);\n clearTimeout(timer);\n if (isWebGpuGraphError(late)) {\n return late;\n }\n const message = messageOf(error);\n return new WebGpuGraphError(\n \"E_VALIDATION\",\n `mapAsync failed for batch ${this.id} \"${this.label}\": ${message}`,\n {\n label: this.label,\n message,\n batchId: this.id,\n },\n );\n }\n\n private attribute(error: WebGpuGraphError): WebGpuGraphError {\n return new WebGpuGraphError(error.code, `${error.message} (delivered to batch ${this.id} \"${this.label}\")`, {\n ...error.details,\n batchId: this.id,\n batchLabel: this.label,\n });\n }\n\n private ensureSlot(byteLength: number): void {\n if (this.slot !== null && this.slot.capacity >= byteLength) {\n return;\n }\n this.releaseSlot();\n this.slot = this.host.readback.borrowSlot(byteLength);\n }\n\n private releaseSlot(): void {\n if (this.slot === null) {\n return;\n }\n const { slot } = this;\n this.slot = null;\n try {\n this.host.readback.returnSlot(slot);\n } catch (error) {\n if (!isWebGpuGraphError(error) || error.code !== \"E_DISPOSED\") {\n throw error;\n }\n }\n }\n\n private countDispatches(pass: GPUComputePassEncoder): void {\n const direct = pass.dispatchWorkgroups.bind(pass);\n const indirect = pass.dispatchWorkgroupsIndirect.bind(pass);\n pass.dispatchWorkgroups = (x: number, y?: number, z?: number): undefined => {\n this.dispatchCount += 1;\n direct(x, y, z);\n return undefined;\n };\n pass.dispatchWorkgroupsIndirect = (buffer: GPUBuffer, offset: number): undefined => {\n this.dispatchCount += 1;\n indirect(buffer, offset);\n return undefined;\n };\n }\n\n private assertOpen(operation: string): void {\n if (this.submitted) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${operation}() after submit() on batch ${this.id} \"${this.label}\"`,\n {\n argument: operation,\n value: this.id,\n expected: \"a batch that has not been submitted\",\n },\n );\n }\n }\n\n private checkByteLength(byteLength: number): void {\n if (!Number.isInteger(byteLength) || byteLength <= 0 || byteLength % 4 !== 0) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `byteLength ${byteLength} is not a positive multiple of 4`,\n {\n argument: \"byteLength\",\n value: byteLength,\n expected: \"a positive multiple of 4\",\n },\n );\n }\n }\n}\n","/**\n * Dispatch planning (spec 5.2; contract 3.9): the 16,776,960 rule. `ceil(items / wg)` workgroups as a 1D dispatch\n * while the count fits one dimension (65,535 groups x 256 = 16,776,960 items, NOT 2^24), else a 2D grid whose\n * kernels linearise their id with the prelude's `linear_id()` and guard `id >= items`. Pure functions with no\n * device: every branch is unit-tested against faked capability tables.\n */\n\nimport { MAX_WORKGROUPS_PER_DIM } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type PlanCaps } from \"../types/context.js\";\n\n/** A dispatch shape (spec 5.2). `stride` is the grid-stride step (null for plain 1D / 2D plans). `z` is 1 from every planner; only K3's pass split sets it (issue #87). */\nexport interface DispatchPlan {\n readonly x: number;\n readonly y: number;\n readonly z: number;\n readonly items: number;\n readonly stride: number | null;\n}\n\n/**\n * The per-dimension workgroup limit a plan honours. PLAN DECISION: the minimum of the spec constant and the table's\n * `maxComputeWorkgroupsPerDimension`; the two are asserted equal on a real device at create() (spec 2.2), so every\n * capability table of the tests yields the same plans and a faked table below the constant is still honoured.\n * @param caps - the capability table\n * @returns the limit\n */\nfunction perDimension(caps: PlanCaps): number {\n return Math.min(MAX_WORKGROUPS_PER_DIM, caps.limits.maxComputeWorkgroupsPerDimension);\n}\n\n/**\n * Validates a non-negative integer argument.\n * @param argument - the argument name\n * @param value - the value\n */\nfunction assertCount(argument: string, value: number): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${argument} must be a non-negative integer, got ${value}`, {\n argument,\n value,\n expected: \"a non-negative integer\",\n });\n }\n}\n\n/**\n * Validates a workgroup size: a power of two >= 1 (the reduction trees of 4.3 need it). Arithmetic, no bit tricks.\n * @param wg - the workgroup size\n */\nfunction assertWorkgroupSize(wg: number): void {\n let rest = wg;\n while (Number.isInteger(rest) && rest > 1 && rest % 2 === 0) {\n rest /= 2;\n }\n if (rest !== 1) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `wg must be a power of two, got ${wg}`, {\n argument: \"wg\",\n value: wg,\n expected: \"a power of two >= 1\",\n });\n }\n}\n\n/**\n * The grid of `groups` workgroups: 1D up to the per-dimension limit, else `x = limit`, `y = ceil(groups / limit)`.\n * @param groups - the workgroup count\n * @param items - the item count the plan covers (recorded in the plan)\n * @param caps - the capability table\n * @returns the plan\n */\nfunction grid(groups: number, items: number, caps: PlanCaps): DispatchPlan {\n const limit = perDimension(caps);\n if (groups === 0) {\n return { x: 0, y: 1, z: 1, items, stride: null };\n }\n if (groups <= limit) {\n return { x: groups, y: 1, z: 1, items, stride: null };\n }\n const y = Math.ceil(groups / limit);\n if (y > limit) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${groups} workgroups exceed the 2D dispatch limit of ${limit * limit}`,\n {\n needed: groups,\n limit: limit * limit,\n path: \"dispatch\",\n algorithm: null,\n items,\n },\n );\n }\n return { x: limit, y, z: 1, items, stride: null };\n}\n\n/**\n * ceil(items / wg) groups as 1D up to MAX_WORKGROUPS_PER_DIM, else a 2D grid; items 0 -> { x: 0, y: 1 }; y above the limit -> E_TOO_LARGE.\n * @param items - the item count\n * @param wg - the workgroup size (a power of two)\n * @param caps - the capability table\n * @returns the plan\n */\nexport function plan1d(items: number, wg: number, caps: PlanCaps): DispatchPlan {\n assertCount(\"items\", items);\n assertWorkgroupSize(wg);\n return grid(Math.ceil(items / wg), items, caps);\n}\n\n/**\n * The 2D form for a group count (x = MAX_WORKGROUPS_PER_DIM, y = ceil(groups / x)); exported for the indirect finalize kernel's host twin (P4).\n * PLAN DECISION: plan1d's rule applied to a group count (spec 5.4: the finalize kernel uses \"the same rule as\n * plan1d\") -- 1D `{ x: groups, y: 1 }` up to the per-dimension limit and the `x = limit` split only above it, through\n * the same `grid()` as plan1d so the two cannot drift; P4's finalize WGSL mirrors exactly this rule. `items` of the\n * returned plan is `groups` (the caller knows its own wg); groups 0 -> { x: 0, y: 1 }.\n * @param groups - the workgroup count\n * @param caps - the capability table\n * @returns the plan\n */\nexport function plan2d(groups: number, caps: PlanCaps): DispatchPlan {\n assertCount(\"groups\", groups);\n return grid(groups, groups, caps);\n}\n\n/**\n * P7 (spec 5.2): groups = min(ceil(items / wg), maxGroups ?? (caps.software ? 64 : 4096), the per-dimension limit) with the kernel looping by `stride = groups * wg`; items 0 -> { x: 0, stride: null }.\n * The cap is the ONE performance default in src/ that may read `caps.software` (spec 2.4, 5.2): a grid-stride map is\n * order-independent, so the result never depends on it and the same body serves both adapters.\n * PLAN DECISION: `maxGroups?` is spelled `?: number` rather than the contract's `?: number | undefined` because the\n * root ESLint rule no-duplicate-type-constituents rejects the explicit undefined on an optional parameter (the call\n * signature is identical).\n * @param items - the item count\n * @param wg - the workgroup size\n * @param caps - the capability table\n * @param maxGroups - the group cap\n * @returns the plan\n */\nexport function planGridStride(items: number, wg: number, caps: PlanCaps, maxGroups?: number): DispatchPlan {\n assertCount(\"items\", items);\n assertWorkgroupSize(wg);\n if (items === 0) {\n return { x: 0, y: 1, z: 1, items, stride: null };\n }\n const cap = Math.min(maxGroups ?? (caps.software ? 64 : 4096), perDimension(caps));\n const groups = Math.min(Math.ceil(items / wg), cap);\n return { x: groups, y: 1, z: 1, items, stride: groups * wg };\n}\n\n/**\n * P4 (spec 5.4): the (x, y, 1) args the device-side finalize kernel writes for a count -- plan1d's rule applied to a\n * u32 count through the same grid() as plan1d and plan2d, so the host twin and the kernel cannot drift; the kernel\n * (src/wgsl/indirect-finalize.wgsl.ts) mirrors exactly this arithmetic. `items` of the plan is the count. A count\n * outside [0, 2^32) is E_INVALID_ARGUMENT (the device holds it as a u32); for any u32 count y <= 1,025, so\n * E_TOO_LARGE is unreachable here.\n * @param count - the device-side count (a u32)\n * @param wg - the workgroup size (a power of two)\n * @param caps - the capability table\n * @returns the plan\n */\nexport function planIndirect(count: number, wg: number, caps: PlanCaps): DispatchPlan {\n assertCount(\"count\", count);\n if (count > 0xffffffff) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `count must fit a u32, got ${count}`, {\n argument: \"count\",\n value: count,\n expected: \"an integer in [0, 2^32)\",\n });\n }\n assertWorkgroupSize(wg);\n return grid(Math.ceil(count / wg), count, caps);\n}\n\n/**\n * The workgroup count of a plan (x * y).\n * @param plan - the plan\n * @returns the count\n */\nexport function groupsOf(plan: DispatchPlan): number {\n return plan.x * plan.y;\n}\n","/**\n * UniformBlock (spec 5.3, D20): one field table generates BOTH the padded WGSL `struct` text spliced into a module\n * and the byte writer / reader the host uses, so the two cannot disagree. The layout is the strict WGSL layout\n * every runtime accepts (Chromium 139 lacks `uniform_buffer_standard_layout`): scalars 4-aligned, vec2 8-aligned,\n * vec4 16-aligned, no vec3, no bool, no arrays, and the total padded to a multiple of 16 (or to `padTo`) through an\n * explicit `@size` on the last member.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { WGSL_RESERVED_WORDS } from \"./prelude.js\";\n\n/** Field types a block may hold; no vec3 (spec 5.3), no bool (not host-shareable), no arrays. */\nexport type UniformFieldType = \"u32\" | \"i32\" | \"f32\" | \"vec2f\" | \"vec2u\" | \"vec4f\" | \"vec4u\";\n/** One field. */\nexport type UniformField = readonly [name: string, type: UniformFieldType];\n/** The values written into or read from a block: scalars as numbers, vectors as number arrays of the vector's width. */\nexport type UniformValues = Readonly<Record<string, number | readonly number[]>>;\n\n/** The scalar a field is made of. */\ntype ScalarKind = \"u32\" | \"i32\" | \"f32\";\n\n/** Size, alignment and composition of each field type (WGSL 14.4.1). */\ninterface TypeInfo {\n readonly size: number;\n readonly align: number;\n readonly width: number;\n readonly scalar: ScalarKind;\n}\n\nconst TYPE_INFO: Readonly<Record<UniformFieldType, TypeInfo>> = Object.freeze({\n u32: { size: 4, align: 4, width: 1, scalar: \"u32\" },\n i32: { size: 4, align: 4, width: 1, scalar: \"i32\" },\n f32: { size: 4, align: 4, width: 1, scalar: \"f32\" },\n vec2f: { size: 8, align: 8, width: 2, scalar: \"f32\" },\n vec2u: { size: 8, align: 8, width: 2, scalar: \"u32\" },\n vec4f: { size: 16, align: 16, width: 4, scalar: \"f32\" },\n vec4u: { size: 16, align: 16, width: 4, scalar: \"u32\" },\n});\n\n/** One laid-out field. */\ninterface FieldLayout {\n readonly name: string;\n readonly type: UniformFieldType;\n readonly offset: number;\n readonly info: TypeInfo;\n}\n\nconst STRUCT_ALIGN = 16;\nconst IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;\nconst U32_LIMIT = 0xffffffff;\nconst I32_MIN = -2147483648;\nconst I32_MAX = 2147483647;\n\n/**\n * Rounds `value` up to the next multiple of `align` (arithmetic, never a bit trick: byte offsets are never operated\n * on bitwise, spec 3.6).\n * @param value - the value to round\n * @param align - the alignment, a positive integer\n * @returns the rounded value\n */\nfunction roundUp(value: number, align: number): number {\n return Math.ceil(value / align) * align;\n}\n\n/**\n * Validates a WGSL identifier for a struct or field name.\n * @param argument - the E_INVALID_ARGUMENT `argument` to report\n * @param name - the identifier\n */\nfunction assertIdentifier(argument: string, name: string): void {\n if (!IDENTIFIER.test(name) || WGSL_RESERVED_WORDS.includes(name)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock: \"${name}\" is not a usable WGSL identifier`, {\n argument,\n value: name,\n expected: \"a WGSL identifier that is not a reserved word\",\n });\n }\n}\n\n/**\n * Validates one scalar component of a value against its scalar kind.\n * @param field - the field name (for the error)\n * @param kind - the scalar kind\n * @param value - the component\n */\nfunction assertScalar(field: string, kind: ScalarKind, value: unknown): asserts value is number {\n if (typeof value !== \"number\") {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock: field \"${field}\" expects a number`, {\n argument: field,\n value,\n expected: kind,\n });\n }\n if (kind === \"u32\" && !(Number.isInteger(value) && value >= 0 && value <= U32_LIMIT)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock: field \"${field}\" is not a u32`, {\n argument: field,\n value,\n expected: \"an integer in [0, 4294967295]\",\n });\n }\n if (kind === \"i32\" && !(Number.isInteger(value) && value >= I32_MIN && value <= I32_MAX)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock: field \"${field}\" is not an i32`, {\n argument: field,\n value,\n expected: \"an integer in [-2147483648, 2147483647]\",\n });\n }\n}\n\n/**\n * Writes one scalar component little-endian.\n * @param view - the target view\n * @param kind - the scalar kind\n * @param offset - the byte offset\n * @param value - the component\n */\nfunction setScalar(view: DataView, kind: ScalarKind, offset: number, value: number): void {\n if (kind === \"u32\") {\n view.setUint32(offset, value, true);\n } else if (kind === \"i32\") {\n view.setInt32(offset, value, true);\n } else {\n view.setFloat32(offset, value, true);\n }\n}\n\n/**\n * Reads one scalar component little-endian.\n * @param view - the source view\n * @param kind - the scalar kind\n * @param offset - the byte offset\n * @returns the component\n */\nfunction getScalar(view: DataView, kind: ScalarKind, offset: number): number {\n if (kind === \"u32\") {\n return view.getUint32(offset, true);\n }\n if (kind === \"i32\") {\n return view.getInt32(offset, true);\n }\n return view.getFloat32(offset, true);\n}\n\n/** A generated struct: the padded WGSL text and the byte writer / reader share one field table, so they cannot disagree (D20). */\nexport class UniformBlock {\n /** The WGSL struct name. */\n readonly name: string;\n /** \"uniform\" (the default) or \"storage\"; both lay out identically, the tag documents the block's address space. */\n readonly layout: \"uniform\" | \"storage\";\n /** The fields in declaration (= byte) order. */\n readonly fields: readonly UniformField[];\n /** The padded byte length (a multiple of 16). */\n readonly byteLength: number;\n /** The `struct <name> { ... }` text with explicit `@size` / `@align` where padding is needed. */\n readonly wgsl: string;\n /** The laid-out fields by name. */\n private readonly table: ReadonlyMap<string, FieldLayout>;\n /** The laid-out fields in order. */\n private readonly laidOut: readonly FieldLayout[];\n\n /**\n * Declares a block; fields are laid out in order with 16-byte alignment for vec4 / the struct, 8 for vec2, 4 for\n * scalars; the total is padded to 16 (uniform, storage) or to `padTo` when given.\n * PLAN DECISION: rejects an empty field list and a struct or field name that is not a WGSL identifier or is a\n * reserved word (spec 3.6: every throwing call leaves state unchanged; a reserved name would be invalid WGSL).\n * PLAN DECISION: optional PARAMETERS (`options?` here, `byteOffset?` of write / read / readField) are spelled\n * `?: T` rather than the contract's `?: T | undefined` because the root ESLint rule\n * no-duplicate-type-constituents rejects the explicit undefined on an optional parameter; every call site is\n * identical, and optional PROPERTIES keep `?: T | undefined`.\n * @param name - the WGSL struct name\n * @param fields - the fields in byte order\n * @param options - the layout tag and the optional padding\n * @param options.layout - \"uniform\" (default) or \"storage\"; the tag documents the address space, the layout is the same\n * @param options.padTo - the byte length to pad to (a multiple of 16 not below the natural size)\n * @returns the block\n */\n static define(\n name: string,\n fields: readonly UniformField[],\n options?: { readonly layout?: \"uniform\" | \"storage\" | undefined; readonly padTo?: number | undefined },\n ): UniformBlock {\n assertIdentifier(\"name\", name);\n if (fields.length === 0) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock ${name}: a block needs at least one field`, {\n argument: \"fields\",\n value: fields.length,\n expected: \">= 1 field\",\n });\n }\n const laidOut: FieldLayout[] = [];\n const table = new Map<string, FieldLayout>();\n let cursor = 0;\n for (const [fieldName, type] of fields) {\n assertIdentifier(\"fields\", fieldName);\n if (table.has(fieldName)) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformBlock ${name}: duplicate field \"${fieldName}\"`,\n {\n argument: \"fields\",\n value: fieldName,\n expected: \"unique field names\",\n },\n );\n }\n const info = TYPE_INFO[type] as TypeInfo | undefined;\n if (info === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock ${name}: unknown field type \"${type}\"`, {\n argument: \"fields\",\n value: type,\n expected: Object.keys(TYPE_INFO).join(\" | \"),\n });\n }\n const offset = roundUp(cursor, info.align);\n const field: FieldLayout = { name: fieldName, type, offset, info };\n laidOut.push(field);\n table.set(fieldName, field);\n cursor = offset + info.size;\n }\n const natural = roundUp(cursor, STRUCT_ALIGN);\n const padTo = options?.padTo;\n if (padTo !== undefined && (!Number.isInteger(padTo) || padTo % STRUCT_ALIGN !== 0 || padTo < natural)) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformBlock ${name}: padTo ${padTo} is not a multiple of 16 >= ${natural}`,\n {\n argument: \"padTo\",\n value: padTo,\n expected: `a multiple of ${STRUCT_ALIGN} not below ${natural}`,\n },\n );\n }\n const byteLength = padTo ?? natural;\n const lines = laidOut.map((field, index) => {\n const last = index === laidOut.length - 1;\n const end = field.offset + field.info.size;\n const size = last && end < byteLength ? `@size(${byteLength - field.offset}) ` : \"\";\n return ` ${size}${field.name}: ${field.type},`;\n });\n const wgsl = `struct ${name} {\\n${lines.join(\"\\n\")}\\n}`;\n return new UniformBlock(name, options?.layout ?? \"uniform\", fields, byteLength, wgsl, laidOut, table);\n }\n\n /**\n * Built by `define()` only.\n * @param name - the struct name\n * @param layout - the address-space tag\n * @param fields - the declared fields\n * @param byteLength - the padded byte length\n * @param wgsl - the struct text\n * @param laidOut - the laid-out fields in order\n * @param table - the laid-out fields by name\n */\n private constructor(\n name: string,\n layout: \"uniform\" | \"storage\",\n fields: readonly UniformField[],\n byteLength: number,\n wgsl: string,\n laidOut: readonly FieldLayout[],\n table: ReadonlyMap<string, FieldLayout>,\n ) {\n this.name = name;\n this.layout = layout;\n this.fields = Object.freeze(fields.map(([fieldName, type]) => Object.freeze([fieldName, type] as const)));\n this.byteLength = byteLength;\n this.wgsl = wgsl;\n this.laidOut = laidOut;\n this.table = table;\n }\n\n /**\n * Byte offset of a field; E_INVALID_ARGUMENT for an unknown field.\n * @param field - the field name\n * @returns the byte offset inside the block\n */\n offsetOf(field: string): number {\n return this.fieldLayout(field).offset;\n }\n\n /**\n * Writes `values` at `byteOffset` (default 0); a missing field is written as 0; an unknown key is\n * E_INVALID_ARGUMENT; a vector of the wrong width is E_INVALID_ARGUMENT. Always little-endian. Every byte of the\n * block's region is written (padding as zero), so a written block is byte-exact.\n * PLAN DECISION: every value is validated first (u32 / vec*u components integers in [0, 2^32 - 1], i32 in\n * [-2^31, 2^31 - 1]) and only then is the region zeroed and written, so a rejected call leaves the view unchanged.\n * @param view - the target view (the region must lie inside it)\n * @param values - the field values\n * @param byteOffset - the region's start inside the view\n */\n write(view: DataView, values: UniformValues, byteOffset?: number): void {\n const base = this.regionStart(view, byteOffset);\n for (const key of Object.keys(values)) {\n if (!this.table.has(key)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock ${this.name}: unknown field \"${key}\"`, {\n argument: \"values\",\n value: key,\n expected: this.laidOut.map((f) => f.name).join(\", \"),\n });\n }\n }\n // validate every value first, so a rejected call leaves the view unchanged (spec 3.6)\n const components: (readonly number[] | null)[] = this.laidOut.map((field) =>\n this.components(field, values[field.name]),\n );\n for (let at = 0; at < this.byteLength; at += 4) {\n view.setUint32(base + at, 0, true);\n }\n this.laidOut.forEach((field, index) => {\n const lanes = components[index];\n if (lanes === null) {\n return;\n }\n lanes.forEach((component, lane) => {\n setScalar(view, field.info.scalar, base + field.offset + 4 * lane, component);\n });\n });\n }\n\n /**\n * The validated components of one field's value: null for an absent field, else `width` numbers.\n * @param field - the laid-out field\n * @param value - the value given for it (undefined when absent)\n * @returns the components or null\n */\n private components(field: FieldLayout, value: number | readonly number[] | undefined): readonly number[] | null {\n if (value === undefined) {\n return null;\n }\n const { scalar, width } = field.info;\n if (width === 1) {\n assertScalar(field.name, scalar, value);\n return [value];\n }\n if (!Array.isArray(value) || value.length !== width) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformBlock ${this.name}: field \"${field.name}\" expects ${width} components`,\n {\n argument: field.name,\n value,\n expected: `an array of ${width} numbers`,\n },\n );\n }\n const lanes: number[] = [];\n for (let lane = 0; lane < width; lane++) {\n const component: unknown = value[lane];\n assertScalar(field.name, scalar, component);\n lanes.push(component);\n }\n return lanes;\n }\n\n /**\n * Reads every field at `byteOffset` (storage mode's reader; also used by tests on uniform blocks).\n * @param view - the source view\n * @param byteOffset - the region's start inside the view\n * @returns the field values (vectors as arrays)\n */\n read(view: DataView, byteOffset?: number): UniformValues {\n const base = this.regionStart(view, byteOffset);\n const out: Record<string, number | readonly number[]> = {};\n for (const field of this.laidOut) {\n out[field.name] = this.decode(view, field, base);\n }\n return out;\n }\n\n /**\n * Reads one field.\n * @param view - the source view\n * @param field - the field name\n * @param byteOffset - the region's start inside the view\n * @returns the value (a number, or an array for a vector)\n */\n readField(view: DataView, field: string, byteOffset?: number): number | readonly number[] {\n const layout = this.fieldLayout(field);\n return this.decode(view, layout, this.regionStart(view, byteOffset));\n }\n\n /**\n * The laid-out field of a name.\n * @param field - the field name\n * @returns the layout\n */\n private fieldLayout(field: string): FieldLayout {\n const layout = this.table.get(field);\n if (layout === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `UniformBlock ${this.name}: unknown field \"${field}\"`, {\n argument: \"field\",\n value: field,\n expected: this.laidOut.map((f) => f.name).join(\", \"),\n });\n }\n return layout;\n }\n\n /**\n * Validates the region `[byteOffset, byteOffset + byteLength)` against the view.\n * @param view - the view\n * @param byteOffset - the requested start (default 0)\n * @returns the start\n */\n private regionStart(view: DataView, byteOffset: number | undefined): number {\n const base = byteOffset ?? 0;\n if (!Number.isInteger(base) || base < 0 || base + this.byteLength > view.byteLength) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformBlock ${this.name}: region [${base}, ${base + this.byteLength}) is outside the view`,\n {\n argument: \"byteOffset\",\n value: base,\n expected: `0 <= byteOffset <= ${view.byteLength - this.byteLength}`,\n },\n );\n }\n return base;\n }\n\n /**\n * Decodes one field from a view.\n * @param view - the source view\n * @param field - the laid-out field\n * @param base - the region start\n * @returns the value\n */\n private decode(view: DataView, field: FieldLayout, base: number): number | readonly number[] {\n const { scalar, width } = field.info;\n if (width === 1) {\n return getScalar(view, scalar, base + field.offset);\n }\n const lanes: number[] = [];\n for (let lane = 0; lane < width; lane++) {\n lanes.push(getScalar(view, scalar, base + field.offset + 4 * lane));\n }\n return lanes;\n }\n}\n","/**\n * The `advance-expand` kernel body (design 6 row 8, 8.10 \"BFS expand\"; P8-T5, the P8 plan's PD-23): Gunrock's\n * block-mapped expansion of a vertex frontier into the edge queue. Each workgroup loads up to `WG` frontier entries,\n * reads their degrees clipped to the bound arc window `[P.arcBase, P.arcEnd)` (so the window-aware form of P8-T12\n * changes nothing here), runs the prelude's INCLUSIVE workgroup scan `wg_scan_u32` over those degrees -- the subgroup\n * form when the device has the feature, the Hillis-Steele form otherwise, which is the ONLY text that differs between\n * the twin's two compilations -- and then every invocation strips the range `[0, aggregate)` with a binary search\n * (`upper_bound`) over the scanned degrees to find which entry its arc belongs to. One `atomicAdd` per WORKGROUP\n * reserves the block's span in the queue (`edgeCount`), the same aggregate lands in `edgeCountUnclamped` (the overflow\n * detector, never clamped) and in `frontierDegreeSum` (the inspect seam's per-level expansion count, rotated into\n * `prevDegreeSum` by the boundary; Beamer's m_f is `nextDegreeSum`, measured by `bfs-next-degree` -- issue #391);\n * a lane whose queue position is at or past `P.edgeCapacity` writes nothing (the clamp). The queue holds the TARGET vertex of each arc only (PD-24: `parent`\n * comes from the post-pass). Uniformity (spec 3.5 rule 1): the guarded loads write locals, the scan call and the\n * `workgroupUniformLoad` sit unconditionally after the guard, and the strip loop is bounded by a uniform value.\n * There is no `TIER` override: a hub row is balanced over all `WG` lanes inside its block, and the small-frontier\n * workgroup-per-row structure is `bfs-fused` (P8-T7). Body only (spec 3.5, D9); the text is normative: the\n * sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const advanceExpandWgsl = /* wgsl */ `\nvar<workgroup> sh: array<u32, WG>; // the block's degrees, then their inclusive scan\nvar<workgroup> rowStart: array<u32, WG>; // the first bound arc of each entry's row\nvar<workgroup> base: u32; // the block's reserved span in the edge queue\nvar<workgroup> wcount: u32; // the frontier's length on a two-phase level, 0 on any other\n\n@compute @workgroup_size(WG)\nfn advance_expand(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x == 0u) { wcount = select(0u, atomicLoad(&counters[0]), atomicLoad(&counters[24]) == 1u); } // frontierCount, on the two-phase path only (the path word)\n let count = workgroupUniformLoad(&wcount); // uniform: the block loop below holds barriers\n for (var b0 = group_id(wid) * WG; b0 < count; b0 = b0 + P.stride) { // grid-stride over blocks of WG entries (a direct dispatch of the plan's groups)\n let i = b0 + lid.x; // this lane's frontier entry\n var deg = 0u;\n var start = 0u;\n if (i < count) { // guarded loads into locals (3.5 rule 1)\n let v = frontierIn[i];\n let lo = max(rowPtr[v], P.arcBase); // the row clipped to the bound window (P8-T12)\n let hi = min(rowPtr[v + 1u], P.arcEnd);\n start = lo;\n deg = select(0u, hi - lo, hi > lo);\n }\n let inclusive = wg_scan_u32(deg, lid.x); // the prelude's inclusive scan in LANE order (P8-T1 Step 5); the twin\n sh[lid.x] = inclusive; // sh is monotone in lid.x, the index the binary search walks\n rowStart[lid.x] = start;\n workgroupBarrier();\n let aggregate = workgroupUniformLoad(&sh[WG - 1u]); // uniform; includes a barrier\n if (lid.x == 0u) {\n base = atomicAdd(&counters[8], aggregate); // edgeCount: ONE reservation per workgroup, not one per arc\n atomicAdd(&counters[9], aggregate); // edgeCountUnclamped: the overflow detector (PD-23)\n atomicAdd(&counters[2], aggregate); // frontierDegreeSum: what this level expanded (the inspect seam)\n }\n workgroupBarrier();\n for (var p = lid.x; p < aggregate; p = p + WG) { // strip [0, aggregate): lane j takes j, j + WG, ...\n var lo = 0u; // upper_bound: the first k with sh[k] > p owns arc p\n var hi = WG;\n loop {\n if (lo >= hi) { break; }\n let mid = (lo + hi) / 2u;\n if (sh[mid] > p) { hi = mid; } else { lo = mid + 1u; }\n }\n let k = lo;\n var exclusive = 0u;\n if (k > 0u) { exclusive = sh[k - 1u]; }\n let arc = rowStart[k] + (p - exclusive);\n let q = base + p;\n if (q < P.edgeCapacity) { edgeQueue[q] = colIdx[arc - P.arcBase]; } // the clamp of PD-23; the queue holds the target vertex only (PD-24)\n }\n workgroupBarrier(); // sh, rowStart and base are reused by the next block\n }\n}\n`;\n","/**\n * The `apsp-fw` kernel body (design 8.7): one phase of one round of blocked Floyd-Warshall over `APSP_TILE x\n * APSP_TILE` blocks of the row-major `n x n` matrix `dist`. Round `r` (`P.round`) runs three dispatches in order,\n * the `PHASE` override choosing which:\n *\n * - PHASE 0, one workgroup: the pivot block `(r, r)`, staged in `tileA` and updated in place.\n * - PHASE 1, `2 (B - 1)` workgroups (`B` = `P.blocks`): every other block of block row `r` (the first `B - 1`\n * workgroups) and of block column `r` (the rest). The pivot block is staged in `tileA`, the block itself in\n * `tileB`, updated in place.\n * - PHASE 2, `(B - 1)^2` workgroups: every block `(i, j)` off the pivot row and column. Its two operands are the\n * pivot-COLUMN block `(i, r)` in `tileA` and the pivot-ROW block `(r, j)` in `tileB`; its own cells are read,\n * minimised over the 32 steps and written by one lane each, never shared, so they stay in registers.\n *\n * In-place updates are race-free because a cell is written only when the candidate is STRICTLY smaller: the cells\n * every lane reads in step `k` (column `k` and row `k` of the tile) would be updated with `d + d[k][k]`, and the\n * diagonal is `0` (weights are non-negative, which the driver checks) or `+Infinity` outside the matrix, so they are\n * never written in step `k`. Every barrier is reached in uniform control flow: the early return keys on the workgroup\n * id and uniforms only, the per-lane loops hold no barrier, and the lanes of an edge tile load `+Infinity` for a cell\n * outside `n x n` (it offers no path; read from `P.infBits` because Tint refuses `+Infinity` as a constant) and\n * store nothing there -- the matrix is exactly `n * n`, never padded, so the\n * ceiling is `floor(sqrt(maxStorageBufferBindingSize / 4))`. Body only (spec 3.5, D9); the text is normative: the\n * sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const apspFwWgsl = /* wgsl */ `\nvar<workgroup> tileA: array<f32, APSP_TILE * APSP_TILE>;\nvar<workgroup> tileB: array<f32, APSP_TILE * APSP_TILE>;\n\nfn tile_row(block: vec2<u32>, c: u32) -> u32 { return block.x * APSP_TILE + c / APSP_TILE; }\nfn tile_col(block: vec2<u32>, c: u32) -> u32 { return block.y * APSP_TILE + c % APSP_TILE; }\n\nfn load_cell(block: vec2<u32>, c: u32) -> f32 {\n let i = tile_row(block, c);\n let j = tile_col(block, c);\n if (i < P.n && j < P.n) { return dist[i * P.n + j]; }\n return bitcast<f32>(P.infBits); // outside the matrix: no path through it\n}\n\nfn store_cell(block: vec2<u32>, c: u32, v: f32) {\n let i = tile_row(block, c);\n let j = tile_col(block, c);\n if (i >= P.n || j >= P.n) { return; } // an edge tile stores nothing outside n x n\n dist[i * P.n + j] = v;\n}\n\n@compute @workgroup_size(WG)\nfn apsp_fw(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let g = group_id(wid);\n let r = P.round;\n let others = max(P.blocks, 2u) - 1u; // the blocks of a strip, the pivot excluded\n let cells = APSP_TILE * APSP_TILE;\n var count = 1u;\n var own = vec2<u32>(r, r); // the block this workgroup updates\n var a = vec2<u32>(r, r); // staged in tileA\n var b = vec2<u32>(r, r); // staged in tileB\n if (PHASE == 1u) {\n count = 2u * others;\n let s = g % others;\n let o = select(s, s + 1u, s >= r); // a strip skips the pivot block\n own = select(vec2<u32>(o, r), vec2<u32>(r, o), g < others); // block row r first, then block column r\n b = own;\n }\n if (PHASE == 2u) {\n count = others * others;\n let i = g / others;\n let j = g % others;\n own = vec2<u32>(select(i, i + 1u, i >= r), select(j, j + 1u, j >= r));\n a = vec2<u32>(own.x, r); // the pivot-column block (i, r)\n b = vec2<u32>(r, own.y); // the pivot-row block (r, j)\n }\n if (g >= count) { return; } // uniform: the workgroup id and uniforms only\n\n for (var c = lid.x; c < cells; c = c + WG) {\n tileA[c] = load_cell(a, c);\n if (PHASE != 0u) { tileB[c] = load_cell(b, c); }\n }\n workgroupBarrier(); // every staged cell is visible\n\n if (PHASE == 2u) {\n for (var c = lid.x; c < cells; c = c + WG) {\n let x = c / APSP_TILE;\n let y = c % APSP_TILE;\n var v = load_cell(own, c);\n for (var kr = 0u; kr < APSP_TILE; kr = kr + 1u) {\n v = min(v, tileA[x * APSP_TILE + kr] + tileB[kr * APSP_TILE + y]);\n }\n store_cell(own, c, v);\n }\n return;\n }\n\n let pivotRow = PHASE == 1u && own.x == r; // block row r reads d[x][k] from the pivot\n for (var k = 0u; k < APSP_TILE; k = k + 1u) {\n for (var c = lid.x; c < cells; c = c + WG) {\n let x = c / APSP_TILE;\n let y = c % APSP_TILE;\n if (PHASE == 0u) {\n let via = tileA[x * APSP_TILE + k] + tileA[k * APSP_TILE + y];\n if (via < tileA[c]) { tileA[c] = via; }\n } else {\n let left = select(tileB[x * APSP_TILE + k], tileA[x * APSP_TILE + k], pivotRow);\n let right = select(tileA[k * APSP_TILE + y], tileB[k * APSP_TILE + y], pivotRow);\n let via = left + right;\n if (via < tileB[c]) { tileB[c] = via; }\n }\n }\n workgroupBarrier(); // step k is complete before step k + 1 reads\n }\n for (var c = lid.x; c < cells; c = c + WG) {\n store_cell(own, c, select(tileB[c], tileA[c], PHASE == 0u));\n }\n}\n`;\n","/**\n * The `apsp-init` kernel body (design 8.7): writes the arcs into the `n x n` distance matrix after `fill` has set\n * every entry to `+Infinity`. One lane per ROW `u`: it walks `u`'s arcs and keeps the cheapest weight per target\n * (`min`), so parallel arcs collapse to the cheapest one, then writes the diagonal zero LAST, so a self-loop never\n * displaces it. Every arc of row `u` lands in row `u` of the matrix and only this lane writes that row, so there is\n * no race and no atomic. Unweighted (`HAS_WEIGHTS` false) every arc costs 1. A directed snapshot writes its one\n * direction; an undirected one stores both arcs of every edge, so both halves are written. The driver refuses\n * negative and non-finite weights before any dispatch. Body only (spec 3.5, D9); the text is normative: the\n * sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const apspInitWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn apsp_init(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let u = linear_id(wid, lid.x);\n if (u >= P.n) { return; }\n let rowBase = u * P.n;\n let end = rowPtr[u + 1u];\n for (var a = rowPtr[u]; a < end; a = a + 1u) {\n let v = colIdx[a];\n let w = select(1.0, weights[a], HAS_WEIGHTS);\n dist[rowBase + v] = min(dist[rowBase + v], w); // parallel arcs collapse to the cheapest\n }\n dist[rowBase + u] = 0.0; // last: a self-loop never displaces the zero\n}\n`;\n","/**\n * The `bc-backward` kernel body (design 8.4 \"each (w, s) PULLS over its successors\", 8.10 \"BC backward (successor\n * pull)\"): one level of a betweenness batch's dependency accumulation, one invocation per log entry `(w, s)` of the\n * level's range `S[P.start .. P.start + P.count)`, which the host planned from the `ends` it read back. Each entry\n * walks the out-arcs of `w` -- the rows the forward pass expanded -- and sums `sigma[s][w] / sigma[s][v] * (1 +\n * delta[s][v])` over the successors `v` (`depth[s][v] == depth[s][w] + 1`), whose dependencies the previous (deeper)\n * dispatch wrote, then writes `delta[s][w]` ONCE. The stored counts are scaled per depth (`bc-count`), so the ratio\n * is taken back to true scale with `ldexp(..., -sigma_shift(levelMax[depth]))`, the step `bc-count` applied between\n * `w`'s depth and its successors'. Only under `SCALED` (the batch reran with `bc-count`'s f32 counts); otherwise the\n * counts are exact u32 and the step is 0, which leaves every ratio bit for bit what it was. No float is ever accumulated through an atomic, so the result is\n * bitwise reproducible. The sources (depth 0) are never dispatched: their dependency stays 0, which is what keeps a\n * source's own dependency out of its score. Grid-stride loop (`P.stride`). ponytail: one lane walks one row, so a\n * vertex of degree above 65,535 exceeds llvmpipe's per-invocation loop cap (CLAUDE.md, Verified Platform Facts) and\n * would need a workgroup-per-row form there; hardware adapters have no such cap. Body only; the sabotage rows of\n * test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bcBackwardWgsl = /* wgsl */ `\nfn sigma_of(word: u32) -> f32 { // a stored count: u32, or f32 bits when SCALED\n if (SCALED) { return bitcast<f32>(word); }\n return f32(word);\n}\n\n@compute @workgroup_size(WG)\nfn bc_backward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n for (var i = linear_id(wid, lid.x); i < P.count; i = i + P.stride) {\n let t = S[P.start + i]; // s * n + w\n let w = t % P.n;\n let base = t - w; // s * n\n let succ = depthK[t] + 1u;\n let sw = sigma_of(sigmaK[t]);\n let shift = select(0i, sigma_shift(levelMax[depthK[t]]), SCALED); // the scale step to the successors' depth\n var acc = 0.0;\n for (var a = rowPtr[w]; a < rowPtr[w + 1u]; a = a + 1u) {\n let v = base + colIdx[a];\n if (depthK[v] == succ) { // v is a successor of w for source s\n acc = acc + ldexp(sw / sigma_of(sigmaK[v]), -shift) * (1.0 + deltaK[v]);\n }\n }\n deltaK[t] = acc; // written once per (w, s)\n }\n}\n`;\n","/**\n * The `bc-count` kernel body (design 8.4, issue #719): the shortest-path counts of the depth a betweenness forward\n * level has just claimed, PULLED once the claims are complete. It runs only in a batch rerun because its u32 counts\n * wrapped (the forward bodies then run with `SCALED` and count nothing); `sigmaK` holds f32 bits throughout. One invocation per entry `t = s * n + x` of the range\n * `S[ends[level + 1] .. stackTop)` (the entries the forward dispatch appended), each summing `sigma[s][v]` over the\n * in-arcs `(v, x)` with `depth[s][v] == level` in CSR order -- the reverse adjacency, which on an undirected snapshot\n * is the forward one. No atomic touches a count, so the sums are bitwise reproducible, and both forward bodies leave\n * the same counts.\n *\n * The counts are f32 and rescaled per depth, because a lattice outgrows any fixed width (a 40 x 40 grid has C(78, 39),\n * about 2.6e22, corner-to-corner paths): each sum is multiplied by `2^-sigma_shift(levelMax[level])`, the power of\n * two that brings the previous depth's largest count down to 2^BC_SIGMA_EXPONENT_CAP, and the result's bits go into\n * `levelMax[level + 1]` by `atomicMax` (positive f32 bits order like the values). Every count of one (depth, batch)\n * shares that scale, and Brandes' backward pass reads only ratios of a count to its successors', so `bc-backward`\n * undoes the one step between two depths and nothing else. A count that leaves f32's normal range anyway -- zero,\n * subnormal, infinite -- raises `sigmaOverflow` (counters word 27): the counts at one depth spread wider than f32 can\n * hold, and the scores are wrong. Grid-stride loop (`P.stride`); the range is read from the device, so the host\n * dispatches for the largest possible level. Body only; the sabotage rows of test/helpers/sabotage.ts are textual\n * edits of it.\n */\nexport const bcCountWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn bc_count(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let level = atomicLoad(&counters[11]);\n let start = ends[level + 1u]; // the boundary closed the claim-from level here\n let count = atomicLoad(&counters[26]) - start; // stackTop: what the forward dispatch appended\n let shift = sigma_shift(atomicLoad(&levelMax[level]));\n for (var i = linear_id(wid, lid.x); i < count; i = i + P.stride) {\n let t = S[start + i]; // s * n + x, at depth level + 1\n let x = t % P.n;\n let base = t - x; // s * n\n var acc = 0.0;\n for (var a = rowPtr[x]; a < rowPtr[x + 1u]; a = a + 1u) { // the in-arcs (v, x)\n let v = base + colIdx[a];\n if (depthK[v] == level) { acc = acc + bitcast<f32>(sigmaK[v]); } // every predecessor's paths, CSR order\n }\n let sigma = ldexp(acc, -shift);\n let bits = bitcast<u32>(sigma);\n sigmaK[t] = bits;\n let exponent = (bits >> 23u) & 0xffu;\n if (exponent == 0u || exponent == 0xffu) { atomicOr(&counters[27], 1u); } // out of f32's normal range\n atomicMax(&levelMax[level + 1u], bits);\n }\n}\n`;\n","/**\n * The `bc-edge-gather` kernel body (design 8.4 \"edge BC accumulates per arc from the same n x k deltas\"): the per-arc\n * twin of `bc-gather`, run once per batch after the backward sweep. One invocation per ARC (`P.count` arcs,\n * grid-stride): it finds the row `w` that owns the arc by an upper-bound search over `rowPtr`, then adds over the\n * batch's sources in order the term the backward pass summed -- `sigma[s][w] / sigma[s][v] * (1 + delta[s][v])`\n * whenever `w` was reached and `depth[s][v] == depth[s][w] + 1`, with `bc-backward`'s depth scale step under `SCALED` -- into\n * `arcScores[arc]`. Each arc is written by one\n * invocation: no atomic, a fixed order. Arc-parallel rather than row-parallel so a hub row is not one lane's loop\n * (llvmpipe caps a shader loop at 65,535 iterations, and a 1,000-arc hub times 64 sources passed it). Body only;\n * the sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bcEdgeGatherWgsl = /* wgsl */ `\nfn sigma_of(word: u32) -> f32 { // a stored count: u32, or f32 bits when SCALED\n if (SCALED) { return bitcast<f32>(word); }\n return f32(word);\n}\n\n@compute @workgroup_size(WG)\nfn bc_edge_gather(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n for (var a = linear_id(wid, lid.x); a < P.count; a = a + P.stride) {\n var lo = 0u; // the row w with rowPtr[w] <= a < rowPtr[w + 1]\n var hi = P.n;\n loop {\n if (lo >= hi) { break; }\n let mid = (lo + hi) / 2u;\n if (rowPtr[mid + 1u] <= a) { lo = mid + 1u; } else { hi = mid; }\n }\n let w = lo;\n let nbr = colIdx[a];\n var acc = arcScores[a];\n for (var s = 0u; s < P.k; s = s + 1u) {\n let base = s * P.n;\n let dw = depthK[base + w];\n if (dw != INVALID_INDEX && depthK[base + nbr] == dw + 1u) { // (w, nbr) is on a shortest path from s\n let shift = select(0i, sigma_shift(levelMax[dw]), SCALED);\n let ratio = ldexp(sigma_of(sigmaK[base + w]) / sigma_of(sigmaK[base + nbr]), -shift);\n acc = acc + ratio * (1.0 + deltaK[base + nbr]);\n }\n }\n arcScores[a] = acc;\n }\n}\n`;\n","/**\n * The `bc-finalize` kernel body (design 8.4, 5.4): the one-lane bookkeeping of a betweenness source batch, two roles\n * by `P.role`. The batch keeps ONE append-only claim log `S` -- every `(vertex, source)` pair the forward pass\n * claims, packed as the index `s * n + v` into the `n x k` arrays -- and `ends`, the level boundaries into it: the\n * entries at depth `L` are `S[ends[L] .. ends[L + 1])`. That log is Brandes' stack, so the backward pass walks the\n * same ranges from the deepest level up and nothing is ever copied between levels.\n *\n * Role 1 seeds the batch: the k seed entries the host wrote into `S[0 .. k)` get depth 0 and one shortest path (the\n * u32 1, or under `SCALED` the bits of the f32 1.0), `levelMax[0]` the bits of 1.0 (the largest count at depth 0,\n * which `bc-count` scales depth 1 from), `ends[0] = 0`, the append cursor `stackTop` (counters word 26) starts at k, the overflow flag (word 27) is cleared,\n * `level` (word 11) is U32_MAX so the first boundary lands on 0, and `done` (word 15) is cleared.\n *\n * Role 0 is the level boundary, recorded before every forward level: it advances `level`, closes the level just\n * claimed by writing `ends[level + 1] = stackTop`, publishes the new level's size in `frontierCount` (word 0) and sets\n * `done` when that level is empty. A boundary that finds `done` set moves nothing, so the levels the host records\n * past the end are no-ops. The forward kernels dispatch directly and read their range from `ends` (no indirect\n * dispatch: design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md). One lane; no barrier follows the\n * early return of the others (spec 3.5 rule 1). Body only; the sabotage rows of test/helpers/sabotage.ts are\n * textual edits of it.\n */\nexport const bcFinalizeWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn bc_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x != 0u) { return; } // one lane; no barrier follows (3.5 rule 1)\n if (P.role == 1u) { // the seed of a batch\n for (var i = 0u; i < P.k; i = i + 1u) {\n let t = S[i];\n depthK[t] = 0u; // the source is at depth 0\n sigmaK[t] = select(1u, bitcast<u32>(1.0), SCALED); // with one shortest path, itself (f32 bits when SCALED)\n }\n levelMax[0] = bitcast<u32>(1.0); // the largest count at depth 0\n ends[0] = 0u;\n atomicStore(&counters[26], P.k); // stackTop: the seeds are the log's first k entries\n atomicStore(&counters[27], 0u); // sigmaOverflow\n atomicStore(&counters[11], U32_MAX); // level: the first boundary brings it to 0\n atomicStore(&counters[15], 0u); // done\n return;\n }\n if (atomicLoad(&counters[15]) != 0u) { return; } // done: a no-op level the host recorded past the end\n let level = atomicLoad(&counters[11]) + 1u;\n let top = atomicLoad(&counters[26]);\n ends[level + 1u] = top; // the level's entries end where the log ends now\n let count = top - ends[level];\n atomicStore(&counters[0], count); // frontierCount (the inspect seam reads it)\n atomicStore(&counters[11], level);\n atomicStore(&counters[15], select(0u, 1u, count == 0u)); // an empty level ends the batch\n}\n`;\n","/**\n * The `bc-forward` kernel body (design 8.4 \"forward pass = BFS with sigma as array<atomic<u32>>\", 8.10 \"BC forward\n * (tagged)\", 16.1): one level of the tagged multi-source breadth-first search of a betweenness batch. The level's\n * frontier is the range `S[ends[level] .. ends[level + 1])` of the claim log, every entry a packed `s * n + u`; the\n * expansion is `advance-expand`'s block-mapped strip (each workgroup loads up to `WG` entries, scans their degrees\n * in workgroup memory, and every lane strips the aggregate by an upper-bound binary search), fused with the claim, so\n * no edge queue exists.\n *\n * For the arc `(u, x)` of the entry `(u, s)`, with `t = s * n + x`: the CLAIM -- a relaxed pre-check that skips the\n * atomic when `t` is already claimed (design 16.1: a stale \"unclaimed\" costs one redundant atomic, a stale \"claimed\"\n * cannot happen because a claim is never revoked), then `atomicMin(&depthK[t], level + 1)`, the invocation that\n * observes INVALID_INDEX the unique winner, which appends `t` to the log; and, as a SEPARATE condition, the COUNT:\n * every arc that reaches `t` at `level + 1` adds `sigma[s][u]` into `sigma[s][x]`, winner or not, which is what makes\n * sigma the number of shortest paths rather than of claims. The add detects a u32 wrap from `atomicAdd`'s return\n * value (`old + add < old`) and raises `sigmaOverflow` (counters word 27); the count is never clamped. Under\n * `SCALED` (a batch rerun because the u32 counts wrapped) the count is skipped and `bc-count` pulls rescaled f32\n * counts after the level instead. The winners of\n * a strip are packed into the log with one workgroup-memory counter and ONE global `atomicAdd` on `stackTop` (word\n * 26) per strip. Uniformity (spec 3.5 rule 1): the range and the aggregate are `workgroupUniformLoad`s and the strip\n * loop steps a uniform `p0`, so every barrier is in uniform control flow. The order of the log inside a level is\n * not deterministic; nothing downstream depends on it (the counts are integers and every dependency is written by\n * index). Body only; the sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bcForwardWgsl = /* wgsl */ `\nvar<workgroup> sh: array<u32, WG>; // the block's degrees, then their inclusive scan\nvar<workgroup> rowStart: array<u32, WG>; // the first arc of each entry's row\nvar<workgroup> entryOf: array<u32, WG>; // each entry, s * n + u\nvar<workgroup> wstart: u32; // the level's first log index\nvar<workgroup> wcount: u32; // the level's entry count\nvar<workgroup> wwon: atomic<u32>; // the strip's winners\nvar<workgroup> wbase: u32; // where the strip's winners go in the log\n\n@compute @workgroup_size(WG)\nfn bc_forward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let level = atomicLoad(&counters[11]);\n if (lid.x == 0u) {\n let lo = ends[level];\n wstart = lo;\n wcount = ends[level + 1u] - lo;\n }\n let start = workgroupUniformLoad(&wstart);\n let count = workgroupUniformLoad(&wcount); // uniform: the block loop below holds barriers\n let next = level + 1u;\n for (var b0 = group_id(wid) * WG; b0 < count; b0 = b0 + P.stride) { // grid-stride over blocks of WG entries\n let i = b0 + lid.x;\n var deg = 0u;\n var first = 0u;\n var entry = 0u;\n if (i < count) { // guarded loads into locals (3.5 rule 1)\n entry = S[start + i];\n let u = entry % P.n;\n first = rowPtr[u];\n deg = rowPtr[u + 1u] - first;\n }\n sh[lid.x] = deg;\n rowStart[lid.x] = first;\n entryOf[lid.x] = entry;\n workgroupBarrier();\n for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan of the degrees\n var t = 0u;\n if (lid.x >= s) { t = sh[lid.x - s]; }\n workgroupBarrier();\n sh[lid.x] = sh[lid.x] + t;\n workgroupBarrier();\n }\n let aggregate = workgroupUniformLoad(&sh[WG - 1u]); // uniform; includes a barrier\n for (var p0 = 0u; p0 < aggregate; p0 = p0 + WG) { // strip [0, aggregate) WG arcs at a time\n let p = p0 + lid.x;\n var won = false;\n var claimed = 0u;\n if (p < aggregate) {\n var lo = 0u; // upper_bound: the first k with sh[k] > p owns arc p\n var hi = WG;\n loop {\n if (lo >= hi) { break; }\n let mid = (lo + hi) / 2u;\n if (sh[mid] > p) { hi = mid; } else { lo = mid + 1u; }\n }\n let k = lo;\n var exclusive = 0u;\n if (k > 0u) { exclusive = sh[k - 1u]; }\n let origin = entryOf[k]; // s * n + u\n let x = (origin - (origin % P.n)) + colIdx[rowStart[k] + (p - exclusive)]; // s * n + x\n if (atomicLoad(&depthK[x]) == INVALID_INDEX) { // the pre-check of design 16.1\n won = atomicMin(&depthK[x], next) == INVALID_INDEX; // the claim: the one winner appends\n }\n if (!SCALED && atomicLoad(&depthK[x]) == next) { // the count: EVERY arc on a shortest path adds\n let add = atomicLoad(&sigmaK[origin]);\n let old = atomicAdd(&sigmaK[x], add);\n if (old + add < old) { atomicOr(&counters[27], 1u); } // the u32 wrap, reported\n }\n claimed = x;\n }\n var slot = 0u;\n if (won) { slot = atomicAdd(&wwon, 1u); }\n workgroupBarrier();\n if (lid.x == 0u) {\n wbase = atomicAdd(&counters[26], atomicLoad(&wwon)); // stackTop: one global atomic per strip\n atomicStore(&wwon, 0u);\n }\n workgroupBarrier();\n if (won) { S[wbase + slot] = claimed; }\n }\n workgroupBarrier(); // sh, rowStart and entryOf are reused by the next block\n }\n}\n`;\n","/**\n * The `bc-forward-edge` kernel body (design 8.4 \"the McLaughlin-Bader online switch to the edge-parallel form\", 8.8\n * row 7): one level of a betweenness batch's forward pass, edge-parallel -- every logical edge of the `edgeList` view\n * for every source of the batch, grid-striding over the edges inside a loop over the k sources. For the edge `(u, x)`\n * and source `s`, when `depth[s][u]` is the level the edge is relaxed toward `x` with EXACTLY the claim and the count\n * of `bc-forward` (the pre-check, `atomicMin`, the winner appends `s * n + x` to the same claim log, every arc on a\n * shortest path adds `sigma[s][u]`, a u32 wrap raises word 27); `UNDIRECTED` relaxes the other direction too, the\n * edge list holding each undirected edge once. Under `SCALED` the count is skipped, as in `bc-forward`. So the two forward bodies are interchangeable level by level and the\n * backward pass cannot tell which ran. A workgroup does nothing when the level is empty (the done boundary). The\n * winners of a strip are packed into the log with one global `atomicAdd` per strip; every barrier is in uniform\n * control flow (the loop bounds are uniforms and the workgroup id). Body only; the sabotage rows of\n * test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bcForwardEdgeWgsl = /* wgsl */ `\nvar<workgroup> wlive: u32; // 1 when the level has entries\nvar<workgroup> wwon: atomic<u32>; // the strip's winners\nvar<workgroup> wbase: u32; // where the strip's winners go in the log\n\nfn claim(x: u32, next: u32) -> bool {\n if (atomicLoad(&depthK[x]) != INVALID_INDEX) { return false; } // the pre-check of design 16.1\n return atomicMin(&depthK[x], next) == INVALID_INDEX;\n}\n\nfn count_paths(origin: u32, x: u32, next: u32) {\n if (!SCALED && atomicLoad(&depthK[x]) == next) { // every arc on a shortest path adds\n let add = atomicLoad(&sigmaK[origin]);\n let old = atomicAdd(&sigmaK[x], add);\n if (old + add < old) { atomicOr(&counters[27], 1u); } // the u32 wrap, reported\n }\n}\n\n@compute @workgroup_size(WG)\nfn bc_forward_edge(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let level = atomicLoad(&counters[11]);\n if (lid.x == 0u) { wlive = select(0u, 1u, ends[level + 1u] > ends[level]); }\n if (workgroupUniformLoad(&wlive) == 0u) { return; } // uniform: nothing below runs on an empty level\n let next = level + 1u;\n for (var s = 0u; s < P.k; s = s + 1u) {\n let base = s * P.n;\n for (var e0 = group_id(wid) * WG; e0 < P.count; e0 = e0 + P.stride) { // grid-stride over the edges\n let e = e0 + lid.x;\n var a = INVALID_INDEX; // the claims this lane won\n var b = INVALID_INDEX;\n if (e < P.count) {\n let u = base + edgeSrc[e];\n let x = base + edgeDst[e];\n if (atomicLoad(&depthK[u]) == level) {\n if (claim(x, next)) { a = x; }\n count_paths(u, x, next);\n }\n if (UNDIRECTED) { // the other direction of an undirected edge\n if (atomicLoad(&depthK[x]) == level) {\n if (claim(u, next)) { b = u; }\n count_paths(x, u, next);\n }\n }\n }\n let mine = select(0u, 1u, a != INVALID_INDEX) + select(0u, 1u, b != INVALID_INDEX);\n var slot = 0u;\n if (mine != 0u) { slot = atomicAdd(&wwon, mine); }\n workgroupBarrier();\n if (lid.x == 0u) {\n wbase = atomicAdd(&counters[26], atomicLoad(&wwon)); // stackTop: one global atomic per strip\n atomicStore(&wwon, 0u);\n }\n workgroupBarrier();\n if (a != INVALID_INDEX) {\n S[wbase + slot] = a;\n slot = slot + 1u;\n }\n if (b != INVALID_INDEX) { S[wbase + slot] = b; }\n }\n }\n}\n`;\n","/**\n * The `bc-gather` kernel body (design 8.4 \"one gather kernel after the batch's last backward level\", 8.10 \"BC\n * gather\"): one invocation per vertex `w`, `bc[w] += delta[0][w] + ... + delta[k - 1][w]` in source order -- k reads,\n * one write, no atomic, a fixed summation order, so the scores are bitwise reproducible across runs and adapters.\n * A source's own dependency is 0 (the backward pass never visits depth 0), so nothing is skipped here. Grid-stride\n * loop (`P.stride`). Body only; the sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bcGatherWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn bc_gather(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n for (var w = linear_id(wid, lid.x); w < P.n; w = w + P.stride) {\n var acc = bc[w];\n for (var s = 0u; s < P.k; s = s + 1u) {\n acc = acc + deltaK[s * P.n + w];\n }\n bc[w] = acc;\n }\n}\n`;\n","/**\n * The `bf-relax` kernel body (design 8.4 \"Bellman-Ford\"; P8-T10, the P8 plan's PD-12 / PD-22 / PD-27 / DEP-P8-E):\n * one edge-parallel relaxation round over the `edgeList()` view -- every logical edge once, in declared orientation,\n * and under `UNDIRECTED` the other direction too, because an undirected edge has ONE weight (read through its\n * forward arc, `weights[edgeToArc[e]]`, from the run's arc-indexed vector: the snapshot's column or the uploaded\n * override). `dist` is `array<atomic<u32>>` holding the f32 bit patterns (`F32_INF_BITS` = unreached, tested as the\n * pattern: `bitcast<f32>(F32_INF_BITS)` is a const-expression Tint rejects). `atomicMin` on the patterns is `min` on\n * the values for NON-NEGATIVE floats only (PD-9); with a negative distance the bit-pattern order reverses, so the\n * claim is a compare-exchange loop on the pattern: read, compute, compare as floats, try to exchange. WGSL lets\n * `atomicCompareExchangeWeak` fail spuriously, so the loop is BOUNDED (PD-12: `P.maxRetries`, the driver's\n * `MAX_RETRIES`) -- on SPURIOUS failures only (`old_value == cur`). A failure that returns another value lost to\n * another lane's successful exchange, which strictly lowered `dist[v]`; that happens at most once per edge into\n * `v` per round, so those iterations are bounded by the in-degree and never counted (issue #470: counted, 32\n * descending candidates in one 32-wide subgroup needed 31 attempts and exhausted 16). A lane that exhausts it sets `flags[1]`\n * (`retryExhausted`): the driver treats the round as changed and runs on, so the lost update is retried by the next\n * round, which examines every edge anyway; a bound hit in the decision round is E_VALIDATION, never a guess. A\n * successful exchange sets `flags[0]` (`changed`); the driver stops when a batch of rounds changed nothing, and a\n * change in the round after `n - 1` is the negative cycle. `P.cutoffBits` is the CPU port's `dv <= cutoff` guard\n * (`+Inf` when absent; with negative weights a negative cutoff legitimately relaxes). Grid-strided over\n * `planGridStride(edgeCount)` with `P.stride` the plan's stride; no barrier anywhere, so the loops may be per lane.\n * The whole arc array is bound (never windowed, DEP-P8-E). Body only (spec 3.5, D9); the text is normative: the\n * sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bfRelaxWgsl = /* wgsl */ `\nfn relax(v: u32, nd: f32) {\n var cur = atomicLoad(&dist[v]);\n var tries = 0u;\n loop {\n if (!(nd < bitcast<f32>(cur))) { break; } // no improvement; +Inf is greater than every finite nd\n let r = atomicCompareExchangeWeak(&dist[v], cur, bitcast<u32>(nd));\n if (r.exchanged) { atomicStore(&flags[0], 1u); break; } // changed\n if (r.old_value == cur) { // a spurious failure: the only kind the bound counts\n tries = tries + 1u;\n if (tries >= P.maxRetries) { atomicStore(&flags[1], 1u); break; } // retryExhausted (PD-12)\n }\n cur = r.old_value; // else another lane's improvement won (issue #470)\n }\n}\n\n@compute @workgroup_size(WG)\nfn bf_relax(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let first = linear_id(wid, lid.x);\n let cutoff = bitcast<f32>(P.cutoffBits);\n for (var e = first; e < P.edgeCount; e = e + P.stride) { // each logical edge once (edgeList)\n let u = edgeSrc[e];\n let v = edgeDst[e];\n let w = weights[edgeToArc[e]]; // the edge's weight through its forward arc\n let du = atomicLoad(&dist[u]);\n if (du != F32_INF_BITS) { // unreached is tested as the bit pattern, as sssp-pred does\n let nd = bitcast<f32>(du) + w;\n if (nd <= cutoff) { relax(v, nd); }\n }\n if (UNDIRECTED) { // the other direction of an undirected edge\n let dv = atomicLoad(&dist[v]);\n if (dv != F32_INF_BITS) {\n let nd = bitcast<f32>(dv) + w;\n if (nd <= cutoff) { relax(u, nd); }\n }\n }\n }\n}\n`;\n","/**\n * The `bfs-bitset-build` kernel body (design 8.4 \"the bitset frontier\"; P8-T8): the vertex-list-to-bitset hand-off\n * of a bottom-up level. One invocation per entry of the input frontier (`frontierCount`, word 0), each `atomicOr`ing\n * its vertex's bit into the `ceil(n / 32)`-word bitset at `P.bitsBase` inside the `sweepIn` buffer (the region a\n * `fill` zeroed just before, on every level). The design's \"bulk non-atomic path when the frontier is >= 40% of\n * n\" iterates WORDS of a frontier that is already a bitset; this frontier is a vertex list, so a word-owning store\n * has nothing to iterate and `atomicOr` per vertex is the whole kernel. The sweep appends what it claims as a plain\n * vertex list, exactly as the contract does, and writes no second bitset: the next level's bits come from this\n * kernel running over that list, so one representation of a frontier (a vertex list plus a count) serves the whole\n * phase and the hand-off in either direction is free. The early return keys on a counter and `local_invocation_id`\n * with no barrier after it (spec 3.5 rule 1). Body only (spec 3.5, D9); the text is normative: the sabotage rows of\n * test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bfsBitsetBuildWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn bfs_bitset_build(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let count = select(0u, atomicLoad(&counters[0]), atomicLoad(&counters[24]) == 3u); // frontierCount, on the bottom-up path only (the path word)\n for (var i = linear_id(wid, lid.x); i < count; i = i + P.stride) { // grid-stride; no barrier anywhere\n let v = frontierIn[i];\n atomicOr(&bits[P.bitsBase + (v >> 5u)], 1u << (v & 31u));\n }\n}\n`;\n","/**\n * The `bfs-bottom-up` kernel body (design 8.4 \"the bottom-up sweep\"; P8-T8, the P8 plan's PD-18 / PD-21): one\n * invocation per entry of the unvisited list (`unvisitedListLen`, word 7; the list is the first region of the\n * read-only `sweepIn` buffer, the frontier bitset its second at `P.bitsBase`), over the REVERSE core bound in group 0\n * (`coreOfView(residency.view(s, \"reverse\"))`: the forward arrays on an undirected snapshot, which P7's residency\n * aliases at zero upload cost). A lane whose vertex is still at `INVALID_INDEX` -- the list is up to 32 levels\n * stale, and an entry claimed since the rebuild is skipped on that test -- walks its in-neighbours until the FIRST\n * one whose bit is set and breaks: that early exit is the whole point of the direction (a vertex with one frontier\n * neighbour among thousands costs one read), and `arcsScanned` (word 16, one `atomicAdd` per workgroup of the lanes'\n * reads through `wg_reduce_u32`) is the counter the sabotage row that removes the exit is pinned to, never a timing.\n * The winners are packed into the output vertex queue by `bfs-contract`'s workgroup scan and one `atomicAdd` per\n * workgroup on `nextFrontierCount`, and claim with a plain `atomicStore`: the list holds every vertex once and the\n * sweep is vertex-parallel, so no two lanes claim one vertex. It adds nothing to `frontierDegreeSum` (a bottom-up\n * level expands nothing), which is why that word is not Beamer's m_f: `bfs-next-degree` sums the degree of what\n * this sweep CLAIMS into `nextDegreeSum`, so the boundary's test and its `unvisitedDegreeSum` subtraction are exact\n * on a bottom-up level like any other (issue #391; the selector's JSDoc). Uniformity (spec 3.5 rule 1): the\n * guarded walk writes locals, the scan and the reduction run unconditionally after it. Body only (spec 3.5, D9); the text is normative: the sabotage rows of\n * test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bfsBottomUpWgsl = /* wgsl */ `\nvar<workgroup> sh: array<u32, WG>;\nvar<workgroup> base: u32;\nvar<workgroup> wcount: u32; // the unvisited list's length on a bottom-up level, 0 on any other\n\n@compute @workgroup_size(WG)\nfn bfs_bottom_up(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let claim = atomicLoad(&counters[11]) + 1u;\n if (lid.x == 0u) { wcount = select(0u, atomicLoad(&counters[7]), atomicLoad(&counters[24]) == 3u); } // unvisitedListLen, on the bottom-up path only (the path word)\n let len = workgroupUniformLoad(&wcount); // uniform: the block loop below holds barriers\n for (var b0 = group_id(wid) * WG; b0 < len; b0 = b0 + P.stride) { // grid-stride over blocks of WG entries\n let i = b0 + lid.x;\n var won = 0u;\n var v = 0u;\n var reads = 0u;\n if (i < len) { // guarded work into locals\n v = sweepIn[i];\n if (atomicLoad(&depth[v]) == INVALID_INDEX) { // a stale entry, claimed since the rebuild, is skipped\n let end = min(rowPtr[v + 1u], P.arcEnd);\n for (var a = max(rowPtr[v], P.arcBase); a < end; a = a + 1u) { // in-neighbours through the reverse core\n reads = reads + 1u;\n let u = colIdx[a - P.arcBase];\n if (mask_bit(sweepIn[P.bitsBase + (u >> 5u)], u)) { won = 1u; break; } // the early exit: a real break, never a flag\n }\n }\n }\n sh[lid.x] = won;\n workgroupBarrier();\n for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan of won (bfs-contract's)\n var t = 0u;\n if (lid.x >= s) { t = sh[lid.x - s]; }\n workgroupBarrier();\n sh[lid.x] = sh[lid.x] + t;\n workgroupBarrier();\n }\n let inclusive = sh[lid.x];\n let readsTotal = wg_reduce_u32(reads, lid.x, 0u); // arcsScanned, one atomic per workgroup (the sabotage witness, Step 6)\n if (lid.x == WG - 1u) { base = atomicAdd(&counters[1], inclusive); }\n if (lid.x == 0u) { atomicAdd(&counters[16], readsTotal); }\n workgroupBarrier();\n if (won == 1u) {\n atomicStore(&depth[v], claim); // no claim race: the list holds v once and the sweep is vertex-parallel\n frontierOut[base + inclusive - 1u] = v;\n }\n workgroupBarrier(); // sh and base are reused by the next block\n }\n}\n`;\n","/**\n * The `bfs-contract` kernel body (design 8.4, 8.10 \"BFS contract\"; P8-T6, the P8 plan's PD-5 / PD-6 / PD-24 /\n * DEP-P8-B): the contraction phase of the two-phase top-down level. One invocation per edge-queue entry (the target\n * vertex `advance-expand` wrote), a direct grid-stride dispatch looping to the `edgeCount` `frontier-finalize` role 1\n * clamped, and only when the block's `path` word says the level is two-phase. The claim is `atomicMin(&depth[v], level + 1)` and the invocation that\n * observes `INVALID_INDEX` is the unique winner (PD-6): `atomicMin` is one read-modify-write, so only the first\n * claimant of this level can see the sentinel; a second claimant of the same level observes `claim`, and a vertex\n * already at a smaller depth returns that depth and keeps it. Design 8.4 says why this is not\n * `atomicCompareExchangeWeak`: WGSL 17.8.5 lets it fail spuriously, so a compare-exchange claim needs a retry loop\n * and a bounded loop could leave a vertex unclaimed for its level; `atomicMin` has no such failure mode. The winners\n * are packed by a Hillis-Steele inclusive scan of the workgroup's `won` flags and ONE `atomicAdd` per workgroup on\n * `nextFrontierCount` reserves the block's span in the output vertex queue. The edge queue holds duplicates (a vertex\n * with three frontier neighbours appears three times); exactly one claimant wins, exactly one appends, so the next\n * frontier is duplicate-free by construction and no ownership dedupe follows (DEP-P8-B). Nothing here writes a\n * parent (PD-24: the post-pass does). Uniformity (spec 3.5 rule 1): the guarded work writes locals, every barrier is\n * reached unconditionally. Body only (spec 3.5, D9); the text is normative: the sabotage rows of\n * test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bfsContractWgsl = /* wgsl */ `\nvar<workgroup> sh: array<u32, WG>;\nvar<workgroup> base: u32;\nvar<workgroup> wcount: u32; // the clamped edge count on a two-phase level, 0 on any other\n\n@compute @workgroup_size(WG)\nfn bfs_contract(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x == 0u) { wcount = select(0u, atomicLoad(&counters[8]), atomicLoad(&counters[24]) == 1u); } // edgeCount, clamped by role 1; the two-phase path only (the path word)\n let count = workgroupUniformLoad(&wcount); // uniform: the block loop below holds barriers\n let claim = atomicLoad(&counters[11]) + 1u; // the depth this level assigns\n for (var b0 = group_id(wid) * WG; b0 < count; b0 = b0 + P.stride) { // grid-stride over blocks of WG entries\n let i = b0 + lid.x;\n var won = 0u;\n var v = 0u;\n if (i < count) { // guarded work into locals\n v = edgeQueue[i];\n let old = atomicMin(&depth[v], claim);\n won = select(0u, 1u, old == INVALID_INDEX); // PD-6: the unique winner\n }\n sh[lid.x] = won;\n workgroupBarrier();\n for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan of won\n var t = 0u;\n if (lid.x >= s) { t = sh[lid.x - s]; }\n workgroupBarrier();\n sh[lid.x] = sh[lid.x] + t;\n workgroupBarrier();\n }\n let inclusive = sh[lid.x];\n if (lid.x == WG - 1u) { base = atomicAdd(&counters[1], inclusive); } // nextFrontierCount: one reservation per workgroup\n workgroupBarrier();\n if (won == 1u) { frontierOut[base + inclusive - 1u] = v; }\n workgroupBarrier(); // sh and base are reused by the next block\n }\n}\n`;\n","/**\n * The `bfs-fused` kernel body (design 8.4 \"the fused variant\", 6 row 8 \"the workgroup-per-row tier\", 8.10 \"BFS\n * fused expand-contract\"; P8-T7, the P8 plan's PD-23 / PD-24): the expansion and the contraction of one level in\n * ONE dispatch, chosen by `frontier-finalize` for a frontier below `P.fusedMax` entries (`path` 2) and for the retry\n * of a level whose edge queue overflowed (`path` 4, PD-23). One WORKGROUP per frontier entry, the workgroups striding\n * the entries by the dispatch's group count (`P.stride`): lane 0 reads the entry's row clipped\n * to the bound arc window, adds its degree to `frontierDegreeSum` (so the inspect seam's per-level expansion count\n * covers fused levels too), and every lane strips the row `WG` arcs at a time, applying `bfs-contract`'s claim\n * inline -- `atomicMin(&depth[v], level + 1)`, the invocation that observes `INVALID_INDEX` the unique winner (PD-6) -- and\n * packing the strip's winners into the output vertex queue by the same Hillis-Steele scan and one `atomicAdd` per\n * strip on `nextFrontierCount`. No edge queue is written or read, which is the whole win for a tiny frontier\n * (Merrill's fleeting iterations) and what makes the overflow retry exact: the partial edge queue is never consulted.\n * On a retry level `advance-expand` has already added the frontier's degree to `frontierDegreeSum`, so that word\n * holds twice the level's expanded degree; since issue #391 no decision reads it (Beamer's m_f is `nextDegreeSum`\n * and the boundary subtracts that), so the doubling only reaches the inspect seam's `prevDegreeSum`. Nothing here\n * writes a parent (PD-24: the post-pass does), which is what keeps the kernel at the eight-storage-buffer budget\n * with the four graph slots. Uniformity (spec 3.5 rule 1): the strip loop's bound and the row start are\n * `workgroupUniformLoad`s, so every barrier of the per-strip append is in uniform control flow; the guarded claim\n * writes locals; a trailing barrier protects `sh` and `base` before the next strip reuses them. The claim line and\n * the scan are `bfs-contract`'s verbatim so a reader can diff the two bodies; the scan's comment differs on purpose\n * (the sabotage rows need distinct find strings). Body only (spec 3.5, D9); the text is normative: the sabotage rows\n * of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bfsFusedWgsl = /* wgsl */ `\nvar<workgroup> sh: array<u32, WG>;\nvar<workgroup> wdeg: u32;\nvar<workgroup> wstart: u32;\nvar<workgroup> base: u32;\nvar<workgroup> wcount: u32; // the frontier's length on a fused or retry level, 0 on any other\n\n@compute @workgroup_size(WG)\nfn bfs_fused(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let claim = atomicLoad(&counters[11]) + 1u;\n if (lid.x == 0u) {\n let path = atomicLoad(&counters[24]); // 2 the fused level, 4 the overflow retry (PD-23)\n wcount = select(0u, atomicLoad(&counters[0]), path == 2u || path == 4u);\n }\n let count = workgroupUniformLoad(&wcount); // uniform: the entry loop below holds barriers\n for (var g = group_id(wid); g < count; g = g + P.stride) { // one workgroup per frontier entry; P.stride is the dispatch's GROUP count\n if (lid.x == 0u) {\n let u = frontierIn[g];\n let a0 = max(rowPtr[u], P.arcBase);\n let a1 = min(rowPtr[u + 1u], P.arcEnd);\n let d = select(0u, a1 - a0, a1 > a0);\n wdeg = d;\n wstart = a0;\n atomicAdd(&counters[2], d); // frontierDegreeSum, so the inspect seam sees fused levels too\n }\n let deg = workgroupUniformLoad(&wdeg); // uniform: the loop below may hold barriers\n let start = workgroupUniformLoad(&wstart);\n for (var p0 = 0u; p0 < deg; p0 = p0 + WG) { // strip the row WG arcs at a time\n let p = p0 + lid.x;\n var won = 0u;\n var v = 0u;\n if (p < deg) { // guarded claim into locals\n v = colIdx[start + p - P.arcBase];\n let old = atomicMin(&depth[v], claim);\n won = select(0u, 1u, old == INVALID_INDEX);\n }\n sh[lid.x] = won;\n workgroupBarrier();\n for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan of won (bfs-contract's, verbatim)\n var t = 0u;\n if (lid.x >= s) { t = sh[lid.x - s]; }\n workgroupBarrier();\n sh[lid.x] = sh[lid.x] + t;\n workgroupBarrier();\n }\n let inclusive = sh[lid.x];\n if (lid.x == WG - 1u) { base = atomicAdd(&counters[1], inclusive); }\n workgroupBarrier();\n if (won == 1u) { frontierOut[base + inclusive - 1u] = v; }\n workgroupBarrier(); // sh and base are reused by the next strip\n }\n }\n}\n`;\n","/**\n * The `bfs-next-degree` kernel body (design 8.4; issue #391, the amendment to P8-T8's PD-21): Beamer's m_f measured\n * EXACTLY, at the end of every level, as the out-degree sum of the vertices the level just claimed -- the next\n * frontier, which is what the next boundary decides the direction FOR. It grid-strides over the output vertex\n * queue (`nextFrontierCount`, word 1, the claim kernels' append span; `P.stride` the plan's stride), reads each\n * entry's out-degree from the `outDegree` view, reduces the lane sums with the prelude's `wg_reduce_u32` and lands\n * ONE `atomicAdd` per workgroup in `nextDegreeSum` (word 25), which `frontier-finalize` role 0 reads for the\n * switch-into-bottom-up test, subtracts from `unvisitedDegreeSum` and zeroes for the next level. It runs on every\n * path that claims (the path word 24 non-zero: two-phase, fused, bottom-up, the retry) and does nothing on a level\n * past the end.\n *\n * Why a kernel of its own: before it, the test used `frontierDegreeSum` (word 2), which the EXPANSION of the\n * previous frontier accumulates, so the boundary compared the degree of the frontier it had just finished with the\n * unvisited set, one level stale, and a bottom-up level (which expands nothing) left it at 0. On the 1M / 10M R-MAT\n * that misses the switch at the level that matters: the frontier of 46,524 hubs at level 1 has 13.6M out-arcs, the\n * unvisited set 7.3M, and the boundary saw the source's 86,405 instead -- top-down wrote 13.6M edge-queue entries\n * where the bottom-up sweep reads 0.6M. Measuring the next frontier's degree at claim time is Beamer's own m_f, and\n * the same word makes `unvisitedDegreeSum` exact after a bottom-up level too. Uniformity (spec 3.5 rule 1): the\n * loop holds no barrier (its trip count is per lane), and the reduction runs unconditionally after it. Body only\n * (spec 3.5, D9); the text is normative: the sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bfsNextDegreeWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn bfs_next_degree(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let count = select(0u, atomicLoad(&counters[1]), atomicLoad(&counters[24]) != 0u); // nextFrontierCount, on a level that claimed (the path word)\n var sum = 0u;\n for (var i = linear_id(wid, lid.x); i < count; i = i + P.stride) { // no barrier inside: the trip count is per lane\n sum = sum + outDegree[frontier[i]];\n }\n let total = wg_reduce_u32(sum, lid.x, 0u); // the prelude's workgroup sum; uniform: after the loop\n if (lid.x == 0u) { atomicAdd(&counters[25], total); } // nextDegreeSum: ONE atomic per workgroup\n}\n`;\n","/**\n * The `bfs-unvisited-flags` kernel body (design 8.4; P8-T8, the P8 plan's PD-18): the producer of the unvisited set\n * Beamer's test is against, run ONCE per submit before the levels. It grid-strides over the vertices\n * (`planGridStride(n)`, `P.stride` the plan's stride) and, per lane, counts the vertices still at `INVALID_INDEX`\n * (`unvisitedCount`, word 5), sums their OUT-degrees (`unvisitedDegreeSum`, word 6: Beamer's m_u counts the edges\n * top-down would examine), and flags the unvisited vertices with a non-zero IN-degree (`unvisitedListLen`, word 7:\n * what the bottom-up sweep iterates, since a vertex nobody points at can never be claimed by it); the three lane\n * sums are reduced by the prelude's `wg_reduce_u32` (its sum code) and ONE `atomicAdd` per word per workgroup lands\n * them in the counters block. `compact` over an iota queue then turns `flags` into the unvisited list. The list is\n * up to `MAX_LEVELS_PER_SUBMIT` levels stale by the time the sweep reads it: it holds vertices claimed since the\n * rebuild, which the sweep skips on the `depth == INVALID_INDEX` test it makes anyway, so staleness costs a few\n * wasted reads and never a wrong depth. Between rebuilds `frontier-finalize` maintains words 5 and 6 by subtraction\n * (its JSDoc states the boundary rule). Uniformity (spec 3.5 rule 1): the loop holds no barrier, and the three\n * reductions run unconditionally after it. Body only (spec 3.5, D9); the text is normative: the sabotage rows of\n * test/helpers/sabotage.ts are textual edits of it.\n */\nexport const bfsUnvisitedFlagsWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn bfs_unvisited_flags(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let first = linear_id(wid, lid.x);\n var cnt = 0u;\n var degSum = 0u;\n var len = 0u;\n for (var v = first; v < P.n; v = v + P.stride) { // no barrier inside: the trip count is per lane\n let unv = depth[v] == INVALID_INDEX;\n let listed = unv && (inDegree[v] != 0u);\n flags[v] = select(0u, 1u, listed);\n cnt = cnt + select(0u, 1u, unv);\n degSum = degSum + select(0u, outDegree[v], unv); // the OUT-degree: Beamer's m_u counts the edges top-down would examine\n len = len + select(0u, 1u, listed);\n }\n let c = wg_reduce_u32(cnt, lid.x, 0u); // the prelude's workgroup sum (combine_u's sum code); uniform: after the loop\n let d = wg_reduce_u32(degSum, lid.x, 0u);\n let l = wg_reduce_u32(len, lid.x, 0u);\n if (lid.x == 0u) { // ONE atomic per word per workgroup\n atomicAdd(&counters[5], c);\n atomicAdd(&counters[6], d);\n atomicAdd(&counters[7], l);\n }\n}\n`;\n","/**\n * The `closeness-level` kernel body: one level of the bit-parallel multi-source breadth-first search of closeness, in\n * ONE dispatch, plus the two seed roles of a batch. A batch runs `32 x P.words` sources at once: bit `b` of word `j`\n * of node `v` is source lane `32 j + b`. The `bits` buffer holds five regions of `P.base` words, `P.words` words per\n * node: `visited` at 0, three frontier regions at `P.base`, `2 P.base` and `3 P.base` that rotate by the level\n * (level `L` reads region `1 + L % 3`, writes region `1 + (L + 1) % 3` and zeroes region `1 + (L + 2) % 3`, the\n * frontier of level `L - 1` that nothing reads any more, so no fill runs between levels; a stale bit could never\n * claim anything, since its node's neighbours were claimed the level after, so the clear only keeps a later frontier\n * from re-walking old nodes), then a sampled run's\n * per-node distance sums at `4 P.base`. The `table` buffer holds the per-level claim counts of the submit (row `P.row`\n * at `P.row x 32 P.words`, one word per source lane), then a ring of three control slots of four words at `P.ctrl`\n * (`any` @0: the level claimed something; `arcs` @1: the out-degree of every (node, word) that joined the next\n * frontier; `pull` @2: `arcs` passed `P.pullAt`), then a sampled run's source list at `P.sourcesAt`.\n *\n * Role 0 (one invocation per node and per arc, `max(n, arcs)` in all): a level whose predecessor claimed nothing\n * returns at once (one uniform load per workgroup), so the host can record more levels than the batch needs.\n * Otherwise the level chooses its step from the slot its predecessor filled, the same way for every invocation:\n * - PUSH (the frontier is cheap to expand): one invocation per out-arc `(u, x)` -- `u` found by a binary search of\n * `rowPtr` -- claims the sources at `u` that `x` has not seen with `atomicOr` on `x`'s visited word; the bits it\n * won (`fresh`) join the next frontier;\n * - PULL (the frontier's arcs pass `P.pullAt`, and `P.pullOk`): one invocation per node not yet reached by every\n * source walks its IN-arcs, ORs the neighbours' frontier words, and keeps the bits it had not seen; it stops at\n * the first in-arc after which every source has reached it (the early exit). Only the owner writes a node's\n * words. The host allows the pull only when no node has more than a few thousand in-arcs, so no\n * invocation of either step loops more than a few tens of thousands of times (llvmpipe silently ends every loop\n * of an invocation past 65,535 iterations).\n * Every claimed bit is tallied per source lane in workgroup memory and flushed with one global `atomicAdd` per lane\n * per workgroup into the level's row; the host turns the counts into exact sums (`count x (L + 1)`) and harmonic\n * sums (`count / (L + 1)`). Role 1 (one invocation per word): zeroes the regions, sets every dead lane of a partial\n * batch as already visited (so the early exit and the \"reached by every source\" test see a full word), and zeroes the\n * control ring. Role 2 (one invocation per lane): seeds lane `b`'s source -- `P.source + b`, or word `P.source + b` of\n * the source list -- into `visited` and level 0's frontier with `atomicOr` (a node listed twice carries both bits),\n * and fills the control slot level 0 reads. Body only; the text is normative: the sabotage rows of\n * test/helpers/sabotage.ts are textual edits of it.\n */\nexport const closenessLevelWgsl = /* wgsl */ `\nconst max_words: u32 = 8u;\nvar<workgroup> tally: array<atomic<u32>, 32u * max_words>; // 32 x max_words: this workgroup's claims per source lane\nvar<workgroup> wlive: u32;\nvar<workgroup> wpull: u32;\nvar<workgroup> wany: atomic<u32>;\nvar<workgroup> warcs: atomic<u32>;\nvar<workgroup> wover: atomic<u32>;\n\nfn dead_lanes(j: u32) -> u32 { // the lanes of word j at or past the batch's source count\n let first = 32u * j;\n if (P.count >= first + 32u) { return 0u; }\n if (P.count <= first) { return U32_MAX; }\n return ~((1u << (P.count - first)) - 1u);\n}\n\nfn add_arcs(slot: u32, value: u32) { // the arcs total of a control slot; pull once it passes P.pullAt\n if (value == 0u) { return; }\n let before = atomicAdd(&table[slot + 1u], value);\n if (value > P.pullAt || before + value > P.pullAt || before + value < before) {\n atomicStore(&table[slot + 2u], 1u);\n }\n}\n\nfn record(j: u32, node: u32, fresh: u32, dist: u32) { // the claims of one word: tallied per lane, a sampled run's sums\n if (P.perNode == 1u) { atomicAdd(&bits[4u * P.base + node], countOneBits(fresh) * dist); }\n var b = fresh;\n loop {\n if (b == 0u) { break; }\n atomicAdd(&tally[32u * j + firstTrailingBit(b)], 1u);\n b = b & (b - 1u);\n }\n}\n\n@compute @workgroup_size(WG)\nfn closeness_level(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n let W = P.words;\n if (P.role == 1u) { // seed, part 1: one invocation per word\n if (i == 0u) {\n for (var k = 0u; k < 12u; k = k + 1u) { atomicStore(&table[P.ctrl + k], 0u); }\n }\n if (i < P.total) { atomicStore(&bits[i], select(0u, dead_lanes(i % W), i < P.base)); }\n return; // uniform: P.role is\n }\n if (P.role == 2u) { // seed, part 2: one invocation per source lane\n if (i < P.count) {\n var v = P.source + i;\n if (P.sourcesAt != 0u) { v = atomicLoad(&table[P.sourcesAt + P.source + i]); }\n let w = v * W + i / 32u;\n let bit = 1u << (i % 32u);\n atomicOr(&bits[w], bit); // visited\n let before = atomicOr(&bits[P.base + w], bit); // level 0's frontier (region 1)\n let slot = P.ctrl + 8u; // the slot of \"level -1\", which level 0 reads\n atomicStore(&table[slot], 1u);\n if (before == 0u) { add_arcs(slot, rowPtr[v + 1u] - rowPtr[v]); }\n }\n return;\n }\n\n // role 0: one level\n let L = P.level;\n let prev = P.ctrl + 4u * ((L + 2u) % 3u);\n let cur = P.ctrl + 4u * (L % 3u);\n if (lid.x == 0u) {\n wlive = atomicLoad(&table[prev]);\n wpull = select(0u, atomicLoad(&table[prev + 2u]), P.pullOk == 1u);\n atomicStore(&wany, 0u);\n atomicStore(&warcs, 0u);\n atomicStore(&wover, 0u);\n }\n for (var k = lid.x; k < 32u * W; k = k + WG) { atomicStore(&tally[k], 0u); }\n let live = workgroupUniformLoad(&wlive); // uniform; includes a barrier\n if (live == 0u) { return; } // the previous level claimed nothing\n let pull = workgroupUniformLoad(&wpull) == 1u;\n if (i == 0u) { // the slot of level L + 1 held level L - 2's\n let nxt = P.ctrl + 4u * ((L + 1u) % 3u);\n atomicStore(&table[nxt], 0u);\n atomicStore(&table[nxt + 1u], 0u);\n atomicStore(&table[nxt + 2u], 0u);\n }\n let frontierBase = P.base * (1u + L % 3u);\n let nextBase = P.base * (1u + (L + 1u) % 3u);\n let staleBase = P.base * (1u + (L + 2u) % 3u);\n let dist = L + 1u;\n var arcs = 0u;\n if (i < P.n) {\n for (var j = 0u; j < W; j = j + 1u) { atomicStore(&bits[staleBase + i * W + j], 0u); }\n }\n if (pull) {\n if (i < P.n) { // one invocation per node: its in-arcs\n var vis: array<u32, max_words>;\n var unseen = 0u;\n for (var j = 0u; j < W; j = j + 1u) {\n vis[j] = atomicLoad(&bits[i * W + j]);\n unseen = unseen | ~vis[j];\n }\n if (unseen != 0u) { // some source has not reached this node yet\n var acc: array<u32, max_words>;\n let end = inRowPtr[i + 1u];\n for (var a = inRowPtr[i]; a < end; a = a + 1u) {\n let u = inColIdx[a];\n var missing = 0u;\n for (var j = 0u; j < W; j = j + 1u) {\n acc[j] = acc[j] | atomicLoad(&bits[frontierBase + u * W + j]);\n missing = missing | ~(acc[j] | vis[j]);\n }\n if (missing == 0u) { break; } // every source has reached it: the early exit\n }\n let degree = rowPtr[i + 1u] - rowPtr[i];\n for (var j = 0u; j < W; j = j + 1u) {\n let fresh = acc[j] & ~vis[j];\n if (fresh != 0u) {\n atomicStore(&bits[i * W + j], vis[j] | fresh);\n atomicStore(&bits[nextBase + i * W + j], fresh);\n arcs = arcs + degree;\n record(j, i, fresh, dist);\n }\n }\n }\n }\n } else if (i < P.arcCount) { // one invocation per arc: no row is walked whole\n var lo = 0u; // the arc's source: the last row starting at or before it\n var hi = P.n - 1u;\n loop {\n if (lo >= hi) { break; }\n let mid = (lo + hi + 1u) / 2u;\n if (rowPtr[mid] <= i) { lo = mid; } else { hi = mid - 1u; }\n }\n let u = lo;\n let x = colIdx[i];\n for (var j = 0u; j < W; j = j + 1u) {\n let mask = atomicLoad(&bits[frontierBase + u * W + j]) & ~atomicLoad(&bits[x * W + j]); // at u, not yet at x\n if (mask == 0u) { continue; }\n let fresh = mask & ~atomicOr(&bits[x * W + j], mask); // the claims this invocation won\n if (fresh == 0u) { continue; }\n if (atomicOr(&bits[nextBase + x * W + j], fresh) == 0u) {\n arcs = arcs + (rowPtr[x + 1u] - rowPtr[x]);\n }\n record(j, x, fresh, dist);\n }\n }\n if (arcs > P.pullAt) {\n atomicStore(&wover, 1u);\n } else if (arcs != 0u) {\n let before = atomicAdd(&warcs, arcs);\n if (before + arcs > P.pullAt || before + arcs < before) { atomicStore(&wover, 1u); }\n }\n workgroupBarrier();\n let row = P.row * 32u * W;\n for (var k = lid.x; k < 32u * W; k = k + WG) { // ONE global atomic per source lane per workgroup\n let c = atomicLoad(&tally[k]);\n if (c != 0u) {\n atomicAdd(&table[row + k], c);\n atomicStore(&wany, 1u);\n }\n }\n workgroupBarrier();\n if (lid.x == 0u) {\n if (atomicLoad(&wany) != 0u) { atomicStore(&table[cur], 1u); }\n if (atomicLoad(&wover) != 0u) {\n atomicStore(&table[cur + 2u], 1u);\n } else {\n add_arcs(cur, atomicLoad(&warcs));\n }\n }\n}\n`;\n","/**\n * The `closeness-rowsum` kernel body: closeness from a finished all-pairs distance matrix, one workgroup per row.\n * Every lane walks its strided columns of row `r` (the distances FROM `r`), skips the diagonal and every unreachable\n * entry (`+Infinity`, compared by its bit pattern because WGSL lets a compiler assume no infinities), and adds, by\n * `P.role`: 0 the hop count as an integer (exact: a row of at most 23,170 hops below 23,170 sums below 2^32), 1 the\n * f32 distance, 2 its reciprocal (harmonic closeness; a zero distance adds nothing, as in the CPU port). A tree reduction in workgroup memory folds the lanes and lane\n * 0 writes `out[r]` -- the integer, or the f32 bit pattern. The host turns the row into the score. Body only; the text\n * is normative: the sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const closenessRowsumWgsl = /* wgsl */ `\nvar<workgroup> partial: array<u32, WG>;\n\n@compute @workgroup_size(WG)\nfn closeness_rowsum(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let row = group_id(wid); // uniform: one workgroup per row\n if (row >= P.n) { return; }\n var whole = 0u;\n var real = 0.0;\n for (var c = lid.x; c < P.n; c = c + WG) {\n let d = dist[row * P.n + c];\n if (c == row || bitcast<u32>(d) == F32_INF_BITS) { continue; }\n if (P.role == 0u) {\n whole = whole + u32(d);\n } else if (P.role == 1u) {\n real = real + d;\n } else if (d > 0.0) {\n real = real + 1.0 / d; // a zero distance adds nothing, as on the CPU\n }\n }\n partial[lid.x] = select(whole, bitcast<u32>(real), P.role != 0u);\n for (var s = WG / 2u; s > 0u; s = s / 2u) {\n workgroupBarrier();\n if (lid.x < s) {\n let a = partial[lid.x];\n let b = partial[lid.x + s];\n partial[lid.x] = select(a + b, bitcast<u32>(bitcast<f32>(a) + bitcast<f32>(b)), P.role != 0u);\n }\n }\n if (lid.x == 0u) { out[row] = partial[0]; }\n}\n`;\n","/**\n * The `compact-scatter` kernel body (spec 6 row 4; P8-T3): the scatter step of `compact`, after the caller's flags\n * have been exclusive-scanned into `offsets`. Every flagged entry lands at its offset, in queue order, so the output\n * is bitwise reproducible; lane 0 writes the total -- the last offset plus the last flag -- into `outCount[P.outIndex]`\n * (the block is bound whole and indexed because a four-byte word is never 256-aligned). The planner never dispatches\n * this body for count 0, so `P.count - 1u` never wraps. Body only (spec 3.5, D9); normative text.\n */\nexport const compactScatterWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn compact_scatter(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i == 0u) { outCount[P.outIndex] = offsets[P.count - 1u] + flags[P.count - 1u]; } // the exclusive scan's total; the planner never dispatches for count 0\n if (i >= P.count) { return; } // no barrier follows\n if (flags[i] != 0u) { out[offsets[i]] = queue[i]; }\n}\n`;\n","/**\n * The `coo-emit` kernel body (design 6 row 10, 8.6; the first step of the simple symmetric graph build): position `i`\n * takes arc `a` -- `i` itself, or `order[i]` under INDEXED, which is how a sorted permutation is materialised -- and\n * writes that arc's source, target and weight. Arc `2e` is logical edge `e` as declared and arc `2e + 1` its reverse,\n * so every edge lands in both directions and the result is symmetric whatever the snapshot's directedness. A\n * self-loop is dropped: both of its arcs are written as `INVALID_INDEX`, which sorts after every node index and which\n * `run-flags` never marks. Weights are 1 without WEIGHTED. Body only (spec 3.5, D9); normative text.\n */\nexport const cooEmitWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn coo_emit(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.count) { return; } // no barrier follows\n var a = i;\n if (INDEXED) { a = order[i]; } // the arc this position takes\n let e = a / 2u; // arc 2e is edge e as declared, arc 2e + 1 its reverse\n let forward = (a % 2u) == 0u;\n let u = edgeSrc[e];\n let v = edgeDst[e];\n var w = 1.0;\n if (WEIGHTED) { w = edgeWeight[e]; }\n if (u == v) { // a self-loop is dropped: both arcs sort last and never open a run\n outSrc[i] = INVALID_INDEX;\n outDst[i] = INVALID_INDEX;\n outWeight[i] = 0.0;\n return;\n }\n outSrc[i] = select(v, u, forward);\n outDst[i] = select(u, v, forward);\n outWeight[i] = w;\n}\n`;\n","/**\n * The `coo-scatter` kernel body (design 6 row 10): the last step of `cooToCsr`, after the histogram of the sources\n * and its exclusive scan into `rowPtr`. Two modes under SORTED_INPUT.\n *\n * SORTED_INPUT false is the design's cursor scatter: an arc reserves its slot with `atomicAdd` on its row's cursor\n * (`cursors`, zeroed by the caller), so slots are handed out in race order and a row is NOT sorted by target even when\n * the input was.\n *\n * SORTED_INPUT true takes arcs already ordered by source: arc `i` then sits at its own index minus its row's start\n * inside the row, no cursor and no atomic, so the write is a pure function of the input and the input order survives\n * into every row. The precondition is checked, not trusted: an arc whose source is below its predecessor's raises\n * `cursors[0]`, the word the driver reads back and refuses. Body only (spec 3.5, D9); normative text.\n */\nexport const cooScatterWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn coo_scatter(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.count) { return; } // no barrier follows\n let s = src[i];\n var slot = 0u;\n if (SORTED_INPUT) {\n if (i > 0u && s < src[i - 1u]) { atomicStore(&cursors[0], 1u); } // unsorted input: the flag the driver refuses\n let within = i - rowPtr[s]; // the arc's place in its row\n slot = rowPtr[s] + within;\n } else {\n slot = rowPtr[s] + atomicAdd(&cursors[s], 1u); // race order: the row is not sorted in this mode\n }\n colIdx[slot] = dst[i];\n if (WEIGHTED) { outWeight[slot] = weight[i]; }\n}\n`;\n","/**\n * The `counting-scatter` kernel body (spec 6 row 5; P4-T3): the scatter of a counting sort. `start[k]` is the\n * exclusive scan of the histogram, `cursor[k]` a zeroed per-bin atomic; an element takes the slot `start[k] +\n * atomicAdd(&cursor[k], 1u)`. The order inside a bin depends on the schedule (set-deterministic, design 6). Body\n * only; normative text.\n */\nexport const countingScatterWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn counting_scatter(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.count) { return; } // no barrier follows\n let k = keys[i];\n let slot = atomicAdd(&cursor[k], 1u); // the per-bin cursor (6 row 5)\n outIndex[start[k] + slot] = i;\n}\n`;\n","/**\n * The `dedupe-claim` kernel body (spec 6 row 4; P8-T3): the first of `dedupe`'s two dispatches. Every entry stores\n * its own index into `owner[queue[i]]` (relaxed atomics: between two dispatches last-writer-wins is well defined, so\n * exactly one index per distinct vertex is the owner). The entry count is `P.count`, or the device word\n * `counters[P.countIndex]` clamped to `P.count` when `P.countIndex` is not `U32_MAX` (the SSSP piles only know their\n * count on the device). `owner` needs no reset between calls: a stale or garbage word is only ever read by an entry\n * whose vertex a current entry has just overwritten. Body only (spec 3.5, D9); normative text.\n */\nexport const dedupeClaimWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn dedupe_claim(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n var count = P.count;\n if (P.countIndex != U32_MAX) { count = min(atomicLoad(&counters[P.countIndex]), P.count); } // a device-side count, clamped to the capacity\n for (var i = linear_id(wid, lid.x); i < count; i = i + P.stride) { // grid-stride; no barrier anywhere\n atomicStore(&owner[queue[i]], i);\n }\n}\n`;\n","/**\n * The `dedupe-filter` kernel body (spec 6 row 4; P8-T3): the second of `dedupe`'s two dispatches, a SEPARATE\n * dispatch because a plain store read back in the same one is a data race (WGSL 6.5.7). An entry survives iff\n * `owner[queue[i]]` still holds its own index; the survivors are packed by a Hillis-Steele inclusive scan of the keep\n * bits in workgroup memory (scan-block's rounds and barrier placement, verbatim) and ONE `atomicAdd` per workgroup on\n * `outCount[P.outIndex]` for the block's aggregate, so the output is set-deterministic: the surviving SET is fixed,\n * the order inside `out` follows the schedule. The entry count is `P.count` or the device word\n * `outCount[P.countIndex]` clamped to it -- the same block and the same word `dedupe-claim` read. Every lane reaches\n * every barrier: the guarded work goes into locals (spec 3.5 rule 1). Body only (spec 3.5, D9); normative text.\n */\nexport const dedupeFilterWgsl = /* wgsl */ `\nvar<workgroup> sh: array<u32, WG>;\nvar<workgroup> base: u32;\nvar<workgroup> wcount: u32;\n\n@compute @workgroup_size(WG)\nfn dedupe_filter(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x == 0u) {\n var count = P.count;\n if (P.countIndex != U32_MAX) { count = min(atomicLoad(&outCount[P.countIndex]), P.count); } // the same count source as the claim\n wcount = count;\n }\n let count = workgroupUniformLoad(&wcount); // uniform: the block loop below holds barriers\n for (var b0 = group_id(wid) * WG; b0 < count; b0 = b0 + P.stride) { // grid-stride over blocks of WG entries\n let i = b0 + lid.x;\n var keep = 0u;\n var v = 0u;\n if (i < count) { v = queue[i]; keep = select(0u, 1u, atomicLoad(&owner[v]) == i); } // guarded work into locals\n sh[lid.x] = keep;\n workgroupBarrier(); // every lane, unconditionally (3.5 rule 1)\n for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan of keep\n var t = 0u;\n if (lid.x >= s) { t = sh[lid.x - s]; }\n workgroupBarrier();\n sh[lid.x] = sh[lid.x] + t;\n workgroupBarrier();\n }\n let inclusive = sh[lid.x];\n if (lid.x == WG - 1u) { base = atomicAdd(&outCount[P.outIndex], inclusive); } // ONE atomic per workgroup: the block's aggregate\n workgroupBarrier();\n if (keep == 1u) { out[base + inclusive - 1u] = v; }\n workgroupBarrier(); // sh and base are reused by the next block\n }\n}\n`;\n","/**\n * The `degree` kernel body (contract 4.5; spec 6 row 3, 11.5): the out-degree of every row of `[P.start, P.end)`\n * through the row-walking gather with the USE_PERM dummy pattern, counting the arcs of the bound window whose\n * neighbour index is a valid node; `P.accumulate == 1` adds into `out[i]` instead of overwriting (the P4 windowed\n * loop). Bindings, overrides and the `RangeParams` block come from the registry entry (src/kernels.ts); WG,\n * USE_PERM and `linear_id` from the prelude. The text is normative: test/helpers/sabotage.ts mutates it textually,\n * so it is copied from the contract and never re-derived or restyled.\n */\nexport const degreeWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn degree(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let row = linear_id(wid, lid.x) + P.start;\n if (row >= P.end) { return; }\n let i = select(row, perm[row], USE_PERM);\n let a0 = max(rowPtr[i], P.arcBase);\n let a1 = min(rowPtr[i + 1u], P.arcEnd);\n var d = 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); never use it as an identifier\n d = d + select(0u, 1u, nbr < P.n);\n }\n out[i] = select(d, out[i] + d, P.accumulate == 1u);\n}\n`;\n","/**\n * K2 of the ForceAtlas2 iteration, `fa2-attraction` (spec 7.5; contract 4.5): the gather of the attraction force\n * over the undirected CSR rows (both arcs present, so the sum is symmetric with no atomics), the linear or linlog\n * law, the optional weights, the distributed-action division by the mass in `pos.w`, written as the FIRST writer of\n * `force` each iteration (or combined into it under `P.accumulate`, the windowed pattern of 4.2). The arcs are read\n * inside the bound window [P.arcBase, P.arcEnd). P4-T5 (PD-6, PD-7) gives it the three degree tiers: TIER 0 is one\n * row per thread over `[P.tierStart, P.tierEnd)`; TIER 1 is 32 lanes per row over `[P.hiEnd, P.midEnd)` with a\n * five-step tree in workgroup memory; TIER 2 is one workgroup per row over `[0, P.hiEnd)` through `wg_reduce_vec4`\n * (hence `needs: [\"subgroups\"]`); the row is `perm[row]` under USE_PERM. `LAW` (P5, spec 7.20) picks the pair law:\n * 0 = the FA2 text, 1 = Fruchterman-Reingold `d^2 / k` (unfloored), 2 = ngraph's Hooke spring `k_s (d - L)`; under\n * 1 / 2 the models compile `LINLOG = false` and `HAS_WEIGHTS = false`, and the law overwrites `w` so weights are\n * ignored either way.\n *\n * Body only (spec 3.5, D9); normative text (contract 4.5); the K2 sabotage mutations (P3-T5, P5-T7, P4-T5 / T6) are\n * textual edits of it.\n *\n * TIER 0 folds its row through `row_force_dense`, a stride-one copy of `row_force`, because the shader compiler\n * emits `row_force(i, 0u, 1u)` as a call and leaves the stride in a parameter: the loop then walks the row with a\n * runtime step, which costs the strength-reduced addressing into colIdx / weights and the unrolling that keeps\n * several loads in flight per thread. TIER 0 runs on every load -- alone when no row reaches degree 32, and over\n * the low-degree rows, which are most of them, when the tiers are bound. The two folds spell their locals apart\n * (`arc` / `nbr` / `weight` / `total` against `a` / `j` / `w` / `f`) so that each sabotage row names exactly one\n * of them.\n */\n\n/** The K2 body: entry point `attraction`; the tier bodies are functions called under the uniform `TIER` override, so the barriers of `tiered` are reached in uniform control flow and `tier0`'s early return is legal (spec 3.5 rule 1). */\nexport const fa2AttractionWgsl = /* wgsl */ `fn store_force(i: u32, f: vec3f) {\n force[3u * i] = f.x;\n force[3u * i + 1u] = f.y;\n force[3u * i + 2u] = f.z;\n}\nfn load_force(i: u32) -> vec3f { return vec3f(force[3u * i], force[3u * i + 1u], force[3u * i + 2u]); }\nfn row_node(row: u32) -> u32 { return select(row, perm[row], USE_PERM); }\nfn row_force(i: u32, lane: u32, step: u32) -> vec3f { // the arcs of row i this lane walks inside the bound window [P.arcBase, P.arcEnd) (4.2)\n let pi = pos[i]; // xyz + mass in one load (D23)\n let a0 = max(rowPtr[i], P.arcBase);\n let a1 = min(rowPtr[i + 1u], P.arcEnd);\n var f = vec3f(0.0);\n for (var a = a0 + lane; a < a1; a = a + step) {\n let j = colIdx[a - P.arcBase];\n if (j == i) { continue; } // a self-loop exerts no force\n var w = 1.0;\n if (HAS_WEIGHTS) { w = weights[a - P.arcBase]; }\n let d = pos[j].xyz - pi.xyz; // toward j\n let len = max(length(d), FA2_DIST_FLOOR);\n if (LAW == 1u) { w = length(d) / P.frK; } // LAW 1 (FR, 7.20): |F| = d^2 / k along d / d, unfloored; the linear select below applies w as is\n if (LAW == 2u) { w = P.springCoefficient * (len - P.springLength) / len; } // LAW 2 (spring, ngraph generateCreateSpringForce.js:33-36): Hooke k_s (d - L) toward j\n let mag = select(w, w * log(1.0 + len) / len, LINLOG); // linear: |F| = w len; linlog: |F| = w log(1 + len)\n f = f + d * mag;\n }\n return f;\n}\nfn row_force_dense(i: u32) -> vec3f { // TIER 0's stride-one twin of row_force (see the header)\n let pi = pos[i];\n let lo = max(rowPtr[i], P.arcBase);\n let hi = min(rowPtr[i + 1u], P.arcEnd);\n var total = vec3f(0.0);\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];\n if (nbr == i) { continue; } // a self-loop exerts no force\n var weight = 1.0;\n if (HAS_WEIGHTS) { weight = weights[k]; }\n let d = pos[nbr].xyz - pi.xyz; // toward the neighbour\n let len = max(length(d), FA2_DIST_FLOOR);\n if (LAW == 1u) { weight = length(d) / P.frK; } // LAW 1 (FR, 7.20), as in row_force\n if (LAW == 2u) { weight = P.springCoefficient * (len - P.springLength) / len; } // LAW 2 (spring), as in row_force\n let mag = select(weight, weight * log(1.0 + len) / len, LINLOG);\n total = total + d * mag;\n }\n return total;\n}\nfn finish(i: u32, f0: vec3f) {\n var f = f0;\n if (DISTRIBUTED) { f = f / pos[i].w; }\n if (P.accumulate == 1u) { f = f + load_force(i); } // the windowed loop of 4.2 (arcBase != 0 dispatches after the first)\n store_force(i, f); // overwrites: attraction is the first writer of force each iteration\n}\nfn tier0(wid: vec3<u32>, lane: u32) { // TIER 0: one row per thread over [tierStart, tierEnd); no barrier, so the early return is legal (3.5 rule 1)\n let row = linear_id(wid, lane) + P.tierStart;\n if (row >= P.tierEnd) { return; }\n let i = row_node(row);\n finish(i, row_force_dense(i));\n}\n\nvar<workgroup> sh: array<vec3f, WG>;\n\nfn tiered(wid: vec3<u32>, lid: u32) { // TIER 1: 32 lanes per row over [hiEnd, midEnd); TIER 2: WG lanes per row over [0, hiEnd) (PD-6, PD-7)\n let g = group_id(wid);\n var row = g;\n var end = P.hiEnd;\n var lane = lid;\n var step = WG;\n if (TIER == 1u) { row = P.hiEnd + g * (WG / 32u) + lid / 32u; end = P.midEnd; lane = lid % 32u; step = 32u; }\n let valid = row < end;\n var i = 0u;\n var f = vec3f(0.0);\n if (valid) { i = row_node(row); f = row_force(i, lane, step); }\n if (TIER == 1u) {\n sh[lid] = f;\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 = vec3f(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(i, sh[lid]); }\n }\n if (TIER == 2u) {\n let t = wg_reduce_vec4(vec4f(f, 0.0), lid, 0u);\n if (valid && lid == 0u) { finish(i, t.xyz); }\n }\n}\n\n@compute @workgroup_size(WG)\nfn attraction(@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","/**\n * K5 of the ForceAtlas2 iteration, `fa2-integrate` (spec 7.11; contract 4.5): the per-node speed factor\n * `speed / (1 + sqrt(speed * swing_i))` with the local swing recomputed inline (paper mode `m |F(t) - F(t-1)|`,\n * networkx mode `m |F|`, contract 4.6), the position update with no displacement clamp (D25), z never integrated\n * in 2D (spec 7.13), `oldForce` stored in paper mode for fixed nodes too (spec 7.11), and the partials A\n * (sum p, sum |p - c|^2, min, max with max |p - c|^2 in `max.w`) and C (sum |dp| over free rows, free count) in\n * uniform control flow. `APPLY` (P5, spec 7.20) picks the integrator: 0 = the FA2 text, 1 = the Fruchterman-Reingold\n * temperature cap `min(|F|, t)` along F, 2 = ngraph's semi-implicit Euler step with drag and the unit speed clamp\n * over the velocity that lives in the `oldForce` slot (PD-2), which also folds the free kinetic energy into\n * `partials.swingTraction.x` (PD-4); mode 1 folds the free force energy `sum |F|^2` into the same slot for K1's\n * adaptive cooling and takes its temperature from the state block when `FA2_FLAG_ADAPTIVE` is set. The energy\n * reduction runs under every mode; only its write is conditional.\n *\n * Body only (spec 3.5, D9); normative text (contract 4.5); the K5 sabotage mutations (P3-T5) are textual edits of it.\n */\n\n/** The K5 body: entry point `integrate`; calls the reduction helpers (`needs: [\"subgroups\"]`, contract 4.3). */\nexport const fa2IntegrateWgsl = /* wgsl */ `fn load_force(i: u32) -> vec3f { return vec3f(force[3u * i], force[3u * i + 1u], force[3u * i + 2u]); }\nfn load_old(i: u32) -> vec3f { return vec3f(oldForce[3u * i], oldForce[3u * i + 1u], oldForce[3u * i + 2u]); }\nfn store_old(i: u32, f: vec3f) {\n oldForce[3u * i] = f.x;\n oldForce[3u * i + 1u] = f.y;\n oldForce[3u * i + 2u] = f.z;\n}\n\n@compute @workgroup_size(WG)\nfn integrate(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n var dp = vec3f(0.0);\n var p = vec4f(0.0);\n var free = false;\n var valid = false;\n var ke = 0.0;\n if (i < P.n) {\n valid = true;\n let f = load_force(i);\n p = pos[i];\n var swing_i = p.w * length(f); // SWING_MODE 1: NetworkX's local swinging m |F| (layout.py line 1497)\n if (SWING_MODE == 0u) { swing_i = p.w * length(f - load_old(i)); } // paper: m |F(t) - F(t-1)|, recomputed inline (7.2)\n let factor = S.speed / (1.0 + sqrt(S.speed * swing_i));\n let fixed = mask_bit(fixedMask[i >> 5u], i);\n dp = select(f * factor, vec3f(0.0), fixed); // APPLY 0 (FA2): no clamp on dp (D25)\n if (APPLY == 1u) { // APPLY 1 (FR, 7.20): move along F by min(|F|, t); a fixed node stays\n let mag = length(f);\n let t = select(P.temperature, S.temperature, (P.flags & FA2_FLAG_ADAPTIVE) != 0u); // adaptive cooling: K1's state temperature\n dp = vec3f(0.0);\n if (mag > 0.0 && !fixed) { dp = f * (min(mag, t) / mag); }\n ke = select(0.0, dot(f, f), !fixed); // the force energy of Hu's step control, folded like the spring preset's kinetic energy\n }\n if (APPLY == 2u) { // APPLY 2 (spring-electrical): ngraph's Euler step over the velocity in the oldForce slot (PD-2)\n var v = load_old(i);\n let fd = f - P.dragCoefficient * v; // drag (generateCreateDragForce.js:18)\n v = v + (P.timeStep / p.w) * fd; // v += (dt / m) F (generateIntegrator.js:27-29)\n let sp = length(v);\n if (sp > 1.0) { v = v / sp; } // the unit speed clamp (generateIntegrator.js:33-37)\n if (P.dim == 2u) { v.z = 0.0; }\n dp = select(P.timeStep * v, vec3f(0.0), fixed); // dp = dt v; a pinned body is skipped (generateIntegrator.js:21, 39-41)\n if (!fixed) { store_old(i, v); }\n ke = select(0.0, 0.5 * p.w * dot(v, v), !fixed); // partials B under APPLY 2 (PD-4)\n }\n if (P.dim == 2u) { dp.z = 0.0; } // 2D never integrates z (7.13)\n p = vec4f(p.xyz + dp, p.w);\n pos[i] = p;\n if (SWING_MODE == 0u) { store_old(i, f); } // fixed nodes too, so a later unpin sees no stale swing (7.11)\n free = !fixed;\n }\n // uniform control flow from here (3.5 rule 1): partials A (sum p, sum |p - c|^2, min, max over valid rows) and C (sum |dp|, free count)\n let c = S.centroid.xyz;\n var sumv = vec4f(0.0);\n var lo = vec4f(F32_MAX);\n var hi = vec4f(-F32_MAX);\n var dl = 0.0;\n var fr = 0u;\n if (valid) {\n let q = p.xyz - c;\n sumv = vec4f(p.xyz, dot(q, q));\n lo = vec4f(p.xyz, 0.0);\n hi = vec4f(p.xyz, dot(q, q)); // max.w carries max |p - c|^2 so K1 can write the exact layoutRadius (spec 3.3)\n }\n if (free) { dl = length(dp); fr = 1u; }\n let tSum = wg_reduce_vec4(sumv, lid.x, 0u);\n let tLo = wg_reduce_vec4(lo, lid.x, 1u);\n let tHi = wg_reduce_vec4(hi, lid.x, 2u);\n let tDl = wg_reduce_f32(dl, lid.x, 0u);\n let tFr = wg_reduce_u32(fr, lid.x, 0u);\n let tKe = wg_reduce_f32(ke, lid.x, 0u);\n if (lid.x == 0u) {\n let g = group_id(wid);\n partials[g].sum = tSum;\n partials[g].min = tLo;\n partials[g].max = tHi;\n partials[g].dispFree = vec2f(tDl, f32(tFr));\n if (APPLY != 0u) { partials[g].swingTraction = vec2f(tKe, 0.0); } // overwrites K3's epilogue: K4 never runs under FR or the preset (PD-4)\n }\n}`;\n","/**\n * The `fa2-repulsion-exact` kernel body (K3; contract 4.5; spec 7.6, 7.9, 7.10): the tiled all-pairs repulsion\n * `|F| = k m_i m_j / d` with the 0.01 distance floor and the antisymmetric coincident kick (`LAW` 0; P5's `LAW` 1\n * is Fruchterman-Reingold `k^2 / d` and `LAW` 2 ngraph's Coulomb `-g m_i m_j / d^2`, both unfloored, spec 7.20,\n * with the kick's magnitude taken from the law at d = 0.01, PD-10), the gravity epilogue\n * (GRAVITY_CENTER 0 = centroid, 1 = origin; STRONG_GRAVITY) added under the `valid` guard, `force += f`, and the\n * swing / traction workgroup reduction in uniform control flow (SWING_MODE 0 = paper: free nodes only against\n * `oldForce`; 1 = NetworkX: positions and forces mixed, every node) whose lane 0 writes\n * `partials[group].swingTraction`. `pos` is `array<vec4f>` with the mass in `.w`; `force` / `oldForce` are stride-3\n * `array<f32>` read through the per-body helpers (4.4 rule 6). Normative text, copied verbatim: the P1-T5 sabotage\n * rows (gravity sign, `k / d2`, the `jj != i` guard, the `.w` mass lane) are textual edits of this string.\n * The j range is split into passes of at most EXACT_TILES_PER_PASS tiles (issue #87: llvmpipe's per-invocation loop\n * budget); an earlier pass adds its partial sum into `force`, the last one runs gravity and the epilogue. A graph of\n * at most 32,768 nodes is one pass, bitwise the single-pass kernel. Record it through recordExactRepulsion.\n */\nexport const fa2RepulsionExactWgsl = /* wgsl */ `\nvar<workgroup> tile: array<vec4f, WG>; // xyz + mass, 4 KiB at WG = 256\n\nfn load_force(i: u32) -> vec3f { return vec3f(force[3u * i], force[3u * i + 1u], force[3u * i + 2u]); }\nfn store_force(i: u32, f: vec3f) {\n force[3u * i] = f.x;\n force[3u * i + 1u] = f.y;\n force[3u * i + 2u] = f.z;\n}\nfn load_old(i: u32) -> vec3f { return vec3f(oldForce[3u * i], oldForce[3u * i + 1u], oldForce[3u * i + 2u]); }\nfn kick_magnitude(mi: f32, mj: f32) -> f32 { // the law's magnitude at d = FA2_DIST_FLOOR (PD-10)\n if (LAW == 1u) { return P.frK * P.frK / FA2_DIST_FLOOR; }\n if (LAW == 2u) { return -P.coulomb * mi * mj / FA2_DIST_FLOOR_SQ; }\n return P.scalingRatio * mi * mj / FA2_DIST_FLOOR;\n}\nfn gravity_force(pi: vec4f) -> vec3f { // spec 7.9: centroid (GRAVITY_CENTER 0) or origin (1); regular or strong\n var q = pi.xyz;\n if (GRAVITY_CENTER == 0u) { q = pi.xyz - S.centroid.xyz; }\n if (STRONG_GRAVITY) { return -P.gravity * pi.w * q; }\n let d = length(q);\n if (d > FA2_DIST_FLOOR) { return -P.gravity * pi.w * q / d; }\n return vec3f(0.0);\n}\n\n@compute @workgroup_size(WG)\nfn repulsion(\n @builtin(workgroup_id) wid: vec3<u32>,\n @builtin(local_invocation_id) lid: vec3<u32>,\n @builtin(num_workgroups) nwg: vec3<u32>,\n) {\n // issue #87: pass p of the tile range is dispatched with p + 1 z slices; only the last slice works, so the pass\n // index needs no uniform. Uniform: keyed on workgroup_id and num_workgroups only.\n if (wid.z + 1u < nwg.z) { return; }\n let i = linear_id(wid, lid.x);\n let valid = i < P.n;\n var pi = vec4f(0.0);\n if (valid) { pi = pos[i]; }\n var f = vec3f(0.0);\n let tiles = (P.n + WG - 1u) / WG;\n let tileBegin = (nwg.z - 1u) * EXACT_TILES_PER_PASS;\n let tileEnd = min(tiles, tileBegin + EXACT_TILES_PER_PASS);\n for (var t = tileBegin; t < tileEnd; t = t + 1u) {\n let j = t * WG + lid.x;\n if (j < P.n) { tile[lid.x] = pos[j]; } else { tile[lid.x] = vec4f(0.0); } // guarded fill; mass 0 marks the pad\n workgroupBarrier(); // uniform: every invocation reaches it\n for (var s = 0u; s < WG; s = s + 1u) {\n let o = tile[s];\n let jj = t * WG + s;\n if (o.w > 0.0 && jj != i) { // mass > 0 for every real node, 0 for the pad\n let d = pi.xyz - o.xyz;\n var d2 = dot(d, d);\n if (d2 < FA2_COINCIDENT_SQ) { // coincident: antisymmetric unit kick of the law's magnitude at d = 0.01 (7.2; PD-10)\n f = f + kick_dir(i, jj, P.dim) * kick_magnitude(pi.w, o.w);\n continue;\n }\n if (LAW == 0u) { d2 = max(d2, FA2_DIST_FLOOR_SQ); } // FA2 alone floors d >= 0.01 (7.2); FR and coulomb are unfloored (7.20)\n let k = P.scalingRatio * pi.w * o.w;\n if (LAW == 0u) { f = f + d * (k / d2); } // LAW 0 (FA2): |F| = k m_i m_j / d along d / d\n if (LAW == 1u) { f = f + d * (P.frK * P.frK / d2); } // LAW 1 (FR, 7.20): |F| = k^2 / d, mass ignored\n if (LAW == 2u) { f = f + d * (-P.coulomb * pi.w * o.w / (d2 * sqrt(d2))); } // LAW 2 (coulomb, ngraph generateQuadTree.js:131-132): |F| = -g m_i m_j / d^2\n }\n }\n workgroupBarrier();\n }\n if (tileEnd < tiles) { // an earlier pass: its partial sum only (uniform: P.n, nwg)\n if (valid) { store_force(i, load_force(i) + f); }\n return;\n }\n // epilogue (7.9, 7.10): gravity and force += under the guard, the swing / traction reduction outside it\n var sw = 0.0;\n var tr = 0.0;\n if (valid) {\n f = f + gravity_force(pi);\n let fnew = load_force(i) + f;\n store_force(i, fnew);\n if (SWING_MODE == 1u) { // NetworkX: positions and forces mixed, every node (7.2)\n sw = pi.w * length(pi.xyz - fnew);\n tr = 0.5 * pi.w * length(pi.xyz + fnew);\n } else if (!mask_bit(fixedMask[i >> 5u], i)) { // paper: free nodes only (Gephi ForceAtlas2.java 283-293)\n let fold = load_old(i);\n sw = pi.w * length(fnew - fold);\n tr = 0.5 * pi.w * length(fnew + fold);\n }\n }\n let t = wg_reduce_vec4(vec4f(sw, tr, 0.0, 0.0), lid.x, 0u); // uniform control flow: 256 -> 1\n if (lid.x == 0u) { partials[group_id(wid)].swingTraction = t.xy; }\n}\n`;\n","/**\n * The `fa2-speed-finalize` kernel body (K4; contract 4.5; spec 7.10): ONE workgroup sums `partials[*].swingTraction`\n * sequentially per lane (deterministic), reduces in uniform control flow, then lane 0 runs the line-for-line port\n * of the CPU `estimateFactor` (SWING_MODE 1 accumulates NetworkX's sums across iterations from S.swing / S.traction)\n * and writes `S.speed`, `S.speedEfficiency`, `S.swing`, `S.traction` and the four controller fields of\n * `T[P.iterationIndex]`. `target` is a WGSL reserved word, hence `targetSpeed`. Normative text, copied verbatim:\n * the P1-T5 sabotage rows (`* 0.5` -> `* 0.9`, the 1.3 rise, the swing / traction swap) are textual edits of it.\n * The halving predicate is `swing > 2.0 * tr`, the exact form of the port's `swing / traction > 2` (contract 4.5\n * CONTRACT DECISION K4-1, G3 finding G3-F6): every paper-mode first iteration after load() has oldForce = 0, so\n * traction is EXACTLY half the swing and the predicate sits on its knife edge; a multiplication by 2 and the\n * comparison are exact on every device, while WGSL grants f32 division 2.5 ULP and Dawn on NVIDIA returns 2 + 1 ulp\n * for 2.2% of the inputs x / (x / 2) (tmp/p3-fix/div-probe.mjs), which took the branch the CPU reference never takes.\n */\nexport const fa2SpeedFinalizeWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn speed_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n let groups = (P.n + WG - 1u) / WG;\n var st = vec2f(0.0);\n for (var g = lid.x; g < groups; g = g + WG) { st = st + partials[g].swingTraction; } // sequential per lane: deterministic\n let t = wg_reduce_vec4(vec4f(st, 0.0, 0.0), lid.x, 0u);\n if (lid.x == 0u) {\n var swing = t.x;\n var traction = t.y;\n if (SWING_MODE == 1u) { swing = S.swing + t.x; traction = S.traction + t.y; } // NetworkX accumulates across iterations from 1\n let n = f32(P.n);\n let optJitter = 0.05 * sqrt(n);\n let minJitter = sqrt(optJitter);\n let maxJitter = 10.0;\n let tr = max(traction, 1.0e-30); // guards the division only (7.10)\n let other = min(maxJitter, optJitter * traction / (n * n));\n var jitter = P.jitterTolerance * max(minJitter, other);\n var eff = S.speedEfficiency;\n if (swing > 2.0 * tr) { // swing / traction > 2 in the exact form (contract 4.5 CONTRACT DECISION K4-1: 2 x is exact, a WGSL f32 division is not)\n if (eff > 0.05) { eff = eff * 0.5; } // the CPU's conditional multiply (7.2)\n jitter = max(jitter, P.jitterTolerance);\n }\n let targetSpeed = select(jitter * eff * traction / swing, 1.0e30, swing == 0.0); // +Inf in the port; 1e30 gives the same min() below (\\`target\\` is reserved)\n if (swing > jitter * traction) {\n if (eff > 0.05) { eff = eff * 0.7; }\n } else if (S.speed < 1000.0) {\n eff = eff * 1.3;\n }\n S.speed = S.speed + min(targetSpeed - S.speed, 0.5 * S.speed);\n S.speedEfficiency = eff;\n S.swing = swing;\n S.traction = traction;\n T[P.iterationIndex].swing = swing;\n T[P.iterationIndex].traction = traction;\n T[P.iterationIndex].speed = S.speed;\n T[P.iterationIndex].speedEfficiency = eff;\n }\n}\n`;\n","/**\n * K1 of the ForceAtlas2 iteration, `fa2-stats-finalize` (spec 7.4; contract 4.5): one workgroup folds the partials\n * the previous integrate (K5) wrote into the state block -- centroid, RMS radius, layout radius (max |p - c|, the\n * exact spec 3.3 value from `partials.max.w`), bounding box, mean displacement over free nodes (0 when every node\n * is fixed), the settle counter -- increments the iteration counter and writes the K1 half of the trace record.\n * On the first iteration after load() (`FA2_FLAG_FIRST`) it folds nothing and keeps the host-written state.\n * `STATS_MODE` (P5, spec 7.20) adds the model statistic: 0 = the FA2 text, 1 = the Fruchterman-Reingold temperature\n * of this iteration into `S.temperature` and the trace's `modelScalar` -- the uniform's under the linear schedule,\n * or, with `FA2_FLAG_ADAPTIVE` set, the adaptive one: the previous iteration's force energy (K5 folds sum |F|^2 over\n * free nodes into `partials.swingTraction.x`) against `S.frEnergy` grows the temperature by 1 / FR_COOLING_STEP after\n * FR_COOLING_PATIENCE consecutive falls and shrinks it by FR_COOLING_STEP on a rise (Yifan Hu 2005, section 3.2);\n * 2 = the spring-electrical kinetic energy K5 folded into `partials.swingTraction.x` (PD-4) into `S.kineticEnergy`\n * and the trace. On the grid tier (`P.gridMax > 0`, P4-T10, PD-14) it also derives the grid frame of the next build\n * from the fold (`extent = max(min(bboxExtent * GRID_BBOX_MARGIN, extentFactor * rmsRadius), GRID_EXTENT_FLOOR)`,\n * `cellSize = extent / G`, `gridMin = centroid - extent / 2` with `cellSize` in `.w`, `invCellSize`, `eps = 0.25\n * cellSize`), copies the previous iteration's pseudo-cell count and occupancy max into the state, and resets the\n * hub counters; the exact tier writes `gridMax: 0` and binds two dummies, so the block is dead there.\n *\n * This file holds the kernel BODY only (spec 3.5, D9): no bind-group lines and no `override` lines -- the composer\n * emits them from the registry entry in src/kernels.ts (contract 3.10.1). The text is normative (contract 4.5) and\n * is the target of the K1 sabotage mutations (test/helpers/sabotage.ts, P3-T5); amend the contract before editing.\n */\n\n/** The K1 body: entry point `stats_finalize`; calls the reduction helpers (`needs: [\"subgroups\"]`, contract 4.3). */\nexport const fa2StatsFinalizeWgsl = /* wgsl */ `// K1: folds the previous integrate's partials into the state block (spec 7.4); one workgroup\n@compute @workgroup_size(WG)\nfn stats_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n let groups = (P.n + WG - 1u) / WG;\n let fold = (P.flags & FA2_FLAG_FIRST) == 0u; // the first iteration after load() keeps the host-written state\n var sum = vec4f(0.0);\n var lo = vec4f(F32_MAX);\n var hi = vec4f(-F32_MAX);\n var disp = 0.0;\n var free = 0u;\n var ke = 0.0;\n if (fold) {\n for (var g = lid.x; g < groups; g = g + WG) { // sequential per lane in index order: deterministic\n let q = partials[g];\n sum = sum + q.sum;\n lo = min(lo, q.min);\n hi = max(hi, q.max);\n disp = disp + q.dispFree.x;\n free = free + u32(q.dispFree.y);\n ke = ke + q.swingTraction.x;\n }\n }\n let tSum = wg_reduce_vec4(sum, lid.x, 0u);\n let tLo = wg_reduce_vec4(lo, lid.x, 1u);\n let tHi = wg_reduce_vec4(hi, lid.x, 2u);\n let tDisp = wg_reduce_f32(disp, lid.x, 0u);\n let tFree = wg_reduce_u32(free, lid.x, 0u);\n let tKe = wg_reduce_f32(ke, lid.x, 0u);\n if (lid.x == 0u) {\n if (fold) {\n let n = f32(P.n);\n let c = tSum.xyz / n;\n S.centroid = vec4f(c, 0.0);\n S.rmsRadius = sqrt(max(tSum.w, 0.0) / n); // RMS radius about the previous centroid (7.17)\n S.min = vec4f(tLo.xyz, 0.0);\n S.max = vec4f(tHi.xyz, 0.0);\n S.radius = sqrt(max(tHi.w, 0.0)); // max |p - centroid| about the same previous centroid as rmsRadius (K5 puts |q|^2 in max.w)\n let meanDisp = select(tDisp / f32(tFree), 0.0, tFree == 0u); // all-fixed: 0, never NaN (7.4)\n S.meanDisplacement = meanDisp;\n S.settledCount = select(0u, S.settledCount + 1u, meanDisp <= min(P.settleThreshold * S.rmsRadius, P.settleFloor)); // relative AND absolute (issue #97)\n }\n S.iteration = S.iteration + 1u;\n T[P.iterationIndex].meanDisplacement = S.meanDisplacement;\n T[P.iterationIndex].settledCount = S.settledCount;\n T[P.iterationIndex].iteration = S.iteration;\n if (P.gridMax > 0u) { // the grid tier (7.7): the robust extent, the cell size, eps, last iteration's counts, the hub counter reset (PD-14)\n let cells = P.gridMax * P.gridMax * select(1u, P.gridMax, P.dim == 3u);\n if (fold) {\n let box = (S.max.xyz - S.min.xyz) * GRID_BBOX_MARGIN;\n var bboxExtent = max(box.x, box.y);\n if (P.dim == 3u) { bboxExtent = max(bboxExtent, box.z); }\n let extent = max(min(bboxExtent, P.extentFactor * S.rmsRadius), GRID_EXTENT_FLOOR); // min(bbox, extentFactor x rms), floored (7.7)\n let cellSize = extent / f32(P.gridMax);\n S.gridMin = vec4f(S.centroid.xyz - vec3f(0.5 * extent), cellSize); // gridMin.w carries cellSize\n S.invCellSize = 1.0 / cellSize;\n S.eps = 0.25 * cellSize;\n }\n var outside = 0u; // the previous iteration's pseudo-cell counts, one per orthant (issue #90; 0 after load)\n for (var o = 0u; o < select(4u, 8u, P.dim == 3u); o = o + 1u) { outside = outside + cellHist[cells + o]; }\n S.outsideGrid = outside;\n S.maxCellOccupancy = atomicLoad(&hubCounters[1]);\n atomicStore(&hubCounters[0], 0u);\n atomicStore(&hubCounters[1], 0u);\n }\n if (STATS_MODE == 1u) { // FR: this iteration's temperature (7.20) into the state and the trace\n if ((P.flags & FA2_FLAG_ADAPTIVE) != 0u) { // adaptive cooling (Yifan Hu 2005 3.2): tKe is the previous iteration's sum |F|^2 over free nodes\n if (fold) {\n var t = S.temperature;\n if (tKe < S.frEnergy) {\n S.frProgress = S.frProgress + 1u;\n if (S.frProgress >= FR_COOLING_PATIENCE) { S.frProgress = 0u; t = t / FR_COOLING_STEP; }\n } else {\n S.frProgress = 0u;\n t = t * FR_COOLING_STEP;\n }\n S.frEnergy = tKe;\n S.temperature = t;\n }\n } else {\n S.temperature = P.temperature;\n }\n T[P.iterationIndex].modelScalar = S.temperature;\n }\n if (STATS_MODE == 2u) { // spring-electrical: the kinetic energy K5 folded into partials B (PD-4); 0 on the first iteration after load()\n S.kineticEnergy = tKe;\n T[P.iterationIndex].modelScalar = tKe;\n }\n }\n}`;\n","/**\n * The per-batch `fa2-to-scene` kernel (spec 7.13, 7.18; contract 4.5): unpacks the vec4f layout-unit positions into\n * the stride-3 scene array the staging copy reads back, applying `scale` and `center`; in 2D the third component is\n * `center.z` on every readback whatever z the device holds.\n *\n * Body only (spec 3.5, D9); normative text (contract 4.5); exempt from the sabotage matrix (SABOTAGE_EXEMPT: a wrong\n * toScene fails the exact-equality position tests directly).\n */\n\n/** The toScene body: entry point `to_scene`; an early return is legal here because no barrier follows (spec 3.5 rule 1). */\nexport const fa2ToSceneWgsl = /* wgsl */ `@compute @workgroup_size(WG)\nfn to_scene(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.n) { return; }\n let s = pos[i].xyz * P.scale + P.center.xyz;\n scene[3u * i] = s.x;\n scene[3u * i + 1u] = s.y;\n scene[3u * i + 2u] = select(s.z, P.center.z, P.dim == 2u); // 2D writes z = center.z on every readback (7.13)\n}`;\n","/**\n * The `fill` kernel body (contract 4.5): `dst[i] = P.value` (mode 0) or `i + P.value` (mode 1, iota) for every\n * `i < P.count`, `i` from the prelude's `linear_id` so a 2D dispatch covers counts above MAX_1D_ITEMS. The 17M-item\n * linear_id test of spec 5.2 / 11.5 is mode 1 over 16,776,961 words. Normative text, copied verbatim.\n */\nexport const fillWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn fill(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.count) { return; }\n dst[i] = select(P.value, i + P.value, P.mode == 1u);\n}\n`;\n","/**\n * The `frontier-finalize` kernel body (design 5.4, 6 row 7; P8-T4, the P8 plan's PD-3 / PD-23 / DEP-P8-C): the\n * device-side selector of the frontier family. One workgroup, one lane, no barrier after the early return (spec 3.5\n * rule 1). It is recorded TWICE per level, in two roles chosen by `P.role`, because a level's counts become known at\n * two moments: role 0 runs at the START of a level -- rotates `nextFrontierCount` into `frontierCount`, advances\n * `level`, decides `done` (an empty frontier, or `level >= P.maxDepth`) and chooses the path; role 1 runs once the\n * edge queue is filled -- clamps `edgeCount` to `P.edgeCapacity`, or, when `edgeCountUnclamped` exceeds the\n * capacity, switches the path to the fused retry over `frontierCount` (PD-23). The decision is ONE word of the\n * counters block, `path` (word 24): 0 nothing (done, or a level past the end), 1 two-phase, 2 fused, 3 bottom-up,\n * 4 the fused retry (role 1), 5 a near SSSP round, 6 a far one (role 2). Every level kernel is a direct grid-stride\n * dispatch that reads that word first and runs only when it names it (decision record\n * design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md: Dawn's validation of an indirect dispatch cost\n * about 0.4 ms of device time each, and the seven indirect slots this kernel once wrote per level were 97 % of a\n * traversal's wall time; the slots and their args buffer are gone). Two rules: a boundary that finds `done` set\n * moves no counter word (the host records levels past the end); role 1 counts a two-phase level only when role 0\n * chose one, which it reads from the path word (a storage write of one dispatch is visible to the next of the same\n * pass).\n *\n * Roles 2 and 3 are the SSSP round boundary of the near-far loop (P8-T9, PD-20), over the same block read in its\n * SSSP sense (word 1 the raw near half's appends, 21 the raw far half's, 0 and 20 the deduped pile counts, 22 the\n * threshold, 23 the delta, 4 the previous threshold, 14 the round's mode): role 2 finds a non-empty raw near half\n * and sizes the near dedupe (count word 1, output word 0; the dedupe's count in word 8) in mode 0; finds it empty\n * and the far half not, raises the threshold by the delta (one f32 add; an add that returns the threshold\n * unchanged sets `done 3`, the host's E_UNSUPPORTED), remembers the previous threshold in word 4 and sizes the far\n * dedupe (count word 21, output word 20; the dedupe's count in word 9) in mode 1; finds both empty and sets\n * `done 1`; and finds a raw half above the capacity and sets `done 2` (the host's E_TOO_LARGE). It counts a round in\n * `level` when it picks a mode and NOT at the done boundary, so `level` at the end is the number of relax rounds\n * dispatched; a boundary that finds `done` set obeys rule 1. Role 3 runs once the dedupe has landed and restarts the\n * raw half the round consumed: mode 0 restarts the raw near half (word 1 to 0), mode 1 the raw far half (word 21\n * to 0); the relax kernels size themselves from words 0 and 20.\n *\n * Beamer's test (P8-T8, PD-21; amended for issue #391), evaluated at every boundary BEFORE the `done` branch (so a\n * switch can be counted at the done boundary too, which the host model of the tests mirrors): top-down switches to\n * bottom-up when `nextDegreeSum > unvisitedDegreeSum / alpha` (u32 division; alpha the host's\n * `max(1, floor(arcCount / n))` unless tuned) and the frontier is growing (`next > frontierCount`); bottom-up\n * switches back when `next * beta < unvisitedCount` (a u32 product, wrapping only above 178M vertices, which no\n * admitted device reaches) and the frontier is shrinking; `P.mode == 1` (the driver's `\"top-down\"`) pins the\n * direction at 0. Every change is counted in `switches`, the previous direction is word 14. `nextDegreeSum` (word\n * 25) is Beamer's m_f measured EXACTLY: `bfs-next-degree` sums the out-degrees of the vertices a level claims at\n * the end of that level, so the boundary that rotates them in as `next` compares the degree of the frontier it is\n * about to expand -- not, as before the amendment, `frontierDegreeSum` (word 2), the degree of the frontier the\n * previous level EXPANDED, one level stale and 0 after a bottom-up level, which on the 1M / 10M R-MAT missed the\n * switch at the level holding 13.6M of the 21M arcs. Word 2 is still accumulated by the expansion and rotated into\n * word 4 for the inspect seam. The two unvisited words are rebuilt exactly once per submit by `bfs-unvisited-flags`\n * (PD-18) and maintained here by subtraction from the SECOND boundary of a submit on, because a boundary may only\n * subtract what the submit's rebuild counted: the rebuild counts the vertices unclaimed when it runs, the frontier\n * rotated in at boundary 0 was claimed by the previous submit's last level, so it was never in the sums, and\n * boundary b subtracts `next = |F_b|` and `nextDegreeSum = deg(F_b)`, both inside the sums iff b >= 1. Both words\n * are therefore exact at every boundary, bottom-up levels included (the sweep's claims are summed like any other).\n * Body only (spec 3.5, D9); the text is normative: the sabotage rows of test/helpers/sabotage.ts are textual edits\n * of it.\n */\nexport const frontierFinalizeWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn frontier_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x != 0u) { return; } // one lane; no barrier follows (3.5 rule 1)\n if (P.role == 0u) { // the level boundary\n if (atomicLoad(&counters[15]) != 0u) { // done already: a no-op level the host recorded past the end\n atomicStore(&counters[24], 0u); // the path word is the only word that moves (P8-T6's levels formula reads the rest)\n return;\n }\n let finished = atomicLoad(&counters[0]);\n let next = atomicLoad(&counters[1]);\n let degSum = atomicLoad(&counters[2]);\n let nextDeg = atomicLoad(&counters[25]); // deg(F_b), summed by bfs-next-degree when F_b was claimed (issue #391)\n atomicStore(&counters[3], finished); // prevFrontierCount\n atomicStore(&counters[4], degSum); // prevDegreeSum\n atomicStore(&counters[0], next); // the rotation\n atomicStore(&counters[1], 0u);\n atomicStore(&counters[2], 0u);\n atomicStore(&counters[25], 0u); // the next level's claims sum from 0\n atomicStore(&counters[8], 0u); // edgeCount\n atomicStore(&counters[9], 0u); // edgeCountUnclamped\n atomicStore(&counters[12], atomicLoad(&counters[12]) + next); // visitedCount\n if (P.firstOfSubmit >= 1u) { // b = the boundary's index inside its submit, clamped (P8-T8, PD-18): F_b was inside the submit's rebuilt sums iff b >= 1\n atomicStore(&counters[5], atomicLoad(&counters[5]) - next); // unvisitedCount, exact\n atomicStore(&counters[6], atomicLoad(&counters[6]) - nextDeg); // unvisitedDegreeSum, exact (issue #391: no longer one level stale)\n }\n let level = atomicLoad(&counters[11]) + 1u; // the seed is U32_MAX, so the first boundary lands on 0\n atomicStore(&counters[11], level);\n let done = (next == 0u) || (level >= P.maxDepth);\n atomicStore(&counters[15], select(0u, 1u, done));\n var direction = atomicLoad(&counters[14]);\n if (P.mode == 1u) {\n direction = 0u; // top-down only (the test seam)\n } else if (direction == 0u) {\n if (nextDeg > atomicLoad(&counters[6]) / P.alpha && next > finished) { direction = 1u; } // m_f > m_u / alpha and growing, m_f the degree of the frontier about to be expanded\n } else {\n if (next * P.beta < atomicLoad(&counters[5]) && next < finished) { direction = 0u; } // next * beta < unvisited and shrinking\n }\n if (direction != atomicLoad(&counters[14])) { atomicStore(&counters[13], atomicLoad(&counters[13]) + 1u); } // switches\n var path = 0u; // word 24: what the level's kernels run (0 nothing, 1 two-phase, 2 fused, 3 bottom-up; role 1 writes 4 for the retry)\n if (done) {\n path = 0u;\n } else if (direction == 1u) { // the bottom-up level (P8-T8): the bits fill, the bitset build, the sweep\n path = 3u;\n atomicStore(&counters[19], atomicLoad(&counters[19]) + 1u);\n } else if (next < P.fusedMax) { // P8-T7 makes this branch reachable (fusedMax is 0 until then)\n path = 2u; // bfs-fused: one WORKGROUP per frontier entry\n atomicStore(&counters[17], atomicLoad(&counters[17]) + 1u);\n } else {\n path = 1u; // advance-expand, then role 1 and bfs-contract\n }\n atomicStore(&counters[14], direction);\n atomicStore(&counters[24], path);\n } else if (P.role == 1u) { // the edge queue is filled\n if (atomicLoad(&counters[24]) != 1u) { // role 0 did not choose the two-phase path (done, fused or bottom-up): nothing to clamp, nothing to count\n return;\n }\n let clamped = min(atomicLoad(&counters[8]), P.edgeCapacity);\n atomicStore(&counters[8], clamped);\n if (atomicLoad(&counters[9]) > P.edgeCapacity) { // PD-23: the fused retry\n atomicStore(&counters[24], 4u); // the path word: bfs-fused runs the retry over frontierCount, bfs-contract nothing\n atomicStore(&counters[10], atomicLoad(&counters[10]) + 1u);\n atomicStore(&counters[17], atomicLoad(&counters[17]) + 1u);\n } else {\n atomicStore(&counters[18], atomicLoad(&counters[18]) + 1u); // twoPhaseLevels counts the CHOICE role 0 made, even for zero edges (P8-T7 Step 4's invariant)\n }\n } else if (P.role == 2u) { // the SSSP round boundary (P8-T9, PD-20): which pile this round relaxes\n atomicStore(&counters[8], 0u); // the dedupe counts (words 8 and 9, the SSSP sense) and the path word: nothing unless a pile is chosen below\n atomicStore(&counters[9], 0u);\n atomicStore(&counters[24], 0u);\n if (atomicLoad(&counters[15]) != 0u) { // done already: a no-op round the host recorded past the end (rule 1)\n return;\n }\n let nearRaw = atomicLoad(&counters[1]); // the raw near half's appends, unclamped\n let farRaw = atomicLoad(&counters[21]); // the raw far half's appends, unclamped\n if (nearRaw > P.edgeCapacity || farRaw > P.edgeCapacity) { // a pile overflowed its half: the host raises E_TOO_LARGE\n atomicStore(&counters[15], 2u);\n return;\n }\n if (nearRaw != 0u) { // a near round: dedupe the near half into nearIn\n atomicStore(&counters[0], 0u); // the deduped near count, accumulated by dedupe-filter\n atomicStore(&counters[14], 0u); // mode 0\n atomicStore(&counters[8], nearRaw); // the near dedupe's count word (dedupe-claim, dedupe-filter over the near half)\n atomicStore(&counters[24], 5u); // the path word: sssp-relax role 0 runs, role 1 nothing\n atomicStore(&counters[11], atomicLoad(&counters[11]) + 1u); // rounds dispatched (the done boundary is not counted)\n } else if (farRaw != 0u) { // the near pile is empty: raise the threshold and re-bucket the far pile\n let threshold = bitcast<f32>(atomicLoad(&counters[22]));\n let raised = threshold + bitcast<f32>(atomicLoad(&counters[23])); // ONE f32 add on the bit patterns (PD-9)\n if (raised == threshold) { // the delta is below the threshold's ulp: the host raises E_UNSUPPORTED\n atomicStore(&counters[15], 3u);\n return;\n }\n atomicStore(&counters[4], atomicLoad(&counters[22])); // prevThresholdBits: what the pass-through drops below\n atomicStore(&counters[22], bitcast<u32>(raised));\n atomicStore(&counters[20], 0u); // the deduped far count, accumulated by dedupe-filter\n atomicStore(&counters[14], 1u); // mode 1\n atomicStore(&counters[9], farRaw); // the far dedupe's count word (dedupe-claim, dedupe-filter over the far half)\n atomicStore(&counters[24], 6u); // the path word: sssp-relax role 1 runs, role 0 nothing\n atomicStore(&counters[11], atomicLoad(&counters[11]) + 1u);\n } else { // both piles empty: finished\n atomicStore(&counters[15], 1u);\n }\n } else if (P.role == 3u) { // the piles are deduped: restart the raw half the round consumed\n if (atomicLoad(&counters[15]) != 0u) { return; } // role 2 chose no pile this round\n if (atomicLoad(&counters[14]) == 0u) {\n atomicStore(&counters[1], 0u); // the raw near half restarts (sssp-relax role 0 sizes itself from word 0)\n } else {\n atomicStore(&counters[21], 0u); // the raw far half restarts (the pass-through re-appends what stays far; role 1 sizes itself from word 20)\n }\n }\n}\n`;\n","/**\n * G1, the `grid-cell-key` kernel body (spec 7.7; P4-T8): the finest cell of every node from the state's robust extent,\n * `floor((p - gridMin) * invCellSize)` (a multiply, correctly rounded everywhere: PD-10), linearised when every axis\n * is in [0, G), and otherwise one of the 2^dim outside pseudo-cells `cells + orthant`, the orthant of the cell about the\n * grid centre (bit a set when `c[a] >= G / 2`; issue #90); `cellVal[i] = i`. The clamp before the floor keeps a\n * far-away or NaN coordinate out of an out-of-range float-to-int conversion. Body only; normative text.\n */\nexport const gridCellKeyWgsl = /* wgsl */ `\nfn grid_cells() -> u32 { return P.gridMax * P.gridMax * select(1u, P.gridMax, P.dim == 3u); }\n\n@compute @workgroup_size(WG)\nfn grid_cell_key(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.n) { return; } // no barrier follows\n let cells = grid_cells();\n let gf = f32(P.gridMax);\n let q = (pos[i].xyz - S.gridMin.xyz) * S.invCellSize; // PD-10: never a division\n let c = vec3<i32>(floor(clamp(q, vec3f(-1.0), vec3f(gf + 1.0))));\n let g = i32(P.gridMax);\n var inside = c.x >= 0 && c.x < g && c.y >= 0 && c.y < g;\n if (P.dim == 3u) { inside = inside && c.z >= 0 && c.z < g; }\n var key = cells + select(0u, 1u, c.x >= g / 2) + select(0u, 2u, c.y >= g / 2); // an outside pseudo-cell: its orthant (issue #90)\n if (P.dim == 3u) { key = key + select(0u, 4u, c.z >= g / 2); }\n if (inside) {\n key = u32(c.x) + P.gridMax * u32(c.y);\n if (P.dim == 3u) { key = key + P.gridMax * P.gridMax * u32(c.z); }\n }\n cellKey[i] = key;\n cellVal[i] = i;\n}\n`;\n","/**\n * G4, the `grid-centroid` kernel body (spec 7.7; P4-T9): thread per finest cell, the 2^dim outside pseudo-cells\n * included (issue #90); the\n * mass-weighted position sum of a cell's sorted range in index order (no atomics: deterministic), the largest\n * occupancy into hubCounters[1], and cells above GRID_HUB_CELL entries appended to hubList for G4b (PD-13). Body\n * only; normative text.\n */\nexport const gridCentroidWgsl = /* wgsl */ `\nfn grid_cells() -> u32 { return P.gridMax * P.gridMax * select(1u, P.gridMax, P.dim == 3u); }\n\n@compute @workgroup_size(WG)\nfn grid_centroid(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let c = linear_id(wid, lid.x);\n if (c >= grid_cells() + select(4u, 8u, P.dim == 3u)) { return; } // cells [0, cells + 2^dim): the pseudo-cells follow the real ones; no barrier follows\n let start = cellStart[c];\n let count = cellStart[c + 1u] - start;\n atomicMax(&hubCounters[1], count); // maxCellOccupancy, read by K1 next iteration\n if (count > GRID_HUB_CELL) { // a hub cell: G4b sums it (PD-13)\n hubList[atomicAdd(&hubCounters[0], 1u)] = c;\n return;\n }\n var acc = vec4f(0.0);\n for (var k = start; k < start + count; k = k + 1u) { // sorted order: deterministic\n let p = pos[sortedIdx[k]];\n acc = acc + vec4f(p.xyz * p.w, p.w); // (sum m x, sum m y, sum m z, sum m)\n }\n pyramid[c] = acc;\n}\n`;\n","/**\n * G4b, the `grid-centroid-hub` kernel body (spec 7.7; P4-T9): one workgroup per word of hubList, dispatched\n * directly (issue #732), so the workgroups past hubCounters[0] idle; a WG-strided mass-weighted sum reduced by the\n * prelude's tree. The work is guarded by `valid`, never an early return, so the reduction is uniform (PD-13). Body\n * only; normative text.\n */\nexport const gridCentroidHubWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn grid_centroid_hub(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let h = group_id(wid);\n let valid = h < hubCount[0]; // a workgroup past the count sums nothing\n var c = 0u;\n var start = 0u;\n var count = 0u;\n if (valid) {\n c = hubList[h];\n start = cellStart[c];\n count = cellStart[c + 1u] - start;\n }\n var acc = vec4f(0.0);\n for (var k = start + lid.x; k < start + count; k = k + WG) { // strided over the cell's sorted range\n let p = pos[sortedIdx[k]];\n acc = acc + vec4f(p.xyz * p.w, p.w);\n }\n let t = wg_reduce_vec4(acc, lid.x, 0u); // uniform control flow: 256 -> 1\n if (valid && lid.x == 0u) { pyramid[c] = t; }\n}\n`;\n","/**\n * G5, the `grid-downsample` kernel body (spec 7.7; P4-T9): one dispatch per coarser level; every parent cell is the\n * sum of its 4 (2D) or 8 (3D) children at the level below, read at P.childBase and written at P.parentBase (the\n * pseudo-cells, indices cells .. of level 0, are never children). No atomics. Body only; normative text.\n */\nexport const gridDownsampleWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn grid_downsample(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let pc = linear_id(wid, lid.x); // the parent cell inside its level\n if (pc >= P.parentCells) { return; } // no barrier follows\n let side = P.parentSide;\n let cs = 2u * side; // the child level's side\n let px = pc % side;\n let py = (pc / side) % side;\n let pz = pc / (side * side);\n var acc = vec4f(0.0);\n for (var dz = 0u; dz < P.depth; dz = dz + 1u) {\n for (var dy = 0u; dy < 2u; dy = dy + 1u) {\n for (var dx = 0u; dx < 2u; dx = dx + 1u) {\n let child = (2u * px + dx) + cs * ((2u * py + dy) + cs * (2u * pz + dz));\n acc = acc + pyramid[P.childBase + child];\n }\n }\n }\n pyramid[P.parentBase + pc] = acc;\n}\n`;\n","/**\n * G6, the `grid-far-field` kernel body (spec 7.7; P4-T10; D24): per node `i = sortedIdx[t]`, its finest cell\n * recomputed from `pos[i]` and the state (PD-10); for an inside node the coarsest level minus the 3x3 (3x3x3)\n * around its coarsest cell, then at every finer level the 6x6 (6x6x6) block that is the parent's 3x3 minus this\n * level's own 3x3 -- space tiled exactly once, no theta -- plus the centroid of each of the 2^dim outside\n * pseudo-cells, one per orthant about the grid centre (issue #90); for an outside node the coarsest level in full and\n * no pseudo-cell. Every cell term is the per-cell law on the mass-weighted\n * centroid (Gephi Region semantics), softened by `eps^2`: `LAW` 0 (FA2) `d * (k m_i M / d2)` with `|d|^2` first\n * floored at 0.01^2 like K3's pair law (issue #89), `LAW` 1 (FR, 7.20)\n * `d * (k^2 M / d2)` (mass 1 per node, so `M` is the cell's count), `LAW` 2 (coulomb) `d * (-g m_i M / d2^1.5)`\n * (P4-T13, PD-22). `force += f` (K2 wrote it). The loop bounds are `P.levels` and `P.gridMax` from the uniform,\n * not a `LEVELS` override (PD-16, DEP-P4-G). Body only; normative text.\n */\nexport const gridFarFieldWgsl = /* wgsl */ `\nfn load_force(i: u32) -> vec3f { return vec3f(force[3u * i], force[3u * i + 1u], force[3u * i + 2u]); }\nfn store_force(i: u32, f: vec3f) {\n force[3u * i] = f.x;\n force[3u * i + 1u] = f.y;\n force[3u * i + 2u] = f.z;\n}\nfn grid_cells() -> u32 { return P.gridMax * P.gridMax * select(1u, P.gridMax, P.dim == 3u); }\nfn grid_side(level: u32) -> u32 { return P.gridMax >> level; }\nfn outside_cells() -> u32 { return select(4u, 8u, P.dim == 3u); } // one pseudo-cell per orthant (issue #90)\nfn level_base(level: u32) -> u32 { // the pyramid index of level L's cell 0 (level 0 carries the pseudo-cells at cells ..)\n var base = 0u;\n for (var l = 0u; l < level; l = l + 1u) {\n let s = grid_side(l);\n base = base + s * s * select(1u, s, P.dim == 3u) + select(0u, outside_cells(), l == 0u);\n }\n return base;\n}\nfn cell_at(level: u32, cx: i32, cy: i32, cz: i32) -> u32 {\n let s = grid_side(level);\n return level_base(level) + u32(cx) + s * (u32(cy) + select(0u, s * u32(cz), P.dim == 3u));\n}\nfn cell_force(pi: vec4f, q: vec4f) -> vec3f { // one far-field term, softened by state.eps (7.7)\n if (q.w <= 0.0) { return vec3f(0.0); } // an empty cell\n let d = pi.xyz - q.xyz / q.w; // to the mass-weighted centroid\n var d2 = dot(d, d);\n if (LAW == 0u) { d2 = max(d2, FA2_DIST_FLOOR_SQ); } // FA2 alone floors d >= 0.01, as K3 and G7 do (issue #89); FR and coulomb are unfloored (7.20)\n d2 = d2 + S.eps * S.eps;\n if (LAW == 1u) { return d * (P.frK * P.frK * q.w / d2); } // LAW 1 (FR, 7.20): k^2 / d per node, q.w nodes at the centroid\n if (LAW == 2u) { return d * (-P.coulomb * pi.w * q.w / (d2 * sqrt(d2))); } // LAW 2 (coulomb): -g m_i M_cell / d^2\n return d * (P.scalingRatio * pi.w * q.w / d2); // LAW 0 (FA2): |F| = k m_i M_cell / d\n}\n\n@compute @workgroup_size(WG)\nfn grid_far_field(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let t = linear_id(wid, lid.x);\n if (t >= P.n) { return; } // no barrier follows\n let i = sortedIdx[t]; // sorted order (D24)\n let pi = pos[i];\n let gf = f32(P.gridMax);\n let q = (pi.xyz - S.gridMin.xyz) * S.invCellSize; // PD-10\n var c0 = vec3<i32>(floor(clamp(q, vec3f(-1.0), vec3f(gf + 1.0))));\n if (P.dim == 2u) { c0.z = 0; } // 2D: one z plane; the loops below visit cz = 0 only, so the 3x3 test must see cz - 0\n let g = i32(P.gridMax);\n var inside = c0.x >= 0 && c0.x < g && c0.y >= 0 && c0.y < g;\n if (P.dim == 3u) { inside = inside && c0.z >= 0 && c0.z < g; }\n let top = P.levels - 1u;\n let ts = i32(grid_side(top)); // the coarsest side (4)\n let zTop = select(0, ts - 1, P.dim == 3u); // z ranges: one plane in 2D\n var f = vec3f(0.0);\n if (inside) {\n let ct = c0 / i32(1u << top); // the node's coarsest cell\n for (var cz = 0; cz <= zTop; cz = cz + 1) {\n for (var cy = 0; cy < ts; cy = cy + 1) {\n for (var cx = 0; cx < ts; cx = cx + 1) {\n if (abs(cx - ct.x) <= 1 && abs(cy - ct.y) <= 1 && abs(cz - ct.z) <= 1) { continue; } // the 3x3(x3) is finer levels' work\n f = f + cell_force(pi, pyramid[cell_at(top, cx, cy, cz)]);\n }\n }\n }\n for (var l = top; l > 0u; l = l - 1u) { // level l - 1: the parent's 3x3 at level l, refined, minus this level's own 3x3\n let level = l - 1u;\n let cl = c0 / i32(1u << level);\n let cp = cl / 2;\n let side = i32(grid_side(level));\n let zLo = select(0, max(0, 2 * (cp.z - 1)), P.dim == 3u);\n let zHi = select(0, min(side - 1, 2 * (cp.z + 1) + 1), P.dim == 3u);\n for (var cz = zLo; cz <= zHi; cz = cz + 1) {\n for (var cy = max(0, 2 * (cp.y - 1)); cy <= min(side - 1, 2 * (cp.y + 1) + 1); cy = cy + 1) {\n for (var cx = max(0, 2 * (cp.x - 1)); cx <= min(side - 1, 2 * (cp.x + 1) + 1); cx = cx + 1) {\n if (abs(cx - cl.x) <= 1 && abs(cy - cl.y) <= 1 && abs(cz - cl.z) <= 1) { continue; }\n f = f + cell_force(pi, pyramid[cell_at(level, cx, cy, cz)]);\n }\n }\n }\n }\n for (var o = 0u; o < outside_cells(); o = o + 1u) { // every outside pseudo-cell: one far-field term per orthant\n f = f + cell_force(pi, pyramid[grid_cells() + o]);\n }\n } else {\n for (var cz = 0; cz <= zTop; cz = cz + 1) { // an outside node: the coarsest level in full, no pseudo-cell (G7 sums them pair by pair)\n for (var cy = 0; cy < ts; cy = cy + 1) {\n for (var cx = 0; cx < ts; cx = cx + 1) {\n f = f + cell_force(pi, pyramid[cell_at(top, cx, cy, cz)]);\n }\n }\n }\n }\n store_force(i, load_force(i) + f);\n}\n`;\n","/**\n * G7, the `grid-near-field` kernel body (spec 7.7, 7.6, 7.20; P4-T10, P4-T13; D24): per node `i = sortedIdx[t]`, the\n * exact pair law of K3 (`LAW` 0: `|F| = k m_i m_j / d` with the 0.01 floor; `LAW` 1: FR's unfloored `k^2 / d`;\n * `LAW` 2: the unfloored coulomb `-g m_i m_j / d^2`; the antisymmetric coincident kick at the law's magnitude at\n * d = 0.01, PD-22) over the 9 (27) finest\n * cells around its own, or over the 2^dim outside pseudo-cells (one per orthant, issue #90) for an outside node; a cell above `nearMax` entries\n * is sampled by `nearMax` INDEPENDENT draws with replacement, draw `k` reading the slot\n * `lowbias32(((c ^ (iteration * 0x9E3779B9)) ^ seed) ^ (k * 0x85EBCA6B)) % count` (every slot's inclusion\n * probability is `nearMax / count` whatever its position in the sorted order, so a duplicated draw is counted twice\n * and the node itself, when drawn, is skipped and not replaced), and scaled by `others / sampled` where `sampled` is\n * the realised number of draws that were not the node (the Horvitz-Thompson form of PD-15 / DEP-P4-K: given\n * `sampled = s`, those `s` draws are i.i.d. uniform over the `others` slots, so the expectation of the scaled sum is\n * the exact cell sum whenever `s >= 1`; the G4 record's G4-F2 row carries the measurement); then\n * the fused epilogue of K3 (gravity, `force +=`, the swing / traction workgroup reduction in uniform control flow).\n * The helpers `load_force`, `store_force`, `load_old`, `kick_magnitude`, `gravity_force` and the epilogue are K3's\n * text. Body only; normative text.\n */\nexport const gridNearFieldWgsl = /* wgsl */ `\nfn load_force(i: u32) -> vec3f { return vec3f(force[3u * i], force[3u * i + 1u], force[3u * i + 2u]); }\nfn store_force(i: u32, f: vec3f) {\n force[3u * i] = f.x;\n force[3u * i + 1u] = f.y;\n force[3u * i + 2u] = f.z;\n}\nfn load_old(i: u32) -> vec3f { return vec3f(oldForce[3u * i], oldForce[3u * i + 1u], oldForce[3u * i + 2u]); }\nfn gravity_force(pi: vec4f) -> vec3f { // spec 7.9: centroid (GRAVITY_CENTER 0) or origin (1); regular or strong\n var q = pi.xyz;\n if (GRAVITY_CENTER == 0u) { q = pi.xyz - S.centroid.xyz; }\n if (STRONG_GRAVITY) { return -P.gravity * pi.w * q; }\n let d = length(q);\n if (d > FA2_DIST_FLOOR) { return -P.gravity * pi.w * q / d; }\n return vec3f(0.0);\n}\nfn grid_cells() -> u32 { return P.gridMax * P.gridMax * select(1u, P.gridMax, P.dim == 3u); }\nfn kick_magnitude(mi: f32, mj: f32) -> f32 { // the law's magnitude at d = FA2_DIST_FLOOR (the P5 plan's PD-10)\n if (LAW == 1u) { return P.frK * P.frK / FA2_DIST_FLOOR; }\n if (LAW == 2u) { return -P.coulomb * mi * mj / FA2_DIST_FLOOR_SQ; }\n return P.scalingRatio * mi * mj / FA2_DIST_FLOOR;\n}\nfn pair_force(i: u32, pi: vec4f, jj: u32, o: vec4f) -> vec3f { // the exact pair law of K3 (7.6, 7.20): the floor (FA2 only), the coincident kick\n let d = pi.xyz - o.xyz;\n var d2 = dot(d, d);\n if (d2 < FA2_COINCIDENT_SQ) { return kick_dir(i, jj, P.dim) * kick_magnitude(pi.w, o.w); }\n if (LAW == 0u) { d2 = max(d2, FA2_DIST_FLOOR_SQ); }\n let k = P.scalingRatio * pi.w * o.w;\n if (LAW == 1u) { return d * (P.frK * P.frK / d2); }\n if (LAW == 2u) { return d * (-P.coulomb * pi.w * o.w / (d2 * sqrt(d2))); }\n return d * (k / d2);\n}\nfn cell_sum(i: u32, pi: vec4f, c: u32, own: bool) -> vec3f { // one finest cell: exact below nearMax entries, Horvitz-Thompson above (PD-15)\n let start = cellStart[c];\n let count = cellStart[c + 1u] - start;\n var f = vec3f(0.0);\n if (count <= P.nearMax) {\n for (var k = start; k < start + count; k = k + 1u) {\n let jj = sortedIdx[k];\n if (jj != i) { f = f + pair_force(i, pi, jj, pos[jj]); }\n }\n return f;\n }\n let base = (c ^ (P.iterationIndex * 0x9E3779B9u)) ^ P.seed; // the per-iteration draw seed (7.16)\n var sampled = 0u;\n for (var k = 0u; k < P.nearMax; k = k + 1u) {\n let jj = sortedIdx[start + (lowbias32(base ^ (k * 0x85EBCA6Bu)) % count)]; // draw k: independent inclusion, with replacement (PD-15)\n if (jj == i) { continue; }\n f = f + pair_force(i, pi, jj, pos[jj]);\n sampled = sampled + 1u;\n }\n if (sampled == 0u) { return vec3f(0.0); }\n let others = select(count, count - 1u, own);\n return f * (f32(others) / f32(sampled)); // others / sampled over the realised sample (DEP-P4-K)\n}\n\n@compute @workgroup_size(WG)\nfn grid_near_field(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let t = linear_id(wid, lid.x);\n let valid = t < P.n;\n var i = 0u;\n var pi = vec4f(0.0);\n var f = vec3f(0.0);\n if (valid) {\n i = sortedIdx[t]; // sorted order (D24)\n pi = pos[i];\n let gf = f32(P.gridMax);\n let q = (pi.xyz - S.gridMin.xyz) * S.invCellSize;\n var c0 = vec3<i32>(floor(clamp(q, vec3f(-1.0), vec3f(gf + 1.0))));\n if (P.dim == 2u) { c0.z = 0; } // 2D: the one z plane\n let g = i32(P.gridMax);\n var inside = c0.x >= 0 && c0.x < g && c0.y >= 0 && c0.y < g;\n if (P.dim == 3u) { inside = inside && c0.z >= 0 && c0.z < g; }\n if (inside) {\n let zr = select(0, 1, P.dim == 3u);\n for (var dz = -zr; dz <= zr; dz = dz + 1) {\n for (var dy = -1; dy <= 1; dy = dy + 1) {\n for (var dx = -1; dx <= 1; dx = dx + 1) {\n let cx = c0.x + dx;\n let cy = c0.y + dy;\n let cz = c0.z + dz;\n if (cx < 0 || cx >= g || cy < 0 || cy >= g || cz < 0 || cz >= g) { continue; }\n let c = u32(cx) + P.gridMax * (u32(cy) + select(0u, P.gridMax * u32(cz), P.dim == 3u));\n f = f + cell_sum(i, pi, c, dx == 0 && dy == 0 && dz == 0);\n }\n }\n }\n } else {\n var own = grid_cells() + select(0u, 1u, c0.x >= g / 2) + select(0u, 2u, c0.y >= g / 2); // G1's orthant key\n if (P.dim == 3u) { own = own + select(0u, 4u, c0.z >= g / 2); }\n for (var o = grid_cells(); o < grid_cells() + select(4u, 8u, P.dim == 3u); o = o + 1u) { // an outside node: every outside pseudo-cell\n f = f + cell_sum(i, pi, o, o == own);\n }\n }\n }\n // epilogue (7.9, 7.10): gravity and force += under the guard, the swing / traction reduction outside it (K3's text)\n var sw = 0.0;\n var tr = 0.0;\n if (valid) {\n f = f + gravity_force(pi);\n let fnew = load_force(i) + f;\n store_force(i, fnew);\n if (SWING_MODE == 1u) { // NetworkX: positions and forces mixed, every node (7.2)\n sw = pi.w * length(pi.xyz - fnew);\n tr = 0.5 * pi.w * length(pi.xyz + fnew);\n } else if (!mask_bit(fixedMask[i >> 5u], i)) { // paper: free nodes only\n let fold = load_old(i);\n sw = pi.w * length(fnew - fold);\n tr = 0.5 * pi.w * length(fnew + fold);\n }\n }\n let tt = wg_reduce_vec4(vec4f(sw, tr, 0.0, 0.0), lid.x, 0u); // uniform control flow: 256 -> 1\n if (lid.x == 0u) { partials[group_id(wid)].swingTraction = tt.xy; }\n}\n`;\n","/**\n * The `group-by-key-row` kernel body (design 8.6; the per-row group-by-key): for every listed row `v`, the arcs of\n * the row are grouped by the key of their target (`keyIn[colIdx[a]]`), the weights are summed per key, and the key\n * with the largest sum wins, ties going to the LOWEST key -- which makes the answer independent of the order the arcs\n * are visited in, and so bitwise reproducible. `bestKey[v]` gets the key (`INVALID_INDEX` for an empty row) and\n * `bestScore[v]` the summed weight.\n *\n * The sums are u32 fixed point, because WGSL has no float atomic: every weight is scaled by `2^s`, a power of two\n * chosen from the exponents of the row's largest weight and of its degree alone so that `maxWeight x degree x 2^s`\n * lies in [2^28, 2^30), and rounded to the nearest integer, halves up. No step rounds a float: the scale needs no\n * product, scaling by a power of two is exact, and so are the integer part and the fraction of the scaled weight.\n * That matters because WGSL lets `x + y` and `x * y` round to EITHER neighbour of an inexact result, so a rounded\n * step could differ between devices; as written, both tiers, every device and any CPU reference compute identical\n * integers. A weight smaller than `2^-s / 2` contributes nothing, and a negative weight counts as zero. Without\n * WEIGHTED every weight is 1.\n *\n * TIER 0: one thread per row (`rows[P.rowsBase + i]`), a pairwise scan in registers -- for short rows, and at most\n * GROUP_ROW_THREAD_LIMIT arcs, since llvmpipe stops an invocation's loops after 65,535 steps. Any other TIER: one\n * workgroup per row (`rows[P.rowsBase + g]`) over its own open-addressing region of `GROUP_HASH_LOAD_FACTOR x degree`\n * slot pairs (key, sum) starting at word `rows[P.basesBase + g]` of `hashRegion`, cleared by the workgroup itself;\n * a key is claimed by a bounded compare-exchange loop with linear probing, and a lane that exhausts its bound raises\n * `hashRegion[0]`, which the driver reads and refuses. Every barrier is reached in uniform control flow: the only\n * early return keys on the workgroup id and a uniform. Body only (spec 3.5, D9); normative text.\n */\nexport const groupByKeyRowWgsl = /* wgsl */ `\nvar<workgroup> shMax: array<f32, WG>;\nvar<workgroup> shKey: array<u32, WG>;\nvar<workgroup> shSum: array<u32, WG>;\n\nfn weight_of(a: u32) -> f32 {\n if (WEIGHTED) { return weights[a]; }\n return 1.0;\n}\nfn scale_of(maxW: f32, d: u32) -> f32 { // 2^s, maxW x d x 2^s in [2^28, 2^30), from exponents alone\n let em = i32((bitcast<u32>(maxW) >> 23u) & 255u) - 127;\n let ed = i32(firstLeadingBit(max(d, 1u)));\n let s = clamp(28 - em - ed, -126, 126);\n return bitcast<f32>(u32(s + 127) << 23u);\n}\nfn inverse_of(scale: f32) -> f32 { // 2^-s, exact\n let s = i32((bitcast<u32>(scale) >> 23u) & 255u) - 127;\n return bitcast<f32>(u32(127 - s) << 23u);\n}\nfn quantize(w: f32, scale: f32) -> u32 { // nearest integer, halves up; every step exact\n let x = max(w * scale, 0.0);\n let i = u32(x);\n return select(i, i + 1u, x - f32(i) >= 0.5);\n}\nfn better(sum: u32, key: u32, bestSum: u32, bestKey0: u32) -> bool { return sum > bestSum || (sum == bestSum && key < bestKey0); }\n\nfn row_thread(v: u32) {\n let lo = rowPtr[v];\n let hi = rowPtr[v + 1u];\n var maxW = 0.0;\n for (var a = lo; a < hi; a = a + 1u) { maxW = max(maxW, weight_of(a)); }\n let scale = scale_of(maxW, hi - lo);\n var bk = INVALID_INDEX;\n var bs = 0u;\n for (var a = lo; a < hi; a = a + 1u) {\n let k = keyIn[colIdx[a]];\n var seen = false;\n for (var b = lo; b < a; b = b + 1u) { if (keyIn[colIdx[b]] == k) { seen = true; break; } }\n if (seen) { continue; } // this key was summed at its first arc\n var sum = 0u;\n for (var b = a; b < hi; b = b + 1u) { if (keyIn[colIdx[b]] == k) { sum = sum + quantize(weight_of(b), scale); } }\n if (better(sum, k, bs, bk)) { bk = k; bs = sum; }\n }\n bestKey[v] = bk;\n bestScore[v] = f32(bs) * inverse_of(scale);\n}\n\nfn row_hash(g: u32, lid: u32) {\n let v = rows[P.rowsBase + g];\n let base = rows[P.basesBase + g];\n let lo = rowPtr[v];\n let hi = rowPtr[v + 1u];\n let cap = GROUP_HASH_LOAD_FACTOR * (hi - lo);\n var m = 0.0;\n for (var a = lo + lid; a < hi; a = a + WG) { m = max(m, weight_of(a)); }\n shMax[lid] = m;\n workgroupBarrier();\n for (var s = WG / 2u; s > 0u; s = s / 2u) {\n if (lid < s) { shMax[lid] = max(shMax[lid], shMax[lid + s]); }\n workgroupBarrier();\n }\n let scale = scale_of(shMax[0], hi - lo);\n for (var j = lid; j < cap; j = j + WG) { // the region is this workgroup's alone: clear it\n atomicStore(&hashRegion[base + 2u * j], INVALID_INDEX);\n atomicStore(&hashRegion[base + 2u * j + 1u], 0u);\n }\n storageBarrier();\n var exhausted = false;\n for (var a = lo + lid; a < hi; a = a + WG) {\n let k = keyIn[colIdx[a]];\n let q = quantize(weight_of(a), scale);\n var slot = lowbias32(k) % cap;\n var steps = 0u;\n loop {\n if (steps >= cap + 64u) { exhausted = true; break; } // bounded: a spurious compare-exchange failure is legal (WGSL 17.8.5)\n steps = steps + 1u;\n let r = atomicCompareExchangeWeak(&hashRegion[base + 2u * slot], INVALID_INDEX, k);\n if (r.exchanged || r.old_value == k) { atomicAdd(&hashRegion[base + 2u * slot + 1u], q); break; }\n if (r.old_value == INVALID_INDEX) { continue; } // a spurious failure: the same slot again\n slot = (slot + 1u) % cap; // linear probing\n }\n }\n if (exhausted) { atomicStore(&hashRegion[0], 1u); }\n storageBarrier();\n var bk = INVALID_INDEX;\n var bs = 0u;\n for (var j = lid; j < cap; j = j + WG) {\n let k = atomicLoad(&hashRegion[base + 2u * j]);\n if (k != INVALID_INDEX) {\n let sum = atomicLoad(&hashRegion[base + 2u * j + 1u]);\n if (better(sum, k, bs, bk)) { bk = k; bs = sum; }\n }\n }\n shKey[lid] = bk;\n shSum[lid] = bs;\n workgroupBarrier();\n for (var s = WG / 2u; s > 0u; s = s / 2u) {\n if (lid < s && better(shSum[lid + s], shKey[lid + s], shSum[lid], shKey[lid])) {\n shKey[lid] = shKey[lid + s];\n shSum[lid] = shSum[lid + s];\n }\n workgroupBarrier();\n }\n if (lid == 0u) {\n bestKey[v] = shKey[0];\n bestScore[v] = f32(shSum[0]) * inverse_of(scale);\n }\n}\n\n@compute @workgroup_size(WG)\nfn group_by_key_row(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n if (TIER == 0u) {\n let i = linear_id(wid, lid.x);\n if (i < P.count) { row_thread(rows[P.rowsBase + i]); }\n return; // TIER is an override: uniform\n }\n let g = group_id(wid);\n if (g >= P.count) { return; } // uniform: the workgroup id and a uniform\n row_hash(g, lid.x);\n}\n`;\n","/**\n * The `histogram` kernel body (spec 6 row 5; P4-T3): one atomicAdd per key into the global `hist` (zeroed by a fill\n * dispatch earlier in the pass, PD-4). Order-independent, hence deterministic. A key >= P.bins is not counted (the\n * caller's contract; the grid's keys are always < cells + 2^dim). Body only; normative text.\n */\nexport const histogramWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn histogram(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.count) { return; } // no barrier follows\n let k = keys[i];\n if (k < P.bins) { atomicAdd(&hist[k], 1u); } // order-independent: the count is the same whatever the schedule\n}\n`;\n","/**\n * The `indirect-finalize` kernel body (spec 5.4; P4-T1): one lane turns the device-side count `counters[P.countIndex]`\n * into the `(x, y, 1)` of an indirect dispatch by plan1d's rule (spec 5.2) and writes it with the count into the\n * 16-byte slot `P.slot` of `args` (PD-2). No barrier follows the early return of the other lanes. Body only (spec 3.5,\n * D9); the text is normative: the P4 sabotage rows are textual edits of it.\n */\nexport const indirectFinalizeWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn indirect_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x != 0u) { return; } // one lane; no barrier follows (3.5 rule 1)\n let count = counters[P.countIndex];\n let groups = count / P.wg + select(0u, 1u, count % P.wg != 0u); // ceil(count / wg) without the u32 wrap of (count + wg - 1) above 2^32 - wg: plan1d's rule (5.2) for ANY u32 count\n var x = groups;\n var y = 1u;\n if (groups > MAX_WORKGROUPS_PER_DIM) { // the 2D split; y <= 1,025 for any u32 count\n x = MAX_WORKGROUPS_PER_DIM;\n y = (groups + MAX_WORKGROUPS_PER_DIM - 1u) / MAX_WORKGROUPS_PER_DIM;\n }\n let base = 4u * P.slot; // 16-byte slots: (x, y, 1, count) (PD-2)\n args[base] = x;\n args[base + 1u] = y;\n args[base + 2u] = 1u;\n args[base + 3u] = count;\n}\n`;\n","/**\n * The `lpa-step` kernel body (design 8.6; label propagation): after `group-by-key-row` has written every vertex's\n * best neighbour label into `bestKey`, a vertex adopts it only when the move goes the way the pass allows -- down to\n * a lower label on a pass whose `P.direction` is 0, up to a higher one when it is 1. That is cuGraph's swap-avoidance\n * rule: two neighbours can no longer trade labels forever, because on any one pass only one of the two moves is\n * legal. Updates are synchronous (`labelsIn` read, `labelsOut` written) and the moves of a workgroup are added to\n * `counters[P.counterIndex]` with ONE atomic per workgroup. Body only (spec 3.5, D9); normative text.\n */\nexport const lpaStepWgsl = /* wgsl */ `\nvar<workgroup> moved: atomic<u32>;\n\n@compute @workgroup_size(WG)\nfn lpa_step(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x == 0u) { atomicStore(&moved, 0u); }\n workgroupBarrier();\n let v = linear_id(wid, lid.x);\n if (v < P.n) {\n let cur = labelsIn[v];\n let best = bestKey[v];\n var next = cur;\n if (best != INVALID_INDEX && best != cur) {\n let down = best < cur;\n if (down == (P.direction == 0u)) { next = best; } // the alternating direction rule\n }\n labelsOut[v] = next;\n if (next != cur) { atomicAdd(&moved, 1u); }\n }\n workgroupBarrier(); // every lane, unconditionally\n if (lid.x == 0u) {\n let m = atomicLoad(&moved);\n if (m > 0u) { atomicAdd(&counters[P.counterIndex], m); } // one atomic per workgroup\n }\n}\n`;\n","/**\n * The `mst-best` kernel body (design 8.5; the P11 plan's P11-T4, PD-6 and PD-7): one logical edge per invocation of\n * a Boruvka round. An edge whose endpoints lie in different components (`comp` holds every vertex's root) offers\n * itself to both components. `atomicMin` exists for u32 only and no atomic compares one word and writes another, so\n * the per-component minimum of the total edge order (weight, then edge index) is TWO passes of this one body, chosen\n * by the `PASS` override: pass 0 takes the minimum `order_key` of the weight into `bestKey`, pass 1 the minimum edge\n * index among the edges that hold that key into `bestEdge`. `order_key` (the prelude) orders negative weights below\n * positive ones and -0 equal to +0, which a raw bit pattern does not. Without `WEIGHTED` every edge weighs 1 and\n * the index alone decides, as in Kruskal. Body only (spec 3.5, D9); normative text: a sabotage mutation is a textual\n * edit of it.\n */\nexport const mstBestWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn mst_best(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let e = linear_id(wid, lid.x);\n if (e >= P.count) { return; }\n let cu = comp[edgeSrc[e]];\n let cv = comp[edgeDst[e]];\n if (cu == cv) { return; } // inside one component, or a self-loop\n var w = 1.0;\n if (WEIGHTED) { w = edgeWeight[e]; }\n let k = order_key(w);\n if (PASS == 0u) {\n atomicMin(&bestKey[cu], k);\n atomicMin(&bestKey[cv], k);\n } else {\n if (k == atomicLoad(&bestKey[cu])) { atomicMin(&bestEdge[cu], e); }\n if (k == atomicLoad(&bestKey[cv])) { atomicMin(&bestEdge[cv], e); }\n }\n}\n`;\n","/**\n * The `mst-link` kernel body (design 8.5; the P11 plan's P11-T4): one vertex per invocation after `mst-best`'s two\n * passes. A component root `c` whose `bestEdge` exists hooks itself onto the component at the edge's other end and\n * records the edge in `treeEdge[c]`. Under the total edge order two components can only choose each other through\n * the SAME edge, so the one cycle possible is a two-cycle; the LOWER root of it keeps its label and only the higher\n * one hooks and records, so the edge is recorded once. Only a root writes its own `comp` word, so a concurrent reader\n * sees either the root or the root's new parent, both inside the component the round merges; `comp` is atomic\n * because WGSL forbids mixing atomic and plain access to one element. Every root hooks at most once in a run (it is\n * no longer a root afterwards), so `treeEdge` ends holding each forest edge exactly once, at the root that chose it.\n * The edges recorded are added to `counters[P.counterIndex]` with one atomic per workgroup; a round that records\n * none ends the run. Body only (spec 3.5, D9); normative text: a sabotage mutation is a textual edit of it.\n */\nexport const mstLinkWgsl = /* wgsl */ `\nvar<workgroup> added: atomic<u32>;\n\n@compute @workgroup_size(WG)\nfn mst_link(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x == 0u) { atomicStore(&added, 0u); }\n workgroupBarrier();\n let c = linear_id(wid, lid.x);\n if (c < P.count) {\n let e = bestEdge[c];\n if (e != INVALID_INDEX) {\n let a = atomicLoad(&comp[edgeSrc[e]]);\n let b = atomicLoad(&comp[edgeDst[e]]);\n let other = select(a, b, a == c);\n let keep = bestEdge[other] == e && c <= other; // the lower root of a two-cycle stays\n if (!keep) { atomicStore(&comp[c], other); }\n if (!keep) { treeEdge[c] = e; atomicAdd(&added, 1u); }\n }\n }\n workgroupBarrier(); // every lane, unconditionally\n if (lid.x == 0u) {\n let k = atomicLoad(&added);\n if (k > 0u) { atomicAdd(&counters[P.counterIndex], k); } // one atomic per workgroup\n }\n}\n`;\n","/**\n * The `orient-flags` kernel body (design 8.5; triangle counting): over the arcs of the simple symmetric graph, arc\n * `(u, v)` is kept when `(degree(v), v)` is above `(degree(u), u)` lexicographically. The order is strict and total,\n * so exactly one arc of every undirected edge survives and every triangle is found once, at its lowest-ranked vertex;\n * the rows stay sorted by target because a compaction preserves order. `src` holds each arc's source. Body only\n * (spec 3.5, D9); normative text.\n */\nexport const orientFlagsWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn orient_flags(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let a = linear_id(wid, lid.x);\n if (a >= P.count) { return; } // no barrier follows\n let u = src[a];\n let v = colIdx[a];\n let du = rowPtr[u + 1u] - rowPtr[u];\n let dv = rowPtr[v + 1u] - rowPtr[v];\n let keep = dv > du || (dv == du && v > u); // (degree, id) of the target above the source's\n flags[a] = select(0u, 1u, keep);\n}\n`;\n","/**\n * The `pr-finalize` kernel body (spec 8.2 dispatch (b)): ONE workgroup folds the `P.groups` per-workgroup partials\n * into the header at `partials[0]` -- a STORAGE region, never a uniform, read by the next dispatch of the same\n * pass -- and records `firstConverged` the first time the delta falls below `P.convergeThreshold`. NORM_MODE 2\n * stores the square root of the folded norm (the L2 case). The recorded iteration is `P.iteration - 1u` because\n * the delta a scale pass produces at iteration i is `|x(i-1) - x(i-2)|`, the error of iteration i - 1 (PD-9).\n * The body is normative: a sabotage mutation is a textual edit of it, so it is not restyled.\n */\n\n/** Entry point `pr_finalize`; override NORM_MODE (2 takes the square root of the folded norm, every other value stores it as folded). */\nexport const prFinalizeWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn pr_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n var d = 0.0;\n var e = 0.0;\n var m = 0.0;\n for (var g = lid.x; g < P.groups; g = g + WG) {\n d = d + partials[1u + g].danglingMass;\n e = e + partials[1u + g].delta;\n m = m + partials[1u + g].norm;\n }\n let folded = wg_reduce_vec4(vec4f(d, e, m, 0.0), lid.x, 0u);\n if (lid.x == 0u) {\n partials[0].danglingMass = folded.x;\n partials[0].delta = folded.y;\n var norm = folded.z;\n if (NORM_MODE == 2u) { norm = sqrt(max(0.0, folded.z)); }\n partials[0].norm = norm;\n partials[0].iteration = P.iteration;\n let unset = partials[0].firstConverged == U32_MAX;\n if (P.trackConvergence == 1u && P.iteration >= 2u && folded.y < P.convergeThreshold && unset) {\n partials[0].firstConverged = P.iteration - 1u;\n }\n }\n}\n`;\n","/**\n * The `pr-scale` kernel body (spec 8.2 dispatch (a)): one invocation per node writes `xNorm[u]` and contributes a\n * per-workgroup partial of the dangling mass, the L1 delta `|rankIn - rankPrev|` and, for the spectral modes, the\n * norm term. NORM_MODE selects the divisor: 0 PageRank (`rankIn[u] / outWeightSum[u]`, 0 and a dangling\n * contribution when the sum is not positive); 1 and 2 are NORM PASSES that write no xNorm and only accumulate\n * `abs(x)` (L1) or `x * x` (L2); 3 divides by the scalar `partials[0].norm` the previous dispatch folded; 4 is the\n * identity (Katz). The body is normative: a sabotage mutation is a textual edit of it, so it is not restyled.\n *\n * The guard is named `inRange`, never `active`: `active` is a WGSL reserved word (spec 16.2) and the composer\n * rejects it before a device is touched.\n */\n\n/** Entry point `pr_scale`; override NORM_MODE (0 PageRank, 1 L1 norm pass, 2 L2 norm pass, 3 scale by partials[0].norm, 4 identity). */\nexport const prScaleWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn pr_scale(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let u = linear_id(wid, lid.x);\n let inRange = u < P.n;\n var x = 0.0;\n var prev = 0.0;\n if (inRange) { x = rankIn[u]; prev = rankPrev[u]; }\n var dangling = 0.0;\n var delta = 0.0;\n var normTerm = 0.0;\n if (inRange) {\n delta = abs(x - prev);\n if (NORM_MODE == 0u) {\n let divisor = outWeightSum[u];\n if (divisor <= 0.0) { dangling = x; xNorm[u] = 0.0; } else { xNorm[u] = x / divisor; }\n }\n if (NORM_MODE == 1u) { normTerm = abs(x); }\n if (NORM_MODE == 2u) { normTerm = x * x; }\n if (NORM_MODE == 3u) {\n var scale = partials[0].norm;\n if (scale <= 0.0) { scale = 1.0; }\n xNorm[u] = x / scale;\n }\n if (NORM_MODE == 4u) { xNorm[u] = x; }\n }\n let folded = wg_reduce_vec4(vec4f(dangling, delta, normTerm, 0.0), lid.x, 0u);\n if (lid.x == 0u) {\n let slot = 1u + group_id(wid);\n partials[slot].danglingMass = folded.x;\n partials[slot].delta = folded.y;\n partials[slot].norm = folded.z;\n }\n}\n`;\n","/**\n * The `radix-hist` kernel body (spec 6 row 6; P4-T4): the RADIX_BINS-bin (2^8) digit histogram of one WG-wide block\n * of keys, privatised in workgroup memory (atomics on workgroup memory are order-independent) and written\n * DIGIT-MAJOR, `hist[digit * P.groups + group]`, so one exclusiveScan over the table yields, per digit, the offsets\n * of the workgroups in workgroup order -- what a stable LSD scatter needs. The bitwise operators act on a KEY and a\n * DIGIT, never on an arc index (house rule). Body only; normative text.\n */\nexport const radixHistWgsl = /* wgsl */ `\nvar<workgroup> local: array<atomic<u32>, RADIX_BINS>;\n\n@compute @workgroup_size(WG)\nfn radix_hist(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n for (var b = lid.x; b < RADIX_BINS; b = b + WG) { atomicStore(&local[b], 0u); }\n workgroupBarrier();\n let g = group_id(wid);\n let i = g * WG + lid.x;\n if (i < P.count) {\n let d = (keys[i] >> P.shift) & RADIX_DIGIT_MASK; // the pass's digit\n atomicAdd(&local[d], 1u);\n }\n workgroupBarrier();\n // Above MAX_1D_ITEMS plan1d pads the 2D grid to x * y >= P.groups workgroups; a padding workgroup (g >= P.groups)\n // holds an all-zero table and its digit-major slot b * P.groups + g is digit b + 1's slot of a REAL group, so it\n // must not store. Uniform per workgroup, no barrier inside. Every test size fits 1D (the ladder tops at 2^22); no\n // case reaches this branch, so the guard is proved by reading, not by a run.\n if (g < P.groups) {\n for (var b = lid.x; b < RADIX_BINS; b = b + WG) { hist[b * P.groups + g] = atomicLoad(&local[b]); } // digit-major\n }\n}\n`;\n","/**\n * The `radix-scatter` kernel body (spec 6 row 6; P4-T4): the stable scatter of one LSD pass. Lane 0 ranks the block's\n * keys serially in index order with a RADIX_BINS-entry counter table (PD-5: deterministic and stable, WG steps per\n * workgroup; ponytail: the 8-way split ranking of GraphWaGu is the upgrade if T-6 shows the sort on the critical\n * path), then every lane writes its key and value at `offsets[digit * P.groups + group] + rank`. Body only;\n * normative text.\n */\nexport const radixScatterWgsl = /* wgsl */ `\nvar<workgroup> rank: array<u32, WG>;\nvar<workgroup> cnt: array<u32, RADIX_BINS>;\n\n@compute @workgroup_size(WG)\nfn radix_scatter(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n for (var b = lid.x; b < RADIX_BINS; b = b + WG) { cnt[b] = 0u; }\n let g = group_id(wid);\n let i = g * WG + lid.x;\n var key = 0u;\n var d = 0u;\n if (i < P.count) {\n key = keys[i];\n d = (key >> P.shift) & RADIX_DIGIT_MASK;\n }\n workgroupBarrier();\n if (lid.x == 0u) { // serial stable ranking (PD-5)\n let last = min(WG, P.count - g * WG);\n for (var s = 0u; s < last; s = s + 1u) {\n let ds = (keys[g * WG + s] >> P.shift) & RADIX_DIGIT_MASK;\n rank[s] = cnt[ds];\n cnt[ds] = cnt[ds] + 1u;\n }\n }\n workgroupBarrier();\n if (i < P.count) {\n let dst = offsets[d * P.groups + g] + rank[lid.x];\n keysOut[dst] = key;\n valsOut[dst] = vals[i];\n }\n}\n`;\n","/**\n * The `reduce` kernel body (contract 4.5; spec 6 row 1): one level of the 2-3 level reduction. Overrides: OP\n * 0 sum / 1 min / 2 max, DTYPE 0 f32 / 1 u32 / 2 vec4f (four words per element, loaded through bitcast from the\n * u32 storage view), FINAL true for the one-workgroup level that folds the partials sequentially per lane in\n * index order (deterministic) and writes one element at `out[P.outOffset]`; the level-1 form writes\n * `out[P.outOffset + group]`. Calls the prelude's `wg_reduce_*` helpers (needs: [\"subgroups\"]) in uniform\n * control flow: DTYPE is a pipeline constant, so the branch on it is uniform. Normative text, copied verbatim.\n */\nexport const reduceWgsl = /* wgsl */ `\n// DTYPE 0 = f32, 1 = u32, 2 = vec4f (4 words per element); OP 0 = sum, 1 = min, 2 = max; FINAL = the one-workgroup level\nfn identity_f() -> f32 { if (OP == 1u) { return F32_MAX; } if (OP == 2u) { return -F32_MAX; } return 0.0; }\nfn identity_u() -> u32 { if (OP == 1u) { return U32_MAX; } return 0u; } // U32_MAX from the prelude: the literal is forbidden in bodies (4.1)\nfn comb_f(a: f32, b: f32) -> f32 { if (OP == 1u) { return min(a, b); } if (OP == 2u) { return max(a, b); } return a + b; }\nfn comb_u(a: u32, b: u32) -> u32 { if (OP == 1u) { return min(a, b); } if (OP == 2u) { return max(a, b); } return a + b; }\nfn comb_v(a: vec4f, b: vec4f) -> vec4f { if (OP == 1u) { return min(a, b); } if (OP == 2u) { return max(a, b); } return a + b; }\nfn load_f(i: u32) -> f32 { return bitcast<f32>(src[i]); }\nfn load_v(i: u32) -> vec4f {\n return vec4f(bitcast<f32>(src[4u * i]), bitcast<f32>(src[4u * i + 1u]), bitcast<f32>(src[4u * i + 2u]), bitcast<f32>(src[4u * i + 3u]));\n}\nfn store_f(i: u32, v: f32) { out[i] = bitcast<u32>(v); }\nfn store_v(i: u32, v: vec4f) {\n out[4u * i] = bitcast<u32>(v.x);\n out[4u * i + 1u] = bitcast<u32>(v.y);\n out[4u * i + 2u] = bitcast<u32>(v.z);\n out[4u * i + 3u] = bitcast<u32>(v.w);\n}\n\n@compute @workgroup_size(WG)\nfn reduce(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n var accF = identity_f();\n var accU = identity_u();\n var accV = vec4f(identity_f());\n if (FINAL) {\n for (var i = lid.x; i < P.count; i = i + WG) { // sequential per lane in index order: deterministic\n if (DTYPE == 0u) { accF = comb_f(accF, load_f(i)); }\n else if (DTYPE == 1u) { accU = comb_u(accU, src[i]); }\n else { accV = comb_v(accV, load_v(i)); }\n }\n } else {\n let i = linear_id(wid, lid.x);\n if (i < P.count) {\n if (DTYPE == 0u) { accF = load_f(i); }\n else if (DTYPE == 1u) { accU = src[i]; }\n else { accV = load_v(i); }\n }\n }\n // uniform control flow: the workgroup reduction of the selected dtype (DTYPE is a pipeline constant, so the branch is uniform)\n var tF = 0.0;\n var tU = 0u;\n var tV = vec4f(0.0);\n if (DTYPE == 0u) { tF = wg_reduce_f32(accF, lid.x, OP); }\n else if (DTYPE == 1u) { tU = wg_reduce_u32(accU, lid.x, OP); }\n else { tV = wg_reduce_vec4(accV, lid.x, OP); }\n if (lid.x == 0u) {\n let g = select(group_id(wid), 0u, FINAL);\n let o = P.outOffset + g;\n if (DTYPE == 0u) { store_f(o, tF); }\n else if (DTYPE == 1u) { out[o] = tU; }\n else { store_v(o, tV); }\n }\n}\n`;\n","/**\n * The `run-flags` kernel body (design 6 row 10; the simple symmetric graph build): over arcs sorted by the pair\n * (`keysA`, `keysB`), `flags[i]` is 1 exactly when arc `i` opens a run of equal pairs -- the first arc, or one whose\n * pair differs from its predecessor's -- and is not a dropped arc (`keysA[i] == INVALID_INDEX`). An exclusive scan\n * of the flags numbers the runs, which is how parallel arcs merge into one. Body only (spec 3.5, D9); normative text.\n */\nexport const runFlagsWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn run_flags(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.count) { return; } // no barrier follows\n let a = keysA[i];\n var first = a != INVALID_INDEX; // a dropped arc never opens a run\n if (i > 0u) { first = first && (a != keysA[i - 1u] || keysB[i] != keysB[i - 1u]); }\n flags[i] = select(0u, 1u, first);\n}\n`;\n","/**\n * The `scan-add` kernel body (spec 6 row 2 step (c); P4-T2): adds the exclusive prefix of its block's sum,\n * `blockOffsets[group]`, to every element of the block. Body only; normative text.\n */\nexport const scanAddWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn scan_add(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let g = group_id(wid);\n let i = g * WG + lid.x;\n if (i >= P.count) { return; } // no barrier follows\n out[i] = out[i] + blockOffsets[g];\n}\n`;\n","/**\n * The `scan-block` kernel body (spec 6 row 2; P4-T2): an exclusive prefix sum of one WG-wide block of `src` in\n * workgroup memory (Hillis-Steele, log2(WG) rounds of two barriers each, every lane in uniform control flow) into\n * `out`, and the block's inclusive total into `blockSums[group]`. u32 addition is exact in any order, so the\n * output is bitwise the same on every adapter (PD-3). Body only (spec 3.5, D9); normative text.\n */\nexport const scanBlockWgsl = /* wgsl */ `\nvar<workgroup> sh: array<u32, WG>;\n\n@compute @workgroup_size(WG)\nfn scan_block(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let g = group_id(wid);\n let i = g * WG + lid.x;\n var v = 0u;\n if (i < P.count) { v = src[i]; }\n sh[lid.x] = v;\n workgroupBarrier();\n for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan; uniform: every lane runs every round\n var t = 0u;\n if (lid.x >= s) { t = sh[lid.x - s]; }\n workgroupBarrier();\n sh[lid.x] = sh[lid.x] + t;\n workgroupBarrier();\n }\n let inclusive = sh[lid.x];\n if (i < P.count) { out[i] = inclusive - v; } // exclusive = inclusive - own value\n if (lid.x == WG - 1u) { blockSums[g] = inclusive; } // the block total (the last lane's inclusive sum)\n}\n`;\n","/**\n * The `segmented-reduce` kernel body (spec 6 row 3; contract 4.5) in its three degree tiers (P4-T5, PD-6). Every\n * tier folds the VALUE snippet over a row's arcs inside the bound window [P.arcBase, P.arcEnd) and writes out[i]\n * 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\n * `perm[row]` under USE_PERM and `row` otherwise, over the rows [P.start, P.end) of the dispatch. TIER 0 is one row\n * per thread (no barrier, so its early return is legal); TIER 1 is 32 lanes per row and WG / 32 rows per workgroup,\n * reduced by a five-step tree in workgroup memory (bitwise the same on every subgroup size); TIER 2 is one row per\n * workgroup through `wg_reduce_f32` of the prelude (the subgroup variant when the feature exists, the workgroup twin\n * otherwise -- hence `needs: [\"subgroups\"]`). The tier bodies are functions called under `if (TIER == 0u)`, an\n * override, so every barrier is reached in uniform control flow. The body is normative: a sabotage mutation\n * (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.\n *\n * TIER 0 folds its row through `row_fold_dense`, a stride-one copy of `row_fold`, because the shader compiler emits\n * `row_fold(i, 0u, 1u)` as a call and leaves the stride in a parameter: the loop then walks the row with a runtime\n * step, which costs the strength-reduced addressing into colIdx / weights and the unrolling that keeps several loads\n * in flight per thread. PageRank's out-weight pass, the only caller that passes no tiers today, runs TIER 0 alone,\n * and under the tiers TIER 0 still folds the low-degree rows, which are most of them. The two folds spell their\n * locals apart (`lo` / `hi` / `k` against `a0` / `a1`) so that each sabotage row names exactly one of them; the\n * VALUE snippet sees the same `row`, `arc`, `nbr` and `weight` in both.\n */\n\n/**\n * Entry point `segmented_reduce`; overrides OP (0 sum, 1 min, 2 max) and TIER (0 thread-per-row, 1 32-lanes-per-row,\n * 2 workgroup-per-row); snippet slot VALUE: statements assigning `v` from `row`, `arc`, `nbr`, `weight` (`target`\n * is a WGSL reserved word, hence `nbr`).\n */\nexport const segmentedReduceWgsl = /* wgsl */ `\nfn identity() -> f32 { if (OP == 1u) { return F32_MAX; } if (OP == 2u) { return -F32_MAX; } return 0.0; }\nfn comb(a: f32, b: f32) -> f32 { if (OP == 1u) { return min(a, b); } if (OP == 2u) { return max(a, b); } return a + b; }\nfn row_node(row: u32) -> u32 { return select(row, perm[row], USE_PERM); }\nfn 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)\n let row = i; // the CSR row the VALUE snippet may name (the node index, under USE_PERM too)\n let a0 = max(rowPtr[i], P.arcBase);\n let a1 = min(rowPtr[i + 1u], P.arcEnd);\n var acc = identity();\n for (var arc = a0 + lane; arc < a1; arc = arc + step) {\n let nbr = colIdx[arc - P.arcBase]; // the neighbour index (\\`target\\` is a WGSL reserved word)\n var weight = 1.0;\n if (HAS_WEIGHTS) { weight = weights[arc - P.arcBase]; }\n var v = 0.0;\n //@@VALUE@@\n acc = comb(acc, v);\n }\n return acc;\n}\nfn row_fold_dense(i: u32) -> f32 { // TIER 0's stride-one twin of row_fold (see the header)\n let row = i; // the CSR row the VALUE snippet may name (as in row_fold)\n let lo = max(rowPtr[i], P.arcBase);\n let hi = min(rowPtr[i + 1u], P.arcEnd);\n var acc = identity();\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];\n var weight = 1.0;\n if (HAS_WEIGHTS) { weight = weights[k]; }\n var v = 0.0;\n //@@VALUE@@\n acc = comb(acc, v);\n }\n return acc;\n}\nfn finish(i: u32, acc: f32) { out[i] = select(acc, comb(out[i], acc), P.accumulate == 1u); }\nfn 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)\n let row = linear_id(wid, lane) + P.start;\n if (row >= P.end) { return; }\n let i = row_node(row);\n finish(i, row_fold_dense(i));\n}\n\nvar<workgroup> sh: array<f32, WG>;\n\nfn 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)\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.end;\n var i = 0u;\n var acc = identity();\n if (valid) { i = row_node(row); acc = row_fold(i, 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 = identity();\n if (lane < s) { t = sh[lid + s]; }\n workgroupBarrier();\n sh[lid] = comb(sh[lid], t);\n workgroupBarrier();\n }\n if (valid && lane == 0u) { finish(i, sh[lid]); }\n }\n if (TIER == 2u) {\n let t = wg_reduce_f32(acc, lid, OP); // the workgroup tree of the prelude (subgroup variant when available)\n if (valid && lid == 0u) { finish(i, t); }\n }\n}\n\n@compute @workgroup_size(WG)\nfn segmented_reduce(@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`;\n","/**\n * 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):\n * every tier folds `weight * xNorm[nbr]` over a row's in-arcs of the REVERSE adjacency in chunks of 64 terms (a\n * two-level f32 sum: the chunk absorbs the rounding of 64 terms, the row total the rounding of the chunk count, so a\n * 10,000-arc hub row loses about 200 rounding steps instead of 10,000; Kahan compensation is not used because\n * Metal's shader compiler folds `((acc + term) - acc) - term` to zero whatever hides it) and writes\n * `rankOut[v] = beta * pv + alpha * (sum + danglingMass * pv)`, where `pv` is `personalization[v]` when\n * HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise. The rows are [P.start, P.n) of the dispatch, `perm[row]`\n * under USE_PERM: TIER 0 is grid-stride over them (one row per thread, `P.stride` from planGridStride); TIER 1 is 32\n * lanes per row and WG / 32 rows per workgroup with a five-step tree in workgroup memory (each lane keeps its own\n * 64-term chunking); TIER 2 is one row per workgroup through `wg_reduce_f32` (hence `needs: [\"subgroups\"]`). PageRank\n * sets alpha to the damping factor, beta to `1 - alpha` and USE_DANGLING; HITS and eigenvector set alpha 1, beta 0,\n * uniformP 0; Katz sets alpha to the attenuation, beta to its constant and uniformP 1. The body is normative: a\n * sabotage mutation (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.\n *\n * TIER 0 folds its row through `row_sum_dense`, a stride-one copy of `row_sum`, because the shader compiler emits\n * `row_sum(v, 0u, 1u)` as a call and leaves the stride in a parameter: the loop then walks the row with a runtime\n * step, which costs the strength-reduced addressing into colIdx / weights and the unrolling that keeps several loads\n * in flight per thread. PageRank and every other caller that passes no in-degree tiers runs TIER 0 alone, and under\n * the tiers it still folds the low-degree rows, which are most of them; the shared fold cost 38 per cent more GPU\n * 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\n * their locals apart (`lo` / `hi` / `k` against `a0` / `a1`) so that each sabotage row names exactly one of them.\n */\n\n/** Entry point `spmv_pull`; overrides HAS_PERSONALIZATION, USE_DANGLING and TIER (0 / 1 / 2) plus the standard USE_PERM / HAS_WEIGHTS. */\nexport const spmvPullWgsl = /* wgsl */ `\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`;\n","/**\n * The `sssp-pred` kernel body (design 8.10 \"SSSP predecessor pass\"; P8-T6 and P8-T9, the P8 plan's PD-11 / PD-24 /\n * PD-27): the ONE post-pass over the settled distances that produces `parent` for `breadthFirstSearch` and\n * `predArc` for `sssp` and `bellmanFord`, so no claim kernel writes a predecessor and every predecessor array is a\n * function of the settled `depth` / `dist` alone (bitwise reproducible, PD-14). `MODE` (a pipeline override) picks\n * the distance type: 1 = u32 depths (`dist` is the BFS depth array, a tight arc is `depth[u] + 1 == depth[v]`, every\n * tight arc is admitted, and the chain is acyclic because depth strictly decreases along it); 0 = f32 bit patterns\n * (a tight arc is `bitcast<u32>(bitcast<f32>(dist[u]) + w) == dist[v]`, one f32 add compared as the bits PD-9\n * stores). `P.predKind` picks what is written: 0 the arc index, 1 the source node index. The winner is the SMALLEST\n * admitted value through `atomicMin` on `pred[v]`, which the driver fills with `INVALID_INDEX` first; the source\n * keeps `INVALID_INDEX` whatever attains it.\n *\n * In `MODE 0` the body runs PD-27's three roles over a `pred` buffer of `2 x hb + 64` words, `hb = roundUp(n, 64)`:\n * `pred[0, n)` the arcs, `pred[hb, hb + n)` the hop counts, `pred[2 hb]` the changed word, `pred[2 hb + 1]` the orphan\n * word. Role 0 (the roots pass, `P.mode 0` only) marks every node with a tight in-arc from a strictly smaller\n * distance as a root (`hops 0`); role 1 (a hop pass, `P.iteration` inside its batch) lowers `hops[v]` to\n * `hops[u] + 1` along every plateau arc (`P.mode 0`: equal distance) or every tight arc (`P.mode 1`: bellmanFord's\n * tight-subgraph rule) and records the pass index in the changed word when it lowered one, returning at its first\n * line when the previous pass changed nothing; role 2 (the predecessor pass) admits the smallest tight arc whose\n * source sits exactly one key step below `v` and counts a reached non-source node the key never reached as an\n * orphan (only bellmanFord can make one). `MODE 1` reads none of `P.role`, `P.mode` and `P.iteration` and never\n * touches `pred` beyond word `n - 1`. The body STRIDES over the rows (`planGridStride(n)`, `P.stride` the plan's\n * stride): a per-invocation body under that plan would leave every row above the dispatch cap at `INVALID_INDEX`,\n * silently. No barrier anywhere, so the early return is legal. Body only (spec 3.5, D9); the text is normative: the\n * sabotage rows of test/helpers/sabotage.ts are textual edits of it.\n */\nexport const ssspPredWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn sssp_pred(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let first = linear_id(wid, lid.x);\n let hb = ((P.n + 63u) / 64u) * 64u; // MODE 0 only: hops[v] is pred[hb + v]; pred[2 hb] is the changed word, pred[2 hb + 1] the orphan word (PD-27)\n if (P.role == 1u && P.iteration != 0u && atomicLoad(&pred[2u * hb]) < P.iteration) { return; } // the previous hop pass changed nothing: converged (no barrier anywhere, so the early return is legal)\n for (var u = first; u < P.n; u = u + P.stride) { // grid-stride over the rows (planGridStride(n)); no barrier anywhere\n let du = dist[u];\n var unreached = false;\n if (MODE == 1u) { unreached = du == INVALID_INDEX; } else { unreached = du == F32_INF_BITS; }\n if (unreached) { continue; }\n var hu = 0u; // u's hop count (MODE 0, roles 1 and 2)\n if (MODE == 0u && P.role != 0u) {\n hu = atomicLoad(&pred[hb + u]);\n if (hu == INVALID_INDEX) { // the key has not reached u yet\n if (P.role == 2u && u != P.source) { atomicAdd(&pred[2u * hb + 1u], 1u); } // an orphan: only bellmanFord can make one (P8-T10 Step 3)\n continue;\n }\n }\n let end = min(rowPtr[u + 1u], P.arcEnd);\n for (var a = max(rowPtr[u], P.arcBase); a < end; a = a + 1u) {\n let v = colIdx[a - P.arcBase];\n if (v == P.source) { continue; } // the source keeps INVALID_INDEX whatever attains it (a zero-weight arc could)\n let dv = dist[v];\n var tight = false; // the arc explains dist[v]\n var below = false; // and its source sits at a strictly smaller distance\n if (MODE == 1u) {\n tight = (du + 1u) == dv; // depth mode: BFS parent, one depth down\n } else {\n let w = select(1.0, weights[a - P.arcBase], HAS_WEIGHTS);\n tight = (dv != F32_INF_BITS) && (bitcast<u32>(bitcast<f32>(du) + w) == dv); // one f32 add, compared as the bit pattern PD-9 stores; never into an unreached v (an overflowed sum is +Inf too)\n below = bitcast<f32>(du) < bitcast<f32>(dv);\n }\n if (!tight) { continue; }\n var admit = false; // this arc is one key step below v\n if (MODE == 1u) {\n admit = true;\n } else if (P.role == 0u) { // the roots pass (the plateau rule only; bellmanFord seeds the source alone)\n if (P.mode == 0u && below) { atomicMin(&pred[hb + v], 0u); }\n } else if (P.role == 1u) { // a hop pass: one hop along a plateau arc (mode 0) or along any tight arc (mode 1)\n if (P.mode == 1u || du == dv) {\n let old = atomicMin(&pred[hb + v], hu + 1u);\n if (hu + 1u < old) { atomicMax(&pred[2u * hb], P.iteration + 1u); } // this pass changed something\n }\n } else { // the predecessor pass: the smallest tight arc one key step below v\n let hv = atomicLoad(&pred[hb + v]);\n if (P.mode == 1u) { admit = hu + 1u == hv; } else if (hv == 0u) { admit = below; } else { admit = (du == dv) && (hu + 1u == hv); }\n }\n if (admit) { atomicMin(&pred[v], select(a, u, P.predKind == 1u)); }\n }\n }\n}\n`;\n","/**\n * The `sssp-relax` kernel body (design 8.4 \"Davidson's near-far\", 8.10 \"SSSP near-far relax\"; P8-T9, the P8 plan's\n * PD-9 / PD-20 / PD-22 / DEP-P8-E): one round of the near-far shortest-path loop. `dist` is `array<atomic<u32>>`\n * holding the IEEE-754 bit patterns of the f32 distances (`F32_INF_BITS` = unreached), and `atomicMin` on the\n * patterns IS `min` on the values, because for non-negative floats the unsigned bit order is the value order\n * (`+0` is `0x00000000`, every sum of non-negatives under round-to-nearest is `+0` or positive, never `-0`), which\n * the driver's host scan of the weight vector guarantees -- the whole trick, and it needs no float atomic (PD-9).\n * Every candidate is ONE f32 add, `dist[u] + w`, so the settled value is the minimum of a fixed set of f32\n * numbers: order-independent, bitwise reproducible, and bitwise equal to the f32 Dijkstra oracle.\n *\n * Two roles over one body, chosen by `P.role`. Role 0 (the near round) reads the deduped near pile `queueIn`\n * (`counters[0]` entries, at most `P.n`), relaxes every arc of every entry's WHOLE row (never windowed, DEP-P8-E),\n * skips a candidate above `P.cutoffBits` (the CPU port's `dv <= cutoff` guard as `nd > cutoff`), and when its\n * `atomicMin` improved `v` -- this lane alone observed a larger old value, so this lane alone owns the append --\n * appends `v` to the raw near half of `queueOut` (word 0, count word 1) when `nd` is below the threshold\n * (`counters[22]`), else to the raw far half (word `P.edgeCapacity`, count word 21). Role 1 (the pass-through,\n * PD-20) re-buckets the deduped far pile (`counters[20]` entries): an entry whose settled distance fell below the\n * PREVIOUS threshold (`counters[4]`) was appended to near at that improvement and relaxed there, so it is dropped;\n * the rest go back to near or far against the threshold the boundary just raised. The count words are unclamped\n * (the write is guarded by the capacity; `frontier-finalize` role 2 detects a pile above it). The appends are per\n * improving relaxation, one atomic each: inside a per-lane arc loop no workgroup aggregation is possible without the\n * uniform-strip structure of `bfs-fused`, and Davidson's kernel appends per thread too. Grid-strided under a direct\n * dispatch of `planGridStride(n)`: `P.stride` is the plan's, a deduped pile of at most `n` entries is covered in a\n * few trips per lane and `i + stride` never wraps (`U32_MAX` would); the block's `path` word (5 a near round, 6 a\n * far one) makes the other role's dispatch a no-op. No barrier anywhere: the loops may\n * be per lane. Body only (spec 3.5, D9); the text is normative: the sabotage rows of test/helpers/sabotage.ts are\n * textual edits of it.\n */\nexport const ssspRelaxWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn sssp_relax(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let first = linear_id(wid, lid.x);\n let mine = select(5u, 6u, P.role == 1u); // the path word role 2 wrote: 5 a near round, 6 a far pass-through\n let chosen = atomicLoad(&counters[24]) == mine; // the other role's dispatch of the round is a no-op\n let count = select(0u, min(atomicLoad(&counters[select(0u, 20u, P.role == 1u)]), P.n), chosen); // the deduped near or far pile\n let threshold = bitcast<f32>(atomicLoad(&counters[22]));\n let cutoff = bitcast<f32>(P.cutoffBits);\n for (var i = first; i < count; i = i + P.stride) { // no barrier anywhere: the loops may be per lane\n let u = queueIn[i];\n let du = bitcast<f32>(atomicLoad(&dist[u]));\n if (P.role == 1u) { // the pass-through (PD-20): re-bucket a far entry\n if (du < bitcast<f32>(atomicLoad(&counters[4]))) { continue; } // below the previous threshold: relaxed in an earlier bucket\n if (du < threshold) {\n let q = atomicAdd(&counters[1], 1u);\n if (q < P.edgeCapacity) { queueOut[q] = u; }\n } else {\n let q = atomicAdd(&counters[21], 1u);\n if (q < P.edgeCapacity) { queueOut[P.edgeCapacity + q] = u; }\n }\n continue;\n }\n let end = rowPtr[u + 1u];\n for (var a = rowPtr[u]; a < end; a = a + 1u) { // the whole row: never windowed (DEP-P8-E)\n let v = colIdx[a];\n let nd = du + select(1.0, weights[a], HAS_WEIGHTS); // ONE f32 add (PD-9)\n if (nd > cutoff) { continue; } // SsspOptions.cutoff: the CPU port's dv <= cutoff\n let bits = bitcast<u32>(nd);\n let old = atomicMin(&dist[v], bits); // exact on non-negative floats\n if (bits < old) { // this lane improved v, so it owns the append\n if (nd < threshold) {\n let q = atomicAdd(&counters[1], 1u);\n if (q < P.edgeCapacity) { queueOut[q] = v; }\n } else {\n let q = atomicAdd(&counters[21], 1u);\n if (q < P.edgeCapacity) { queueOut[P.edgeCapacity + q] = v; }\n }\n }\n }\n }\n}\n`;\n","/**\n * The `tri-intersect` kernel body (design 8.5): one invocation per ORIENTED arc `(u, v)`; every common target `w` of\n * the oriented rows of `u` and `v` closes a triangle, found exactly once. The rows are sorted by target, so they are\n * intersected by a merge, or -- when one row is more than TRIANGLE_BINARY_SEARCH_RATIO times the other -- by a binary\n * search of each element of the shorter row in the longer. SEARCH forces a path: 0 chooses, 1 always merges, 2\n * always searches (the tier-agreement tests compare the two). `counts` gains one per triangle at `w` as it is found\n * and the arc's triangle count at `u` and `v` once at the end: u32 atomics, so the counts are exact and\n * order-independent. Body only (spec 3.5, D9); normative text.\n */\nexport const triIntersectWgsl = /* wgsl */ `\nfn contains(lo0: u32, hi0: u32, x: u32) -> bool { // binary search of x in colIdx[lo0, hi0), sorted ascending\n var lo = lo0;\n var hi = hi0;\n loop {\n if (lo >= hi) { break; }\n let mid = lo + (hi - lo) / 2u;\n let y = colIdx[mid];\n if (y == x) { return true; }\n if (y < x) { lo = mid + 1u; } else { hi = mid; }\n }\n return false;\n}\n\n@compute @workgroup_size(WG)\nfn tri_intersect(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let a = linear_id(wid, lid.x);\n if (a >= P.count) { return; } // no barrier follows\n let u = src[a];\n let v = colIdx[a];\n let uLo = rowPtr[u];\n let uHi = rowPtr[u + 1u];\n let vLo = rowPtr[v];\n let vHi = rowPtr[v + 1u];\n let du = uHi - uLo;\n let dv = vHi - vLo;\n var search = SEARCH == 2u;\n if (SEARCH == 0u) { search = du / TRIANGLE_BINARY_SEARCH_RATIO > dv || dv / TRIANGLE_BINARY_SEARCH_RATIO > du; }\n var found = 0u;\n if (search) {\n var sLo = uLo;\n var sHi = uHi;\n var lLo = vLo;\n var lHi = vHi;\n if (du > dv) { sLo = vLo; sHi = vHi; lLo = uLo; lHi = uHi; }\n for (var k = sLo; k < sHi; k = k + 1u) {\n let w = colIdx[k];\n if (contains(lLo, lHi, w)) { atomicAdd(&counts[w], 1u); found = found + 1u; }\n }\n } else {\n var i = uLo;\n var j = vLo;\n loop {\n if (i >= uHi || j >= vHi) { break; }\n let x = colIdx[i];\n let y = colIdx[j];\n if (x == y) { atomicAdd(&counts[x], 1u); found = found + 1u; i = i + 1u; j = j + 1u; }\n else if (x < y) { i = i + 1u; }\n else { j = j + 1u; }\n }\n }\n if (found > 0u) { atomicAdd(&counts[u], found); atomicAdd(&counts[v], found); }\n}\n`;\n","/**\n * The `wcc-compress` kernel body (spec 8.3): pointer jumping to the root, reading through `atomicLoad` on the same\n * `array<atomic<u32>>` because WGSL forbids mixing atomic and plain access to one element. The walk is bounded by\n * `P.maxSteps`; a walk that runs out leaves a shorter path, which the next round finishes. The body is normative:\n * a sabotage mutation is a textual edit of it, so it is not restyled.\n */\n\n/** Entry point `wcc_compress`; no overrides. */\nexport const wccCompressWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn wcc_compress(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let first = linear_id(wid, lid.x);\n for (var v = first; v < P.items; v = v + P.stride) {\n var root = atomicLoad(&comp[v]);\n var steps = 0u;\n loop {\n let parent = atomicLoad(&comp[root]);\n if (parent == root) { break; }\n if (steps >= P.maxSteps) { break; }\n steps = steps + 1u;\n root = parent;\n }\n atomicStore(&comp[v], root);\n }\n}\n`;\n","/**\n * The `wcc-link-edges` kernel body (spec 8.3): the each-edge-once link round of Afforest, correct for directed and\n * undirected input alike because `edgeList()` yields every logical edge once in declared orientation (design 10.1).\n * `link_pair` is the same GAP `Link` transcription as wcc-link-sample (each module is composed alone, so the helper\n * is copied, not shared): all-u32 CAS on `comp`, an `array<atomic<u32>>` because WGSL forbids mixing atomic and\n * plain access to one element, with a bounded retry loop (PD-5) and the changed flag at `P.flagIndex` inside the\n * same array (PD-4). The `P.giant` guard is GAP's \"skip the vertices already in the giant component\" and is a pure\n * optimisation -- linking two vertices already in one component is a no-op. The body is normative: a sabotage\n * mutation is a textual edit of it, so it is not restyled.\n */\n\n/** Entry point `wcc_link_edges`; no overrides. */\nexport const wccLinkEdgesWgsl = /* wgsl */ `\nfn link_pair(a: u32, b: u32) {\n var p1 = atomicLoad(&comp[a]);\n var p2 = atomicLoad(&comp[b]);\n var steps = 0u;\n loop {\n if (p1 == p2) { break; }\n if (steps >= P.maxSteps) { atomicStore(&comp[P.flagIndex], 1u); break; }\n steps = steps + 1u;\n let hi = max(p1, p2);\n let lo = min(p1, p2);\n let pHigh = atomicLoad(&comp[hi]);\n if (pHigh == lo) { break; }\n if (pHigh == hi) {\n let swapped = atomicCompareExchangeWeak(&comp[hi], hi, lo);\n if (swapped.exchanged) { atomicStore(&comp[P.flagIndex], 1u); break; }\n }\n p1 = atomicLoad(&comp[atomicLoad(&comp[hi])]);\n p2 = atomicLoad(&comp[lo]);\n }\n}\n\n@compute @workgroup_size(WG)\nfn wcc_link_edges(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let first = linear_id(wid, lid.x);\n for (var e = first; e < P.items; e = e + P.stride) {\n let u = edgeSrc[e];\n let v = edgeDst[e];\n if (u == v) { continue; }\n if (atomicLoad(&comp[u]) == P.giant && atomicLoad(&comp[v]) == P.giant) { continue; }\n link_pair(u, v);\n }\n}\n`;\n","/**\n * The `wcc-link-sample` kernel body (spec 8.3): one of Afforest's sampled link rounds -- every vertex links its\n * r-th neighbour, `colIdx[rowPtr[v] + P.r]`, when it has one. `link_pair` is GAP's `Link` (gapbs/cc.cc lines\n * 40-150) transcribed for WGSL: all-u32 CAS on `comp`, which is `array<atomic<u32>>` because WGSL forbids mixing\n * atomic and plain access to one element, with a bounded retry loop (PD-5). The changed flag is the word at\n * `P.flagIndex` inside the same array (PD-4). The body is normative: a sabotage mutation is a textual edit of it,\n * so it is not restyled.\n */\n\n/** Entry point `wcc_link_sample`; standard USE_PERM / HAS_WEIGHTS only (the body reads neither weights nor a permutation beyond the row select). */\nexport const wccLinkSampleWgsl = /* wgsl */ `\nfn link_pair(a: u32, b: u32) {\n var p1 = atomicLoad(&comp[a]);\n var p2 = atomicLoad(&comp[b]);\n var steps = 0u;\n loop {\n if (p1 == p2) { break; }\n if (steps >= P.maxSteps) { atomicStore(&comp[P.flagIndex], 1u); break; }\n steps = steps + 1u;\n let hi = max(p1, p2);\n let lo = min(p1, p2);\n let pHigh = atomicLoad(&comp[hi]);\n if (pHigh == lo) { break; }\n if (pHigh == hi) {\n let swapped = atomicCompareExchangeWeak(&comp[hi], hi, lo);\n if (swapped.exchanged) { atomicStore(&comp[P.flagIndex], 1u); break; }\n }\n p1 = atomicLoad(&comp[atomicLoad(&comp[hi])]);\n p2 = atomicLoad(&comp[lo]);\n }\n}\n\n@compute @workgroup_size(WG)\nfn wcc_link_sample(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let first = linear_id(wid, lid.x);\n for (var row = first; row < P.items; row = row + P.stride) {\n let v = select(row, perm[row], USE_PERM);\n let a0 = rowPtr[v];\n let a1 = rowPtr[v + 1u];\n if (a0 + P.r < a1) {\n link_pair(v, colIdx[a0 + P.r]);\n }\n }\n}\n`;\n","/**\n * The `wcc-sample` kernel body (spec 8.3 \"a 1,024-entry histogram readback to find the giant component\"): writes\n * the component label of `P.items` pseudo-randomly chosen vertices into `hist`, which the host reads back and takes\n * the mode of (PD-12: GAP's SampleFrequentElement counts on the host too, and a device histogram over component\n * ids would return a bucket, not an id). The sampler uses the prelude's `lowbias32` and `%`, never a bitwise\n * operator on an index.\n */\n\n/** Entry point `wcc_sample`; no overrides. */\nexport const wccSampleWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn wcc_sample(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let i = linear_id(wid, lid.x);\n if (i >= P.items) { return; }\n let v = lowbias32(i + P.r) % P.n;\n hist[i] = atomicLoad(&comp[v]);\n}\n`;\n","/**\n * THE kernel registry (spec 3.5; contract 3.10): every WGSL module the package compiles, keyed by id, with the\n * binding table, the override declarations, the generated uniform / storage blocks and the feature needs from\n * which src/kernel/wgsl.ts emits the bind declarations and src/kernel/pipeline-cache.ts derives the explicit\n * bind-group layouts. A variant cannot exist without an entry here: the compile tests, the bind-group-budget\n * test and PipelineCache.warm() iterate this table. P1-T4 lands degree, reduce, fill, fa2-repulsion-exact (K3)\n * and fa2-speed-finalize (K4) together with every generated block of contract 3.10.2; P2-T2 lands\n * segmented-reduce; P3-T2 adds fa2-stats-finalize (K1), fa2-attraction (K2), fa2-integrate (K5) and\n * fa2-to-scene; M8b-T3 adds the seven P7 entries: spmv-pull, pr-scale, pr-finalize, wcc-link-sample,\n * wcc-link-edges, wcc-compress and wcc-sample. P4-T1 adds indirect-finalize; the other P4 entries follow, one task\n * each (the P4 plan, PD-1). P8-T3 opens the P8 run of nine appends (the P8 plan, PD-2) with compact-scatter,\n * dedupe-claim and dedupe-filter; P8-T4 adds frontier-finalize with the FrontierCounters and FrontierParams blocks;\n * P8-T5 adds advance-expand; P8-T6 adds bfs-contract and sssp-pred; P8-T7 adds bfs-fused; P8-T8 adds bfs-bottom-up,\n * bfs-bitset-build and bfs-unvisited-flags; P8-T9 adds sssp-relax; P8-T10 adds bf-relax with the BfParams and BfFlags\n * blocks; closeness adds closeness-level and closeness-rowsum with the ClosenessParams block; P9 (betweenness) adds bc-finalize, bc-forward,\n * bc-backward, bc-gather, bc-edge-gather, bc-forward-edge and bc-count (issue #719) with the BcParams block; all-pairs shortest paths\n * (design 8.7) adds apsp-init and apsp-fw with the ApspParams block. P11 (the structure and community phase, plan\n * design/webgpu/plans/2026-09-23-webgpu-p11-structure-and-community.md) adds the graph build on the device (coo-emit,\n * run-flags, coo-scatter), the per-row group-by-key (group-by-key-row), label propagation's step (lpa-step) and\n * triangle counting (orient-flags, tri-intersect), and Boruvka's minimum spanning tree adds mst-best and mst-link\n * with the MstParams block. This file is the only importer of src/wgsl/** (spec 3.2;\n * test/layers.test.ts).\n */\n\nimport { STATE_HEADER_BYTES } from \"./constants.js\";\nimport { WebGpuGraphError } from \"./errors.js\";\nimport { UniformBlock } from \"./kernel/struct-block.js\";\nimport { type BindingDecl, type OverrideDecl, type WgslModuleSpec } from \"./kernel/wgsl.js\";\nimport { type CoreBinding } from \"./memory/residency.js\";\nimport { type Binding } from \"./types/memory.js\";\nimport { advanceExpandWgsl } from \"./wgsl/advance-expand.wgsl.js\";\nimport { apspFwWgsl } from \"./wgsl/apsp-fw.wgsl.js\";\nimport { apspInitWgsl } from \"./wgsl/apsp-init.wgsl.js\";\nimport { bcBackwardWgsl } from \"./wgsl/bc-backward.wgsl.js\";\nimport { bcCountWgsl } from \"./wgsl/bc-count.wgsl.js\";\nimport { bcEdgeGatherWgsl } from \"./wgsl/bc-edge-gather.wgsl.js\";\nimport { bcFinalizeWgsl } from \"./wgsl/bc-finalize.wgsl.js\";\nimport { bcForwardWgsl } from \"./wgsl/bc-forward.wgsl.js\";\nimport { bcForwardEdgeWgsl } from \"./wgsl/bc-forward-edge.wgsl.js\";\nimport { bcGatherWgsl } from \"./wgsl/bc-gather.wgsl.js\";\nimport { bfRelaxWgsl } from \"./wgsl/bf-relax.wgsl.js\";\nimport { bfsBitsetBuildWgsl } from \"./wgsl/bfs-bitset-build.wgsl.js\";\nimport { bfsBottomUpWgsl } from \"./wgsl/bfs-bottom-up.wgsl.js\";\nimport { bfsContractWgsl } from \"./wgsl/bfs-contract.wgsl.js\";\nimport { bfsFusedWgsl } from \"./wgsl/bfs-fused.wgsl.js\";\nimport { bfsNextDegreeWgsl } from \"./wgsl/bfs-next-degree.wgsl.js\";\nimport { bfsUnvisitedFlagsWgsl } from \"./wgsl/bfs-unvisited-flags.wgsl.js\";\nimport { closenessLevelWgsl } from \"./wgsl/closeness-level.wgsl.js\";\nimport { closenessRowsumWgsl } from \"./wgsl/closeness-rowsum.wgsl.js\";\nimport { compactScatterWgsl } from \"./wgsl/compact-scatter.wgsl.js\";\nimport { cooEmitWgsl } from \"./wgsl/coo-emit.wgsl.js\";\nimport { cooScatterWgsl } from \"./wgsl/coo-scatter.wgsl.js\";\nimport { countingScatterWgsl } from \"./wgsl/counting-scatter.wgsl.js\";\nimport { dedupeClaimWgsl } from \"./wgsl/dedupe-claim.wgsl.js\";\nimport { dedupeFilterWgsl } from \"./wgsl/dedupe-filter.wgsl.js\";\nimport { degreeWgsl } from \"./wgsl/degree.wgsl.js\";\nimport { fa2AttractionWgsl } from \"./wgsl/fa2-attraction.wgsl.js\";\nimport { fa2IntegrateWgsl } from \"./wgsl/fa2-integrate.wgsl.js\";\nimport { fa2RepulsionExactWgsl } from \"./wgsl/fa2-repulsion-exact.wgsl.js\";\nimport { fa2SpeedFinalizeWgsl } from \"./wgsl/fa2-speed-finalize.wgsl.js\";\nimport { fa2StatsFinalizeWgsl } from \"./wgsl/fa2-stats-finalize.wgsl.js\";\nimport { fa2ToSceneWgsl } from \"./wgsl/fa2-to-scene.wgsl.js\";\nimport { fillWgsl } from \"./wgsl/fill.wgsl.js\";\nimport { frontierFinalizeWgsl } from \"./wgsl/frontier-finalize.wgsl.js\";\nimport { gridCellKeyWgsl } from \"./wgsl/grid-cell-key.wgsl.js\";\nimport { gridCentroidWgsl } from \"./wgsl/grid-centroid.wgsl.js\";\nimport { gridCentroidHubWgsl } from \"./wgsl/grid-centroid-hub.wgsl.js\";\nimport { gridDownsampleWgsl } from \"./wgsl/grid-downsample.wgsl.js\";\nimport { gridFarFieldWgsl } from \"./wgsl/grid-far-field.wgsl.js\";\nimport { gridNearFieldWgsl } from \"./wgsl/grid-near-field.wgsl.js\";\nimport { groupByKeyRowWgsl } from \"./wgsl/group-by-key-row.wgsl.js\";\nimport { histogramWgsl } from \"./wgsl/histogram.wgsl.js\";\nimport { indirectFinalizeWgsl } from \"./wgsl/indirect-finalize.wgsl.js\";\nimport { lpaStepWgsl } from \"./wgsl/lpa-step.wgsl.js\";\nimport { mstBestWgsl } from \"./wgsl/mst-best.wgsl.js\";\nimport { mstLinkWgsl } from \"./wgsl/mst-link.wgsl.js\";\nimport { orientFlagsWgsl } from \"./wgsl/orient-flags.wgsl.js\";\nimport { prFinalizeWgsl } from \"./wgsl/pr-finalize.wgsl.js\";\nimport { prScaleWgsl } from \"./wgsl/pr-scale.wgsl.js\";\nimport { radixHistWgsl } from \"./wgsl/radix-hist.wgsl.js\";\nimport { radixScatterWgsl } from \"./wgsl/radix-scatter.wgsl.js\";\nimport { reduceWgsl } from \"./wgsl/reduce.wgsl.js\";\nimport { runFlagsWgsl } from \"./wgsl/run-flags.wgsl.js\";\nimport { scanAddWgsl } from \"./wgsl/scan-add.wgsl.js\";\nimport { scanBlockWgsl } from \"./wgsl/scan-block.wgsl.js\";\nimport { segmentedReduceWgsl } from \"./wgsl/segmented-reduce.wgsl.js\";\nimport { spmvPullWgsl } from \"./wgsl/spmv-pull.wgsl.js\";\nimport { ssspPredWgsl } from \"./wgsl/sssp-pred.wgsl.js\";\nimport { ssspRelaxWgsl } from \"./wgsl/sssp-relax.wgsl.js\";\nimport { triIntersectWgsl } from \"./wgsl/tri-intersect.wgsl.js\";\nimport { wccCompressWgsl } from \"./wgsl/wcc-compress.wgsl.js\";\nimport { wccLinkEdgesWgsl } from \"./wgsl/wcc-link-edges.wgsl.js\";\nimport { wccLinkSampleWgsl } from \"./wgsl/wcc-link-sample.wgsl.js\";\nimport { wccSampleWgsl } from \"./wgsl/wcc-sample.wgsl.js\";\n\n/** Every module id of P1-P4, P7, P8, P9 and P11 (later ids are appended, never renamed). */\nexport type KernelId =\n | \"degree\"\n | \"reduce\"\n | \"fill\"\n | \"segmented-reduce\"\n | \"fa2-stats-finalize\"\n | \"fa2-attraction\"\n | \"fa2-repulsion-exact\"\n | \"fa2-speed-finalize\"\n | \"fa2-integrate\"\n | \"fa2-to-scene\"\n | \"spmv-pull\"\n | \"pr-scale\"\n | \"pr-finalize\"\n | \"wcc-link-sample\"\n | \"wcc-link-edges\"\n | \"wcc-compress\"\n | \"wcc-sample\"\n | \"indirect-finalize\"\n | \"scan-block\"\n | \"scan-add\"\n | \"histogram\"\n | \"counting-scatter\"\n | \"radix-hist\"\n | \"radix-scatter\"\n | \"grid-cell-key\"\n | \"grid-centroid\"\n | \"grid-centroid-hub\"\n | \"grid-downsample\"\n | \"grid-far-field\"\n | \"grid-near-field\"\n | \"compact-scatter\"\n | \"dedupe-claim\"\n | \"dedupe-filter\"\n | \"frontier-finalize\"\n | \"advance-expand\"\n | \"bfs-contract\"\n | \"sssp-pred\"\n | \"bfs-fused\"\n | \"bfs-bottom-up\"\n | \"bfs-bitset-build\"\n | \"bfs-unvisited-flags\"\n | \"bfs-next-degree\"\n | \"sssp-relax\"\n | \"bf-relax\"\n | \"closeness-level\"\n | \"closeness-rowsum\"\n | \"bc-finalize\"\n | \"bc-forward\"\n | \"bc-backward\"\n | \"bc-gather\"\n | \"bc-count\"\n | \"bc-edge-gather\"\n | \"bc-forward-edge\"\n | \"apsp-init\"\n | \"apsp-fw\"\n | \"coo-emit\"\n | \"run-flags\"\n | \"coo-scatter\"\n | \"orient-flags\"\n | \"tri-intersect\"\n | \"group-by-key-row\"\n | \"lpa-step\"\n | \"mst-best\"\n | \"mst-link\";\n\n/** One registry entry: everything of a WgslModuleSpec except the per-variant overrides and snippets. */\nexport interface KernelEntry {\n readonly id: KernelId;\n readonly body: string;\n readonly entryPoint: string;\n readonly bindings: readonly BindingDecl[];\n readonly overrideDecls: readonly OverrideDecl[];\n readonly uniforms: readonly UniformBlock[];\n /** [\"subgroups\"] when the body calls a reduction helper (the twin axis), else []. */\n readonly needs: readonly \"subgroups\"[];\n /** The snippet marker names the body carries (segmented-reduce: [\"VALUE\"]). */\n readonly snippetSlots: readonly string[];\n /** The phase the entry landed in (documentation and the compile-matrix filter). */\n readonly phase: \"P1\" | \"P2\" | \"P3\" | \"P4\" | \"P7\" | \"P8\" | \"P9\" | \"P11\";\n}\n\n// ---- the generated blocks (spec 5.3; contract 3.10.2): field order = byte order, offsets in the JSDoc\n\n/** `RangeParams` (uniform, 32 B): rows `[start, end)` @0 / @4 of the dispatch, the bound arc window `[arcBase, arcEnd)` @8 / @12 (0 and arcCount when not windowed), `accumulate` @16 (1 combines into `out[i]` instead of overwriting: the P4 windowed loop), `n` @20 (the node count that bounds neighbour indices), `pad0` @24, `pad1` @28. */\nexport const RANGE_PARAMS: UniformBlock = UniformBlock.define(\"RangeParams\", [\n [\"start\", \"u32\"],\n [\"end\", \"u32\"],\n [\"arcBase\", \"u32\"],\n [\"arcEnd\", \"u32\"],\n [\"accumulate\", \"u32\"],\n [\"n\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n]);\n\n/** `ReduceParams` (uniform, 16 B): `count` @0 elements of the level, `outOffset` @4 (the element index the level writes at), `level` @8, `pad0` @12. */\nexport const REDUCE_PARAMS: UniformBlock = UniformBlock.define(\"ReduceParams\", [\n [\"count\", \"u32\"],\n [\"outOffset\", \"u32\"],\n [\"level\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `FillParams` (uniform, 16 B): `count` @0 words, `value` @4, `mode` @8 (0 = the constant `value`, 1 = iota `i + value`), `pad0` @12. */\nexport const FILL_PARAMS: UniformBlock = UniformBlock.define(\"FillParams\", [\n [\"count\", \"u32\"],\n [\"value\", \"u32\"],\n [\"mode\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `Fa2Params` (uniform, 144 B; spec 7.3): the per-iteration ForceAtlas2 parameters -- `n` @0, `dim` @4, `flags` @8 (bit 0 = FA2_FLAG_FIRST), `tierStart` @12, `tierEnd` @16, `iterationIndex` @20, `seed` @24, `nearMax` @28, `scalingRatio` @32, `gravity` @36, `jitterTolerance` @40, `scale` @44, `center` @48 (xyz, w 0), `settleThreshold` @64, `extentFactor` @68, `gridMax` @72, `levels` @76, `arcBase` @80 / `arcEnd` @84 (the bound arc window of K2, 0 and arcCount in the layout), `accumulate` @88 (1 combines into `force`: the windowed pattern), `hiEnd` @92 / `midEnd` @124 (the degreeOrder tier boundaries, PD-7; both 0 without a permutation); the P5 model fields (PD-3): `frK` @96 (the FR optimal distance), `temperature` @100 (the FR temperature of this iteration), `springLength` @104, `springCoefficient` @108, `coulomb` @112 (ngraph's `gravity`, negative repels), `dragCoefficient` @116, `timeStep` @120; `settleFloor` @128 (the absolute bound on the mean displacement of a settled iteration, in layout units: issue #97); 144 B. */\nexport const FA2_PARAMS: UniformBlock = UniformBlock.define(\"Fa2Params\", [\n [\"n\", \"u32\"],\n [\"dim\", \"u32\"],\n [\"flags\", \"u32\"],\n [\"tierStart\", \"u32\"],\n [\"tierEnd\", \"u32\"],\n [\"iterationIndex\", \"u32\"],\n [\"seed\", \"u32\"],\n [\"nearMax\", \"u32\"],\n [\"scalingRatio\", \"f32\"],\n [\"gravity\", \"f32\"],\n [\"jitterTolerance\", \"f32\"],\n [\"scale\", \"f32\"],\n [\"center\", \"vec4f\"],\n [\"settleThreshold\", \"f32\"],\n [\"extentFactor\", \"f32\"],\n [\"gridMax\", \"u32\"],\n [\"levels\", \"u32\"],\n [\"arcBase\", \"u32\"],\n [\"arcEnd\", \"u32\"],\n [\"accumulate\", \"u32\"],\n [\"hiEnd\", \"u32\"],\n [\"frK\", \"f32\"],\n [\"temperature\", \"f32\"],\n [\"springLength\", \"f32\"],\n [\"springCoefficient\", \"f32\"],\n [\"coulomb\", \"f32\"],\n [\"dragCoefficient\", \"f32\"],\n [\"timeStep\", \"f32\"],\n [\"midEnd\", \"u32\"],\n [\"settleFloor\", \"f32\"],\n]);\n\n/** `Fa2State` (storage, padded to STATE_HEADER_BYTES = 256; spec 7.3): the device-resident controller state the finalize kernels write and the host reads back for stats -- `speed` @0, `speedEfficiency` @4, `swing` @8, `traction` @12, `centroid` @16, `rmsRadius` @32, `radius` @36, `meanDisplacement` @40, `iteration` @44, `min` @48, `max` @64, `gridMin` @80 (P4), `eps` @96 (P4), `settledCount` @100, `outsideGrid` @104 (P4), `maxCellOccupancy` @108 (P4), `temperature` @112 (FR, written by K1 under STATS_MODE 1), `kineticEnergy` @116 (the preset, K1 under STATS_MODE 2), `frEnergy` @120 / `frProgress` @124 (the FR adaptive cooling), `invCellSize` @128 (P4, PD-10: `1 / cellSize`, written by K1 beside `cellSize` in `gridMin.w`; G1 multiplies by it so every key is bitwise reproducible), `reserved0` @132 (f32), `reserved1` @136 (vec2f), `reserved2` .. `reserved8` @144 .. @240. */\nexport const FA2_STATE: UniformBlock = UniformBlock.define(\n \"Fa2State\",\n [\n [\"speed\", \"f32\"],\n [\"speedEfficiency\", \"f32\"],\n [\"swing\", \"f32\"],\n [\"traction\", \"f32\"],\n [\"centroid\", \"vec4f\"],\n [\"rmsRadius\", \"f32\"],\n [\"radius\", \"f32\"],\n [\"meanDisplacement\", \"f32\"],\n [\"iteration\", \"u32\"],\n [\"min\", \"vec4f\"],\n [\"max\", \"vec4f\"],\n [\"gridMin\", \"vec4f\"],\n [\"eps\", \"f32\"],\n [\"settledCount\", \"u32\"],\n [\"outsideGrid\", \"u32\"],\n [\"maxCellOccupancy\", \"u32\"],\n [\"temperature\", \"f32\"],\n [\"kineticEnergy\", \"f32\"],\n [\"frEnergy\", \"f32\"],\n [\"frProgress\", \"u32\"],\n [\"invCellSize\", \"f32\"],\n [\"reserved0\", \"f32\"],\n [\"reserved1\", \"vec2f\"],\n [\"reserved2\", \"vec4f\"],\n [\"reserved3\", \"vec4f\"],\n [\"reserved4\", \"vec4f\"],\n [\"reserved5\", \"vec4f\"],\n [\"reserved6\", \"vec4f\"],\n [\"reserved7\", \"vec4f\"],\n [\"reserved8\", \"vec4f\"],\n ],\n { layout: \"storage\", padTo: STATE_HEADER_BYTES },\n);\n\n/** `Fa2Trace` (storage record, 32 B; spec 7.3): one per-iteration trace record -- `swing` @0, `traction` @4, `speed` @8, `speedEfficiency` @12 (written by K4), `meanDisplacement` @16, `settledCount` @20, `iteration` @24 (written by K1), `modelScalar` @28 (K1: the temperature under STATS_MODE 1, the kinetic energy under 2, 0 under 0); the trace region is `array<Fa2Trace>` at byte offset STATE_HEADER_BYTES of the state buffer. */\nexport const FA2_TRACE: UniformBlock = UniformBlock.define(\n \"Fa2Trace\",\n [\n [\"swing\", \"f32\"],\n [\"traction\", \"f32\"],\n [\"speed\", \"f32\"],\n [\"speedEfficiency\", \"f32\"],\n [\"meanDisplacement\", \"f32\"],\n [\"settledCount\", \"u32\"],\n [\"iteration\", \"u32\"],\n [\"modelScalar\", \"f32\"],\n ],\n { layout: \"storage\" },\n);\n\n/** `Fa2Partial` (storage record, 64 B; spec 7.3): one per-workgroup partial -- `sum` @0 (xyz = sum of positions, w = sum of |p - centroid|^2), `min` @16, `max` @32 (w = max of |p - centroid|^2, the exact layoutRadius source), written by K5; `swingTraction` @48 (written by K3's epilogue); `dispFree` @56 (x = sum |dp| over free rows, y = the free count as an f32 <= 256, written by K5). */\nexport const FA2_PARTIAL: UniformBlock = UniformBlock.define(\n \"Fa2Partial\",\n [\n [\"sum\", \"vec4f\"],\n [\"min\", \"vec4f\"],\n [\"max\", \"vec4f\"],\n [\"swingTraction\", \"vec2f\"],\n [\"dispFree\", \"vec2f\"],\n ],\n { layout: \"storage\" },\n);\n\n/** `SpmvParams` (uniform, 32 B; spec 8.2): `n` @0 rows of the pull, the bound arc window `[arcBase, arcEnd)` @4 / @8 (0 and arcCount when not windowed), the grid-stride step `stride` @12, `alpha` @16, `beta` @20 (the `1 - alpha` term), `uniformP` @24 (the uniform personalization mass `1 / n`, 0 for a pure SpMV), `start` @28 (the first row of the dispatch; TIER 0 strides from it, the tiers index from it). */\nexport const SPMV_PARAMS: UniformBlock = UniformBlock.define(\"SpmvParams\", [\n [\"n\", \"u32\"],\n [\"arcBase\", \"u32\"],\n [\"arcEnd\", \"u32\"],\n [\"stride\", \"u32\"],\n [\"alpha\", \"f32\"],\n [\"beta\", \"f32\"],\n [\"uniformP\", \"f32\"],\n [\"start\", \"u32\"],\n]);\n\n/** `PrParams` (uniform, 32 B; spec 8.2): `n` @0, `groups` @4 (the per-workgroup partial count the finalize folds), `iteration` @8 (1-based), `trackConvergence` @12 (1 records firstConverged), `convergeThreshold` @16 (`tolerance * n`, the design's `delta < tol * n`), `pad0` @20, `pad1` @24, `pad2` @28. */\nexport const PR_PARAMS: UniformBlock = UniformBlock.define(\"PrParams\", [\n [\"n\", \"u32\"],\n [\"groups\", \"u32\"],\n [\"iteration\", \"u32\"],\n [\"trackConvergence\", \"u32\"],\n [\"convergeThreshold\", \"f32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n [\"pad2\", \"u32\"],\n]);\n\n/**\n * `PrPartial` (storage record, 32 B; spec 8.2). Element 0 is the HEADER, whose first 16 bytes are exactly the four\n * fields the design names -- `danglingMass` @0, `delta` @4, `firstConvergedIteration` @8, `iteration` @12 -- plus\n * `norm` @16, which M8b adds so HITS / eigenvector / Katz keep their normaliser on the device (PD-10). Element\n * `1 + g` is workgroup g's partial: it uses `danglingMass`, `delta` and `norm` as three sums and leaves the two u32\n * fields zero.\n */\nexport const PR_PARTIAL: UniformBlock = UniformBlock.define(\n \"PrPartial\",\n [\n [\"danglingMass\", \"f32\"],\n [\"delta\", \"f32\"],\n [\"firstConverged\", \"u32\"],\n [\"iteration\", \"u32\"],\n [\"norm\", \"f32\"],\n [\"pad0\", \"f32\"],\n [\"pad1\", \"f32\"],\n [\"pad2\", \"f32\"],\n ],\n { layout: \"storage\" },\n);\n\n/** `WccParams` (uniform, 32 B; spec 8.3): `n` @0, `items` @4 (rows for a sample round, edges for an edge round, 1024 for the sampler), `stride` @8, `r` @12 (the neighbour index of the sampled round, and the sampler's seed), `flagIndex` @16 (the changed word inside `comp`, PD-4), `giant` @20 (`U32_MAX` before the sample), `maxSteps` @24, `pad0` @28. */\nexport const WCC_PARAMS: UniformBlock = UniformBlock.define(\"WccParams\", [\n [\"n\", \"u32\"],\n [\"items\", \"u32\"],\n [\"stride\", \"u32\"],\n [\"r\", \"u32\"],\n [\"flagIndex\", \"u32\"],\n [\"giant\", \"u32\"],\n [\"maxSteps\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `IndirectParams` (uniform, 16 B; spec 5.4): `countIndex` @0 (the word of `counters` holding the count), `wg` @4 (the consumer's workgroup size), `slot` @8 (the 16-byte args slot to write), `pad0` @12. */\nexport const INDIRECT_PARAMS: UniformBlock = UniformBlock.define(\"IndirectParams\", [\n [\"countIndex\", \"u32\"],\n [\"wg\", \"u32\"],\n [\"slot\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `ScanParams` (uniform, 16 B; spec 6 row 2): `count` @0 (the u32 words of the level), `pad0` @4, `pad1` @8, `pad2` @12. */\nexport const SCAN_PARAMS: UniformBlock = UniformBlock.define(\"ScanParams\", [\n [\"count\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n [\"pad2\", \"u32\"],\n]);\n\n/** `GridLevelParams` (uniform, 32 B; spec 7.7 G5, P4-T9): `childBase` @0 and `parentBase` @4 (the first cell of the child / parent level inside the pyramid), `parentSide` @8, `parentCells` @12 (`parentSide^dim`), `depth` @16 (1 in 2D, 2 in 3D), `pad0` @20, `pad1` @24, `pad2` @28. */\nexport const GRID_LEVEL_PARAMS: UniformBlock = UniformBlock.define(\"GridLevelParams\", [\n [\"childBase\", \"u32\"],\n [\"parentBase\", \"u32\"],\n [\"parentSide\", \"u32\"],\n [\"parentCells\", \"u32\"],\n [\"depth\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n [\"pad2\", \"u32\"],\n]);\n\n/** `HistParams` (uniform, 16 B; spec 6 row 5): `count` @0 (the keys), `bins` @4 (a key >= bins is not counted), `pad0` @8, `pad1` @12. */\nexport const HIST_PARAMS: UniformBlock = UniformBlock.define(\"HistParams\", [\n [\"count\", \"u32\"],\n [\"bins\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n]);\n\n/** `RadixParams` (uniform, 16 B; spec 6 row 6): `count` @0 (the pairs), `shift` @4 (the pass's digit shift, 8 x pass), `groups` @8 (ceil(count / WG), the stride of the digit-major table), `pad0` @12. */\nexport const RADIX_PARAMS: UniformBlock = UniformBlock.define(\"RadixParams\", [\n [\"count\", \"u32\"],\n [\"shift\", \"u32\"],\n [\"groups\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `CompactParams` (uniform, 16 B; spec 6 row 4, P8-T3): `count` @0 (the entries, or the capacity a device count is clamped to), `outIndex` @4 (the word of `outCount` that receives the output count: the block is bound whole because a four-byte word is never 256-aligned), `countIndex` @8 (the word of the counters block holding the entry count, or `U32_MAX` for a host-known count; `compact-scatter` ignores it), `pad0` @12. */\nexport const COMPACT_PARAMS: UniformBlock = UniformBlock.define(\"CompactParams\", [\n [\"count\", \"u32\"],\n [\"outIndex\", \"u32\"],\n [\"countIndex\", \"u32\"],\n [\"stride\", \"u32\"],\n]);\n\n/**\n * `FrontierCounters` (storage, 112 B; design 6 row 7, P8-T4, PD-8): EVERY counter of the frontier family is a word of\n * this one block, byte offset 4 x index, because a four-byte word is never a legal storage-binding offset and the\n * device-side selector must reach every count it acts on through one binding; every kernel binds it as\n * `array<atomic<u32>>` and indexes by the `W` record of src/primitives/frontier.ts, and the host decodes the result\n * copy with `FRONTIER_COUNTERS.read`. `frontierCount` @0 (role 0 rotates it in from word 1; never seeded),\n * `nextFrontierCount` @4 (the claim kernels' append span; the BFS seed is 1), `frontierDegreeSum` @8,\n * `prevFrontierCount` @12, `prevDegreeSum` @16, `unvisitedCount` @20, `unvisitedDegreeSum` @24,\n * `unvisitedListLen` @28 (P8-T8), `edgeCount` @32 (clamped by role 1), `edgeCountUnclamped` @36 (the overflow\n * detector, PD-23), `overflowLevels` @40, `level` @44 (the current level; the seed is U32_MAX so the first boundary\n * lands on 0), `visitedCount` @48, `switches` @52, `direction` @56, `done` @60 (the four bytes the host reads per\n * submit), `arcsScanned` @64, `fusedLevels` @68, `twoPhaseLevels` @72, `bottomUpLevels` @76, `farCount` @80,\n * `nextFarCount` @84, `thresholdBits` @88, `deltaBits` @92 (P8-T9), `path` @96 (what the level's kernels run, written\n * by the selector: 0 nothing, 1 two-phase, 2 fused, 3 bottom-up, 4 the fused retry, 5 a near SSSP round, 6 a far\n * one; every level kernel is a direct dispatch that reads it first -- G8-F5), `nextDegreeSum` @100 (issue #391: the\n * out-degree sum of the vertices the level claimed, accumulated by `bfs-next-degree` at the end of every level and\n * read, subtracted and zeroed by the next boundary -- Beamer's m_f measured on the frontier the boundary decides\n * for, not on the one it has just expanded); `stackTop` @104 (betweenness: the append cursor of the claim log, which\n * `bc-finalize` also writes into `ends` at every level boundary) and `sigmaOverflow` @108 (betweenness: 1 once a\n * rescaled path count left f32's normal range) are APPENDED so every earlier word keeps its byte offset. The words nothing writes before P8-T8 / P8-T9 are declared now because\n * the byte layout is what the single result copy decodes.\n */\nexport const FRONTIER_COUNTERS: UniformBlock = UniformBlock.define(\n \"FrontierCounters\",\n [\n [\"frontierCount\", \"u32\"],\n [\"nextFrontierCount\", \"u32\"],\n [\"frontierDegreeSum\", \"u32\"],\n [\"prevFrontierCount\", \"u32\"],\n [\"prevDegreeSum\", \"u32\"],\n [\"unvisitedCount\", \"u32\"],\n [\"unvisitedDegreeSum\", \"u32\"],\n [\"unvisitedListLen\", \"u32\"],\n [\"edgeCount\", \"u32\"],\n [\"edgeCountUnclamped\", \"u32\"],\n [\"overflowLevels\", \"u32\"],\n [\"level\", \"u32\"],\n [\"visitedCount\", \"u32\"],\n [\"switches\", \"u32\"],\n [\"direction\", \"u32\"],\n [\"done\", \"u32\"],\n [\"arcsScanned\", \"u32\"],\n [\"fusedLevels\", \"u32\"],\n [\"twoPhaseLevels\", \"u32\"],\n [\"bottomUpLevels\", \"u32\"],\n [\"farCount\", \"u32\"],\n [\"nextFarCount\", \"u32\"],\n [\"thresholdBits\", \"u32\"],\n [\"deltaBits\", \"u32\"],\n [\"path\", \"u32\"],\n [\"nextDegreeSum\", \"u32\"],\n [\"stackTop\", \"u32\"],\n [\"sigmaOverflow\", \"u32\"],\n ],\n { layout: \"storage\" },\n);\n\n/**\n * `FrontierParams` (uniform, 80 B; P8-T4): the params block every P8 kernel except the three compact / dedupe\n * primitives and `bf-relax` binds -- `role` @0 (the finalize role), `wg` @4 (the consumers' workgroup size),\n * `alpha` @8, `beta` @12 (Beamer's thresholds, P8-T8), `fusedMax` @16, `edgeCapacity` @20, `maxDepth` @24, `n` @28,\n * `mode` @32 (BFS: 0 auto, 1 top-down only; `sssp-pred`: the PD-27 key rule), `cutoffBits` @36, `arcBase` @40,\n * `arcEnd` @44 (the bound arc window), `predKind` @48 (0 arc, 1 node), `bitsBase` @52, `source` @56, `stride` @60\n * (a grid-stride plan's stride), `firstOfSubmit` @64 (the boundary's index inside its submit, clamped to 1: both\n * the unvisited-count and the unvisited-degree-sum subtraction run at >= 1, issue #391), `iteration` @68 (an\n * `sssp-pred` hop pass, P8-T9), `pad3` @72, `pad2` @76. The `slotBase` field that once addressed the selector's indirect slots went with\n * the slots (2026-09-25); `pad2` keeps the block an explicit 80 bytes, the way every block here is padded.\n */\nexport const FRONTIER_PARAMS: UniformBlock = UniformBlock.define(\"FrontierParams\", [\n [\"role\", \"u32\"],\n [\"wg\", \"u32\"],\n [\"alpha\", \"u32\"],\n [\"beta\", \"u32\"],\n [\"fusedMax\", \"u32\"],\n [\"edgeCapacity\", \"u32\"],\n [\"maxDepth\", \"u32\"],\n [\"n\", \"u32\"],\n [\"mode\", \"u32\"],\n [\"cutoffBits\", \"u32\"],\n [\"arcBase\", \"u32\"],\n [\"arcEnd\", \"u32\"],\n [\"predKind\", \"u32\"],\n [\"bitsBase\", \"u32\"],\n [\"source\", \"u32\"],\n [\"stride\", \"u32\"],\n [\"firstOfSubmit\", \"u32\"],\n [\"iteration\", \"u32\"],\n [\"pad3\", \"u32\"],\n [\"pad2\", \"u32\"],\n]);\n\n/** `BcParams` (uniform, 32 B; betweenness): `n` @0, `k` @4 (the batch's sources), `start` @8 (the first log index of a backward level), `count` @12 (a backward level's entries, or the edge count of `bc-forward-edge`), `stride` @16 (a grid-stride plan's stride), `role` @20 (`bc-finalize`: 0 the level boundary, 1 the seed), `pad0` @24, `pad1` @28. */\nexport const BC_PARAMS: UniformBlock = UniformBlock.define(\"BcParams\", [\n [\"n\", \"u32\"],\n [\"k\", \"u32\"],\n [\"start\", \"u32\"],\n [\"count\", \"u32\"],\n [\"stride\", \"u32\"],\n [\"role\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n]);\n\n/**\n * `ClosenessParams` (uniform, 64 B): the params of `closeness-level` and `closeness-rowsum` -- `role` @0 (level: 0 a\n * level, 1 the seed's clear, 2 the seed's sources; rowsum: 0 integer, 1 f32, 2 harmonic), `n` @4, `words` @8 (32-bit\n * words per node, so `32 x words` sources per batch), `base` @12 (the words of one `bits` region), `total` @16 (the\n * words the clear zeroes), `level` @20, `row` @24 (the level's row of the submit's count table), `ctrl` @28 (the word\n * of the control ring in `table`), `count` @32 (the batch's sources), `source` @36 (its first source, or its first\n * word of the source list), `sourcesAt` @40 (the word of a sampled run's source list in `table`, 0 for the exact\n * run), `pullAt` @44 (the frontier arcs above which a level pulls), `perNode` @48 (1: a sampled run's per-node\n * distance sums), `arcCount` @52 (the arcs a push level covers), `pullOk` @56 (1: a level may pull), `pad0` @60.\n */\nexport const CLOSENESS_PARAMS: UniformBlock = UniformBlock.define(\"ClosenessParams\", [\n [\"role\", \"u32\"],\n [\"n\", \"u32\"],\n [\"words\", \"u32\"],\n [\"base\", \"u32\"],\n [\"total\", \"u32\"],\n [\"level\", \"u32\"],\n [\"row\", \"u32\"],\n [\"ctrl\", \"u32\"],\n [\"count\", \"u32\"],\n [\"source\", \"u32\"],\n [\"sourcesAt\", \"u32\"],\n [\"pullAt\", \"u32\"],\n [\"perNode\", \"u32\"],\n [\"arcCount\", \"u32\"],\n [\"pullOk\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `BfParams` (uniform, 16 B; P8-T10): `edgeCount` @0 (the logical edges of the `edgeList` view), `stride` @4 (the grid-stride plan's stride), `maxRetries` @8 (PD-12's compare-exchange bound), `cutoffBits` @12 (the f32 bit pattern of the CPU port's `cutoff`, `+Inf` when absent). */\nexport const BF_PARAMS: UniformBlock = UniformBlock.define(\"BfParams\", [\n [\"edgeCount\", \"u32\"],\n [\"stride\", \"u32\"],\n [\"maxRetries\", \"u32\"],\n [\"cutoffBits\", \"u32\"],\n]);\n\n/** `BfFlags` (storage, 16 B; P8-T10): the two words `bf-relax` raises and the host reads back after every batch of rounds -- `changed` @0 (some exchange succeeded), `retryExhausted` @4 (some lane hit `maxRetries`, PD-12), `pad0` @8, `pad1` @12. Bound by the kernel as `array<atomic<u32>>`; the block is the host's decoder. */\nexport const BF_FLAGS: UniformBlock = UniformBlock.define(\n \"BfFlags\",\n [\n [\"changed\", \"u32\"],\n [\"retryExhausted\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n ],\n { layout: \"storage\" },\n);\n\n/** `ApspParams` (uniform, 16 B; design 8.7): `n` @0 (the node count, the matrix side), `round` @4 (the pivot block index of the blocked Floyd-Warshall round), `blocks` @8 (`ceil(n / APSP_TILE)`), `infBits` @12 (`F32_INF_BITS`: a kernel reads `+Infinity` from a uniform because Tint refuses it as a constant expression). */\nexport const APSP_PARAMS: UniformBlock = UniformBlock.define(\"ApspParams\", [\n [\"n\", \"u32\"],\n [\"round\", \"u32\"],\n [\"blocks\", \"u32\"],\n [\"infBits\", \"u32\"],\n]);\n\n/** `CooParams` (uniform, 16 B; P11): `count` @0 (the arcs or positions of the dispatch), `pad0` @4, `pad1` @8, `pad2` @12. The one params block of `coo-emit`, `run-flags`, `coo-scatter`, `orient-flags` and `tri-intersect`. */\nexport const COO_PARAMS: UniformBlock = UniformBlock.define(\"CooParams\", [\n [\"count\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n [\"pad2\", \"u32\"],\n]);\n\n/** `GroupParams` (uniform, 16 B; P11): `rowsBase` @0 (the word of `rows` where the dispatch's row list starts), `basesBase` @4 (the word where the workgroup tier's region offsets start), `count` @8 (the rows of the dispatch), `pad0` @12. */\nexport const GROUP_PARAMS: UniformBlock = UniformBlock.define(\"GroupParams\", [\n [\"rowsBase\", \"u32\"],\n [\"basesBase\", \"u32\"],\n [\"count\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `LpaParams` (uniform, 16 B; P11): `n` @0, `direction` @4 (0: a pass that moves labels down only, 1: up only), `counterIndex` @8 (the word of `counters` that receives the pass's move count), `pad0` @12. */\nexport const LPA_PARAMS: UniformBlock = UniformBlock.define(\"LpaParams\", [\n [\"n\", \"u32\"],\n [\"direction\", \"u32\"],\n [\"counterIndex\", \"u32\"],\n [\"pad0\", \"u32\"],\n]);\n\n/** `MstParams` (uniform, 16 B; P11): `count` @0 (the edges of `mst-best`, the vertices of `mst-link`), `counterIndex` @4 (the word of `counters` that receives the round's recorded edges), `pad0` @8, `pad1` @12. */\nexport const MST_PARAMS: UniformBlock = UniformBlock.define(\"MstParams\", [\n [\"count\", \"u32\"],\n [\"counterIndex\", \"u32\"],\n [\"pad0\", \"u32\"],\n [\"pad1\", \"u32\"],\n]);\n\n// ---- the entries (contract 3.10.1; group 0 = graph, 1 = state, 2 = params, 3 = cold)\n\n/**\n * One binding declaration of contract 3.9, so the tables below read like the rows of 3.10.1.\n * @param group - the bind group (0 graph, 1 state, 2 params, 3 cold)\n * @param binding - the slot inside the group\n * @param name - the WGSL variable name (also the KernelBindings key)\n * @param kind - \"storage\" (read_write), \"storage-ro\" (read) or \"uniform\"\n * @param wgslType - the element / struct type text\n * @returns the declaration\n */\nfunction decl(\n group: 0 | 1 | 2 | 3,\n binding: number,\n name: string,\n kind: BindingDecl[\"kind\"],\n wgslType: string,\n): BindingDecl {\n return { group, binding, name, kind, wgslType };\n}\n\n/** The four group-0 graph slots of every row-walking kernel (spec 3.5): rowPtr, colIdx, weights | dummy, perm | dummy -- all read-only, so the dummies never alias a writable slot (3.10.1). */\nconst GRAPH_SLOTS: readonly BindingDecl[] = [\n decl(0, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(0, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(0, 2, \"weights\", \"storage-ro\", \"array<f32>\"),\n decl(0, 3, \"perm\", \"storage-ro\", \"array<u32>\"),\n];\n\n/** `degree` (3.10.1): 5 storage bindings; only the standard USE_PERM / HAS_WEIGHTS overrides. */\nconst DEGREE: KernelEntry = {\n id: \"degree\",\n body: degreeWgsl,\n entryPoint: \"degree\",\n bindings: GRAPH_SLOTS.concat(decl(1, 0, \"out\", \"storage\", \"array<u32>\"), decl(2, 0, \"P\", \"uniform\", \"RangeParams\")),\n overrideDecls: [],\n uniforms: [RANGE_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P1\",\n};\n\n/** `reduce` (3.10.1): the multi-level reduction; OP 0 sum / 1 min / 2 max, DTYPE 0 f32 / 1 u32 / 2 vec4f, FINAL for the one-workgroup level; 2 storage bindings; calls the reduction helpers. */\nconst REDUCE: KernelEntry = {\n id: \"reduce\",\n body: reduceWgsl,\n entryPoint: \"reduce\",\n bindings: [\n decl(1, 0, \"src\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"out\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"ReduceParams\"),\n ],\n overrideDecls: [\n { name: \"OP\", type: \"u32\", default: 0 },\n { name: \"DTYPE\", type: \"u32\", default: 0 },\n { name: \"FINAL\", type: \"bool\", default: false },\n ],\n uniforms: [REDUCE_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P1\",\n};\n\n/** `fill` (3.10.1): dst[i] = value (mode 0) or i + value (mode 1) over `count` words; 1 storage binding. */\nconst FILL: KernelEntry = {\n id: \"fill\",\n body: fillWgsl,\n entryPoint: \"fill\",\n bindings: [decl(1, 0, \"dst\", \"storage\", \"array<u32>\"), decl(2, 0, \"P\", \"uniform\", \"FillParams\")],\n overrideDecls: [],\n uniforms: [FILL_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P1\",\n};\n\n/** `segmented-reduce` (3.10.1): the per-row fold of the VALUE snippet over the CSR rows; OP 0 sum / 1 min / 2 max, TIER 0 thread-per-row / 1 32-lanes-per-row / 2 workgroup-per-row (the degreeOrder tiers, P4 PD-6) plus the standard USE_PERM / HAS_WEIGHTS; 5 storage bindings; one snippet slot; calls the reduction helpers (TIER 2). */\nconst SEGMENTED_REDUCE: KernelEntry = {\n id: \"segmented-reduce\",\n body: segmentedReduceWgsl,\n entryPoint: \"segmented_reduce\",\n bindings: GRAPH_SLOTS.concat(decl(1, 0, \"out\", \"storage\", \"array<f32>\"), decl(2, 0, \"P\", \"uniform\", \"RangeParams\")),\n overrideDecls: [\n { name: \"OP\", type: \"u32\", default: 0 },\n { name: \"TIER\", type: \"u32\", default: 0 },\n ],\n uniforms: [RANGE_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [\"VALUE\"],\n phase: \"P2\",\n};\n\n/** `fa2-stats-finalize` (K1, 3.10.1): the one-workgroup fold of the previous integrate's partials into the state block and the K1 half of the trace record; STATS_MODE 0 FA2 / 1 FR temperature / 2 kinetic energy (P5); the grid frame, counts and hub-counter reset under `P.gridMax > 0` (P4-T10, PD-14: `cellHist` and `hubCounters` are bound to dummies on the exact tier); 5 storage bindings; calls the reduction helpers. */\nconst FA2_STATS_FINALIZE: KernelEntry = {\n id: \"fa2-stats-finalize\",\n body: fa2StatsFinalizeWgsl,\n entryPoint: \"stats_finalize\",\n bindings: [\n decl(1, 0, \"partials\", \"storage-ro\", \"array<Fa2Partial>\"),\n decl(1, 1, \"S\", \"storage\", \"Fa2State\"),\n decl(1, 2, \"T\", \"storage\", \"array<Fa2Trace>\"),\n decl(1, 3, \"cellHist\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"hubCounters\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [{ name: \"STATS_MODE\", type: \"u32\", default: 0 }],\n uniforms: [FA2_PARAMS, FA2_STATE, FA2_TRACE, FA2_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P3\",\n};\n\n/** `fa2-attraction` (K2, 3.10.1): the attraction gather over the CSR rows (the first writer of `force` each iteration); LINLOG / DISTRIBUTED / TIER 0 thread-per-row / 1 32-lanes-per-row / 2 workgroup-per-row (P4 PD-6) plus the standard USE_PERM / HAS_WEIGHTS; LAW 0 FA2 / 1 FR / 2 spring (P5); 6 storage bindings; calls the reduction helpers (TIER 2). */\nconst FA2_ATTRACTION: KernelEntry = {\n id: \"fa2-attraction\",\n body: fa2AttractionWgsl,\n entryPoint: \"attraction\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 1, \"force\", \"storage\", \"array<f32>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ),\n overrideDecls: [\n { name: \"LINLOG\", type: \"bool\", default: false },\n { name: \"DISTRIBUTED\", type: \"bool\", default: false },\n { name: \"TIER\", type: \"u32\", default: 0 },\n { name: \"LAW\", type: \"u32\", default: 0 },\n ],\n uniforms: [FA2_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P3\",\n};\n\n/** `fa2-repulsion-exact` (K3, 3.10.1): the tiled all-pairs repulsion with the gravity and swing / traction epilogue; LAW 0 FA2 / 1 FR / 2 coulomb (P5); 6 storage bindings (`oldForce` read-only: it only calls load_old); calls the reduction helpers. */\nconst FA2_REPULSION_EXACT: KernelEntry = {\n id: \"fa2-repulsion-exact\",\n body: fa2RepulsionExactWgsl,\n entryPoint: \"repulsion\",\n bindings: [\n decl(1, 0, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 1, \"S\", \"storage\", \"Fa2State\"),\n decl(1, 2, \"force\", \"storage\", \"array<f32>\"),\n decl(1, 3, \"oldForce\", \"storage-ro\", \"array<f32>\"),\n decl(1, 4, \"fixedMask\", \"storage-ro\", \"array<u32>\"),\n decl(1, 5, \"partials\", \"storage\", \"array<Fa2Partial>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [\n { name: \"SWING_MODE\", type: \"u32\", default: 0 },\n { name: \"STRONG_GRAVITY\", type: \"bool\", default: false },\n { name: \"GRAVITY_CENTER\", type: \"u32\", default: 0 },\n { name: \"LAW\", type: \"u32\", default: 0 },\n ],\n uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P1\",\n};\n\n/** `fa2-speed-finalize` (K4, 3.10.1): the one-workgroup partials fold and estimateFactor; 3 storage bindings; calls the reduction helpers. */\nconst FA2_SPEED_FINALIZE: KernelEntry = {\n id: \"fa2-speed-finalize\",\n body: fa2SpeedFinalizeWgsl,\n entryPoint: \"speed_finalize\",\n bindings: [\n decl(1, 0, \"partials\", \"storage-ro\", \"array<Fa2Partial>\"),\n decl(1, 1, \"S\", \"storage\", \"Fa2State\"),\n decl(1, 2, \"T\", \"storage\", \"array<Fa2Trace>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [{ name: \"SWING_MODE\", type: \"u32\", default: 0 }],\n uniforms: [FA2_PARAMS, FA2_STATE, FA2_TRACE, FA2_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P1\",\n};\n\n/** `fa2-integrate` (K5, 3.10.1): the per-node speed factor and position update (no clamp, D25), `oldForce` stored in SWING_MODE 0, and the partials A / C of the next K1; APPLY 0 FA2 / 1 FR temperature cap / 2 ngraph Euler (P5); 6 storage bindings; calls the reduction helpers. */\nconst FA2_INTEGRATE: KernelEntry = {\n id: \"fa2-integrate\",\n body: fa2IntegrateWgsl,\n entryPoint: \"integrate\",\n bindings: [\n decl(1, 0, \"force\", \"storage-ro\", \"array<f32>\"),\n decl(1, 1, \"oldForce\", \"storage\", \"array<f32>\"),\n decl(1, 2, \"fixedMask\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"S\", \"storage\", \"Fa2State\"),\n decl(1, 4, \"pos\", \"storage\", \"array<vec4f>\"),\n decl(1, 5, \"partials\", \"storage\", \"array<Fa2Partial>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [\n { name: \"SWING_MODE\", type: \"u32\", default: 0 },\n { name: \"APPLY\", type: \"u32\", default: 0 },\n ],\n uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P3\",\n};\n\n/** `fa2-to-scene` (3.10.1): the per-batch unpack of the vec4f layout positions into the stride-3 scene array with `scale` / `center` applied (z = center.z in 2D); 2 storage bindings. */\nconst FA2_TO_SCENE: KernelEntry = {\n id: \"fa2-to-scene\",\n body: fa2ToSceneWgsl,\n entryPoint: \"to_scene\",\n bindings: [\n decl(1, 0, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 1, \"scene\", \"storage\", \"array<f32>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [],\n uniforms: [FA2_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P3\",\n};\n\n/** `spmv-pull` (spec 8.10): the pull SpMV over the reverse adjacency; HAS_PERSONALIZATION / USE_DANGLING / TIER 0 grid-stride / 1 32-lanes-per-row / 2 workgroup-per-row (the reverseDegreeOrder tiers, P4 PD-6) plus the standard USE_PERM / HAS_WEIGHTS; 8 storage bindings (the design's count); calls the reduction helpers (TIER 2). */\nconst SPMV_PULL: KernelEntry = {\n id: \"spmv-pull\",\n body: spmvPullWgsl,\n entryPoint: \"spmv_pull\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"xNorm\", \"storage-ro\", \"array<f32>\"),\n decl(1, 1, \"rankOut\", \"storage\", \"array<f32>\"),\n decl(1, 2, \"personalization\", \"storage-ro\", \"array<f32>\"),\n decl(1, 3, \"partials\", \"storage-ro\", \"array<PrPartial>\"),\n decl(2, 0, \"P\", \"uniform\", \"SpmvParams\"),\n ),\n overrideDecls: [\n { name: \"HAS_PERSONALIZATION\", type: \"bool\", default: false },\n { name: \"USE_DANGLING\", type: \"bool\", default: false },\n { name: \"TIER\", type: \"u32\", default: 0 },\n ],\n uniforms: [SPMV_PARAMS, PR_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P7\",\n};\n\n/** `pr-scale` (spec 8.2 dispatch (a), 8.10): the per-node normaliser and the per-workgroup partials; NORM_MODE 0 PageRank / 1 L1 pass / 2 L2 pass / 3 scale / 4 identity; 5 storage bindings; calls the reduction helpers. */\nconst PR_SCALE: KernelEntry = {\n id: \"pr-scale\",\n body: prScaleWgsl,\n entryPoint: \"pr_scale\",\n bindings: [\n decl(1, 0, \"rankIn\", \"storage-ro\", \"array<f32>\"),\n decl(1, 1, \"rankPrev\", \"storage-ro\", \"array<f32>\"),\n decl(1, 2, \"outWeightSum\", \"storage-ro\", \"array<f32>\"),\n decl(1, 3, \"xNorm\", \"storage\", \"array<f32>\"),\n decl(1, 4, \"partials\", \"storage\", \"array<PrPartial>\"),\n decl(2, 0, \"P\", \"uniform\", \"PrParams\"),\n ],\n overrideDecls: [{ name: \"NORM_MODE\", type: \"u32\", default: 0 }],\n uniforms: [PR_PARAMS, PR_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P7\",\n};\n\n/** `pr-finalize` (spec 8.2 dispatch (b), 8.10): the one-workgroup fold of the partials into the header at partials[0] and the firstConverged record; NORM_MODE 2 takes the square root; 1 storage binding; calls the reduction helpers. */\nconst PR_FINALIZE: KernelEntry = {\n id: \"pr-finalize\",\n body: prFinalizeWgsl,\n entryPoint: \"pr_finalize\",\n bindings: [decl(1, 0, \"partials\", \"storage\", \"array<PrPartial>\"), decl(2, 0, \"P\", \"uniform\", \"PrParams\")],\n overrideDecls: [{ name: \"NORM_MODE\", type: \"u32\", default: 0 }],\n uniforms: [PR_PARAMS, PR_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P7\",\n};\n\n/** `wcc-link-sample` (spec 8.3): Afforest's sampled link round over the CSR rows (every vertex links its r-th neighbour); the standard USE_PERM / HAS_WEIGHTS only; 5 storage bindings (the four graph slots and the atomic `comp`, whose word at P.flagIndex is the changed flag, PD-4). */\nconst WCC_LINK_SAMPLE: KernelEntry = {\n id: \"wcc-link-sample\",\n body: wccLinkSampleWgsl,\n entryPoint: \"wcc_link_sample\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"comp\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"WccParams\"),\n ),\n overrideDecls: [],\n uniforms: [WCC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P7\",\n};\n\n/** `wcc-link-edges` (spec 8.3, 8.10): Afforest's each-edge-once link round over the edge list; no overrides; 3 storage bindings (the design's count: edgeSrc, edgeDst and the atomic `comp` carrying the changed flag). */\nconst WCC_LINK_EDGES: KernelEntry = {\n id: \"wcc-link-edges\",\n body: wccLinkEdgesWgsl,\n entryPoint: \"wcc_link_edges\",\n bindings: [\n decl(1, 0, \"edgeSrc\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"edgeDst\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"comp\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"WccParams\"),\n ],\n overrideDecls: [],\n uniforms: [WCC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P7\",\n};\n\n/** `wcc-compress` (spec 8.3, 8.10): Afforest's bounded pointer-jumping compress; no overrides; 1 storage binding. */\nconst WCC_COMPRESS: KernelEntry = {\n id: \"wcc-compress\",\n body: wccCompressWgsl,\n entryPoint: \"wcc_compress\",\n bindings: [decl(1, 0, \"comp\", \"storage\", \"array<atomic<u32>>\"), decl(2, 0, \"P\", \"uniform\", \"WccParams\")],\n overrideDecls: [],\n uniforms: [WCC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P7\",\n};\n\n/** `wcc-sample` (spec 8.3, 8.10): the component-label sample of P.items pseudo-random vertices the host takes the mode of (PD-12); no overrides; 2 storage bindings. */\nconst WCC_SAMPLE: KernelEntry = {\n id: \"wcc-sample\",\n body: wccSampleWgsl,\n entryPoint: \"wcc_sample\",\n bindings: [\n decl(1, 0, \"comp\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 1, \"hist\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"WccParams\"),\n ],\n overrideDecls: [],\n uniforms: [WCC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P7\",\n};\n\n/** `indirect-finalize` (spec 5.4; P4-T1): the one-lane count -> (x, y, 1, count) finalize; 2 storage bindings. */\nconst INDIRECT_FINALIZE: KernelEntry = {\n id: \"indirect-finalize\",\n body: indirectFinalizeWgsl,\n entryPoint: \"indirect_finalize\",\n bindings: [\n decl(1, 0, \"counters\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"args\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"IndirectParams\"),\n ],\n overrideDecls: [],\n uniforms: [INDIRECT_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `scan-block` (spec 6 row 2 steps (a) / (b); P4-T2, PD-3): the Hillis-Steele exclusive scan of one WG-wide block into `out` and its total into `blockSums[group]`; 3 storage bindings; no subgroup variant. */\nconst SCAN_BLOCK: KernelEntry = {\n id: \"scan-block\",\n body: scanBlockWgsl,\n entryPoint: \"scan_block\",\n bindings: [\n decl(1, 0, \"src\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"out\", \"storage\", \"array<u32>\"),\n decl(1, 2, \"blockSums\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"ScanParams\"),\n ],\n overrideDecls: [],\n uniforms: [SCAN_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `scan-add` (spec 6 row 2 step (c); P4-T2): adds `blockOffsets[group]` to every element of the block; 2 storage bindings. */\nconst SCAN_ADD: KernelEntry = {\n id: \"scan-add\",\n body: scanAddWgsl,\n entryPoint: \"scan_add\",\n bindings: [\n decl(1, 0, \"out\", \"storage\", \"array<u32>\"),\n decl(1, 1, \"blockOffsets\", \"storage-ro\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"ScanParams\"),\n ],\n overrideDecls: [],\n uniforms: [SCAN_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `histogram` (spec 6 row 5; P4-T3, PD-4): one global atomicAdd per key into `hist` (zeroed by a `fill` dispatch earlier in the pass); 2 storage bindings; one path, no PRIVATE override. */\nconst HISTOGRAM: KernelEntry = {\n id: \"histogram\",\n body: histogramWgsl,\n entryPoint: \"histogram\",\n bindings: [\n decl(1, 0, \"keys\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"hist\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"HistParams\"),\n ],\n overrideDecls: [],\n uniforms: [HIST_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `counting-scatter` (spec 6 row 5; P4-T3): the scatter of a counting sort, `outIndex[start[k] + atomicAdd(&cursor[k], 1u)] = i`; 4 storage bindings; set-deterministic (the order inside a bin follows the schedule). */\nconst COUNTING_SCATTER: KernelEntry = {\n id: \"counting-scatter\",\n body: countingScatterWgsl,\n entryPoint: \"counting_scatter\",\n bindings: [\n decl(1, 0, \"keys\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"start\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"cursor\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 3, \"outIndex\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"HistParams\"),\n ],\n overrideDecls: [],\n uniforms: [HIST_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `radix-hist` (spec 6 row 6; P4-T4, PD-5): the per-workgroup 256-bin digit histogram, privatised in workgroup memory and stored digit-major `hist[digit * groups + group]`; 2 storage bindings. */\nconst RADIX_HIST: KernelEntry = {\n id: \"radix-hist\",\n body: radixHistWgsl,\n entryPoint: \"radix_hist\",\n bindings: [\n decl(1, 0, \"keys\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"hist\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"RadixParams\"),\n ],\n overrideDecls: [],\n uniforms: [RADIX_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `radix-scatter` (spec 6 row 6; P4-T4, PD-5): the stable scatter of one LSD pass, ranked serially by lane 0, written at `offsets[digit * groups + group] + rank`; 5 storage bindings. */\nconst RADIX_SCATTER: KernelEntry = {\n id: \"radix-scatter\",\n body: radixScatterWgsl,\n entryPoint: \"radix_scatter\",\n bindings: [\n decl(1, 0, \"keys\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"vals\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"offsets\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"keysOut\", \"storage\", \"array<u32>\"),\n decl(1, 4, \"valsOut\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"RadixParams\"),\n ],\n overrideDecls: [],\n uniforms: [RADIX_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `grid-cell-key` (G1, spec 7.7; P4-T8, PD-10): the finest cell key of every node, `floor((p - gridMin) * invCellSize)` linearised, or the outside pseudo-cell of its orthant `G^dim + orthant` (issue #90); `cellVal[i] = i`; 4 storage bindings (the state read-only: K1 writes it). */\nconst GRID_CELL_KEY: KernelEntry = {\n id: \"grid-cell-key\",\n body: gridCellKeyWgsl,\n entryPoint: \"grid_cell_key\",\n bindings: [\n decl(1, 0, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 1, \"S\", \"storage-ro\", \"Fa2State\"),\n decl(1, 2, \"cellKey\", \"storage\", \"array<u32>\"),\n decl(1, 3, \"cellVal\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [],\n uniforms: [FA2_PARAMS, FA2_STATE],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `grid-centroid` (G4, spec 7.7; P4-T9, PD-13): thread per finest cell (the 2^dim orthant pseudo-cells included), the serial mass-weighted sum in sorted order into level 0, the occupancy max into `hubCounters[1]`, hub cells (> GRID_HUB_CELL) appended to `hubList`; 6 storage bindings. */\nconst GRID_CENTROID: KernelEntry = {\n id: \"grid-centroid\",\n body: gridCentroidWgsl,\n entryPoint: \"grid_centroid\",\n bindings: [\n decl(1, 0, \"sortedIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"cellStart\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 3, \"pyramid\", \"storage\", \"array<vec4f>\"),\n decl(1, 4, \"hubList\", \"storage\", \"array<u32>\"),\n decl(1, 5, \"hubCounters\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [],\n uniforms: [FA2_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `grid-centroid-hub` (G4b, spec 7.7; P4-T9, PD-13, DEP-P4-L): one workgroup per word of `hubList`, dispatched directly, a WG-strided sum through `wg_reduce_vec4` guarded by `h < hubCount[0]`; 6 storage bindings (`hubCount` is a read-only view of `hubCounters`). */\nconst GRID_CENTROID_HUB: KernelEntry = {\n id: \"grid-centroid-hub\",\n body: gridCentroidHubWgsl,\n entryPoint: \"grid_centroid_hub\",\n bindings: [\n decl(1, 0, \"sortedIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"cellStart\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 3, \"pyramid\", \"storage\", \"array<vec4f>\"),\n decl(1, 4, \"hubList\", \"storage-ro\", \"array<u32>\"),\n decl(1, 5, \"hubCount\", \"storage-ro\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [],\n uniforms: [FA2_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `grid-downsample` (G5, spec 7.7; P4-T9): one dispatch per coarser level, every parent the sum of its 4 / 8 children at `P.childBase`, written at `P.parentBase`; 1 storage binding. */\nconst GRID_DOWNSAMPLE: KernelEntry = {\n id: \"grid-downsample\",\n body: gridDownsampleWgsl,\n entryPoint: \"grid_downsample\",\n bindings: [decl(1, 0, \"pyramid\", \"storage\", \"array<vec4f>\"), decl(2, 0, \"P\", \"uniform\", \"GridLevelParams\")],\n overrideDecls: [],\n uniforms: [GRID_LEVEL_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `grid-far-field` (G6, spec 7.7; P4-T10, PD-16, DEP-P4-G): per node in sorted order, the coarsest level minus its 3x3 (3x3x3) and, per finer level, the parent's 3x3 refined minus the level's own 3x3, plus the 2^dim orthant pseudo-cells; the FA2 term floored at 0.01 (issue #89); the loop bounds are `P.levels` / `P.gridMax`; LAW 0 FA2 / 1 FR / 2 coulomb per cell (P4-T13, PD-22); 5 storage bindings. */\nconst GRID_FAR_FIELD: KernelEntry = {\n id: \"grid-far-field\",\n body: gridFarFieldWgsl,\n entryPoint: \"grid_far_field\",\n bindings: [\n decl(1, 0, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 1, \"sortedIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"pyramid\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 3, \"S\", \"storage-ro\", \"Fa2State\"),\n decl(1, 4, \"force\", \"storage\", \"array<f32>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [{ name: \"LAW\", type: \"u32\", default: 0 }],\n uniforms: [FA2_PARAMS, FA2_STATE],\n needs: [],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `grid-near-field` (G7, spec 7.7; P4-T10, PD-15): per node in sorted order, K3's exact pair law over the 9 (27) finest cells, a cell above `nearMax` sampled through the hashed window and scaled by `others / sampled`, then K3's fused epilogue (gravity, `force +=`, the swing / traction reduction); SWING_MODE / STRONG_GRAVITY / GRAVITY_CENTER / LAW as K3 (LAW 0 FA2 / 1 FR / 2 coulomb, P4-T13, PD-22); 8 storage bindings; calls the reduction helpers. */\nconst GRID_NEAR_FIELD: KernelEntry = {\n id: \"grid-near-field\",\n body: gridNearFieldWgsl,\n entryPoint: \"grid_near_field\",\n bindings: [\n decl(1, 0, \"pos\", \"storage-ro\", \"array<vec4f>\"),\n decl(1, 1, \"sortedIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"cellStart\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"S\", \"storage\", \"Fa2State\"),\n decl(1, 4, \"force\", \"storage\", \"array<f32>\"),\n decl(1, 5, \"oldForce\", \"storage-ro\", \"array<f32>\"),\n decl(1, 6, \"fixedMask\", \"storage-ro\", \"array<u32>\"),\n decl(1, 7, \"partials\", \"storage\", \"array<Fa2Partial>\"),\n decl(2, 0, \"P\", \"uniform\", \"Fa2Params\"),\n ],\n overrideDecls: [\n { name: \"SWING_MODE\", type: \"u32\", default: 0 },\n { name: \"STRONG_GRAVITY\", type: \"bool\", default: false },\n { name: \"GRAVITY_CENTER\", type: \"u32\", default: 0 },\n { name: \"LAW\", type: \"u32\", default: 0 },\n ],\n uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P4\",\n};\n\n/** `compact-scatter` (spec 6 row 4; P8-T3): the scatter of `compact` after the flags' exclusive scan, plus the total into `outCount[P.outIndex]`; 5 storage bindings; order-preserving, so bitwise reproducible. */\nconst COMPACT_SCATTER: KernelEntry = {\n id: \"compact-scatter\",\n body: compactScatterWgsl,\n entryPoint: \"compact_scatter\",\n bindings: [\n decl(1, 0, \"queue\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"flags\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"offsets\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"out\", \"storage\", \"array<u32>\"),\n decl(1, 4, \"outCount\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"CompactParams\"),\n ],\n overrideDecls: [],\n uniforms: [COMPACT_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `dedupe-claim` (spec 6 row 4; P8-T3): `atomicStore(&owner[queue[i]], i)` for every entry, the count from `P.count` or the device word `counters[P.countIndex]`; 3 storage bindings (`counters` is `array<atomic<u32>>` and therefore read-write, although only loaded: WGSL admits an atomic only in a read-write storage buffer). */\nconst DEDUPE_CLAIM: KernelEntry = {\n id: \"dedupe-claim\",\n body: dedupeClaimWgsl,\n entryPoint: \"dedupe_claim\",\n bindings: [\n decl(1, 0, \"queue\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"owner\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"CompactParams\"),\n ],\n overrideDecls: [],\n uniforms: [COMPACT_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `dedupe-filter` (spec 6 row 4; P8-T3): a separate dispatch keeping the entries that still own their vertex, packed by a workgroup scan and one `atomicAdd` per workgroup on `outCount[P.outIndex]`, which is also the block the count word `P.countIndex` is read from; 4 storage bindings; set-deterministic. */\nconst DEDUPE_FILTER: KernelEntry = {\n id: \"dedupe-filter\",\n body: dedupeFilterWgsl,\n entryPoint: \"dedupe_filter\",\n bindings: [\n decl(1, 0, \"queue\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"owner\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"out\", \"storage\", \"array<u32>\"),\n decl(1, 3, \"outCount\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"CompactParams\"),\n ],\n overrideDecls: [],\n uniforms: [COMPACT_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `frontier-finalize` (design 5.4, 8.10 \"BFS finalizeArgs\"; P8-T4, PD-3): the one-lane level-boundary selector that rotates the counters block and writes the level's `path` word (role 0), then clamps the edge count or switches the path to the fused retry (role 1); 1 storage binding (the block as `array<atomic<u32>>`). Since 2026-09-25 it writes no indirect slots: every level kernel is a direct dispatch gated by the path word. */\nconst FRONTIER_FINALIZE: KernelEntry = {\n id: \"frontier-finalize\",\n body: frontierFinalizeWgsl,\n entryPoint: \"frontier_finalize\",\n bindings: [decl(1, 0, \"counters\", \"storage\", \"array<atomic<u32>>\"), decl(2, 0, \"P\", \"uniform\", \"FrontierParams\")],\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `advance-expand` (design 6 row 8, 8.10 \"BFS expand\"; P8-T5): the block-mapped expansion of the frontier into the edge queue -- each workgroup scans its entries' degrees with the prelude's `wg_scan_u32` (the twin axis: `needs: [\"subgroups\"]` is what makes the subgroup compilation differ) and strips the aggregate by binary search, one `atomicAdd` per workgroup reserving its span; 7 storage bindings (the four graph slots, `frontierIn`, the counters block as `array<atomic<u32>>`, `edgeQueue`); no `TIER` override (the workgroup-per-row structure is `bfs-fused`). */\nconst ADVANCE_EXPAND: KernelEntry = {\n id: \"advance-expand\",\n body: advanceExpandWgsl,\n entryPoint: \"advance_expand\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"frontierIn\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"edgeQueue\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ),\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `bfs-contract` (design 8.4, 8.10 \"BFS contract\"; P8-T6, PD-6): the contraction of the edge queue -- `atomicMin(&depth[v], level + 1)` with the invocation that observes `INVALID_INDEX` the unique winner, packed into the output vertex queue by a workgroup scan and one `atomicAdd` per workgroup on `nextFrontierCount`; 4 storage bindings (no `owner`: the claim already dedupes, DEP-P8-B; no `parent`: the post-pass writes it, PD-24; both counts are words of `counters`). */\nconst BFS_CONTRACT: KernelEntry = {\n id: \"bfs-contract\",\n body: bfsContractWgsl,\n entryPoint: \"bfs_contract\",\n bindings: [\n decl(1, 0, \"edgeQueue\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"depth\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 3, \"frontierOut\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ],\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `sssp-pred` (design 8.10 \"SSSP predecessor pass\"; P8-T6 / P8-T9, PD-24 / PD-27): the one post-pass over the settled distances, grid-striding every row -- `MODE 1` reads u32 depths and writes BFS `parent`, `MODE 0` reads f32 bit patterns and writes `predArc` under PD-27's key, `P.predKind` choosing the node or the arc index; 6 storage bindings (the four graph slots, `dist` bound plain across dispatches, `pred` as `array<atomic<u32>>`, which in `MODE 0` also carries the hop counts and the two flag words in its upper regions). */\nconst SSSP_PRED: KernelEntry = {\n id: \"sssp-pred\",\n body: ssspPredWgsl,\n entryPoint: \"sssp_pred\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"dist\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"pred\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ),\n overrideDecls: [{ name: \"MODE\", type: \"u32\", default: 0 }],\n uniforms: [FRONTIER_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `bfs-fused` (design 8.4 \"the fused variant\", 6 row 8 \"the workgroup-per-row tier\", 8.10 \"BFS fused expand-contract\"; P8-T7, PD-23): one level's expansion and contraction in one dispatch, one WORKGROUP per frontier entry, every lane stripping the entry's row with `bfs-contract`'s claim inline and no edge queue traffic; a direct grid-stride dispatch that runs when the path word is 2 (a frontier below `P.fusedMax`) or 4 (the overflow retry, role 1's), sized from `frontierCount`; 8 storage bindings (the four graph slots, `frontierIn`, the counters block as `array<atomic<u32>>`, `depth` as `array<atomic<u32>>`, `frontierOut`) -- exactly at the budget, which is why no `parent` lives here (PD-24). */\nconst BFS_FUSED: KernelEntry = {\n id: \"bfs-fused\",\n body: bfsFusedWgsl,\n entryPoint: \"bfs_fused\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"frontierIn\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"depth\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 3, \"frontierOut\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ),\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `bfs-bottom-up` (design 8.4 \"the bottom-up sweep\", 8.10 \"BFS bottom-up\"; P8-T8, PD-18 / PD-21): one invocation per entry of the unvisited list, walking its in-neighbours through the REVERSE core bound in group 0 until the first one whose bit is set in the frontier bitset (the early exit `arcsScanned` witnesses), claiming with a plain `atomicStore` and packing the winners into the output vertex queue by `bfs-contract`'s scan; 8 storage bindings (the four graph slots of the reverse core, `sweepIn` read-only -- the unvisited list at word 0 and the bitset at `P.bitsBase`, one buffer -- the counters block, `depth` and `frontierOut` as `array<atomic<u32>>` / `array<u32>`); `needs: [\"subgroups\"]` for the `wg_reduce_u32` call (a twin kernel). */\nconst BFS_BOTTOM_UP: KernelEntry = {\n id: \"bfs-bottom-up\",\n body: bfsBottomUpWgsl,\n entryPoint: \"bfs_bottom_up\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"sweepIn\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"depth\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 3, \"frontierOut\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ),\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `bfs-bitset-build` (design 8.4 \"the bitset frontier\"; P8-T8): the vertex-list-to-bitset hand-off of a bottom-up level -- one `atomicOr` per entry of the input frontier into the `ceil(n / 32)`-word bitset at `P.bitsBase` of the `sweepIn` buffer (bound whole as `bits`, read-write); 3 storage bindings. */\nconst BFS_BITSET_BUILD: KernelEntry = {\n id: \"bfs-bitset-build\",\n body: bfsBitsetBuildWgsl,\n entryPoint: \"bfs_bitset_build\",\n bindings: [\n decl(1, 0, \"frontierIn\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"bits\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ],\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `bfs-unvisited-flags` (design 8.4; P8-T8, PD-18): the unvisited set's producer, once per submit -- grid-striding over the vertices, counting the unclaimed ones and their OUT-degree sum into words 5 and 6 and flagging those with a non-zero IN-degree (word 7, what the sweep iterates) for `compact`; 5 storage bindings (the `outDegree` and `inDegree` VIEWS rather than the graph group, `depth` read-only, `flags`, the counters block); `needs: [\"subgroups\"]` for the three `wg_reduce_u32` calls (a twin kernel). */\nconst BFS_UNVISITED_FLAGS: KernelEntry = {\n id: \"bfs-unvisited-flags\",\n body: bfsUnvisitedFlagsWgsl,\n entryPoint: \"bfs_unvisited_flags\",\n bindings: [\n decl(1, 0, \"outDegree\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"inDegree\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"depth\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"flags\", \"storage\", \"array<u32>\"),\n decl(1, 4, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ],\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `bfs-next-degree` (design 8.4; issue #391): Beamer's m_f measured exactly -- once per level, after the claim kernels, grid-striding over the output vertex queue and summing the `outDegree` view over the vertices the level claimed into word 25, one `atomicAdd` per workgroup; 3 storage bindings (`frontier` read-only, the `outDegree` VIEW, the counters block); `needs: [\"subgroups\"]` for the `wg_reduce_u32` call (a twin kernel). */\nconst BFS_NEXT_DEGREE: KernelEntry = {\n id: \"bfs-next-degree\",\n body: bfsNextDegreeWgsl,\n entryPoint: \"bfs_next_degree\",\n bindings: [\n decl(1, 0, \"frontier\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"outDegree\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ],\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [\"subgroups\"],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `sssp-relax` (design 8.4 \"Davidson's near-far\", 8.10 \"SSSP near-far relax\"; P8-T9, PD-9 / PD-20 / DEP-P8-E): one round of the near-far loop -- role 0 relaxes the deduped near pile's whole rows with `atomicMin` on the f32 bit patterns of `dist` and appends each improved vertex to the raw near or far half of `queueOut` (the two halves of ONE buffer at word 0 and word `P.edgeCapacity`), role 1 re-buckets the deduped far pile; 8 storage bindings (the four graph slots with the run's weights bound in the weights slot, `dist` and the counters block as `array<atomic<u32>>`, `queueIn` read-only, `queueOut`) -- exactly at the budget, which is why no `pred` lives here (PD-11) and why the piles' counts, the threshold and the delta are words of the block. */\nconst SSSP_RELAX: KernelEntry = {\n id: \"sssp-relax\",\n body: ssspRelaxWgsl,\n entryPoint: \"sssp_relax\",\n bindings: GRAPH_SLOTS.concat(\n decl(1, 0, \"dist\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 1, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 2, \"queueIn\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"queueOut\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"FrontierParams\"),\n ),\n overrideDecls: [],\n uniforms: [FRONTIER_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `bf-relax` (design 8.4 \"Bellman-Ford\"; P8-T10, PD-12 / DEP-P8-E): one edge-parallel relaxation round over the `edgeList` view with a bounded compare-exchange on the f32 bit patterns of `dist` (negative distances reverse the bit-pattern order, so no `atomicMin`); `UNDIRECTED` relaxes the other direction of every edge too; 6 storage bindings (`edgeSrc`, `edgeDst`, `edgeToArc` -- the core's segment, or an iota scratch on a directed identity snapshot --, the run's arc-indexed `weights`, `dist` and the `BfFlags` block as `array<atomic<u32>>`); no graph group. */\nconst BF_RELAX: KernelEntry = {\n id: \"bf-relax\",\n body: bfRelaxWgsl,\n entryPoint: \"bf_relax\",\n bindings: [\n decl(1, 0, \"edgeSrc\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"edgeDst\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"edgeToArc\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"weights\", \"storage-ro\", \"array<f32>\"),\n decl(1, 4, \"dist\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 5, \"flags\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"BfParams\"),\n ],\n overrideDecls: [{ name: \"UNDIRECTED\", type: \"bool\", default: false }],\n uniforms: [BF_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `closeness-level` (design 8.4 \"32 sources per u32 word\"): one level of closeness's bit-parallel multi-source BFS in one dispatch, `32 x P.words` sources per batch -- role 0 the level (push over the out-arcs or pull over the in-arcs, push one invocation per arc, pull one per node, chosen per level on the device from the frontier's arcs against `P.pullAt`, the pull with an early exit once every source has reached the node), role 1 and role 2 the batch's seed; 6 storage bindings (the forward and the reverse CSR as group-1 state, `bits` and `table` as `array<atomic<u32>>`). */\nconst CLOSENESS_LEVEL: KernelEntry = {\n id: \"closeness-level\",\n body: closenessLevelWgsl,\n entryPoint: \"closeness_level\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"inRowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"inColIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"bits\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 5, \"table\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"ClosenessParams\"),\n ],\n overrideDecls: [],\n uniforms: [CLOSENESS_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P8\",\n};\n\n/** `closeness-rowsum` (design 8.7): closeness from a finished all-pairs matrix, one workgroup per row -- the off-diagonal finite entries summed as integers (`P.role` 0), as f32 (1) or as reciprocals (2, harmonic), by a tree reduction; 2 storage bindings (`dist` read-only, `out`). */\nconst CLOSENESS_ROWSUM: KernelEntry = {\n id: \"closeness-rowsum\",\n body: closenessRowsumWgsl,\n entryPoint: \"closeness_rowsum\",\n bindings: [\n decl(1, 0, \"dist\", \"storage-ro\", \"array<f32>\"),\n decl(1, 1, \"out\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"ClosenessParams\"),\n ],\n overrideDecls: [],\n uniforms: [CLOSENESS_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `bc-finalize` (design 8.4, 5.4): the one-lane bookkeeping of a betweenness batch -- role 1 seeds it (depth 0 and one path for the k seed entries of the claim log, `stackTop = k`, `level = U32_MAX`), role 0 is the level boundary (`ends[level + 1] = stackTop`, `frontierCount`, `done` on an empty level); 6 storage bindings (the counters block as `array<atomic<u32>>`, `ends`, `S` read-only, `depthK`, `sigmaK` and `levelMax` plain: one lane writes the seed; `SCALED` seeds f32 bits). The design's finalize row has 2; `ends` is the third (the level boundary), and the seed's `S`, `depthK`, `sigmaK` and `levelMax` make it six. */\nconst BC_FINALIZE: KernelEntry = {\n id: \"bc-finalize\",\n body: bcFinalizeWgsl,\n entryPoint: \"bc_finalize\",\n bindings: [\n decl(1, 0, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 1, \"ends\", \"storage\", \"array<u32>\"),\n decl(1, 2, \"S\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"depthK\", \"storage\", \"array<u32>\"),\n decl(1, 4, \"sigmaK\", \"storage\", \"array<u32>\"),\n decl(1, 5, \"levelMax\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"BcParams\"),\n ],\n overrideDecls: [{ name: \"SCALED\", type: \"bool\", default: false }],\n uniforms: [BC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `bc-forward` (design 8.4, 8.10 \"BC forward (tagged)\", 16.1): one level of the tagged multi-source BFS -- the block-mapped strip over the level's range of the claim log with the claim, the path count and the overflow report inline (`SCALED`: the claim only, `bc-count` counts), the winners appended to the log; 7 storage bindings (`rowPtr`, `colIdx`, `S` read-write -- the level being read and the appends are ranges of ONE binding --, `ends` read-only, the counters block, `depthK` and `sigmaK` as `array<atomic<u32>>`); the inlined Hillis-Steele scan, so `needs: []`. */\nconst BC_FORWARD: KernelEntry = {\n id: \"bc-forward\",\n body: bcForwardWgsl,\n entryPoint: \"bc_forward\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"S\", \"storage\", \"array<u32>\"),\n decl(1, 3, \"ends\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 5, \"depthK\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 6, \"sigmaK\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"BcParams\"),\n ],\n overrideDecls: [{ name: \"SCALED\", type: \"bool\", default: false }],\n uniforms: [BC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `bc-backward` (design 8.4, 8.10 \"BC backward (successor pull)\"): one level of the dependency accumulation, one invocation per log entry of a host-planned range, each pulling over its successors and writing its delta once; 7 storage bindings (`rowPtr`, `colIdx`, `S`, `depthK`, `sigmaK` read-only, `deltaK`, `levelMax` read-only: the depth scale of `bc-count`, read under `SCALED`). */\nconst BC_BACKWARD: KernelEntry = {\n id: \"bc-backward\",\n body: bcBackwardWgsl,\n entryPoint: \"bc_backward\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"S\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"depthK\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"sigmaK\", \"storage-ro\", \"array<u32>\"),\n decl(1, 5, \"deltaK\", \"storage\", \"array<f32>\"),\n decl(1, 6, \"levelMax\", \"storage-ro\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"BcParams\"),\n ],\n overrideDecls: [{ name: \"SCALED\", type: \"bool\", default: false }],\n uniforms: [BC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `bc-gather` (design 8.4, 8.10 \"BC gather\"): `bc[w] += sum over s of delta[s][w]`, one invocation per vertex, no atomic; 2 storage bindings (`deltaK` read-only, `bc`). */\nconst BC_GATHER: KernelEntry = {\n id: \"bc-gather\",\n body: bcGatherWgsl,\n entryPoint: \"bc_gather\",\n bindings: [\n decl(1, 0, \"deltaK\", \"storage-ro\", \"array<f32>\"),\n decl(1, 1, \"bc\", \"storage\", \"array<f32>\"),\n decl(2, 0, \"P\", \"uniform\", \"BcParams\"),\n ],\n overrideDecls: [],\n uniforms: [BC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `bc-edge-gather` (design 8.4 \"edge BC accumulates per arc from the same n x k deltas\"): the per-arc twin of `bc-gather`, one invocation per arc (its row found by an upper-bound search over `rowPtr`) adding the arc's term over the batch's sources; 7 storage bindings (`rowPtr`, `colIdx`, `depthK`, `sigmaK`, `deltaK` read-only, `arcScores`, `levelMax` read-only). */\nconst BC_EDGE_GATHER: KernelEntry = {\n id: \"bc-edge-gather\",\n body: bcEdgeGatherWgsl,\n entryPoint: \"bc_edge_gather\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"depthK\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"sigmaK\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"deltaK\", \"storage-ro\", \"array<f32>\"),\n decl(1, 5, \"arcScores\", \"storage\", \"array<f32>\"),\n decl(1, 6, \"levelMax\", \"storage-ro\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"BcParams\"),\n ],\n overrideDecls: [{ name: \"SCALED\", type: \"bool\", default: false }],\n uniforms: [BC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `bc-forward-edge` (design 8.4 \"the edge-parallel form\", 8.8 row 7): one forward level edge-parallel over the `edgeList` view for every source of the batch, with `bc-forward`'s claim, count and overflow report (`SCALED`: the claim only), appending to the same claim log; `UNDIRECTED` relaxes both directions of every edge; 7 storage bindings (`edgeSrc`, `edgeDst`, `S` read-write, `ends` read-only, the counters block, `depthK` and `sigmaK` as `array<atomic<u32>>`). */\nconst BC_FORWARD_EDGE: KernelEntry = {\n id: \"bc-forward-edge\",\n body: bcForwardEdgeWgsl,\n entryPoint: \"bc_forward_edge\",\n bindings: [\n decl(1, 0, \"edgeSrc\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"edgeDst\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"S\", \"storage\", \"array<u32>\"),\n decl(1, 3, \"ends\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 5, \"depthK\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 6, \"sigmaK\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"BcParams\"),\n ],\n overrideDecls: [\n { name: \"UNDIRECTED\", type: \"bool\", default: false },\n { name: \"SCALED\", type: \"bool\", default: false },\n ],\n uniforms: [BC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `bc-count` (design 8.4, issue #719): in a batch rerun because its u32 counts wrapped, the path counts of the depth a forward level just claimed, pulled over the in-arcs in CSR order as f32 bits and rescaled per depth by a power of two, the overflow flag raised when a count leaves f32's normal range; 8 storage bindings (the REVERSE core's `rowPtr` and `colIdx`, `S` and `ends` read-only, the counters block and `levelMax` as `array<atomic<u32>>`, `depthK` read-only, `sigmaK` read-write). */\nconst BC_COUNT: KernelEntry = {\n id: \"bc-count\",\n body: bcCountWgsl,\n entryPoint: \"bc_count\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"S\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"ends\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 5, \"depthK\", \"storage-ro\", \"array<u32>\"),\n decl(1, 6, \"sigmaK\", \"storage\", \"array<u32>\"),\n decl(1, 7, \"levelMax\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"BcParams\"),\n ],\n overrideDecls: [],\n uniforms: [BC_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `apsp-init` (design 8.7): one lane per row writes that row's arcs into the `+Infinity`-filled `n x n` matrix, the cheapest of parallel arcs, then the diagonal zero; 5 storage bindings (the four graph slots -- `perm` bound to its dummy, the rows are never permuted -- and `dist`). */\nconst APSP_INIT: KernelEntry = {\n id: \"apsp-init\",\n body: apspInitWgsl,\n entryPoint: \"apsp_init\",\n bindings: GRAPH_SLOTS.concat(decl(1, 0, \"dist\", \"storage\", \"array<f32>\"), decl(2, 0, \"P\", \"uniform\", \"ApspParams\")),\n overrideDecls: [],\n uniforms: [APSP_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `apsp-fw` (design 8.7): one phase of one blocked Floyd-Warshall round over 32 x 32 tiles in workgroup memory -- `PHASE` 0 the pivot block, 1 the pivot row and column, 2 every other block; 1 storage binding (`dist`, read-write). */\nconst APSP_FW: KernelEntry = {\n id: \"apsp-fw\",\n body: apspFwWgsl,\n entryPoint: \"apsp_fw\",\n bindings: [decl(1, 0, \"dist\", \"storage\", \"array<f32>\"), decl(2, 0, \"P\", \"uniform\", \"ApspParams\")],\n overrideDecls: [{ name: \"PHASE\", type: \"u32\", default: 0 }],\n uniforms: [APSP_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P9\",\n};\n\n/** `coo-emit` (design 6 row 10; P11): position i takes arc i, or `order[i]` under INDEXED, and writes its source, target and weight -- arc 2e is edge e as declared, 2e + 1 its reverse; a self-loop's two arcs become `INVALID_INDEX`; 7 storage bindings. */\nconst COO_EMIT: KernelEntry = {\n id: \"coo-emit\",\n body: cooEmitWgsl,\n entryPoint: \"coo_emit\",\n bindings: [\n decl(1, 0, \"edgeSrc\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"edgeDst\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"edgeWeight\", \"storage-ro\", \"array<f32>\"),\n decl(1, 3, \"order\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"outSrc\", \"storage\", \"array<u32>\"),\n decl(1, 5, \"outDst\", \"storage\", \"array<u32>\"),\n decl(1, 6, \"outWeight\", \"storage\", \"array<f32>\"),\n decl(2, 0, \"P\", \"uniform\", \"CooParams\"),\n ],\n overrideDecls: [\n { name: \"INDEXED\", type: \"bool\", default: false },\n { name: \"WEIGHTED\", type: \"bool\", default: false },\n ],\n uniforms: [COO_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `run-flags` (design 6 row 10; P11): 1 where an arc opens a run of equal (keysA, keysB) pairs and is not dropped; 3 storage bindings. */\nconst RUN_FLAGS: KernelEntry = {\n id: \"run-flags\",\n body: runFlagsWgsl,\n entryPoint: \"run_flags\",\n bindings: [\n decl(1, 0, \"keysA\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"keysB\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"flags\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"CooParams\"),\n ],\n overrideDecls: [],\n uniforms: [COO_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `coo-scatter` (design 6 row 10; P11): the scatter of `cooToCsr` -- the cursor mode, or under SORTED_INPUT the order-preserving mode whose precondition flag is `cursors[0]`; 7 storage bindings. */\nconst COO_SCATTER: KernelEntry = {\n id: \"coo-scatter\",\n body: cooScatterWgsl,\n entryPoint: \"coo_scatter\",\n bindings: [\n decl(1, 0, \"src\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"dst\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"weight\", \"storage-ro\", \"array<f32>\"),\n decl(1, 3, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"cursors\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 5, \"colIdx\", \"storage\", \"array<u32>\"),\n decl(1, 6, \"outWeight\", \"storage\", \"array<f32>\"),\n decl(2, 0, \"P\", \"uniform\", \"CooParams\"),\n ],\n overrideDecls: [\n { name: \"SORTED_INPUT\", type: \"bool\", default: false },\n { name: \"WEIGHTED\", type: \"bool\", default: false },\n ],\n uniforms: [COO_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `orient-flags` (design 8.5; P11): 1 where arc (u, v) points up the (degree, id) order, one arc per undirected edge; 4 storage bindings. */\nconst ORIENT_FLAGS: KernelEntry = {\n id: \"orient-flags\",\n body: orientFlagsWgsl,\n entryPoint: \"orient_flags\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"src\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"flags\", \"storage\", \"array<u32>\"),\n decl(2, 0, \"P\", \"uniform\", \"CooParams\"),\n ],\n overrideDecls: [],\n uniforms: [COO_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `tri-intersect` (design 8.5, 8.10 \"Triangle intersection\"; P11): one oriented arc per invocation, merge or binary-search intersection (SEARCH 0 chooses, 1 merge, 2 search), u32 atomic per-node counts; 4 storage bindings. */\nconst TRI_INTERSECT: KernelEntry = {\n id: \"tri-intersect\",\n body: triIntersectWgsl,\n entryPoint: \"tri_intersect\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"src\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"counts\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"CooParams\"),\n ],\n overrideDecls: [{ name: \"SEARCH\", type: \"u32\", default: 0 }],\n uniforms: [COO_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `group-by-key-row` (design 8.6; P11): per listed row, the target key with the largest summed weight (lowest key on a tie), TIER 0 a thread per row, else a workgroup per row over a global hash region; 8 storage bindings. */\nconst GROUP_BY_KEY_ROW: KernelEntry = {\n id: \"group-by-key-row\",\n body: groupByKeyRowWgsl,\n entryPoint: \"group_by_key_row\",\n bindings: [\n decl(1, 0, \"rowPtr\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"colIdx\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"weights\", \"storage-ro\", \"array<f32>\"),\n decl(1, 3, \"keyIn\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"rows\", \"storage-ro\", \"array<u32>\"),\n decl(1, 5, \"hashRegion\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 6, \"bestKey\", \"storage\", \"array<u32>\"),\n decl(1, 7, \"bestScore\", \"storage\", \"array<f32>\"),\n decl(2, 0, \"P\", \"uniform\", \"GroupParams\"),\n ],\n overrideDecls: [\n { name: \"TIER\", type: \"u32\", default: 0 },\n { name: \"WEIGHTED\", type: \"bool\", default: false },\n ],\n uniforms: [GROUP_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `lpa-step` (design 8.6, 8.10 \"Label propagation\"; P11): a vertex adopts its best neighbour label when the move goes the pass's direction; one atomic per workgroup adds the moves to `counters[P.counterIndex]`; 4 storage bindings. */\nconst LPA_STEP: KernelEntry = {\n id: \"lpa-step\",\n body: lpaStepWgsl,\n entryPoint: \"lpa_step\",\n bindings: [\n decl(1, 0, \"labelsIn\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"bestKey\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"labelsOut\", \"storage\", \"array<u32>\"),\n decl(1, 3, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"LpaParams\"),\n ],\n overrideDecls: [],\n uniforms: [LPA_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `mst-best` (design 8.5; P11-T4, PD-7): one edge per invocation offers itself to both endpoint components; PASS 0 takes the minimum `order_key` of the weight, PASS 1 the minimum edge index among that key's edges; 6 storage bindings. */\nconst MST_BEST: KernelEntry = {\n id: \"mst-best\",\n body: mstBestWgsl,\n entryPoint: \"mst_best\",\n bindings: [\n decl(1, 0, \"edgeSrc\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"edgeDst\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"edgeWeight\", \"storage-ro\", \"array<f32>\"),\n decl(1, 3, \"comp\", \"storage-ro\", \"array<u32>\"),\n decl(1, 4, \"bestKey\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 5, \"bestEdge\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"MstParams\"),\n ],\n overrideDecls: [\n { name: \"PASS\", type: \"u32\", default: 0 },\n { name: \"WEIGHTED\", type: \"bool\", default: false },\n ],\n uniforms: [MST_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/** `mst-link` (design 8.5; P11-T4): a component root hooks onto the component its best edge reaches and records the edge, the lower root of a two-cycle staying; one atomic per workgroup counts the recorded edges; 6 storage bindings. */\nconst MST_LINK: KernelEntry = {\n id: \"mst-link\",\n body: mstLinkWgsl,\n entryPoint: \"mst_link\",\n bindings: [\n decl(1, 0, \"edgeSrc\", \"storage-ro\", \"array<u32>\"),\n decl(1, 1, \"edgeDst\", \"storage-ro\", \"array<u32>\"),\n decl(1, 2, \"bestEdge\", \"storage-ro\", \"array<u32>\"),\n decl(1, 3, \"comp\", \"storage\", \"array<atomic<u32>>\"),\n decl(1, 4, \"treeEdge\", \"storage\", \"array<u32>\"),\n decl(1, 5, \"counters\", \"storage\", \"array<atomic<u32>>\"),\n decl(2, 0, \"P\", \"uniform\", \"MstParams\"),\n ],\n overrideDecls: [],\n uniforms: [MST_PARAMS],\n needs: [],\n snippetSlots: [],\n phase: \"P11\",\n};\n\n/**\n * The entries by id, in dispatch order. PLAN DECISION: `KernelId` is declared in full (contract 3.10) while the\n * entries landed phase by phase, so the table is built as a Partial record and exported below through the\n * contract's `Readonly<Record<KernelId, KernelEntry>>` type by one assertion; the runtime membership check of\n * `entryOf` is the E_INVALID_ARGUMENT the contract documents for a JS caller's unknown id. P1-T4 landed the five\n * P1 entries, P2-T2 `\"segmented-reduce\"`, and P3-T2 `\"fa2-stats-finalize\"`, `\"fa2-attraction\"`, `\"fa2-integrate\"`\n * and `\"fa2-to-scene\"`; M8b-T3 landed the seven P7 entries and P4 its thirteen; P8-T3 landed the three compact /\n * dedupe entries, P8-T4 `\"frontier-finalize\"`, P8-T5 `\"advance-expand\"`, P8-T6 `\"bfs-contract\"` and `\"sssp-pred\"` and\n * P8-T7 `\"bfs-fused\"`, P8-T8 `\"bfs-bottom-up\"`, `\"bfs-bitset-build\"` and `\"bfs-unvisited-flags\"`, P8-T9\n * `\"sssp-relax\"`, P8-T10 `\"bf-relax\"`, closeness `\"closeness-level\"` and `\"closeness-rowsum\"`, betweenness the\n * six `\"bc-*\"` entries, all-pairs shortest paths `\"apsp-init\"` and `\"apsp-fw\"`, and P11 its seven (the graph\n * build, the group-by-key, label propagation's step and triangle counting) plus Boruvka's `\"mst-best\"` and\n * `\"mst-link\"`, so every member of `KernelId`\n * is present and the assertion is exact.\n */\nconst REGISTRY: Readonly<Partial<Record<KernelId, KernelEntry>>> = Object.freeze({\n degree: DEGREE,\n reduce: REDUCE,\n fill: FILL,\n \"segmented-reduce\": SEGMENTED_REDUCE,\n \"fa2-stats-finalize\": FA2_STATS_FINALIZE,\n \"fa2-attraction\": FA2_ATTRACTION,\n \"fa2-repulsion-exact\": FA2_REPULSION_EXACT,\n \"fa2-speed-finalize\": FA2_SPEED_FINALIZE,\n \"fa2-integrate\": FA2_INTEGRATE,\n \"fa2-to-scene\": FA2_TO_SCENE,\n \"spmv-pull\": SPMV_PULL,\n \"pr-scale\": PR_SCALE,\n \"pr-finalize\": PR_FINALIZE,\n \"wcc-link-sample\": WCC_LINK_SAMPLE,\n \"wcc-link-edges\": WCC_LINK_EDGES,\n \"wcc-compress\": WCC_COMPRESS,\n \"wcc-sample\": WCC_SAMPLE,\n \"indirect-finalize\": INDIRECT_FINALIZE,\n \"scan-block\": SCAN_BLOCK,\n \"scan-add\": SCAN_ADD,\n histogram: HISTOGRAM,\n \"counting-scatter\": COUNTING_SCATTER,\n \"radix-hist\": RADIX_HIST,\n \"radix-scatter\": RADIX_SCATTER,\n \"grid-cell-key\": GRID_CELL_KEY,\n \"grid-centroid\": GRID_CENTROID,\n \"grid-centroid-hub\": GRID_CENTROID_HUB,\n \"grid-downsample\": GRID_DOWNSAMPLE,\n \"grid-far-field\": GRID_FAR_FIELD,\n \"grid-near-field\": GRID_NEAR_FIELD,\n \"compact-scatter\": COMPACT_SCATTER,\n \"dedupe-claim\": DEDUPE_CLAIM,\n \"dedupe-filter\": DEDUPE_FILTER,\n \"frontier-finalize\": FRONTIER_FINALIZE,\n \"advance-expand\": ADVANCE_EXPAND,\n \"bfs-contract\": BFS_CONTRACT,\n \"sssp-pred\": SSSP_PRED,\n \"bfs-fused\": BFS_FUSED,\n \"bfs-bottom-up\": BFS_BOTTOM_UP,\n \"bfs-bitset-build\": BFS_BITSET_BUILD,\n \"bfs-unvisited-flags\": BFS_UNVISITED_FLAGS,\n \"bfs-next-degree\": BFS_NEXT_DEGREE,\n \"sssp-relax\": SSSP_RELAX,\n \"bf-relax\": BF_RELAX,\n \"closeness-level\": CLOSENESS_LEVEL,\n \"closeness-rowsum\": CLOSENESS_ROWSUM,\n \"bc-finalize\": BC_FINALIZE,\n \"bc-forward\": BC_FORWARD,\n \"bc-backward\": BC_BACKWARD,\n \"bc-gather\": BC_GATHER,\n \"bc-count\": BC_COUNT,\n \"bc-edge-gather\": BC_EDGE_GATHER,\n \"bc-forward-edge\": BC_FORWARD_EDGE,\n \"apsp-init\": APSP_INIT,\n \"apsp-fw\": APSP_FW,\n \"coo-emit\": COO_EMIT,\n \"run-flags\": RUN_FLAGS,\n \"coo-scatter\": COO_SCATTER,\n \"orient-flags\": ORIENT_FLAGS,\n \"tri-intersect\": TRI_INTERSECT,\n \"group-by-key-row\": GROUP_BY_KEY_ROW,\n \"lpa-step\": LPA_STEP,\n \"mst-best\": MST_BEST,\n \"mst-link\": MST_LINK,\n});\n\n/** THE registry (spec 3.5): every entry, keyed by id. */\nexport const KERNELS: Readonly<Record<KernelId, KernelEntry>> = REGISTRY as Readonly<Record<KernelId, KernelEntry>>;\n\n/** The bodies installed by setKernelBodyOverride (the sabotage seam of spec 11.9 item 1), by id. */\nconst bodyOverrides = new Map<KernelId, string>();\n\n/**\n * The entry of an id, or E_INVALID_ARGUMENT for an id that is not (yet) registered.\n * @param id - the module id\n * @returns the entry\n */\nfunction entryOf(id: KernelId): KernelEntry {\n const entry = REGISTRY[id];\n if (entry === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `unknown kernel id \"${id}\"`, {\n argument: \"id\",\n value: id,\n expected: Object.keys(REGISTRY),\n });\n }\n return entry;\n}\n\n/**\n * A WgslModuleSpec for a variant: the entry plus the overrides / snippets given; unknown override names are\n * rejected at compose time. A body override installed by setKernelBodyOverride is used instead of the entry's\n * body.\n * @param id - the module id\n * @param overrides - the override values of this variant (the five standard names and the entry's overrideDecls)\n * @param snippets - the texts substituted at the body's `//@@NAME@@` markers\n * @returns the spec the PipelineCache compiles\n */\nexport function kernelSpec(\n id: KernelId,\n overrides?: Readonly<Record<string, number | boolean>>,\n snippets?: Readonly<Record<string, string>>,\n): WgslModuleSpec {\n const entry = entryOf(id);\n return {\n id: entry.id,\n body: bodyOverrides.get(id) ?? entry.body,\n bindings: entry.bindings,\n overrideDecls: entry.overrideDecls,\n overrides: overrides ?? {},\n needs: entry.needs,\n uniforms: entry.uniforms,\n snippets,\n };\n}\n\n/**\n * The sabotage seam (spec 11.9 item 1): replaces an entry's body for specs created afterwards (null restores).\n * Tests use a FRESH context per mutation because the pipeline key does not include the body.\n * @internal\n * @param id - the module id\n * @param body - the replacement body, or null to restore the normative one\n */\nexport function setKernelBodyOverride(id: KernelId, body: string | null): void {\n entryOf(id);\n if (body === null) {\n bodyOverrides.delete(id);\n } else {\n bodyOverrides.set(id, body);\n }\n}\n\n/**\n * The group-0 graph bindings of a core with the dummy rules applied (spec 3.5, 4.1): colIdx <- rowPtr when null,\n * weights <- colIdx ?? rowPtr when null, perm <- rowPtr when null. `weights` is the binding to use in the weights\n * slot: omitted -> core.weights (degree, segmented-reduce); a layout passes its RESOLVED weights\n * (ModelResources.weights, 3.13), null meaning \"attract with 1.0\" even on a weighted snapshot.\n * @param core - the resident core arrays of a snapshot\n * @param perm - the degreeOrder row permutation, or null (rowPtr is bound as the dummy)\n * @param weights - the weights binding to use; undefined takes the core's, null binds the colIdx dummy\n * @returns the four bindings in slot order\n */\nexport function graphBindings(\n core: CoreBinding,\n perm: Binding | null,\n weights?: Binding | null,\n): Readonly<Record<\"rowPtr\" | \"colIdx\" | \"weights\" | \"perm\", Binding>> {\n const colIdx = core.colIdx ?? core.rowPtr;\n const resolved = weights === undefined ? core.weights : weights;\n return {\n rowPtr: core.rowPtr,\n colIdx,\n weights: resolved ?? colIdx,\n perm: perm ?? core.rowPtr,\n };\n}\n\n/**\n * The override values graphBindings implies: USE_PERM = perm !== null, HAS_WEIGHTS = (weights === undefined ?\n * core.weights : weights) !== null.\n * @param core - the resident core arrays of a snapshot\n * @param perm - the row permutation binding, or null\n * @param weights - the weights binding to use; undefined takes the core's, null means \"unweighted\"\n * @returns the two standard override values of the variant\n */\nexport function graphOverrides(\n core: CoreBinding,\n perm: Binding | null,\n weights?: Binding | null,\n): Readonly<{ USE_PERM: boolean; HAS_WEIGHTS: boolean }> {\n const resolved = weights === undefined ? core.weights : weights;\n return { USE_PERM: perm !== null, HAS_WEIGHTS: resolved !== null };\n}\n","/**\n * The shape helpers every core-walking primitive shares (spec 4.1): the row count and the arc count a CoreBinding\n * implies, the per-window binding of a windowed core (P4-T7, PD-8), the windowed rejections the pull and the\n * whole-core drivers keep (DEP-P4-B), and the ViewBinding -> CoreBinding adapter the P7 pull kernels need.\n * Moved out of segmented-reduce.ts by M8b-T4 so spmv.ts can use them without duplicating them; the `primitive`\n * argument keeps each caller's error details byte-identical to what they were when the helpers were private.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type CoreBinding, type ViewBinding } from \"../memory/residency.js\";\nimport { type ArcWindow, type Binding } from \"../types/memory.js\";\n\n/** The lanes one TIER 1 (mid-degree) row is folded by, in segmentedReduce and spmvPull alike (PD-6: bitwise the same on every subgroup size). */\nexport const MID_TIER_LANES = 32;\n\n/** The degree tiers of degreeOrder(): the permutation binding and the CPU-side segmentOffsets [0, hiEnd, midEnd, lowEnd, n]. */\nexport interface DegreeTiers {\n readonly perm: Binding;\n readonly segmentOffsets: readonly [number, number, number, number, number];\n}\n\n/**\n * The DegreeTiers of a degreeOrder / reverseDegreeOrder view (the perm binding and the five segment offsets\n * [0, hiEnd, midEnd, lowEnd, n] of graph-format's cuGraph thresholds 1024 / 32 / 1).\n * @param view - residency.view(s, \"degreeOrder\") or view(s, \"reverseDegreeOrder\")\n * @returns the tiers; E_INVALID_ARGUMENT when the view has no perm binding or its segmentOffsets are not five\n * ascending numbers ending at the row count (4 bytes per row of the perm binding)\n */\nexport function degreeTiersOf(view: ViewBinding): DegreeTiers {\n const { perm }: { readonly perm?: Binding | undefined } = view.bindings;\n if (perm === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `the ${view.view} view has no perm binding`, {\n argument: \"view\",\n value: view.view,\n expected: \"a view with a perm binding (degreeOrder, reverseDegreeOrder)\",\n });\n }\n const so: readonly number[] | undefined = view.scalars.segmentOffsets;\n const ascending =\n so !== undefined &&\n so.length === 5 &&\n so[0] === 0 &&\n so.every((value, k) => Number.isInteger(value) && (k === 0 || value >= so[k - 1]));\n if (!ascending || so[4] !== perm.size / 4) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `the ${view.view} view's segmentOffsets are not five ascending numbers ending at the row count`,\n {\n argument: \"view\",\n value: so === undefined ? null : Array.from(so),\n expected: `[0, hiEnd, midEnd, lowEnd, ${perm.size / 4}] ascending`,\n },\n );\n }\n const segmentOffsets: readonly [number, number, number, number, number] = [so[0], so[1], so[2], so[3], so[4]];\n return Object.freeze({ perm, segmentOffsets });\n}\n\n/**\n * The row count of a core from its rowPtr binding (4(n + 1) bytes).\n * @param core - the core\n * @param primitive - the caller's name, used in the message and the detail\n * @returns n\n */\nexport function rowCountOf(core: CoreBinding, primitive: string): number {\n const bytes = core.rowPtr.size;\n if (bytes < 4 || bytes % 4 !== 0) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${primitive}: a rowPtr binding of ${bytes} bytes is not 4(n + 1)`,\n {\n argument: \"core.rowPtr\",\n value: bytes,\n expected: \"a positive multiple of 4\",\n },\n );\n }\n return bytes / 4 - 1;\n}\n\n/**\n * The arc count a core implies: the colIdx binding is 4 bytes per arc, and a null colIdx is an arc-less snapshot.\n * @param core - the core\n * @returns the arc count\n */\nexport function arcCountOf(core: CoreBinding): number {\n return core.colIdx === null ? 0 : core.colIdx.size / 4;\n}\n\n/**\n * The binding of one arc window of a windowed core's arc-indexed array (spec 4.2): the buffer the window was placed\n * in, at the window's offset, over its arcs; the kernel reads `array[arc - P.arcBase]` with `arcBase = w.start`.\n * @param core - a windowed core (arcBuffers non-null)\n * @param name - the arc-indexed array\n * @param w - one of core.windows\n * @returns the binding; E_INVALID_ARGUMENT when the core is not windowed or the array is absent\n */\nexport function windowBinding(core: CoreBinding, name: \"colIdx\" | \"weights\" | \"arcToEdge\", w: ArcWindow): Binding {\n const buffer = core.arcBuffers?.[name][w.bufferIndex];\n if (buffer === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `windowBinding: the core has no window buffers of ${name}`, {\n argument: \"core\",\n value: name,\n expected: \"a windowed core whose plan uploaded the array\",\n });\n }\n return { buffer, offset: w.offset, size: 4 * (w.end - w.start), window: w };\n}\n\n/** One dispatch of a frontier-walking kernel over a core (P8-T12): the arc range it owns and the core with its arc-indexed arrays bound to that window (the core itself, over every arc, when it is not windowed). */\nexport interface CoreWindow {\n readonly arcBase: number;\n readonly arcEnd: number;\n readonly core: CoreBinding;\n}\n\n/**\n * The per-window dispatches of a kernel that walks rows named by a FRONTIER rather than by a row range (P8-T12:\n * `advance-expand`, `bfs-fused`, `bfs-bottom-up`, `sssp-pred`): every window sees every frontier entry and clips\n * each row to `[arcBase, arcEnd)`, so the ranges must PARTITION `[0, arcCount)` or a row is expanded twice. P4's\n * windows do not: `planArcWindows` opens a window at the previous window's end aligned DOWN to 64 arcs, so two\n * consecutive windows overlap by up to 63 arcs at an unaligned row boundary (the overlap belongs to the earlier\n * window's rows, which a row-range dispatch such as `degree` never revisits). Here a window owns `[start, next\n * window's start)` -- the last one `[start, end)` -- which is inside its binding (`next.start <= end`) and\n * partitions the arcs exactly; a window whose owned range is empty dispatches, harmlessly, over nothing.\n * @param core - the core (windowed or not)\n * @returns one entry per window, in arc order; exactly one entry over `[0, arcCount)` when the core is not windowed\n */\nexport function coreWindows(core: CoreBinding): readonly CoreWindow[] {\n if (core.windows === null) {\n return [{ arcBase: 0, arcEnd: arcCountOf(core), core }];\n }\n return core.windows.map((w, k, all) => ({\n arcBase: w.start,\n arcEnd: k + 1 < all.length ? all[k + 1].start : w.end,\n core: {\n ...core,\n colIdx: windowBinding(core, \"colIdx\", w),\n weights: core.weights === null ? null : windowBinding(core, \"weights\", w),\n },\n }));\n}\n\n/**\n * Rejects a windowed core: the pull cannot accumulate its affine epilogue across windows (DEP-P4-B).\n * @param core - the core\n * @param primitive - the caller's name, used in the message and the feature detail\n */\nexport function assertNotWindowed(core: CoreBinding, primitive: string): void {\n if (core.plan === \"windowed\" || core.windows !== null) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${primitive}: windowed cores are not executed by the pull`, {\n feature: `${primitive}.windowed`,\n });\n }\n}\n\n/**\n * Rejects a windowed core for a driver that walks the whole core (DEP-P4-B: pageRank, the power iterations and\n * connectedComponents): `E_TOO_LARGE { needed, limit, path: \"windowed\", algorithm }` (spec 3.8 / 3.12), the refusal\n * GraphResidency.core() itself issued before P4-T7 executed windows for degree and segmentedReduce.\n * @param core - the core\n * @param arcCount - the snapshot's arc count (4 bytes per arc of each arc-indexed array)\n * @param limit - the device's maxStorageBufferBindingSize\n * @param algorithm - the driver's name\n */\nexport function assertWholeCore(core: CoreBinding, arcCount: number, limit: number, algorithm: string): void {\n if (core.plan === \"windowed\") {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${algorithm}: the arc arrays need a windowed upload (${core.windows?.length ?? 0} windows), which ${algorithm} does not execute (DEP-P4-B)`,\n { needed: 4 * arcCount, limit, path: \"windowed\", algorithm },\n );\n }\n}\n\n/**\n * The CoreBinding shape of a residency VIEW (spec 4.3). residency.view() returns a ViewBinding -- a name -> Binding\n * record -- while graphBindings / graphOverrides and every core-walking primitive read rowPtr / colIdx / weights as\n * top-level fields (src/kernels.ts graphBindings / graphOverrides). This is the only adapter between the two in the\n * package. `plan` is \"perArray\" because views always upload per array (spec 4.3 lines 1182-1186) and `windows` is\n * null because a view is never windowed, which is what makes assertNotWindowed pass for a view. `serial` is -1: a\n * view is not a core and no caller of this function reads serial (nothing in src/primitives or src/algorithms\n * reads CoreBinding.serial). A zero-size `colIdx` or `weights` binding (the reverse view of an arc-less directed\n * snapshot uploads zero-byte arc arrays) becomes null, the core's own spelling of \"no arcs\", so `graphBindings` binds\n * the dummy instead of a zero-length range (P8-T8: the one-node directed fixture of the BFS suite).\n * @param v - the view binding, from residency.view(s, \"reverse\") or view(s, \"edgeList\")\n * @param arcCount - the arc count of the view, from v.scalars.arcCount[0]; it must agree with the colIdx binding,\n * which is what record() derives the arc window from (E_INVALID_ARGUMENT { argument: \"arcCount\" } otherwise)\n * @returns the equivalent CoreBinding\n */\nexport function coreOfView(v: ViewBinding, arcCount: number): CoreBinding {\n const { rowPtr }: { readonly rowPtr?: Binding | undefined } = v.bindings;\n if (rowPtr === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `the ${v.view} view has no rowPtr binding`, {\n argument: \"view\",\n value: v.view,\n expected: \"a view with a rowPtr binding (reverse)\",\n });\n }\n // an arc-less DIRECTED snapshot's reverse view uploads zero-byte arc arrays; the core spells \"no arcs\" as null\n // (graphBindings then binds the rowPtr dummy), and a zero-size binding is never bound (spec 3.6)\n const colIdx = v.bindings.colIdx === undefined || v.bindings.colIdx.size === 0 ? null : v.bindings.colIdx;\n const weights = v.bindings.weights === undefined || v.bindings.weights.size === 0 ? null : v.bindings.weights;\n const bound = colIdx === null ? 0 : colIdx.size / 4;\n if (bound !== arcCount) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `the ${v.view} view binds ${bound} arcs but its arcCount scalar says ${arcCount}`,\n {\n argument: \"arcCount\",\n value: arcCount,\n expected: bound,\n },\n );\n }\n return Object.freeze({\n serial: -1,\n plan: \"perArray\" as const,\n rowPtr,\n colIdx,\n weights,\n arcToEdge: null,\n edgeToArc: null,\n windows: null,\n arcBuffers: null,\n hasWeights: weights !== null,\n });\n}\n","/**\n * The UniformRing of spec 5.3: one UNIFORM buffer holding UNIFORM_SLOT_BYTES-stride slots for the\n * per-iteration params of a batch. A batch reserves k contiguous slots, writes their values into the\n * host shadow, flushes them with ONE queue.writeBuffer and records k dispatches that select their slot\n * through a dynamic offset -- no per-iteration writeBuffer and no host round trip. The stride is 256\n * because minUniformBufferOffsetAlignment is 256 on every runtime the package targets (the Dawn-node\n * ADAPTER advertises 64, which the package never requests; spec 2.6).\n */\n\nimport { UNIFORM_SLOT_BYTES } from \"../constants.js\";\nimport type { AllocationTracker } from \"../device/error-scope.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport type { Binding } from \"../types/memory.js\";\nimport type { UniformBlock, UniformValues } from \"./struct-block.js\";\n\n/** One UNIFORM buffer with UNIFORM_SLOT_BYTES-stride slots for the per-iteration params of a batch (spec 5.3). */\nexport class UniformRing {\n /** Number of slots. */\n readonly slots: number;\n /**\n * How many reservations covered a DIRTY slot (written since the last `flush()`): the one reuse that corrupts,\n * because the batch being recorded still reads that record and the shadow overwrites it before the flush sends\n * either. A wrap onto slots an earlier, flushed batch wrote is harmless: its `writeBuffer` is ordered before that\n * batch's submit and the next flush after it. A driver sizes its ring so this stays 0 (P8-T12: `bfsRingSlots`).\n */\n overruns = 0;\n private readonly dirty: Uint8Array;\n private readonly device: GPUDevice;\n private readonly allocator: AllocationTracker;\n private readonly buffer: GPUBuffer;\n private readonly label: string;\n private readonly shadow: ArrayBuffer;\n private readonly view: DataView;\n private next = 0;\n private dirtyLo = -1;\n private dirtyHi = -1;\n private destroyed = false;\n\n /**\n * Creates the ring buffer (`slots x UNIFORM_SLOT_BYTES` bytes, UNIFORM | COPY_DST) through the allocator.\n * @param device - the device the buffer belongs to\n * @param allocator - the context's OOM-scoped allocator (the buffer is destroyed through it)\n * @param slots - number of slots; E_INVALID_ARGUMENT unless a positive integer\n * @param label - the buffer label\n */\n constructor(device: GPUDevice, allocator: AllocationTracker, slots: number, label: string) {\n if (!Number.isInteger(slots) || slots < 1) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformRing \"${label}\": slots must be a positive integer, got ${slots}`,\n {\n argument: \"slots\",\n value: slots,\n expected: \"an integer >= 1\",\n },\n );\n }\n this.device = device;\n this.allocator = allocator;\n this.slots = slots;\n this.label = label;\n this.shadow = new ArrayBuffer(slots * UNIFORM_SLOT_BYTES);\n this.view = new DataView(this.shadow);\n this.dirty = new Uint8Array(slots);\n this.buffer = allocator.createBuffer({\n label,\n size: slots * UNIFORM_SLOT_BYTES,\n usage: BufferUsage.UNIFORM | BufferUsage.COPY_DST,\n });\n }\n\n /**\n * The whole-buffer binding a kernel binds once (size = the block's byteLength; the slot is the dynamic offset).\n * @param block - the params block the kernel declares for this binding\n * @returns the binding at offset 0 of the ring buffer\n */\n binding(block: UniformBlock): Binding {\n this.assertLive();\n this.assertFits(block);\n return { buffer: this.buffer, offset: 0, size: block.byteLength, window: null };\n }\n\n /**\n * Byte offset of a slot (the dynamic offset a dispatch passes for it).\n * @param slot - a slot index in [0, slots)\n * @returns slot x UNIFORM_SLOT_BYTES\n */\n offsetOf(slot: number): number {\n this.checkSlot(slot);\n return slot * UNIFORM_SLOT_BYTES;\n }\n\n /**\n * Reserves `count` contiguous slots for a batch, wrapping to 0 when the tail is too short; E_INVALID_ARGUMENT when count > slots.\n * @param count - slots needed, in [1, slots]\n * @returns the first slot of the reservation\n */\n reserve(count: number): number {\n this.assertLive();\n if (!Number.isInteger(count) || count < 1 || count > this.slots) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformRing \"${this.label}\": cannot reserve ${count} of ${this.slots} slots`,\n {\n argument: \"count\",\n value: count,\n expected: `an integer in [1, ${this.slots}]`,\n },\n );\n }\n if (this.next + count > this.slots) {\n this.next = 0;\n }\n const first = this.next;\n this.next += count;\n if (this.dirty.subarray(first, first + count).includes(1)) {\n this.overruns += 1;\n }\n return first;\n }\n\n /**\n * Writes one block's values into a slot of the host shadow; `flush()` sends the dirty range with one writeBuffer.\n * @param slot - the slot to fill\n * @param block - the block whose layout the bytes follow\n * @param values - the field values (a missing field is written as 0 by the block)\n */\n write(slot: number, block: UniformBlock, values: UniformValues): void {\n this.checkSlot(slot);\n this.assertFits(block);\n block.write(this.view, values, slot * UNIFORM_SLOT_BYTES);\n this.dirty[slot] = 1;\n if (this.dirtyLo < 0 || slot < this.dirtyLo) {\n this.dirtyLo = slot;\n }\n if (slot > this.dirtyHi) {\n this.dirtyHi = slot;\n }\n }\n\n /**\n * queue.writeBuffer of the dirty slots (called by the batch driver before submit): one call covering\n * [lowest dirty slot, highest dirty slot]; nothing when no slot is dirty.\n */\n flush(): void {\n this.assertLive();\n if (this.dirtyLo < 0) {\n return;\n }\n const begin = this.dirtyLo * UNIFORM_SLOT_BYTES;\n const end = (this.dirtyHi + 1) * UNIFORM_SLOT_BYTES;\n this.device.queue.writeBuffer(this.buffer, begin, this.shadow, begin, end - begin);\n this.dirty.fill(0);\n this.dirtyLo = -1;\n this.dirtyHi = -1;\n }\n\n /** Destroys the buffer (through the allocator); idempotent. */\n destroy(): void {\n if (this.destroyed) {\n return;\n }\n this.destroyed = true;\n this.allocator.destroy(this.buffer);\n }\n\n private assertLive(): void {\n if (this.destroyed) {\n throw new WebGpuGraphError(\"E_DISPOSED\", `UniformRing \"${this.label}\" is destroyed`, { label: this.label });\n }\n }\n\n private checkSlot(slot: number): void {\n this.assertLive();\n if (!Number.isInteger(slot) || slot < 0 || slot >= this.slots) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformRing \"${this.label}\": slot ${slot} is outside [0, ${this.slots})`,\n {\n argument: \"slot\",\n value: slot,\n expected: `an integer in [0, ${this.slots})`,\n },\n );\n }\n }\n\n private assertFits(block: UniformBlock): void {\n if (block.byteLength > UNIFORM_SLOT_BYTES) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `UniformRing \"${this.label}\": block ${block.name} is ${block.byteLength} bytes, a slot holds ${UNIFORM_SLOT_BYTES}`,\n { argument: \"block\", value: block.name, expected: `byteLength <= ${UNIFORM_SLOT_BYTES}` },\n );\n }\n }\n}\n","/**\n * The `exclusiveScan` primitive driver (spec 6 row 2; P4-T2, PD-3): a reduce-then-scan over u32 words. Level 0 runs\n * `scan-block` over `count` items into `out` (each workgroup an exclusive Hillis-Steele scan of its WG-wide block) and\n * writes one block sum per workgroup; while a level has more than one block, the next level scans its block sums\n * (exclusive, into `offsets_L`) and writes its own block sums, recursively; the top level has ONE block, so its one\n * sums word is the total. Then, top down, `scan-add` adds `offsets_L[g]` to every element of block `g` of level L's\n * output. u32 addition is exact in any order, so two runs on any two adapters are bitwise identical; there is no\n * subgroup variant (DEP-P4-E) and no decoupled look-back.\n *\n * The driver owns no device objects beyond a one-word zero it keeps for the empty scan: the caller supplies a\n * ReduceScope (the same record `reduce` takes) and the compute pass to record into. `src/primitives/**` never imports\n * `src/context.ts`.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type DispatchPlan, groupsOf, plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { kernelSpec, SCAN_PARAMS } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ReduceScope } from \"./reduce.js\";\n\n/** Where the scan's total landed: one u32 word at `index` of `binding` (a word of the planner's scratch, valid until the next record()). */\nexport interface ScanTotal {\n readonly binding: Binding;\n readonly index: number;\n}\n\n/** A prepared exclusive scan (spec 6 row 2): records the level dispatches of one scan into a pass. */\nexport interface ScanPlanner {\n /**\n * Records the scan of `count` u32 of `src` into `out` (exclusive); returns where the total landed (a word of the\n * planner's scratch, valid until the next record()); nothing for count 0 (the total word is then 0).\n * @param pass - the compute pass\n * @param src - the input words (at least 4 x count bytes)\n * @param count - the word count (a non-negative integer below 2^32)\n * @param out - the output words (at least 4 x count bytes)\n * @returns the total's location\n */\n record(pass: GPUComputePassEncoder, src: Binding, count: number, out: Binding): ScanTotal;\n /** Dispatches the last record() issued: 0 for count 0, else `2 x levels - 1` (one block scan per level, one add-back per level below the top). */\n readonly lastDispatches: number;\n}\n\n/** The largest u32: the largest count `ScanParams.count` can carry. */\nconst U32_MAX = 0xffffffff;\n\n/**\n * Prepares the two scan pipelines of a scope (compiles once) so record() is synchronous. The zero word the empty\n * scan's total points at is a scratch of `scope`, so the planner lives exactly as long as the scope: never use a\n * planner after its scope's dispose().\n * @param scope - the caller's scope (device, caps, cache, scratch, params)\n * @returns the planner\n */\nexport async function prepareScan(scope: ReduceScope): Promise<ScanPlanner> {\n const block = await scope.pipelines.kernel(kernelSpec(\"scan-block\"));\n const add = await scope.pipelines.kernel(kernelSpec(\"scan-add\"));\n const zero = scope.scratch(4, \"scan/zero\");\n scope.device.queue.writeBuffer(zero, 0, new Uint32Array(1));\n return new ScanPlannerImpl(scope, block, add, { buffer: zero, offset: 0, size: 4, window: null });\n}\n\n/**\n * The argument checks of record() (E_INVALID_ARGUMENT before anything is recorded).\n * @param src - the input binding\n * @param count - the word count\n * @param out - the output binding\n */\nfunction checkRecordArguments(src: Binding, count: number, out: Binding): void {\n if (!Number.isSafeInteger(count) || count < 0 || count > U32_MAX) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"scan: count must be a non-negative integer below 2^32\", {\n argument: \"count\",\n value: count,\n });\n }\n if (src.size < 4 * count) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"scan: src is smaller than 4 x count bytes\", {\n argument: \"src\",\n value: src.size,\n expected: 4 * count,\n });\n }\n if (out.size < 4 * count) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"scan: out is smaller than 4 x count bytes\", {\n argument: \"out\",\n value: out.size,\n expected: 4 * count,\n });\n }\n}\n\n/** One level of the recursion: its input words, its exclusive output, its count, its dispatch plan and its per-block sums. */\ninterface Level {\n readonly input: Binding;\n readonly output: Binding;\n readonly count: number;\n readonly plan: DispatchPlan;\n readonly sums: Binding;\n}\n\n/** The planner: the two resolved kernels over one scope. */\nclass ScanPlannerImpl implements ScanPlanner {\n private readonly scope: ReduceScope;\n private readonly block: Kernel;\n private readonly add: Kernel;\n private readonly zero: Binding;\n private dispatches = 0;\n\n /**\n * Wraps the resolved kernels; use prepareScan().\n * @param scope - the caller's scope\n * @param block - the `scan-block` kernel\n * @param add - the `scan-add` kernel\n * @param zero - a one-word binding holding 0 (the total of the empty scan)\n */\n constructor(scope: ReduceScope, block: Kernel, add: Kernel, zero: Binding) {\n this.scope = scope;\n this.block = block;\n this.add = add;\n this.zero = zero;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns the count\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the levels into the pass (see the interface).\n * @param pass - the compute pass\n * @param src - the input words\n * @param count - the word count\n * @param out - the output words\n * @returns the total's location\n */\n record(pass: GPUComputePassEncoder, src: Binding, count: number, out: Binding): ScanTotal {\n checkRecordArguments(src, count, out);\n if (count === 0) {\n this.dispatches = 0;\n return { binding: this.zero, index: 0 };\n }\n const wg = this.scope.workgroupSize;\n const levels: Level[] = [];\n let input = src;\n let output = out;\n let levelCount = count;\n for (;;) {\n const blocks = Math.ceil(levelCount / wg);\n // Sized by the PADDED workgroup count (reduce's shape, reduce.ts partials-1): above MAX_1D_ITEMS plan1d pads\n // the grid to x * y >= blocks, and every padded workgroup still stores its (zero) block sum at its own index.\n // The next level scans only `blocks` words, so the padded tail is written and never read.\n const plan = plan1d(levelCount, wg, this.scope.caps);\n const groups = groupsOf(plan);\n const sums = this.scratch(groups, `scan/sums${levels.length}`);\n levels.push({ input, output, count: levelCount, plan, sums });\n if (blocks === 1) {\n break;\n }\n input = sums;\n output = this.scratch(groups, `scan/offsets${levels.length}`);\n levelCount = blocks;\n }\n for (const level of levels) {\n const params = this.scope.params(SCAN_PARAMS, { count: level.count, pad0: 0, pad1: 0, pad2: 0 });\n const bound = this.block.bind({\n src: level.input,\n out: level.output,\n blockSums: level.sums,\n P: params.binding,\n });\n this.block.dispatch(pass, bound, level.plan, [params.offset]);\n }\n for (let l = levels.length - 2; l >= 0; l--) {\n const level = levels[l];\n const params = this.scope.params(SCAN_PARAMS, { count: level.count, pad0: 0, pad1: 0, pad2: 0 });\n const bound = this.add.bind({ out: level.output, blockOffsets: levels[l + 1].output, P: params.binding });\n this.add.dispatch(pass, bound, level.plan, [params.offset]);\n }\n this.dispatches = 2 * levels.length - 1;\n const top = levels[levels.length - 1];\n return { binding: top.sums, index: 0 };\n }\n\n /**\n * A scratch of `words` u32 from the scope, bound whole (never zero-length; the pool rounds the buffer up).\n * @param words - the word count (>= 1)\n * @param label - the scratch label\n * @returns the binding\n */\n private scratch(words: number, label: string): Binding {\n const size = 4 * words;\n const buffer = this.scope.scratch(size, label);\n return { buffer, offset: 0, size, window: null };\n }\n}\n","/**\n * The device self-check: one real exclusive scan of known numbers, run once per device before this package\n * computes anything on it, so a device that returns wrong numbers is refused instead of believed.\n *\n * WHY IT EXISTS. On the Windows host lane -- Dawn's D3D12 backend over the Microsoft Basic Render Driver, the\n * software renderer built into Windows -- every exclusive scan of more than one workgroup came back wrong: a\n * block total of 1 where 256 belonged, or a second block nothing wrote at all, differing between two runs of\n * identical code in one job. Everything built on the scan was wrong with it (the histogram, the radix sort, the\n * grid build and every layout above them, eighteen test files), while every single-block scan and every earlier\n * primitive stayed right. Three shader repairs failed; copying Microsoft's current redistributable renderer\n * beside the runner's Node executable made all of it pass untouched. The defect is the driver's, and the danger\n * to a caller is not a crash but silence: a graph laid out from wrong numbers with no error anywhere.\n *\n * WHY IT SCANS RATHER THAN PROBING A CONSTRUCT. An earlier hand-written probe matrix of workgroup constructs\n * (test/primitives/workgroup-id-probe.test.ts) was measured PASSING on that renderer in the same job in which the\n * real scan returned the wrong answer, so a copy of the shader's shape is not evidence about the shader. This\n * check therefore drives the shipped `prepareScan` through the shipped composer and pipeline cache: it tests the\n * code that runs, and it cannot drift away from it. One scan covers both recorded failures -- a value crossing\n * `workgroupBarrier` inside a block, and a block total crossing from one dispatch of a compute pass to the next\n * dispatch that reads it, which is the shape of every driver in this package.\n *\n * WHY IT REFUSES RATHER THAN ROUTING AROUND THE DEFECT. See docs/decisions/device-self-check.md: a barrier-free second\n * implementation was designed and costed, and rejected because it would ship unverified on the only platform it\n * exists for.\n *\n * WHERE IT RUNS. Lazily, at the first compute entry point a caller reaches, memoised per GPUDevice: the\n * algorithms (degree, connectedComponents, the power-iteration family) and calibrateLayout await it on entry, and\n * a layout simulation awaits it in the compile-and-bind promise `load()` starts -- the promise every batch and\n * every debug run already awaits before it may submit. So a caller is covered whether the context was created,\n * adopted through `create({ device })` or adopted through `GpuContext.from`, and a simulation refuses before its\n * first iteration without the check sitting on the per-batch path, where an extra await would move the moment a\n * submission becomes visible to a step() issued in the same tick and so change how the frame loop coalesces.\n * It deliberately does NOT run in GpuContext.create:\n * a context that only compiles -- Dawn's null backend, which computes nothing by design -- must stay usable, and\n * `src/context.ts` may not import a primitive (the layer rule of spec 3.2).\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { UniformRing } from \"../kernel/uniform-ring.js\";\nimport { type CheckedContext, type DeviceCheck, type DeviceCheckMismatch } from \"../types/context.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ReduceScope } from \"./reduce.js\";\nimport { prepareScan } from \"./scan.js\";\n\n/**\n * The word written into every output slot before the dispatch, so a word NOTHING wrote is distinguishable from\n * a word written wrongly. The Windows lane returned this value from the second block, which is how the failure\n * was read as \"the block was never written\" rather than \"the block was miscomputed\".\n */\nconst POISON = 0xdeadbeef;\n\n/** Full workgroups the check scans; one partial workgroup of a single word follows them. */\nconst CHECK_BLOCKS = 32;\n\n/** Params slots the scan's levels need (two levels of block scan plus one add-back, with room to spare). */\nconst RING_SLOTS = 8;\n\n/** The settled check per device: the one work a second caller never repeats. A rejection is dropped, so a check that failed to RUN is retried. */\nconst checked = new WeakMap<GPUDevice, Promise<DeviceCheck>>();\n\n/**\n * The input word at `i`: 1, 2, 3, ... so no two workgroups have the same block total (all-ones would give every\n * block the same one, and a block total stored at the wrong index would still read correct -- which is exactly\n * the Windows symptom) and every output word is a different number.\n * @param i - the word index\n * @returns the input value\n */\nfunction inputAt(i: number): number {\n return i + 1;\n}\n\n/**\n * The verdict: the first output word or total that disagrees with the arithmetic answer, or null when nothing\n * does. Pure, so test/primitives/verify.test.ts can drive it past a fabricated wrong result and exercise the\n * refusal without a broken device.\n * @param words - the `count` output words read back from the device\n * @param total - the total word read back from the device\n * @param count - the words scanned\n * @returns the first disagreement, or null\n * @internal\n */\nexport function checkScanWords(words: Uint32Array, total: number, count: number): DeviceCheckMismatch | null {\n let running = 0;\n for (let i = 0; i < count; i++) {\n const got = words[i];\n if (got !== running) {\n return { where: `out[${String(i)}]`, expected: running, actual: got, poison: got === POISON };\n }\n // u32 addition wraps in WGSL, so the host oracle wraps too: at WORKGROUP_SIZE 256 the total cannot\n // reach 2^32, but a false refusal would deny every device on earth, so it is not left to that constant\n running = (running + inputAt(i)) >>> 0;\n }\n if (total !== running) {\n return { where: \"total\", expected: running, actual: total, poison: total === POISON };\n }\n return null;\n}\n\n/**\n * Binds a whole scratch buffer.\n * @param buffer - the buffer\n * @param size - the bytes bound\n * @returns the binding\n */\nfunction whole(buffer: GPUBuffer, size: number): Binding {\n return { buffer, offset: 0, size, window: null };\n}\n\n/**\n * Runs the check once: one scan of `CHECK_BLOCKS * workgroupSize + 1` words recorded into one compute pass, one\n * submit, the output and the total read back and verified on the host.\n *\n * It never throws for a wrong ANSWER -- that is the returned record's job. A failure of the machinery (a lost\n * device, a validation error, out of memory) propagates with its own code, so \"the driver computes incorrectly\"\n * is never said about a device that merely died.\n * @param ctx - the context to check\n * @returns what the check found\n */\nasync function runCheck(ctx: CheckedContext): Promise<DeviceCheck> {\n const started = performance.now();\n const wg = ctx.workgroupSize;\n const count = CHECK_BLOCKS * wg + 1;\n const bytes = 4 * count;\n const lease = ctx.pool.lease();\n const ring = new UniformRing(ctx.device, ctx.allocator, RING_SLOTS, \"device-check/ring\");\n try {\n const scope: ReduceScope = {\n device: ctx.device,\n caps: ctx.caps,\n pipelines: ctx.pipelines,\n pool: ctx.pool,\n workgroupSize: wg,\n scratch: (byteLength, label) => lease.storage(byteLength, `device-check/${label}`),\n params(block, values) {\n const slot = ring.reserve(1);\n ring.write(slot, block, values);\n return { binding: ring.binding(block), offset: ring.offsetOf(slot) };\n },\n };\n const planner = await prepareScan(scope);\n const src = lease.storage(bytes, \"device-check/src\");\n const out = lease.storage(bytes, \"device-check/out\");\n const input = new Uint32Array(count);\n for (let i = 0; i < count; i++) {\n input[i] = inputAt(i);\n }\n ctx.device.queue.writeBuffer(src, 0, input);\n ctx.device.queue.writeBuffer(out, 0, new Uint32Array(count).fill(POISON));\n const encoder = ctx.device.createCommandEncoder({ label: \"device-check\" });\n const pass = encoder.beginComputePass({ label: \"device-check\" });\n const total = planner.record(pass, whole(src, bytes), count, whole(out, bytes));\n pass.end();\n ring.flush();\n ctx.device.queue.submit([encoder.finish()]);\n const words = new Uint32Array(await ctx.readback.read(out, bytes));\n const totalWord = new Uint32Array(\n await ctx.readback.read(total.binding.buffer, 4, undefined, total.binding.offset + 4 * total.index),\n );\n const mismatch = checkScanWords(words, totalWord[0], count);\n return {\n check: \"exclusive-scan\",\n ok: mismatch === null,\n workgroupSize: wg,\n count,\n blocks: CHECK_BLOCKS,\n ms: performance.now() - started,\n vendor: ctx.caps.vendor,\n architecture: ctx.caps.architecture,\n description: ctx.caps.description,\n mismatch,\n };\n } finally {\n ring.destroy();\n lease.release();\n }\n}\n\n/**\n * What this device computed when it was asked for an answer this package already knows, run once per device and\n * remembered. A caller may await it before committing work to a context; every compute entry point of the\n * package awaits it too, so the cost is paid once whoever asks first.\n *\n * It reports rather than throws, so a caller can ask a device a question without having to catch the answer. The\n * entry points use `assertDeviceComputes`, which turns a failing report into E_DEVICE_INCORRECT.\n * @param ctx - the context whose device is checked\n * @returns the capability record; `ok` false means this device returns wrong numbers\n */\nexport function verifyDevice(ctx: CheckedContext): Promise<DeviceCheck> {\n const cached = checked.get(ctx.device);\n if (cached !== undefined) {\n return cached;\n }\n const running = runCheck(ctx).catch((err: unknown) => {\n // only a settled verdict is worth keeping: a check that could not RUN (a lost device, a transient\n // out-of-memory) must not answer for the device forever\n checked.delete(ctx.device);\n throw err;\n });\n checked.set(ctx.device, running);\n return running;\n}\n\n/**\n * The guard every compute entry point awaits: resolves on a device that computed the check correctly, throws\n * E_DEVICE_INCORRECT on one that did not, carrying the first wrong word, what was required there, and the\n * adapter strings that separate a broken driver from a fixed one.\n * @param ctx - the context about to be computed on\n * @internal\n */\nexport async function assertDeviceComputes(ctx: CheckedContext): Promise<void> {\n const check = await verifyDevice(ctx);\n const { mismatch } = check;\n if (mismatch === null) {\n return;\n }\n const adapter = {\n vendor: check.vendor,\n architecture: check.architecture,\n device: ctx.caps.device,\n description: check.description,\n };\n const hint =\n check.architecture === \"warp\"\n ? \"this is the Microsoft Basic Render Driver; the Microsoft.Direct3D.WARP redistributable (1.0.21 or newer) beside the host executable computes it correctly\"\n : undefined;\n const observed = mismatch.poison\n ? `${mismatch.where} was never written (the ${String(POISON)} the check wrote beforehand survived the dispatch)`\n : `${mismatch.where} came back as ${String(mismatch.actual)} where ${String(mismatch.expected)} was required`;\n const message =\n `this device computes multi-workgroup shaders incorrectly: an exclusive scan of ${String(check.count)} ` +\n `known numbers is wrong -- ${observed}. Refusing to run: every number this package computed here would ` +\n `be unreliable. adapter: ${adapter.vendor}/${adapter.architecture} \"${adapter.description}\"`;\n throw new WebGpuGraphError(\n \"E_DEVICE_INCORRECT\",\n hint === undefined ? message : `${message}. ${hint}`,\n {\n check: check.check,\n where: mismatch.where,\n expected: mismatch.expected,\n actual: mismatch.actual,\n poison: mismatch.poison,\n count: check.count,\n blocks: check.blocks,\n workgroupSize: check.workgroupSize,\n adapter,\n ...(hint === undefined ? {} : { hint }),\n },\n );\n}\n","/**\n * The ReduceScope an algorithm driver hands the primitives (contract 3.11), built over a GpuContext: `scratch` comes\n * from ONE Lease (released by `dispose()` in the algorithm's `finally`, spec 4.4) and `params` from a UniformRing\n * slot, so a batch of k iterations writes k parameter blocks into one buffer and dispatches with dynamic offsets\n * instead of allocating a uniform buffer per dispatch (spec 5.3). The src/ twin of the tests' testReduceScope\n * (test/helpers/segmented-reduce.ts). `slots` sizes the ring for the LARGEST batch the caller records: reserve()\n * wraps, so a ring too small silently reuses a slot another dispatch of the same batch still reads.\n */\n\nimport { type GpuContext } from \"../context.js\";\nimport { UniformRing } from \"../kernel/uniform-ring.js\";\nimport { type ReduceScope } from \"../primitives/reduce.js\";\n\n/** A ReduceScope over a context plus the two lifecycle calls an algorithm makes: flush() before submit, dispose() in its finally. (The `indirect()` lease it once added for the frontier's args buffer went with that buffer, 2026-09-25.) */\nexport interface AlgorithmScope extends ReduceScope {\n /** queue.writeBuffer of the params slots written since the last flush (called before the batch is submitted). */\n flush(): void;\n /** Destroys the ring and releases every scratch buffer of the lease; idempotent. */\n dispose(): void;\n /** The ring's `overruns` so far: reservations that wrapped over a record the batch being recorded still reads (0 on a correctly sized ring; P8-T12). */\n ringOverruns(): number;\n}\n\n/**\n * The scope of one algorithm call.\n * @param ctx - the context\n * @param label - the label prefix of the ring and every scratch buffer\n * @param slots - the params slots of the ring: at least the parameter blocks of the largest batch recorded\n * @returns the scope\n */\nexport function algorithmScope(ctx: GpuContext, label: string, slots: number): AlgorithmScope {\n const lease = ctx.pool.lease();\n const ring = new UniformRing(ctx.device, ctx.allocator, slots, `${label}/ring`);\n return {\n device: ctx.device,\n caps: ctx.caps,\n pipelines: ctx.pipelines,\n pool: ctx.pool,\n workgroupSize: ctx.workgroupSize,\n scratch: (byteLength, scratchLabel) => lease.storage(byteLength, `${label}/${scratchLabel}`),\n params(block, values) {\n const slot = ring.reserve(1);\n ring.write(slot, block, values);\n return { binding: ring.binding(block), offset: ring.offsetOf(slot) };\n },\n flush: () => {\n ring.flush();\n },\n dispose(): void {\n ring.destroy();\n lease.release();\n },\n ringOverruns: () => ring.overruns,\n };\n}\n","/**\n * The `compact` and `dedupe` primitive driver (spec 6 row 4; P8-T3, the P8 plan's PD-1 / DEP-P8-A). `compact` is\n * flag, scan, scatter: the flags are the caller's (one u32 per entry, written by the kernel that produced the queue),\n * `exclusiveScan` turns them into offsets, and `compact-scatter` lands every flagged entry at its offset in queue\n * order -- order-preserving, so bitwise reproducible -- and writes the total into one word of the caller's block.\n * `dedupe` is Davidson's ownership trick in two dispatches: `dedupe-claim` stores every entry's index into\n * `owner[vertex]`, `dedupe-filter` keeps the entries that still own their vertex. Two dispatches because a plain\n * store read back in the same dispatch is a data race (WGSL 6.5.7); between dispatches the relaxed atomics make\n * last-writer-wins well defined, so exactly one index per distinct vertex survives (set-deterministic: the SET is\n * fixed, the order inside `out` follows the schedule).\n *\n * `owner` needs NO reset between calls, whatever it holds: a word is read only by an entry `i` whose vertex `v` a\n * claim of the SAME call has just written, so a stale index or garbage at `owner[v]` is overwritten before any lane\n * compares against it, and a word no current entry names is never read. The design's row implies a reset; the `fill`\n * over `n` per round is the dispatch this saves.\n *\n * The count of `compact` is host-known. `dedupe`'s callers (the SSSP piles of P8-T9) only know their entry count on\n * the device, so `countIndex` names a word of the counters block and the kernels read `min(counters[countIndex],\n * count)` -- the device word clamped to the capacity `count` -- or `count` alone when `countIndex` is `U32_MAX`. The\n * counters block is bound WHOLE and indexed, for the count word and for the output word alike, because\n * `Kernel.bind` rejects a binding whose offset is not a multiple of 256 and a four-byte word never is.\n *\n * The driver owns no device objects: the caller supplies a ReduceScope (the same record `reduce` takes) and the\n * compute pass to record into. `src/primitives/**` never imports `src/context.ts`.\n */\n\nimport { U32_MAX } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { COMPACT_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ReduceScope } from \"./reduce.js\";\nimport { prepareScan, type ScanPlanner } from \"./scan.js\";\n\n/** One compaction: `count` entries of `queue` whose `flags` word is non-zero go to `out` in order; the total goes to `outCount[outIndex]`. */\nexport interface CompactRecord {\n /** The entries (at least 4 x count bytes). */\n readonly queue: Binding;\n /** One u32 per entry, 0 or 1 (at least 4 x count bytes). */\n readonly flags: Binding;\n /** The entry count (a non-negative integer below 2^32; host-known). */\n readonly count: number;\n /** The compacted entries (at least 4 x count bytes; the words past the total are not written). */\n readonly out: Binding;\n /** The block whose word `outIndex` receives the total (bound whole). */\n readonly outCount: Binding;\n /** The word of `outCount` to write. */\n readonly outIndex: number;\n}\n\n/** One dedupe: the entries of `queue` are filtered to one per distinct vertex into `out`; the surviving count is ADDED to `outCount[outIndex]`, which the caller zeroes before the pass. */\nexport interface DedupeRecord {\n /** The entries, vertex indices below the owner's length (at least 4 x count bytes). */\n readonly queue: Binding;\n /** The entry count when `countIndex` is `U32_MAX`, else the capacity the device count is clamped to (a non-negative integer below 2^32). */\n readonly count: number;\n /** `U32_MAX` for a host-known count; else the word of `counters` holding the entry count on the device. */\n readonly countIndex: number;\n /** The block the count word is read from; with a device count it must be the SAME range as `outCount` (both kernels read the word through their own binding), and it is bound but never read when `countIndex` is `U32_MAX`. */\n readonly counters: Binding;\n /** The ownership words, one per vertex (the caller's promise: at least 4 x n bytes; never reset). */\n readonly owner: Binding;\n /** The surviving entries (at least 4 x count bytes; the words past the count are not written). */\n readonly out: Binding;\n /** The block whose word `outIndex` accumulates the surviving count (bound whole; zeroed by the caller before the pass). */\n readonly outCount: Binding;\n /** The word of `outCount` to add to; never equal to `countIndex`. */\n readonly outIndex: number;\n}\n\n/** A prepared compact / dedupe (spec 6 row 4): records the dispatches of one call into a pass. */\nexport interface CompactPlanner {\n /**\n * Records the compaction (the flags' exclusive scan, then the scatter). For count 0 nothing is recorded and\n * `outCount[outIndex]` keeps its prior value: a four-byte write at an unaligned offset is impossible, so every\n * caller zeroes its block before the pass.\n * @param pass - the compute pass\n * @param record - the buffers and the count\n */\n record(pass: GPUComputePassEncoder, record: CompactRecord): void;\n /**\n * Records the claim and the filter over `plan1d(count)`; nothing for count 0 (`outCount[outIndex]` then keeps\n * its prior value).\n * @param pass - the compute pass\n * @param record - the buffers, the count and the count word\n */\n recordDedupe(pass: GPUComputePassEncoder, record: DedupeRecord): void;\n /** Dispatches the last record*() issued: compact 0 for count 0, else the scan's `2 x levels - 1` plus one (`2 x levels`); dedupe 0 for a direct count 0, else 2. */\n readonly lastDispatches: number;\n}\n\n/**\n * Prepares the three pipelines and the scan of a scope (compiles once) so record() is synchronous. The planner\n * lives exactly as long as the scope (the scan keeps a scratch word of it): never use it after the scope's dispose().\n * @param scope - the caller's scope (device, caps, cache, scratch, params)\n * @returns the planner\n */\nexport async function prepareCompact(scope: ReduceScope): Promise<CompactPlanner> {\n const scatter = await scope.pipelines.kernel(kernelSpec(\"compact-scatter\"));\n const claim = await scope.pipelines.kernel(kernelSpec(\"dedupe-claim\"));\n const filter = await scope.pipelines.kernel(kernelSpec(\"dedupe-filter\"));\n const scan = await prepareScan(scope);\n return new CompactPlannerImpl(scope, scatter, claim, filter, scan);\n}\n\n/**\n * The E_INVALID_ARGUMENT of a bad count.\n * @param what - the primitive's name for the message\n * @param count - the count\n */\nfunction checkCount(what: string, count: number): void {\n if (!Number.isSafeInteger(count) || count < 0 || count > U32_MAX) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${what}: count must be a non-negative integer below 2^32`, {\n argument: \"count\",\n value: count,\n });\n }\n}\n\n/**\n * The E_INVALID_ARGUMENT of a binding shorter than `words` u32.\n * @param what - the primitive's name for the message\n * @param name - the argument name\n * @param binding - the binding\n * @param words - the words it must hold\n */\nfunction checkWords(what: string, name: string, binding: Binding, words: number): void {\n if (binding.size < 4 * words) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${what}: ${name} is smaller than 4 x ${words} bytes`, {\n argument: name,\n value: binding.size,\n expected: 4 * words,\n });\n }\n}\n\n/**\n * The E_INVALID_ARGUMENT of a word index outside a block.\n * @param what - the primitive's name for the message\n * @param name - the argument name\n * @param index - the word index\n * @param block - the block it indexes\n */\nfunction checkWordIndex(what: string, name: string, index: number, block: Binding): void {\n if (!Number.isSafeInteger(index) || index < 0 || 4 * (index + 1) > block.size) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${what}: ${name} ${index} is outside the block`, {\n argument: name,\n value: index,\n expected: `0 <= ${name} < ${Math.floor(block.size / 4)}`,\n });\n }\n}\n\n/**\n * The argument checks of record() (E_INVALID_ARGUMENT before anything is recorded).\n * @param r - the record\n */\nfunction checkCompactArguments(r: CompactRecord): void {\n checkCount(\"compact\", r.count);\n checkWords(\"compact\", \"queue\", r.queue, r.count);\n checkWords(\"compact\", \"flags\", r.flags, r.count);\n checkWords(\"compact\", \"out\", r.out, r.count);\n checkWordIndex(\"compact\", \"outIndex\", r.outIndex, r.outCount);\n}\n\n/**\n * The argument checks of recordDedupe(): the count, the two entry buffers (`out` holds at\n * most one entry per owner word, so it is checked against `min(count, owner words)`: the SSSP piles of P8-T9 dedupe\n * a raw half of `arcCount` capacity into an `n`-word pile), the output word, and -- with a device count -- a count\n * word that is inside `counters`, is not the output word (the filter's atomicAdd would corrupt the count other\n * workgroups of the same dispatch still read) and lives in the block `outCount` names (the two kernels read it\n * through their own binding).\n * @param r - the record\n */\nfunction checkDedupeArguments(r: DedupeRecord): void {\n checkCount(\"dedupe\", r.count);\n checkWords(\"dedupe\", \"queue\", r.queue, r.count);\n checkWords(\"dedupe\", \"out\", r.out, Math.min(r.count, Math.floor(r.owner.size / 4)));\n checkWordIndex(\"dedupe\", \"outIndex\", r.outIndex, r.outCount);\n if (r.countIndex === U32_MAX) {\n return;\n }\n checkWordIndex(\"dedupe\", \"countIndex\", r.countIndex, r.counters);\n if (r.countIndex === r.outIndex) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"dedupe: countIndex must not be the output word outIndex\", {\n argument: \"countIndex\",\n value: r.countIndex,\n });\n }\n if (\n r.counters.buffer !== r.outCount.buffer ||\n r.counters.offset !== r.outCount.offset ||\n r.counters.size !== r.outCount.size\n ) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n \"dedupe: counters must be the same range as outCount when countIndex names a device word\",\n {\n argument: \"counters\",\n value: r.counters.size,\n expected: r.outCount.size,\n },\n );\n }\n}\n\n/** The two bound dedupe kernels and the dynamic offset of the one params record they share. */\ninterface BoundDedupe {\n readonly claim: BoundKernel;\n readonly filter: BoundKernel;\n readonly offset: number;\n}\n\n/** The planner: the three resolved kernels and the scan over one scope. */\nclass CompactPlannerImpl implements CompactPlanner {\n private readonly scope: ReduceScope;\n private readonly scatter: Kernel;\n private readonly claim: Kernel;\n private readonly filter: Kernel;\n private readonly scan: ScanPlanner;\n private dispatches = 0;\n\n /**\n * Wraps the resolved kernels; use prepareCompact().\n * @param scope - the caller's scope\n * @param scatter - the `compact-scatter` kernel\n * @param claim - the `dedupe-claim` kernel\n * @param filter - the `dedupe-filter` kernel\n * @param scan - the scan planner of the same scope\n */\n constructor(scope: ReduceScope, scatter: Kernel, claim: Kernel, filter: Kernel, scan: ScanPlanner) {\n this.scope = scope;\n this.scatter = scatter;\n this.claim = claim;\n this.filter = filter;\n this.scan = scan;\n }\n\n /**\n * Dispatches the last record*() issued.\n * @returns the count\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the scan and the scatter (see the interface).\n * @param pass - the compute pass\n * @param r - the record\n */\n record(pass: GPUComputePassEncoder, r: CompactRecord): void {\n checkCompactArguments(r);\n if (r.count === 0) {\n this.dispatches = 0;\n return;\n }\n const size = 4 * r.count;\n const offsets: Binding = { buffer: this.scope.scratch(size, \"compact/offsets\"), offset: 0, size, window: null };\n this.scan.record(pass, r.flags, r.count, offsets);\n const params = this.scope.params(COMPACT_PARAMS, {\n count: r.count,\n outIndex: r.outIndex,\n countIndex: U32_MAX,\n stride: 0,\n });\n const bound = this.scatter.bind({\n queue: r.queue,\n flags: r.flags,\n offsets,\n out: r.out,\n outCount: r.outCount,\n P: params.binding,\n });\n this.scatter.dispatch(pass, bound, plan1d(r.count, this.scope.workgroupSize, this.scope.caps), [params.offset]);\n this.dispatches = this.scan.lastDispatches + 1;\n }\n\n /**\n * Records the claim and the filter over plan1d(count) (see the interface).\n * @param pass - the compute pass\n * @param r - the record\n */\n recordDedupe(pass: GPUComputePassEncoder, r: DedupeRecord): void {\n checkDedupeArguments(r);\n if (r.count === 0) {\n this.dispatches = 0;\n return;\n }\n const plan = planGridStride(r.count, this.scope.workgroupSize, this.scope.caps);\n const bound = this.bindDedupe(r, plan.stride ?? this.scope.workgroupSize);\n this.claim.dispatch(pass, bound.claim, plan, [bound.offset]);\n this.filter.dispatch(pass, bound.filter, plan, [bound.offset]);\n this.dispatches = 2;\n }\n\n /**\n * One params record (both kernels read the same values) and the two bind groups.\n * @param r - the record\n * @param stride - the grid-stride plan's stride (entries per pass over the grid)\n * @returns the bound kernels and the record's dynamic offset\n */\n private bindDedupe(r: DedupeRecord, stride: number): BoundDedupe {\n const params = this.scope.params(COMPACT_PARAMS, {\n count: r.count,\n outIndex: r.outIndex,\n countIndex: r.countIndex,\n stride,\n });\n return {\n claim: this.claim.bind({ queue: r.queue, owner: r.owner, counters: r.counters, P: params.binding }),\n filter: this.filter.bind({\n queue: r.queue,\n owner: r.owner,\n out: r.out,\n outCount: r.outCount,\n P: params.binding,\n }),\n offset: params.offset,\n };\n }\n}\n","/**\n * The `Frontier` of design 6 row 7 and the device-side dispatch selector of design 5.4 (P8-T4; the P8 plan's PD-1,\n * PD-3, PD-8, PD-23, DEP-P8-A, DEP-P8-C). A traversal's per-level state is two n-slot vertex queues, ONE 25-word\n * counters block (every counter of the phase is a word of it: a four-byte word is never a legal storage-binding\n * offset, and the selector must reach every count it acts on through one binding) and the edge queue. The host\n * never reads a counter inside a submit: `frontier-finalize`, one lane, runs at the START of every level (role 0:\n * rotates `nextFrontierCount` into `frontierCount`, advances `level`, decides `done`, chooses the level's path) and\n * again once the edge queue is filled (role 1: clamps `edgeCount`, or on an overflow -- `edgeCountUnclamped >\n * edgeCapacity` -- switches the path to the fused retry, PD-23). The choice is the block's `path` word (`W.path`,\n * word 24); every level kernel is a direct grid-stride dispatch that reads it first and does nothing unless the\n * word names it (design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md: the seven indirect slots the\n * selector once wrote per level cost about 0.4 ms of Dawn validation each and were 97 % of a traversal's wall\n * time; they and their args buffer are gone). The host records up to `MAX_LEVELS_PER_SUBMIT` levels per submit and\n * reads `done` (four bytes) once per submit; a boundary that finds `done` set writes path 0 and moves no counter,\n * so the recorded levels past the end are no-ops and the counters freeze at the finishing boundary's values.\n *\n * The seed: `frontierCount` is NEVER seeded, because the first boundary rotates it out unread. A BFS driver calls\n * `reset(queue, source, { nextFrontierCount: 1, level: U32_MAX })`: the first boundary rotates the 1 in, adds it into\n * `visitedCount`, and wraps `level` to 0, so the level-0 expansion claims the source's neighbours at `level + 1 == 1`.\n * `reset` is a queue write, ordered before the submit that follows, and it puts the source on side 0.\n *\n * Every buffer comes from the caller's ONE lease (`scope.scratch`) so the algorithm's dispose()\n * releases them together (design 4.4). The two vertex queues are two BUFFERS, never two ranges of one: `Kernel.bind`\n * rejects one buffer bound read-only and read-write in one dispatch even for disjoint ranges. `src/primitives/**`\n * never imports `src/context.ts`.\n */\n\nimport { MAX_LEVELS_PER_SUBMIT, U32_MAX } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { FRONTIER_COUNTERS, FRONTIER_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ReduceScope } from \"./reduce.js\";\n\n/** The values of the `path` word (`W.path`): what a level's kernels run; every level kernel reads it first. */\nexport const PATH: Readonly<{\n none: 0;\n twoPhase: 1;\n fused: 2;\n bottomUp: 3;\n fusedRetry: 4;\n near: 5;\n far: 6;\n}> = Object.freeze({ none: 0, twoPhase: 1, fused: 2, bottomUp: 3, fusedRetry: 4, near: 5, far: 6 });\n\n/** The words of the counters block (`FRONTIER_COUNTERS`), by index: byte offset 4 x word; no driver types a number. */\nexport const W: Readonly<{\n frontierCount: 0;\n nextFrontierCount: 1;\n frontierDegreeSum: 2;\n prevFrontierCount: 3;\n prevDegreeSum: 4;\n unvisitedCount: 5;\n unvisitedDegreeSum: 6;\n unvisitedListLen: 7;\n edgeCount: 8;\n edgeCountUnclamped: 9;\n overflowLevels: 10;\n level: 11;\n visitedCount: 12;\n switches: 13;\n direction: 14;\n done: 15;\n arcsScanned: 16;\n fusedLevels: 17;\n twoPhaseLevels: 18;\n bottomUpLevels: 19;\n farCount: 20;\n nextFarCount: 21;\n thresholdBits: 22;\n deltaBits: 23;\n path: 24;\n nextDegreeSum: 25;\n stackTop: 26;\n sigmaOverflow: 27;\n}> = Object.freeze({\n frontierCount: 0,\n nextFrontierCount: 1,\n frontierDegreeSum: 2,\n prevFrontierCount: 3,\n prevDegreeSum: 4,\n unvisitedCount: 5,\n unvisitedDegreeSum: 6,\n unvisitedListLen: 7,\n edgeCount: 8,\n edgeCountUnclamped: 9,\n overflowLevels: 10,\n level: 11,\n visitedCount: 12,\n switches: 13,\n direction: 14,\n done: 15,\n arcsScanned: 16,\n fusedLevels: 17,\n twoPhaseLevels: 18,\n bottomUpLevels: 19,\n farCount: 20,\n nextFarCount: 21,\n thresholdBits: 22,\n deltaBits: 23,\n path: 24,\n nextDegreeSum: 25,\n stackTop: 26,\n sigmaOverflow: 27,\n});\n\n/** The words a `reset` seeds (every other word is zeroed). */\nexport type FrontierSeed = Readonly<Partial<Record<keyof typeof W, number>>>;\n\n/** The `FrontierParams` fields a caller passes to `recordFinalize`; the planner fills `role`, `wg`, `edgeCapacity` and `n` itself. A missing field is written as 0. */\nexport type FrontierFinalizeFields = Readonly<\n Partial<\n Record<\n | \"alpha\"\n | \"beta\"\n | \"fusedMax\"\n | \"maxDepth\"\n | \"mode\"\n | \"cutoffBits\"\n | \"arcBase\"\n | \"arcEnd\"\n | \"predKind\"\n | \"bitsBase\"\n | \"source\"\n | \"stride\"\n | \"firstOfSubmit\"\n | \"iteration\",\n number\n >\n >\n>;\n\n/**\n * The given words of a partial record (a key spelled with an undefined value is dropped, so the block writer sees\n * only numbers).\n * @param words - the partial record\n * @returns the defined entries\n */\nfunction definedWords(words: Readonly<Partial<Record<string, number>>>): Record<string, number> {\n const out: Record<string, number> = {};\n for (const [name, value] of Object.entries(words)) {\n if (value !== undefined) {\n out[name] = value;\n }\n }\n return out;\n}\n\n/** The largest role `frontier-finalize` knows: 0 and 1 land here (P8-T4), 2 and 3 are the SSSP piles' (P8-T9). */\nconst MAX_ROLE = 3;\n\n/**\n * The E_INVALID_ARGUMENT of a value that is not a non-negative integer.\n * @param argument - the argument name\n * @param value - the value\n */\nfunction assertCount(argument: string, value: number): void {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `frontier: ${argument} must be a non-negative integer`, {\n argument,\n value,\n expected: \"a non-negative integer\",\n });\n }\n}\n\n/** The frontier queue of design 6 row 7: two vertex queues, the counters block and the edge queue, all leased by the caller's scope. */\nexport class Frontier {\n /** The two n-slot u32 vertex queues (`vertices[side]` is the input of the current level). */\n readonly vertices: readonly [Binding, Binding];\n /** The `FrontierCounters` block, 112 B, bound by every kernel as `array<atomic<u32>>`. */\n readonly counters: Binding;\n /** The edge queue: `edgeCapacity` entries of u32 (the target vertex of an arc). */\n readonly edgeQueue: Binding;\n /** How many entries the edge queue holds; role 1 clamps `edgeCount` to it and detects an overflow above it. */\n readonly edgeCapacity: number;\n /** The vertex count (a `reset` source is below it). */\n readonly n: number;\n private sideIndex: 0 | 1 = 0;\n\n /**\n * Wraps the leased buffers; use prepareFrontier().\n * @param vertices - the two vertex queues\n * @param counters - the counters block\n * @param edgeQueue - the edge queue\n * @param edgeCapacity - the edge queue's entry count\n * @param n - the vertex count\n */\n constructor(\n vertices: readonly [Binding, Binding],\n counters: Binding,\n edgeQueue: Binding,\n edgeCapacity: number,\n n: number,\n ) {\n this.vertices = vertices;\n this.counters = counters;\n this.edgeQueue = edgeQueue;\n this.edgeCapacity = edgeCapacity;\n this.n = n;\n }\n\n /**\n * Which vertex queue is the input of the current level (a host-side index between two cached bind-group sets).\n * @returns 0 or 1\n */\n get side(): 0 | 1 {\n return this.sideIndex;\n }\n\n /**\n * The vertex queue the current level expands from.\n * @returns `vertices[side]`\n */\n get input(): Binding {\n return this.sideIndex === 0 ? this.vertices[0] : this.vertices[1];\n }\n\n /**\n * The vertex queue the current level's claims append to.\n * @returns `vertices[1 - side]`\n */\n get output(): Binding {\n return this.sideIndex === 0 ? this.vertices[1] : this.vertices[0];\n }\n\n /** Flips the two vertex queues; the counts rotate inside the block, so nothing else moves. */\n swap(): void {\n this.sideIndex = this.sideIndex === 0 ? 1 : 0;\n }\n\n /**\n * Seeds a traversal: one `queue.writeBuffer` of the whole 112-byte block (zero except the caller's words) and one of\n * `vertices[0][0] = source`, both ordered before the submit that follows; the source is on side 0 afterwards.\n * `frontierCount` is not a word to seed: the first boundary rotates word 1 into it (the BFS seed is\n * `{ nextFrontierCount: 1, level: U32_MAX }`). A source outside `[0, n)`, an unknown word or a value that is not a\n * u32 is E_INVALID_ARGUMENT before anything is written.\n * @param queue - the device queue\n * @param source - the source vertex\n * @param seed - the words to seed\n */\n reset(queue: GPUQueue, source: number, seed: FrontierSeed): void {\n if (!Number.isInteger(source) || source < 0 || source >= this.n) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `frontier: source ${source} is outside [0, ${this.n})`, {\n argument: \"source\",\n value: source,\n expected: `an integer in [0, ${this.n})`,\n });\n }\n const bytes = new ArrayBuffer(FRONTIER_COUNTERS.byteLength);\n FRONTIER_COUNTERS.write(new DataView(bytes), definedWords(seed));\n this.sideIndex = 0;\n queue.writeBuffer(this.counters.buffer, this.counters.offset, bytes);\n queue.writeBuffer(this.vertices[0].buffer, this.vertices[0].offset, Uint32Array.of(source));\n }\n}\n\n/** A prepared frontier (design 6 row 7): the leased queue and the recorded selector dispatches. */\nexport interface FrontierPlanner {\n /** The queue the planner's selector rotates and chooses the path of. */\n readonly frontier: Frontier;\n /**\n * Records one `frontier-finalize` dispatch (one workgroup) in `role` for `level` of the current submit: one\n * `FrontierParams` record with `wg`, `edgeCapacity` and `n` filled by the planner and every other field from\n * `fields`. A level outside `[0, MAX_LEVELS_PER_SUBMIT)` (the selector addresses nothing by level any more, but\n * the host's submit cadence still is the bound) or a role outside `[0, 3]` is E_INVALID_ARGUMENT before\n * anything is recorded.\n * @param pass - the compute pass\n * @param role - 0 the level boundary, 1 the edge-queue role (2 and 3 are P8-T9's)\n * @param level - the level inside the submit\n * @param fields - the tuning and window words\n */\n recordFinalize(pass: GPUComputePassEncoder, role: number, level: number, fields: FrontierFinalizeFields): void;\n}\n\n/**\n * Leases the frontier's buffers from the scope and compiles the selector so `recordFinalize` is synchronous. The\n * edge capacity defaults to `max(1, min(arcCount, floor(maxStorageBufferBindingSize / 4)))` (never a zero-length\n * buffer: the one-node graph has no arcs); a test passes a small one to force the overflow path. The planner lives\n * exactly as long as the scope: never use it after the scope's dispose().\n * @param scope - the caller's scope (device, caps, cache, scratch, params)\n * @param n - the vertex count\n * @param arcCount - the arc count (the natural edge-queue size)\n * @param edgeCapacity - the edge queue's entry count, when the caller chooses it (an integer >= 1)\n * @returns the planner\n */\nexport async function prepareFrontier(\n scope: ReduceScope,\n n: number,\n arcCount: number,\n edgeCapacity?: number,\n): Promise<FrontierPlanner> {\n assertCount(\"n\", n);\n assertCount(\"arcCount\", arcCount);\n const capacity =\n edgeCapacity ?? Math.max(1, Math.min(arcCount, Math.floor(scope.caps.limits.maxStorageBufferBindingSize / 4)));\n if (!Number.isSafeInteger(capacity) || capacity < 1 || capacity > U32_MAX) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"frontier: edgeCapacity must be an integer >= 1\", {\n argument: \"edgeCapacity\",\n value: capacity,\n expected: \"an integer in [1, 2^32)\",\n });\n }\n const kernel = await scope.pipelines.kernel(kernelSpec(\"frontier-finalize\"));\n const queueBytes = 4 * Math.max(1, n);\n const vertices: readonly [Binding, Binding] = [\n { buffer: scope.scratch(queueBytes, \"frontier/vertices-0\"), offset: 0, size: queueBytes, window: null },\n { buffer: scope.scratch(queueBytes, \"frontier/vertices-1\"), offset: 0, size: queueBytes, window: null },\n ];\n const counters: Binding = {\n buffer: scope.scratch(FRONTIER_COUNTERS.byteLength, \"frontier/counters\"),\n offset: 0,\n size: FRONTIER_COUNTERS.byteLength,\n window: null,\n };\n const edgeQueue: Binding = {\n buffer: scope.scratch(4 * capacity, \"frontier/edge-queue\"),\n offset: 0,\n size: 4 * capacity,\n window: null,\n };\n const frontier = new Frontier(vertices, counters, edgeQueue, capacity, n);\n return new FrontierPlannerImpl(scope, kernel, frontier);\n}\n\n/** The planner: the selector kernel bound once to the frontier's block. */\nclass FrontierPlannerImpl implements FrontierPlanner {\n readonly frontier: Frontier;\n private readonly scope: ReduceScope;\n private readonly kernel: Kernel;\n\n /**\n * Wraps the resolved kernel; use prepareFrontier().\n * @param scope - the caller's scope\n * @param kernel - the `frontier-finalize` kernel\n * @param frontier - the leased queue\n */\n constructor(scope: ReduceScope, kernel: Kernel, frontier: Frontier) {\n this.scope = scope;\n this.kernel = kernel;\n this.frontier = frontier;\n }\n\n /**\n * Records one selector dispatch (see the interface).\n * @param pass - the compute pass\n * @param role - the role\n * @param level - the level inside the submit\n * @param fields - the caller's fields\n */\n recordFinalize(pass: GPUComputePassEncoder, role: number, level: number, fields: FrontierFinalizeFields): void {\n if (!Number.isInteger(level) || level < 0 || level >= MAX_LEVELS_PER_SUBMIT) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `frontier: level ${level} is outside the submit`, {\n argument: \"level\",\n value: level,\n expected: `an integer in [0, ${MAX_LEVELS_PER_SUBMIT})`,\n });\n }\n if (!Number.isInteger(role) || role < 0 || role > MAX_ROLE) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `frontier: role ${role} is not a finalize role`, {\n argument: \"role\",\n value: role,\n expected: `an integer in [0, ${MAX_ROLE}]`,\n });\n }\n const { scope, frontier } = this;\n const params = scope.params(FRONTIER_PARAMS, {\n ...definedWords(fields),\n role,\n wg: scope.workgroupSize,\n edgeCapacity: frontier.edgeCapacity,\n n: frontier.n,\n });\n const bound = this.kernel.bind({ counters: frontier.counters, P: params.binding });\n this.kernel.dispatch(pass, bound, plan1d(1, scope.workgroupSize, scope.caps), [params.offset]);\n }\n}\n","/**\n * The `advance` primitive of design 6 row 8 (P8-T5 / P8-T12; the P8 plan's PD-1, PD-23, DEP-P8-A, DEP-P8-E): the\n * block-mapped expansion of a `Frontier`'s input queue into its edge queue by the `advance-expand` kernel, a DIRECT\n * grid-stride dispatch over a grid planned for n entries that loops to `frontierCount` and runs only when the `path`\n * word `frontier-finalize` role 0 wrote earlier in the same pass says the level is two-phase; the host never knows\n * the frontier's size. The kernel leaves `edgeCount` (clamped later by role 1),\n * `edgeCountUnclamped` (the overflow detector) and `frontierDegreeSum` in the counters block.\n *\n * Design 6 row 8 names three structures -- block-mapped, a WORKGROUP_PER_ROW tier for rows above 1,024 arcs, and a\n * subgroup tier. Here they are: the block-mapped body is the large-frontier kernel and already balances a hub row\n * over all `WG` lanes of its block (a 10,000-degree entry costs its block 40 strips, never one lane 10,000 reads);\n * the workgroup-per-row structure IS `bfs-fused` (P8-T7), one workgroup per frontier entry, which the selector\n * chooses for a small frontier such as a hub-only level, so `advance-expand` declares no `TIER` override and the tier\n * choice is the fused / two-phase choice; and the subgroup tier is not a second body but the same body compiled\n * against the prelude's subgroup helper block (`wg_scan_u32` becomes `subgroupExclusiveAdd` / `subgroupAdd` plus the\n * elected-lane slot carry), which `needs: [\"subgroups\"]` in the registry entry switches on when the device has the\n * feature. Both forms return each lane's prefix in LANE order, so the arcs land at the same queue positions; only\n * the order ACROSS workgroups (the `atomicAdd` reservation order) is schedule-dependent, which is why a test compares\n * sorted queues.\n *\n * A windowed core (spec 4.2: `colIdx` above `maxStorageBufferBindingSize`, bound as arc windows) is executed, not\n * refused (P8-T12 lifts DEP-P8-E for the frontier family): one dispatch per window, the frontier and its count the\n * same in every window, each dispatch binding that window's `colIdx` and\n * carrying its owned arc range in `arcBase` / `arcEnd` (`coreWindows`: the ranges partition the arcs, which P4's\n * overlapping window bounds do not). The body clips every row to the range, so a row straddling two windows emits\n * each arc exactly once, and the per-window dispatches accumulate into the same edge queue through the same\n * `edgeCount` reservation while `edgeCountUnclamped` and `frontierDegreeSum` add up across windows to the level's\n * totals. `src/primitives/**` never imports `src/context.ts`.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { planGridStride } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { FRONTIER_PARAMS, graphBindings, graphOverrides, kernelSpec } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { type CoreWindow, coreWindows, rowCountOf } from \"./core-shape.js\";\nimport { type Frontier } from \"./frontier.js\";\nimport { type ReduceScope } from \"./reduce.js\";\n\n/** A prepared advance (design 6 row 8): records one expansion of a frontier per level. */\nexport interface AdvancePlanner {\n /** The compiled `advance-expand` kernel (so `bfs-fused` can share its bind groups' shape). */\n readonly kernel: Kernel;\n /** The arc windows every level dispatches over: one over the whole core, or the windowed core's (P8-T12). */\n readonly windows: readonly CoreWindow[];\n /**\n * Records the expansion of `frontier.input` into `frontier.edgeQueue` as a DIRECT grid-stride dispatch per window\n * (`planGridStride(n)`: the frontier holds at most n entries; the kernel loops to the count word and runs only\n * when the selector's path word says the level is two-phase): one `FrontierParams` record per window\n * (`edgeCapacity`, `n`, `wg`, `stride` and the window's arc range) and the kernel bound to the window's graph\n * arrays, the input queue, the counters block and the edge queue (`Kernel.bind` reuses the bind groups of the\n * same buffers and ranges, so the two sides of a frontier cost two bind-group sets per window). A frontier\n * whose `n` is not the core's row count is E_INVALID_ARGUMENT before anything is recorded.\n * @param pass - the compute pass\n * @param frontier - the queue to expand (its `input` side)\n */\n record(pass: GPUComputePassEncoder, frontier: Frontier): void;\n}\n\n/**\n * Compiles `advance-expand` for the core's weights pattern (no permutation: the frontier names rows directly) so\n * `record` is synchronous, and resolves the core's windows once. The planner lives exactly as long as the scope:\n * never use it after the scope's dispose().\n * @param scope - the caller's scope (pipelines, params)\n * @param core - the resident core arrays of the snapshot the frontier walks (windowed or not)\n * @returns the planner\n */\nexport async function prepareAdvance(scope: ReduceScope, core: CoreBinding): Promise<AdvancePlanner> {\n const kernel = await scope.pipelines.kernel(kernelSpec(\"advance-expand\", graphOverrides(core, null)));\n return new AdvancePlannerImpl(scope, core, kernel);\n}\n\n/** The planner: the compiled kernel over one core's windows. */\nclass AdvancePlannerImpl implements AdvancePlanner {\n readonly kernel: Kernel;\n readonly windows: readonly CoreWindow[];\n private readonly scope: ReduceScope;\n private readonly n: number;\n\n /**\n * Wraps the resolved kernel; use prepareAdvance().\n * @param scope - the caller's scope\n * @param core - the core the kernel was compiled for\n * @param kernel - the `advance-expand` kernel\n */\n constructor(scope: ReduceScope, core: CoreBinding, kernel: Kernel) {\n this.scope = scope;\n this.kernel = kernel;\n this.windows = coreWindows(core);\n this.n = rowCountOf(core, \"advance\");\n }\n\n /**\n * Records one direct expansion per window (see the interface).\n * @param pass - the compute pass\n * @param frontier - the queue to expand\n */\n record(pass: GPUComputePassEncoder, frontier: Frontier): void {\n if (frontier.n !== this.n) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `advance: the frontier holds ${frontier.n} vertices, the core ${this.n} rows`,\n {\n argument: \"frontier\",\n value: frontier.n,\n expected: this.n,\n },\n );\n }\n const { scope } = this;\n const plan = planGridStride(frontier.n, scope.workgroupSize, scope.caps); // the frontier holds at most n entries\n for (const w of this.windows) {\n const params = scope.params(FRONTIER_PARAMS, {\n wg: scope.workgroupSize,\n edgeCapacity: frontier.edgeCapacity,\n n: frontier.n,\n arcBase: w.arcBase,\n arcEnd: w.arcEnd,\n stride: plan.stride ?? scope.workgroupSize,\n });\n const bound = this.kernel.bind({\n ...graphBindings(w.core, null),\n frontierIn: frontier.input,\n counters: frontier.counters,\n edgeQueue: frontier.edgeQueue,\n P: params.binding,\n });\n this.kernel.dispatch(pass, bound, plan, [params.offset]);\n }\n }\n}\n","/**\n * The `radixSort` primitive driver (spec 6 row 6; P4-T4, PD-5): a STABLE LSD key-value sort of u32 words, 8 bits per\n * pass, `bits / 8` passes. Every pass runs `radix-hist` (one 256-bin digit histogram per WG-wide block, stored\n * DIGIT-MAJOR `hist[digit * groups + group]`), `exclusiveScan` over that table (so each word becomes, per digit, the\n * offset of its workgroup in workgroup order) and `radix-scatter` (lane 0 ranks its block's keys serially in index\n * order, every lane writes its pair at `offsets[digit * groups + group] + rank`). The pairs swap after every pass, so an\n * odd pass count (bits 8 / 24) leaves the result in the caller's scratch pair and an even one (16 / 32) in the input\n * pair; record() RETURNS the pair so no caller guesses. u32 arithmetic and a serial ranking make two runs on any two\n * adapters bitwise identical.\n *\n * The scan cannot run in place: `Kernel.bind` (and WebGPU's usage-scope rule) rejects one buffer bound `storage-ro`\n * and `storage` in one dispatch, so the caller supplies TWO tables of `radixHistBytes`: `scratch.hist` (the raw\n * digit-major table `radix-hist` writes; the LAST pass's table stays there) and `scratch.offsets` (its exclusive\n * scan, what `radix-scatter` reads). Both are the caller's so a per-iteration sort (the grid, PD-11) binds the same\n * buffers every iteration and `Kernel.bind`'s identity cache holds.\n *\n * The driver owns no device objects and acquires no scratch of its own: the caller supplies a ReduceScope (the\n * record `reduce` and `exclusiveScan` take; the scan's block sums come from it) and the compute pass to record\n * into. `src/primitives/**` never imports `src/context.ts`.\n */\n\nimport { RADIX_BINS, U32_MAX } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { kernelSpec, RADIX_PARAMS } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ReduceScope } from \"./reduce.js\";\nimport { prepareScan, type ScanPlanner } from \"./scan.js\";\n\n/** The bits of one pass. */\nconst RADIX_DIGIT_BITS = 8;\n\n/** The key widths record() accepts: `bits / 8` passes, so the low `bits` of every key order the pairs. */\nexport type RadixBits = 8 | 16 | 24 | 32;\n\n/**\n * The caller's scratch: a second key-value pair the passes ping-pong with, the digit-major histogram table and its\n * scanned twin (each `radixHistBytes` bytes at least).\n */\nexport interface RadixSortScratch {\n readonly keys: Binding;\n readonly vals: Binding;\n /** The raw digit-major table `radix-hist` writes (the last pass's stays readable after the sort). */\n readonly hist: Binding;\n /** The exclusive scan of `hist`, what `radix-scatter` reads. */\n readonly offsets: Binding;\n}\n\n/** Where the sorted pairs landed: the input pair or the scratch pair (record() decides by the pass count). */\nexport interface RadixSortResult {\n readonly keys: Binding;\n readonly vals: Binding;\n}\n\n/** A prepared radix sort (spec 6 row 6): records the pass dispatches of one sort into a pass. */\nexport interface RadixSortPlanner {\n /**\n * Records the stable sort of `count` (key, value) pairs by the low `bits` of the key; returns the pair holding the\n * result (the scratch pair after an odd pass count, the input pair after an even one); count 0 records nothing and\n * returns the input pair.\n * @param pass - the compute pass\n * @param keys - the keys (at least 4 x count bytes)\n * @param vals - the values (at least 4 x count bytes)\n * @param count - the pair count (a non-negative integer below 2^32)\n * @param bits - the key width: 8, 16, 24 or 32\n * @param scratch - the second pair, the histogram table and its scanned twin\n * @returns the pair the result lives in\n */\n record(\n pass: GPUComputePassEncoder,\n keys: Binding,\n vals: Binding,\n count: number,\n bits: RadixBits,\n scratch: RadixSortScratch,\n ): RadixSortResult;\n /** Dispatches the last record() issued: 0 for count 0, else `passes x (2 + the scan's dispatches over the table)`. */\n readonly lastDispatches: number;\n}\n\n/**\n * The byte size of the digit-major histogram table of one pass over `count` keys at workgroup size `wg`:\n * `4 x 256 x ceil(count / wg)` (the caller sizes `scratch.hist` by it; 0 for count 0, which records nothing).\n * @param count - the pair count\n * @param wg - the workgroup size (`scope.workgroupSize`)\n * @returns the bytes\n */\nexport function radixHistBytes(count: number, wg: number): number {\n return 4 * RADIX_BINS * Math.ceil(count / wg);\n}\n\n/**\n * Prepares the two radix pipelines and the scan of a scope (compiles once) so record() is synchronous. The planner\n * lives exactly as long as the scope: never use a planner after its scope's dispose().\n * @param scope - the caller's scope (device, caps, cache, scratch, params)\n * @returns the planner\n */\nexport async function prepareRadixSort(scope: ReduceScope): Promise<RadixSortPlanner> {\n const hist = await scope.pipelines.kernel(kernelSpec(\"radix-hist\"));\n const scatter = await scope.pipelines.kernel(kernelSpec(\"radix-scatter\"));\n const scan = await prepareScan(scope);\n return new RadixSortPlannerImpl(scope, hist, scatter, scan);\n}\n\n/**\n * One binding-size check of record().\n * @param argument - the argument name\n * @param binding - the binding\n * @param bytes - the bytes it must hold\n */\nfunction checkBinding(argument: string, binding: Binding, bytes: number): void {\n if (binding.size < bytes) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `radixSort: ${argument} is smaller than ${bytes} bytes`, {\n argument,\n value: binding.size,\n expected: bytes,\n });\n }\n}\n\n/**\n * The argument checks of record() (E_INVALID_ARGUMENT before anything is recorded).\n * @param keys - the keys\n * @param vals - the values\n * @param count - the pair count\n * @param bits - the key width\n * @param scratch - the scratch\n * @param wg - the workgroup size\n */\nfunction checkRecordArguments(\n keys: Binding,\n vals: Binding,\n count: number,\n bits: RadixBits,\n scratch: RadixSortScratch,\n wg: number,\n): void {\n if (bits !== 8 && bits !== 16 && bits !== 24 && bits !== 32) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"radixSort: bits must be 8, 16, 24 or 32\", {\n argument: \"bits\",\n value: bits,\n expected: [8, 16, 24, 32],\n });\n }\n if (!Number.isSafeInteger(count) || count < 0 || count > U32_MAX) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"radixSort: count must be a non-negative integer below 2^32\", {\n argument: \"count\",\n value: count,\n });\n }\n const pairBytes = 4 * count;\n checkBinding(\"keys\", keys, pairBytes);\n checkBinding(\"vals\", vals, pairBytes);\n checkBinding(\"scratch.keys\", scratch.keys, pairBytes);\n checkBinding(\"scratch.vals\", scratch.vals, pairBytes);\n const tableBytes = radixHistBytes(count, wg);\n checkBinding(\"scratch.hist\", scratch.hist, tableBytes);\n checkBinding(\"scratch.offsets\", scratch.offsets, tableBytes);\n}\n\n/** The planner: the two resolved kernels and the scan over one scope. */\nclass RadixSortPlannerImpl implements RadixSortPlanner {\n private readonly scope: ReduceScope;\n private readonly hist: Kernel;\n private readonly scatter: Kernel;\n private readonly scan: ScanPlanner;\n private dispatches = 0;\n\n /**\n * Wraps the resolved kernels; use prepareRadixSort().\n * @param scope - the caller's scope\n * @param hist - the `radix-hist` kernel\n * @param scatter - the `radix-scatter` kernel\n * @param scan - the scan planner of the same scope\n */\n constructor(scope: ReduceScope, hist: Kernel, scatter: Kernel, scan: ScanPlanner) {\n this.scope = scope;\n this.hist = hist;\n this.scatter = scatter;\n this.scan = scan;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns the count\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the passes into the pass (see the interface).\n * @param pass - the compute pass\n * @param keys - the keys\n * @param vals - the values\n * @param count - the pair count\n * @param bits - the key width\n * @param scratch - the second pair, the histogram table and its scanned twin\n * @returns the pair the result lives in\n */\n record(\n pass: GPUComputePassEncoder,\n keys: Binding,\n vals: Binding,\n count: number,\n bits: RadixBits,\n scratch: RadixSortScratch,\n ): RadixSortResult {\n const wg = this.scope.workgroupSize;\n checkRecordArguments(keys, vals, count, bits, scratch, wg);\n if (count === 0) {\n this.dispatches = 0;\n return { keys, vals };\n }\n const groups = Math.ceil(count / wg);\n const plan = plan1d(count, wg, this.scope.caps);\n const tableWords = RADIX_BINS * groups;\n const tableBytes = 4 * tableWords;\n const histTable: Binding = { ...scratch.hist, size: tableBytes };\n const offsets: Binding = { ...scratch.offsets, size: tableBytes };\n let src: RadixSortResult = { keys, vals };\n let dst: RadixSortResult = { keys: scratch.keys, vals: scratch.vals };\n let dispatches = 0;\n const passes = bits / RADIX_DIGIT_BITS;\n for (let p = 0; p < passes; p++) {\n const params = this.scope.params(RADIX_PARAMS, { count, shift: RADIX_DIGIT_BITS * p, groups, pad0: 0 });\n const histBound = this.hist.bind({ keys: src.keys, hist: histTable, P: params.binding });\n this.hist.dispatch(pass, histBound, plan, [params.offset]);\n this.scan.record(pass, histTable, tableWords, offsets);\n const scatterBound = this.scatter.bind({\n keys: src.keys,\n vals: src.vals,\n offsets,\n keysOut: dst.keys,\n valsOut: dst.vals,\n P: params.binding,\n });\n this.scatter.dispatch(pass, scatterBound, plan, [params.offset]);\n dispatches += 2 + this.scan.lastDispatches;\n [src, dst] = [dst, src];\n }\n this.dispatches = dispatches;\n return src;\n }\n}\n","/**\n * Breadth-first search on the device (design 8.4, 3.3 line 807, 9.7; P8-T6 / P8-T7 / P8-T8, the P8 plan's PD-5 /\n * PD-6 / PD-7 / PD-14 / PD-18 / PD-21 / PD-23 / PD-24 / PD-26 / DEP-P8-B): the direction-optimizing traversal over\n * the `Frontier` of P8-T4, every per-level choice made ON THE DEVICE. Every level is nine recorded dispatches, all\n * DIRECT (2026-09-25, docs/decisions/G8.md G8-F5: Dawn validates every `dispatchWorkgroupsIndirect` with an internal\n * clamp pass costing about 0.4 ms of device time whether or not it dispatches anything, in Node and in Chromium\n * alike, and that was 97 % of a traversal's wall time) -- `frontier-finalize` role 0 (the level boundary: rotates\n * the counts, advances `level`, decides `done`, evaluates Beamer's test and CHOOSES, writing the choice into the\n * block's `path` word: 3 bottom-up, 2 fused for a top-down frontier below `fusedMax` entries, 1 two-phase for any\n * other, 0 done), `advance-expand` (the frontier's rows into the edge queue), `frontier-finalize` role 1 (clamps\n * `edgeCount`, or, when the edge queue overflowed, sets `path` 4 for the fused retry, PD-23), `bfs-contract` (the\n * claim `atomicMin(&depth[v], level + 1)`, the winners packed into the next vertex queue), `bfs-fused` (one workgroup\n * per frontier entry with the same claim inline and no edge queue; the fused level and the retry alike), then the\n * bottom-up trio: a `fill` zeroing the frontier bitset, `bfs-bitset-build` setting the frontier's bits, and\n * `bfs-bottom-up` sweeping the unvisited list over the REVERSE core (each unvisited vertex reads its in-neighbours\n * until the first one in the bitset and claims itself), and last `bfs-next-degree` (the out-degree sum of whatever\n * the level claimed, into the block's `nextDegreeSum` word: Beamer's m_f for the NEXT boundary, measured on the\n * frontier that boundary decides for -- issue #391, which found the previous proxy, the degree of the frontier just\n * expanded, one level stale and missing the switch at the level holding two thirds of the 1M / 10M R-MAT's arcs).\n * Every kernel is a grid-stride dispatch of a host-planned grid (`planGridStride`) that loops to its count word and\n * reads the path word first, so exactly one path does the level's work and the others cost one uniform load per\n * workgroup. The unvisited set Beamer's test is against (PD-18) is rebuilt exactly once per submit, before the\n * levels, by `bfs-unvisited-flags` plus `compact` over an iota queue, and maintained between rebuilds by subtraction\n * inside the selector (whose JSDoc states the boundary rule; both words are exact at every boundary). The host records `MAX_LEVELS_PER_SUBMIT`\n * levels into ONE command buffer, submits, and reads four bytes, the `done` word (PD-7): a road network has\n * thousands of levels and a per-level `mapAsync` would be slower than the CPU. A level recorded past the end is a\n * no-op (its boundary finds `done` set, writes path 0 and moves no counter), so the loop needs no diameter and\n * ends on `done`; a traversal has at most `n` levels, so more submits than that is E_VALIDATION, never a hang. The\n * thresholds are uniform fields (`FUSED_FRONTIER_MAX`; alpha derived as `max(1, floor(arcCount / n))`, PD-21;\n * `BEAMER_BETA`; `mode 1` pinning top-down -- each unless the tuning says otherwise), so a test forces any path\n * without recompiling; the block's `fusedLevels` / `twoPhaseLevels` / `bottomUpLevels` / `overflowLevels` /\n * `switches` words record which path each level took.\n *\n * There is no dedupe (DEP-P8-B, PD-5): the edge queue holds duplicates -- a vertex with three frontier neighbours\n * appears three times -- but for one level exactly one invocation observes `INVALID_INDEX` at `depth[v]` and\n * exactly that one appends `v`, so the next vertex frontier is duplicate-free by construction and an ownership\n * dedupe would have nothing to remove. `parent` is not written by the claim (PD-24): `sssp-pred` in `MODE 1` runs\n * once over the settled depths and writes the SMALLEST `u` with `depth[u] + 1 == depth[v]` and an arc `u -> v`, so\n * it is bitwise reproducible where a claim-time parent would be a scheduling accident. `order` (PD-14) is one\n * stable radix sort of the node indices by `depth`: grouped by level, ascending by index within a level,\n * `INVALID_INDEX` last, and the first `visitedCount` values are the result. The result batch stages every array\n * into one staging slot, so a traversal maps `ceil(levels / 32) + 1` buffers in all.\n *\n * `maxDepth` reaches the device as a `u32` field of `FrontierParams`, and the uniform writer refuses anything that\n * is not an integer in `[0, 2^32 - 1]`; the host therefore normalises it first, to exactly the CPU port's rule\n * (`algorithms/src/indexed/bfs.ts`: a node at depth `d >= maxDepth` is reached and not expanded, unbounded when\n * absent). The tuning entry `bfsWithTuning` (PD-26) is what the tests drive; nothing public exposes it.\n *\n * A core whose `colIdx` exceeds `maxStorageBufferBindingSize` is bound as arc windows and EXECUTED (P8-T12, DEP-P8-E\n * lifted for the frontier family): `advance-expand`, `bfs-fused` and `sssp-pred` run once per window of the\n * forward core and `bfs-bottom-up` once per window of the reverse core, every window its own dispatch with its own\n * `FrontierParams` record carrying the window's owned arc range (`coreWindows`), and the claims, being `atomicMin`s\n * and an `INVALID_INDEX` entry test, are idempotent across windows. The ring is sized per run by `bfsRingSlots`.\n */\n\nimport { type GraphSnapshot, INVALID_INDEX, type U32 } from \"@graphty/graph-format\";\n\nimport { BEAMER_BETA, FUSED_FRONTIER_MAX, MAX_LEVELS_PER_SUBMIT, U32_MAX } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { type DispatchPlan, plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { type UniformValues } from \"../kernel/struct-block.js\";\nimport {\n FILL_PARAMS,\n FRONTIER_COUNTERS,\n FRONTIER_PARAMS,\n graphBindings,\n graphOverrides,\n kernelSpec,\n} from \"../kernels.js\";\nimport { prepareAdvance } from \"../primitives/advance.js\";\nimport { prepareCompact } from \"../primitives/compact.js\";\nimport { coreOfView, coreWindows } from \"../primitives/core-shape.js\";\nimport { type FrontierFinalizeFields, prepareFrontier, W } from \"../primitives/frontier.js\";\nimport { prepareRadixSort, radixHistBytes } from \"../primitives/radix-sort.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type BfsOptions } from \"../types/accelerator.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { type GpuBfsResult } from \"../types/traversal.js\";\nimport { type AlgorithmScope, algorithmScope } from \"./scope.js\";\n\nconst ALGORITHM = \"breadthFirstSearch\";\n\n/** Workgroups of the `bfs-next-degree` grid (issue #391): enough to sum n out-degrees by grid stride, few enough that a high-diameter traversal does not pay a full-width reduction per level. */\nconst NEXT_DEGREE_MAX_GROUPS = 128;\n\n/**\n * Params slots of the ring, COUNTED per run (P8-T12), because `UniformRing.reserve` wraps to slot 0 when a submit's\n * records outrun the ring and silently overwrites a record the submit still reads; the ring's `overruns` counts\n * exactly that reuse, `AlgorithmScope.ringOverruns()` exposes it, and the faked-limit test holds it at 0 for the\n * whole run. The bound per level is `5 + 4 x windows`: five recorded once per level (`frontier-finalize` twice,\n * `bfs-contract`, the bits `fill`, `bfs-bitset-build`) and four re-issued once per arc window (`advance-expand`,\n * `bfs-fused`, the fused retry, `bfs-bottom-up`). The driver as built writes fewer -- the contract and the bitset\n * build share one window-free record, a window's two fused dispatches share one, the bits fill has one record per\n * submit, `bfs-next-degree` has one window-free record of its own (issue #391), and a directed snapshot's reverse\n * view is one window whatever the forward core's count -- so at most `4 + 3 x windows` per level, and the bound\n * holds with room. The 16 covers the per-submit rebuild\n * (`bfs-unvisited-flags` and `compact`, whose scan is at most 9 dispatches for any n below 2^32, so 10, plus the\n * bits fill). The result batch flushes in its own submit, so the ring must hold IT too, and its size grows with `n`,\n * not with the cadence: the iota `fill`, the radix sort's four passes of one record plus its scan's `2 x levels - 1`\n * (the table is `256 x ceil(n / WG)` words and a level covers `WG` of them, so four levels for any n below 2^32 at\n * the package's WG of 256), the `pred` `fill` and `sssp-pred` once per window -- `2 + 4 x 8 + windows = 34 + windows`\n * at most, which a small cadence undercuts (built 2026-09-25: `(5 + 4) x 1 + 16 = 25` slots against the 27 a\n * 262,143-node result batch records wrapped over the radix sort's own records and returned a wrong `order`, silently\n * -- the plan's `19 + windows` count had no scan level in it). The slot count is therefore the larger of the two\n * batches. At one window and `MAX_LEVELS_PER_SUBMIT` it is P8-T6's 304; test/device/constants.test.ts pins the\n * arithmetic.\n * @internal\n * @param windows - the forward core's arc windows (1 when it is not windowed)\n * @param levelsPerSubmit - the levels recorded per submit\n * @returns the ring's slot count\n */\nexport function bfsRingSlots(windows: number, levelsPerSubmit: number): number {\n return Math.max((5 + 4 * windows) * levelsPerSubmit + 16, RESULT_BATCH_SLOTS + windows);\n}\n\n/** The result batch's records before its per-window `sssp-pred` dispatches: two `fill`s and the 32-bit radix sort's four passes of at most eight records each (see `bfsRingSlots`). */\nconst RESULT_BATCH_SLOTS = 2 + 4 * 8;\n\n/**\n * The knobs the tests need and nothing public offers (PD-26): the per-level candidate rule, the edge queue's size,\n * the submit cadence, the predecessor kind, and the two inspect seams.\n * @internal\n */\nexport interface BfsTuning {\n /** `\"auto\"` (default) lets the selector choose per level by Beamer's test; `\"top-down\"` disables the bottom-up candidate (`mode 1`). */\n readonly direction?: \"auto\" | \"top-down\" | undefined;\n /** Beamer's alpha (`max(1, floor(arcCount / n))` when absent, PD-21): top-down switches to bottom-up when the frontier's degree sum exceeds the unvisited degree sum divided by it and the frontier is growing. */\n readonly alpha?: number | undefined;\n /** Beamer's beta (`BEAMER_BETA` when absent): bottom-up switches back when `next * beta < unvisitedCount` and the frontier is shrinking; 0 makes that half of the test true whenever anything is unvisited. */\n readonly beta?: number | undefined;\n /** The fused expand-contract threshold (`FUSED_FRONTIER_MAX` when absent): a level whose frontier is below it takes the fused path; 0 never fuses, `U32_MAX` always does. */\n readonly fusedMax?: number | undefined;\n /** The edge queue's entry count; a test fakes a small one to force the overflow path (PD-23). */\n readonly edgeCapacity?: number | undefined;\n /** Levels recorded per submit (default `MAX_LEVELS_PER_SUBMIT`); 1 hands `onLevel` the block after every level. */\n readonly levelsPerSubmit?: number | undefined;\n /** What the post-pass writes into `parent`: 1 (default) the node index, 0 the arc index (P8-T9's unit-weight route). */\n readonly predKind?: 0 | 1 | undefined;\n /** The inspect seam (design 11.9 item 2): after every SUBMIT, the index of the last level recorded, the whole counters block as the submit left it, the vertices the submit's last level claimed (the next level's input queue, `nextFrontierCount` long), and the total `compact` wrote when it rebuilt the unvisited list at the top of the submit (the independent count the block's `unvisitedListLen` must equal, P8-T8). */\n readonly onLevel?:\n | ((level: number, counters: UniformValues, frontier: U32, compactCount: number) => void)\n | undefined;\n /** Fires once, right after `algorithmScope(...)`, so a test can hold the scope and read its ring counters after the run. */\n readonly onScope?: ((scope: AlgorithmScope) => void) | undefined;\n}\n\n/**\n * The CPU port's `maxDepth` as a `u32`: `U32_MAX` (no cap) when absent, `NaN` (`d >= NaN` never holds) or at or\n * above `U32_MAX` (which covers `Infinity`); otherwise `max(0, ceil(maxDepth))` -- `2.5` behaves as 3 because\n * `d >= 2.5` first holds at `d == 3`, and a negative value gives 0, the source alone, because `0 >= -1` already holds.\n * @param maxDepth - the caller's option\n * @returns the value the uniform carries\n */\nfunction normaliseMaxDepth(maxDepth: number | undefined): number {\n if (maxDepth === undefined || Number.isNaN(maxDepth) || maxDepth >= U32_MAX) {\n return U32_MAX;\n }\n return Math.max(0, Math.ceil(maxDepth));\n}\n\n/**\n * Validates `options.dest` for a depth result of `n` elements.\n * @param dest - the caller's destination array, if any\n * @param n - the node count\n * @returns the destination as a U32, or null when none was given\n */\nfunction checkDest(dest: Float32Array | Uint32Array | undefined, n: number): U32 | null {\n if (dest === undefined) {\n return null;\n }\n if (dest instanceof Uint32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {\n return dest as U32;\n }\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: dest must be a Uint32Array of length ${n} over an ArrayBuffer`,\n {\n argument: \"dest\",\n value: `${dest.constructor.name}(${dest.length})`,\n expected: `Uint32Array(${n}) over an ArrayBuffer`,\n },\n );\n}\n\n/**\n * Whole-buffer binding of a scratch buffer over its first `size` bytes.\n * @param buffer - the buffer\n * @param size - the bound byte length\n * @returns the binding\n */\nfunction bindingOf(buffer: GPUBuffer, size: number): Binding {\n return { buffer, offset: 0, size, window: null };\n}\n\n/**\n * A degree view's one array on the device (the `outDegree` / `inDegree` views of P7, one u32 per vertex).\n * @param ctx - the context\n * @param s - the snapshot\n * @param name - the view\n * @returns the binding\n */\nfunction degreeView(ctx: GpuContext, s: GraphSnapshot, name: \"outDegree\" | \"inDegree\"): Binding {\n const { bindings }: { readonly bindings: Readonly<Partial<Record<\"outDegree\" | \"inDegree\", Binding>>> } =\n ctx.residency.view(s, name);\n const { [name]: binding } = bindings;\n if (binding === undefined) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: the ${name} view has no ${name} binding`, {\n label: `${ALGORITHM}/${name}`,\n message: `the ${name} view has no ${name} binding`,\n });\n }\n return binding;\n}\n\n/**\n * The E_ABORTED error of a signal.\n * @param batchId - the last submitted batch, when one exists\n * @returns the error\n */\nfunction aborted(batchId?: number): WebGpuGraphError {\n return new WebGpuGraphError(\n \"E_ABORTED\",\n `${ALGORITHM}: the signal was aborted`,\n batchId === undefined ? {} : { batchId },\n );\n}\n\n/**\n * One scalar word of a decoded block (every FrontierCounters field is a u32, so anything else is a decoder bug).\n * @param block - the decoded block\n * @param name - the field\n * @returns the word\n */\nfunction wordOf(block: UniformValues, name: string): number {\n const value = block[name];\n if (typeof value !== \"number\") {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: counters.${name} did not decode to a number`, {\n label: `${ALGORITHM}/counters`,\n message: `the field ${name} did not decode to a number`,\n });\n }\n return value;\n}\n\n/**\n * Breadth-first search with the test knobs of PD-26; `breadthFirstSearch` is this with an empty tuning.\n * @internal\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param source - the source node index\n * @param options - `maxDepth`, plus dest / signal / onProgress\n * @param tuning - the knobs\n * @returns the depths, parents, order, visited count, level count and switches\n */\nexport async function bfsWithTuning(\n ctx: GpuContext,\n s: GraphSnapshot,\n source: number,\n options: (BfsOptions & GpuRunOptions) | undefined,\n tuning: BfsTuning,\n): Promise<GpuBfsResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const n = s.nodeCount;\n if (!Number.isInteger(source) || source < 0 || source >= n) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${ALGORITHM}: source ${source} is outside [0, ${n})`, {\n argument: \"source\",\n value: source,\n expected: `an integer in [0, ${n})`,\n });\n }\n const levelsPerSubmit = tuning.levelsPerSubmit ?? MAX_LEVELS_PER_SUBMIT;\n if (!Number.isInteger(levelsPerSubmit) || levelsPerSubmit < 1 || levelsPerSubmit > MAX_LEVELS_PER_SUBMIT) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: levelsPerSubmit must be an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n {\n argument: \"levelsPerSubmit\",\n value: levelsPerSubmit,\n expected: `an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n },\n );\n }\n const dest = checkDest(options?.dest, n);\n const maxDepth = normaliseMaxDepth(options?.maxDepth);\n const predKind = tuning.predKind ?? 1;\n if (options?.signal?.aborted) {\n throw aborted();\n }\n const core = ctx.residency.core(s);\n // a windowed core (colIdx above the binding limit) is executed, not refused (P8-T12 lifts DEP-P8-E): every\n // frontier-walking kernel is dispatched once per arc window with the window's owned range in its record\n const forward = coreWindows(core);\n // the bottom-up sweep walks in-neighbours over the reverse core: on an undirected snapshot the forward arrays\n // themselves (graph-format invariant I7; P7's residency aliases them, so a windowed core's windows ARE the\n // reverse's), on a directed one the reverse VIEW, which spec 4.3 never windows -- so a directed snapshot whose\n // reverse adjacency exceeds one binding is refused here, as the residency refuses the undirected view, instead\n // of failing at the device's bind-group validation\n if (s.directed && 4 * s.arcCount > ctx.caps.limits.maxStorageBufferBindingSize) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: the reverse adjacency of a directed snapshot (${4 * s.arcCount} bytes) needs arc windows, which no view executes (spec 4.3); the bottom-up sweep binds it whole`,\n {\n needed: 4 * s.arcCount,\n limit: ctx.caps.limits.maxStorageBufferBindingSize,\n path: \"windowed\",\n algorithm: ALGORITHM,\n },\n );\n }\n const reverse = s.directed ? coreOfView(ctx.residency.view(s, \"reverse\"), s.arcCount) : core;\n const backward = coreWindows(reverse);\n // the two degree views the unvisited rebuild reads (P8-T8)\n const outDegree = degreeView(ctx, s, \"outDegree\");\n const inDegree = degreeView(ctx, s, \"inDegree\");\n const scope = algorithmScope(ctx, ALGORITHM, bfsRingSlots(forward.length, levelsPerSubmit));\n tuning.onScope?.(scope);\n try {\n const bytes = 4 * n;\n const wg = ctx.workgroupSize;\n const depth = bindingOf(scope.scratch(bytes, \"depth\"), bytes);\n // the sweep's input, one buffer in two regions: the unvisited list at word 0 and the frontier bitset at\n // word bitsBase = roundUp(n, 64), so the bits region's byte offset is 256-aligned and fill can bind it alone\n const bitsBase = Math.ceil(n / 64) * 64;\n const bitsWords = Math.ceil(n / 32);\n const sweepBytes = 4 * (bitsBase + bitsWords);\n const sweepIn = bindingOf(scope.scratch(sweepBytes, \"sweep-in\"), sweepBytes);\n const unvisitedList: Binding = { buffer: sweepIn.buffer, offset: 0, size: bytes, window: null };\n const frontierBits: Binding = {\n buffer: sweepIn.buffer,\n offset: 4 * bitsBase,\n size: 4 * bitsWords,\n window: null,\n };\n const flags = bindingOf(scope.scratch(bytes, \"unvisited-flags\"), bytes);\n const iota = bindingOf(scope.scratch(bytes, \"iota\"), bytes);\n const compactCount = bindingOf(scope.scratch(4, \"compact-count\"), 4);\n await ctx.allocator.check();\n const planner = await prepareFrontier(scope, n, s.arcCount, tuning.edgeCapacity);\n const advance = await prepareAdvance(scope, core);\n const compact = await prepareCompact(scope);\n const contract = await ctx.pipelines.kernel(kernelSpec(\"bfs-contract\"));\n const fused = await ctx.pipelines.kernel(kernelSpec(\"bfs-fused\", graphOverrides(core, null)));\n const bitset = await ctx.pipelines.kernel(kernelSpec(\"bfs-bitset-build\"));\n const bottomUp = await ctx.pipelines.kernel(kernelSpec(\"bfs-bottom-up\", graphOverrides(reverse, null)));\n const unvisited = await ctx.pipelines.kernel(kernelSpec(\"bfs-unvisited-flags\"));\n const nextDegree = await ctx.pipelines.kernel(kernelSpec(\"bfs-next-degree\"));\n const pred = await ctx.pipelines.kernel(kernelSpec(\"sssp-pred\", { ...graphOverrides(core, null), MODE: 1 }));\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const sort = await prepareRadixSort(scope);\n const { frontier } = planner;\n const { counters } = frontier;\n const { queue } = ctx.device;\n const fillPlan = plan1d(n, wg, ctx.caps);\n // the level kernels are DIRECT grid-stride dispatches gated by the selector's path word (word 24): the plan\n // bounds the grid, the kernel loops to its count word. The contract walks the edge queue and the bitset build\n // the frontier from one record, so one plan covers both; bfs-fused is one workgroup per entry and takes the\n // plan's GROUP count as its stride (planGridStride's cap applies to the groups)\n const levelPlan = planGridStride(Math.max(n, frontier.edgeCapacity), wg, ctx.caps);\n const sweepPlan = planGridStride(n, wg, ctx.caps);\n // `bfs-next-degree` sums at most n words and is dispatched on EVERY level, so its fixed cost -- one\n // workgroup reduction (six barriers) and one atomic per workgroup -- is paid 1,999 times on the\n // 1000 x 1000 grid. A capped grid pays it 128 times a level instead of ceil(n / wg): on the card the\n // grid row went from 436 to 356 ms and neither R-MAT row moved.\n const degreePlan = planGridStride(n, wg, ctx.caps, NEXT_DEGREE_MAX_GROUPS);\n const fusedPlan = planGridStride(n * wg, wg, ctx.caps);\n const bitsPlan = plan1d(bitsWords, wg, ctx.caps);\n const recordFill = (pass: GPUComputePassEncoder, dst: Binding, value: number, mode: 0 | 1): void => {\n const params = scope.params(FILL_PARAMS, { count: n, value, mode, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst, P: params.binding }), fillPlan, [params.offset]);\n };\n const flagsPlan: DispatchPlan = planGridStride(n, wg, ctx.caps);\n /**\n * The rebuild of the unvisited set (PD-18), recorded at the top of every submit before its levels.\n * @param pass - the compute pass\n */\n const recordRebuild = (pass: GPUComputePassEncoder): void => {\n const params = scope.params(FRONTIER_PARAMS, { wg, n, stride: flagsPlan.stride ?? n });\n const bound = unvisited.bind({ outDegree, inDegree, depth, flags, counters, P: params.binding });\n unvisited.dispatch(pass, bound, flagsPlan, [params.offset]);\n compact.record(pass, {\n queue: iota,\n flags,\n count: n,\n out: unvisitedList,\n outCount: compactCount,\n outIndex: 0,\n });\n };\n const submit = (batch: CommandBatch): ReturnType<CommandBatch[\"submit\"]> => {\n scope.flush();\n return batch.submit();\n };\n\n // setup: depth = INVALID_INDEX everywhere and the iota queue compact reads; then the source at 0 and the\n // seeded block, both queue writes ordered before the first level submit (the seed is rotated in by the\n // first boundary, P8-T4)\n const setup = new CommandBatch(ctx, `${ALGORITHM}/setup`);\n const setupPass = setup.pass(\"fill\");\n recordFill(setupPass, depth, INVALID_INDEX, 0);\n recordFill(setupPass, iota, 0, 1);\n setup.endPass();\n await submit(setup).readback;\n ctx.assertReady();\n queue.writeBuffer(depth.buffer, depth.offset + 4 * source, Uint32Array.of(0));\n frontier.reset(queue, source, { nextFrontierCount: 1, level: U32_MAX });\n\n // the levels: MAX_LEVELS_PER_SUBMIT per submit, four bytes back (PD-7); Beamer's test chooses the direction\n // per level (mode 0; mode 1 pins top-down), with the fused path below fusedMax (P8-T7)\n const fields: FrontierFinalizeFields = {\n mode: tuning.direction === \"top-down\" ? 1 : 0,\n alpha: tuning.alpha ?? Math.max(1, Math.floor(s.arcCount / n)),\n beta: tuning.beta ?? BEAMER_BETA,\n fusedMax: tuning.fusedMax ?? FUSED_FRONTIER_MAX,\n maxDepth,\n };\n let levelsRecorded = 0;\n let submits = 0;\n for (;;) {\n // the rebuild (PD-18): the three unvisited words zeroed by a queue write ordered before this submit,\n // then the flags kernel and compact at the top of the pass, unconditionally, never per level\n queue.writeBuffer(counters.buffer, counters.offset + 4 * W.unvisitedCount, new Uint32Array(3));\n const batch = new CommandBatch(ctx, `${ALGORITHM}/levels`);\n const pass = batch.pass(\"bfs\");\n recordRebuild(pass);\n const bitsParams = scope.params(FILL_PARAMS, { count: bitsWords, value: 0, mode: 0, pad0: 0 });\n const boundBitsFill = fill.bind({ dst: frontierBits, P: bitsParams.binding });\n for (let level = 0; level < levelsPerSubmit; level++) {\n planner.recordFinalize(pass, 0, level, { ...fields, firstOfSubmit: Math.min(level, 1) });\n advance.record(pass, frontier);\n planner.recordFinalize(pass, 1, level, fields);\n // one window-free record serves the contract and the bitset build, which read no arc; the kernels that\n // walk arcs (the fused dispatch, the sweep) get one record per window below (P8-T12)\n const params = scope.params(FRONTIER_PARAMS, {\n wg,\n n,\n edgeCapacity: frontier.edgeCapacity,\n arcBase: 0,\n arcEnd: s.arcCount,\n bitsBase,\n stride: levelPlan.stride ?? wg,\n });\n const boundContract = contract.bind({\n edgeQueue: frontier.edgeQueue,\n counters,\n depth,\n frontierOut: frontier.output,\n P: params.binding,\n });\n contract.dispatch(pass, boundContract, levelPlan, [params.offset]);\n // the fused path (role 0's choice) and the overflow retry (role 1's, PD-23): ONE dispatch per window that\n // the path word turns into the level's work or into nothing (the claim is idempotent across windows)\n for (const w of forward) {\n const fusedParams = scope.params(FRONTIER_PARAMS, {\n wg,\n n,\n edgeCapacity: frontier.edgeCapacity,\n arcBase: w.arcBase,\n arcEnd: w.arcEnd,\n stride: fusedPlan.x * fusedPlan.y,\n });\n const boundFused = fused.bind({\n ...graphBindings(w.core, null),\n frontierIn: frontier.input,\n counters,\n depth,\n frontierOut: frontier.output,\n P: fusedParams.binding,\n });\n fused.dispatch(pass, boundFused, fusedPlan, [fusedParams.offset]);\n }\n // the bottom-up level (role 0's choice under Beamer's test, P8-T8): the bitset zeroed (every level: a\n // top-down level zeroes bits nobody reads, cheaper than a gate), the frontier's bits set, the unvisited\n // list swept over the reverse core\n fill.dispatch(pass, boundBitsFill, bitsPlan, [bitsParams.offset]);\n const boundBitset = bitset.bind({\n frontierIn: frontier.input,\n counters,\n bits: sweepIn,\n P: params.binding,\n });\n bitset.dispatch(pass, boundBitset, levelPlan, [params.offset]);\n // the sweep once per window of the REVERSE core (an entry claimed in one window is skipped in the next)\n for (const w of backward) {\n const sweepParams = scope.params(FRONTIER_PARAMS, {\n wg,\n n,\n arcBase: w.arcBase,\n arcEnd: w.arcEnd,\n bitsBase,\n stride: sweepPlan.stride ?? wg,\n });\n const boundSweep = bottomUp.bind({\n ...graphBindings(w.core, null),\n sweepIn,\n counters,\n depth,\n frontierOut: frontier.output,\n P: sweepParams.binding,\n });\n bottomUp.dispatch(pass, boundSweep, sweepPlan, [sweepParams.offset]);\n }\n // the next frontier's out-degree sum (issue #391): whichever path claimed, the vertices are in the output\n // queue now, and the next boundary reads word 25 as Beamer's m_f for the frontier it is about to expand\n const degreeParams = scope.params(FRONTIER_PARAMS, { wg, n, stride: degreePlan.stride ?? wg });\n const boundDegree = nextDegree.bind({\n frontier: frontier.output,\n outDegree,\n counters,\n P: degreeParams.binding,\n });\n nextDegree.dispatch(pass, boundDegree, degreePlan, [degreeParams.offset]);\n frontier.swap();\n }\n batch.endPass();\n const doneRequest = batch.readback(counters.buffer, counters.offset + 4 * W.done, 4);\n const inspect =\n tuning.onLevel === undefined\n ? null\n : {\n block: batch.readback(counters.buffer, counters.offset, FRONTIER_COUNTERS.byteLength),\n frontier: batch.readback(frontier.input.buffer, frontier.input.offset, frontier.input.size),\n count: batch.readback(compactCount.buffer, compactCount.offset, 4),\n };\n const submitted = submit(batch);\n const back = await submitted.readback;\n levelsRecorded += levelsPerSubmit;\n submits += 1;\n ctx.assertReady();\n if (options?.signal?.aborted) {\n throw aborted(submitted.id);\n }\n options?.onProgress?.(Math.min(levelsRecorded, n), n);\n if (inspect !== null && tuning.onLevel !== undefined) {\n const block = FRONTIER_COUNTERS.read(new DataView(back), inspect.block.offset);\n const claimed = new Uint32Array(back, inspect.frontier.offset, wordOf(block, \"nextFrontierCount\"));\n const rebuilt = new Uint32Array(back, inspect.count.offset, 1)[0];\n tuning.onLevel(levelsRecorded - 1, block, claimed.slice(), rebuilt);\n }\n if (new Uint32Array(back, doneRequest.offset, 1)[0] !== 0) {\n break;\n }\n if (submits > n + 1) {\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: the done flag never rose in ${submits} submits (a traversal has at most ${n} levels)`,\n { label: ALGORITHM, message: `the done flag never rose in ${submits} submits` },\n );\n }\n }\n\n // the result batch: order by one stable radix sort of the node indices by depth (PD-14), parent by the\n // post-pass in depth mode (PD-24), then every array through ONE staging slot\n const keys = bindingOf(scope.scratch(bytes, \"order/keys\"), bytes);\n const vals = bindingOf(scope.scratch(bytes, \"order/vals\"), bytes);\n const histBytes = radixHistBytes(n, wg);\n const scratch = {\n keys: bindingOf(scope.scratch(bytes, \"order/keys-scratch\"), bytes),\n vals: bindingOf(scope.scratch(bytes, \"order/vals-scratch\"), bytes),\n hist: bindingOf(scope.scratch(histBytes, \"order/hist\"), histBytes),\n offsets: bindingOf(scope.scratch(histBytes, \"order/offsets\"), histBytes),\n };\n const parent = bindingOf(scope.scratch(bytes, \"parent\"), bytes);\n const result = new CommandBatch(ctx, `${ALGORITHM}/result`);\n result.copy(depth, keys, bytes);\n const pass = result.pass(\"result\");\n recordFill(pass, vals, 0, 1);\n const sorted = sort.record(pass, keys, vals, n, 32, scratch);\n recordFill(pass, parent, INVALID_INDEX, 0);\n // the post-pass once per arc window (its atomicMin admits the same smallest parent whichever window holds the arc)\n const predPlan = planGridStride(n, wg, ctx.caps);\n for (const w of forward) {\n const predParams = scope.params(FRONTIER_PARAMS, {\n wg,\n n,\n arcBase: w.arcBase,\n arcEnd: w.arcEnd,\n predKind,\n source,\n stride: predPlan.stride ?? n,\n });\n const predBound = pred.bind({\n ...graphBindings(w.core, null),\n dist: depth,\n pred: parent,\n P: predParams.binding,\n });\n pred.dispatch(pass, predBound, predPlan, [predParams.offset]);\n }\n result.endPass();\n const depthRequest = result.readback(depth.buffer, depth.offset, bytes);\n const parentRequest = result.readback(parent.buffer, parent.offset, bytes);\n const orderRequest = result.readback(sorted.vals.buffer, sorted.vals.offset, bytes);\n const blockRequest = result.readback(counters.buffer, counters.offset, FRONTIER_COUNTERS.byteLength);\n const back = await submit(result).readback;\n ctx.assertReady();\n const block = FRONTIER_COUNTERS.read(new DataView(back), blockRequest.offset);\n const visitedCount = wordOf(block, \"visitedCount\");\n if (visitedCount > n) {\n // every vertex is claimed at most once, so a count above n is a kernel bug (a claim that lets two\n // same-level claimants append), never a result to return\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: visitedCount ${visitedCount} exceeds the ${n} vertices (a duplicate claim)`,\n {\n label: `${ALGORITHM}/visitedCount`,\n message: `the device counted ${visitedCount} visits of ${n} vertices`,\n },\n );\n }\n const level = wordOf(block, \"level\");\n // done by an empty frontier (the level word already counts the boundary that found it), or by maxDepth with\n // a reached-but-unexpanded level\n const levels = wordOf(block, \"frontierCount\") === 0 ? level : level + 1;\n const depthOut = dest ?? new Uint32Array(n);\n depthOut.set(new Uint32Array(back, depthRequest.offset, n));\n return {\n depth: depthOut,\n parent: new Uint32Array(back, parentRequest.offset, n).slice(),\n order: new Uint32Array(back, orderRequest.offset, visitedCount).slice(),\n visitedCount,\n levels,\n switches: wordOf(block, \"switches\"),\n };\n } finally {\n scope.dispose();\n }\n}\n\n/**\n * Breadth-first search on the device (spec 3.3 line 807, design 8.4, 9.7): `depth` exact, `parent` the smallest\n * predecessor one depth down (PD-24), `order` grouped by depth and ascending by index within a depth (PD-14), all\n * bitwise reproducible; `maxDepth` as the CPU port reads it (a node at the cap is reached and not expanded).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param source - the source node index (E_INVALID_ARGUMENT outside `[0, n)`, so the empty graph refuses every source)\n * @param options - `maxDepth`, plus dest (a Uint32Array of length n for `depth`) / signal / onProgress\n * @returns the depths, parents, order, visited count, level count and switches (the direction changes Beamer's test made on the device)\n */\nexport function breadthFirstSearch(\n ctx: GpuContext,\n s: GraphSnapshot,\n source: number,\n options?: BfsOptions & GpuRunOptions,\n): Promise<GpuBfsResult> {\n return bfsWithTuning(ctx, s, source, options, {});\n}\n","/**\n * Weighted single-source shortest paths on the device (design 8.4, 3.3 line 808, 9.7; P8-T9, the P8 plan's PD-9 /\n * PD-10 / PD-11 / PD-14 / PD-19 / PD-20 / PD-22 / PD-27 / DEP-P8-E): Davidson's near-far queue over the `Frontier`\n * of P8-T4 with the `dedupe` of P8-T3, every per-round decision made ON THE DEVICE. `dist` is `array<atomic<u32>>`\n * holding the f32 bit patterns of the distances (`F32_INF_BITS` = unreached), claimed by `atomicMin`, which is\n * exact on non-negative floats (PD-9): the settled value is the minimum of a fixed set of f32 sums, so it is\n * bitwise reproducible, bitwise identical across adapters, and bitwise equal to the f32 Dijkstra oracle.\n *\n * A round is eight recorded dispatches: `frontier-finalize` role 2 (the round boundary: a non-empty raw near half\n * is deduped into `nearIn` for a near round; an empty one with a non-empty far half raises the threshold by the\n * delta and dedupes the far half into `farIn` for a pass-through; both empty is `done`), `dedupe-claim` and\n * `dedupe-filter` over each half (direct grid-stride dispatches; role 2 writes the chosen half's raw count into that\n * dedupe's count word -- `edgeCount` for the near half, `edgeCountUnclamped` for the far one, two words SSSP borrows\n * -- and 0 into the other's, so the half not chosen is a no-op), role 3 (restarts the raw half the round consumed),\n * and `sssp-relax` twice (role 0 over `nearIn` sized by `frontierCount`, role 1 over `farIn` sized by `farCount`;\n * the block's `path` word, 5 a near round and 6 a far one, makes the other role's dispatch a no-op). Nothing in a\n * round is an indirect dispatch (2026-09-25). The far pile is re-bucketed by the\n * relax kernel's pass-through, not by `compact` (PD-20): a far entry whose settled distance fell below the previous\n * threshold was relaxed in the near band already and is dropped, the rest go back to near or far against the raised\n * threshold. The near pile is ONE pile (no sub-partitions). The host records `MAX_LEVELS_PER_SUBMIT` rounds per\n * submit and reads four bytes, the `done` word: 1 finished, 2 a raw half above its capacity (E_TOO_LARGE\n * `sssp.pile`: the far half accumulates one entry per improving relaxation beyond the threshold across a bucket's\n * near rounds and is deduped only at the split, so the refusal is reachable on a graph whose vertices improve many\n * times inside one bucket), 3 the f32 threshold absorbed the delta (E_UNSUPPORTED `sssp.thresholdAbsorbed`). The\n * rounds are at most `n + ceil(sum / delta) + 1` (each near round settles the pile's minimum, one pass-through per\n * bucket), so more submits than that is E_VALIDATION, never a hang.\n *\n * The two routings (PD-22) are decided by the RUN's weight vector: `options.weights` when given (`arcCount` long or\n * E_INVALID_ARGUMENT; narrowed to `Float32Array` when it is not one -- a `U32` or `I32` value above 2^24, or the\n * bits of an `F64` value below the f32 ulp, is rounded silently, the package-wide f32 caveat and not a refusal --\n * uploaded into a lease buffer and bound in the graph group's weights slot with `HAS_WEIGHTS` set even on an\n * unweighted snapshot), else the snapshot's column, else none. A run whose vector is all ones, or has none, is the\n * unit-weight BFS of P8-T6 with a depth cap derived from `cutoff` (`dv <= cutoff` on unit weights is\n * `depth <= floor(cutoff)`), its `predArc` from `sssp-pred` in depth mode writing arc indices, `reachedCount` the\n * visited count -- not a fallback, a better algorithm for the input. A negative weight is E_UNSUPPORTED\n * `sssp.negativeWeights` (use bellmanFord), a non-finite one E_UNSUPPORTED `sssp.nonFiniteWeights` (the bit-pattern\n * order is undefined for NaN); `cutoff: NaN` is E_INVALID_ARGUMENT, because the CPU port's `dv <= NaN` relaxes\n * nothing while the kernel's `nd > NaN` guard would relax everything (PD-19). All host-side, before any device work.\n * The delta is `SSSP_DELTA_FACTOR x avgWeight / avgDegree` over the vector in use (1 for an all-zero vector), seeded\n * into the counters block as `deltaBits` and `thresholdBits`.\n *\n * `predArc` is a second pass over the settled distances (PD-11), never packed into the distance atomic: `sssp-pred`\n * in `MODE 0` follows PD-27's plateau rule -- the smallest TIGHT arc whose source sits one key step below `v`, the\n * key `(dist, hops)` with `hops` the plateau depth from a root -- through three roles over one buffer (the arcs,\n * the hop counts, the changed word and the orphan word), so the chain strictly decreases the key, ends at the\n * source, and is bitwise reproducible. A hop batch of `MAX_LEVELS_PER_SUBMIT` passes that still changed something\n * is recorded again without the roots pass; a reached node the key never reached is a kernel bug (E_VALIDATION),\n * never a result. The tuning entry `ssspWithTuning` (PD-26's shape) is what the tests drive; nothing public\n * exposes it.\n *\n * The host-side helpers of the two routings (`resolveWeights`, `normaliseCutoff`, `checkDest`, `assertSource`,\n * `unitWeightRoute`) and the predecessor pass (`predecessorPass`, both PD-27 keys) are shared with\n * `bellman-ford.ts` (P8-T10), which is the same seam type over the same `SsspOptions`; they take the algorithm's\n * name for their messages and are `@internal`.\n */\n\nimport { type F32, type GraphSnapshot, INVALID_INDEX, type NumericVector, type U32 } from \"@graphty/graph-format\";\n\nimport { F32_INF_BITS, MAX_LEVELS_PER_SUBMIT, SSSP_DELTA_FACTOR } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { type UniformValues } from \"../kernel/struct-block.js\";\nimport {\n FILL_PARAMS,\n FRONTIER_COUNTERS,\n FRONTIER_PARAMS,\n graphBindings,\n graphOverrides,\n kernelSpec,\n} from \"../kernels.js\";\nimport { type DedupeRecord, prepareCompact } from \"../primitives/compact.js\";\nimport { assertWholeCore } from \"../primitives/core-shape.js\";\nimport { prepareFrontier, W } from \"../primitives/frontier.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type SsspOptions } from \"../types/accelerator.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { type GpuSsspResult } from \"../types/traversal.js\";\nimport { bfsWithTuning } from \"./bfs.js\";\nimport { type AlgorithmScope, algorithmScope } from \"./scope.js\";\n\nconst ALGORITHM = \"sssp\";\n\n/** The arc-window alignment of the raw halves: the far half's byte offset is `4 x cap`, a multiple of 256, so `dedupe` can bind it alone. */\nconst HALF_ALIGN = 64;\n\n/**\n * Params slots of the ring, COUNTED (`UniformRing.reserve` wraps silently): per round `frontier-finalize` twice and\n * the two dedupe records (4), plus the two relax records shared by every round of a submit (the near and the far\n * role read the same fields), so `4 x MAX_LEVELS_PER_SUBMIT + 2` for a round submit; the predecessor batch is the\n * roots pass, `MAX_LEVELS_PER_SUBMIT` hop passes, one `fill` and the predecessor pass (35) and the setup batch two\n * `fill`s; they flush in their own submits but must fit the same ring.\n */\nconst RING_SLOTS = 4 * MAX_LEVELS_PER_SUBMIT + 40;\n\n/**\n * The knobs the tests need and nothing public offers (PD-26's shape): the submit cadence, the near-far delta and the\n * inspect seam.\n * @internal\n */\nexport interface SsspTuning {\n /** Rounds recorded per submit (default `MAX_LEVELS_PER_SUBMIT`); 1 hands `onRound` the block after every round. */\n readonly roundsPerSubmit?: number | undefined;\n /** The near-far delta (a finite positive number) in place of the derived `SSSP_DELTA_FACTOR x avgWeight / avgDegree`. */\n readonly delta?: number | undefined;\n /** The inspect seam: after every SUBMIT, the index of the last round recorded and the whole counters block as the submit left it. */\n readonly onRound?: ((round: number, counters: UniformValues) => void) | undefined;\n}\n\n/**\n * The weight vector a run uses and what the host scan found in it.\n * @internal\n */\nexport interface WeightVector {\n /** The per-arc weights (the snapshot's column, or the override narrowed to f32). */\n readonly values: F32;\n /** Null when the snapshot's own column is used (the core's binding serves); else the override to upload. */\n readonly override: F32 | null;\n readonly allOne: boolean;\n readonly nonNegative: boolean;\n readonly finite: boolean;\n /** The f64 sum of the vector (the delta's numerator and the round bound's). */\n readonly sum: number;\n}\n\n/**\n * The f32 bit pattern of a number (the form the counters block and `FrontierParams` carry).\n * @internal\n * @param value - the number (rounded to f32 first)\n * @returns the pattern\n */\nexport function bitsOf(value: number): number {\n return new Uint32Array(Float32Array.of(value).buffer)[0];\n}\n\n/**\n * Whole-buffer binding of a scratch buffer over its first `size` bytes.\n * @internal\n * @param buffer - the buffer\n * @param size - the bound byte length\n * @returns the binding\n */\nexport function bindingOf(buffer: GPUBuffer, size: number): Binding {\n return { buffer, offset: 0, size, window: null };\n}\n\n/**\n * The E_ABORTED error of a signal.\n * @internal\n * @param algorithm - the algorithm's name (the message prefix)\n * @param batchId - the last submitted batch, when one exists\n * @returns the error\n */\nexport function aborted(algorithm: string, batchId?: number): WebGpuGraphError {\n return new WebGpuGraphError(\n \"E_ABORTED\",\n `${algorithm}: the signal was aborted`,\n batchId === undefined ? {} : { batchId },\n );\n}\n\n/**\n * E_INVALID_ARGUMENT unless `source` is an integer in `[0, n)`.\n * @internal\n * @param algorithm - the algorithm's name (the message prefix)\n * @param source - the caller's source node index\n * @param n - the node count\n */\nexport function assertSource(algorithm: string, source: number, n: number): void {\n if (!Number.isInteger(source) || source < 0 || source >= n) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${algorithm}: source ${source} is outside [0, ${n})`, {\n argument: \"source\",\n value: source,\n expected: `an integer in [0, ${n})`,\n });\n }\n}\n\n/**\n * One scalar word of a decoded block (every FrontierCounters field is a u32, so anything else is a decoder bug).\n * @param block - the decoded block\n * @param name - the field\n * @returns the word\n */\nfunction wordOf(block: UniformValues, name: string): number {\n const value = block[name];\n if (typeof value !== \"number\") {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: counters.${name} did not decode to a number`, {\n label: `${ALGORITHM}/counters`,\n message: `the field ${name} did not decode to a number`,\n });\n }\n return value;\n}\n\n/**\n * Validates `options.dest` for a distance result of `n` elements.\n * @internal\n * @param algorithm - the algorithm's name (the message prefix)\n * @param dest - the caller's destination array, if any\n * @param n - the node count\n * @returns the destination as an F32, or null when none was given\n */\nexport function checkDest(algorithm: string, dest: Float32Array | Uint32Array | undefined, n: number): F32 | null {\n if (dest === undefined) {\n return null;\n }\n if (dest instanceof Float32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {\n return dest as F32;\n }\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${algorithm}: dest must be a Float32Array of length ${n} over an ArrayBuffer`,\n {\n argument: \"dest\",\n value: `${dest.constructor.name}(${dest.length})`,\n expected: `Float32Array(${n}) over an ArrayBuffer`,\n },\n );\n}\n\n/**\n * The CPU port's `cutoff` before any device work: absent is no cap; `NaN` is refused (PD-19: `dv <= NaN` relaxes\n * nothing on the CPU while the kernel's `nd > NaN` guard would relax everything, a silently inverted option);\n * anything else is a finite or infinite number.\n * @internal\n * @param algorithm - the algorithm's name (the message prefix)\n * @param cutoff - the caller's option\n * @returns the cap\n */\nexport function normaliseCutoff(algorithm: string, cutoff: number | undefined): number {\n if (cutoff === undefined) {\n return Infinity;\n }\n if (Number.isNaN(cutoff)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${algorithm}: cutoff must not be NaN`, {\n argument: \"cutoff\",\n value: cutoff,\n expected: \"a number (the CPU port and the kernel would disagree on NaN)\",\n });\n }\n return cutoff;\n}\n\n/**\n * The weight vector of the run (PD-22): the override, validated and narrowed, else the snapshot's column, else\n * null; scanned once on the host for the routing flags and the sum.\n * @internal\n * @param algorithm - the algorithm's name (the message prefix)\n * @param s - the snapshot\n * @param weights - the caller's override, if any\n * @returns the vector and its flags, or null when the run has no weights at all\n */\nexport function resolveWeights(\n algorithm: string,\n s: GraphSnapshot,\n weights: NumericVector | undefined,\n): WeightVector | null {\n if (weights === undefined) {\n if (s.weights === null) {\n return null;\n }\n let sum = 0;\n for (const w of s.weights) {\n sum += w;\n }\n return {\n values: s.weights,\n override: null,\n allOne: s.flags.allWeightsOne,\n nonNegative: s.flags.nonNegativeWeights,\n finite: s.flags.finiteWeights,\n sum,\n };\n }\n if (weights.length !== s.arcCount) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${algorithm}: weights has ${weights.length} entries, the snapshot ${s.arcCount} arcs`,\n { argument: \"weights\", value: weights.length, expected: s.arcCount },\n );\n }\n // the f32 narrowing: a U32 / I32 value above 2^24 or the bits of an F64 value below the f32 ulp round silently\n const values: F32 = weights instanceof Float32Array ? weights : Float32Array.from(weights);\n let allOne = true;\n let nonNegative = true;\n let finite = true;\n let sum = 0;\n for (const w of values) {\n if (w !== 1) {\n allOne = false;\n }\n if (w < 0) {\n nonNegative = false;\n }\n if (!Number.isFinite(w)) {\n finite = false;\n }\n sum += w;\n }\n return { values, override: values, allOne, nonNegative, finite, sum };\n}\n\n/**\n * The unit-weight route (PD-22): the BFS with `cutoff` as a depth cap (`dv <= cutoff` on unit weights is\n * `depth <= floor(cutoff)`; no cap or `+Infinity` is no cap, a negative cutoff the source alone), its `parent` in\n * arc form, its depths as f32 distances.\n * @internal\n * @param ctx - the context\n * @param s - the snapshot\n * @param source - the source node index\n * @param cutoff - the normalised cutoff\n * @param dest - the caller's destination, if any\n * @param options - the run options\n * @returns the result\n */\nexport async function unitWeightRoute(\n ctx: GpuContext,\n s: GraphSnapshot,\n source: number,\n cutoff: number,\n dest: F32 | null,\n options: GpuRunOptions | undefined,\n): Promise<GpuSsspResult> {\n const maxDepth = cutoff === Infinity ? undefined : Math.floor(cutoff);\n const bfs = await bfsWithTuning(\n ctx,\n s,\n source,\n { maxDepth, signal: options?.signal, onProgress: options?.onProgress },\n { predKind: 0 },\n );\n const dist = dest ?? new Float32Array(s.nodeCount);\n for (let v = 0; v < s.nodeCount; v++) {\n const d = bfs.depth[v];\n dist[v] = d === INVALID_INDEX ? Infinity : d;\n }\n return { dist, predArc: bfs.parent, reachedCount: bfs.visitedCount };\n}\n\n/**\n * The words of PD-27's `pred` buffer for `n` nodes: the arcs at 0, the hop counts at `hb = roundUp(n, 64)`, the\n * changed word at `2 hb` and the orphan word after it, in a 64-word tail.\n * @internal\n * @param n - the node count\n * @returns the word count (`2 x hb + 64`)\n */\nexport function predBufferWords(n: number): number {\n return 2 * Math.ceil(n / 64) * 64 + 64;\n}\n\n/**\n * What the predecessor pass needs from its driver.\n * @internal\n */\nexport interface PredecessorPassInput {\n /** The algorithm's name (the batch labels and the E_VALIDATION label). */\n readonly algorithm: string;\n readonly ctx: GpuContext;\n readonly scope: AlgorithmScope;\n /** `sssp-pred` compiled in `MODE 0` with the run's graph overrides. */\n readonly predKernel: Kernel;\n /** Records one `fill` of `count` words of `dst` with `value` (the driver's own closure over its `fill` kernel). */\n readonly recordFill: (pass: GPUComputePassEncoder, dst: Binding, count: number, value: number) => void;\n /** The graph group with the run's weights in the weights slot. */\n readonly graph: Readonly<Record<\"rowPtr\" | \"colIdx\" | \"weights\" | \"perm\", Binding>>;\n /** The settled distances (f32 bit patterns, `F32_INF_BITS` unreached). */\n readonly dist: Binding;\n /** The `predBufferWords(n)`-word pred buffer, every word `INVALID_INDEX` (the driver's setup fill). */\n readonly pred: Binding;\n readonly n: number;\n readonly arcCount: number;\n readonly source: number;\n /** PD-27's key: 0 the plateau rule (`sssp`; a roots pass first), 1 the tight-subgraph rule (`bellmanFord`; the source is the only root). */\n readonly mode: 0 | 1;\n}\n\n/**\n * What the predecessor pass read back, in one batch with the arcs.\n * @internal\n */\nexport interface PredecessorPassOutput {\n /** The settled distances (the dist buffer), a view of the batch's copy. */\n readonly dist: Float32Array;\n /** `pred[0, n)`: the arcs. */\n readonly predArc: U32;\n /** The orphan word: reached non-source nodes the key never reached. */\n readonly orphans: number;\n}\n\n/**\n * The predecessor pass (PD-11, PD-27): the source is the one seeded root and the two flag words are zeroed by\n * `queue.writeBuffer`; then ONE batch of the roots pass (the plateau rule only), `MAX_LEVELS_PER_SUBMIT` hop passes\n * with `P.iteration` counting inside the batch, the arcs re-filled with `INVALID_INDEX` and the predecessor pass,\n * with the readbacks of `dist`, `pred[0, n)` and the two flag words; recorded again without the roots pass while the\n * last hop pass still changed something (a plateau, or a tight subgraph, `k` hops deep needs `ceil((k + 1) / 32)`\n * batches). More than `ceil((n + 1) / MAX_LEVELS_PER_SUBMIT) + 1` batches is E_VALIDATION, because a hop count is at\n * most `n`. The orphan word is returned, not judged: `sssp` treats it as a kernel bug and `bellmanFord` as the rounded\n * cycle PD-27 names.\n * @internal\n * @param input - the driver's buffers, kernels and key rule\n * @returns the distances, the arcs and the orphan count\n */\nexport async function predecessorPass(input: PredecessorPassInput): Promise<PredecessorPassOutput> {\n const { algorithm, ctx, scope, predKernel, recordFill, graph, dist, pred, n, arcCount, source, mode } = input;\n const wg = ctx.workgroupSize;\n const { queue } = ctx.device;\n const bytes = 4 * n;\n const hb = Math.ceil(n / 64) * 64;\n const predArcs: Binding = { buffer: pred.buffer, offset: pred.offset, size: bytes, window: null };\n queue.writeBuffer(pred.buffer, pred.offset + 4 * (hb + source), Uint32Array.of(0));\n queue.writeBuffer(pred.buffer, pred.offset + 4 * 2 * hb, new Uint32Array(2));\n const predPlan = planGridStride(n, wg, ctx.caps);\n const predFields = {\n wg,\n n,\n arcBase: 0,\n arcEnd: arcCount,\n predKind: 0,\n source,\n stride: predPlan.stride ?? n,\n mode,\n };\n const maxBatches = Math.ceil((n + 1) / MAX_LEVELS_PER_SUBMIT) + 1;\n let batches = 0;\n for (;;) {\n const batch = new CommandBatch(ctx, `${algorithm}/pred`);\n const pass = batch.pass(\"pred\");\n const recordRole = (role: number, iteration: number): void => {\n const params = scope.params(FRONTIER_PARAMS, { ...predFields, role, iteration });\n const bound = predKernel.bind({ ...graph, dist, pred, P: params.binding });\n predKernel.dispatch(pass, bound, predPlan, [params.offset]);\n };\n if (batches === 0 && mode === 0) {\n recordRole(0, 0);\n }\n for (let iteration = 0; iteration < MAX_LEVELS_PER_SUBMIT; iteration++) {\n recordRole(1, iteration);\n }\n recordFill(pass, predArcs, n, INVALID_INDEX);\n recordRole(2, 0);\n batch.endPass();\n const distRequest = batch.readback(dist.buffer, dist.offset, bytes);\n const predRequest = batch.readback(pred.buffer, pred.offset, bytes);\n const flagsRequest = batch.readback(pred.buffer, pred.offset + 4 * 2 * hb, 8);\n scope.flush();\n const back = await batch.submit().readback;\n ctx.assertReady();\n batches += 1;\n const [changed, orphans] = new Uint32Array(back, flagsRequest.offset, 2);\n if (changed < MAX_LEVELS_PER_SUBMIT) {\n return {\n dist: new Float32Array(back, distRequest.offset, n),\n predArc: new Uint32Array(back, predRequest.offset, n).slice(),\n orphans,\n };\n }\n if (batches > maxBatches) {\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${algorithm}: the hop passes still changed something after ${batches} batches (a hop count is at most ${n})`,\n { label: `${algorithm}/pred`, message: `the hop passes did not converge in ${batches} batches` },\n );\n }\n queue.writeBuffer(pred.buffer, pred.offset + 4 * 2 * hb, new Uint32Array(2));\n }\n}\n\n/**\n * Single-source shortest paths with the test knobs of PD-26's shape; `sssp` is this with an empty tuning.\n * @internal\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param source - the source node index\n * @param options - `cutoff` and `weights`, plus dest / signal / onProgress\n * @param tuning - the knobs\n * @returns the distances, the predecessor arcs and the reached count\n */\nexport async function ssspWithTuning(\n ctx: GpuContext,\n s: GraphSnapshot,\n source: number,\n options: (SsspOptions & GpuRunOptions) | undefined,\n tuning: SsspTuning,\n): Promise<GpuSsspResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const n = s.nodeCount;\n assertSource(ALGORITHM, source, n);\n const roundsPerSubmit = tuning.roundsPerSubmit ?? MAX_LEVELS_PER_SUBMIT;\n if (!Number.isInteger(roundsPerSubmit) || roundsPerSubmit < 1 || roundsPerSubmit > MAX_LEVELS_PER_SUBMIT) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: roundsPerSubmit must be an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n {\n argument: \"roundsPerSubmit\",\n value: roundsPerSubmit,\n expected: `an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n },\n );\n }\n if (tuning.delta !== undefined && !(Number.isFinite(tuning.delta) && tuning.delta > 0)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${ALGORITHM}: delta must be a finite positive number`, {\n argument: \"delta\",\n value: tuning.delta,\n expected: \"a finite positive number\",\n });\n }\n const dest = checkDest(ALGORITHM, options?.dest, n);\n const vector = resolveWeights(ALGORITHM, s, options?.weights);\n const cutoff = normaliseCutoff(ALGORITHM, options?.cutoff);\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM);\n }\n if (vector === null || vector.allOne) {\n return unitWeightRoute(ctx, s, source, cutoff, dest, options);\n }\n if (!vector.nonNegative) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: a negative weight has no shortest path here`, {\n feature: \"sssp.negativeWeights\",\n hint: \"use bellmanFord\",\n });\n }\n if (!vector.finite) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: a NaN or infinite weight has no bit-pattern order`, {\n feature: \"sssp.nonFiniteWeights\",\n });\n }\n const { arcCount } = s;\n const core = ctx.residency.core(s);\n const limit = ctx.caps.limits.maxStorageBufferBindingSize;\n assertWholeCore(core, arcCount, limit, ALGORITHM);\n // the raw halves: cap entries each, the far half at word cap so its byte offset is 256-aligned; one binding\n // of both halves is what the relax kernel sees, so the whole buffer is held to the binding limit (DEP-P8-E)\n const cap = Math.ceil(Math.max(1, arcCount) / HALF_ALIGN) * HALF_ALIGN;\n if (8 * cap > limit) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: the near-far queue of ${cap} entries per half needs ${8 * cap} bytes, above the ${limit}-byte binding limit (the relax is never windowed)`,\n { needed: 8 * cap, limit, path: \"sssp.queue\", algorithm: ALGORITHM },\n );\n }\n // PD-22: the delta from the vector in use; an all-zero vector would land every relaxation on the far pile\n const delta = Math.fround(\n tuning.delta ?? (vector.sum === 0 ? 1 : (SSSP_DELTA_FACTOR * (vector.sum / arcCount)) / (arcCount / n)),\n );\n const deltaBits = bitsOf(delta);\n const maxRounds = n + Math.ceil(vector.sum / delta) + 1;\n const maxSubmits = Math.ceil((maxRounds + 1) / roundsPerSubmit) + 1;\n const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);\n try {\n const wg = ctx.workgroupSize;\n const bytes = 4 * n;\n const dist = bindingOf(scope.scratch(bytes, \"dist\"), bytes);\n const owner = bindingOf(scope.scratch(bytes, \"owner\"), bytes);\n const queueOut = bindingOf(scope.scratch(8 * cap, \"queue-out\"), 8 * cap);\n const nearHalf: Binding = { buffer: queueOut.buffer, offset: 0, size: 4 * cap, window: null };\n const farHalf: Binding = { buffer: queueOut.buffer, offset: 4 * cap, size: 4 * cap, window: null };\n // the pred buffer of PD-27: the arcs at 0, the hop counts at hb, the changed word at 2 hb, the orphan word after it\n const predWords = predBufferWords(n);\n const pred = bindingOf(scope.scratch(4 * predWords, \"pred\"), 4 * predWords);\n const { queue } = ctx.device;\n let weightsBinding: Binding | undefined;\n if (vector.override !== null) {\n const uploaded = scope.scratch(4 * arcCount, \"weights\");\n queue.writeBuffer(uploaded, 0, vector.override);\n weightsBinding = bindingOf(uploaded, 4 * arcCount);\n }\n await ctx.allocator.check();\n const planner = await prepareFrontier(scope, n, arcCount, cap);\n const compact = await prepareCompact(scope);\n const overrides = graphOverrides(core, null, weightsBinding);\n const relax = await ctx.pipelines.kernel(kernelSpec(\"sssp-relax\", overrides));\n const predKernel = await ctx.pipelines.kernel(kernelSpec(\"sssp-pred\", { ...overrides, MODE: 0 }));\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const graph = graphBindings(core, null, weightsBinding);\n const { frontier } = planner;\n const { counters } = frontier;\n const nearIn = frontier.vertices[0];\n const farIn = frontier.vertices[1];\n const recordFill = (pass: GPUComputePassEncoder, dst: Binding, count: number, value: number): void => {\n const params = scope.params(FILL_PARAMS, { count, value, mode: 0, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst, P: params.binding }), plan1d(count, wg, ctx.caps), [params.offset]);\n };\n const submit = (batch: CommandBatch): ReturnType<CommandBatch[\"submit\"]> => {\n scope.flush();\n return batch.submit();\n };\n\n // setup: dist = +Inf everywhere and the pred buffer INVALID_INDEX; then the source at 0, the seeded block\n // (the source in the RAW near half so the first boundary dedupes a one-entry pile like every later one)\n const setup = new CommandBatch(ctx, `${ALGORITHM}/setup`);\n const setupPass = setup.pass(\"fill\");\n recordFill(setupPass, dist, n, F32_INF_BITS);\n recordFill(setupPass, pred, predWords, INVALID_INDEX);\n setup.endPass();\n await submit(setup).readback;\n ctx.assertReady();\n queue.writeBuffer(dist.buffer, dist.offset + 4 * source, Uint32Array.of(0));\n frontier.reset(queue, source, { nextFrontierCount: 1, thresholdBits: deltaBits, deltaBits });\n queue.writeBuffer(queueOut.buffer, queueOut.offset, Uint32Array.of(source));\n\n // the rounds: MAX_LEVELS_PER_SUBMIT per submit, four bytes back\n const nearDedupe: DedupeRecord = {\n queue: nearHalf,\n count: cap,\n countIndex: W.edgeCount, // role 2 writes the raw near count here when it chooses a near round, 0 otherwise\n counters,\n owner,\n out: nearIn,\n outCount: counters,\n outIndex: W.frontierCount,\n };\n const farDedupe: DedupeRecord = {\n queue: farHalf,\n count: cap,\n countIndex: W.edgeCountUnclamped, // and the raw far count here on a far round\n counters,\n owner,\n out: farIn,\n outCount: counters,\n outIndex: W.farCount,\n };\n const relaxPlan = planGridStride(n, wg, ctx.caps); // a pile holds at most n entries; the kernel loops to the count word\n const relaxFields = {\n wg,\n n,\n edgeCapacity: cap,\n arcBase: 0,\n arcEnd: arcCount,\n cutoffBits: bitsOf(cutoff),\n source,\n stride: relaxPlan.stride ?? wg,\n };\n let roundsRecorded = 0;\n let submits = 0;\n for (;;) {\n const batch = new CommandBatch(ctx, `${ALGORITHM}/rounds`);\n const pass = batch.pass(\"sssp\");\n const near = scope.params(FRONTIER_PARAMS, { ...relaxFields, role: 0 });\n const far = scope.params(FRONTIER_PARAMS, { ...relaxFields, role: 1 });\n const boundNear = relax.bind({ ...graph, dist, counters, queueIn: nearIn, queueOut, P: near.binding });\n const boundFar = relax.bind({ ...graph, dist, counters, queueIn: farIn, queueOut, P: far.binding });\n for (let round = 0; round < roundsPerSubmit; round++) {\n // every dispatch of a round is DIRECT: role 2 writes the chosen half's raw count into the dedupe's count\n // word (the other's is 0) and the path word the relax roles gate on, so the half not chosen is a no-op\n planner.recordFinalize(pass, 2, round, {});\n compact.recordDedupe(pass, nearDedupe);\n compact.recordDedupe(pass, farDedupe);\n planner.recordFinalize(pass, 3, round, {});\n relax.dispatch(pass, boundNear, relaxPlan, [near.offset]);\n relax.dispatch(pass, boundFar, relaxPlan, [far.offset]);\n }\n batch.endPass();\n const doneRequest = batch.readback(counters.buffer, counters.offset + 4 * W.done, 4);\n const inspect =\n tuning.onRound === undefined\n ? null\n : batch.readback(counters.buffer, counters.offset, FRONTIER_COUNTERS.byteLength);\n const submitted = submit(batch);\n const back = await submitted.readback;\n roundsRecorded += roundsPerSubmit;\n submits += 1;\n ctx.assertReady();\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM, submitted.id);\n }\n options?.onProgress?.(Math.min(roundsRecorded, maxRounds), maxRounds);\n if (inspect !== null && tuning.onRound !== undefined) {\n tuning.onRound(roundsRecorded - 1, FRONTIER_COUNTERS.read(new DataView(back), inspect.offset));\n }\n const done = new Uint32Array(back, doneRequest.offset, 1)[0];\n if (done === 1) {\n break;\n }\n if (done !== 0) {\n const block = FRONTIER_COUNTERS.read(\n new DataView(\n await ctx.readback.read(\n counters.buffer,\n FRONTIER_COUNTERS.byteLength,\n undefined,\n counters.offset,\n ),\n ),\n );\n if (done === 2) {\n const needed = Math.max(wordOf(block, \"nextFrontierCount\"), wordOf(block, \"nextFarCount\"));\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: a raw pile of ${needed} entries overflowed its ${cap}-entry half`,\n { needed, limit: cap, path: \"sssp.pile\", algorithm: ALGORITHM },\n );\n }\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `${ALGORITHM}: the f32 threshold ${wordOf(block, \"thresholdBits\")} absorbed the delta ${deltaBits} (as bit patterns); the far pile can no longer be bucketed`,\n { feature: \"sssp.thresholdAbsorbed\", hint: \"the distances outgrew the delta's f32 precision\" },\n );\n }\n if (submits > maxSubmits) {\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: the done flag never rose in ${submits} submits (at most ${maxRounds} rounds)`,\n { label: `${ALGORITHM}/rounds`, message: `the done flag never rose in ${submits} submits` },\n );\n }\n }\n\n // the predecessor pass (PD-11, PD-27) under the plateau rule\n const passed = await predecessorPass({\n algorithm: ALGORITHM,\n ctx,\n scope,\n predKernel,\n recordFill,\n graph,\n dist,\n pred,\n n,\n arcCount,\n source,\n mode: 0,\n });\n if (passed.orphans !== 0) {\n // (2) of PD-27: every reached non-source node has an admitted in-arc under non-negative weights\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: ${passed.orphans} reached node(s) the predecessor key never reached (a kernel bug)`,\n { label: `${ALGORITHM}/pred`, message: `${passed.orphans} orphan(s) in the predecessor pass` },\n );\n }\n const distOut = dest ?? new Float32Array(n);\n distOut.set(passed.dist);\n let reachedCount = 0;\n for (const d of distOut) {\n if (d !== Infinity) {\n reachedCount += 1;\n }\n }\n return { dist: distOut, predArc: passed.predArc, reachedCount };\n } finally {\n scope.dispose();\n }\n}\n\n/**\n * Single-source shortest paths on the device (spec 3.3 line 808, design 8.4, 9.7): `dist` in f32, bitwise equal to\n * the f32 Dijkstra (PD-9), `predArc` a tight arc one PD-27 key step below each reached node (the chain always ends\n * at the source), `reachedCount`; `cutoff` as the CPU port reads it (`dv <= cutoff`), `weights` a per-arc override\n * of the snapshot's column for this run; a run with unit weights is the BFS (PD-22).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param source - the source node index (E_INVALID_ARGUMENT outside `[0, n)`)\n * @param options - `cutoff` and `weights`, plus dest (a Float32Array of length n for `dist`) / signal / onProgress\n * @returns the distances, the predecessor arcs and the reached count\n */\nexport function sssp(\n ctx: GpuContext,\n s: GraphSnapshot,\n source: number,\n options?: SsspOptions & GpuRunOptions,\n): Promise<GpuSsspResult> {\n return ssspWithTuning(ctx, s, source, options, {});\n}\n","/**\n * All-pairs shortest paths on the device (design 8.7, 3.3 lines 813 and 835, 9.7): blocked Floyd-Warshall over\n * `APSP_TILE x APSP_TILE` tiles of ONE `n x n` f32 matrix. `fill` sets the matrix to `+Infinity`, `apsp-init` writes\n * the arcs (the cheapest of parallel arcs) and the diagonal zero, then `B = ceil(n / APSP_TILE)` rounds each run the\n * three `apsp-fw` phases in order: the pivot block, the pivot row and column, everything else. The whole sweep --\n * `3 B` dispatches -- is recorded into ONE compute pass: WebGPU runs the dispatches of a pass in order and makes each\n * one's writes visible to the next, so nothing is read back until the matrix is done. Above\n * `APSP_MAX_DISPATCHES_PER_SUBMIT` dispatches the sweep is split into further submits and `signal` is checked\n * between them -- but no binding WebGPU devices offer today reaches that (a 4 GiB binding is 32,767 nodes, 3,072\n * dispatches), so in practice the sweep is one submit: `signal` is checked before it and after it, never during,\n * and `onProgress` fires once. The result is bitwise reproducible (no atomics, and a cell is only ever written by one\n * lane per dispatch), exact for hop counts, and the minimum of f32 path sums for weights.\n *\n * The ceiling: the matrix is exactly `n * n` (never padded to the tile) and is bound as ONE storage binding, so\n * `n <= floor(sqrt(limit / 4))` with `limit` the smaller of the device's `maxStorageBufferBindingSize` and\n * `maxBufferSize`. A context's default `limits: \"raise\"` takes the adapter's own limits: 23,170 nodes on a hardware\n * adapter under Dawn (a 2 GiB binding), 5,792 on lavapipe or under `limits: \"default\"` (the 128 MiB spec default).\n * Above it the call throws `E_TOO_LARGE` naming the node count, the ceiling, the limit it read and\n * `GpuContextOptions.limits` as the way to raise it; the rows are never windowed. Refused before any device work: a negative weight (`E_UNSUPPORTED\n * allPairs.negativeWeights` -- Floyd-Warshall's in-place tile update is race-free only while the diagonal stays 0)\n * and a NaN or infinite one (`allPairs.nonFiniteWeights`). `weighted` defaults to \"the snapshot has weights\";\n * `weighted: false` on a weighted snapshot computes hop counts. The empty graph returns an empty matrix without a\n * dispatch. `allPairsWithTuning` is what the tests drive; nothing public exposes it.\n */\n\nimport { type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { APSP_MAX_DISPATCHES_PER_SUBMIT, APSP_TILE, F32_INF_BITS } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d, plan2d } from \"../kernel/dispatch.js\";\nimport { APSP_PARAMS, FILL_PARAMS, graphBindings, graphOverrides, kernelSpec } from \"../kernels.js\";\nimport { assertWholeCore } from \"../primitives/core-shape.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type ApspOptions, type GpuApspResult } from \"../types/all-pairs.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { type AlgorithmScope, algorithmScope } from \"./scope.js\";\nimport { aborted, bindingOf, checkDest } from \"./sssp.js\";\n\nconst ALGORITHM = \"allPairsShortestPath\";\n\n/**\n * The rounds one submit holds by default: three dispatches per round.\n * @internal\n */\nexport const DEFAULT_ROUNDS_PER_SUBMIT = Math.floor(APSP_MAX_DISPATCHES_PER_SUBMIT / 3);\n\n/**\n * The knobs the tests need and nothing public offers.\n * @internal\n */\nexport interface AllPairsTuning {\n /** Rounds recorded per submit (default `floor(APSP_MAX_DISPATCHES_PER_SUBMIT / 3)`); 1 submits every round alone. */\n readonly roundsPerSubmit?: number | undefined;\n}\n\n/**\n * The largest node count whose `n x n` f32 matrix fits the device (design 8.7): `floor(sqrt(limit / 4))` over the\n * smaller of `maxStorageBufferBindingSize` and `maxBufferSize`, corrected so the float square root can never\n * overshoot by one.\n * @internal\n * @param limits - the device limits\n * @returns the ceiling and the limit that set it\n */\nexport function allPairsCeiling(limits: Pick<GPUSupportedLimits, \"maxStorageBufferBindingSize\" | \"maxBufferSize\">): {\n readonly maxNodes: number;\n readonly limit: number;\n readonly limitName: \"maxStorageBufferBindingSize\" | \"maxBufferSize\";\n} {\n const binding = limits.maxStorageBufferBindingSize;\n const bufferSize = limits.maxBufferSize;\n const limitName = bufferSize < binding ? \"maxBufferSize\" : \"maxStorageBufferBindingSize\";\n const limit = Math.min(binding, bufferSize);\n let maxNodes = Math.floor(Math.sqrt(limit / 4));\n while (4 * maxNodes * maxNodes > limit) {\n maxNodes -= 1;\n }\n while (4 * (maxNodes + 1) * (maxNodes + 1) <= limit) {\n maxNodes += 1;\n }\n return { maxNodes, limit, limitName };\n}\n\n/**\n * The blocked sweep itself, shared with closeness's all-pairs route: the `n x n` matrix leased from `scope`, filled,\n * initialised from the arcs and swept to the shortest distances, every submit awaited; the matrix stays on the device.\n * The caller has checked the ceiling and the weights.\n * @internal\n * @param ctx - the context\n * @param s - the snapshot (n > 0)\n * @param scope - the scope that leases the matrix and the params records (`min(roundsPerSubmit, blocks) + 2` slots)\n * @param weighted - true sums the snapshot's weights, false counts hops\n * @param roundsPerSubmit - the rounds recorded per submit\n * @param options - signal / onProgress (rounds done of `ceil(n / 32)`)\n * @param algorithm - the name errors carry\n * @returns the matrix binding (`4 n^2` bytes, row-major, `dist[i * n + j]` from `i` to `j`)\n */\nexport async function sweepAllPairs(\n ctx: GpuContext,\n s: GraphSnapshot,\n scope: AlgorithmScope,\n weighted: boolean,\n roundsPerSubmit: number,\n options: GpuRunOptions | undefined,\n algorithm: string,\n): Promise<Binding> {\n const n = s.nodeCount;\n const core = ctx.residency.core(s);\n assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, algorithm);\n const blocks = Math.ceil(n / APSP_TILE);\n const wg = ctx.workgroupSize;\n const bytes = 4 * n * n;\n const matrix = bindingOf(scope.scratch(bytes, \"dist\"), bytes);\n await ctx.allocator.check();\n const weightsBinding = weighted ? undefined : null;\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const init = await ctx.pipelines.kernel(kernelSpec(\"apsp-init\", graphOverrides(core, null, weightsBinding)));\n const phases = await Promise.all(\n [0, 1, 2].map((phase) => ctx.pipelines.kernel(kernelSpec(\"apsp-fw\", { PHASE: phase }))),\n );\n const graph = graphBindings(core, null, weightsBinding);\n const others = blocks - 1;\n const phasePlans = [plan2d(1, ctx.caps), plan2d(2 * others, ctx.caps), plan2d(others * others, ctx.caps)];\n\n for (let first = 0; first < blocks; first += roundsPerSubmit) {\n const batch = new CommandBatch(ctx, `${algorithm}/sweep`);\n const pass = batch.pass(\"apsp\");\n if (first === 0) {\n const fillParams = scope.params(FILL_PARAMS, { count: n * n, value: F32_INF_BITS, mode: 0, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst: matrix, P: fillParams.binding }), plan1d(n * n, wg, ctx.caps), [\n fillParams.offset,\n ]);\n const initParams = scope.params(APSP_PARAMS, { n, round: 0, blocks, infBits: F32_INF_BITS });\n init.dispatch(pass, init.bind({ ...graph, dist: matrix, P: initParams.binding }), plan1d(n, wg, ctx.caps), [\n initParams.offset,\n ]);\n }\n const last = Math.min(first + roundsPerSubmit, blocks);\n for (let round = first; round < last; round++) {\n const params = scope.params(APSP_PARAMS, { n, round, blocks, infBits: F32_INF_BITS });\n for (let phase = 0; phase < 3; phase++) {\n const kernel = phases[phase];\n kernel.dispatch(pass, kernel.bind({ dist: matrix, P: params.binding }), phasePlans[phase], [\n params.offset,\n ]);\n }\n }\n batch.endPass();\n scope.flush();\n const submitted = batch.submit();\n await submitted.readback;\n ctx.assertReady();\n options?.onProgress?.(last, blocks);\n if (options?.signal?.aborted) {\n throw aborted(algorithm, submitted.id);\n }\n }\n return matrix;\n}\n\n/**\n * All-pairs shortest paths with the test knobs; `allPairsShortestPath` is this with an empty tuning.\n * @internal\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - `weighted`, plus dest (a Float32Array of length n * n) / signal / onProgress (rounds done of `ceil(n / 32)`)\n * @param tuning - the knobs\n * @returns the row-major `n x n` distances and `n`\n */\nexport async function allPairsWithTuning(\n ctx: GpuContext,\n s: GraphSnapshot,\n options: (ApspOptions & GpuRunOptions) | undefined,\n tuning: AllPairsTuning,\n): Promise<GpuApspResult> {\n ctx.assertReady();\n const n = s.nodeCount;\n const roundsPerSubmit = tuning.roundsPerSubmit ?? DEFAULT_ROUNDS_PER_SUBMIT;\n if (!Number.isInteger(roundsPerSubmit) || roundsPerSubmit < 1 || roundsPerSubmit > DEFAULT_ROUNDS_PER_SUBMIT) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: roundsPerSubmit must be an integer in [1, ${DEFAULT_ROUNDS_PER_SUBMIT}]`,\n {\n argument: \"roundsPerSubmit\",\n value: roundsPerSubmit,\n expected: `an integer in [1, ${DEFAULT_ROUNDS_PER_SUBMIT}]`,\n },\n );\n }\n const { maxNodes, limit, limitName } = allPairsCeiling(ctx.caps.limits);\n if (n > maxNodes) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: ${n} nodes need a ${4 * n * n}-byte distance matrix in one storage binding; this device's ${limitName} of ${limit} bytes holds at most ${maxNodes} nodes -- raise it through GpuContextOptions.limits`,\n {\n needed: 4 * n * n,\n limit,\n path: \"allPairs.matrix\",\n algorithm: ALGORITHM,\n nodes: n,\n maxNodes,\n limitName,\n hint: `raise ${limitName} through GpuContextOptions.limits`,\n },\n );\n }\n const dist = checkDest(ALGORITHM, options?.dest, n * n) ?? new Float32Array(n * n);\n const weighted = (options?.weighted ?? s.weights !== null) && s.weights !== null && !s.flags.allWeightsOne;\n if (weighted && !s.flags.nonNegativeWeights) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: a negative weight is not supported`, {\n feature: \"allPairs.negativeWeights\",\n hint: \"the blocked Floyd-Warshall sweep needs non-negative weights; pass weighted: false for hop counts\",\n });\n }\n if (weighted && !s.flags.finiteWeights) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: a NaN or infinite weight has no shortest path`, {\n feature: \"allPairs.nonFiniteWeights\",\n });\n }\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM);\n }\n if (n === 0) {\n return { dist, n };\n }\n await assertDeviceComputes(ctx);\n const scope = algorithmScope(ctx, ALGORITHM, Math.min(roundsPerSubmit, Math.ceil(n / APSP_TILE)) + 2);\n try {\n const matrix = await sweepAllPairs(ctx, s, scope, weighted, roundsPerSubmit, options, ALGORITHM);\n const bytes = 4 * n * n;\n await ctx.readback.read(matrix.buffer, bytes, dist);\n ctx.assertReady();\n return { dist, n };\n } finally {\n scope.dispose();\n }\n}\n\n/**\n * All-pairs shortest paths on the device (design 8.7, 3.3 line 813): blocked Floyd-Warshall over 32 x 32 tiles of one\n * `n x n` f32 matrix. `dist[i * n + j]` is the distance from `i` to `j`, `+Infinity` when unreachable, `0` on the\n * diagonal. `E_TOO_LARGE` above `floor(sqrt(maxStorageBufferBindingSize / 4))` nodes (23,170 at a 2 GiB binding, the\n * usual hardware adapter under the context's default `limits: \"raise\"`; 5,792 at the 128 MiB spec default);\n * `E_UNSUPPORTED` for a negative or non-finite weight unless `weighted: false`.\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - `weighted` (default: the snapshot has weights), plus dest (a Float32Array of length n * n) / signal / onProgress\n * @returns the row-major `n x n` distances and `n`\n */\nexport function allPairsShortestPath(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: ApspOptions & GpuRunOptions,\n): Promise<GpuApspResult> {\n return allPairsWithTuning(ctx, s, options, {});\n}\n","/**\n * Bellman-Ford with negative-cycle detection on the device (design 8.4, 3.3 line 809, 9.7; P8-T10, the P8 plan's\n * PD-12 / PD-19 / PD-22 / PD-27 / DEP-P8-E): the edge-parallel relaxation of `bf-relax` over the `edgeList()` view\n * -- every logical edge once, both directions on an undirected snapshot -- in batches of `ROUNDS_PER_BATCH` rounds\n * with the `BfFlags` block (`changed`, `retryExhausted`) zeroed before each batch and read back after it, one\n * `mapAsync` per batch. The loop stops when a batch changed nothing (a reachable negative cycle changes something\n * every round, so nothing has been missed) or when `n - 1` rounds have run, in which case ONE more round runs and\n * `changed` after it IS `hasNegativeCycle`; the last batch is clamped so the reported round count never exceeds\n * `n - 1`. `dist` holds f32 bit patterns and the claim is a BOUNDED compare-exchange (PD-12: `MAX_RETRIES`, because\n * with a negative distance the bit-pattern order reverses and `atomicMin` is wrong, and WGSL lets the exchange fail\n * spuriously; only those spurious failures count, never a loss to another lane's improvement, issue #470): a lane that exhausts the bound raises `retryExhausted`, which the driver treats as changed and runs\n * on -- the lost update is retried by the next round, which examines every edge anyway -- and tallies for the tests;\n * raised in the decision round it is E_VALIDATION, never a guess.\n *\n * The routing is P8-T9's, by the RUN's weight vector (PD-22): `options.weights` when given (`arcCount` long or\n * E_INVALID_ARGUMENT; narrowed to `Float32Array` when it is not one -- a `U32` or `I32` value above 2^24, or the bits\n * of an `F64` value below the f32 ulp, is rounded silently, the package-wide f32 caveat and not a refusal), else the\n * snapshot's column, else none; a run whose vector is all ones, or has none, is the unit-weight BFS of P8-T6 with a\n * depth cap derived from `cutoff` (there is nothing negative to relax) and the flag false; a non-finite weight is\n * E_UNSUPPORTED `bellmanFord.nonFiniteWeights`; `cutoff: NaN` is E_INVALID_ARGUMENT (PD-19); every other cutoff goes\n * to the kernel's `nd <= cutoff` unchanged, a negative one yielding the source alone only when no negative weight\n * can satisfy it. One rule the kernel's shape forces: on an UNDIRECTED snapshot the kernel reads ONE weight per\n * logical edge (its forward arc's) and applies it in both directions, so a caller-supplied override whose two arcs\n * of one edge differ means the caller wanted a directed graph, and the driver REFUSES it (E_UNSUPPORTED\n * `bellmanFord.asymmetricUndirectedWeights`, before any device work) rather than half-honour it; the snapshot's own\n * column never trips it. `edgeToArc` is absent from the residency on a directed snapshot built from a sorted edge\n * list (`flags.arcToEdgeIsIdentity`): edge `e` IS arc `e` there, and the driver binds an `edgeCount`-word iota\n * scratch in that slot (the `fill` kernel's mode 1) so the kernel reads `weights[edgeToArc[e]]` unchanged.\n *\n * `predArc` is P8-T9's predecessor pass under PD-27's tight-subgraph rule (`P.mode 1`): the key is the hop count\n * from the source over every tight arc (`fround(dist[u] + w) == dist[v]`; a tight arc with a negative weight steps to\n * a LARGER distance, so `dist` is no key here), `hops[source] = 0` the only seed and no roots pass, so the chain\n * strictly decreases the key and ends at the source. An ORPHAN -- a reached node the tight subgraph never reaches --\n * can arise only when f32 rounding let a cycle improve a distance once (`s -> a` at 2^24, `a -> b` at +1, `b -> a` at\n * -1: `dist[a]` ends at `2^24 - 1` and the source's arc is no longer tight; exact arithmetic has no such run), and the\n * driver refuses it as E_UNSUPPORTED `bellmanFord.roundedCycle` rather than return a chain that ends short of the\n * source (the seam's walker would hand `arcSourceIn` an `INVALID_INDEX`). With `hasNegativeCycle` the result carries\n * the last round's `dist` and `predArc` and says so: the pass still runs, its chains are still acyclic, a node the\n * tight subgraph does not reach keeps `INVALID_INDEX`, and the orphan refusal is skipped. The tuning entry\n * `bellmanFordWithTuning` (PD-26's shape) is what the tests drive; nothing public exposes it.\n */\n\nimport { type F32, type GraphSnapshot, INVALID_INDEX } from \"@graphty/graph-format\";\n\nimport { F32_INF_BITS, MAX_LEVELS_PER_SUBMIT } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { BF_FLAGS, BF_PARAMS, FILL_PARAMS, graphBindings, graphOverrides, kernelSpec } from \"../kernels.js\";\nimport { assertWholeCore } from \"../primitives/core-shape.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type SsspOptions } from \"../types/accelerator.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { type GpuBellmanFordResult } from \"../types/traversal.js\";\nimport { algorithmScope } from \"./scope.js\";\nimport {\n aborted,\n assertSource,\n bindingOf,\n bitsOf,\n checkDest,\n normaliseCutoff,\n predBufferWords,\n predecessorPass,\n resolveWeights,\n unitWeightRoute,\n type WeightVector,\n} from \"./sssp.js\";\n\nconst ALGORITHM = \"bellmanFord\";\n\n/** Design 8.4: the changed flag is read every 8 rounds (one `mapAsync` per batch). */\nconst ROUNDS_PER_BATCH = 8;\n\n/** PD-12: the bound on one lane's SPURIOUS compare-exchange failures (a loss to another lane is not counted, issue #470). */\nconst MAX_RETRIES = 16;\n\n/**\n * Params slots of the ring, COUNTED (`UniformRing.reserve` wraps silently): a batch of rounds shares ONE `BfParams`\n * record across its dispatches; the setup batch is three `fill`s; the predecessor batch is `MAX_LEVELS_PER_SUBMIT`\n * hop passes, one `fill` and the predecessor pass (34).\n */\nconst RING_SLOTS = MAX_LEVELS_PER_SUBMIT + 16;\n\n/**\n * The knobs the tests need and nothing public offers (PD-26's shape): the retry bound and the batch cadence.\n * @internal\n */\nexport interface BellmanFordTuning {\n /** The compare-exchange retry bound per lane (default `MAX_RETRIES`), on spurious failures only; 1 makes the first one exhaust it. */\n readonly maxRetries?: number | undefined;\n /** Rounds recorded per batch (default `ROUNDS_PER_BATCH`), each batch one readback of the flags. */\n readonly roundsPerBatch?: number | undefined;\n}\n\n/**\n * The tuning entry's answer: the result plus what the tests pin.\n * @internal\n */\nexport interface BellmanFordRun {\n readonly result: GpuBellmanFordResult;\n /** The rounds dispatched before the decision round (at most `n - 1`; 0 on the unit-weight route). */\n readonly rounds: number;\n /** The batches in which some lane exhausted the retry bound (PD-12); 0 on every fixture of the suite. */\n readonly retryExhaustedRounds: number;\n}\n\n/**\n * The undirected rule (see the file comment): every arc's weight equals its edge's forward arc's, else E_UNSUPPORTED.\n * @param s - the snapshot (undirected)\n * @param vector - the caller's override, narrowed\n */\nfunction assertSymmetric(s: GraphSnapshot, vector: F32): void {\n const { arcToEdge, edgeToArc } = s;\n for (let a = 0; a < s.arcCount; a++) {\n const forward = edgeToArc[arcToEdge[a]];\n if (vector[a] !== vector[forward]) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `${ALGORITHM}: weights[${a}] = ${vector[a]} differs from weights[${forward}] = ${vector[forward]}, the forward arc of the same undirected edge; the kernel reads one weight per edge`,\n { feature: \"bellmanFord.asymmetricUndirectedWeights\", hint: \"use a directed snapshot\" },\n );\n }\n }\n}\n\n/**\n * Bellman-Ford with the test knobs of PD-26's shape; `bellmanFord` is this with an empty tuning.\n * @internal\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param source - the source node index\n * @param options - `cutoff` and `weights`, plus dest / signal / onProgress\n * @param tuning - the knobs\n * @returns the result, the rounds run and the retry-exhausted tally\n */\nexport async function bellmanFordWithTuning(\n ctx: GpuContext,\n s: GraphSnapshot,\n source: number,\n options: (SsspOptions & GpuRunOptions) | undefined,\n tuning: BellmanFordTuning,\n): Promise<BellmanFordRun> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const n = s.nodeCount;\n assertSource(ALGORITHM, source, n);\n const maxRetries = tuning.maxRetries ?? MAX_RETRIES;\n if (!Number.isInteger(maxRetries) || maxRetries < 1) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${ALGORITHM}: maxRetries must be an integer >= 1`, {\n argument: \"maxRetries\",\n value: maxRetries,\n expected: \"an integer >= 1\",\n });\n }\n const roundsPerBatch = tuning.roundsPerBatch ?? ROUNDS_PER_BATCH;\n if (!Number.isInteger(roundsPerBatch) || roundsPerBatch < 1 || roundsPerBatch > MAX_LEVELS_PER_SUBMIT) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: roundsPerBatch must be an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n {\n argument: \"roundsPerBatch\",\n value: roundsPerBatch,\n expected: `an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n },\n );\n }\n const dest = checkDest(ALGORITHM, options?.dest, n);\n const vector: WeightVector | null = resolveWeights(ALGORITHM, s, options?.weights);\n const cutoff = normaliseCutoff(ALGORITHM, options?.cutoff);\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM);\n }\n if (vector === null || vector.allOne) {\n const unit = await unitWeightRoute(ctx, s, source, cutoff, dest, options);\n return { result: { ...unit, hasNegativeCycle: false }, rounds: 0, retryExhaustedRounds: 0 };\n }\n if (!vector.finite) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: a NaN or infinite weight has no shortest path`, {\n feature: \"bellmanFord.nonFiniteWeights\",\n });\n }\n if (!s.directed && vector.override !== null) {\n assertSymmetric(s, vector.override);\n }\n const { arcCount } = s;\n const core = ctx.residency.core(s, [\"rowPtr\", \"colIdx\", \"weights\", \"edgeToArc\"]);\n assertWholeCore(core, arcCount, ctx.caps.limits.maxStorageBufferBindingSize, ALGORITHM);\n const edges = ctx.residency.view(s, \"edgeList\");\n const edgeCount = edges.scalars.edgeCount[0];\n const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);\n try {\n const wg = ctx.workgroupSize;\n const bytes = 4 * n;\n const dist = bindingOf(scope.scratch(bytes, \"dist\"), bytes);\n const predWords = predBufferWords(n);\n const pred = bindingOf(scope.scratch(4 * predWords, \"pred\"), 4 * predWords);\n const flags = bindingOf(scope.scratch(BF_FLAGS.byteLength, \"flags\"), BF_FLAGS.byteLength);\n // the directed identity snapshot has no edgeToArc segment: edge e IS arc e, so an iota stands in the slot\n let iota: Binding | null = null;\n let { edgeToArc } = core;\n if (edgeToArc === null) {\n iota = bindingOf(scope.scratch(4 * edgeCount, \"iota\"), 4 * edgeCount);\n edgeToArc = iota;\n }\n const { queue } = ctx.device;\n let weightsBinding: Binding | undefined;\n if (vector.override !== null) {\n const uploaded = scope.scratch(4 * arcCount, \"weights\");\n queue.writeBuffer(uploaded, 0, vector.override);\n weightsBinding = bindingOf(uploaded, 4 * arcCount);\n }\n await ctx.allocator.check();\n const overrides = graphOverrides(core, null, weightsBinding);\n const relax = await ctx.pipelines.kernel(kernelSpec(\"bf-relax\", { UNDIRECTED: !s.directed }));\n const predKernel = await ctx.pipelines.kernel(kernelSpec(\"sssp-pred\", { ...overrides, MODE: 0 }));\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const graph = graphBindings(core, null, weightsBinding);\n const recordFill = (\n pass: GPUComputePassEncoder,\n dst: Binding,\n count: number,\n value: number,\n mode = 0,\n ): void => {\n const params = scope.params(FILL_PARAMS, { count, value, mode, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst, P: params.binding }), plan1d(count, wg, ctx.caps), [params.offset]);\n };\n const submit = (batch: CommandBatch): ReturnType<CommandBatch[\"submit\"]> => {\n scope.flush();\n return batch.submit();\n };\n\n // setup: dist = +Inf everywhere, the pred buffer INVALID_INDEX, the iota when needed; then the source at 0\n const setup = new CommandBatch(ctx, `${ALGORITHM}/setup`);\n const setupPass = setup.pass(\"fill\");\n recordFill(setupPass, dist, n, F32_INF_BITS);\n recordFill(setupPass, pred, predWords, INVALID_INDEX);\n if (iota !== null) {\n recordFill(setupPass, iota, edgeCount, 0, 1);\n }\n setup.endPass();\n await submit(setup).readback;\n ctx.assertReady();\n queue.writeBuffer(dist.buffer, dist.offset + 4 * source, Uint32Array.of(0));\n\n // the rounds: roundsPerBatch per batch, the flags zeroed before and read after; the last batch clamped to\n // n - 1 rounds in all, then the decision round\n const edgePlan = planGridStride(edgeCount, wg, ctx.caps);\n const relaxBindings = {\n edgeSrc: edges.bindings.src,\n edgeDst: edges.bindings.dst,\n edgeToArc,\n weights: graph.weights,\n dist,\n flags,\n };\n const relaxFields = {\n edgeCount,\n stride: edgePlan.stride ?? edgeCount,\n maxRetries,\n cutoffBits: bitsOf(cutoff),\n };\n const zero = new Uint32Array(BF_FLAGS.byteLength / 4);\n const runRounds = async (\n count: number,\n label: string,\n ): Promise<{ readonly changed: number; readonly retryExhausted: number; readonly id: number }> => {\n queue.writeBuffer(flags.buffer, flags.offset, zero);\n const batch = new CommandBatch(ctx, `${ALGORITHM}/${label}`);\n const pass = batch.pass(\"relax\");\n const params = scope.params(BF_PARAMS, relaxFields);\n const bound = relax.bind({ ...relaxBindings, P: params.binding });\n for (let round = 0; round < count; round++) {\n relax.dispatch(pass, bound, edgePlan, [params.offset]);\n }\n batch.endPass();\n const request = batch.readback(flags.buffer, flags.offset, BF_FLAGS.byteLength);\n const submitted = submit(batch);\n const back = await submitted.readback;\n ctx.assertReady();\n const block = BF_FLAGS.read(new DataView(back), request.offset);\n return { changed: Number(block.changed), retryExhausted: Number(block.retryExhausted), id: submitted.id };\n };\n let rounds = 0;\n let retryExhaustedRounds = 0;\n let hasNegativeCycle = false;\n for (;;) {\n const remaining = n - 1 - rounds;\n if (remaining <= 0) {\n // the decision round: a change after n - 1 rounds is a negative cycle reachable from the source\n const decision = await runRounds(1, \"decision\");\n if (decision.retryExhausted !== 0) {\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: a lane exhausted the ${maxRetries}-retry compare-exchange bound in the decision round, so its change is not a verdict`,\n {\n label: `${ALGORITHM}/retry`,\n message: \"retryExhausted in the decision round\",\n batchId: decision.id,\n },\n );\n }\n hasNegativeCycle = decision.changed !== 0;\n break;\n }\n const count = Math.min(roundsPerBatch, remaining);\n const batch = await runRounds(count, \"rounds\");\n rounds += count;\n if (batch.retryExhausted !== 0) {\n retryExhaustedRounds += 1;\n }\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM, batch.id);\n }\n options?.onProgress?.(rounds, n);\n if (batch.changed === 0 && batch.retryExhausted === 0) {\n break;\n }\n }\n\n // the predecessor pass (PD-11, PD-27) under the tight-subgraph rule; the flags block was read after the\n // decision round, so the batch reads dist, the arcs and the pass's two words\n const passed = await predecessorPass({\n algorithm: ALGORITHM,\n ctx,\n scope,\n predKernel,\n recordFill,\n graph,\n dist,\n pred,\n n,\n arcCount,\n source,\n mode: 1,\n });\n if (passed.orphans !== 0 && !hasNegativeCycle) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `${ALGORITHM}: ${passed.orphans} reached node(s) the tight subgraph never reaches (a cycle of weights below one f32 ulp relaxed once)`,\n {\n feature: \"bellmanFord.roundedCycle\",\n hint: \"a cycle of weights below one f32 ulp relaxed once at a distance above 2^24; scale the weights or shorten the distances\",\n },\n );\n }\n const distOut = dest ?? new Float32Array(n);\n distOut.set(passed.dist);\n let reachedCount = 0;\n for (const d of distOut) {\n if (d !== Infinity) {\n reachedCount += 1;\n }\n }\n return {\n result: { dist: distOut, predArc: passed.predArc, reachedCount, hasNegativeCycle },\n rounds,\n retryExhaustedRounds,\n };\n } finally {\n scope.dispose();\n }\n}\n\n/**\n * Bellman-Ford on the device (spec 3.3 line 809, design 8.4, 9.7): `dist` in f32 (bitwise the f32 Bellman-Ford\n * fixed point, which is `sssp`'s where the weights are non-negative), `predArc` a tight arc one hop of the tight\n * subgraph below each reached node (the chain always ends at the source), `reachedCount`, and `hasNegativeCycle` --\n * true when a negative cycle is reachable from the source, in which case `dist` and `predArc` are the last round's\n * values, not shortest paths; `cutoff` and `weights` as `sssp` reads them (the seam's `SsspOptions`).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param source - the source node index (E_INVALID_ARGUMENT outside `[0, n)`)\n * @param options - `cutoff` and `weights`, plus dest (a Float32Array of length n for `dist`) / signal / onProgress\n * @returns the distances, the predecessor arcs, the reached count and the negative-cycle flag\n */\nexport async function bellmanFord(\n ctx: GpuContext,\n s: GraphSnapshot,\n source: number,\n options?: SsspOptions & GpuRunOptions,\n): Promise<GpuBellmanFordResult> {\n return (await bellmanFordWithTuning(ctx, s, source, options, {})).result;\n}\n","/**\n * The pull SpMV primitive of spec 6 row 9 / 8.2 (P7; M8b plan PD-1 / PD-2): the `spmv-pull` module over the rows of\n * a REVERSE adjacency, each row folding `weight * xNorm[nbr]` over its in-arcs (a two-level f32 sum) and writing\n * `rankOut[v] = beta * pv + alpha * (sum + danglingMass * pv)`, where `pv` is `personalization[v]` under\n * HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise, and `danglingMass` is `partials[0].danglingMass`\n * under USE_DANGLING. PageRank sets alpha to the damping, beta to 1 - alpha and USE_DANGLING; HITS and eigenvector\n * set alpha 1, beta 0, uniformP 0; Katz sets alpha to the attenuation, beta to its constant and uniformP 1.\n *\n * It is its own registry entry rather than a `segmentedReduce` VALUE snippet (PD-1): the snippet vocabulary is\n * `row, arc, nbr, weight, v` and cannot read `xNorm[nbr]`, and the design's binding table gives the kernel eight\n * storage bindings of its own. Without tiers it is ONE grid-stride dispatch (TIER 0, USE_PERM false: the perm slot\n * carries the rowPtr dummy of graphBindings); with the in-degree tiers of `reverseDegreeOrder()` (P4-T5, PD-6) it\n * is up to three dispatches over the permuted rows -- TIER 2 one workgroup per row over [0, hiEnd), TIER 1 32 lanes\n * per row over [hiEnd, midEnd), TIER 0 grid-stride over [midEnd, n) -- each compiled only when its range is\n * non-empty. The row and arc counts come from the core's binding sizes exactly as segmentedReduce derives them.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { graphBindings, graphOverrides, kernelSpec, SPMV_PARAMS } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { arcCountOf, assertNotWindowed, type DegreeTiers, MID_TIER_LANES, rowCountOf } from \"./core-shape.js\";\nimport { type ReduceScope } from \"./reduce.js\";\n\n/** The group-1 bindings of one pull: the pre-scaled input, the output, the personalization (null binds xNorm as the dummy) and the PrPartial block whose header carries danglingMass. */\nexport interface SpmvResources {\n readonly xNorm: Binding;\n readonly rankOut: Binding;\n readonly personalization: Binding | null;\n readonly partials: Binding;\n}\n\n/** The scalar coefficients of one pull (SpmvParams alpha / beta / uniformP). */\nexport interface SpmvCoefficients {\n readonly alpha: number;\n readonly beta: number;\n readonly uniformP: number;\n}\n\n/** Options of prepareSpmvPull: the two variant flags, the weights binding and the in-degree tiers (null: one grid-stride dispatch). */\nexport interface SpmvPullOptions {\n readonly personalization: boolean;\n readonly dangling: boolean;\n /** The weights binding to fold with: `undefined` takes the core's, `null` runs UNWEIGHTED on a weighted core. */\n readonly weights?: Binding | null | undefined;\n readonly tiers: DegreeTiers | null;\n}\n\n/** A prepared pull: records one grid-stride dispatch (no tiers) or up to three tier dispatches over the rows of a reverse core into a pass. */\nexport interface SpmvPullPlanner {\n /** Records the dispatches over rows [0, n) of `rev` writing rankOut[v] (f32) per row; nothing for n = 0. */\n record(\n pass: GPUComputePassEncoder,\n rev: CoreBinding,\n resources: SpmvResources,\n coefficients: SpmvCoefficients,\n ): void;\n /** Dispatches the last record() issued (0 for n = 0; 1 without tiers; 1 to 3 with them). */\n readonly lastDispatches: number;\n}\n\n/** One tier's compiled pipeline and the rows [start, end) of the permutation it covers per record() (a tier whose range is empty is not compiled). */\ninterface TierDispatch {\n readonly tier: 0 | 1 | 2;\n readonly kernel: Kernel;\n readonly start: number;\n readonly end: number;\n}\n\n/**\n * The tiered planner: without tiers ONE `spmv-pull` dispatch, grid-stride over every row; with tiers TIER 2 over\n * [0, hiEnd) (one workgroup per row), then TIER 1 over [hiEnd, midEnd) (WG / 32 rows per workgroup), then TIER 0\n * grid-stride over [midEnd, n), each with its own SpmvParams record (`n` is the range END) and the perm binding.\n */\nclass SpmvPullPlannerImpl implements SpmvPullPlanner {\n private readonly scope: ReduceScope;\n private readonly tiers: readonly TierDispatch[];\n private readonly perm: Binding | null;\n private readonly weights: Binding | null | undefined;\n private dispatches = 0;\n\n /**\n * Wraps the compiled tier pipelines with the choices they were compiled for.\n * @param scope - the scope the pipelines were prepared in\n * @param tiers - the compiled tiers in dispatch order (TIER 2, 1, 0; only the non-empty ones)\n * @param perm - the reverseDegreeOrder permutation binding (null: USE_PERM false, rows are node indices)\n * @param weights - the weights option the pipelines' HAS_WEIGHTS was derived from; record() binds the same way\n */\n constructor(\n scope: ReduceScope,\n tiers: readonly TierDispatch[],\n perm: Binding | null,\n weights: Binding | null | undefined,\n ) {\n this.scope = scope;\n this.tiers = tiers;\n this.perm = perm;\n this.weights = weights;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns 0 when the last record covered no rows, else the number of non-empty tier ranges\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the dispatches: every tier's rows over the arcs [0, arcCount), each with its own params record (TIER 0\n * grid-stride through planGridStride, the tiers through plan1d); nothing for n = 0 (no zero-length binding is\n * ever created). `personalization ?? xNorm` follows the group-0 dummy rule: both slots are storage-ro, so the\n * aliasing check of Kernel.bind does not fire, and HAS_PERSONALIZATION false never reads it.\n * @param pass - the pass to record into\n * @param rev - the reverse core (any snapshot with the weights pattern the planner was prepared for; with tiers,\n * the one the tiers were built from)\n * @param resources - xNorm, rankOut, personalization, partials\n * @param coefficients - alpha, beta, uniformP\n */\n record(\n pass: GPUComputePassEncoder,\n rev: CoreBinding,\n resources: SpmvResources,\n coefficients: SpmvCoefficients,\n ): void {\n const n = rowCountOf(rev, \"spmvPull\");\n const wg = this.scope.workgroupSize;\n this.dispatches = 0;\n for (const { tier, kernel, start, end } of this.tiers) {\n const last = tier === 0 ? n : end;\n const rows = last - start;\n if (rows <= 0) {\n continue;\n }\n const plan =\n tier === 0\n ? planGridStride(rows, wg, this.scope.caps)\n : plan1d(rows, tier === 2 ? 1 : wg / MID_TIER_LANES, this.scope.caps);\n if (plan.x === 0) {\n continue;\n }\n const params = this.scope.params(SPMV_PARAMS, {\n n: last,\n arcBase: 0,\n arcEnd: arcCountOf(rev),\n stride: plan.stride ?? rows,\n alpha: coefficients.alpha,\n beta: coefficients.beta,\n uniformP: coefficients.uniformP,\n start,\n });\n const bound = kernel.bind({\n ...graphBindings(rev, this.perm, this.weights),\n xNorm: resources.xNorm,\n rankOut: resources.rankOut,\n personalization: resources.personalization ?? resources.xNorm,\n partials: resources.partials,\n P: params.binding,\n });\n kernel.dispatch(pass, bound, plan, [params.offset]);\n this.dispatches++;\n }\n }\n}\n\n/**\n * Prepares the pull pipelines for a reverse core's weights pattern and the two variant flags: TIER 0 always\n * (USE_PERM = tiers !== null); TIER 1 iff a row of in-degree 32..1023 exists (segmentOffsets[2] >\n * segmentOffsets[1]); TIER 2 iff a row of in-degree >= 1024 exists (segmentOffsets[1] > 0). The mid tier folds 32\n * lanes per row, so a device whose workgroup size is below 32 is E_UNSUPPORTED { feature: \"spmvPull.tiers\" }.\n * @param scope - the reduce scope (pipelines, params writer)\n * @param rev - the reverse core whose weights pattern selects HAS_WEIGHTS\n * @param options - personalization, dangling, weights, tiers (null: the single grid-stride dispatch)\n * @returns the planner\n */\nexport async function prepareSpmvPull(\n scope: ReduceScope,\n rev: CoreBinding,\n options: SpmvPullOptions,\n): Promise<SpmvPullPlanner> {\n assertNotWindowed(rev, \"spmvPull\");\n const { tiers } = options;\n const perm = tiers?.perm ?? null;\n if (tiers !== null && scope.workgroupSize < MID_TIER_LANES) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `spmvPull: the mid tier folds ${MID_TIER_LANES} lanes per row, more than the workgroup size ${scope.workgroupSize}`,\n { feature: \"spmvPull.tiers\" },\n );\n }\n const ranges: readonly { readonly tier: 0 | 1 | 2; readonly start: number; readonly end: number }[] =\n tiers === null\n ? [{ tier: 0, start: 0, end: rowCountOf(rev, \"spmvPull\") }]\n : [\n { tier: 2, start: 0, end: tiers.segmentOffsets[1] },\n { tier: 1, start: tiers.segmentOffsets[1], end: tiers.segmentOffsets[2] },\n { tier: 0, start: tiers.segmentOffsets[2], end: tiers.segmentOffsets[4] },\n ];\n const compiled: TierDispatch[] = [];\n for (const range of ranges) {\n if (range.tier !== 0 && range.end <= range.start) {\n continue;\n }\n const spec = kernelSpec(\"spmv-pull\", {\n ...graphOverrides(rev, perm, options.weights),\n HAS_PERSONALIZATION: options.personalization,\n USE_DANGLING: options.dangling,\n TIER: range.tier,\n });\n compiled.push({ ...range, kernel: await scope.pipelines.kernel(spec) });\n }\n return new SpmvPullPlannerImpl(scope, compiled, perm, options.weights);\n}\n","/**\n * The power-iteration driver HITS, eigenvector centrality and Katz centrality share (spec 8.2 lines 2603-2605; M8b\n * plan PD-10): per iteration `pr-scale` at NORM_MODE 1 | 2 | 4 folds the norm term (and the L1 delta) into the\n * per-workgroup partials, `pr-finalize` folds them into the header at `partials[0]` (the square root for L2) and\n * records `firstConverged`, `pr-scale` at NORM_MODE 3 writes `xNorm[u] = x[u] / partials[0].norm` (skipped at\n * mode 4, the identity, where the first scale pass already wrote `xNorm[u] = x[u]`), and `spmv-pull` writes the\n * next iterate. Four dispatches (three for Katz), all on the device, NO readback inside the batch: the scalar\n * normaliser the host cannot supply without a readback is exactly what stays on the device, so these three batch\n * eight iterations per submit like PageRank does.\n *\n * The ping-pong is TWO buffers alternated through two cached bind groups (PD-7 / DEP-M8B-G), and `rankPrev` is the\n * buffer this iteration overwrites: it still holds x(i-2) when `pr-scale` reads it, because the scale runs before\n * the pull in the same pass (PD-9). With an `alternate` adjacency (HITS, spec 8.2: \"alternates two pulls\") the\n * iterations pull over `adjacency` and `alternate` in turn, and the ring is THREE buffers so the buffer being\n * overwritten holds x(i-3) -- the previous iterate of the same kind -- and the delta stays meaningful. The batch\n * loop duplicates src/algorithms/pagerank.ts, which its own task owns.\n */\n\nimport { type F32, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { U32_MAX } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { groupsOf, plan1d } from \"../kernel/dispatch.js\";\nimport { kernelSpec, PR_PARAMS, PR_PARTIAL } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { assertWholeCore, coreOfView } from \"../primitives/core-shape.js\";\nimport { prepareSpmvPull } from \"../primitives/spmv.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { algorithmScope } from \"./scope.js\";\n\n/** Iterations per submit (spec 8.2: k = 8). */\nconst BATCH = 8;\n/** Params slots of one batch: four blocks per iteration times the batch, plus a margin (the plan's `4 * 8 + 8`) that also holds the last batch's convergence check. */\nconst RING_SLOTS = 4 * BATCH + 8;\n\n/**\n * What one power iteration run needs. `adjacency` is the CoreBinding the pull walks -- the forward core for hubs\n * and eigenvector, coreOfView(view(s, \"reverse\")) for authorities and Katz (spec 8.2 lines 2603-2606). Exported\n * for runPowerIteration's signature, not imported by name.\n * @public\n */\nexport interface PowerIterationConfig {\n /**\n * 1 = L1 (sum) normalise, 2 = L2 normalise, 4 = identity (Katz: no normaliser). Never 0 or 3 here: 0 is\n * PageRank's per-node divisor and 3 is the internal scale pass this driver issues itself.\n */\n readonly normMode: 1 | 2 | 4;\n readonly adjacency: CoreBinding;\n /**\n * Null: every iteration pulls over `adjacency`. Non-null: the odd iterations (1, 3, ...) pull over `adjacency`\n * and the even ones over `alternate`, so x(i) = A_alt * norm(A * norm(x(i-2))) -- one interleaved chain of HITS,\n * whose hubs and authorities are the last iterates of the two chains (forward-first and reverse-first). The\n * ring then has three buffers and `weights` must be null or undefined (each core's own weights).\n */\n readonly alternate: CoreBinding | null;\n readonly alpha: number;\n readonly beta: number;\n readonly uniformP: number;\n readonly maxIterations: number;\n readonly tolerance: number;\n /** undefined takes the adjacency's weights, null runs UNWEIGHTED on a weighted snapshot (T4 Step 4). */\n readonly weights: Binding | null | undefined;\n readonly label: string;\n readonly signal: AbortSignal | undefined;\n readonly onProgress: ((done: number, total: number) => void) | undefined;\n}\n\n/** The iterate, the device-recorded first converged iteration, and the number of iterations actually run. */\nexport interface PowerIterationRun {\n readonly scores: F32;\n /** x(m - 1) on an alternating run: the chain's last iterate of the OTHER kind (hub or authority); null otherwise. */\n readonly previous: F32 | null;\n readonly iterations: number;\n readonly converged: boolean;\n readonly iterationsRun: number;\n}\n\n/**\n * Validates `options.dest` for a score result of `n` elements.\n * @param dest - the caller's destination array, if any\n * @param n - the node count\n * @param algorithm - the caller's name, for the message\n * @returns the destination as an F32, or null when none was given\n */\nexport function checkDest(dest: Float32Array | Uint32Array | undefined, n: number, algorithm: string): F32 | null {\n if (dest === undefined) {\n return null;\n }\n if (dest instanceof Float32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {\n return dest as F32;\n }\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${algorithm}: dest must be a Float32Array of length ${n} over an ArrayBuffer`,\n {\n argument: \"dest\",\n value: `${dest.constructor.name}(${dest.length})`,\n expected: `Float32Array(${n}) over an ArrayBuffer`,\n },\n );\n}\n\n/**\n * The resident core; a windowed plan is refused with `E_TOO_LARGE { path: \"windowed\", algorithm }` (spec 3.8, 3.12;\n * DEP-P4-B: only degree and segmentedReduce execute windows).\n * @param ctx - the context\n * @param s - the snapshot\n * @param algorithm - the caller's name\n * @returns the core binding\n */\nexport function coreOf(ctx: GpuContext, s: GraphSnapshot, algorithm: string): CoreBinding {\n const core = ctx.residency.core(s);\n assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, algorithm);\n return core;\n}\n\n/**\n * The reverse adjacency as the CoreBinding the pull walks (the forward buffers on an undirected snapshot, PD-13).\n * @param ctx - the context\n * @param s - the snapshot (n > 0)\n * @returns the reverse core\n */\nexport function reverseOf(ctx: GpuContext, s: GraphSnapshot): CoreBinding {\n // core() is what records (or re-records, after a release) the snapshot in the residency; Katz binds only this\n // view, so without it a released snapshot is E_RELEASED instead of uploaded again (issue #623)\n ctx.residency.core(s, [\"rowPtr\"]);\n const view = ctx.residency.view(s, \"reverse\");\n return coreOfView(view, view.scalars.arcCount[0]);\n}\n\n/**\n * The E_ABORTED error of a signal.\n * @param algorithm - the caller's name\n * @param batchId - the last submitted batch, when one exists\n * @returns the error\n */\nexport function aborted(algorithm: string, batchId?: number): WebGpuGraphError {\n return new WebGpuGraphError(\n \"E_ABORTED\",\n `${algorithm}: the signal was aborted`,\n batchId === undefined ? {} : { batchId },\n );\n}\n\n/**\n * Whole-buffer binding of a scratch buffer over its first `size` bytes.\n * @param buffer - the buffer\n * @param size - the bound byte length\n * @returns the binding\n */\nfunction whole(buffer: GPUBuffer, size: number): Binding {\n return { buffer, offset: 0, size, window: null };\n}\n\n/**\n * Runs the power iteration of `config` over `n` nodes from x(0) = 1 / n, in batches of eight iterations with ONE\n * readback per batch (the header and the iterate together), stopping at the first batch whose header records a\n * converged iteration or at `maxIterations`. The returned iterate is RAW: the last `spmv-pull` output, which the\n * caller normalises once on the host. The iterate travels with the header in EVERY batch, not once after the loop:\n * whether a batch terminates the run is known only from its header, and a second readback for the iterate would\n * be a second mapAsync (the plan's case 8 counts exactly one). The cost is 4n bytes (8n on an alternating run) of\n * staging per batch of 8 that the loop then discards when it continues -- 40 MB per 8 iterations at 10M nodes;\n * pagerank.ts pays the same.\n * @param ctx - the context\n * @param n - the node count (> 0)\n * @param config - the recurrence, the adjacency and the run options\n * @returns the raw iterate, the first converged iteration, whether it converged and the iterations actually run\n */\nexport async function runPowerIteration(\n ctx: GpuContext,\n n: number,\n config: PowerIterationConfig,\n): Promise<PowerIterationRun> {\n await assertDeviceComputes(ctx);\n const scope = algorithmScope(ctx, config.label, RING_SLOTS);\n try {\n const bytes = 4 * n;\n // x(i) lives in ring[i % ring.length]: two buffers for one pull per iteration, three for the alternating pair\n const ring = (config.alternate === null ? [\"rankA\", \"rankB\"] : [\"rankA\", \"rankB\", \"rankC\"]).map((label) =>\n whole(scope.scratch(bytes, label), bytes),\n );\n const xNorm = whole(scope.scratch(bytes, \"xNorm\"), bytes);\n const scalePlan = plan1d(n, ctx.workgroupSize, ctx.caps);\n const groups = groupsOf(scalePlan);\n const partialsBytes = PR_PARTIAL.byteLength * (1 + groups);\n const partialsBuffer = scope.scratch(partialsBytes, \"partials\");\n const partials = whole(partialsBuffer, partialsBytes);\n await ctx.allocator.check();\n const pullOptions = { personalization: false, dangling: false, weights: config.weights, tiers: null };\n const pulls = [{ core: config.adjacency, pull: await prepareSpmvPull(scope, config.adjacency, pullOptions) }];\n if (config.alternate !== null) {\n pulls.push({ core: config.alternate, pull: await prepareSpmvPull(scope, config.alternate, pullOptions) });\n }\n const scaleNorm = await ctx.pipelines.kernel(kernelSpec(\"pr-scale\", { NORM_MODE: config.normMode }));\n const scaleApply =\n config.normMode === 4 ? null : await ctx.pipelines.kernel(kernelSpec(\"pr-scale\", { NORM_MODE: 3 }));\n const finalize = await ctx.pipelines.kernel(kernelSpec(\"pr-finalize\", { NORM_MODE: config.normMode }));\n const finalizePlan = plan1d(1, ctx.workgroupSize, ctx.caps);\n const { queue } = ctx.device;\n queue.writeBuffer(ring[0].buffer, 0, new Float32Array(n).fill(1 / n));\n for (const slot of ring.slice(1)) {\n queue.writeBuffer(slot.buffer, 0, new Float32Array(n));\n }\n const header = new ArrayBuffer(PR_PARTIAL.byteLength);\n PR_PARTIAL.write(new DataView(header), { firstConverged: U32_MAX, iteration: 0 });\n queue.writeBuffer(partialsBuffer, 0, header);\n const coefficients = { alpha: config.alpha, beta: config.beta, uniformP: config.uniformP };\n let iterationsRun = 0;\n for (;;) {\n const k = Math.min(BATCH, config.maxIterations - iterationsRun);\n const batch = new CommandBatch(ctx, config.label);\n const pass = batch.pass(\"iterations\");\n // the scale + finalize of iteration i measures the error of iteration i - 1 (PD-9), so the last batch\n // runs them once more, with no apply and no pull, to measure the error of iteration maxIterations itself\n const last = iterationsRun + k === config.maxIterations;\n for (let i = 0; i < k + (last ? 1 : 0); i++) {\n const iteration = iterationsRun + i + 1;\n const params = scope.params(PR_PARAMS, {\n n,\n groups,\n iteration,\n trackConvergence: 1,\n convergeThreshold: config.tolerance * n,\n });\n const rankIn = ring[(iteration - 1) % ring.length];\n // the slot the pull overwrites still holds x(iteration - ring.length): that is rankPrev (PD-9)\n const rankOut = ring[iteration % ring.length];\n const { core, pull } = pulls[(iteration - 1) % pulls.length];\n // outWeightSum takes rankIn as its dummy: storage-ro, read only under NORM_MODE 0, never compiled here\n const scaleBindings = {\n rankIn,\n rankPrev: rankOut,\n outWeightSum: rankIn,\n xNorm,\n partials,\n P: params.binding,\n };\n scaleNorm.dispatch(pass, scaleNorm.bind(scaleBindings), scalePlan, [params.offset]);\n finalize.dispatch(pass, finalize.bind({ partials, P: params.binding }), finalizePlan, [params.offset]);\n if (i === k) {\n break;\n }\n if (scaleApply !== null) {\n scaleApply.dispatch(pass, scaleApply.bind(scaleBindings), scalePlan, [params.offset]);\n }\n pull.record(pass, core, { xNorm, rankOut, personalization: null, partials }, coefficients);\n }\n batch.endPass();\n const headerRequest = batch.readback(partialsBuffer, 0, PR_PARTIAL.byteLength);\n const scoresRequest = batch.readback(ring[(iterationsRun + k) % ring.length].buffer, 0, bytes);\n // x(m - 1) on an alternating run: the other kind, still intact in the third ring slot\n const previousRequest =\n config.alternate === null\n ? null\n : batch.readback(ring[(iterationsRun + k - 1) % ring.length].buffer, 0, bytes);\n scope.flush();\n const submitted = batch.submit();\n const back = await submitted.readback; // the ONE mapAsync of the batch (G7 item 5)\n iterationsRun += k;\n ctx.assertReady();\n if (config.signal?.aborted === true) {\n throw aborted(config.label, submitted.id);\n }\n config.onProgress?.(iterationsRun, config.maxIterations);\n const folded = PR_PARTIAL.read(new DataView(back), headerRequest.offset);\n const firstConverged = folded.firstConverged as number;\n const converged = firstConverged !== U32_MAX;\n if (converged || iterationsRun >= config.maxIterations) {\n if (converged && iterationsRun < config.maxIterations) {\n config.onProgress?.(config.maxIterations, config.maxIterations);\n }\n return {\n scores: new Float32Array(back, scoresRequest.offset, n).slice(),\n previous:\n previousRequest === null ? null : new Float32Array(back, previousRequest.offset, n).slice(),\n iterations: converged ? firstConverged : iterationsRun,\n converged,\n iterationsRun,\n };\n }\n }\n } finally {\n scope.dispose();\n }\n}\n","/**\n * Betweenness and edge betweenness on the device (design 8.4 \"Betweenness (A7)\", 3.3 lines 811-812, 9.7): Brandes'\n * algorithm as McLaughlin-Bader run it, k sources at a time.\n *\n * A source batch keeps four `n x k` arrays -- `depthK`, `sigmaK` (u32 shortest-path counts, or the f32 bits of the\n * rescaled ones), `deltaK` (f32 dependencies) and the claim log `S` -- plus `ends`, the level boundaries into the log,\n * and `levelMax`, the f32 bits of the largest rescaled count at each depth. Every array is indexed by\n * `s * n + v`, and a log entry IS that index, so one u32 names a `(vertex, source)` pair: `4 n k` bytes can never\n * reach 2^32 because each array is one storage binding. The forward pass is a tagged breadth-first search: every\n * level is `bc-finalize` (the boundary: `ends[level + 1] = stackTop`, `done` on an empty level) and then ONE forward\n * dispatch, either `bc-forward` (block-mapped over the level's range of the log) or `bc-forward-edge` (every edge of\n * the `edgeList` view for every source), both claiming, counting and appending with the same rules.\n * Levels are recorded `MAX_LEVELS_PER_SUBMIT` per submit with one small readback (the counters block and the `ends`\n * prefix), and the log's `ends` is known on the host when the forward phase ends, so the backward pass is planned\n * exactly: one `bc-backward` dispatch per level from the deepest to depth 1, each writing `delta[s][w]` once by pulling\n * over the successors; then `bc-gather` adds each vertex's k dependencies into `bc` (and `bc-edge-gather` each arc's k\n * terms into `arcScores`). Nothing accumulates a float through an atomic, so the scores are bitwise reproducible.\n *\n * Path counts that outgrow u32 (issue #719): a batch counts exactly in u32 first, and the forward kernels report a\n * wrap. A 19 x 19 grid already has C(36, 18), about 9.1e9, corner-to-corner paths, and f32 counts would only move the\n * cliff to a 68 x 68 grid. So a batch whose counts wrapped is abandoned before its backward pass and run again with\n * every kernel's `SCALED` override: the forward bodies only claim, and after each level `bc-count` pulls the new\n * depth's counts over the in-arcs (the `reverse` view; the forward core when undirected) as f32 divided by the power of\n * two that keeps the previous depth's largest count at 2^BC_SIGMA_EXPONENT_CAP; `bc-backward` and `bc-edge-gather` undo\n * that one step in the ratio Brandes' recursion reads, so the scores are what unbounded counts give. The rest of the\n * run stays scaled. A batch that never wraps runs exactly as before, bit for bit. In the scaled form `sigmaOverflow`\n * rises only when the counts at ONE depth span more than f32's exponent range (about 2^226; measured from a corner of a\n * grid, 235 x 235 raises it and 230 x 230 does not); the `@graphty/algorithms` dispatcher then throws instead of\n * returning the scores.\n *\n * The batch size k is planned from the device limits at 16 bytes per (node, source) -- the three arrays design 4.7\n * counts plus the 4-byte log entry it omits -- as `min(floor(maxStorageBufferBindingSize / 4n), floor(0.25 x\n * maxBufferSize / 16n), BC_MAX_BATCH)` (256), at least 1 (`planBatchSize`); a graph whose single source does not fit one binding is\n * E_TOO_LARGE. The forward form is chosen per batch: the first batch runs `bc-forward`; a later one runs the\n * edge-parallel form when the previous batch's level count -- the MAXIMUM depth over its sources, the only depth\n * figure the host has, which over-estimates the median of design 8.4's rule and so errs toward the frontier form --\n * is below `BC_EDGE_PARALLEL_GAMMA x log2(n)`.\n *\n * The host applies the CPU package's convention after the readback (`@graphty/algorithms` betweenness.ts): the vertex\n * scores are halved on an undirected snapshot (the gather counts each unordered pair from both ends); the edge scores\n * are folded with `foldArcs(s, perArc, \"sum\")` and halved the same way, because an undirected edge's two arcs carry\n * the pairs that cross it in each direction. Over every source both arcs hold the same sum, but over a sample they do\n * not: on the path 0-1-2 with the one source 2, arc 1->0 collects 1 and arc 0->1 collects 0, so keeping either arc\n * alone would lose the pairs crossing the other way. `normalized`\n * divides both by `(n - 1)(n - 2)` directed or half that undirected, when positive. A sampled run (`sources` or `k`)\n * is the UNSCALED sum over the sources run, reported beside `sourcesUsed`. `endpoints: true` is refused: the CPU's\n * endpoints branch (`algorithms/src/algorithms/centrality/betweenness.ts`, `predecessors.length === 0 && w !==\n * source`) can never fire for a vertex on the Brandes stack, so there is no behaviour to be in parity with.\n * Betweenness is breadth-first on both packages; weights are ignored. Parallel edges are distinct shortest paths\n * here (each arc adds to sigma), where the CPU package refuses them or, with `allowParallelEdges`, collapses them to\n * one: on a multigraph the two packages' scores differ.\n */\n\nimport { type F32, foldArcs, type GraphSnapshot, type U32 } from \"@graphty/graph-format\";\n\nimport {\n BC_BACKWARD_LEVELS_PER_SUBMIT,\n BC_BATCH_BUDGET_FRACTION,\n BC_COUNT_MAX_GROUPS,\n BC_EDGE_PARALLEL_GAMMA,\n BC_MAX_BATCH,\n MAX_LEVELS_PER_SUBMIT,\n} from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { BC_PARAMS, FILL_PARAMS, FRONTIER_COUNTERS, kernelSpec } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { assertWholeCore } from \"../primitives/core-shape.js\";\nimport { W } from \"../primitives/frontier.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type BetweennessAcceleratorOptions } from \"../types/accelerator.js\";\nimport { type GpuBetweennessResult, type GpuEdgeScoresResult } from \"../types/betweenness.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { reverseOf } from \"./power-iteration.js\";\nimport { type AlgorithmScope, algorithmScope } from \"./scope.js\";\nimport { aborted, bindingOf, checkDest } from \"./sssp.js\";\n\nconst ALGORITHM = \"betweennessCentrality\";\n\n/** Bytes one (node, source) pair holds in a batch: depthK, sigmaK, deltaK and the claim-log entry, 4 each. */\nconst BYTES_PER_NODE_SOURCE = 16;\n\n/** The seed of the deterministic draw of `k` sources (any fixed value: the draw only has to repeat). */\nconst SAMPLE_SEED = 0x9e3779b9;\n\n/** Params slots of the ring: a forward submit's records per level (boundary, forward and, when scaled, count) or a backward submit's levels, plus the fills, the seed and the gathers. */\nconst RING_SLOTS = Math.max(3 * MAX_LEVELS_PER_SUBMIT, BC_BACKWARD_LEVELS_PER_SUBMIT) + 16;\n\n/** The device limits the batch planner reads. */\ninterface BatchLimits {\n readonly maxStorageBufferBindingSize: number;\n readonly maxBufferSize: number;\n}\n\n/**\n * Which forward body a batch runs: pinned by the tuning, or chosen per batch.\n * @internal\n */\nexport type ForwardForm = \"frontier\" | \"edge\";\n\n/**\n * What the inspect seam hands the tests after every batch.\n * @internal\n */\nexport interface BetweennessBatchReport {\n /** The batch's sources, in tag order. */\n readonly sources: readonly number[];\n /** The forward body the batch ran. */\n readonly forward: ForwardForm;\n /** The non-empty levels (depth 0 .. levels - 1). */\n readonly levels: number;\n /** `ends[0 .. levels + 1]`: the entries at depth L are `S[ends[L] .. ends[L + 1])`. */\n readonly ends: U32;\n /** Whether the batch ran with rescaled f32 counts (its u32 counts wrapped on the first try). */\n readonly scaled: boolean;\n /** Whether a rescaled path count left f32's normal range in this batch. */\n readonly sigmaOverflow: boolean;\n /** The `n x k` arrays as the batch left them (null unless the tuning asked for them); `sigmaK` as stored: u32 counts, or the f32 bits of the scaled ones. */\n readonly depthK: U32 | null;\n readonly sigmaK: U32 | null;\n readonly deltaK: F32 | null;\n}\n\n/**\n * The knobs the tests need and nothing public offers.\n * @internal\n */\nexport interface BetweennessTuning {\n /** Pins the forward body (default: the per-batch choice). */\n readonly forward?: ForwardForm | \"auto\" | undefined;\n /** Forward levels recorded per submit (default `MAX_LEVELS_PER_SUBMIT`). */\n readonly levelsPerSubmit?: number | undefined;\n /** Faked device limits for the planner (a test's way to make k shrink). */\n readonly limits?: BatchLimits | undefined;\n /** Called after every batch. */\n readonly onBatch?: ((report: BetweennessBatchReport) => void) | undefined;\n /** Read the batch's `depthK`, `sigmaK` and `deltaK` back for `onBatch`. */\n readonly readArrays?: boolean | undefined;\n}\n\n/** The raw outcome of a run: the unhalved, unnormalised sums. */\ninterface RawBetweenness {\n readonly vertex: F32;\n readonly perArc: F32 | null;\n readonly sourcesUsed: number;\n readonly sigmaOverflow: boolean;\n readonly batches: number;\n}\n\n/**\n * The source batch size (design 8.4, 10.1): `min(floor(maxStorageBufferBindingSize / 4n), floor(0.25 x maxBufferSize /\n * 16n), BC_MAX_BATCH, remaining)`, at least 1. Each of the four `n x k` arrays is one binding of `4 n k` bytes, and the batch's\n * four together stay inside a quarter of the largest buffer.\n * @internal\n * @param n - the vertex count (>= 1)\n * @param remaining - the sources still to run (>= 1)\n * @param limits - the device limits\n * @returns k\n * @throws E_TOO_LARGE when one source's `ends` array (`4 (n + 2)` bytes, the largest) exceeds the binding limit\n */\nexport function planBatchSize(n: number, remaining: number, limits: BatchLimits): number {\n // the largest single binding of a one-source batch is `ends`, 4 (n + 2) bytes\n const needed = 4 * (n + 2);\n if (needed > limits.maxStorageBufferBindingSize) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: one source needs ${needed} bytes in its largest binding at n = ${n}, above maxStorageBufferBindingSize = ${limits.maxStorageBufferBindingSize}; a limit of at least ${needed} admits one source per batch`,\n { needed, limit: limits.maxStorageBufferBindingSize, path: \"binding\", algorithm: ALGORITHM },\n );\n }\n const kByBinding = Math.floor(limits.maxStorageBufferBindingSize / (4 * n));\n const kByBudget = Math.floor((BC_BATCH_BUDGET_FRACTION * limits.maxBufferSize) / (BYTES_PER_NODE_SOURCE * n));\n return Math.max(1, Math.min(kByBinding, kByBudget, BC_MAX_BATCH, remaining));\n}\n\n/**\n * `k` distinct vertices drawn by a partial Fisher-Yates shuffle over a fixed-seed mulberry32 stream: the same call\n * draws the same sources every time.\n * @param n - the vertex count\n * @param k - how many to draw (<= n)\n * @returns the sources\n */\nfunction drawSources(n: number, k: number): number[] {\n const pool = Array.from({ length: n }, (_, i) => i);\n let state = SAMPLE_SEED;\n for (let i = 0; i < k; i++) {\n state = (state + 0x6d2b79f5) >>> 0;\n let t = Math.imul(state ^ (state >>> 15), state | 1);\n t = (t + Math.imul(t ^ (t >>> 7), t | 61)) ^ t;\n const unit = ((t ^ (t >>> 14)) >>> 0) / 2 ** 32;\n const j = i + Math.floor(unit * (n - i));\n [pool[i], pool[j]] = [pool[j], pool[i]];\n }\n return pool.slice(0, k);\n}\n\n/**\n * The E_INVALID_ARGUMENT of a bad option.\n * @param argument - the option\n * @param value - its value\n * @param expected - what it must be\n * @returns the error\n */\nfunction badArgument(argument: string, value: unknown, expected: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${ALGORITHM}: ${argument} must be ${expected}`, {\n argument,\n value,\n expected,\n });\n}\n\n/**\n * The sources a call runs: `sources` as given, else `k` drawn, else every vertex.\n * @param options - the call's options\n * @param n - the vertex count\n * @returns the sources\n */\nfunction resolveSources(options: BetweennessAcceleratorOptions | undefined, n: number): number[] {\n const k = options?.k;\n if (k !== undefined && (!Number.isInteger(k) || k < 0 || k > n)) {\n throw badArgument(\"k\", k, `an integer in [0, ${n}]`);\n }\n const given = options?.sources;\n if (given !== undefined) {\n for (const v of given) {\n if (!Number.isInteger(v) || v < 0 || v >= n) {\n throw badArgument(\"sources\", v, `node indices in [0, ${n})`);\n }\n }\n if (k !== undefined && k !== given.length) {\n throw badArgument(\"k\", k, `absent or equal to sources.length (${given.length})`);\n }\n return [...given];\n }\n if (k !== undefined) {\n return drawSources(n, k);\n }\n return Array.from({ length: n }, (_, i) => i);\n}\n\n/** The device state of a run: the batch arrays sized for the largest batch, the results, the kernels. */\ninterface RunState {\n readonly ctx: GpuContext;\n readonly scope: AlgorithmScope;\n readonly n: number;\n readonly S: Binding;\n readonly ends: Binding;\n readonly levelMax: Binding;\n readonly depthK: Binding;\n readonly sigmaK: Binding;\n readonly deltaK: Binding;\n readonly counters: Binding;\n readonly bc: Binding;\n readonly arcScores: Binding | null;\n readonly rowPtr: Binding;\n readonly colIdx: Binding;\n readonly edgeSrc: Binding | null;\n readonly edgeDst: Binding | null;\n readonly edgeCount: number;\n readonly arcCount: number;\n readonly fill: Kernel;\n readonly gather: Kernel;\n /** The u32 kernels every batch tries first. */\n readonly exact: ModeKernels;\n /** The `SCALED` kernels, compiled when a batch's counts first wrap. */\n scaled: ModeKernels | null;\n /** Each bc kernel bound once per run: its resources never change inside a run, only the params offset does. */\n readonly bound: Map<Kernel, BoundKernel>;\n}\n\n/** The kernels of one counting mode; `count` and `reverse` (the in-arcs it pulls over) only when scaled. */\ninterface ModeKernels {\n readonly finalize: Kernel;\n readonly forward: Kernel;\n readonly forwardEdge: Kernel | null;\n readonly backward: Kernel;\n readonly edgeGather: Kernel | null;\n readonly count: { readonly kernel: Kernel; readonly rowPtr: Binding; readonly colIdx: Binding } | null;\n}\n\n/**\n * Compiles the kernels of one counting mode.\n * @param ctx - the context\n * @param s - the snapshot\n * @param core - its forward core (the in-arcs of an undirected snapshot)\n * @param withForwardEdge - also the edge-parallel forward body\n * @param withEdges - also the per-arc gather\n * @param scaled - the `SCALED` variants plus `bc-count`\n * @returns the kernels\n */\nasync function modeKernels(\n ctx: GpuContext,\n s: GraphSnapshot,\n core: CoreBinding,\n withForwardEdge: boolean,\n withEdges: boolean,\n scaled: boolean,\n): Promise<ModeKernels> {\n const SCALED = scaled;\n const [finalize, forward, backward] = await Promise.all(\n ([\"bc-finalize\", \"bc-forward\", \"bc-backward\"] as const).map((id) =>\n ctx.pipelines.kernel(kernelSpec(id, { SCALED })),\n ),\n );\n const forwardEdge = withForwardEdge\n ? await ctx.pipelines.kernel(kernelSpec(\"bc-forward-edge\", { UNDIRECTED: !s.directed, SCALED }))\n : null;\n const edgeGather = withEdges ? await ctx.pipelines.kernel(kernelSpec(\"bc-edge-gather\", { SCALED })) : null;\n let count: ModeKernels[\"count\"] = null;\n if (scaled) {\n const reverse = s.directed ? reverseOf(ctx, s) : core;\n count = {\n kernel: await ctx.pipelines.kernel(kernelSpec(\"bc-count\")),\n rowPtr: reverse.rowPtr,\n colIdx: reverse.colIdx ?? reverse.rowPtr,\n };\n }\n return { finalize, forward, forwardEdge, backward, edgeGather, count };\n}\n\n/**\n * Records one `fill` of `count` words.\n * @param state - the run\n * @param pass - the pass\n * @param dst - the buffer\n * @param count - the words\n * @param value - the u32 written\n */\nfunction recordFill(state: RunState, pass: GPUComputePassEncoder, dst: Binding, count: number, value: number): void {\n const { scope, fill, ctx } = state;\n const params = scope.params(FILL_PARAMS, { count, value, mode: 0, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst, P: params.binding }), plan1d(count, ctx.workgroupSize, ctx.caps), [\n params.offset,\n ]);\n}\n\n/**\n * Records a kernel with one BcParams record; the kernel is bound on its first use in the run.\n * @param state - the run\n * @param pass - the pass\n * @param kernel - the kernel\n * @param resources - its storage bindings (the same on every call for one kernel)\n * @param fields - the BcParams fields\n * @param items - the items the grid-stride plan covers\n * @param maxGroups - the most workgroups the plan launches (default: the planner's cap)\n */\nfunction recordBc(\n state: RunState,\n pass: GPUComputePassEncoder,\n kernel: Kernel,\n resources: Readonly<Record<string, Binding>>,\n fields: Readonly<Record<string, number>>,\n items: number,\n maxGroups?: number,\n): void {\n const { scope, ctx } = state;\n const plan = planGridStride(items, ctx.workgroupSize, ctx.caps, maxGroups);\n const params = scope.params(BC_PARAMS, { ...fields, stride: plan.stride ?? 0 });\n let bound = state.bound.get(kernel);\n if (bound === undefined) {\n bound = kernel.bind({ ...resources, P: params.binding });\n state.bound.set(kernel, bound);\n }\n kernel.dispatch(pass, bound, items === 0 ? plan1d(1, ctx.workgroupSize, ctx.caps) : plan, [params.offset]);\n}\n\n/**\n * Submits after flushing the ring and waits for the readback; aborts between submits.\n * @param state - the run\n * @param batch - the batch\n * @param signal - the caller's signal\n * @returns the readback bytes\n */\nasync function submit(state: RunState, batch: CommandBatch, signal: AbortSignal | undefined): Promise<ArrayBuffer> {\n state.scope.flush();\n const submitted = batch.submit();\n const back = await submitted.readback;\n state.ctx.assertReady();\n if (signal?.aborted) {\n throw aborted(ALGORITHM, submitted.id);\n }\n return back;\n}\n\n/**\n * One source batch: seed, forward levels until an empty one, backward levels, the gathers. In the exact mode a batch\n * whose u32 counts wrapped stops after its forward phase (`wrapped`), before anything reaches the scores.\n * @param state - the run\n * @param mode - the kernels of the counting mode\n * @param sources - the batch's sources\n * @param form - the forward body\n * @param levelsPerSubmit - the forward cadence\n * @param tuning - the knobs\n * @param signal - the caller's signal\n * @returns the batch's levels, whether its exact counts wrapped, and the scaled form's overflow flag\n */\nasync function runBatch(\n state: RunState,\n mode: ModeKernels,\n sources: readonly number[],\n form: ForwardForm,\n levelsPerSubmit: number,\n tuning: BetweennessTuning,\n signal: AbortSignal | undefined,\n): Promise<{ levels: number; wrapped: boolean; overflow: boolean }> {\n const { ctx, n, S, ends, levelMax, depthK, sigmaK, deltaK, counters } = state;\n const k = sources.length;\n const words = n * k;\n const seeds = Uint32Array.from(sources, (v, s) => s * n + v);\n ctx.device.queue.writeBuffer(S.buffer, S.offset, seeds);\n\n // the forward phase: the first submit also clears the batch's arrays and seeds it\n const forwardFields = { n, k, count: form === \"edge\" ? state.edgeCount : 0 };\n const forwardItems = form === \"edge\" ? state.edgeCount : words;\n let recorded = 0;\n let levels = 0;\n let overflow = false;\n let endsWords: U32 | null = null;\n for (let first = true; endsWords === null; first = false) {\n const batch = new CommandBatch(ctx, `${ALGORITHM}/forward`);\n const pass = batch.pass(\"forward\");\n if (first) {\n recordFill(state, pass, depthK, words, 0xffffffff);\n recordFill(state, pass, sigmaK, words, 0);\n recordFill(state, pass, deltaK, words, 0);\n if (mode.count !== null) {\n recordFill(state, pass, levelMax, n + 2, 0);\n }\n recordBc(state, pass, mode.finalize, { counters, ends, S, depthK, sigmaK, levelMax }, { n, k, role: 1 }, 1);\n }\n for (let level = 0; level < levelsPerSubmit; level++) {\n recordBc(state, pass, mode.finalize, { counters, ends, S, depthK, sigmaK, levelMax }, { n, k, role: 0 }, 1);\n if (form === \"edge\" && mode.forwardEdge !== null && state.edgeSrc !== null && state.edgeDst !== null) {\n recordBc(\n state,\n pass,\n mode.forwardEdge,\n { edgeSrc: state.edgeSrc, edgeDst: state.edgeDst, S, ends, counters, depthK, sigmaK },\n forwardFields,\n forwardItems,\n );\n } else {\n recordBc(\n state,\n pass,\n mode.forward,\n { rowPtr: state.rowPtr, colIdx: state.colIdx, S, ends, counters, depthK, sigmaK },\n forwardFields,\n forwardItems,\n );\n }\n if (mode.count !== null) {\n const { kernel, rowPtr, colIdx } = mode.count;\n recordBc(\n state,\n pass,\n kernel,\n { rowPtr, colIdx, S, ends, counters, depthK, sigmaK, levelMax },\n { n, k },\n words,\n BC_COUNT_MAX_GROUPS,\n );\n }\n }\n recorded += levelsPerSubmit;\n batch.endPass();\n const endsCount = Math.min(n + 2, recorded + 1);\n const countersRequest = batch.readback(counters.buffer, counters.offset, FRONTIER_COUNTERS.byteLength);\n const endsRequest = batch.readback(ends.buffer, ends.offset, 4 * endsCount);\n const back = await submit(state, batch, signal);\n const words32 = new Uint32Array(back, countersRequest.offset, FRONTIER_COUNTERS.byteLength / 4);\n if (words32[W.done] !== 0) {\n levels = words32[W.level];\n overflow = words32[W.sigmaOverflow] !== 0;\n endsWords = new Uint32Array(back, endsRequest.offset, endsCount).slice(0, levels + 1);\n if (overflow && mode.count === null) {\n return { levels, wrapped: true, overflow: false };\n }\n } else if (recorded > n + 2) {\n // a batch claims at most n - 1 levels deep, then one level is empty\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: the done flag never rose in ${recorded} levels`, {\n label: ALGORITHM,\n message: `the done flag never rose in ${recorded} levels`,\n });\n }\n }\n\n // the backward phase, planned from ends: depth levels - 1 down to 1, then the gathers\n const backwardLevels: number[] = [];\n for (let level = levels - 1; level >= 1; level--) {\n backwardLevels.push(level);\n }\n let arrays: { depthK: U32; sigmaK: U32; deltaK: F32 } | null = null;\n for (let i = 0; ; i += BC_BACKWARD_LEVELS_PER_SUBMIT) {\n const chunk = backwardLevels.slice(i, i + BC_BACKWARD_LEVELS_PER_SUBMIT);\n const last = i + BC_BACKWARD_LEVELS_PER_SUBMIT >= backwardLevels.length;\n const batch = new CommandBatch(ctx, `${ALGORITHM}/backward`);\n const pass = batch.pass(\"backward\");\n for (const level of chunk) {\n const start = endsWords[level];\n const count = endsWords[level + 1] - start;\n recordBc(\n state,\n pass,\n mode.backward,\n { rowPtr: state.rowPtr, colIdx: state.colIdx, S, depthK, sigmaK, deltaK, levelMax },\n { n, k, start, count },\n count,\n );\n }\n if (last) {\n recordBc(state, pass, state.gather, { deltaK, bc: state.bc }, { n, k }, n);\n if (mode.edgeGather !== null && state.arcScores !== null) {\n recordBc(\n state,\n pass,\n mode.edgeGather,\n {\n rowPtr: state.rowPtr,\n colIdx: state.colIdx,\n depthK,\n sigmaK,\n deltaK,\n arcScores: state.arcScores,\n levelMax,\n },\n { n, k, count: state.arcCount },\n state.arcCount,\n );\n }\n }\n batch.endPass();\n const wantArrays = last && tuning.readArrays === true;\n const requests = wantArrays\n ? [depthK, sigmaK, deltaK].map((b) => batch.readback(b.buffer, b.offset, 4 * words))\n : [];\n const back = await submit(state, batch, signal);\n if (wantArrays) {\n arrays = {\n depthK: new Uint32Array(back, requests[0].offset, words).slice(),\n sigmaK: new Uint32Array(back, requests[1].offset, words).slice(),\n deltaK: new Float32Array(back, requests[2].offset, words).slice(),\n };\n }\n if (last) {\n break;\n }\n }\n tuning.onBatch?.({\n sources,\n forward: form,\n levels,\n ends: endsWords.slice(),\n scaled: mode.count !== null,\n sigmaOverflow: overflow,\n depthK: arrays?.depthK ?? null,\n sigmaK: arrays?.sigmaK ?? null,\n deltaK: arrays?.deltaK ?? null,\n });\n return { levels, wrapped: false, overflow };\n}\n\n/**\n * The raw sums of a run over `sources` (see the file comment).\n * @param ctx - the context\n * @param s - the snapshot\n * @param sources - the sources (non-empty, n >= 1)\n * @param withEdges - also accumulate the per-arc scores\n * @param tuning - the knobs\n * @param options - signal / onProgress\n * @returns the raw sums\n */\nasync function runRaw(\n ctx: GpuContext,\n s: GraphSnapshot,\n sources: readonly number[],\n withEdges: boolean,\n tuning: BetweennessTuning,\n options: GpuRunOptions | undefined,\n): Promise<RawBetweenness> {\n const n = s.nodeCount;\n const pinned = tuning.forward ?? \"auto\";\n const levelsPerSubmit = tuning.levelsPerSubmit ?? MAX_LEVELS_PER_SUBMIT;\n if (!Number.isInteger(levelsPerSubmit) || levelsPerSubmit < 1 || levelsPerSubmit > MAX_LEVELS_PER_SUBMIT) {\n throw badArgument(\"levelsPerSubmit\", levelsPerSubmit, `an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`);\n }\n const limits = tuning.limits ?? ctx.caps.limits;\n const kMax = planBatchSize(n, sources.length, limits);\n const core = ctx.residency.core(s);\n assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, ALGORITHM);\n const { edgeCount } = s;\n // the edge-parallel form runs only when pinned, or from the second batch on: a one-batch run never uploads the view\n const mayRunEdge = pinned === \"edge\" || (pinned === \"auto\" && sources.length > kMax);\n const edgeView = mayRunEdge && edgeCount > 0 ? ctx.residency.view(s, \"edgeList\") : null;\n const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);\n try {\n const arrayBytes = 4 * n * kMax;\n const lease = (bytes: number, label: string): Binding => bindingOf(scope.scratch(bytes, label), bytes);\n const arcBytes = 4 * Math.max(1, s.arcCount);\n const [fill, gather] = await Promise.all(\n ([\"fill\", \"bc-gather\"] as const).map((id) => ctx.pipelines.kernel(kernelSpec(id))),\n );\n const exact = await modeKernels(ctx, s, core, edgeView !== null, withEdges, false);\n const state: RunState = {\n ctx,\n scope,\n n,\n S: lease(arrayBytes, \"S\"),\n ends: lease(4 * (n + 2), \"ends\"),\n levelMax: lease(4 * (n + 2), \"level-max\"),\n depthK: lease(arrayBytes, \"depthK\"),\n sigmaK: lease(arrayBytes, \"sigmaK\"),\n deltaK: lease(arrayBytes, \"deltaK\"),\n counters: lease(FRONTIER_COUNTERS.byteLength, \"counters\"),\n bc: lease(4 * n, \"bc\"),\n arcScores: withEdges ? lease(arcBytes, \"arc-scores\") : null,\n rowPtr: core.rowPtr,\n colIdx: core.colIdx ?? core.rowPtr,\n edgeSrc: edgeView?.bindings.src ?? null,\n edgeDst: edgeView?.bindings.dst ?? null,\n edgeCount,\n arcCount: s.arcCount,\n fill,\n gather,\n exact,\n scaled: null,\n bound: new Map(),\n };\n await ctx.allocator.check();\n\n // the result accumulators start at 0\n const setup = new CommandBatch(ctx, `${ALGORITHM}/setup`);\n const setupPass = setup.pass(\"setup\");\n recordFill(state, setupPass, state.bc, n, 0);\n if (state.arcScores !== null) {\n recordFill(state, setupPass, state.arcScores, arcBytes / 4, 0);\n }\n setup.endPass();\n await submit(state, setup, options?.signal);\n\n let overflow = false;\n let batches = 0;\n let previousLevels = -1;\n for (let start = 0; start < sources.length; ) {\n const k = planBatchSize(n, sources.length - start, limits);\n let form: ForwardForm = pinned === \"edge\" ? \"edge\" : \"frontier\";\n if (pinned === \"auto\" && previousLevels >= 0) {\n form = previousLevels < BC_EDGE_PARALLEL_GAMMA * Math.log2(n) ? \"edge\" : \"frontier\";\n }\n if (state.exact.forwardEdge === null) {\n form = \"frontier\"; // no edges to run edge-parallel over\n }\n const batch = sources.slice(start, start + k);\n let outcome = await runBatch(\n state,\n state.scaled ?? state.exact,\n batch,\n form,\n levelsPerSubmit,\n tuning,\n options?.signal,\n );\n if (outcome.wrapped) {\n // the u32 counts wrapped: this batch, and every later one, counts rescaled f32 instead\n state.scaled ??= await modeKernels(ctx, s, core, edgeView !== null, withEdges, true);\n outcome = await runBatch(state, state.scaled, batch, form, levelsPerSubmit, tuning, options?.signal);\n }\n overflow = overflow || outcome.overflow;\n previousLevels = outcome.levels;\n start += k;\n batches += 1;\n options?.onProgress?.(start, sources.length);\n }\n\n const result = new CommandBatch(ctx, `${ALGORITHM}/result`);\n const vertexRequest = result.readback(state.bc.buffer, state.bc.offset, 4 * n);\n const arcRequest =\n state.arcScores === null\n ? null\n : result.readback(state.arcScores.buffer, state.arcScores.offset, 4 * s.arcCount);\n const back = await submit(state, result, options?.signal);\n return {\n vertex: new Float32Array(back, vertexRequest.offset, n).slice(),\n perArc: arcRequest === null ? null : new Float32Array(back, arcRequest.offset, s.arcCount).slice(),\n sourcesUsed: sources.length,\n sigmaOverflow: overflow,\n batches,\n };\n } finally {\n scope.dispose();\n }\n}\n\n/**\n * The CPU's normalisation factor: `(n - 1)(n - 2)` directed, half that undirected; 1 when not normalising or when the\n * factor is not positive.\n * @param s - the snapshot\n * @param normalized - the option\n * @returns the divisor\n */\nfunction normaliser(s: GraphSnapshot, normalized: boolean | undefined): number {\n const n = s.nodeCount;\n const factor = s.directed ? (n - 1) * (n - 2) : ((n - 1) * (n - 2)) / 2;\n return normalized === true && factor > 0 ? factor : 1;\n}\n\n/**\n * The checks every entry makes before any device work.\n * @param ctx - the context\n * @param options - the options\n */\nasync function precheck(ctx: GpuContext, options: BetweennessAcceleratorOptions | undefined): Promise<void> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n if (options?.endpoints === true) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: endpoints: true is not supported`, {\n feature: \"betweenness.endpoints\",\n hint: \"the CPU endpoints branch in algorithms/src/algorithms/centrality/betweenness.ts (predecessors.length === 0 && w !== source) never fires, so there is no convention to match\",\n });\n }\n}\n\n/**\n * Vertex betweenness with the test knobs; `betweennessCentrality` is this with an empty tuning.\n * @internal\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot\n * @param options - the betweenness options plus dest / signal / onProgress\n * @param tuning - the knobs\n * @returns the scores\n */\nexport async function betweennessWithTuning(\n ctx: GpuContext,\n s: GraphSnapshot,\n options: (BetweennessAcceleratorOptions & GpuRunOptions) | undefined,\n tuning: BetweennessTuning,\n): Promise<GpuBetweennessResult> {\n await precheck(ctx, options);\n const n = s.nodeCount;\n const scores = checkDest(ALGORITHM, options?.dest, n) ?? new Float32Array(n);\n const sources = resolveSources(options, n);\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM);\n }\n if (n === 0 || sources.length === 0) {\n scores.fill(0);\n return { scores, iterations: 0, converged: true, precision: \"f32\", sourcesUsed: 0, sigmaOverflow: false };\n }\n const raw = await runRaw(ctx, s, sources, false, tuning, options);\n const divisor = (s.directed ? 1 : 2) * normaliser(s, options?.normalized);\n for (let v = 0; v < n; v++) {\n scores[v] = raw.vertex[v] / divisor;\n }\n return {\n scores,\n iterations: raw.batches,\n converged: true,\n precision: \"f32\",\n sourcesUsed: raw.sourcesUsed,\n sigmaOverflow: raw.sigmaOverflow,\n };\n}\n\n/**\n * Edge betweenness with the test knobs; `edgeBetweennessCentrality` is this with an empty tuning.\n * @internal\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot\n * @param options - the betweenness options plus dest (a Float32Array of edgeCount) / signal / onProgress\n * @param tuning - the knobs\n * @param onArcs - called with the per-arc scores before the fold (the tests' pairing check)\n * @returns the per-edge scores\n */\nexport async function edgeBetweennessWithTuning(\n ctx: GpuContext,\n s: GraphSnapshot,\n options: (BetweennessAcceleratorOptions & GpuRunOptions) | undefined,\n tuning: BetweennessTuning,\n onArcs?: (perArc: F32) => void,\n): Promise<GpuEdgeScoresResult> {\n await precheck(ctx, options);\n const n = s.nodeCount;\n const scores = checkDest(\"edgeBetweennessCentrality\", options?.dest, s.edgeCount) ?? new Float32Array(s.edgeCount);\n const sources = resolveSources(options, n);\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM);\n }\n if (n === 0 || sources.length === 0 || s.arcCount === 0) {\n scores.fill(0);\n return { scores, precision: \"f32\", sourcesUsed: sources.length, sigmaOverflow: false };\n }\n const raw = await runRaw(ctx, s, sources, true, tuning, options);\n const perArc = raw.perArc ?? new Float32Array(s.arcCount);\n onArcs?.(perArc);\n const folded = foldArcs(s, perArc, \"sum\");\n const divisor = (s.directed ? 1 : 2) * normaliser(s, options?.normalized);\n for (let e = 0; e < s.edgeCount; e++) {\n scores[e] = folded[e] / divisor;\n }\n return { scores, precision: \"f32\", sourcesUsed: raw.sourcesUsed, sigmaOverflow: raw.sigmaOverflow };\n}\n\n/**\n * Betweenness centrality on the device (spec 3.3 line 811, design 8.4): Brandes' algorithm, k sources per batch.\n * Exact over every vertex by default; `sources` or `k` gives the SAMPLED form, whose scores are the unscaled sum over\n * the sources run (`sourcesUsed` beside them; multiply by `n / sourcesUsed` for the estimator of the full sum). The\n * CPU package's convention: halved on an undirected snapshot, `normalized` divides by `(n - 1)(n - 2)` directed or\n * half that undirected. Weights are ignored (breadth-first on both packages). `endpoints: true` is E_UNSUPPORTED.\n * The path counts are f32 rescaled per depth, so a lattice's astronomically many shortest paths are counted exactly\n * enough; `sigmaOverflow` is true only when the counts at one depth spread wider than f32's exponent range (about\n * 2^226): the scores are then wrong, and the `@graphty/algorithms` dispatcher throws instead of returning them.\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - `normalized`, `endpoints`, `sources`, `k`, plus dest (a Float32Array of length n) / signal / onProgress (sources done, sources total)\n * @returns the f32 scores, `iterations` (the source batches run), `converged: true`, `sourcesUsed`, `sigmaOverflow`\n */\nexport function betweennessCentrality(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: BetweennessAcceleratorOptions & GpuRunOptions,\n): Promise<GpuBetweennessResult> {\n return betweennessWithTuning(ctx, s, options, {});\n}\n\n/**\n * Edge betweenness centrality on the device (spec 3.3 line 812, design 8.4): the per-arc terms of the same batches,\n * folded to one score per edge with `foldArcs(s, perArc, \"sum\")` and halved on an undirected snapshot (the two arcs\n * carry the pairs crossing the edge in each direction, so their sum counts each unordered pair twice; this is the CPU\n * package's number, and it holds for a sample too). `normalized`, sampling, `endpoints` and `sigmaOverflow` as in\n * `betweennessCentrality`.\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - as `betweennessCentrality`, dest a Float32Array of length edgeCount\n * @returns the f32 per-edge scores, `sourcesUsed`, `sigmaOverflow`\n */\nexport function edgeBetweennessCentrality(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: BetweennessAcceleratorOptions & GpuRunOptions,\n): Promise<GpuEdgeScoresResult> {\n return edgeBetweennessWithTuning(ctx, s, options, {});\n}\n","/**\n * Closeness centrality on the device (design 8.4, 3.3 line 810, 9.7): `score[s] = 1 / sumDist_s`, with `sumDist_s`\n * the exact sum of the finite distances from `s` to every OTHER node -- an unreached node adds nothing -- and `0` when\n * nothing is reached; or, with `harmonic`, `score[s] = sum of 1 / dist` over the same nodes (a zero distance adds\n * nothing). No reached factor and no Wasserman-Faust scaling: this is EXACTLY the legacy default (`normalized:\n * false`) of `closenessCentrality` in `@graphty/algorithms`, the number graphty-element's closeness panel shows.\n *\n * Three routes, chosen from the inputs before any device work:\n *\n * - ALL-PAIRS (an exact run whose `n x n` f32 matrix fits one binding, weighted, or unweighted up to\n * `ALL_PAIRS_MAX_NODES`): `allPairsShortestPath`'s blocked Floyd-Warshall sweep, then `closeness-rowsum` folds each row on\n * the device -- hop counts as exact integers, weighted distances and harmonic reciprocals in f32 -- and only `n`\n * words come back. Weighted scores agree with the one-search-per-source route up to f32 rounding of the sums.\n * - LEVELS (unweighted, every other case): a bit-parallel multi-source breadth-first search, `32 x words` sources per\n * batch (up to `MAX_WORDS` = 8 words, 256 sources), ONE `closeness-level` dispatch per level. Each level chooses on\n * the device between pushing the frontier over the out-arcs (one invocation per arc) and pulling it over the\n * in-arcs (one invocation per node, with an early exit once every source has reached the node), from the arcs the\n * frontier would push against `pullAt`; a graph with a node of more than `PULL_MAX_DEGREE` in-arcs only pushes. The levels of a\n * submit tally their claims per source into one count table, read back once per submit; the host folds the counts\n * into exact sums in f64 (`count x distance`) and harmonic sums (`count / distance`). A level whose predecessor\n * claimed nothing returns at once, so recording `MAX_LEVELS_PER_SUBMIT` levels costs little past a batch's depth.\n * - ONE SEARCH PER SOURCE (weighted above the all-pairs ceiling, or a weighted sampled run): one `sssp` per source,\n * the sums reduced on the host between calls.\n *\n * `weighted` defaults to the snapshot's `flags.weighted`; `weighted: false` on a weighted snapshot ignores the column;\n * `weighted: true` over unit weights or no column is the unweighted problem. `maxIterations` and `tolerance` are the\n * seam's placeholder keys and an exact traversal has neither, so a defined value is REFUSED before any device work\n * (`E_UNSUPPORTED { option }`); `undefined` is legal. `iterations` reports the source batches run (the sources, on the\n * one-search-per-source route; 1 on the all-pairs route), `converged` is always true.\n *\n * A SAMPLED run (`sources`, undirected snapshots only) seeds its batches from the listed sources and adds every\n * claim's distance into a per-node sum, folded on the host into `1 / sum` per NODE: on an undirected graph the\n * distance from a source to a node is the distance from the node to the source, which is what the CPU port's sampled\n * closeness sums. A sampled harmonic run is refused (`E_UNSUPPORTED closenessCentrality.sampledHarmonic`): the\n * per-node reciprocal sums would need a float atomic.\n *\n * Cost, stated so nobody is surprised: closeness is O(n x m) on any device -- at 1M nodes it is 3,907 batches of a\n * full multi-source traversal. The level kernel binds the whole arc array (`assertWholeCore`) and, on a directed\n * snapshot, the whole reverse adjacency. `closenessWithTuning` is what the tests drive; nothing public exposes it.\n */\n\nimport { type F32, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { MAX_LEVELS_PER_SUBMIT } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d, plan2d } from \"../kernel/dispatch.js\";\nimport { CLOSENESS_PARAMS, FILL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { assertWholeCore, coreOfView } from \"../primitives/core-shape.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type ClosenessAcceleratorOptions, type HitsOptionsLike } from \"../types/accelerator.js\";\nimport { type GpuClosenessResult } from \"../types/algorithms.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { allPairsCeiling, DEFAULT_ROUNDS_PER_SUBMIT, sweepAllPairs } from \"./all-pairs.js\";\nimport { algorithmScope } from \"./scope.js\";\nimport { aborted, bindingOf, checkDest, sssp } from \"./sssp.js\";\n\nconst ALGORITHM = \"closenessCentrality\";\n\n/**\n * The most 32-bit words per node of the level route: `32 x MAX_WORDS` = 256 sources per batch, the size of the\n * kernel's workgroup tally.\n * @internal\n */\nexport const MAX_WORDS = 8;\n\n/**\n * A level pulls when the arcs its frontier would push exceed `words x arcCount / PULL_RATIO`: the push touches every\n * arc whatever the frontier, so it is the cheap step only while few of them claim anything, and the pull's early exit\n * pays once the frontier is large. Measured on the RTX 4070 SUPER (level route, eight words per node) against always\n * pushing and always pulling: uniform random graphs of 4,096 nodes at 64 to 512 arcs per node 9.9 / 13.5 / 19.9 ms\n * against 16.5 / 25.7 / 68.4 pushing and 12.4 / 18.9 / 36.7 pulling; 16,384 nodes at 32 arcs per node 52.7 against\n * 142.7 and 54.1; at 8 arcs per node and below, rings, a path, a grid and a star within noise of the better of the\n * two. 4 and 16 measured within a few percent of 64.\n */\nconst PULL_RATIO = 64;\n\n/**\n * The most in-arcs a node may have for the level route to pull: a pull invocation walks one node's in-arcs, so its\n * loop count is about `in-degree x (words + 1)`, and llvmpipe silently ends every loop of an invocation past 65,535\n * iterations (`(65,535 - 512) / 9` is 7,225 at eight words). A graph with a larger hub runs every level as a push,\n * one invocation per arc.\n * @internal\n */\nexport const PULL_MAX_DEGREE = 4096;\n\n/** The control ring at the end of the count table: three slots of four words (`any`, `arcs`, `pull`, pad). */\nconst CTRL_WORDS = 12;\n\n/** Which route a run took. @internal */\nexport type ClosenessRoute = \"levels\" | \"all-pairs\" | \"per-source\";\n\n/**\n * The knobs the tests and the measurements need and nothing public offers.\n * @internal\n */\nexport interface ClosenessTuning {\n /** Levels recorded per submit on the level route (default `MAX_LEVELS_PER_SUBMIT`). */\n readonly levelsPerSubmit?: number | undefined;\n /** Words per node on the level route (default: as many as the sources need, at most `MAX_WORDS`). */\n readonly words?: number | undefined;\n /** The frontier arcs above which a level pulls (default `words x arcCount / PULL_RATIO`); 0 pulls whenever the frontier has an arc, `0xFFFFFFFF` never pulls. A graph with a node of more than `PULL_MAX_DEGREE` in-arcs never pulls. */\n readonly pullAt?: number | undefined;\n /** Force a route of an exact run (the all-pairs route still needs the matrix to fit). */\n readonly route?: ClosenessRoute | undefined;\n /** Called with the route the run takes. */\n readonly onRoute?: ((route: ClosenessRoute) => void) | undefined;\n /** Level route, exact run: after every batch, its first source, the exact sum of distances and the nodes reached of each of its sources. */\n readonly onBatch?: ((batchStart: number, sums: Float64Array, reached: Uint32Array) => void) | undefined;\n}\n\n/**\n * The most nodes an unweighted exact run sends to the all-pairs route: the blocked sweep's `n^3` work beats the level\n * route's `n / 256` batches of a full traversal only on small graphs. Measured on the RTX 4070 SUPER: a ring with\n * chords takes 2.7 ms on the all-pairs route against 3.5 to 4 ms on the level route at 1,024 nodes, 11 against 4.4\n * at 2,048 and 71 against 10 at 4,096; a graph with `n^2 / 12` arcs 0.9 against 1.4 at 512, 2.5 against 2.6 at\n * 1,024, 11 against 6 to 9 at 2,048 and 73 against 24 at 4,096. A deep sparse graph is the exception this does not\n * see: a 4,096-node path takes 70 ms on the all-pairs route and 0.7 s on the level route, one dispatch per level for\n * 4,095 levels.\n * @internal\n */\nexport const ALL_PAIRS_MAX_NODES = 1024;\n\n/**\n * The score of a sum: `1 / sum`, `0` when nothing was reached.\n * @param sum - the sum of distances\n * @returns the score\n */\nfunction inverse(sum: number): number {\n return sum === 0 ? 0 : 1 / sum;\n}\n\n/**\n * The one-search-per-source route: one `sssp` per source, the sums reduced on the host. With `sources` (a sampled run\n * on an undirected snapshot) each search adds its distances into the sums of the nodes it reaches instead of its own.\n * @param ctx - the context\n * @param s - the snapshot\n * @param scores - the destination\n * @param sources - a sampled run's sources, or null for every node\n * @param harmonic - sum reciprocal distances (exact runs only)\n * @param options - the run options\n * @returns the result\n */\nasync function perSourceRoute(\n ctx: GpuContext,\n s: GraphSnapshot,\n scores: F32,\n sources: readonly number[] | null,\n harmonic: boolean,\n options: GpuRunOptions | undefined,\n): Promise<GpuClosenessResult> {\n const n = s.nodeCount;\n const count = sources?.length ?? n;\n const totals = sources === null ? null : new Float64Array(n);\n for (let i = 0; i < count; i++) {\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM);\n }\n const source = sources === null ? i : sources[i];\n const { dist } = await sssp(ctx, s, source, { signal: options?.signal });\n let sum = 0;\n for (let v = 0; v < n; v++) {\n const d = dist[v];\n if (v !== source && d !== Infinity) {\n if (totals !== null) {\n totals[v] += d;\n } else if (!harmonic) {\n sum += d;\n } else if (d > 0) {\n sum += 1 / d;\n }\n }\n }\n if (totals === null) {\n scores[source] = harmonic ? sum : inverse(sum);\n }\n options?.onProgress?.(i + 1, count);\n }\n totals?.forEach((sum, v) => {\n scores[v] = inverse(sum);\n });\n return { scores, iterations: count, converged: true, precision: \"f32\", sourcesUsed: count };\n}\n\n/**\n * The all-pairs route (see the file comment). The caller checked that the matrix fits.\n * @param ctx - the context\n * @param s - the snapshot\n * @param scores - the destination\n * @param weighted - sum the weights, or count hops\n * @param harmonic - sum reciprocal distances\n * @param options - the run options\n * @returns the result\n */\nasync function allPairsRoute(\n ctx: GpuContext,\n s: GraphSnapshot,\n scores: F32,\n weighted: boolean,\n harmonic: boolean,\n options: GpuRunOptions | undefined,\n): Promise<GpuClosenessResult> {\n const n = s.nodeCount;\n const scope = algorithmScope(ctx, ALGORITHM, Math.min(DEFAULT_ROUNDS_PER_SUBMIT, Math.ceil(n / 32)) + 3);\n try {\n const matrix = await sweepAllPairs(\n ctx,\n s,\n scope,\n weighted,\n DEFAULT_ROUNDS_PER_SUBMIT,\n { signal: options?.signal },\n ALGORITHM,\n );\n const rowsum = await ctx.pipelines.kernel(kernelSpec(\"closeness-rowsum\"));\n const out = bindingOf(scope.scratch(4 * n, \"row-sums\"), 4 * n);\n const role = harmonic ? 2 : Number(weighted);\n const params = scope.params(CLOSENESS_PARAMS, { role, n });\n const batch = new CommandBatch(ctx, `${ALGORITHM}/row-sums`);\n rowsum.dispatch(\n batch.pass(\"row-sums\"),\n rowsum.bind({ dist: matrix, out, P: params.binding }),\n plan2d(n, ctx.caps),\n [params.offset],\n );\n batch.endPass();\n const request = batch.readback(out.buffer, out.offset, 4 * n);\n scope.flush();\n const back = await batch.submit().readback;\n ctx.assertReady();\n if (role === 0) {\n new Uint32Array(back, request.offset, n).forEach((sum, v) => {\n scores[v] = inverse(sum);\n });\n } else {\n new Float32Array(back, request.offset, n).forEach((sum, v) => {\n scores[v] = harmonic ? sum : inverse(sum);\n });\n }\n options?.onProgress?.(n, n);\n return { scores, iterations: 1, converged: true, precision: \"f32\", sourcesUsed: n };\n } finally {\n scope.dispose();\n }\n}\n\n/**\n * The level route (see the file comment).\n * @param ctx - the context\n * @param s - the snapshot\n * @param scores - the destination\n * @param sources - a sampled run's sources, or null for every node\n * @param harmonic - sum reciprocal distances (exact runs only)\n * @param levelsPerSubmit - the submit cadence\n * @param options - the run options\n * @param tuning - the knobs\n * @returns the result\n */\nasync function levelRoute(\n ctx: GpuContext,\n s: GraphSnapshot,\n scores: F32,\n sources: readonly number[] | null,\n harmonic: boolean,\n levelsPerSubmit: number,\n options: GpuRunOptions | undefined,\n tuning: ClosenessTuning,\n): Promise<GpuClosenessResult> {\n const n = s.nodeCount;\n const seedCount = sources?.length ?? n;\n if (seedCount === 0) {\n return { scores, iterations: 0, converged: true, precision: \"f32\", sourcesUsed: 0 };\n }\n const limit = Math.min(ctx.caps.limits.maxStorageBufferBindingSize, ctx.caps.limits.maxBufferSize);\n const core = ctx.residency.core(s);\n assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, ALGORITHM);\n if (s.directed && 4 * s.arcCount > limit) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: the reverse adjacency of a directed snapshot (${4 * s.arcCount} bytes) does not fit one binding`,\n { needed: 4 * s.arcCount, limit, path: \"closeness.reverse\", algorithm: ALGORITHM },\n );\n }\n const reverse = s.directed ? coreOfView(ctx.residency.view(s, \"reverse\"), s.arcCount) : core;\n // words per node: as many as the sources need, within one binding of four regions (plus a sampled run's per-node\n // sums) and, for a sampled run, so a node's per-batch distance sum (at most 32 words (n - 1)) fits a u32\n const extra = sources === null ? 0 : n;\n const fitWords = Math.floor((limit / 4 - extra) / (4 * n));\n const sumWords = sources === null ? MAX_WORDS : Math.floor(0xffffffff / (32 * Math.max(1, n - 1)));\n const words = tuning.words ?? Math.max(1, Math.min(MAX_WORDS, Math.ceil(seedCount / 32), fitWords, sumWords));\n if (!Number.isInteger(words) || words < 1 || words > MAX_WORDS) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: words must be an integer in [1, ${MAX_WORDS}]`,\n {\n argument: \"words\",\n value: words,\n expected: `an integer in [1, ${MAX_WORDS}]`,\n },\n );\n }\n const base = n * words;\n const bitsWords = 4 * base + extra;\n if (4 * bitsWords > limit) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: ${n} nodes need a ${4 * bitsWords}-byte search state in one binding of at most ${limit} bytes`,\n { needed: 4 * bitsWords, limit, path: \"closeness.bits\", algorithm: ALGORITHM },\n );\n }\n const lanes = 32 * words;\n const rowWords = levelsPerSubmit * lanes;\n const ctrl = rowWords;\n const sourcesAt = sources === null ? 0 : ctrl + CTRL_WORDS;\n const tableWords = ctrl + CTRL_WORDS + (sources?.length ?? 0);\n const pullAt = tuning.pullAt ?? Math.min(0xffffffff, Math.floor((words * s.arcCount) / PULL_RATIO));\n // slots: the row fill and the levels of one submit, plus the two seed records of a batch's first submit\n const scope = algorithmScope(ctx, ALGORITHM, levelsPerSubmit + 4);\n try {\n const wg = ctx.workgroupSize;\n const bits = bindingOf(scope.scratch(4 * bitsWords, \"bits\"), 4 * bitsWords);\n const table = bindingOf(scope.scratch(4 * tableWords, \"table\"), 4 * tableWords);\n const rows = { ...table, size: 4 * rowWords };\n if (sources !== null) {\n ctx.device.queue.writeBuffer(table.buffer, table.offset + 4 * sourcesAt, Uint32Array.from(sources));\n }\n await ctx.allocator.check();\n const level = await ctx.pipelines.kernel(kernelSpec(\"closeness-level\"));\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const state = {\n rowPtr: core.rowPtr,\n colIdx: core.colIdx ?? core.rowPtr,\n inRowPtr: reverse.rowPtr,\n inColIdx: reverse.colIdx ?? reverse.rowPtr,\n bits,\n table,\n };\n const levelPlan = plan1d(Math.max(n, s.arcCount), wg, ctx.caps);\n const pullOk = s.inDegree().every((d) => d <= PULL_MAX_DEGREE) ? 1 : 0;\n const totals = sources === null ? null : new Float64Array(n);\n const shared = {\n n,\n words,\n base,\n ctrl,\n pullAt,\n perNode: sources === null ? 0 : 1,\n sourcesAt,\n arcCount: s.arcCount,\n pullOk,\n };\n\n let batches = 0;\n for (let batchStart = 0; batchStart < seedCount; batchStart += lanes) {\n const count = Math.min(lanes, seedCount - batchStart);\n const sums = new Float64Array(count);\n const reciprocal = new Float64Array(count);\n const reached = new Uint32Array(count);\n for (let firstLevel = 0, done = false; !done; firstLevel += levelsPerSubmit) {\n if (firstLevel > n + 1) {\n // a batch claims at most n - 1 levels deep, then one level claims nothing\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: the batch at ${batchStart} still claimed at level ${firstLevel}`,\n { label: ALGORITHM, message: `the batch still claimed at level ${firstLevel}` },\n );\n }\n const batch = new CommandBatch(ctx, `${ALGORITHM}/levels`);\n const pass = batch.pass(\"closeness\");\n if (firstLevel === 0) {\n const clear = scope.params(CLOSENESS_PARAMS, { ...shared, role: 1, total: bitsWords, count });\n const bound = level.bind({ ...state, P: clear.binding });\n level.dispatch(pass, bound, plan1d(bitsWords, wg, ctx.caps), [clear.offset]);\n const seed = scope.params(CLOSENESS_PARAMS, { ...shared, role: 2, count, source: batchStart });\n level.dispatch(pass, bound, plan1d(count, wg, ctx.caps), [seed.offset]);\n }\n const zero = scope.params(FILL_PARAMS, { count: rowWords, value: 0, mode: 0, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst: rows, P: zero.binding }), plan1d(rowWords, wg, ctx.caps), [\n zero.offset,\n ]);\n let bound: ReturnType<typeof level.bind> | null = null;\n for (let row = 0; row < levelsPerSubmit; row++) {\n const params = scope.params(CLOSENESS_PARAMS, {\n ...shared,\n role: 0,\n count,\n level: firstLevel + row,\n row,\n });\n bound ??= level.bind({ ...state, P: params.binding });\n level.dispatch(pass, bound, levelPlan, [params.offset]);\n }\n batch.endPass();\n const rowRequest = batch.readback(table.buffer, table.offset, 4 * rowWords);\n const nodeRequest =\n totals === null ? null : batch.readback(bits.buffer, bits.offset + 16 * base, 4 * n);\n scope.flush();\n const submitted = batch.submit();\n const back = await submitted.readback;\n ctx.assertReady();\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM, submitted.id);\n }\n const counts = new Uint32Array(back, rowRequest.offset, rowWords);\n for (let row = 0; row < levelsPerSubmit && !done; row++) {\n const distance = firstLevel + row + 1;\n let claimed = 0;\n for (let lane = 0; lane < count; lane++) {\n const c = counts[row * lanes + lane];\n sums[lane] += c * distance;\n reciprocal[lane] += c / distance;\n reached[lane] += c;\n claimed += c;\n }\n done = claimed === 0;\n }\n if (done && totals !== null && nodeRequest !== null) {\n new Uint32Array(back, nodeRequest.offset, n).forEach((sum, v) => {\n totals[v] += sum;\n });\n }\n }\n if (sources === null) {\n for (let lane = 0; lane < count; lane++) {\n scores[batchStart + lane] = harmonic ? reciprocal[lane] : inverse(sums[lane]);\n }\n tuning.onBatch?.(batchStart, sums, reached);\n }\n batches += 1;\n options?.onProgress?.(batchStart + count, seedCount);\n }\n totals?.forEach((sum, v) => {\n scores[v] = inverse(sum);\n });\n return { scores, iterations: batches, converged: true, precision: \"f32\", sourcesUsed: seedCount };\n } finally {\n scope.dispose();\n }\n}\n\n/**\n * A sampled run's sources, checked: node indices of `s`, on an undirected snapshot only.\n * @param s - the snapshot\n * @param sources - the caller's list, or undefined for every node\n * @returns the list, or null for every node\n * @throws WebGpuGraphError E_INVALID_ARGUMENT for an index outside the snapshot, E_UNSUPPORTED on a directed snapshot\n */\nfunction checkSources(s: GraphSnapshot, sources: readonly number[] | undefined): readonly number[] | null {\n if (sources === undefined) {\n return null;\n }\n if (s.directed) {\n // a search FROM a source measures distance to the nodes it reaches, which is the distance FROM them to the\n // source only when every edge runs both ways\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: sampled sources need an undirected snapshot`, {\n feature: \"closenessCentrality.directedSources\",\n hint: \"run the CPU port, which searches the in-arcs\",\n });\n }\n for (const v of sources) {\n if (!Number.isInteger(v) || v < 0 || v >= s.nodeCount) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${ALGORITHM}: a source is not a node index`, {\n argument: \"sources\",\n value: v,\n expected: `an integer in [0, ${s.nodeCount})`,\n });\n }\n }\n return sources;\n}\n\n/**\n * Closeness with the test knobs; `closenessCentrality` is this with an empty tuning.\n * @internal\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - `weighted`, `harmonic` and a sampled run's `sources` honoured, the placeholder `maxIterations` / `tolerance` refused when defined, plus dest / signal / onProgress\n * @param tuning - the knobs\n * @returns the scores, the batches run, `converged: true`, `precision: \"f32\"` and `sourcesUsed`\n */\nexport async function closenessWithTuning(\n ctx: GpuContext,\n s: GraphSnapshot,\n options: (ClosenessAcceleratorOptions & HitsOptionsLike & GpuRunOptions) | undefined,\n tuning: ClosenessTuning,\n): Promise<GpuClosenessResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n for (const key of [\"maxIterations\", \"tolerance\"] as const) {\n if (options?.[key] !== undefined) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: ${key} has no meaning for an exact traversal`, {\n option: key,\n hint: \"closeness is an exact traversal; the option has no meaning here\",\n });\n }\n }\n const n = s.nodeCount;\n const sources = checkSources(s, options?.sources);\n const harmonic = options?.harmonic === true;\n if (harmonic && sources !== null) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: harmonic closeness from sampled sources`, {\n feature: \"closenessCentrality.sampledHarmonic\",\n hint: \"run the CPU port, or drop the sources for the exact harmonic score\",\n });\n }\n const levelsPerSubmit = tuning.levelsPerSubmit ?? MAX_LEVELS_PER_SUBMIT;\n if (!Number.isInteger(levelsPerSubmit) || levelsPerSubmit < 1 || levelsPerSubmit > MAX_LEVELS_PER_SUBMIT) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: levelsPerSubmit must be an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n {\n argument: \"levelsPerSubmit\",\n value: levelsPerSubmit,\n expected: `an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,\n },\n );\n }\n const scores = checkDest(ALGORITHM, options?.dest, n) ?? new Float32Array(n);\n const weighted = (options?.weighted ?? s.flags.weighted) && s.weights !== null && !s.flags.allWeightsOne;\n if (options?.signal?.aborted) {\n throw aborted(ALGORITHM);\n }\n if (weighted && !s.flags.nonNegativeWeights) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `${ALGORITHM}: a negative weight has no shortest-path distance to sum`,\n {\n feature: \"closenessCentrality.negativeWeights\",\n hint: \"pass weighted: false to ignore the column\",\n },\n );\n }\n if (weighted && !s.flags.finiteWeights) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: a NaN or infinite weight has no shortest path`, {\n feature: \"closenessCentrality.nonFiniteWeights\",\n });\n }\n const fits = n > 0 && n <= allPairsCeiling(ctx.caps.limits).maxNodes;\n let route: ClosenessRoute;\n if (sources !== null || !fits) {\n route = weighted ? \"per-source\" : \"levels\";\n } else {\n route = tuning.route ?? (weighted || n <= ALL_PAIRS_MAX_NODES ? \"all-pairs\" : \"levels\");\n }\n if (route === \"levels\" && weighted) {\n route = \"per-source\";\n }\n tuning.onRoute?.(route);\n if (route === \"all-pairs\") {\n return allPairsRoute(ctx, s, scores, weighted, harmonic, options);\n }\n if (route === \"per-source\") {\n return perSourceRoute(ctx, s, scores, sources, harmonic, options);\n }\n return levelRoute(ctx, s, scores, sources, harmonic, levelsPerSubmit, options, tuning);\n}\n\n/**\n * Closeness centrality on the device (spec 3.3 line 810, design 8.4, 9.7): `scores[s] = 1 / sumDist_s` over the finite\n * distances from `s` to every other node, `0` when nothing is reached -- the legacy default of `@graphty/algorithms`'\n * `closenessCentrality` -- or, with `harmonic`, the sum of `1 / dist` over the same nodes. Small and weighted\n * graphs whose all-pairs matrix fits one binding run the all-pairs sweep and a row sum; other unweighted graphs run a\n * bit-parallel multi-source search of up to 256 sources per batch; weighted graphs above the all-pairs ceiling run one\n * `sssp` per source. `weighted` defaults to the snapshot's flag, `maxIterations` / `tolerance` are refused when\n * defined. `iterations` is the source batches run and `converged` is always true.\n *\n * SAMPLED (`sources`, node indices, duplicates run twice; undirected snapshots only, E_UNSUPPORTED\n * `closenessCentrality.directedSources` otherwise; not with `harmonic`, E_UNSUPPORTED\n * `closenessCentrality.sampledHarmonic`): the batches seed the listed sources instead of every node, and each node's\n * score is `1 / sum` of its distances to the sources that reach it (itself excluded), `0` when none does: the sampled\n * score of the CPU port, unscaled. `sourcesUsed` is the list's length (`n` exact).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - `weighted`, `harmonic`, `sources`, plus dest (a Float32Array of length n for `scores`) / signal / onProgress\n * @returns the scores, the batches run, `converged: true`, `precision: \"f32\"` and `sourcesUsed`\n */\nexport function closenessCentrality(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: ClosenessAcceleratorOptions & HitsOptionsLike & GpuRunOptions,\n): Promise<GpuClosenessResult> {\n return closenessWithTuning(ctx, s, options, {});\n}\n","/**\n * Weakly connected components on the device (spec 8.3, 3.3): Afforest from GAP's cc.cc, step for step. `comp[v] = v`\n * by `fill` mode 1; two sampled link rounds over the r-th out-neighbour of every row plus a compress (one batch, no\n * readback); a 1,024-vertex label sample the host takes the mode of, which is the giant component (PD-12); then\n * each-edge-once link rounds over `edgeList()` -- correct for directed and undirected input alike, which is what\n * makes the partition the WEAK one -- in batches of four `link + compress` pairs, ONE readback of the changed flag per\n * batch, until the flag stays 0; a final compress; readback; `renumberPartition` on the host in first-seen order so\n * the labels are IDENTICAL to the CPU's (spec 9.7), or the raw roots when `renumber: false`.\n *\n * PLAN DECISION PD-4: the changed flag is the word at `comp[n]`, so the link kernels bind three buffers (design 8.10).\n * PLAN DECISION PD-11: `E_PARTITION` is NOT a pass-through. The kernels only ever store a value read out of `comp`,\n * which `fill` seeded with `v < n`, so no label can be `INVALID_INDEX`; the host verifies every label is `< n` before\n * `renumberPartition` sees it and raises `E_VALIDATION { label: \"connectedComponents/labels\" }` if that ever fails --\n * it would mean a GPU bug, which no caller could act on as `E_PARTITION`.\n * DEP-M8B-C: no `dedupe` primitive; Afforest's link is idempotent, so a repeated edge is a no-op.\n */\n\nimport { type GraphSnapshot, renumberPartition, type U32 } from \"@graphty/graph-format\";\n\nimport { U32_MAX } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { FILL_PARAMS, graphBindings, graphOverrides, kernelSpec, WCC_PARAMS } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { assertWholeCore } from \"../primitives/core-shape.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type ComponentsOptions, type GpuLabelResult } from \"../types/algorithms.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { algorithmScope } from \"./scope.js\";\n\nconst ALGORITHM = \"connectedComponents\";\n/** Link rounds between two reads of the changed flag (design 8.3: \"checked every 4 rounds\"). */\nconst ROUNDS_PER_BATCH = 4;\n/** The edge-round cap; the flag not settling by then is a hard error, never a fallback. */\nconst MAX_WCC_ROUNDS = 64;\n/** The sampled vertices the giant component is found from (design 8.3). */\nconst SAMPLE_SIZE = 1024;\n/** The bound of a CAS retry loop and of a compress walk (PD-5). */\nconst MAX_STEPS = 1024;\n/** Params slots of the largest batch: four link + four compress blocks; the setup batch uses fill + 2 links + compress. */\nconst RING_SLOTS = 2 * ROUNDS_PER_BATCH;\n\n/**\n * Validates `options.dest` for a label result of `n` elements.\n * @param dest - the caller's destination array, if any\n * @param n - the node count\n * @returns the destination as a U32, or null when none was given\n */\nfunction checkDest(dest: Float32Array | Uint32Array | undefined, n: number): U32 | null {\n if (dest === undefined) {\n return null;\n }\n if (dest instanceof Uint32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {\n return dest as U32;\n }\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: dest must be a Uint32Array of length ${n} over an ArrayBuffer`,\n {\n argument: \"dest\",\n value: `${dest.constructor.name}(${dest.length})`,\n expected: `Uint32Array(${n}) over an ArrayBuffer`,\n },\n );\n}\n\n/**\n * The resident core; a windowed plan is refused with `E_TOO_LARGE { path: \"windowed\", algorithm }` (spec 3.8, 3.12;\n * DEP-P4-B: only degree and segmentedReduce execute windows).\n * @param ctx - the context\n * @param s - the snapshot\n * @returns the core binding\n */\nfunction coreOf(ctx: GpuContext, s: GraphSnapshot): CoreBinding {\n const core = ctx.residency.core(s);\n assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, ALGORITHM);\n return core;\n}\n\n/**\n * Whole-buffer binding of a scratch buffer over its first `size` bytes.\n * @param buffer - the buffer\n * @param size - the bound byte length\n * @returns the binding\n */\nfunction bindingOf(buffer: GPUBuffer, size: number): Binding {\n return { buffer, offset: 0, size, window: null };\n}\n\n/**\n * The result object over a label array whose labels are all `< n`: `count` blocks, `groups()` built lazily once in\n * first-seen label order (which for renumbered labels is index order). Shared with label propagation.\n * @param labels - the labels\n * @param count - the block count\n * @returns the result\n */\nexport function labelResult(labels: U32, count: number): GpuLabelResult {\n let groups: U32[] | null = null;\n return {\n labels,\n count,\n groups(): U32[] {\n if (groups !== null) {\n return groups;\n }\n const n = labels.length;\n const dense = new Uint32Array(n).fill(U32_MAX);\n const sizes = new Uint32Array(count);\n let next = 0;\n for (let v = 0; v < n; v++) {\n let k = dense[labels[v]];\n if (k === U32_MAX) {\n k = next++;\n dense[labels[v]] = k;\n }\n sizes[k]++;\n }\n const built: U32[] = Array.from(sizes, (size) => new Uint32Array(size));\n const filled = new Uint32Array(count);\n for (let v = 0; v < n; v++) {\n const k = dense[labels[v]];\n built[k][filled[k]++] = v;\n }\n groups = built;\n return built;\n },\n };\n}\n\n/**\n * The mode of the sampled labels (GAP's SampleFrequentElement, counted on the host; PD-12).\n * @param sample - the sampled labels\n * @returns the most frequent label\n */\nfunction modeOf(sample: Uint32Array): number {\n const counts = new Map<number, number>();\n let best = sample[0];\n let bestCount = 0;\n for (const label of sample) {\n const c = (counts.get(label) ?? 0) + 1;\n counts.set(label, c);\n if (c > bestCount) {\n best = label;\n bestCount = c;\n }\n }\n return best;\n}\n\n/**\n * Verifies every label is a node index (so `renumberPartition` can never see `INVALID_INDEX`, PD-11) and counts the\n * distinct roots.\n * @param raw - the labels the device produced\n * @returns the number of distinct labels\n */\nfunction checkLabels(raw: U32): number {\n const n = raw.length;\n const seen = new Uint8Array(n);\n let count = 0;\n for (let v = 0; v < n; v++) {\n const label = raw[v];\n if (label >= n) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: labels[${v}] = ${label} is not a node index`, {\n label: `${ALGORITHM}/labels`,\n message: `the device produced a label outside [0, ${n})`,\n });\n }\n if (seen[label] === 0) {\n seen[label] = 1;\n count++;\n }\n }\n return count;\n}\n\n/**\n * Weakly connected components on the device (spec 3.3, 8.3): Afforest over the resident core and the edge list;\n * labels dense in first-seen order (`renumber: true`, the default) or the raw roots (`renumber: false`).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - renumber (default true), plus dest / signal / onProgress\n * @returns the labels, the component count and groups()\n */\nexport async function connectedComponents(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: ComponentsOptions & GpuRunOptions,\n): Promise<GpuLabelResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const n = s.nodeCount;\n const renumber = options?.renumber !== false;\n const dest = checkDest(options?.dest, n);\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted before any work started`, {});\n }\n if (n === 0) {\n options?.onProgress?.(1, 1);\n return labelResult(dest ?? new Uint32Array(0), 0);\n }\n const core = coreOf(ctx, s);\n if (s.arcCount === 0) {\n // every node is its own block, and the identity is already first-seen dense: renumbered and raw agree\n const labels = dest ?? new Uint32Array(n);\n for (let v = 0; v < n; v++) {\n labels[v] = v;\n }\n options?.onProgress?.(1, 1);\n return labelResult(labels, n);\n }\n const edges = ctx.residency.view(s, \"edgeList\");\n const edgeCount = edges.scalars.edgeCount[0];\n const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);\n try {\n const compBytes = 4 * (n + 1);\n const comp = scope.scratch(compBytes, \"comp\");\n const items = Math.min(SAMPLE_SIZE, n);\n const hist = scope.scratch(4 * items, \"hist\");\n await ctx.allocator.check();\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\", {}));\n const linkSample = await ctx.pipelines.kernel(kernelSpec(\"wcc-link-sample\", graphOverrides(core, null)));\n const linkEdges = await ctx.pipelines.kernel(kernelSpec(\"wcc-link-edges\", {}));\n const compress = await ctx.pipelines.kernel(kernelSpec(\"wcc-compress\", {}));\n const sample = await ctx.pipelines.kernel(kernelSpec(\"wcc-sample\", {}));\n const { queue } = ctx.device;\n const compBinding = bindingOf(comp, compBytes);\n const histBinding = bindingOf(hist, 4 * items);\n const rowPlan = planGridStride(n, ctx.workgroupSize, ctx.caps);\n const edgePlan = planGridStride(edgeCount, ctx.workgroupSize, ctx.caps);\n const flagIndex = n;\n const zero = new Uint32Array(1);\n const wccParams = (fields: {\n items: number;\n stride: number;\n r: number;\n giant: number;\n }): { binding: Binding; offset: number } =>\n scope.params(WCC_PARAMS, { n, ...fields, flagIndex, maxSteps: MAX_STEPS, pad0: 0 });\n const recordCompress = (pass: GPUComputePassEncoder): void => {\n const params = wccParams({ items: n, stride: rowPlan.stride ?? n, r: 0, giant: U32_MAX });\n compress.dispatch(pass, compress.bind({ comp: compBinding, P: params.binding }), rowPlan, [params.offset]);\n };\n const submit = (batch: CommandBatch): ReturnType<CommandBatch[\"submit\"]> => {\n scope.flush();\n return batch.submit();\n };\n\n // batch 1: comp[v] = v, the flag cleared, two sampled link rounds over the r-th out-neighbour, one compress\n queue.writeBuffer(comp, 4 * flagIndex, zero);\n const setup = new CommandBatch(ctx, `${ALGORITHM}/setup`);\n let pass = setup.pass(\"sample-rounds\");\n const fillParams = scope.params(FILL_PARAMS, { count: n, value: 0, mode: 1, pad0: 0 });\n fill.dispatch(\n pass,\n fill.bind({ dst: bindingOf(comp, 4 * n), P: fillParams.binding }),\n plan1d(n, ctx.workgroupSize, ctx.caps),\n [fillParams.offset],\n );\n const graph = graphBindings(core, null);\n for (let r = 0; r < 2; r++) {\n const params = wccParams({ items: n, stride: rowPlan.stride ?? n, r, giant: U32_MAX });\n const bound = linkSample.bind({ ...graph, comp: compBinding, P: params.binding });\n linkSample.dispatch(pass, bound, rowPlan, [params.offset]);\n }\n recordCompress(pass);\n setup.endPass();\n await submit(setup).readback;\n ctx.assertReady();\n\n // batch 2: the label sample, whose mode is the giant component\n const sampler = new CommandBatch(ctx, `${ALGORITHM}/sample`);\n pass = sampler.pass(\"sample\");\n const sampleParams = wccParams({ items, stride: 0, r: 0, giant: U32_MAX });\n sample.dispatch(\n pass,\n sample.bind({ comp: compBinding, hist: histBinding, P: sampleParams.binding }),\n plan1d(items, ctx.workgroupSize, ctx.caps),\n [sampleParams.offset],\n );\n sampler.endPass();\n const histRequest = sampler.readback(hist, 0, 4 * items);\n const histBytes = await submit(sampler).readback;\n ctx.assertReady();\n const giant = modeOf(new Uint32Array(histBytes, histRequest.offset, items));\n\n // the edge rounds: four (link + compress) per batch, one readback of the changed flag per batch\n const edgeBindings = { edgeSrc: edges.bindings.src, edgeDst: edges.bindings.dst, comp: compBinding };\n let rounds = 0;\n for (;;) {\n queue.writeBuffer(comp, 4 * flagIndex, zero);\n const batch = new CommandBatch(ctx, `${ALGORITHM}/rounds`);\n pass = batch.pass(\"edge-rounds\");\n for (let i = 0; i < ROUNDS_PER_BATCH; i++) {\n const params = wccParams({ items: edgeCount, stride: edgePlan.stride ?? edgeCount, r: 0, giant });\n const bound = linkEdges.bind({ ...edgeBindings, P: params.binding });\n linkEdges.dispatch(pass, bound, edgePlan, [params.offset]);\n recordCompress(pass);\n }\n batch.endPass();\n const flagRequest = batch.readback(comp, 4 * flagIndex, 4);\n const submitted = submit(batch);\n const back = await submitted.readback;\n rounds += ROUNDS_PER_BATCH;\n ctx.assertReady();\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted`, {\n batchId: submitted.id,\n });\n }\n if (new Uint32Array(back, flagRequest.offset, 1)[0] === 0) {\n break;\n }\n if (rounds >= MAX_WCC_ROUNDS) {\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: the changed flag never settled in ${MAX_WCC_ROUNDS} rounds`,\n { label: ALGORITHM, message: `the changed flag never settled in ${MAX_WCC_ROUNDS} rounds` },\n );\n }\n }\n\n // the final compress, then the labels\n const final = new CommandBatch(ctx, `${ALGORITHM}/final`);\n recordCompress(final.pass(\"compress\"));\n final.endPass();\n await submit(final).readback;\n ctx.assertReady();\n const raw = !renumber && dest !== null ? dest : new Uint32Array(n);\n await ctx.readback.read(comp, 4 * n, raw);\n ctx.assertReady();\n const distinct = checkLabels(raw);\n options?.onProgress?.(1, 1);\n if (!renumber) {\n return labelResult(raw, distinct);\n }\n const { labels, count } = renumberPartition(raw, dest ?? undefined);\n return labelResult(labels, count);\n } finally {\n scope.dispose();\n }\n}\n","/**\n * The per-row group-by-key primitive (design 8.6; the P11 plan's PD-8): for every row `v` of a CSR graph, group the\n * row's arcs by the key of their target (`keyIn[colIdx[a]]`), sum the weights per key, and write the key with the\n * largest sum to `bestKey[v]` -- the LOWEST such key on a tie, which makes the answer independent of the visiting\n * order -- and its summed weight to `bestScore[v]`. An empty row gets `INVALID_INDEX` and 0. Label propagation's step\n * is its first caller: the best key of a row is the weighted mode of the neighbours' labels.\n *\n * Sums are u32 fixed point at a per-row power-of-two scale (the kernel header says how), so the two tiers and any\n * reference that follows the same arithmetic agree bitwise. A key must be below `INVALID_INDEX`.\n *\n * Two tiers, chosen per row on the host from an upper bound of each row's length (`planGroupRows`):\n * - TIER 0, a thread per row, for rows of at most `threadMax` arcs (GROUP_ROW_THREAD_MAX by default): a pairwise scan\n * in registers, no workgroup memory, no barrier.\n * - TIER 1, a workgroup per row, for the rest: the row's keys are hashed into its own region of\n * `GROUP_HASH_LOAD_FACTOR x length` slots of `hashRegion`, then the workgroup reduces the slots to the best one.\n *\n * PLAN DECISION (the P11 plan, PD-8): the plan's small tier sorted a row of up to 256 arcs in workgroup memory with a\n * bitonic sort, one workgroup per row; this tier is a thread per row instead, because a workgroup of 256 lanes spent\n * on a row of ten arcs -- the typical row -- idles 246 of them, and the pairwise scan needs no barrier at all. Rows\n * above GROUP_ROW_THREAD_MAX take the workgroup hash tier, which is the plan's large tier unchanged.\n */\n\nimport { GROUP_HASH_LOAD_FACTOR, GROUP_ROW_THREAD_LIMIT, GROUP_ROW_THREAD_MAX } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d, plan2d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { GROUP_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ReduceScope } from \"./reduce.js\";\n\n/**\n * The rows of each tier, as the host planned them: upload `words` into the `rows` binding and size `hashRegion` by `regionWords`.\n * @public\n */\nexport interface GroupRows {\n /** The thread tier's rows, then the workgroup tier's rows, then each workgroup-tier row's region offset (in words of `hashRegion`). */\n readonly words: Uint32Array<ArrayBuffer>;\n readonly threadCount: number;\n readonly hashCount: number;\n /** The words of `hashRegion`: word 0 is the exhausted flag, then two words (key, sum) per slot of every workgroup-tier row. */\n readonly regionWords: number;\n}\n\n/**\n * Splits the rows into the two tiers from an upper bound of every row's length (the exact length works too; a bound\n * only costs region space): rows whose bound is at most `threadMax` go to the thread tier, the rest to the workgroup\n * tier with `GROUP_HASH_LOAD_FACTOR x bound` slots each.\n * @param lengthBound - an upper bound of every row's arc count, one per row\n * @param threadMax - the longest row the thread tier takes (0 sends every row to the workgroup tier; at most GROUP_ROW_THREAD_LIMIT)\n * @returns the plan\n */\nexport function planGroupRows(lengthBound: ArrayLike<number>, threadMax: number = GROUP_ROW_THREAD_MAX): GroupRows {\n if (!Number.isInteger(threadMax) || threadMax < 0 || threadMax > GROUP_ROW_THREAD_LIMIT) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `planGroupRows: threadMax must be an integer in [0, ${GROUP_ROW_THREAD_LIMIT}]`,\n { argument: \"threadMax\", value: threadMax, expected: `[0, ${GROUP_ROW_THREAD_LIMIT}]` },\n );\n }\n const n = lengthBound.length;\n const thread: number[] = [];\n const hash: number[] = [];\n for (let v = 0; v < n; v++) {\n (lengthBound[v] <= threadMax ? thread : hash).push(v);\n }\n const words = new Uint32Array(thread.length + 2 * hash.length);\n words.set(thread, 0);\n words.set(hash, thread.length);\n let next = 1;\n for (let g = 0; g < hash.length; g++) {\n words[thread.length + hash.length + g] = next;\n next += 2 * GROUP_HASH_LOAD_FACTOR * lengthBound[hash[g]];\n }\n return { words, threadCount: thread.length, hashCount: hash.length, regionWords: next };\n}\n\n/**\n * One grouping over a graph.\n * @public\n */\nexport interface GroupByKeyRecord {\n readonly rowPtr: Binding;\n readonly colIdx: Binding;\n /** One f32 per arc, or null (every arc weighs 1). */\n readonly weights: Binding | null;\n /** One key per node, each below `INVALID_INDEX`. */\n readonly keyIn: Binding;\n /** The plan's counts; its `words` must be what `rows` holds. */\n readonly plan: GroupRows;\n readonly rows: Binding;\n /** At least `plan.regionWords` words; word 0 must be zeroed by the caller once, and is 1 afterwards iff a probe loop exhausted its bound. */\n readonly hashRegion: Binding;\n readonly bestKey: Binding;\n readonly bestScore: Binding;\n}\n\n/**\n * A prepared group-by-key.\n * @public\n */\nexport interface GroupByKeyPlanner {\n /**\n * Records the (up to two) tier dispatches of one grouping into the pass.\n * @param pass - the compute pass\n * @param record - the graph, the keys, the tier plan and the outputs\n */\n record(pass: GPUComputePassEncoder, record: GroupByKeyRecord): void;\n}\n\n/**\n * Compiles the four variants (two tiers, weighted or not) so record() is synchronous.\n * @param scope - the caller's scope\n * @returns the planner\n */\nexport async function prepareGroupByKeyRow(scope: ReduceScope): Promise<GroupByKeyPlanner> {\n const kernels = new Map<string, Kernel>();\n for (const tier of [0, 1]) {\n for (const weighted of [false, true]) {\n const spec = kernelSpec(\"group-by-key-row\", { TIER: tier, WEIGHTED: weighted });\n kernels.set(`${tier}/${weighted}`, await scope.pipelines.kernel(spec));\n }\n }\n return new GroupByKeyPlannerImpl(scope, kernels);\n}\n\n/**\n * The E_INVALID_ARGUMENT of a binding shorter than `words` u32.\n * @param name - the argument name\n * @param binding - the binding\n * @param words - the words it must hold\n */\nfunction checkWords(name: string, binding: Binding, words: number): void {\n if (binding.size < 4 * words) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `groupByKeyRow: ${name} is smaller than 4 x ${words} bytes`, {\n argument: name,\n value: binding.size,\n expected: 4 * words,\n });\n }\n}\n\n/** The planner: the four variants over one scope. */\nclass GroupByKeyPlannerImpl implements GroupByKeyPlanner {\n private readonly scope: ReduceScope;\n private readonly kernels: ReadonlyMap<string, Kernel>;\n\n /**\n * Wraps the compiled variants; use prepareGroupByKeyRow().\n * @param scope - the caller's scope\n * @param kernels - the variants by `tier/weighted`\n */\n constructor(scope: ReduceScope, kernels: ReadonlyMap<string, Kernel>) {\n this.scope = scope;\n this.kernels = kernels;\n }\n\n /**\n * Records the tier dispatches (see the interface).\n * @param pass - the compute pass\n * @param r - the record\n */\n record(pass: GPUComputePassEncoder, r: GroupByKeyRecord): void {\n const { threadCount, hashCount } = r.plan;\n const rows = threadCount + hashCount;\n checkWords(\"rows\", r.rows, rows + hashCount);\n checkWords(\"hashRegion\", r.hashRegion, r.plan.regionWords);\n checkWords(\"rowPtr\", r.rowPtr, rows + 1);\n if (rows === 0) {\n return;\n }\n const weighted = r.weights !== null;\n const tiers: readonly (readonly [0 | 1, number, number])[] = [\n [0, 0, threadCount],\n [1, threadCount, hashCount],\n ];\n for (const [tier, rowsBase, count] of tiers) {\n if (count === 0) {\n continue;\n }\n const kernel = this.kernels.get(`${tier}/${weighted}`);\n if (kernel === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"groupByKeyRow: no variant was prepared\", {\n argument: \"tier\",\n value: tier,\n });\n }\n const params = this.scope.params(GROUP_PARAMS, {\n rowsBase,\n basesBase: threadCount + hashCount,\n count,\n pad0: 0,\n });\n const bound = kernel.bind({\n rowPtr: r.rowPtr,\n colIdx: r.colIdx,\n weights: r.weights ?? r.colIdx,\n keyIn: r.keyIn,\n rows: r.rows,\n hashRegion: r.hashRegion,\n bestKey: r.bestKey,\n bestScore: r.bestScore,\n P: params.binding,\n });\n const plan =\n tier === 0 ? plan1d(count, this.scope.workgroupSize, this.scope.caps) : plan2d(count, this.scope.caps);\n kernel.dispatch(pass, bound, plan, [params.offset]);\n }\n }\n}\n","/**\n * The `histogram` and `countingSortByKey` primitive drivers (spec 6 row 5; P4-T3, PD-4). `histogram` zeroes `hist`\n * with a `fill` dispatch and then adds one per key in global memory: order-independent, so bitwise deterministic on\n * every adapter. `countingSortByKey` is the histogram, an exclusive scan of it into `outStart`, a zeroed per-bin\n * `cursor`, and the scatter `outIndex[outStart[k] + atomicAdd(&cursor[k], 1)] = i`: the SET of indices inside a bin\n * is fixed, their order follows the schedule (set-deterministic, design 6). Every zeroing is a dispatch inside the\n * caller's pass (PD-12), never an encoder clear.\n *\n * The drivers own no device objects: the caller supplies a ReduceScope (the same record `reduce` takes) and the\n * compute pass to record into. `src/primitives/**` never imports `src/context.ts`.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { FILL_PARAMS, HIST_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ReduceScope } from \"./reduce.js\";\nimport { prepareScan, type ScanPlanner } from \"./scan.js\";\n\n/** A prepared histogram (spec 6 row 5): records the fill and the one counting dispatch into a pass. */\nexport interface HistogramPlanner {\n /**\n * Records the histogram of `count` u32 keys of `keys` over `bins` bins into `hist` (zeroed first by a `fill`\n * dispatch); a key >= bins is not counted. For count 0 only the fill is recorded, so `hist` is all zero.\n * @param pass - the compute pass\n * @param keys - the keys (at least 4 x count bytes)\n * @param count - the key count (a non-negative integer below 2^32)\n * @param bins - the bin count (an integer in [1, 2^32))\n * @param hist - the counts (at least 4 x bins bytes)\n */\n record(pass: GPUComputePassEncoder, keys: Binding, count: number, bins: number, hist: Binding): void;\n /** Dispatches the last record() issued: 1 (the fill) for count 0, else 2. */\n readonly lastDispatches: number;\n}\n\n/** The two per-bin scratch arrays of a counting sort: the histogram and the scatter cursor, each at least 4 x bins bytes. */\ninterface CountingSortScratch {\n readonly hist: Binding;\n readonly cursor: Binding;\n}\n\n/** A prepared counting sort by key (spec 6 row 5): records the histogram, the scan, the cursor fill and the scatter into a pass. */\nexport interface CountingSortPlanner {\n /**\n * Records the counting sort of `count` keys of `keys` (every key < bins) into `outIndex` (the indices in key\n * order; the order inside a bin follows the schedule) and `outStart` (the exclusive scan of the histogram, so bin\n * k holds `outIndex[outStart[k] .. outStart[k + 1])` when outStart has bins + 1 words, as the grid's does).\n * For count 0 the two fills and the scan run and `outStart` is all zero.\n * @param pass - the compute pass\n * @param keys - the keys (at least 4 x count bytes)\n * @param count - the key count (a non-negative integer below 2^32)\n * @param bins - the bin count (an integer in [1, 2^32))\n * @param scratch - the per-bin histogram and cursor (each at least 4 x bins bytes)\n * @param outIndex - the sorted indices (at least 4 x count bytes)\n * @param outStart - the bin starts (at least 4 x bins bytes)\n */\n record(\n pass: GPUComputePassEncoder,\n keys: Binding,\n count: number,\n bins: number,\n scratch: CountingSortScratch,\n outIndex: Binding,\n outStart: Binding,\n ): void;\n /** Dispatches the last record() issued: the histogram's + the scan's + 1 (the cursor fill) + 1 (the scatter, count > 0 only). */\n readonly lastDispatches: number;\n}\n\n/** The largest u32: the largest value `HistParams.count` / `bins` can carry. */\nconst U32_MAX = 0xffffffff;\n\n/**\n * Prepares the histogram pipelines of a scope (compiles `histogram` and `fill` once) so record() is synchronous.\n * @param scope - the caller's scope (device, caps, cache, scratch, params)\n * @returns the planner\n */\nexport async function prepareHistogram(scope: ReduceScope): Promise<HistogramPlanner> {\n return prepareHistogramImpl(scope);\n}\n\n/**\n * The concrete histogram planner (its recordZero is what the counting sort reuses for the cursor).\n * @param scope - the caller's scope\n * @returns the planner\n */\nasync function prepareHistogramImpl(scope: ReduceScope): Promise<HistogramPlannerImpl> {\n const histogram = await scope.pipelines.kernel(kernelSpec(\"histogram\"));\n const fill = await scope.pipelines.kernel(kernelSpec(\"fill\"));\n return new HistogramPlannerImpl(scope, histogram, fill);\n}\n\n/**\n * Prepares the counting-sort pipelines of a scope (the histogram's, the scan's and `counting-scatter`) so record()\n * is synchronous. The planner lives exactly as long as the scope (the scan keeps a scratch word of it).\n * @param scope - the caller's scope\n * @returns the planner\n */\nexport async function prepareCountingSort(scope: ReduceScope): Promise<CountingSortPlanner> {\n const histogram = await prepareHistogramImpl(scope);\n const scan = await prepareScan(scope);\n const scatter = await scope.pipelines.kernel(kernelSpec(\"counting-scatter\"));\n return new CountingSortPlannerImpl(scope, histogram, scan, scatter);\n}\n\n/**\n * The E_INVALID_ARGUMENT of a binding shorter than `words` u32.\n * @param name - the argument name\n * @param binding - the binding\n * @param words - the words it must hold\n */\nfunction checkWords(name: string, binding: Binding, words: number): void {\n if (binding.size < 4 * words) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `histogram: ${name} is smaller than 4 x ${words} bytes`, {\n argument: name,\n value: binding.size,\n expected: 4 * words,\n });\n }\n}\n\n/**\n * The argument checks shared by both record() methods (E_INVALID_ARGUMENT before anything is recorded).\n * @param keys - the keys binding\n * @param count - the key count\n * @param bins - the bin count\n * @param hist - the histogram binding\n */\nfunction checkHistogramArguments(keys: Binding, count: number, bins: number, hist: Binding): void {\n if (!Number.isSafeInteger(count) || count < 0 || count > U32_MAX) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"histogram: count must be a non-negative integer below 2^32\", {\n argument: \"count\",\n value: count,\n });\n }\n if (!Number.isSafeInteger(bins) || bins < 1 || bins > U32_MAX) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"histogram: bins must be an integer in [1, 2^32)\", {\n argument: \"bins\",\n value: bins,\n });\n }\n checkWords(\"keys\", keys, count);\n checkWords(\"hist\", hist, bins);\n}\n\n/** The planner: the histogram and fill kernels over one scope. */\nclass HistogramPlannerImpl implements HistogramPlanner {\n private readonly scope: ReduceScope;\n private readonly histogram: Kernel;\n private readonly fill: Kernel;\n private dispatches = 0;\n\n /**\n * Wraps the resolved kernels; use prepareHistogram().\n * @param scope - the caller's scope\n * @param histogram - the `histogram` kernel\n * @param fill - the `fill` kernel\n */\n constructor(scope: ReduceScope, histogram: Kernel, fill: Kernel) {\n this.scope = scope;\n this.histogram = histogram;\n this.fill = fill;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns the count\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the fill and the histogram (see the interface).\n * @param pass - the compute pass\n * @param keys - the keys\n * @param count - the key count\n * @param bins - the bin count\n * @param hist - the counts\n */\n record(pass: GPUComputePassEncoder, keys: Binding, count: number, bins: number, hist: Binding): void {\n checkHistogramArguments(keys, count, bins, hist);\n this.recordZero(pass, hist, bins);\n this.dispatches = 1;\n if (count === 0) {\n return;\n }\n const params = this.scope.params(HIST_PARAMS, { count, bins, pad0: 0, pad1: 0 });\n const bound = this.histogram.bind({ keys, hist, P: params.binding });\n this.histogram.dispatch(pass, bound, plan1d(count, this.scope.workgroupSize, this.scope.caps), [params.offset]);\n this.dispatches = 2;\n }\n\n /**\n * Records a `fill` of `words` zeros into `dst` (PD-12: a dispatch inside the pass, never an encoder clear).\n * @param pass - the compute pass\n * @param dst - the words to zero\n * @param words - how many (>= 1)\n */\n recordZero(pass: GPUComputePassEncoder, dst: Binding, words: number): void {\n const params = this.scope.params(FILL_PARAMS, { count: words, value: 0, mode: 0, pad0: 0 });\n const bound = this.fill.bind({ dst, P: params.binding });\n this.fill.dispatch(pass, bound, plan1d(words, this.scope.workgroupSize, this.scope.caps), [params.offset]);\n }\n}\n\n/** The planner: the histogram planner, the scan planner and the scatter kernel over one scope. */\nclass CountingSortPlannerImpl implements CountingSortPlanner {\n private readonly scope: ReduceScope;\n private readonly histogram: HistogramPlannerImpl;\n private readonly scan: ScanPlanner;\n private readonly scatter: Kernel;\n private dispatches = 0;\n\n /**\n * Wraps the resolved planners and kernel; use prepareCountingSort().\n * @param scope - the caller's scope\n * @param histogram - the histogram planner (also the zeroing of the cursor)\n * @param scan - the scan planner\n * @param scatter - the `counting-scatter` kernel\n */\n constructor(scope: ReduceScope, histogram: HistogramPlannerImpl, scan: ScanPlanner, scatter: Kernel) {\n this.scope = scope;\n this.histogram = histogram;\n this.scan = scan;\n this.scatter = scatter;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns the count\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the four stages (see the interface).\n * @param pass - the compute pass\n * @param keys - the keys\n * @param count - the key count\n * @param bins - the bin count\n * @param scratch - the histogram and cursor\n * @param outIndex - the sorted indices\n * @param outStart - the bin starts\n */\n record(\n pass: GPUComputePassEncoder,\n keys: Binding,\n count: number,\n bins: number,\n scratch: CountingSortScratch,\n outIndex: Binding,\n outStart: Binding,\n ): void {\n checkHistogramArguments(keys, count, bins, scratch.hist);\n checkWords(\"cursor\", scratch.cursor, bins);\n checkWords(\"outIndex\", outIndex, count);\n checkWords(\"outStart\", outStart, bins);\n this.histogram.record(pass, keys, count, bins, scratch.hist);\n this.scan.record(pass, scratch.hist, bins, outStart);\n this.histogram.recordZero(pass, scratch.cursor, bins);\n this.dispatches = this.histogram.lastDispatches + this.scan.lastDispatches + 1;\n if (count === 0) {\n return;\n }\n const params = this.scope.params(HIST_PARAMS, { count, bins, pad0: 0, pad1: 0 });\n const bound = this.scatter.bind({ keys, start: outStart, cursor: scratch.cursor, outIndex, P: params.binding });\n this.scatter.dispatch(pass, bound, plan1d(count, this.scope.workgroupSize, this.scope.caps), [params.offset]);\n this.dispatches += 1;\n }\n}\n","/**\n * The `cooToCsr` primitive driver (design 6 row 10; the P11 plan's PD-1): compressed sparse rows built on the device\n * from `count` arcs `(src[i], dst[i], weights[i])` over `n` nodes. It is the histogram of the sources (over `n + 1`\n * bins, so the last word is 0), their exclusive scan into `rowPtr` (so `rowPtr[n]` is the arc count) and the\n * `coo-scatter` of the targets and weights into `colIdx` and `outWeights`.\n *\n * The scatter has two modes, and they promise different things:\n * - `sortedInput: false` is design 6 row 10's cursor scatter. Each arc reserves its slot with an atomic on its row's\n * cursor, so slots go out in race order: `rowPtr` is deterministic, but the order inside a row is not, and a row is\n * NOT sorted by target even when the input was.\n * - `sortedInput: true` requires the arcs ordered by source and writes each at its own index minus its row's start:\n * no cursor, no atomic, the input order survives into every row, and the output is a pure function of the input.\n * Arcs sorted by (source, target) therefore give rows sorted by target -- which every intersection relies on. The\n * precondition is checked on the device: an out-of-order source raises word 0 of `out.flag`, which the caller\n * must read back and refuse, because unsorted input in this mode gives rows that are silently scrambled.\n *\n * A caller who passes unsorted arcs with `sortedInput: true`, or sorted arcs with `sortedInput: false`, and needs\n * sorted rows gets a graph whose rows are not sorted and whose triangle intersection is then silently wrong.\n *\n * A planner over a ReduceScope with a synchronous `record` (the shape of every primitive here), not the design's free\n * function: pipelines compile once in `prepareCooToCsr`, and `src/primitives/**` never imports `src/context.ts`.\n */\n\nimport { U32_MAX } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { COO_PARAMS, FILL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type HistogramPlanner, prepareHistogram } from \"./histogram.js\";\nimport { type ReduceScope } from \"./reduce.js\";\nimport { prepareScan, type ScanPlanner } from \"./scan.js\";\n\n/**\n * The graph `record` writes.\n * @public\n */\nexport interface CooToCsrOutput {\n /** `n + 1` words. */\n readonly rowPtr: Binding;\n /** At least `count` words. */\n readonly colIdx: Binding;\n /** At least `count` f32, or null when the input has no weights. */\n readonly weights: Binding | null;\n /** Word 0 is zeroed, then raised to 1 by an out-of-order source under `sortedInput`; a scratch word otherwise. */\n readonly flag: Binding;\n}\n\n/**\n * One build: `count` arcs whose sources are below `n`.\n * @public\n */\nexport interface CooToCsrRecord {\n readonly src: Binding;\n readonly dst: Binding;\n /** One f32 per arc, or null (the output then has no weights). */\n readonly weights: Binding | null;\n readonly count: number;\n readonly n: number;\n /** The arcs are ordered by source: take the order-preserving scatter (see the file header). */\n readonly sortedInput: boolean;\n readonly out: CooToCsrOutput;\n}\n\n/**\n * A prepared `cooToCsr`.\n * @public\n */\nexport interface CooToCsrPlanner {\n /**\n * Records the histogram, the scan and (for count > 0) the scatter of one build into the pass.\n * @param pass - the compute pass\n * @param record - the arcs and the output\n */\n record(pass: GPUComputePassEncoder, record: CooToCsrRecord): void;\n}\n\n/**\n * Compiles the scatter's four variants, the histogram's, the scan's and `fill` so record() is synchronous. The\n * planner lives as long as the scope: its scratch comes from it.\n * @param scope - the caller's scope\n * @returns the planner\n */\nexport async function prepareCooToCsr(scope: ReduceScope): Promise<CooToCsrPlanner> {\n const histogram = await prepareHistogram(scope);\n const scan = await prepareScan(scope);\n const fill = await scope.pipelines.kernel(kernelSpec(\"fill\"));\n const scatter = new Map<string, Kernel>();\n for (const sorted of [false, true]) {\n for (const weighted of [false, true]) {\n const spec = kernelSpec(\"coo-scatter\", { SORTED_INPUT: sorted, WEIGHTED: weighted });\n scatter.set(`${sorted}/${weighted}`, await scope.pipelines.kernel(spec));\n }\n }\n return new CooToCsrPlannerImpl(scope, histogram, scan, fill, scatter);\n}\n\n/**\n * The E_INVALID_ARGUMENT of a binding shorter than `words` u32.\n * @param name - the argument name\n * @param binding - the binding\n * @param words - the words it must hold\n */\nfunction checkWords(name: string, binding: Binding, words: number): void {\n if (binding.size < 4 * words) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `cooToCsr: ${name} is smaller than 4 x ${words} bytes`, {\n argument: name,\n value: binding.size,\n expected: 4 * words,\n });\n }\n}\n\n/**\n * The argument checks of record() (E_INVALID_ARGUMENT before anything is recorded).\n * @param r - the record\n */\nfunction checkRecord(r: CooToCsrRecord): void {\n for (const [name, value] of [\n [\"count\", r.count],\n [\"n\", r.n],\n ] as const) {\n if (!Number.isSafeInteger(value) || value < 0 || value >= U32_MAX) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `cooToCsr: ${name} must be an integer in [0, 2^32 - 1)`, {\n argument: name,\n value,\n });\n }\n }\n if ((r.weights === null) !== (r.out.weights === null)) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n \"cooToCsr: weights and out.weights must be both present or both null\",\n {\n argument: \"weights\",\n value: r.weights === null ? \"null\" : \"present\",\n expected: r.out.weights === null ? \"null\" : \"present\",\n },\n );\n }\n checkWords(\"src\", r.src, r.count);\n checkWords(\"dst\", r.dst, r.count);\n checkWords(\"out.rowPtr\", r.out.rowPtr, r.n + 1);\n checkWords(\"out.colIdx\", r.out.colIdx, r.count);\n checkWords(\"out.flag\", r.out.flag, 1);\n if (r.weights !== null && r.out.weights !== null) {\n checkWords(\"weights\", r.weights, r.count);\n checkWords(\"out.weights\", r.out.weights, r.count);\n }\n}\n\n/** The planner: the histogram and scan planners, `fill` and the four scatter variants over one scope. */\nclass CooToCsrPlannerImpl implements CooToCsrPlanner {\n private readonly scope: ReduceScope;\n private readonly histogram: HistogramPlanner;\n private readonly scan: ScanPlanner;\n private readonly fill: Kernel;\n private readonly scatter: ReadonlyMap<string, Kernel>;\n\n /**\n * Wraps the resolved planners and kernels; use prepareCooToCsr().\n * @param scope - the caller's scope\n * @param histogram - the histogram planner\n * @param scan - the scan planner\n * @param fill - the `fill` kernel\n * @param scatter - the `coo-scatter` variants by `sorted/weighted`\n */\n constructor(\n scope: ReduceScope,\n histogram: HistogramPlanner,\n scan: ScanPlanner,\n fill: Kernel,\n scatter: ReadonlyMap<string, Kernel>,\n ) {\n this.scope = scope;\n this.histogram = histogram;\n this.scan = scan;\n this.fill = fill;\n this.scatter = scatter;\n }\n\n /**\n * Records one build (see the interface).\n * @param pass - the compute pass\n * @param r - the arcs and the output\n */\n record(pass: GPUComputePassEncoder, r: CooToCsrRecord): void {\n checkRecord(r);\n const { scope } = this;\n const wg = scope.workgroupSize;\n const degreeBytes = 4 * (r.n + 1);\n const degrees: Binding = {\n buffer: scope.scratch(degreeBytes, \"cooToCsr/degrees\"),\n offset: 0,\n size: degreeBytes,\n window: null,\n };\n this.histogram.record(pass, r.src, r.count, r.n + 1, degrees);\n this.scan.record(pass, degrees, r.n + 1, r.out.rowPtr);\n let cursors = r.out.flag;\n if (r.sortedInput) {\n this.zero(pass, r.out.flag, 1);\n } else if (r.n > 0) {\n const bytes = 4 * r.n;\n cursors = { buffer: scope.scratch(bytes, \"cooToCsr/cursors\"), offset: 0, size: bytes, window: null };\n this.zero(pass, cursors, r.n);\n }\n if (r.count === 0) {\n return;\n }\n const weighted = r.weights !== null;\n const kernel = this.scatter.get(`${r.sortedInput}/${weighted}`);\n if (kernel === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"cooToCsr: no scatter variant was prepared\", {\n argument: \"sortedInput\",\n value: r.sortedInput,\n });\n }\n // the unweighted variant never touches the weight slots: a read-only dummy and a writable scratch word\n const outWeight = r.out.weights ?? {\n buffer: scope.scratch(4, \"cooToCsr/weight-dummy\"),\n offset: 0,\n size: 4,\n window: null,\n };\n const params = scope.params(COO_PARAMS, { count: r.count, pad0: 0, pad1: 0, pad2: 0 });\n const bound = kernel.bind({\n src: r.src,\n dst: r.dst,\n weight: r.weights ?? r.dst,\n rowPtr: r.out.rowPtr,\n cursors,\n colIdx: r.out.colIdx,\n outWeight,\n P: params.binding,\n });\n kernel.dispatch(pass, bound, plan1d(r.count, wg, scope.caps), [params.offset]);\n }\n\n /**\n * Records a `fill` of `words` zeros.\n * @param pass - the compute pass\n * @param dst - the words\n * @param words - how many (>= 1)\n */\n private zero(pass: GPUComputePassEncoder, dst: Binding, words: number): void {\n const params = this.scope.params(FILL_PARAMS, { count: words, value: 0, mode: 0, pad0: 0 });\n const bound = this.fill.bind({ dst, P: params.binding });\n this.fill.dispatch(pass, bound, plan1d(words, this.scope.workgroupSize, this.scope.caps), [params.offset]);\n }\n}\n","/**\n * The segmented (per-row) reduction primitive of spec 6 row 3: the caller's VALUE snippet folded over every CSR\n * row's arcs into `out[row]` (f32), a row with no arcs receiving the identity element. Without tiers it is ONE\n * thread-per-row dispatch (TIER 0, USE_PERM false: the perm slot carries the rowPtr dummy of graphBindings). With\n * the degree tiers of degreeOrder() (P4-T5, PD-6) it is up to three dispatches over the permuted rows: TIER 2, one\n * workgroup per row of degree >= 1024 over [0, hiEnd); TIER 1, 32 lanes per row of degree 32..1023 over [hiEnd,\n * midEnd); TIER 0, one thread per row over [midEnd, n) -- each compiled only when its range is non-empty. The row\n * and arc counts come from the core's binding sizes: the residency binds every array at its exact byte length\n * (contract 3.8), so rowPtr is 4(n + 1) bytes and colIdx 4 x arcCount. On a windowed core (spec 4.2, P4-T7, PD-8)\n * the dispatches repeat per window with `arcBase = w.start`, `arcEnd = w.end` and `accumulate = 1` over an out\n * pre-filled with the identity element (unless the caller asked to accumulate), so a row split across windows\n * combines its partials: the untiered dispatch covers the window's rows [rowFirst, rowLast], while every tier\n * dispatch covers its FULL tier range (permutation positions, not comparable with the window's node rows; a row\n * whose arcs lie outside the window folds nothing and `finish` writes comb(out[i], identity) = out[i]).\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { FILL_PARAMS, graphBindings, graphOverrides, kernelSpec, RANGE_PARAMS } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { type ArcWindow, type Binding } from \"../types/memory.js\";\nimport { arcCountOf, type DegreeTiers, MID_TIER_LANES, rowCountOf, windowBinding } from \"./core-shape.js\";\nimport { type ReduceOp, type ReduceScope } from \"./reduce.js\";\n\nexport { type DegreeTiers } from \"./core-shape.js\";\n\n/** 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). */\nexport interface SegmentedReduceOptions {\n readonly op: ReduceOp;\n readonly valueSnippet: string;\n readonly tiers: DegreeTiers | null;\n readonly accumulate?: boolean | undefined;\n}\n\n/** A prepared segmented reduce: one thread-per-row dispatch without tiers, up to three tier dispatches with them (times the windows of a windowed core, plus its identity fill). */\nexport interface SegmentedReducePlanner {\n /** Records the dispatches over rows [0, n) writing out[i] (f32) per row; a row with no arcs gets the identity element. */\n record(pass: GPUComputePassEncoder, core: CoreBinding, out: Binding): void;\n /** Dispatches the last record() issued (0 for n = 0; 1 without tiers; 1 to 3 with them; on a windowed core the identity fill plus that many per window). */\n readonly lastDispatches: number;\n}\n\n/** The largest finite f32, 0x1.fffffep+127 (the prelude's F32_MAX): the min identity; its negation the max identity. */\nconst F32_MAX = 2 ** 128 - 2 ** 104;\n\n/**\n * The u32 bit pattern the `fill` kernel writes so every out word holds the identity element of the operator before\n * the windowed dispatches accumulate into it (PD-8).\n * @param op - the operator\n * @returns the bits of 0 (sum), F32_MAX (min) or -F32_MAX (max)\n */\nfunction identityFillWord(op: ReduceOp): number {\n let identity = 0;\n if (op === \"min\") {\n identity = F32_MAX;\n } else if (op === \"max\") {\n identity = -F32_MAX;\n }\n const view = new DataView(new ArrayBuffer(4));\n view.setFloat32(0, identity, true);\n return view.getUint32(0, true);\n}\n\n/** The identifiers a VALUE snippet may name (contract 3.11, 4.5); every other identifier is rejected textually before compose. */\nconst VALUE_SNIPPET_VOCABULARY: ReadonlySet<string> = new Set([\"row\", \"arc\", \"nbr\", \"weight\", \"v\"]);\n\n/**\n * The WGSL words a snippet statement may use that are not identifiers: the statement keywords (never the flow\n * keywords `return` / `break` / `continue`, which would leave the fold), the scalar type constructors and the\n * builtin math functions a value expression may call (a bounded list; a binding, a uniform or a module function such\n * as `identity` / `comb` / `linear_id` is NOT in it and is rejected as an identifier).\n */\nconst VALUE_SNIPPET_WGSL_WORDS: ReadonlySet<string> = new Set([\n \"if\",\n \"else\",\n \"let\",\n \"var\",\n \"const\",\n \"true\",\n \"false\",\n \"f32\",\n \"u32\",\n \"i32\",\n \"bool\",\n \"abs\",\n \"ceil\",\n \"clamp\",\n \"exp\",\n \"exp2\",\n \"floor\",\n \"fract\",\n \"inverseSqrt\",\n \"log\",\n \"log2\",\n \"max\",\n \"min\",\n \"mix\",\n \"pow\",\n \"round\",\n \"select\",\n \"sign\",\n \"sqrt\",\n \"step\",\n \"trunc\",\n]);\n\n/**\n * The OP override value of an operator (the body's `OP == 1u` / `OP == 2u` tests, contract 4.5).\n * @param op - the operator\n * @returns 0 for sum, 1 for min, 2 for max\n */\nfunction opCode(op: ReduceOp): number {\n switch (op) {\n case \"sum\":\n return 0;\n case \"min\":\n return 1;\n case \"max\":\n return 2;\n default:\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `segmentedReduce: unknown op ${String(op)}`, {\n argument: \"op\",\n value: op,\n expected: \"sum | min | max\",\n });\n }\n}\n\n/**\n * WGSL comments removed (a comment may mention `target` or any other word).\n * @param text - WGSL text\n * @returns the text with block and line comments replaced by spaces\n */\nfunction stripComments(text: string): string {\n return text.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \" \").replace(/\\/\\/[^\\n]*/g, \" \");\n}\n\n/**\n * The textual vocabulary check of contract 3.11: the snippet must assign `v` (`=`, `+=`, `-=`, `*=` or `/=`) and its\n * identifiers may be only row, arc, nbr, weight and v; numeric literals and the WGSL words of\n * VALUE_SNIPPET_WGSL_WORDS are not identifiers and pass; anything else -- a binding, a uniform, a module function,\n * a locally declared name, a flow keyword, a reserved word such as `target` -- is E_SHADER_COMPILE { stage:\n * \"compose\", slot: \"VALUE\", identifier } on every device, before any shader is created.\n * @param snippet - the VALUE snippet text\n */\nfunction validateValueSnippet(snippet: string): void {\n const code = stripComments(snippet);\n if (!/\\bv\\s*[-+*/]?=(?!=)/.test(code)) {\n throw new WebGpuGraphError(\"E_SHADER_COMPILE\", \"segmentedReduce: the VALUE snippet never assigns v\", {\n id: \"segmented-reduce\",\n stage: \"compose\",\n slot: \"VALUE\",\n });\n }\n const tokens = code.match(/[A-Za-z_][A-Za-z0-9_]*|[0-9][0-9A-Za-z_.]*/g) ?? [];\n for (const token of tokens) {\n if (/^[0-9]/.test(token) || VALUE_SNIPPET_VOCABULARY.has(token) || VALUE_SNIPPET_WGSL_WORDS.has(token)) {\n continue;\n }\n throw new WebGpuGraphError(\n \"E_SHADER_COMPILE\",\n `segmentedReduce: the VALUE snippet names \"${token}\"; the only identifiers allowed are row, arc, nbr, weight and v`,\n { id: \"segmented-reduce\", stage: \"compose\", slot: \"VALUE\", identifier: token },\n );\n }\n}\n\n/** One tier's compiled pipeline and the rows [start, end) of the permutation it covers per record() (a tier whose range is empty is not compiled). */\ninterface TierDispatch {\n readonly tier: 0 | 1 | 2;\n readonly kernel: Kernel;\n readonly start: number;\n readonly end: number;\n}\n\n/**\n * The tiered planner: without tiers ONE `segmented-reduce` dispatch with TIER 0 over [0, n); with tiers TIER 2 over\n * [0, hiEnd) (one workgroup per row), then TIER 1 over [hiEnd, midEnd) (WG / 32 rows per workgroup), then TIER 0\n * over [midEnd, n), each with its own RangeParams record and the perm binding.\n */\nclass TieredPlanner implements SegmentedReducePlanner {\n private readonly scope: ReduceScope;\n private readonly tiers: readonly TierDispatch[];\n private readonly fill: Kernel;\n private readonly perm: Binding | null;\n private readonly hasWeights: boolean;\n private readonly accumulate: boolean;\n private readonly identityWord: number;\n private dispatches = 0;\n\n /**\n * Wraps the compiled tier pipelines with the pattern they were compiled for.\n * @param scope - the scope the pipelines were prepared in\n * @param tiers - the compiled tiers in dispatch order (TIER 2, 1, 0; only the non-empty ones)\n * @param fill - the `fill` pipeline of the identity pre-fill of a windowed core\n * @param perm - the degreeOrder permutation binding (null: USE_PERM false, rows are node indices)\n * @param hasWeights - the HAS_WEIGHTS the pipelines were compiled with\n * @param accumulate - whether record() combines into out instead of overwriting\n * @param identityWord - the u32 bits of the operator's identity element (identityFillWord)\n */\n constructor(\n scope: ReduceScope,\n tiers: readonly TierDispatch[],\n fill: Kernel,\n perm: Binding | null,\n hasWeights: boolean,\n accumulate: boolean,\n identityWord: number,\n ) {\n this.scope = scope;\n this.tiers = tiers;\n this.fill = fill;\n this.perm = perm;\n this.hasWeights = hasWeights;\n this.accumulate = accumulate;\n this.identityWord = identityWord;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns 0 for n = 0, else the number of non-empty tier ranges\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the dispatches: every tier's rows over the arcs [0, arcCount), each with its own params record;\n * nothing for n = 0 (no zero-length binding is ever created). On a windowed core: the identity fill (unless\n * accumulating into the caller's out), then the dispatches once per window (PD-8).\n * @param pass - the pass to record into\n * @param core - a core with the SAME weights pattern as the one prepared (any snapshot; with tiers, the one the\n * tiers were built from)\n * @param out - at least 4n bytes of f32\n */\n record(pass: GPUComputePassEncoder, core: CoreBinding, out: Binding): void {\n if ((core.weights !== null) !== this.hasWeights) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n \"segmentedReduce: the core's weights pattern differs from the one prepared\",\n {\n argument: \"core\",\n value: core.weights !== null,\n expected: this.hasWeights,\n },\n );\n }\n const n = rowCountOf(core, \"segmentedReduce\");\n if (out.size < 4 * n) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `segmentedReduce: out holds ${out.size} bytes, ${4 * n} needed`,\n {\n argument: \"out\",\n value: out.size,\n expected: `>= ${4 * n}`,\n },\n );\n }\n this.dispatches = 0;\n if (n === 0) {\n return;\n }\n if (core.windows === null) {\n this.recordWindow(pass, core, out, n, null, 0);\n return;\n }\n if (!this.accumulate) {\n const params = this.scope.params(FILL_PARAMS, { count: n, value: this.identityWord, mode: 0 });\n const bound = this.fill.bind({ dst: out, P: params.binding });\n this.fill.dispatch(pass, bound, plan1d(n, this.scope.workgroupSize, this.scope.caps), [params.offset]);\n this.dispatches++;\n }\n const { windows } = core;\n windows.forEach((w, k) => {\n const windowed: CoreBinding = {\n ...core,\n colIdx: windowBinding(core, \"colIdx\", w),\n weights: core.weights === null ? null : windowBinding(core, \"weights\", w),\n };\n this.recordWindow(pass, windowed, out, n, w, k + 1 < windows.length ? windows[k + 1].start : w.end);\n });\n }\n\n /**\n * The tier dispatches over one arc window (or the whole core when `w` is null): every non-empty tier over its\n * full range, except the untiered TIER 0 dispatch, which covers exactly the window's rows. Consecutive windows\n * overlap by up to ARC_WINDOW_ALIGN - 1 arcs (the next window opens at the aligned-down end of this one), and a\n * tier dispatch visits EVERY row, so the tiers fold [w.start, nextStart) and leave the overlap to the next\n * window; the untiered dispatch keeps [w.start, w.end): its rows [rowFirst, rowLast] are exactly the rows whose\n * arcs end inside this window, and the next window's rows start after them.\n * @param pass - the pass to record into\n * @param core - the core with the window's colIdx / weights bound\n * @param out - the output binding\n * @param n - the row count\n * @param w - the window, or null for the single whole-core dispatch\n * @param nextStart - the next window's first arc (w.end for the last window)\n */\n private recordWindow(\n pass: GPUComputePassEncoder,\n core: CoreBinding,\n out: Binding,\n n: number,\n w: ArcWindow | null,\n nextStart: number,\n ): void {\n const wg = this.scope.workgroupSize;\n for (const { tier, kernel, start, end } of this.tiers) {\n let first = start;\n let last = tier === 0 ? n : end;\n let arcEnd = w === null ? arcCountOf(core) : Math.min(w.end, nextStart);\n if (w !== null && this.perm === null) {\n first = w.rowFirst;\n last = w.rowLast + 1;\n arcEnd = w.end;\n }\n const rows = last - first;\n if (rows <= 0) {\n continue;\n }\n const params = this.scope.params(RANGE_PARAMS, {\n start: first,\n end: last,\n arcBase: w === null ? 0 : w.start,\n arcEnd,\n accumulate: w !== null || this.accumulate ? 1 : 0,\n n,\n });\n const bound = kernel.bind({ ...graphBindings(core, this.perm), out, P: params.binding });\n let rowsPerGroup = wg;\n if (tier === 2) {\n rowsPerGroup = 1;\n } else if (tier === 1) {\n rowsPerGroup = wg / MID_TIER_LANES;\n }\n kernel.dispatch(pass, bound, plan1d(rows, rowsPerGroup, this.scope.caps), [params.offset]);\n this.dispatches++;\n }\n }\n}\n\n/**\n * Prepares the tier pipelines for a snapshot's dummy pattern (USE_PERM = tiers !== null, HAS_WEIGHTS) and snippet:\n * TIER 0 always; TIER 1 iff a row of degree 32..1023 exists (segmentOffsets[2] > segmentOffsets[1]); TIER 2 iff a\n * row of degree >= 1024 exists (segmentOffsets[1] > 0). The mid tier folds 32 lanes per row, so a device whose\n * workgroup size is below 32 is E_UNSUPPORTED { feature: \"segmentedReduce.tiers\" }.\n * @param scope - the reduce scope (pipelines, pool, params writer)\n * @param core - the core whose weights pattern selects HAS_WEIGHTS\n * @param options - operator, snippet, tiers (null: the single thread-per-row dispatch), accumulate\n * @returns the planner\n */\nexport async function prepareSegmentedReduce(\n scope: ReduceScope,\n core: CoreBinding,\n options: SegmentedReduceOptions,\n): Promise<SegmentedReducePlanner> {\n const op = opCode(options.op);\n validateValueSnippet(options.valueSnippet);\n const { tiers } = options;\n const perm = tiers?.perm ?? null;\n if (tiers !== null && scope.workgroupSize < MID_TIER_LANES) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `segmentedReduce: the mid tier folds ${MID_TIER_LANES} lanes per row, more than the workgroup size ${scope.workgroupSize}`,\n { feature: \"segmentedReduce.tiers\" },\n );\n }\n const ranges: readonly { readonly tier: 0 | 1 | 2; readonly start: number; readonly end: number }[] =\n tiers === null\n ? [{ tier: 0, start: 0, end: rowCountOf(core, \"segmentedReduce\") }]\n : [\n { tier: 2, start: 0, end: tiers.segmentOffsets[1] },\n { tier: 1, start: tiers.segmentOffsets[1], end: tiers.segmentOffsets[2] },\n { tier: 0, start: tiers.segmentOffsets[2], end: tiers.segmentOffsets[4] },\n ];\n const compiled: TierDispatch[] = [];\n for (const range of ranges) {\n if (range.tier !== 0 && range.end <= range.start) {\n continue;\n }\n const overrides = { ...graphOverrides(core, perm), OP: op, TIER: range.tier };\n const spec = kernelSpec(\"segmented-reduce\", overrides, { VALUE: options.valueSnippet });\n compiled.push({ ...range, kernel: await scope.pipelines.kernel(spec) });\n }\n const fill = await scope.pipelines.kernel(kernelSpec(\"fill\"));\n return new TieredPlanner(\n scope,\n compiled,\n fill,\n perm,\n core.weights !== null,\n options.accumulate === true,\n identityFillWord(options.op),\n );\n}\n","/**\n * The simple symmetric graph (the P11 plan's PD-4): triangle counting and label propagation are defined over an\n * undirected graph with no parallel edges and no self-loops, and a snapshot may be directed, may carry parallel\n * edges and may carry self-loops. This builds that graph on the device from the snapshot's edge list:\n *\n * 1. `coo-emit` writes two arcs per logical edge -- the edge as declared and its reverse -- and drops a self-loop\n * by writing both of its arcs as `INVALID_INDEX`, which sorts last.\n * 2. Two stable radix sorts order the arcs by (source, target): by target first, then by source, the second sort's\n * stability keeping the first's order among equal sources. Between and after them `coo-emit` re-reads the edge\n * list through the sorted permutation (INDEXED), so no gather kernel is needed.\n * 3. `run-flags` marks the first arc of every run of equal pairs; the scan of the flags counts the runs, which is\n * the number of distinct arcs `U` -- read back once, because every later size depends on it.\n * 4. Three `compact`s keep the first arc of every run (its source, its target and its position), and a segmented\n * sum over the runs merges the weights of parallel arcs in input order (so the merged weight is bitwise\n * reproducible).\n * 5. `cooToCsr` in its sorted-input mode builds the rows, which come out sorted by target.\n *\n * The first submit ends at step 3; steps 4 and 5 are recorded into a batch that is RETURNED OPEN, so the caller\n * records its own first work into the same submit and saves a synchronisation. The caller must check the\n * precondition flag of `cooToCsr` with `assertBuildSorted` after that submit.\n *\n * Every intermediate array is `2 x edgeCount` words and is bound whole, so a snapshot whose arcs exceed one storage\n * binding is refused with `E_TOO_LARGE` before any upload. A weighted build refuses, with `E_UNSUPPORTED`, a pair\n * joined by more than PARALLEL_MERGE_LIMIT parallel edges (see the constant).\n *\n * ponytail: about nine of the arrays are alive at the peak (72 bytes per logical edge); reuse buffers across the\n * steps if a 1M-node / 10M-edge build needs the room.\n */\n\nimport { type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { PARALLEL_MERGE_LIMIT } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch, type ReadbackRequest } from \"../kernel/batch.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { COO_PARAMS, FILL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { prepareCompact } from \"../primitives/compact.js\";\nimport { prepareCooToCsr } from \"../primitives/coo-to-csr.js\";\nimport { prepareRadixSort, type RadixBits, radixHistBytes } from \"../primitives/radix-sort.js\";\nimport { prepareScan } from \"../primitives/scan.js\";\nimport { prepareSegmentedReduce } from \"../primitives/segmented-reduce.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type AlgorithmScope } from \"./scope.js\";\n\n/**\n * The simple symmetric graph on the device.\n * @public\n */\nexport interface SimpleGraph {\n readonly n: number;\n /** Arcs: twice the undirected edges of the simple graph. */\n readonly arcCount: number;\n /** `n + 1` words. */\n readonly rowPtr: Binding;\n /** `arcCount` words, each row sorted ascending; null when there are no arcs. */\n readonly colIdx: Binding | null;\n /** `arcCount` f32, the summed weight of the parallel edges each arc merges (1 per edge on an unweighted snapshot); null when there are no arcs or weights were not asked for. */\n readonly weights: Binding | null;\n /** The source of every arc (`arcCount` words, non-decreasing); null when there are no arcs. */\n readonly src: Binding | null;\n}\n\n/**\n * The open second batch of a build: record more work into it, submit it, then call `assertBuildSorted`.\n * @public\n */\nexport interface SimpleGraphBuild {\n readonly graph: SimpleGraph;\n readonly batch: CommandBatch;\n /** The readback of the sorted-input flag of `cooToCsr`, already scheduled on `batch`. */\n readonly flag: ReadbackRequest;\n}\n\n/**\n * The key width that orders node indices below `n` with `INVALID_INDEX` after all of them: the low `bits` of\n * `INVALID_INDEX` are all ones, so every node index must stay below `2^bits - 1`.\n * @param n - the node count\n * @returns 8, 16, 24 or 32\n */\nfunction sortBitsFor(n: number): RadixBits {\n for (const bits of [8, 16, 24] as const) {\n if (n < 2 ** bits) {\n return bits;\n }\n }\n return 32;\n}\n\n/**\n * A whole-binding view of a scratch buffer of `words` u32 (at least one word, so a binding is never zero-length).\n * @param scope - the scope the buffer comes from\n * @param words - the words\n * @param label - the scratch label\n * @returns the binding\n */\nfunction scratchWords(scope: AlgorithmScope, words: number, label: string): Binding {\n const size = 4 * Math.max(1, words);\n return { buffer: scope.scratch(size, label), offset: 0, size, window: null };\n}\n\n/**\n * Throws `E_TOO_LARGE` when a buffer the caller binds whole is larger than one storage binding of the device.\n * @param ctx - the context whose limit applies\n * @param needed - the bytes of the largest whole binding\n * @param path - what does not fit\n * @param algorithm - the algorithm, for the error\n */\nexport function assertBindable(ctx: GpuContext, needed: number, path: string, algorithm: string): void {\n const limit = ctx.caps.limits.maxStorageBufferBindingSize;\n if (needed > limit) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${algorithm}: ${path} needs ${needed} bytes in one binding, above the device limit of ${limit}`,\n { needed, limit, path, algorithm },\n );\n }\n}\n\n/**\n * Throws `E_UNSUPPORTED` when a weighted build would merge more than PARALLEL_MERGE_LIMIT parallel arcs into one: the\n * edges joining one pair, in either direction. Only a pair of two vertices that each touch more than the limit can,\n * so the exact count runs over those pairs alone and costs nothing on an ordinary graph.\n * @param n - the node count\n * @param src - the edge sources\n * @param dst - the edge targets\n * @param algorithm - the algorithm, for the error\n */\nfunction assertMergeable(n: number, src: ArrayLike<number>, dst: ArrayLike<number>, algorithm: string): void {\n const incident = new Uint32Array(n);\n for (let e = 0; e < src.length; e++) {\n if (src[e] !== dst[e]) {\n incident[src[e]]++;\n incident[dst[e]]++;\n }\n }\n const heavy = new Map<number, number>();\n for (let v = 0; v < n; v++) {\n if (incident[v] > PARALLEL_MERGE_LIMIT) {\n heavy.set(v, heavy.size);\n }\n }\n if (heavy.size < 2) {\n return;\n }\n const pairs = new Uint32Array(heavy.size * heavy.size);\n for (let e = 0; e < src.length; e++) {\n const a = heavy.get(src[e]);\n const b = heavy.get(dst[e]);\n if (a === undefined || b === undefined || a === b) {\n continue;\n }\n const key = Math.min(a, b) * heavy.size + Math.max(a, b);\n if (++pairs[key] > PARALLEL_MERGE_LIMIT) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `${algorithm}: nodes ${src[e]} and ${dst[e]} are joined by more than ${PARALLEL_MERGE_LIMIT} parallel edges, more than one weighted merge sums`,\n { feature: `${algorithm}.parallelEdges`, hint: \"run it unweighted, or merge the parallel edges first\" },\n );\n }\n }\n}\n\n/**\n * Throws `E_VALIDATION` when the device found the build's arcs out of source order, which would mean a bug in the\n * sorts: the rows would be scrambled and every intersection over them wrong.\n * @param bytes - the batch's readback bytes\n * @param build - the build whose flag was read\n * @param label - the algorithm, for the error\n */\nexport function assertBuildSorted(bytes: ArrayBuffer, build: SimpleGraphBuild, label: string): void {\n if (new Uint32Array(bytes, build.flag.offset, 1)[0] !== 0) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${label}: the simple graph's arcs reached cooToCsr out of order`, {\n label: `${label}/simple-graph`,\n message: \"the sorted-input precondition of cooToCsr failed on the device\",\n });\n }\n}\n\n/**\n * Builds the simple symmetric graph of `s` (see the file header): submits the first batch and waits for its\n * four-byte readback, then records the rest into a batch it returns open.\n * @param ctx - the context\n * @param s - the snapshot (its edge list is uploaded through the residency, or found there)\n * @param scope - the caller's scope: every buffer of the graph is its scratch\n * @param withWeights - merge and keep the weights (label propagation) or not (triangle counting)\n * @param label - the batch label prefix\n * @returns the graph and the open batch\n */\nexport async function buildSimpleSymmetric(\n ctx: GpuContext,\n s: GraphSnapshot,\n scope: AlgorithmScope,\n withWeights: boolean,\n label: string,\n): Promise<SimpleGraphBuild> {\n const n = s.nodeCount;\n const wg = ctx.workgroupSize;\n const cooToCsr = await prepareCooToCsr(scope);\n const flag = scratchWords(scope, 1, \"simple/flag\");\n const rowPtr = scratchWords(scope, n + 1, \"simple/rowPtr\");\n const { edgeCount } = s;\n const list = s.edgeList();\n let selfLoops = 0;\n for (let e = 0; e < edgeCount; e++) {\n if (list.src[e] === list.dst[e]) {\n selfLoops++;\n }\n }\n const valid = 2 * (edgeCount - selfLoops);\n const empty = (): SimpleGraphBuild => {\n const batch = new CommandBatch(ctx, `${label}/simple-graph`);\n cooToCsr.record(batch.pass(\"simple-graph\"), {\n src: flag,\n dst: flag,\n weights: null,\n count: 0,\n n,\n sortedInput: true,\n out: { rowPtr, colIdx: flag, weights: null, flag },\n });\n batch.endPass();\n const graph: SimpleGraph = { n, arcCount: 0, rowPtr, colIdx: null, weights: null, src: null };\n return { graph, batch, flag: batch.readback(flag.buffer, 0, 4) };\n };\n if (valid === 0) {\n return empty();\n }\n const arcs = 2 * edgeCount;\n const tableBytes = Math.max(4, radixHistBytes(arcs, wg));\n assertBindable(ctx, Math.max(4 * (arcs + 1), tableBytes), \"the simple graph's arc arrays\", label);\n if (withWeights) {\n assertMergeable(n, list.src, list.dst, label);\n }\n // core() is what records (or re-records, after a release) the snapshot in the residency; the build reads only\n // the edge list, so it asks for rowPtr alone\n ctx.residency.core(s, [\"rowPtr\"]);\n const edges = ctx.residency.view(s, \"edgeList\");\n const edgeWeights = edges.bindings.weights ?? null;\n const emitPlan = plan1d(arcs, wg, ctx.caps);\n const emit = new Map<boolean, Kernel>();\n for (const indexed of [false, true]) {\n const spec = kernelSpec(\"coo-emit\", { INDEXED: indexed, WEIGHTED: edgeWeights !== null });\n emit.set(indexed, await ctx.pipelines.kernel(spec));\n }\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const runFlags = await ctx.pipelines.kernel(kernelSpec(\"run-flags\"));\n const sort = await prepareRadixSort(scope);\n const scan = await prepareScan(scope);\n const compact = await prepareCompact(scope);\n\n const aSrc = scratchWords(scope, arcs, \"simple/aSrc\");\n const aDst = scratchWords(scope, arcs, \"simple/aDst\");\n const aW = scratchWords(scope, arcs, \"simple/aW\");\n const vals = scratchWords(scope, arcs, \"simple/vals\");\n const sKeys = scratchWords(scope, arcs, \"simple/sortKeys\");\n const sVals = scratchWords(scope, arcs, \"simple/sortVals\");\n const hist: Binding = {\n buffer: scope.scratch(tableBytes, \"simple/hist\"),\n offset: 0,\n size: tableBytes,\n window: null,\n };\n const offsets: Binding = {\n buffer: scope.scratch(tableBytes, \"simple/offsets\"),\n offset: 0,\n size: tableBytes,\n window: null,\n };\n const sortedSrc = scratchWords(scope, arcs, \"simple/sortedSrc\");\n const sortedDst = scratchWords(scope, arcs, \"simple/sortedDst\");\n const sortedW = scratchWords(scope, arcs, \"simple/sortedW\");\n const flags = scratchWords(scope, arcs, \"simple/flags\");\n const runIndex = scratchWords(scope, arcs, \"simple/runIndex\");\n const dummy = scratchWords(scope, 1, \"simple/dummy\");\n await ctx.allocator.check();\n\n const recordEmit = (pass: GPUComputePassEncoder, order: Binding | null, out: readonly Binding[]): void => {\n const kernel = emit.get(order !== null);\n if (kernel === undefined) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"buildSimpleSymmetric: no coo-emit variant\", {\n argument: \"order\",\n value: order === null ? \"null\" : \"present\",\n });\n }\n const params = scope.params(COO_PARAMS, { count: arcs, pad0: 0, pad1: 0, pad2: 0 });\n const bound = kernel.bind({\n edgeSrc: edges.bindings.src,\n edgeDst: edges.bindings.dst,\n edgeWeight: edgeWeights ?? edges.bindings.src,\n order: order ?? dummy,\n outSrc: out[0],\n outDst: out[1],\n outWeight: out[2],\n P: params.binding,\n });\n kernel.dispatch(pass, bound, emitPlan, [params.offset]);\n };\n const recordIota = (pass: GPUComputePassEncoder, dst: Binding, words: number): void => {\n const params = scope.params(FILL_PARAMS, { count: words, value: 0, mode: 1, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst, P: params.binding }), plan1d(words, wg, ctx.caps), [params.offset]);\n };\n\n // batch 1: emit, sort by target, re-emit in that order, sort by source, re-emit sorted, flag the runs, count them\n const bits = sortBitsFor(n);\n const first = new CommandBatch(ctx, `${label}/simple-sort`);\n const pass = first.pass(\"simple-sort\");\n recordEmit(pass, null, [aSrc, aDst, aW]);\n recordIota(pass, vals, arcs);\n const byTarget = sort.record(pass, aDst, vals, arcs, bits, { keys: sKeys, vals: sVals, hist, offsets });\n recordEmit(pass, byTarget.vals, [aSrc, aDst, aW]);\n const free = byTarget.vals.buffer === vals.buffer ? sVals : vals;\n const bySource = sort.record(pass, aSrc, byTarget.vals, arcs, bits, {\n keys: byTarget.keys.buffer === aDst.buffer ? sKeys : aDst,\n vals: free,\n hist,\n offsets,\n });\n recordEmit(pass, bySource.vals, [sortedSrc, sortedDst, sortedW]);\n const params = scope.params(COO_PARAMS, { count: arcs, pad0: 0, pad1: 0, pad2: 0 });\n runFlags.dispatch(pass, runFlags.bind({ keysA: sortedSrc, keysB: sortedDst, flags, P: params.binding }), emitPlan, [\n params.offset,\n ]);\n const total = scan.record(pass, flags, arcs, runIndex);\n first.endPass();\n const totalRequest = first.readback(total.binding.buffer, total.binding.offset + 4 * total.index, 4);\n scope.flush();\n const back = await first.submit().readback;\n ctx.assertReady();\n const unique = new Uint32Array(back, totalRequest.offset, 1)[0];\n if (unique === 0 || unique > valid) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${label}: ${unique} distinct arcs from ${valid} valid ones`, {\n label: `${label}/simple-graph`,\n message: \"the run count of the simple graph build is outside [1, valid arcs]\",\n });\n }\n\n // batch 2 (returned open): keep the first arc of every run, merge the weights, build the rows\n const uSrc = scratchWords(scope, arcs, \"simple/src\");\n const uDst = scratchWords(scope, arcs, \"simple/dst\");\n const runStart = scratchWords(scope, arcs + 1, \"simple/runStart\");\n const counts = scratchWords(scope, 1, \"simple/count\");\n const colIdx = scratchWords(scope, unique, \"simple/colIdx\");\n const weights = withWeights ? scratchWords(scope, unique, \"simple/weights\") : null;\n const merged = withWeights ? scratchWords(scope, unique, \"simple/merged\") : null;\n // the terminator of the last run: every valid arc precedes the dropped ones, so the runs end at `valid`\n ctx.device.queue.writeBuffer(runStart.buffer, 4 * unique, Uint32Array.of(valid));\n const reduce =\n merged === null\n ? null\n : await prepareSegmentedReduce(scope, runCore(runStart, unique, sortedDst, sortedW, valid), {\n op: \"sum\",\n valueSnippet: \"v = weight;\",\n tiers: null,\n });\n const second = new CommandBatch(ctx, `${label}/simple-graph`);\n const pass2 = second.pass(\"simple-graph\");\n const positions = vals;\n recordIota(pass2, positions, arcs);\n for (const [queue, out] of [\n [sortedSrc, uSrc],\n [sortedDst, uDst],\n [positions, runStart],\n ] as const) {\n compact.record(pass2, { queue, flags, count: arcs, out, outCount: counts, outIndex: 0 });\n }\n if (reduce !== null && merged !== null) {\n reduce.record(pass2, runCore(runStart, unique, sortedDst, sortedW, valid), merged);\n }\n cooToCsr.record(pass2, {\n src: uSrc,\n dst: uDst,\n weights: merged,\n count: unique,\n n,\n sortedInput: true,\n out: { rowPtr, colIdx, weights, flag },\n });\n second.endPass();\n const graph: SimpleGraph = { n, arcCount: unique, rowPtr, colIdx, weights, src: uSrc };\n return { graph, batch: second, flag: second.readback(flag.buffer, 0, 4) };\n}\n\n/**\n * The runs as a CSR the segmented sum walks: row r is run r, its arcs the sorted positions `[runStart[r],\n * runStart[r + 1])`, its weights the sorted weights, so a row's sum is the merged weight in input order.\n * @param runStart - the run starts plus the terminator\n * @param runs - the run count\n * @param sortedDst - the sorted targets (the fold reads a neighbour it ignores)\n * @param sortedW - the sorted weights\n * @param valid - the arcs the runs cover\n * @returns the core binding\n */\nfunction runCore(runStart: Binding, runs: number, sortedDst: Binding, sortedW: Binding, valid: number): CoreBinding {\n return {\n serial: -1,\n plan: \"perArray\",\n rowPtr: { ...runStart, size: 4 * (runs + 1) },\n colIdx: { ...sortedDst, size: 4 * valid },\n weights: { ...sortedW, size: 4 * valid },\n arcToEdge: null,\n edgeToArc: null,\n windows: null,\n arcBuffers: null,\n hasWeights: true,\n };\n}\n","/**\n * Label propagation (design 8.6, 3.3 line 807; the P11 plan's P11-T6) over the simple symmetric graph of the\n * snapshot (`buildSimpleSymmetric`). Every vertex starts with its own index as its label; each pass,\n * `group-by-key-row` finds every vertex's weighted mode of its neighbours' labels (the lowest label on a tie) and\n * `lpa-step` adopts it synchronously -- but only in the pass's direction: down to a lower label on even passes, up to\n * a higher one on odd passes (cuGraph's swap-avoidance rule), which is what stops two neighbours trading labels\n * forever. A pass that moves nothing in either direction after one that moved nothing in the other is a fixed point,\n * and the run stops there or at `maxIterations` passes.\n *\n * Passes are recorded LABEL_PROP_PASSES_PER_SUBMIT to a submit with one readback of their move counts, because a\n * readback per pass costs more than the passes on a small graph; the passes after the fixed point inside the last\n * submit change nothing, so the labels are those of the fixed point. The first submit is the graph build's second.\n * The labels are renumbered in first-seen order on the host (`renumberPartition`), as connected components' are.\n *\n * The result is bitwise reproducible on one device and between devices: the grouping is order-independent and every\n * sum is an integer.\n */\n\nimport { type GraphSnapshot, renumberPartition, type U32 } from \"@graphty/graph-format\";\n\nimport { LABEL_PROP_PASSES_PER_SUBMIT } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { FILL_PARAMS, kernelSpec, LPA_PARAMS } from \"../kernels.js\";\nimport { planGroupRows, prepareGroupByKeyRow } from \"../primitives/group-by-key.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type GpuLabelResult } from \"../types/algorithms.js\";\nimport { type LabelPropagationOptions } from \"../types/community.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { labelResult } from \"./components.js\";\nimport { algorithmScope } from \"./scope.js\";\nimport { assertBindable, assertBuildSorted, buildSimpleSymmetric } from \"./simple-symmetric.js\";\n\nconst ALGORITHM = \"labelPropagation\";\n/** The default pass cap, as in `@graphty/algorithms`' labelPropagation. */\nconst DEFAULT_MAX_ITERATIONS = 100;\n/** Params slots of the largest batch: the graph build's second submit plus one batch of passes. */\nconst RING_SLOTS = 1024;\n\n/**\n * Validates `options.dest` for a label result of `n` elements.\n * @param dest - the caller's destination array, if any\n * @param n - the node count\n * @returns the destination as a U32, or null when none was given\n */\nfunction checkDest(dest: Float32Array | Uint32Array | undefined, n: number): U32 | null {\n if (dest === undefined) {\n return null;\n }\n if (dest instanceof Uint32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {\n return dest as U32;\n }\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: dest must be a Uint32Array of length ${n} over an ArrayBuffer`,\n {\n argument: \"dest\",\n value: `${dest.constructor.name}(${dest.length})`,\n expected: `Uint32Array(${n}) over an ArrayBuffer`,\n },\n );\n}\n\n/**\n * The pass cap.\n * @param value - options.maxIterations\n * @returns the cap\n */\nfunction maxIterationsOf(value: number | undefined): number {\n if (value === undefined) {\n return DEFAULT_MAX_ITERATIONS;\n }\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${ALGORITHM}: maxIterations must be a non-negative integer`, {\n argument: \"maxIterations\",\n value,\n expected: \"a non-negative integer\",\n });\n }\n return value;\n}\n\n/**\n * An upper bound of every vertex's number of distinct neighbours in the simple symmetric graph: its arcs in both\n * directions, which the merge of parallel edges and the drop of self-loops can only shrink.\n * @param s - the snapshot\n * @returns one bound per vertex\n */\nfunction neighbourBound(s: GraphSnapshot): Uint32Array {\n const out = s.outDegree();\n if (!s.directed) {\n return out;\n }\n const inDegree = s.inDegree();\n const bound = new Uint32Array(s.nodeCount);\n for (let v = 0; v < bound.length; v++) {\n bound[v] = out[v] + inDegree[v];\n }\n return bound;\n}\n\n/**\n * The labels as a result: every label must be a node index (a device bug otherwise), then renumbered first-seen.\n * @param raw - the labels the device produced\n * @param dest - the caller's destination, if any\n * @returns the result\n */\nfunction resultOf(raw: U32, dest: U32 | null): GpuLabelResult {\n const n = raw.length;\n for (let v = 0; v < n; v++) {\n if (raw[v] >= n) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: labels[${v}] = ${raw[v]} is not a node index`, {\n label: `${ALGORITHM}/labels`,\n message: `the device produced a label outside [0, ${n})`,\n });\n }\n }\n const { labels, count } = renumberPartition(raw, dest ?? undefined);\n return labelResult(labels, count);\n}\n\n/**\n * The identity labelling: every vertex its own community.\n * @param n - the node count\n * @param dest - the caller's destination, if any\n * @returns the result\n */\nfunction identityResult(n: number, dest: U32 | null): GpuLabelResult {\n const labels = dest ?? new Uint32Array(n);\n for (let v = 0; v < n; v++) {\n labels[v] = v;\n }\n return labelResult(labels, n);\n}\n\n/**\n * Label propagation on the device (see the file header).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (its edge list is uploaded through ctx.residency, or found there)\n * @param options - maxIterations (default 100), weighted (default true), plus dest / signal / onProgress\n * @returns the labels, dense in first-seen order, the community count and groups()\n */\nexport async function labelPropagation(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: LabelPropagationOptions & GpuRunOptions,\n): Promise<GpuLabelResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const n = s.nodeCount;\n const dest = checkDest(options?.dest, n);\n const maxIterations = maxIterationsOf(options?.maxIterations);\n const weighted = options?.weighted !== false;\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted before any work started`, {});\n }\n if (n === 0 || s.edgeCount === 0 || maxIterations === 0) {\n options?.onProgress?.(1, 1);\n return identityResult(n, dest);\n }\n // the hash region of the workgroup tier is bound whole: refuse a graph it outgrows before any device work\n const plan = planGroupRows(neighbourBound(s));\n assertBindable(ctx, 4 * plan.regionWords, \"the group-by hash region\", ALGORITHM);\n const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);\n try {\n const build = await buildSimpleSymmetric(ctx, s, scope, weighted, ALGORITHM);\n const { graph } = build;\n if (graph.colIdx === null) {\n // only self-loops: no vertex has a neighbour, so nothing ever moves\n scope.flush();\n const bytes = await build.batch.submit().readback;\n ctx.assertReady();\n assertBuildSorted(bytes, build, ALGORITHM);\n options?.onProgress?.(1, 1);\n return identityResult(n, dest);\n }\n const wg = ctx.workgroupSize;\n const words = (count: number, label: string): Binding => {\n const size = 4 * Math.max(1, count);\n return { buffer: scope.scratch(size, label), offset: 0, size, window: null };\n };\n const rows = words(plan.words.length, \"rows\");\n const region = words(plan.regionWords, \"hashRegion\");\n const labelsA = words(n, \"labelsA\");\n const labelsB = words(n, \"labelsB\");\n const bestKey = words(n, \"bestKey\");\n const bestScore = words(n, \"bestScore\");\n const counters = words(LABEL_PROP_PASSES_PER_SUBMIT, \"counters\");\n await ctx.allocator.check();\n const { queue } = ctx.device;\n queue.writeBuffer(rows.buffer, 0, plan.words);\n queue.writeBuffer(region.buffer, 0, new Uint32Array(1));\n const groupBy = await prepareGroupByKeyRow(scope);\n const step = await ctx.pipelines.kernel(kernelSpec(\"lpa-step\"));\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const nodePlan = plan1d(n, wg, ctx.caps);\n\n let { batch } = build;\n let first = true;\n let cur = labelsA;\n let next = labelsB;\n let done = 0;\n let previousLast = -1;\n for (;;) {\n const k = Math.min(LABEL_PROP_PASSES_PER_SUBMIT, maxIterations - done);\n queue.writeBuffer(counters.buffer, 0, new Uint32Array(k));\n const pass = batch.pass(\"passes\");\n if (first) {\n const iota = scope.params(FILL_PARAMS, { count: n, value: 0, mode: 1, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst: labelsA, P: iota.binding }), nodePlan, [iota.offset]);\n }\n for (let i = 0; i < k; i++) {\n groupBy.record(pass, {\n rowPtr: graph.rowPtr,\n colIdx: graph.colIdx,\n weights: weighted ? graph.weights : null,\n keyIn: cur,\n plan,\n rows,\n hashRegion: region,\n bestKey,\n bestScore,\n });\n const params = scope.params(LPA_PARAMS, {\n n,\n direction: (done + i) % 2,\n counterIndex: i,\n pad0: 0,\n });\n step.dispatch(\n pass,\n step.bind({ labelsIn: cur, bestKey, labelsOut: next, counters, P: params.binding }),\n nodePlan,\n [params.offset],\n );\n [cur, next] = [next, cur];\n }\n batch.endPass();\n const movesRequest = batch.readback(counters.buffer, 0, 4 * k);\n const exhaustedRequest = batch.readback(region.buffer, 0, 4);\n scope.flush();\n const submitted = batch.submit();\n const bytes = await submitted.readback;\n ctx.assertReady();\n if (first) {\n assertBuildSorted(bytes, build, ALGORITHM);\n first = false;\n }\n if (new Uint32Array(bytes, exhaustedRequest.offset, 1)[0] !== 0) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: a hash probe exhausted its bound`, {\n label: `${ALGORITHM}/group-by-key`,\n message: \"a compare-exchange loop of the workgroup tier ran out of steps\",\n });\n }\n const moves = new Uint32Array(bytes, movesRequest.offset, k);\n done += k;\n const lastTwo = k >= 2 ? moves[k - 2] + moves[k - 1] : previousLast + moves[0];\n previousLast = moves[k - 1];\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted`, {\n batchId: submitted.id,\n });\n }\n options?.onProgress?.(done, maxIterations);\n if (lastTwo === 0 || done >= maxIterations) {\n break;\n }\n batch = new CommandBatch(ctx, `${ALGORITHM}/passes`);\n }\n const raw = new Uint32Array(n);\n await ctx.readback.read(cur.buffer, 4 * n, raw);\n ctx.assertReady();\n return resultOf(raw, dest);\n } finally {\n scope.dispose();\n }\n}\n","/**\n * Boruvka's minimum spanning forest (design 8.5, 3.3 line 808; the P11 plan's P11-T4) over the snapshot's edge list,\n * each logical edge once, so a directed snapshot is spanned as its underlying undirected multigraph -- what\n * `@graphty/algorithms`' `kruskalMST` does. Every vertex starts as its own component (`comp[v] = v`); each round:\n *\n * 1. `fill` resets every component's `bestKey` and `bestEdge` to `U32_MAX`;\n * 2. `mst-best` twice (PD-7): the per-component minimum of the TOTAL edge order -- the order-preserving key of the\n * weight first (PD-6: negative weights order below positive ones, -0 equals +0), the edge index among ties -- over\n * the edges whose endpoints lie in different components, so self-loops and edges inside a component never compete;\n * 3. `mst-link`: each root with a best edge hooks onto the component at its other end and records the edge, the lower\n * root of a two-cycle keeping its label so the edge is recorded once;\n * 4. `wcc-compress` (PD-7: the Afforest kernel, unchanged) until every vertex points at its root: a walk of at most\n * COMPRESS_STEPS per dispatch divides every depth by COMPRESS_STEPS, so `compressPasses(n)` dispatches suffice.\n *\n * Because the order is total the forest is unique: it is the one Kruskal accepts when its sort breaks ties by edge\n * index, which `kruskalMST` does. So the edge SET equals the CPU's on every graph, tied weights included; only the\n * order of `edges` differs.\n *\n * BORUVKA_ROUNDS_PER_SUBMIT rounds are recorded per submit with one readback of their recorded-edge counts; a round\n * that records nothing ends the run (rounds after it inside the same submit change nothing). The round count is at\n * most ceil(log2 n) + 1, because every round at least halves the components that still have an outgoing edge;\n * MAX_ROUNDS is the bound a device bug cannot pass, never a fallback. The forest is read back once at the end.\n *\n * PLAN DECISION (P11-T4 Step 3 appends each edge through an `atomicAdd` on the counters block): a root records its\n * edge in its own word of `treeEdge`, because a root hooks at most once in a run. The result is then deterministic\n * (the edges in root order, round by round) with no host sort, where an atomic append is ordered by the schedule.\n *\n * `totalWeight` is summed on the host in f64 over the snapshot's own edge weights, so it differs from\n * `kruskalMST`'s only by the order of the summation.\n */\n\nimport { type GraphSnapshot, INVALID_INDEX, type U32 } from \"@graphty/graph-format\";\n\nimport { BORUVKA_ROUNDS_PER_SUBMIT, U32_MAX } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { plan1d, planGridStride } from \"../kernel/dispatch.js\";\nimport { FILL_PARAMS, kernelSpec, MST_PARAMS, WCC_PARAMS } from \"../kernels.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { type GpuMstResult } from \"../types/structure.js\";\nimport { algorithmScope } from \"./scope.js\";\n\nconst ALGORITHM = \"minimumSpanningTree\";\n/** The bound of one compress walk (the `maxSteps` of `wcc-compress`), as connected components uses. */\nconst COMPRESS_STEPS = 1024;\n/** A round count no correct run reaches: at most ceil(log2 n) + 1 <= 33 rounds for any u32 node count. */\nconst MAX_ROUNDS = 64;\n/** Params slots of the largest batch: the first one's two initial fills, the reset fill, the shared best-pass and compress blocks, and one link block per round. */\nconst RING_SLOTS = 5 + BORUVKA_ROUNDS_PER_SUBMIT;\n\n/**\n * The `wcc-compress` dispatches that flatten any forest of `n` vertices: each one divides every depth by\n * COMPRESS_STEPS (a vertex lands at least COMPRESS_STEPS ancestors up, or on its root).\n * @param n - the vertex count\n * @returns the dispatch count, at least 1\n */\nexport function compressPasses(n: number): number {\n let passes = 1;\n for (let reach = COMPRESS_STEPS; reach < n; reach *= COMPRESS_STEPS) {\n passes++;\n }\n return passes;\n}\n\n/**\n * The forest from the per-root `treeEdge` words, with the host-side f64 total.\n * @param s - the snapshot\n * @param treeEdge - one word per vertex, the edge its component recorded or INVALID_INDEX\n * @param expected - the edge count the rounds reported\n * @returns the result\n */\nfunction resultOf(s: GraphSnapshot, treeEdge: Uint32Array, expected: number): GpuMstResult {\n const edges: U32 = new Uint32Array(expected);\n const { weights } = s.edgeList();\n let taken = 0;\n let totalWeight = 0;\n for (const e of treeEdge) {\n if (e === INVALID_INDEX) {\n continue;\n }\n if (e >= s.edgeCount || taken === expected) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: the device recorded an edge it did not count`, {\n label: `${ALGORITHM}/treeEdge`,\n message: `edge ${e} at forest position ${taken} of ${expected}`,\n });\n }\n edges[taken++] = e;\n totalWeight += weights === null ? 1 : weights[e];\n }\n if (taken !== expected) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: ${taken} recorded edges, ${expected} counted`, {\n label: `${ALGORITHM}/treeEdge`,\n message: \"the per-round counts disagree with the recorded forest\",\n });\n }\n return { edges, totalWeight };\n}\n\n/**\n * Boruvka's minimum spanning forest on the device (see the file header).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (its edge list is uploaded through ctx.residency, or found there)\n * @param options - signal, onProgress (`dest` is refused: the forest's length is not known before the run)\n * @returns the forest's logical edge indices and its total weight\n */\nexport async function minimumSpanningTree(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: GpuRunOptions,\n): Promise<GpuMstResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n if (options?.dest !== undefined) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `${ALGORITHM}: dest is not supported`, {\n option: \"dest\",\n hint: \"the forest's edge count is known only after the run\",\n });\n }\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted before any work started`, {});\n }\n const n = s.nodeCount;\n const m = s.edgeCount;\n if (n === 0 || m === 0) {\n options?.onProgress?.(1, 1);\n return { edges: new Uint32Array(0), totalWeight: 0 };\n }\n // core() is what records (or re-records, after a release) the snapshot in the residency; only the edge list is read\n ctx.residency.core(s, [\"rowPtr\"]);\n const edges = ctx.residency.view(s, \"edgeList\");\n const edgeWeight = edges.bindings.weights ?? null;\n const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);\n try {\n const wg = ctx.workgroupSize;\n const words = (count: number, label: string): Binding => {\n const size = 4 * Math.max(1, count);\n return { buffer: scope.scratch(size, label), offset: 0, size, window: null };\n };\n const comp = words(n, \"comp\");\n const bestKey = words(n, \"bestKey\");\n const bestEdge = words(n, \"bestEdge\");\n const treeEdge = words(n, \"treeEdge\");\n const counters = words(BORUVKA_ROUNDS_PER_SUBMIT, \"counters\");\n await ctx.allocator.check();\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const weighted = edgeWeight !== null;\n const minKey = await ctx.pipelines.kernel(kernelSpec(\"mst-best\", { PASS: 0, WEIGHTED: weighted }));\n const minEdge = await ctx.pipelines.kernel(kernelSpec(\"mst-best\", { PASS: 1, WEIGHTED: weighted }));\n const link = await ctx.pipelines.kernel(kernelSpec(\"mst-link\"));\n const compress = await ctx.pipelines.kernel(kernelSpec(\"wcc-compress\"));\n const nodePlan = plan1d(n, wg, ctx.caps);\n const edgePlan = plan1d(m, wg, ctx.caps);\n const compressPlan = planGridStride(n, wg, ctx.caps);\n const passes = compressPasses(n);\n const { queue } = ctx.device;\n\n let batch = new CommandBatch(ctx, `${ALGORITHM}/rounds`);\n let first = true;\n let rounds = 0;\n let recorded = 0;\n for (;;) {\n queue.writeBuffer(counters.buffer, 0, new Uint32Array(BORUVKA_ROUNDS_PER_SUBMIT));\n const pass = batch.pass(\"rounds\");\n const fillFor = (value: number, mode: number): { binding: Binding; offset: number } =>\n scope.params(FILL_PARAMS, { count: n, value, mode, pad0: 0 });\n if (first) {\n const iota = fillFor(0, 1);\n fill.dispatch(pass, fill.bind({ dst: comp, P: iota.binding }), nodePlan, [iota.offset]);\n const none = fillFor(INVALID_INDEX, 0);\n fill.dispatch(pass, fill.bind({ dst: treeEdge, P: none.binding }), nodePlan, [none.offset]);\n }\n const reset = fillFor(U32_MAX, 0);\n const edgeParams = scope.params(MST_PARAMS, { count: m, counterIndex: 0, pad0: 0, pad1: 0 });\n const compressParams = scope.params(WCC_PARAMS, {\n n,\n items: n,\n stride: compressPlan.stride ?? n,\n r: 0,\n flagIndex: 0,\n giant: U32_MAX,\n maxSteps: COMPRESS_STEPS,\n pad0: 0,\n });\n const graph = {\n edgeSrc: edges.bindings.src,\n edgeDst: edges.bindings.dst,\n edgeWeight: edgeWeight ?? edges.bindings.src,\n };\n for (let i = 0; i < BORUVKA_ROUNDS_PER_SUBMIT; i++) {\n for (const dst of [bestKey, bestEdge]) {\n fill.dispatch(pass, fill.bind({ dst, P: reset.binding }), nodePlan, [reset.offset]);\n }\n for (const kernel of [minKey, minEdge]) {\n kernel.dispatch(\n pass,\n kernel.bind({ ...graph, comp, bestKey, bestEdge, P: edgeParams.binding }),\n edgePlan,\n [edgeParams.offset],\n );\n }\n const linkParams = scope.params(MST_PARAMS, { count: n, counterIndex: i, pad0: 0, pad1: 0 });\n link.dispatch(\n pass,\n link.bind({\n edgeSrc: graph.edgeSrc,\n edgeDst: graph.edgeDst,\n bestEdge,\n comp,\n treeEdge,\n counters,\n P: linkParams.binding,\n }),\n nodePlan,\n [linkParams.offset],\n );\n for (let j = 0; j < passes; j++) {\n compress.dispatch(pass, compress.bind({ comp, P: compressParams.binding }), compressPlan, [\n compressParams.offset,\n ]);\n }\n }\n batch.endPass();\n const countsRequest = batch.readback(counters.buffer, 0, 4 * BORUVKA_ROUNDS_PER_SUBMIT);\n scope.flush();\n const submitted = batch.submit();\n const bytes = await submitted.readback;\n ctx.assertReady();\n first = false;\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted`, {\n batchId: submitted.id,\n });\n }\n const counts = new Uint32Array(bytes, countsRequest.offset, BORUVKA_ROUNDS_PER_SUBMIT);\n let settled = false;\n for (const count of counts) {\n recorded += count;\n settled ||= count === 0;\n }\n rounds += BORUVKA_ROUNDS_PER_SUBMIT;\n if (recorded > n - 1) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: ${recorded} forest edges on ${n} nodes`, {\n label: `${ALGORITHM}/counters`,\n message: \"a spanning forest has at most n - 1 edges\",\n });\n }\n if (settled) {\n break;\n }\n if (rounds >= MAX_ROUNDS) {\n throw new WebGpuGraphError(\"E_VALIDATION\", `${ALGORITHM}: still merging after ${rounds} rounds`, {\n label: `${ALGORITHM}/rounds`,\n message: \"Boruvka halves the components every round; the device did not\",\n });\n }\n batch = new CommandBatch(ctx, `${ALGORITHM}/rounds`);\n }\n const raw = new Uint32Array(n);\n await ctx.readback.read(treeEdge.buffer, 4 * n, raw);\n ctx.assertReady();\n options?.onProgress?.(1, 1);\n return resultOf(s, raw, recorded);\n } finally {\n scope.dispose();\n }\n}\n","/**\n * PageRank and personalized PageRank on the device (spec 8.2, 3.3): a pull over the reverse adjacency with the\n * out-weight normaliser folded into `xNorm` by `pr-scale`, the dangling mass and the L1 delta folded by\n * `pr-finalize` into the header at `partials[0]`, and `spmv-pull` writing the next iterate. Iterations run in\n * batches of PR_BATCH per submit, ONE readback per batch (the header and the iterate together), and the device\n * records `firstConverged` the first time the delta falls below `tolerance * n`, so the reported `iterations` is the\n * first converged iteration and not the batch boundary (spec 9.7).\n *\n * PLAN DECISION PD-7: the ping-pong is TWO buffers (`rankA`, `rankB`) alternated through two cached bind groups;\n * one buffer of two aliased halves would bind (each kernel sees the halves in one access mode) but saves nothing.\n * PLAN DECISION PD-8: `outWeightSum` is call scratch from the Lease, one `segmentedReduce` pass per call.\n * PLAN DECISION PD-9: `pr-scale` at iteration i reads x(i-1) and x(i-2), so its delta is the error of iteration\n * i - 1 and `pr-finalize` records `P.iteration - 1`; the ping-pong supplies `rankPrev` for free because it is the\n * buffer this iteration overwrites, and `pr-scale` runs before `spmv-pull` in the same pass.\n */\n\nimport { type F32, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { U32_MAX } from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch } from \"../kernel/batch.js\";\nimport { groupsOf, plan1d } from \"../kernel/dispatch.js\";\nimport { kernelSpec, PR_PARAMS, PR_PARTIAL } from \"../kernels.js\";\nimport { type ArrayBinding, type CoreBinding } from \"../memory/residency.js\";\nimport { assertWholeCore, coreOfView } from \"../primitives/core-shape.js\";\nimport { prepareSegmentedReduce } from \"../primitives/segmented-reduce.js\";\nimport { prepareSpmvPull } from \"../primitives/spmv.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type GpuPageRankResult, type PageRankOptions } from \"../types/algorithms.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { algorithmScope } from \"./scope.js\";\n\n/** Iterations per submit (spec 8.2: k = 8). */\nconst PR_BATCH = 8;\n/** Params slots of one batch: per iteration one PrParams (shared by pr-scale and pr-finalize) and one SpmvParams, plus the normaliser's RangeParams and the last batch's convergence check; a smaller ring wraps onto a slot the same batch still reads. */\nconst RING_SLOTS = 2 * PR_BATCH + 2;\n\n/**\n * Validates `options.dest` for a score result of `n` elements.\n * @param dest - the caller's destination array, if any\n * @param n - the node count\n * @param algorithm - the caller's name, for the message\n * @returns the destination as an F32, or null when none was given\n */\nfunction checkDest(dest: Float32Array | Uint32Array | undefined, n: number, algorithm: string): F32 | null {\n if (dest === undefined) {\n return null;\n }\n if (dest instanceof Float32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {\n return dest as F32;\n }\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${algorithm}: dest must be a Float32Array of length ${n} over an ArrayBuffer`,\n {\n argument: \"dest\",\n value: `${dest.constructor.name}(${dest.length})`,\n expected: `Float32Array(${n}) over an ArrayBuffer`,\n },\n );\n}\n\n/**\n * The resident core; a windowed plan is refused with `E_TOO_LARGE { path: \"windowed\", algorithm }` (spec 3.8, 3.12;\n * DEP-P4-B: only degree and segmentedReduce execute windows).\n * @param ctx - the context\n * @param s - the snapshot\n * @param algorithm - the caller's name\n * @returns the core binding\n */\nfunction coreOf(ctx: GpuContext, s: GraphSnapshot, algorithm: string): CoreBinding {\n const core = ctx.residency.core(s);\n assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, algorithm);\n return core;\n}\n\n/**\n * Whole-buffer binding of a scratch buffer over its first `size` bytes.\n * @param buffer - the buffer\n * @param size - the bound byte length\n * @returns the binding\n */\nfunction bindingOf(buffer: GPUBuffer, size: number): Binding {\n return { buffer, offset: 0, size, window: null };\n}\n\n/**\n * The E_ABORTED error of a signal.\n * @param algorithm - the caller's name\n * @param batchId - the last submitted batch, when one exists\n * @returns the error\n */\nfunction aborted(algorithm: string, batchId?: number): WebGpuGraphError {\n return new WebGpuGraphError(\n \"E_ABORTED\",\n `${algorithm}: the signal was aborted`,\n batchId === undefined ? {} : { batchId },\n );\n}\n\n/**\n * The shared driver: `personalization` is the normalised vector of personalizedPageRank or null for the uniform\n * 1 / n of pageRank.\n * @param ctx - the context\n * @param s - the snapshot\n * @param personalization - the normalised personalization (sum 1), or null\n * @param options - the PageRank and run options\n * @param algorithm - the public name, for messages and labels\n * @returns the result\n */\nasync function run(\n ctx: GpuContext,\n s: GraphSnapshot,\n personalization: F32 | null,\n options: (PageRankOptions & GpuRunOptions) | undefined,\n algorithm: string,\n): Promise<GpuPageRankResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const n = s.nodeCount;\n const alpha = options?.dampingFactor ?? 0.85;\n const maxIterations = options?.maxIterations ?? 100;\n const tolerance = options?.tolerance ?? 1e-6;\n const useWeights = options?.weighted !== false;\n if (!Number.isInteger(maxIterations) || maxIterations < 1) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${algorithm}: maxIterations must be a positive integer`, {\n argument: \"maxIterations\",\n value: maxIterations,\n expected: \"a positive integer\",\n });\n }\n const dest = checkDest(options?.dest, n, algorithm);\n if (options?.signal?.aborted) {\n throw aborted(algorithm);\n }\n if (n === 0) {\n options?.onProgress?.(maxIterations, maxIterations);\n return {\n scores: dest ?? new Float32Array(0),\n iterations: 0,\n converged: true,\n danglingMass: 0,\n precision: \"f32\",\n };\n }\n const core = coreOf(ctx, s, algorithm);\n if (s.arcCount === 0) {\n // every node is dangling: the whole mass is redistributed by pv each iteration, so pv is the fixed point\n const scores = dest ?? new Float32Array(n);\n if (personalization === null) {\n scores.fill(1 / n);\n } else {\n scores.set(personalization);\n }\n options?.onProgress?.(maxIterations, maxIterations);\n return { scores, iterations: 0, converged: true, danglingMass: 1, precision: \"f32\" };\n }\n const view = ctx.residency.view(s, \"reverse\");\n const rev = coreOfView(view, view.scalars.arcCount[0]);\n // weighted: false runs the unweighted algorithm on BOTH sides: the normaliser sums 1 per arc and the pull folds 1\n const weights: Binding | null | undefined = useWeights ? undefined : null;\n const weightedCore: CoreBinding = useWeights ? core : { ...core, weights: null, hasWeights: false };\n const weightedRev: CoreBinding = useWeights ? rev : { ...rev, weights: null, hasWeights: false };\n const scope = algorithmScope(ctx, algorithm, RING_SLOTS);\n let uploaded: ArrayBinding | null = null;\n try {\n const bytes = 4 * n;\n const rankA = scope.scratch(bytes, \"rankA\");\n const rankB = scope.scratch(bytes, \"rankB\");\n const xNorm = scope.scratch(bytes, \"xNorm\");\n const outWeightSum = scope.scratch(bytes, \"outWeightSum\");\n const scalePlan = plan1d(n, ctx.workgroupSize, ctx.caps);\n const groups = groupsOf(scalePlan);\n const partialsBytes = PR_PARTIAL.byteLength * (1 + groups);\n const partials = scope.scratch(partialsBytes, \"partials\");\n // the header as the last pull left it, before the convergence check of the last batch overwrites danglingMass\n const lastHeader = scope.scratch(PR_PARTIAL.byteLength, \"lastHeader\");\n if (personalization !== null) {\n uploaded = ctx.residency.array(personalization, `${algorithm}/personalization`);\n }\n await ctx.allocator.check();\n const normaliser = await prepareSegmentedReduce(scope, weightedCore, {\n op: \"sum\",\n valueSnippet: \"v = weight;\",\n tiers: null,\n });\n const pull = await prepareSpmvPull(scope, weightedRev, {\n personalization: personalization !== null,\n dangling: true,\n weights,\n tiers: null,\n });\n const scale = await ctx.pipelines.kernel(kernelSpec(\"pr-scale\", { NORM_MODE: 0 }));\n const finalize = await ctx.pipelines.kernel(kernelSpec(\"pr-finalize\", { NORM_MODE: 0 }));\n const finalizePlan = plan1d(1, ctx.workgroupSize, ctx.caps);\n const { queue } = ctx.device;\n queue.writeBuffer(rankA, 0, new Float32Array(n).fill(1 / n));\n queue.writeBuffer(rankB, 0, new Float32Array(n));\n const header = new ArrayBuffer(PR_PARTIAL.byteLength);\n PR_PARTIAL.write(new DataView(header), { firstConverged: U32_MAX, iteration: 0 });\n queue.writeBuffer(partials, 0, header);\n const rank = [bindingOf(rankA, bytes), bindingOf(rankB, bytes)];\n const xNormBinding = bindingOf(xNorm, bytes);\n const outWeightSumBinding = bindingOf(outWeightSum, bytes);\n const partialsBinding = bindingOf(partials, partialsBytes);\n const lastHeaderBinding = bindingOf(lastHeader, PR_PARTIAL.byteLength);\n const coefficients = { alpha, beta: 1 - alpha, uniformP: 1 / n };\n let cur = 0;\n let iterationsRun = 0;\n for (;;) {\n const k = Math.min(PR_BATCH, maxIterations - iterationsRun);\n const batch = new CommandBatch(ctx, algorithm);\n let pass = batch.pass(\"iterations\");\n if (iterationsRun === 0) {\n normaliser.record(pass, weightedCore, outWeightSumBinding);\n }\n const last = iterationsRun + k === maxIterations;\n // the scale + finalize of iteration i measures the error of iteration i - 1 (PD-9), so the last batch\n // runs them once more, with no pull, to measure the error of iteration maxIterations itself\n for (let i = 0; i < k + (last ? 1 : 0); i++) {\n const params = scope.params(PR_PARAMS, {\n n,\n groups,\n iteration: iterationsRun + i + 1,\n trackConvergence: 1,\n convergeThreshold: tolerance * n,\n });\n const other = 1 - cur;\n if (i === k) {\n batch.copy(partialsBinding, lastHeaderBinding, PR_PARTIAL.byteLength);\n pass = batch.pass(\"convergence\");\n }\n const scaleBound = scale.bind({\n rankIn: rank[cur],\n rankPrev: rank[other],\n outWeightSum: outWeightSumBinding,\n xNorm: xNormBinding,\n partials: partialsBinding,\n P: params.binding,\n });\n scale.dispatch(pass, scaleBound, scalePlan, [params.offset]);\n const finalizeBound = finalize.bind({ partials: partialsBinding, P: params.binding });\n finalize.dispatch(pass, finalizeBound, finalizePlan, [params.offset]);\n if (i === k) {\n break;\n }\n pull.record(\n pass,\n weightedRev,\n {\n xNorm: xNormBinding,\n rankOut: rank[other],\n personalization: uploaded?.binding ?? null,\n partials: partialsBinding,\n },\n coefficients,\n );\n cur = other;\n }\n batch.endPass();\n const headerRequest = batch.readback(partials, 0, PR_PARTIAL.byteLength);\n const lastHeaderRequest = last ? batch.readback(lastHeader, 0, PR_PARTIAL.byteLength) : headerRequest;\n const scoresRequest = batch.readback(rank[cur].buffer, 0, bytes);\n scope.flush();\n const submitted = batch.submit();\n const back = await submitted.readback;\n iterationsRun += k;\n ctx.assertReady();\n if (options?.signal?.aborted) {\n throw aborted(algorithm, submitted.id);\n }\n options?.onProgress?.(iterationsRun, maxIterations);\n const folded = PR_PARTIAL.read(new DataView(back), headerRequest.offset);\n const firstConverged = folded.firstConverged as number;\n const converged = firstConverged !== U32_MAX;\n if (converged || iterationsRun >= maxIterations) {\n const scores = dest ?? new Float32Array(n);\n scores.set(new Float32Array(back, scoresRequest.offset, n));\n if (converged && iterationsRun < maxIterations) {\n options?.onProgress?.(maxIterations, maxIterations);\n }\n return {\n scores,\n iterations: converged ? firstConverged : iterationsRun,\n converged,\n danglingMass: PR_PARTIAL.read(new DataView(back), lastHeaderRequest.offset).danglingMass as number,\n precision: \"f32\",\n };\n }\n }\n } finally {\n uploaded?.destroy();\n scope.dispose();\n }\n}\n\n/**\n * PageRank on the device (spec 3.3, 8.2): NetworkX semantics, f32 scores, `iterations` the first converged\n * iteration (spec 9.7).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - dampingFactor 0.85 / maxIterations 100 / tolerance 1e-6 / weighted true, plus dest / signal / onProgress\n * @returns the scores, iterations, converged, danglingMass and precision\n */\nexport function pageRank(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: PageRankOptions & GpuRunOptions,\n): Promise<GpuPageRankResult> {\n return run(ctx, s, null, options, \"pageRank\");\n}\n\n/**\n * Personalized PageRank on the device (spec 3.3, 8.2): the personalization vector replaces the uniform 1 / n in\n * the teleport and the dangling redistribution; it is normalised to sum 1 on the host.\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param personalization - one finite non-negative mass per node, not all zero\n * @param options - dampingFactor 0.85 / maxIterations 100 / tolerance 1e-6 / weighted true, plus dest / signal / onProgress\n * @returns the scores, iterations, converged, danglingMass and precision\n */\nexport async function personalizedPageRank(\n ctx: GpuContext,\n s: GraphSnapshot,\n personalization: F32,\n options?: PageRankOptions & GpuRunOptions,\n): Promise<GpuPageRankResult> {\n const n = s.nodeCount;\n const invalid = (value: unknown, expected: string): WebGpuGraphError =>\n new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `personalizedPageRank: personalization must be ${expected}`, {\n argument: \"personalization\",\n value,\n expected,\n });\n if (!(personalization instanceof Float32Array) || personalization.length !== n) {\n throw invalid(\n `${personalization.constructor.name}(${personalization.length})`,\n `a Float32Array of length ${n}`,\n );\n }\n let total = 0;\n for (let v = 0; v < n; v++) {\n const mass = personalization[v];\n if (!Number.isFinite(mass) || mass < 0) {\n throw invalid(mass, \"finite and non-negative in every entry\");\n }\n total += mass;\n }\n if (n > 0 && !(total > 0)) {\n throw invalid(total, \"a vector whose entries sum to a positive number\");\n }\n const normalised = new Float32Array(n);\n for (let v = 0; v < n; v++) {\n normalised[v] = personalization[v] / total;\n }\n return run(ctx, s, normalised, options, \"personalizedPageRank\");\n}\n","/**\n * HITS, eigenvector centrality and Katz centrality on the device (spec 3.3 lines 794-796, 8.2 lines 2603-2605):\n * three entry points over the ONE power-iteration driver, differing only in the adjacency the pull walks, the\n * normaliser and the coefficients. Eigenvector is the L2-normalised iteration over the forward core; Katz is\n * `alpha * A^T x + beta` over the reverse view with no per-iteration normaliser; HITS alternates the two pulls with\n * sum normalisation, `a(i) = A^T norm(h(i-1))` and `h(i) = A norm(a(i-1))` (the CPU package's recurrence, which\n * design 9.7 makes the parity target), as TWO interleaved chains of the driver -- the reverse-first chain from the\n * hub seed and the forward-first chain from the authority seed -- so a call is still two runs and two readbacks.\n * Every result is normalised ONCE on the host after the readback (sum for HITS, L2 for the other two), matching\n * the f64 oracle; the per-iteration normaliser never leaves the device (PD-10).\n */\n\nimport { type F32, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport {\n type EigenvectorOptions,\n type GpuHitsResult,\n type GpuScoresResult,\n type HitsOptions,\n type KatzOptions,\n} from \"../types/algorithms.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { aborted, checkDest, coreOf, type PowerIterationRun, reverseOf, runPowerIteration } from \"./power-iteration.js\";\n\n/** The three options every entry point shares, resolved. */\ninterface Resolved {\n readonly n: number;\n readonly maxIterations: number;\n readonly tolerance: number;\n readonly weights: Binding | null | undefined;\n readonly dest: F32 | null;\n}\n\n/**\n * Resolves and validates the shared options and the run options' `dest` / `signal`.\n * @param ctx - the context\n * @param s - the snapshot\n * @param options - maxIterations / tolerance / weighted plus dest / signal\n * @param algorithm - the public name, for messages\n * @returns the resolved options\n */\nfunction resolve(\n ctx: GpuContext,\n s: GraphSnapshot,\n options: (HitsOptions & GpuRunOptions) | undefined,\n algorithm: string,\n): Resolved {\n ctx.assertReady();\n const n = s.nodeCount;\n const maxIterations = options?.maxIterations ?? 100;\n const tolerance = options?.tolerance ?? 1e-6;\n if (!Number.isInteger(maxIterations) || maxIterations < 1) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${algorithm}: maxIterations must be a positive integer`, {\n argument: \"maxIterations\",\n value: maxIterations,\n expected: \"a positive integer\",\n });\n }\n const dest = checkDest(options?.dest, n, algorithm);\n if (options?.signal?.aborted) {\n throw aborted(algorithm);\n }\n // weighted: false runs UNWEIGHTED on a weighted snapshot: the pull folds 1 per arc (prepareSpmvPull's null)\n return { n, maxIterations, tolerance, weights: options?.weighted === false ? null : undefined, dest };\n}\n\n/**\n * A finite coefficient, or E_INVALID_ARGUMENT.\n * @param value - the caller's value, or undefined for the default\n * @param fallback - the default\n * @param argument - the option name\n * @returns the coefficient\n */\nfunction finite(value: number | undefined, fallback: number, argument: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `katzCentrality: ${argument} must be a finite number`, {\n argument,\n value: resolved,\n expected: \"a finite number\",\n });\n }\n return resolved;\n}\n\n/**\n * Copies the raw iterate into its destination divided by its norm (unchanged when the norm is not positive).\n * @param raw - the driver's iterate\n * @param dest - the caller's destination, or null for the raw array itself\n * @param norm - \"sum\" (L1) or \"l2\"\n * @returns the normalised scores\n */\nfunction normalised(raw: F32, dest: F32 | null, norm: \"sum\" | \"l2\"): F32 {\n let acc = 0;\n for (const v of raw) {\n acc += norm === \"sum\" ? Math.abs(v) : v * v;\n }\n const scale = norm === \"sum\" ? acc : Math.sqrt(acc);\n const out = dest ?? raw;\n for (let v = 0; v < raw.length; v++) {\n out[v] = scale > 0 ? raw[v] / scale : raw[v];\n }\n return out;\n}\n\n/**\n * The score result of one run.\n * @param run - the driver's run\n * @param dest - the caller's destination, or null\n * @param norm - the final normaliser\n * @returns the result\n */\nfunction scoresOf(run: PowerIterationRun, dest: F32 | null, norm: \"sum\" | \"l2\"): GpuScoresResult {\n return {\n scores: normalised(run.scores, dest, norm),\n iterations: run.iterations,\n converged: run.converged,\n precision: \"f32\",\n };\n}\n\n/**\n * The n = 0 result: nothing to iterate.\n * @param dest - the caller's destination, or null\n * @param total - the run's progress denominator, reported to onProgress as both done and total\n * @param onProgress - the caller's progress callback\n * @returns the empty result\n */\nfunction empty(\n dest: F32 | null,\n total: number,\n onProgress: ((done: number, total: number) => void) | undefined,\n): GpuScoresResult {\n onProgress?.(total, total);\n return { scores: dest ?? new Float32Array(0), iterations: 0, converged: true, precision: \"f32\" };\n}\n\n/**\n * The latest iterate of one kind across the two HITS chains: a chain holds its seed's kind after an even number of\n * iterations m (in `scores`, index m) and the other kind's last iterate one back (in `previous`, index m - 1, never\n * null on an alternating run; the fallback only satisfies the type).\n * @param sameSeed - the chain seeded with the wanted kind\n * @param otherSeed - the chain seeded with the other kind\n * @returns the raw iterate with the higher index\n */\nfunction latestOfKind(sameSeed: PowerIterationRun, otherSeed: PowerIterationRun): F32 {\n const fromSame = sameSeed.iterationsRun % 2 === 0 ? sameSeed.iterationsRun : sameSeed.iterationsRun - 1;\n const fromOther = otherSeed.iterationsRun % 2 === 1 ? otherSeed.iterationsRun : otherSeed.iterationsRun - 1;\n const chain = fromSame >= fromOther ? sameSeed : otherSeed;\n const index = Math.max(fromSame, fromOther);\n return (index === chain.iterationsRun ? chain.scores : chain.previous) ?? chain.scores;\n}\n\n/**\n * Eigenvector centrality on the device (spec 3.3, 8.2): the L2-normalised power iteration over the forward\n * adjacency, converging on `delta < n * tolerance`; the scores are L2-normalised.\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - maxIterations 100 / tolerance 1e-6 / weighted true, plus dest / signal / onProgress\n * @returns the scores, iterations, converged and precision\n */\nexport async function eigenvectorCentrality(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: EigenvectorOptions & GpuRunOptions,\n): Promise<GpuScoresResult> {\n const algorithm = \"eigenvectorCentrality\";\n const r = resolve(ctx, s, options, algorithm);\n if (r.n === 0) {\n return empty(r.dest, r.maxIterations, options?.onProgress);\n }\n const run = await runPowerIteration(ctx, r.n, {\n normMode: 2,\n adjacency: coreOf(ctx, s, algorithm),\n alternate: null,\n alpha: 1,\n beta: 0,\n uniformP: 0,\n maxIterations: r.maxIterations,\n tolerance: r.tolerance,\n weights: r.weights,\n label: algorithm,\n signal: options?.signal,\n onProgress: options?.onProgress,\n });\n return scoresOf(run, r.dest, \"l2\");\n}\n\n/**\n * Katz centrality on the device (spec 3.3, 8.2): `x = alpha * A^T x + beta` over the reverse adjacency with no\n * per-iteration normaliser; the scores are L2-normalised once at the end.\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - alpha 0.1 / beta 1 / maxIterations 100 / tolerance 1e-6 / weighted true, plus dest / signal / onProgress\n * @returns the scores, iterations, converged and precision\n */\nexport async function katzCentrality(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: KatzOptions & GpuRunOptions,\n): Promise<GpuScoresResult> {\n const algorithm = \"katzCentrality\";\n const alpha = finite(options?.alpha, 0.1, \"alpha\");\n const beta = finite(options?.beta, 1, \"beta\");\n const r = resolve(ctx, s, options, algorithm);\n if (r.n === 0) {\n return empty(r.dest, r.maxIterations, options?.onProgress);\n }\n const run = await runPowerIteration(ctx, r.n, {\n normMode: 4,\n adjacency: reverseOf(ctx, s),\n alternate: null,\n alpha,\n beta,\n uniformP: 1,\n maxIterations: r.maxIterations,\n tolerance: r.tolerance,\n weights: r.weights,\n label: algorithm,\n signal: options?.signal,\n onProgress: options?.onProgress,\n });\n return scoresOf(run, r.dest, \"l2\");\n}\n\n/**\n * HITS on the device (spec 3.3, 8.2): `a(i) = A^T norm(h(i-1))` and `h(i) = A norm(a(i-1))` from uniform seeds,\n * sum-normalised. Those two recurrences interleave into two independent chains, each alternating the reverse and\n * the forward pull, so the driver runs twice: the chain seeded as hubs pulls reverse first and holds h(m) after an\n * even number m of iterations and a(m) after an odd one; the chain seeded as authorities is the mirror image. Each\n * chain stops at its own batch boundary, so the two can end on opposite parities holding the SAME kind; the result\n * takes the latest iterate of each kind across both chains (a chain's last two iterates are one of each kind),\n * which is h(m) and a(m) when both ran m iterations and never two vectors of one kind otherwise.\n * `iterations` is the larger of the two and `converged` their conjunction. `dest`, when given, receives the hubs.\n * Both vectors are sum-normalised.\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - maxIterations 100 / tolerance 1e-6 / weighted true, plus dest / signal / onProgress\n * @returns hubs, authorities, iterations, converged and precision\n */\nexport async function hits(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: HitsOptions & GpuRunOptions,\n): Promise<GpuHitsResult> {\n const algorithm = \"hits\";\n const r = resolve(ctx, s, options, algorithm);\n const total = 2 * r.maxIterations;\n if (r.n === 0) {\n const { scores, iterations, converged, precision } = empty(r.dest, total, options?.onProgress);\n return { hubs: scores, authorities: new Float32Array(0), iterations, converged, precision };\n }\n const onProgress = options?.onProgress;\n const shared = {\n normMode: 1 as const,\n alpha: 1,\n beta: 0,\n uniformP: 0,\n maxIterations: r.maxIterations,\n tolerance: r.tolerance,\n weights: r.weights,\n signal: options?.signal,\n };\n const forward = coreOf(ctx, s, algorithm);\n const reverse = reverseOf(ctx, s);\n const hubSeeded = await runPowerIteration(ctx, r.n, {\n ...shared,\n adjacency: reverse,\n alternate: forward,\n label: `${algorithm}/hub-seeded`,\n onProgress:\n onProgress === undefined\n ? undefined\n : (done) => {\n onProgress(done, total);\n },\n });\n const authoritySeeded = await runPowerIteration(ctx, r.n, {\n ...shared,\n adjacency: forward,\n alternate: reverse,\n label: `${algorithm}/authority-seeded`,\n onProgress:\n onProgress === undefined\n ? undefined\n : (done) => {\n onProgress(r.maxIterations + done, total);\n },\n });\n return {\n hubs: normalised(latestOfKind(hubSeeded, authoritySeeded), r.dest, \"sum\"),\n authorities: normalised(latestOfKind(authoritySeeded, hubSeeded), null, \"sum\"),\n iterations: Math.max(hubSeeded.iterations, authoritySeeded.iterations),\n converged: hubSeeded.converged && authoritySeeded.converged,\n precision: \"f32\",\n };\n}\n","/**\n * Triangle counting with the local clustering coefficient and the transitivity (design 8.5, 3.3 line 806, design 17\n * line 5067; the P11 plan's P11-T8). Over the simple symmetric graph of the snapshot (`buildSimpleSymmetric`, so a\n * directed snapshot, parallel edges and self-loops all give the answer of the underlying simple undirected graph):\n *\n * 1. `orient-flags` keeps arc (u, v) when v is above u in the (degree, id) order, one arc per undirected edge;\n * 2. two `compact`s keep the oriented arcs' sources and targets -- in order, so the oriented rows stay sorted -- and\n * `cooToCsr` in its sorted-input mode builds the oriented rows (there are exactly `arcs / 2` of them, so no count\n * is read back);\n * 3. `tri-intersect` intersects the two oriented rows of every oriented arc and adds each triangle to the counts of\n * its three vertices with u32 atomics -- exact, and independent of the schedule.\n *\n * All of it rides in the build's second submit, so a call is two synchronisations whatever the graph.\n *\n * PLAN DECISION (the P11 plan's DEP-P11-C): the coefficient and the transitivity are computed on the host from the\n * per-node counts and the simple graph's `rowPtr`, both read back in the same submit, not by a `tri-coefficient`\n * kernel. f32 division on the device is not correctly rounded (2.5 ULP on the reference card), and the transitivity's\n * denominator -- the sum of `d (d - 1) / 2` -- overflows a u32 at a single node of degree 92,682; in f64 on the host\n * both are exact to the f32 the result stores, and the `rowPtr` read costs the same bytes as the coefficient array a\n * device epilogue would have read back instead.\n */\n\nimport { type F32, type GraphSnapshot, type U32 } from \"@graphty/graph-format\";\n\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { COO_PARAMS, FILL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { prepareCompact } from \"../primitives/compact.js\";\nimport { prepareCooToCsr } from \"../primitives/coo-to-csr.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\nimport { type GpuTriangleResult } from \"../types/structure.js\";\nimport { algorithmScope } from \"./scope.js\";\nimport { assertBuildSorted, buildSimpleSymmetric } from \"./simple-symmetric.js\";\n\nconst ALGORITHM = \"triangleCount\";\n/** Params slots of the largest batch: the build's two sorts and scans plus the orientation's compactions and build. */\nconst RING_SLOTS = 1024;\n\n/**\n * Validates `options.dest` for the per-node counts.\n * @param dest - the caller's destination array, if any\n * @param n - the node count\n * @returns the destination as a U32, or null when none was given\n */\nfunction checkDest(dest: Float32Array | Uint32Array | undefined, n: number): U32 | null {\n if (dest === undefined) {\n return null;\n }\n if (dest instanceof Uint32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {\n return dest as U32;\n }\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${ALGORITHM}: dest must be a Uint32Array of length ${n} over an ArrayBuffer`,\n {\n argument: \"dest\",\n value: `${dest.constructor.name}(${dest.length})`,\n expected: `Uint32Array(${n}) over an ArrayBuffer`,\n },\n );\n}\n\n/**\n * The coefficient, the total and the transitivity from the per-node counts and the simple graph's rows, in f64.\n * @param perNode - the triangles of every node\n * @param rowPtr - the simple graph's `n + 1` row offsets\n * @returns the result\n */\nfunction epilogue(perNode: U32, rowPtr: Uint32Array): GpuTriangleResult {\n const n = perNode.length;\n const coefficient: F32 = new Float32Array(n);\n let sum = 0;\n let triples = 0;\n for (let v = 0; v < n; v++) {\n const d = rowPtr[v + 1] - rowPtr[v];\n const t = perNode[v];\n sum += t;\n if (d >= 2) {\n const pairs = (d * (d - 1)) / 2;\n triples += pairs;\n coefficient[v] = t / pairs;\n }\n }\n return { perNode, total: sum / 3, coefficient, transitivity: triples === 0 ? 0 : sum / triples };\n}\n\n/**\n * Counts the triangles of the simple undirected graph underlying `s` on the device (see the file header).\n * @param ctx - the context whose device runs the kernels\n * @param s - the snapshot (its edge list is uploaded through ctx.residency, or found there)\n * @param options - dest (the per-node counts), signal, onProgress\n * @returns the per-node counts, the total, the clustering coefficients and the transitivity\n */\nexport async function triangleCount(\n ctx: GpuContext,\n s: GraphSnapshot,\n options?: GpuRunOptions,\n): Promise<GpuTriangleResult> {\n return await triangleCountWithSearch(ctx, s, 0, options);\n}\n\n/**\n * `triangleCount` with the intersection path forced (the tier-agreement tests' seam): 0 chooses per arc, 1 always\n * merges, 2 always binary-searches.\n * @internal\n * @param ctx - the context\n * @param s - the snapshot\n * @param search - the `SEARCH` override of `tri-intersect`\n * @param options - dest, signal, onProgress\n * @returns the result\n */\nexport async function triangleCountWithSearch(\n ctx: GpuContext,\n s: GraphSnapshot,\n search: 0 | 1 | 2,\n options?: GpuRunOptions,\n): Promise<GpuTriangleResult> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const n = s.nodeCount;\n const dest = checkDest(options?.dest, n);\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted before any work started`, {});\n }\n if (n === 0) {\n options?.onProgress?.(1, 1);\n return epilogue(dest ?? new Uint32Array(0), new Uint32Array(1));\n }\n const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);\n try {\n const build = await buildSimpleSymmetric(ctx, s, scope, false, ALGORITHM);\n const { graph, batch } = build;\n const wg = ctx.workgroupSize;\n const countsBytes = 4 * n;\n const counts: Binding = {\n buffer: scope.scratch(countsBytes, \"counts\"),\n offset: 0,\n size: countsBytes,\n window: null,\n };\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const pass = batch.pass(\"triangles\");\n let orientedFlag: Binding | null = null;\n const zero = scope.params(FILL_PARAMS, { count: n, value: 0, mode: 0, pad0: 0 });\n fill.dispatch(pass, fill.bind({ dst: counts, P: zero.binding }), plan1d(n, wg, ctx.caps), [zero.offset]);\n if (graph.arcCount > 0 && graph.colIdx !== null && graph.src !== null) {\n const oriented = graph.arcCount / 2;\n const orient = await ctx.pipelines.kernel(kernelSpec(\"orient-flags\"));\n const intersect = await ctx.pipelines.kernel(kernelSpec(\"tri-intersect\", { SEARCH: search }));\n const compact = await prepareCompact(scope);\n const cooToCsr = await prepareCooToCsr(scope);\n const words = (count: number, label: string): Binding => ({\n buffer: scope.scratch(4 * count, label),\n offset: 0,\n size: 4 * count,\n window: null,\n });\n const flags = words(graph.arcCount, \"orient/flags\");\n const oSrc = words(graph.arcCount, \"orient/src\");\n const oDst = words(graph.arcCount, \"orient/dst\");\n const oRowPtr = words(n + 1, \"orient/rowPtr\");\n const oColIdx = words(oriented, \"orient/colIdx\");\n const scratch = words(1, \"orient/count\");\n const oFlag = words(1, \"orient/flag\");\n const arcPlan = plan1d(graph.arcCount, wg, ctx.caps);\n const p1 = scope.params(COO_PARAMS, { count: graph.arcCount, pad0: 0, pad1: 0, pad2: 0 });\n orient.dispatch(\n pass,\n orient.bind({ rowPtr: graph.rowPtr, colIdx: graph.colIdx, src: graph.src, flags, P: p1.binding }),\n arcPlan,\n [p1.offset],\n );\n compact.record(pass, {\n queue: graph.src,\n flags,\n count: graph.arcCount,\n out: oSrc,\n outCount: scratch,\n outIndex: 0,\n });\n compact.record(pass, {\n queue: graph.colIdx,\n flags,\n count: graph.arcCount,\n out: oDst,\n outCount: scratch,\n outIndex: 0,\n });\n cooToCsr.record(pass, {\n src: oSrc,\n dst: oDst,\n weights: null,\n count: oriented,\n n,\n sortedInput: true,\n out: { rowPtr: oRowPtr, colIdx: oColIdx, weights: null, flag: oFlag },\n });\n orientedFlag = oFlag;\n const p2 = scope.params(COO_PARAMS, { count: oriented, pad0: 0, pad1: 0, pad2: 0 });\n intersect.dispatch(\n pass,\n intersect.bind({ rowPtr: oRowPtr, colIdx: oColIdx, src: oSrc, counts, P: p2.binding }),\n plan1d(oriented, wg, ctx.caps),\n [p2.offset],\n );\n }\n batch.endPass();\n const countsRequest = batch.readback(counts.buffer, 0, countsBytes);\n const rowsRequest = batch.readback(graph.rowPtr.buffer, 0, 4 * (n + 1));\n const orientedRequest = orientedFlag === null ? null : batch.readback(orientedFlag.buffer, 0, 4);\n scope.flush();\n const submitted = batch.submit();\n const bytes = await submitted.readback;\n ctx.assertReady();\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", `${ALGORITHM}: the signal was aborted`, { batchId: submitted.id });\n }\n assertBuildSorted(bytes, build, ALGORITHM);\n if (orientedRequest !== null && new Uint32Array(bytes, orientedRequest.offset, 1)[0] !== 0) {\n throw new WebGpuGraphError(\n \"E_VALIDATION\",\n `${ALGORITHM}: the oriented arcs reached cooToCsr out of order`,\n {\n label: `${ALGORITHM}/oriented`,\n message: \"the sorted-input precondition of cooToCsr failed on the device\",\n },\n );\n }\n const perNode = dest ?? new Uint32Array(n);\n perNode.set(new Uint32Array(bytes, countsRequest.offset, n));\n const rowPtr = new Uint32Array(bytes, rowsRequest.offset, n + 1);\n options?.onProgress?.(1, 1);\n return epilogue(perNode, rowPtr);\n } finally {\n scope.dispose();\n }\n}\n","/**\n * 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\n * the caller's pass, the cell keys (G1, `grid-cell-key`), the stable sort by key (G2: `radixSort` at GRID_SORT_BITS,\n * or `countingSortByKey` when the caller asks for the set-deterministic path) and the per-cell histogram with its\n * exclusive scan (G3: the `histogram` kernel over `cellKey` and the `scan` of it; DEP-P4-I names no grid-specific\n * id). `cellHist` and `cellStart` hold `histWords = cells + 2^dim + 1` words: every real cell, the 2^dim outside\n * pseudo-cells (one per orthant about the grid centre, issue #90) from index `cells`, and one more so\n * `cellStart[histWords - 1] === n` closes the last range. Every zeroing is a `fill` dispatch inside the\n * pass (PD-12), never an encoder clear.\n *\n * The named grid buffers (`cellKey`, `cellVal`, `sortedKey`, `sortedIdx`, `cellHist`, `cellStart`) are the caller's\n * (the model's `BufferSpec`s, so `inspect(name)` reaches them); the anonymous scratch of the sort (the digit-major\n * table and its scan, the counting-sort cursor) is taken from the scope ONCE at bind() so the sub-kernels bind the\n * same buffers every iteration and `Kernel.bind`'s identity cache holds (PD-11). `src/primitives/**` never imports\n * `src/context.ts`.\n */\n\nimport { GRID_COARSEST_SIDE, GRID_MIN_SIDE, GRID_SORT_BITS } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { kernelSpec } from \"../kernels.js\";\nimport { type ResolvedLayoutTuning } from \"../types/layout.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport {\n type CountingSortPlanner,\n type HistogramPlanner,\n prepareCountingSort,\n prepareHistogram,\n} from \"./histogram.js\";\nimport { prepareRadixSort, radixHistBytes, type RadixSortPlanner } from \"./radix-sort.js\";\nimport { type ReduceScope } from \"./reduce.js\";\nimport { prepareScan, type ScanPlanner } from \"./scan.js\";\n\n/** The grid's geometry (spec 7.7 geometry table; PD-9), computed on the host once per load. */\nexport interface GridSpec {\n /** 2 or 3. */\n readonly dim: 2 | 3;\n /** The finest side `G` per axis: a power of two in [GRID_MIN_SIDE, floorPow2(gridMax)]. */\n readonly g: number;\n /** `log2(G / GRID_COARSEST_SIDE) + 1`. */\n readonly levels: number;\n /** `G^dim` finest cells; the outside pseudo-cells are indices `cells .. cells + outsideCells - 1`. */\n readonly cells: number;\n /** `2^dim`: one outside pseudo-cell per orthant about the grid centre (issue #90). */\n readonly outsideCells: number;\n /** `cells + outsideCells + 1`: the length of `cellHist` / `cellStart`. */\n readonly histWords: number;\n /** The first cell of every level inside the pyramid: `levelOffsets[0] = 0`, level 0 holds `cells + outsideCells` (the pseudo-cells last), level L `(G / 2^L)^dim`. */\n readonly levelOffsets: readonly number[];\n /** Every level's cells together: `levelOffsets[levels - 1] + GRID_COARSEST_SIDE^dim`. */\n readonly pyramidCells: number;\n /** Whether G2 is the stable radix sort (true) or the set-deterministic counting sort (false). */\n readonly deterministic: boolean;\n}\n\n/**\n * The smallest power of two >= x (by doubling; 1 for x <= 1).\n * @param x - a non-negative number\n * @returns the power of two\n */\nfunction nextPow2(x: number): number {\n let p = 1;\n while (p < x) {\n p *= 2;\n }\n return p;\n}\n\n/**\n * The largest power of two <= x (by doubling; 1 for x < 2).\n * @param x - a number >= 1\n * @returns the power of two\n */\nfunction floorPow2(x: number): number {\n let p = 1;\n while (p * 2 <= x) {\n p *= 2;\n }\n return p;\n}\n\n/**\n * The grid of `n` nodes in `dim` dimensions under the tuning (spec 7.7 geometry table; PD-9): `G = clamp(nextPow2(2 *\n * ceil(n^(1 / dim))), GRID_MIN_SIDE, floorPow2(gridMax))` where `gridMax` is `gridMax2D` or `gridMax3D`, rounded DOWN\n * to a power of two so every level's side is an integer (512 and 128 stay; 100 becomes 64); `levels = log2(G /\n * GRID_COARSEST_SIDE) + 1`. At the caps: 349,524 pyramid cells in 2D, 2,396,744 in 3D (the design's counts plus the\n * 2^dim pseudo-cells).\n * @param n - the node count (>= 0)\n * @param dim - 2 or 3\n * @param tuning - the resolved layout tuning (`gridMax2D`, `gridMax3D`, `deterministic`)\n * @returns the spec\n */\nexport function gridSpecFor(\n n: number,\n dim: 2 | 3,\n tuning: Pick<ResolvedLayoutTuning, \"gridMax2D\" | \"gridMax3D\" | \"deterministic\">,\n): GridSpec {\n const gridMax = dim === 3 ? tuning.gridMax3D : tuning.gridMax2D;\n const side = dim === 3 ? Math.cbrt(n) : Math.sqrt(n);\n const cap = Math.max(GRID_MIN_SIDE, floorPow2(Math.max(1, gridMax)));\n const g = Math.min(cap, Math.max(GRID_MIN_SIDE, nextPow2(2 * Math.ceil(side))));\n let levels = 1;\n for (let s = g; s > GRID_COARSEST_SIDE; s /= 2) {\n levels++;\n }\n const cells = g ** dim;\n const outsideCells = 2 ** dim;\n const levelOffsets: number[] = [0];\n let s = g;\n for (let level = 0; level + 1 < levels; level++) {\n levelOffsets.push(levelOffsets[level] + s ** dim + (level === 0 ? outsideCells : 0));\n s /= 2;\n }\n return {\n dim,\n g,\n levels,\n cells,\n outsideCells,\n histWords: cells + outsideCells + 1,\n levelOffsets: Object.freeze(levelOffsets),\n pyramidCells: levelOffsets[levels - 1] + GRID_COARSEST_SIDE ** dim,\n deterministic: tuning.deterministic,\n };\n}\n\n/**\n * The bytes of the pyramid (spec 7.7: 16 B per cell, every level, the pseudo-cells included): 38,347,904 at the 3D cap.\n * @param spec - the grid\n * @returns the byte length\n */\nexport function gridPyramidBytes(spec: GridSpec): number {\n return 16 * spec.pyramidCells;\n}\n\n/**\n * The buffers the build reads and writes (the model's named buffers; `state` and `params` are the blocks G1 reads).\n * The parameter type of GridBuildPlanner.bind (knip: exported for the signature, not imported by name).\n * @public\n */\nexport interface GridBuildBindings {\n /** `array<vec4f>` positions (xyz, mass). */\n readonly pos: Binding;\n /** The `Fa2State` block (`gridMin`, `invCellSize`), read-only here. */\n readonly state: Binding;\n /** The `Fa2Params` uniform ring (`n`, `dim`, `gridMax`); `record()` takes the iteration's dynamic offset. */\n readonly params: Binding;\n /**\n * `n` words: G1's keys, node-indexed until G2. On the deterministic path the radix sort ping-pongs through this\n * pair (PD-5: three passes, the even one writes the input pair), so after G2 `cellKey` / `cellVal` hold the\n * sort's last even-pass intermediate -- a permutation of the keys, which is why the histogram recorded after it\n * counts the same multiset; the node-indexed keys of an iteration are read through `upTo: \"G1\"`. The counting\n * path never writes them.\n */\n readonly cellKey: Binding;\n /** `n` words: G1's values (`i`); the sort's working pair with `cellKey`. */\n readonly cellVal: Binding;\n /** `n` words: the sorted keys (the radix path's result pair; unused by the counting path). */\n readonly sortedKey: Binding;\n /** `n` words: the sorted node indices. */\n readonly sortedIdx: Binding;\n /** `histWords` (`cells + 2^dim + 1`) words: the per-cell counts. */\n readonly cellHist: Binding;\n /** `histWords` (`cells + 2^dim + 1`) words: the exclusive scan of `cellHist`. */\n readonly cellStart: Binding;\n}\n\n/** Where `record()` stops: after the keys (G1), after the sort (G2) or after the histogram and its scan (G3, the default). */\nexport type GridBuildStage = \"G1\" | \"G2\" | \"G3\";\n\n/** A prepared grid build (spec 7.7 G1-G3): binds once per load, records the stages of one iteration into a pass. */\nexport interface GridBuildPlanner {\n /**\n * Binds the named buffers and takes the sort's scratch from the scope, sized by `cellKey` (its word count is the\n * node capacity; PD-11); called once per load (a second call rebinds and takes fresh scratch, so it belongs to a\n * reload, never to an iteration).\n * @param bindings - the buffers\n */\n bind(bindings: GridBuildBindings): void;\n /**\n * Records G1, G2 and G3 for `n` nodes at the `Fa2Params` slot `paramsOffset`; `upTo` stops after the named\n * stage (the counting path has no separate G2 stop: its sort and histogram are one sequence, so \"G2\" runs it all).\n * @param pass - the compute pass\n * @param n - the node count (in [1, the capacity]; the caller never records a grid iteration for an empty graph)\n * @param paramsOffset - the dynamic offset of this iteration's `Fa2Params`\n * @param upTo - the last stage to record (default \"G3\")\n */\n record(pass: GPUComputePassEncoder, n: number, paramsOffset: number, upTo?: GridBuildStage): void;\n /** Dispatches the last record() issued. */\n readonly lastDispatches: number;\n}\n\n/** The G2 / G3 planners: the stable radix path (PD-5) or the set-deterministic counting path. */\ntype SortPath =\n | {\n readonly kind: \"radix\";\n readonly radix: RadixSortPlanner;\n readonly histogram: HistogramPlanner;\n readonly scan: ScanPlanner;\n }\n | { readonly kind: \"counting\"; readonly counting: CountingSortPlanner };\n\n/**\n * Prepares the grid build's pipelines over a scope (G1 and the sort / histogram / scan planners it composes; compiles\n * once) so bind() and record() are synchronous. The planner lives exactly as long as the scope.\n * @param scope - the caller's scope (device, caps, cache, scratch, params)\n * @param spec - the grid\n * @returns the planner\n */\nexport async function prepareGridBuild(scope: ReduceScope, spec: GridSpec): Promise<GridBuildPlanner> {\n const cellKey = await scope.pipelines.kernel(kernelSpec(\"grid-cell-key\"));\n const path: SortPath = spec.deterministic\n ? {\n kind: \"radix\",\n radix: await prepareRadixSort(scope),\n histogram: await prepareHistogram(scope),\n scan: await prepareScan(scope),\n }\n : { kind: \"counting\", counting: await prepareCountingSort(scope) };\n return new GridBuildPlannerImpl(scope, spec, cellKey, path);\n}\n\n/** What bind() prepared: the buffers, the node capacity and the sort's scratch (the radix table and its scan, or the counting-sort cursor and an unused twin). */\ninterface Bound {\n readonly bindings: GridBuildBindings;\n readonly capacity: number;\n readonly scratchA: Binding;\n readonly scratchB: Binding;\n}\n\n/** The planner: G1 and the composed sort / histogram / scan over one scope. */\nclass GridBuildPlannerImpl implements GridBuildPlanner {\n private readonly scope: ReduceScope;\n private readonly spec: GridSpec;\n private readonly cellKey: Kernel;\n private readonly path: SortPath;\n private bound: Bound | null = null;\n private dispatches = 0;\n\n /**\n * Wraps the resolved kernel and planners; use prepareGridBuild().\n * @param scope - the caller's scope\n * @param spec - the grid\n * @param cellKey - the `grid-cell-key` kernel\n * @param path - the sort path\n */\n constructor(scope: ReduceScope, spec: GridSpec, cellKey: Kernel, path: SortPath) {\n this.scope = scope;\n this.spec = spec;\n this.cellKey = cellKey;\n this.path = path;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns the count\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Binds the buffers and takes the sort's scratch (see the interface).\n * @param bindings - the buffers\n */\n bind(bindings: GridBuildBindings): void {\n const capacity = Math.floor(bindings.cellKey.size / 4);\n if (capacity < 1) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"gridBuild: cellKey must hold at least one word\", {\n argument: \"cellKey\",\n value: bindings.cellKey.size,\n expected: 4,\n });\n }\n const words =\n this.path.kind === \"radix\" ? radixHistBytes(capacity, this.scope.workgroupSize) / 4 : this.spec.histWords;\n this.bound = {\n bindings,\n capacity,\n scratchA: this.scratch(words, \"grid/sort-scratch-a\"),\n scratchB: this.scratch(words, \"grid/sort-scratch-b\"),\n };\n }\n\n /**\n * Records the stages (see the interface).\n * @param pass - the compute pass\n * @param n - the node count\n * @param paramsOffset - the `Fa2Params` dynamic offset\n * @param upTo - the last stage\n */\n record(pass: GPUComputePassEncoder, n: number, paramsOffset: number, upTo?: GridBuildStage): void {\n const { bound } = this;\n if (bound === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"gridBuild: record() before bind()\", { argument: \"bind\" });\n }\n if (!Number.isSafeInteger(n) || n < 1 || n > bound.capacity) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"gridBuild: n must be an integer in [1, the capacity]\", {\n argument: \"n\",\n value: n,\n expected: bound.capacity,\n });\n }\n const stop = upTo ?? \"G3\";\n const b = bound.bindings;\n const keyBound = this.cellKey.bind({\n pos: b.pos,\n S: b.state,\n cellKey: b.cellKey,\n cellVal: b.cellVal,\n P: b.params,\n });\n this.cellKey.dispatch(pass, keyBound, plan1d(n, this.scope.workgroupSize, this.scope.caps), [paramsOffset]);\n this.dispatches = 1;\n if (stop === \"G1\") {\n return;\n }\n const { histWords: bins } = this.spec;\n if (this.path.kind === \"counting\") {\n const { counting } = this.path;\n const scratch = { hist: b.cellHist, cursor: bound.scratchA };\n counting.record(pass, b.cellKey, n, bins, scratch, b.sortedIdx, b.cellStart);\n this.dispatches += counting.lastDispatches;\n return;\n }\n const { radix, histogram, scan } = this.path;\n radix.record(pass, b.cellKey, b.cellVal, n, GRID_SORT_BITS, {\n keys: b.sortedKey,\n vals: b.sortedIdx,\n hist: bound.scratchA,\n offsets: bound.scratchB,\n });\n this.dispatches += radix.lastDispatches;\n if (stop === \"G2\") {\n return;\n }\n histogram.record(pass, b.cellKey, n, bins, b.cellHist);\n scan.record(pass, b.cellHist, bins, b.cellStart);\n this.dispatches += histogram.lastDispatches + scan.lastDispatches;\n }\n\n /**\n * A scratch of `words` u32 from the scope, bound whole.\n * @param words - the word count (>= 1)\n * @param label - the scratch label\n * @returns the binding\n */\n private scratch(words: number, label: string): Binding {\n const size = 4 * Math.max(1, words);\n const buffer = this.scope.scratch(size, label);\n return { buffer, offset: 0, size, window: null };\n }\n}\n","/**\n * The CPU port's random number generator, bit for bit, and the NaN-row seeding both paths share (spec 7.2 \"Initial\n * positions\", 9.3 seedPositions, 7.14 `pos`, 7.19 topology change): a seed gives the same start on the CPU and the\n * GPU because both write the same f32 values in index order. The package carries its own copy of the LCG for its\n * whole life (D27: it cannot import @graphty/layout at runtime). The CANONICAL copy is\n * layout/src/simulation/seed.ts; this one is cross-tested against it, bit for bit, by\n * test/layouts/seed-cross.test.ts (W1b, Task M5b-T3).\n */\n\nimport type { F32, GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { WebGpuGraphError } from \"../errors.js\";\n\n/** The CPU port's LCG constants (layout/src/utils/random.ts): m = 2^35 - 31, a = 185852, c = 1. */\nexport const LCG_M = 34359738337;\n/** The multiplier a of the port's LCG. */\nexport const LCG_A = 185852;\n/** The increment c of the port's LCG. */\nexport const LCG_C = 1;\n\n/**\n * The port's RandomNumberGenerator, bit for bit: `seed || Math.floor(Math.random() * 1000000)` (seed 0 / null =\n * unseeded, the quirk preserved), state = seed % m, next = (a * state + c) % m, value = state / m. The product\n * a * state stays below 2^53 (a < 2^18, state < 2^35), so every step is exact in f64, as it is in the port.\n */\nexport class Lcg {\n /** The seed actually used (a random one when unseeded). */\n readonly seed: number;\n\n private state: number;\n\n /**\n * Creates the generator; a seed of 0, -0, NaN or null means unseeded (the port's `seed || random` quirk).\n * @param seed - the seed, or null for a random seed\n */\n constructor(seed: number | null) {\n this.seed = seed === null || seed === 0 || Number.isNaN(seed) ? Math.floor(Math.random() * 1000000) : seed;\n this.state = this.seed % LCG_M;\n }\n\n /**\n * Next value in [0, 1).\n * @returns state / m after one LCG step\n */\n next(): number {\n this.state = (LCG_A * this.state + LCG_C) % LCG_M;\n return this.state / LCG_M;\n }\n}\n\n/**\n * The three center components of a CommonLayoutOptions.center (missing components are 0).\n * @param center - the caller's center, or null\n * @returns [x, y, z]; E_INVALID_ARGUMENT when a component is not finite\n */\nfunction resolveCenter(center: ArrayLike<number> | null): [number, number, number] {\n const out: [number, number, number] = [0, 0, 0];\n if (center === null) {\n return out;\n }\n for (let axis = 0; axis < 3 && axis < center.length; axis++) {\n const v = center[axis];\n if (!Number.isFinite(v)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `center[${axis}] is not finite`, {\n argument: \"center\",\n value: v,\n expected: \"finite components\",\n });\n }\n out[axis] = v;\n }\n return out;\n}\n\n/**\n * Seeds the unseeded rows of the owner's stride-3 SCENE array in index order (spec 9.3 seedPositions, 7.14 `pos`,\n * 7.19 topology change): a row is unseeded when any of its `dim` components is not finite; every such component\n * draws one LCG value; when NO row is fully finite the draw is uniform in [-1, 1) layout units per axis (`range:\n * \"fa2\"`; `\"fr\"` is [0, 1)), otherwise uniform inside the [min, max] box of the finite components per axis,\n * converted to layout units (an axis with no finite value falls back to the range box); the value is written as\n * `v * scale + center[axis]`, which for scale 1 / center 0 is bit-identical to the port's `u * 2 - 1` (resp. `u`);\n * in 2D the third component of a seeded row is written as center[2]. An axis whose finite box has zero width (one\n * finite row, or every finite row sharing that coordinate) is padded to the range box's width centered on it, so\n * the drawn rows never all land on one point or one line. Finite components are never changed and a\n * fully finite row is never touched. No random number is drawn when nothing needs seeding.\n * PLAN DECISION 12 (P3-T1): the box is taken over every finite COMPONENT (the port's rule), not over the fully\n * finite ROWS only; the two differ only when a partially finite row's finite axis lies outside the fully finite\n * rows' box (pinned by test/layouts/seed.test.ts). PLAN DECISION 13: a 2D row whose x and y are finite is seeded\n * whatever its z holds.\n * @param s - the snapshot (nodeCount rows)\n * @param positions - the owner's stride-3 scene-unit array, length 3 * nodeCount, modified in place\n * @param seed - the LCG seed (0 / null = unseeded, the port's quirk)\n * @param dim - 2 or 3\n * @param scale - the scene scale (> 0)\n * @param center - the scene center, or null for the origin\n * @param range - \"fa2\" for [-1, 1), \"fr\" for [0, 1)\n */\nexport function seedPositions(\n s: GraphSnapshot,\n positions: F32,\n seed: number | null,\n dim: 2 | 3,\n scale: number,\n center: ArrayLike<number> | null,\n range: \"fa2\" | \"fr\",\n): void {\n const n = s.nodeCount;\n if (dim !== 2 && dim !== 3) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `dim must be 2 or 3, got ${String(dim)}`, {\n argument: \"dim\",\n value: dim,\n expected: \"2 or 3\",\n });\n }\n if (positions.length !== 3 * n) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `positions has ${positions.length} entries, expected ${3 * n}`,\n {\n argument: \"positions\",\n value: positions.length,\n expected: 3 * n,\n },\n );\n }\n if (!Number.isFinite(scale) || scale <= 0) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `scale must be a finite number > 0, got ${scale}`, {\n argument: \"scale\",\n value: scale,\n expected: \"a finite number > 0\",\n });\n }\n const c = resolveCenter(center);\n\n // classify the rows and collect the per-axis box of the finite components (scene units)\n const lo = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];\n const hi = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];\n let finiteRows = 0;\n let unseededRows = 0;\n for (let i = 0; i < n; i++) {\n let finite = true;\n for (let axis = 0; axis < dim; axis++) {\n const v = positions[3 * i + axis];\n if (Number.isFinite(v)) {\n if (v < lo[axis]) {\n lo[axis] = v;\n }\n if (v > hi[axis]) {\n hi[axis] = v;\n }\n } else {\n finite = false;\n }\n }\n if (finite) {\n finiteRows++;\n } else {\n unseededRows++;\n }\n }\n if (unseededRows === 0) {\n return;\n }\n\n // the per-axis draw box in layout units\n const rangeLo = range === \"fr\" ? 0 : -1;\n const rangeHi = 1;\n const boxLo = [rangeLo, rangeLo, rangeLo];\n const boxHi = [rangeHi, rangeHi, rangeHi];\n if (finiteRows > 0) {\n for (let axis = 0; axis < dim; axis++) {\n if (Number.isFinite(lo[axis]) && Number.isFinite(hi[axis])) {\n boxLo[axis] = (lo[axis] - c[axis]) / scale;\n boxHi[axis] = (hi[axis] - c[axis]) / scale;\n if (boxLo[axis] === boxHi[axis]) {\n // a zero-width axis (one finite row, or every finite row on one line) would stack every drawn\n // row on that coordinate: pad it to the range box's width, centered on it\n const half = (rangeHi - rangeLo) / 2;\n boxLo[axis] -= half;\n boxHi[axis] += half;\n }\n }\n }\n }\n\n const rng = new Lcg(seed);\n for (let i = 0; i < n; i++) {\n let unseeded = false;\n for (let axis = 0; axis < dim; axis++) {\n if (!Number.isFinite(positions[3 * i + axis])) {\n unseeded = true;\n }\n }\n if (!unseeded) {\n continue;\n }\n for (let axis = 0; axis < dim; axis++) {\n const at = 3 * i + axis;\n if (!Number.isFinite(positions[at])) {\n const u = rng.next();\n const v = boxLo[axis] + u * (boxHi[axis] - boxLo[axis]);\n positions[at] = v * scale + c[axis];\n }\n }\n if (dim === 2) {\n positions[3 * i + 2] = c[2];\n }\n }\n}\n","/**\n * The shared layout state machine (spec 7.19): the buffers every model shares (positions, scenePositions, fixed,\n * partials, state + trace), the in-flight batches and their readbacks, the settle window, the fixed mask and the\n * setPosition override list (spec 7.12), the trace and the batch driver; consumes a ForceModel by composition (the\n * per-model kernel sequence, buffers, overrides, per-iteration params, controller hooks and stats decoding).\n * Positions are layout units on the device and scene units in the owner's array (spec 7.18): load() repacks\n * (scene - center) / scale into vec4f with the mass in .w (D23); the model's toScene stage, recorded once per batch\n * on the last iteration (PLAN DECISION 2), writes p * scale + center back into scenePositions.\n */\n\nimport { type F32, type GraphSnapshot, makeMask, maskTest, type NodeMask, type U32 } from \"@graphty/graph-format\";\n\nimport {\n FA2_DEFAULTS,\n FA2_FLAG_FIRST,\n MAX_1D_ITEMS,\n MAX_ITERATIONS_PER_STEP,\n PARTIAL_BYTES,\n STATE_HEADER_BYTES,\n UNIFORM_SLOT_BYTES,\n} from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { hasErrorCode, WebGpuGraphError } from \"../errors.js\";\nimport { CommandBatch, type ReadbackRequest, type SubmittedBatch } from \"../kernel/batch.js\";\nimport { type PipelineCache } from \"../kernel/pipeline-cache.js\";\nimport { type PassTiming } from \"../kernel/profiler.js\";\nimport { type UniformBlock, type UniformFieldType, type UniformValues } from \"../kernel/struct-block.js\";\nimport { UniformRing } from \"../kernel/uniform-ring.js\";\nimport { type WgslModuleSpec } from \"../kernel/wgsl.js\";\nimport { graphOverrides } from \"../kernels.js\";\nimport { type BufferPool } from \"../memory/buffer-pool.js\";\nimport { type ArrayBinding, type CoreBinding } from \"../memory/residency.js\";\nimport { type DegreeTiers, degreeTiersOf } from \"../primitives/core-shape.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type PlanCaps } from \"../types/context.js\";\nimport {\n type GpuLayoutSimulation,\n type LayoutStatsBase,\n type ResolvedLayoutTuning,\n type RunOptions,\n} from \"../types/layout.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type CommonLayoutOptions, type SimulationOptions } from \"../types/options.js\";\nimport { type ResolvedWeights } from \"./inputs.js\";\nimport { seedPositions } from \"./seed.js\";\n\n// ============================================================ the model hook interface (contract 3.13)\n\n/** A model-owned buffer beyond the shared set (spec 7.19: oldForce, velocity, the grid tier's). */\nexport interface BufferSpec {\n readonly name: string;\n readonly byteLength: number;\n readonly usage: number;\n readonly zero: boolean;\n}\n\n/** Host writes into the state header collected between submits (spec 7.19 onLoad / onReheat / onSetParams). */\nexport interface StateWriter {\n /** Queues a field write (flushed by one writeBuffer before the next submit; also applied to the host shadow immediately). */\n set(field: string, value: number | readonly number[]): void;\n /** The host shadow of a field (last known value). */\n get(field: string): number | readonly number[];\n}\n\n/** What a model gets at bind time (after load() / a resize): the graph, the shared and model buffers, the ring, the cache. */\nexport interface ModelResources {\n readonly device: GPUDevice;\n readonly caps: PlanCaps;\n readonly pipelines: PipelineCache;\n readonly core: CoreBinding;\n /** `tiers.perm`, or null when no row has degree >= 32 (P4 PD-7: the rowPtr dummy is bound and USE_PERM is false). */\n readonly perm: Binding | null;\n /**\n * The degree tiers of the snapshot's degreeOrder view (the perm binding and the CPU-side segment offsets\n * [0, hiEnd, midEnd, lowEnd, n]), or null when no row has degree >= 32 -- then every K2 dispatch is the\n * thread-per-row TIER 0 over node indices, as before P4.\n */\n readonly tiers: DegreeTiers | null;\n /**\n * The RESOLVED weights binding (model.inputs(): source \"arcs\" -> core.weights (null on an unweighted snapshot),\n * \"column\" -> the registered ArrayBinding's binding, \"none\" -> null); group 0 is built as\n * graphBindings(core, perm, weights) (3.10).\n */\n readonly weights: Binding | null;\n readonly n: number;\n readonly dim: 2 | 3;\n readonly tier: \"exact\" | \"grid\";\n readonly ring: UniformRing;\n /** The context's buffer pool (the grid stage's lease of sort scratch draws on it, P4 PD-11). */\n readonly pool: BufferPool;\n /** A shared or model-owned buffer by name: \"positions\", \"scenePositions\", \"fixed\", \"partials\", \"state\", \"trace\", plus every BufferSpec name. */\n buffer(name: string): Binding;\n}\n\n/** The per-load inputs a model resolves from the snapshot and its options (mass into the `.w` lane; weights into the group-0 slot). */\nexport interface ModelInputs {\n readonly mass: F32;\n readonly weights: ResolvedWeights;\n /** A mask to apply at load (the FR `fixed` option, PD-6); validated against `ceil(n / 32)` words; absent / null leaves the words as they are (kept on a same-size reload, cleared on a resize, spec 7.12). */\n readonly fixed?: NodeMask | null | undefined;\n}\n\n/**\n * Spec 7.19 ForceModel (kind, buffers, overrides, paramsFor, recordIteration, onLoad, onReheat, onSetParams,\n * readStats) with SEVEN additions (CONTRACT DECISION, each with its reason): `stages` (the kernel stage names for\n * debugRunStages / inspect, spec 11.9 item 2); `params` (the model's uniform block, which must declare the shared\n * field names n, dim, flags, iterationIndex, seed, scale, center, settleThreshold, so the simulation can write\n * them); `state` and `trace` (the model's generated Fa2State / Fa2Trace blocks, so the simulation allocates,\n * initialises and decodes the state buffer through the model's own layouts, D20); `specs` (the module specs of an\n * override set, for warm() and the compile matrix); `bind` (the model compiles and binds after load(), when the\n * buffers exist); `inputs` (mass and weight resolution need the model's option names -- nodeMass / weight are\n * ForceAtlas2Options, not CommonLayoutOptions -- so the simulation calls it at load() and derives USE_PERM /\n * HAS_WEIGHTS from ModelResources, 3.10); and the optional `upTo` argument of `recordIteration` (truncates the\n * sequence after a stage, for debugRunStages / inspect). PLAN DECISION 4: the state block must declare centroid,\n * min, max (vec4f), rmsRadius, radius, meanDisplacement (f32), iteration, settledCount (u32) and fit in\n * STATE_HEADER_BYTES; the params block must declare the eight shared names with center a vec4f and fit in\n * UNIFORM_SLOT_BYTES. PLAN DECISION 6: paramsFor receives the GLOBAL iteration index; the shared fields win.\n * PLAN DECISION 2: recordIteration with `upTo` undefined records EVERY stage (toScene included); `upTo = <stage>`\n * stops after that stage.\n */\nexport interface ForceModel<Options, Stats extends LayoutStatsBase> {\n readonly kind: \"forceatlas2\" | \"fruchtermanReingold\" | \"springElectrical\";\n readonly stages: readonly string[];\n readonly params: UniformBlock;\n readonly state: UniformBlock;\n readonly trace: UniformBlock;\n buffers(n: number, dim: 2 | 3): readonly BufferSpec[];\n /** Called at load() before the upload: FA2 = { mass: resolveNodeMass(s, nodeMass), weights: resolveWeights(s, weight) }. */\n inputs(s: GraphSnapshot, options: Options): ModelInputs;\n /** The model's OWN override set; the simulation merges USE_PERM / HAS_WEIGHTS from graphOverrides(core, perm, resources.weights) before specs() / bind(). */\n overrides(options: Options): Readonly<Record<string, number | boolean>>;\n specs(overrides: Readonly<Record<string, number | boolean>>, subgroups: boolean): readonly WgslModuleSpec[];\n bind(resources: ModelResources, overrides: Readonly<Record<string, number | boolean>>): Promise<void>;\n paramsFor(iteration: number, options: Options): UniformValues;\n recordIteration(batch: CommandBatch, slot: number, tier: \"exact\" | \"grid\", upTo?: string): void;\n onLoad(state: StateWriter): void;\n onReheat(state: StateWriter): void;\n onSetParams(patch: Partial<Options>, state: StateWriter): void;\n readStats(state: DataView, trace: DataView): Stats;\n /** Releases what the model holds outside the simulation's buffers (the grid stage's lease, P4-T10); called by dispose() once every in-flight batch has settled. */\n dispose?(): void;\n}\n\n// ============================================================ module-private helpers\n\n/** The shared params fields (name, width) every model params block must declare (PLAN DECISION 4). */\nconst SHARED_PARAM_FIELDS: readonly (readonly [string, number])[] = [\n [\"n\", 1],\n [\"dim\", 1],\n [\"flags\", 1],\n [\"iterationIndex\", 1],\n [\"seed\", 1],\n [\"scale\", 1],\n [\"center\", 4],\n [\"settleThreshold\", 1],\n];\n\n/** The state fields (name, width) the simulation writes at load() and reads after every batch (PLAN DECISION 4). */\nconst SHARED_STATE_FIELDS: readonly (readonly [string, number])[] = [\n [\"centroid\", 4],\n [\"min\", 4],\n [\"max\", 4],\n [\"rmsRadius\", 1],\n [\"radius\", 1],\n [\"meanDisplacement\", 1],\n [\"iteration\", 1],\n [\"settledCount\", 1],\n];\n\n/** The names of the shared buffers a BufferSpec may not reuse. */\nconst SHARED_BUFFER_NAMES: readonly string[] = [\"positions\", \"scenePositions\", \"fixed\", \"partials\", \"state\", \"trace\"];\n\n/** The buffers inspect() returns as Uint32Array: the mask, the trace records and the grid tier's index / count arrays (P4). */\nconst U32_BUFFER_NAMES: ReadonlySet<string> = new Set([\n \"fixed\",\n \"trace\",\n \"cellKey\",\n \"cellVal\",\n \"sortedKey\",\n \"sortedIdx\",\n \"cellHist\",\n \"cellStart\",\n \"hubList\",\n \"hubCounters\",\n]);\n\n/** The per-batch epilogue stage: iterations 0..k-2 stop after the stage that precedes it (PLAN DECISION 2). */\nconst EPILOGUE_STAGE = \"toScene\";\n\nlet simulationCounter = 0;\n\n/**\n * An E_INVALID_ARGUMENT with the documented details shape.\n * @param argument - the argument name\n * @param value - the offending value\n * @param expected - what was expected\n * @param message - the message\n * @returns the error\n */\nfunction invalidArgument(argument: string, value: unknown, expected: unknown, message: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_INVALID_ARGUMENT\", message, { argument, value, expected });\n}\n\n/**\n * The E_DISPOSED of a simulation.\n * @param label - the simulation label\n * @returns the error\n */\nfunction disposedError(label: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_DISPOSED\", `${label} is disposed`, { label });\n}\n\n/**\n * Coerces a caught value to an Error for Promise rejections.\n * @param err - the caught value\n * @returns the value when it is an Error, else a wrapping Error\n */\nfunction asError(err: unknown): Error {\n if (err instanceof Error) {\n return err;\n }\n return new Error(typeof err === \"string\" ? err : \"unknown error\");\n}\n\n/**\n * Reads a field of an option record the generic type does not name (maxIter, iterations, nodeSize).\n * @param record - the options or patch\n * @param key - the field name\n * @returns the value, or undefined\n */\nfunction optionField(record: object, key: string): unknown {\n return (record as Record<string, unknown>)[key];\n}\n\n/**\n * The number of scalars of a uniform field type.\n * @param type - the field type\n * @returns 1, 2 or 4\n */\nfunction fieldWidth(type: UniformFieldType): number {\n switch (type) {\n case \"u32\":\n case \"i32\":\n case \"f32\":\n return 1;\n case \"vec2f\":\n case \"vec2u\":\n return 2;\n case \"vec4f\":\n case \"vec4u\":\n return 4;\n default:\n throw invalidArgument(\"type\", type, \"a UniformFieldType\", \"unknown uniform field type\");\n }\n}\n\n/**\n * The type of a block field, or null when the block does not declare it.\n * @param block - the block\n * @param field - the field name\n * @returns the type or null\n */\nfunction fieldTypeOrNull(block: UniformBlock, field: string): UniformFieldType | null {\n for (const [name, type] of block.fields) {\n if (name === field) {\n return type;\n }\n }\n return null;\n}\n\n/**\n * The type of a block field.\n * @param block - the block\n * @param field - the field name\n * @returns the type; E_INVALID_ARGUMENT when the block does not declare the field\n */\nfunction fieldTypeOf(block: UniformBlock, field: string): UniformFieldType {\n const type = fieldTypeOrNull(block, field);\n if (type === null) {\n throw invalidArgument(\n \"field\",\n field,\n block.fields.map((f) => f[0]),\n `block ${block.name} has no field ${field}`,\n );\n }\n return type;\n}\n\n/**\n * Asserts a block declares every (name, width) pair (PLAN DECISION 4).\n * @param block - the block\n * @param required - the required fields\n * @param what - \"model.params\" or \"model.state\", for the error\n */\nfunction requireFields(block: UniformBlock, required: readonly (readonly [string, number])[], what: string): void {\n for (const [field, width] of required) {\n const type = fieldTypeOrNull(block, field);\n if (type === null) {\n throw invalidArgument(\n what,\n field,\n required.map((r) => r[0]),\n `${what} block ${block.name} must declare ${field}`,\n );\n }\n if (fieldWidth(type) !== width) {\n throw invalidArgument(\n what,\n field,\n `a field of width ${width}`,\n `${what}.${field} must have width ${width}`,\n );\n }\n }\n}\n\n/**\n * A stable string of an override record, for the law-change comparison of setParams.\n * @param record - the overrides\n * @returns the JSON of the sorted entries\n */\nfunction stableKey(record: Readonly<Record<string, number | boolean>>): string {\n return JSON.stringify(\n Object.keys(record)\n .sort()\n .map((k) => [k, record[k]]),\n );\n}\n\n/**\n * The stats record with msPerIteration filled by the simulation (PLAN DECISION 3).\n * @param stats - the model's record\n * @param msPerIteration - the measured value\n * @returns the record\n */\nfunction withMs<S extends LayoutStatsBase>(stats: S, msPerIteration: number | null): S {\n return { ...stats, msPerIteration };\n}\n\n/**\n * True for a SharedArrayBuffer (the package never writes into one, spec 5.7).\n * @param buffer - the backing buffer\n * @returns true when shared\n */\nfunction isSharedBuffer(buffer: ArrayBufferLike): boolean {\n return typeof SharedArrayBuffer !== \"undefined\" && buffer instanceof SharedArrayBuffer;\n}\n\n/**\n * The validated scale of an option record (FA2_DEFAULTS.scale when absent).\n * @param options - the options\n * @returns the scale\n */\nfunction scaleOf(options: CommonLayoutOptions): number {\n const scale = options.scale ?? FA2_DEFAULTS.scale;\n if (!Number.isFinite(scale) || scale <= 0) {\n throw invalidArgument(\"scale\", scale, \"a finite number > 0\", `scale must be a finite number > 0, got ${scale}`);\n }\n return scale;\n}\n\n/**\n * The validated center of an option record (missing components are 0).\n * @param options - the options\n * @returns [x, y, z]\n */\nfunction centerOf(options: CommonLayoutOptions): [number, number, number] {\n const out: [number, number, number] = [0, 0, 0];\n const { center } = options;\n if (center === undefined) {\n return out;\n }\n for (let axis = 0; axis < 3 && axis < center.length; axis++) {\n const v = center[axis];\n if (!Number.isFinite(v)) {\n throw invalidArgument(\"center\", v, \"finite components\", `center[${axis}] is not finite`);\n }\n out[axis] = v;\n }\n return out;\n}\n\n/**\n * The repulsion tier of a node count under a tuning (PLAN DECISION 11; spec 7.8: `\"auto\"` by `n` alone). Exported\n * so a model's `buffers(n, dim)` decides the tier by the same rule `load()` applies (P4 PD-18).\n * @param tuning - the resolved tuning\n * @param n - the node count\n * @returns \"exact\" or \"grid\"\n */\nexport function tierFor(tuning: ResolvedLayoutTuning, n: number): \"exact\" | \"grid\" {\n if (tuning.repulsion === \"exact\") {\n return \"exact\";\n }\n if (tuning.repulsion === \"grid\") {\n return \"grid\";\n }\n return n <= tuning.exactMaxNodes ? \"exact\" : \"grid\";\n}\n\n/**\n * A whole-buffer binding.\n * @param buffer - the buffer\n * @param size - its byte length\n * @returns the binding\n */\nfunction wholeBinding(buffer: GPUBuffer, size: number): Binding {\n return { buffer, offset: 0, size, window: null };\n}\n\n/**\n * The host side of the state header (PLAN DECISION 5): a shadow of every field, a queue of the fields set since\n * the last flush, and the byte image the queued fields are copied from.\n */\nclass HeaderWriter implements StateWriter {\n private readonly block: UniformBlock;\n private readonly shadow = new Map<string, number | readonly number[]>();\n private readonly queued = new Map<string, number | readonly number[]>();\n\n /**\n * Creates a writer over a model's state block with every field 0.\n * @param block - the model's state block\n */\n constructor(block: UniformBlock) {\n this.block = block;\n this.reset();\n }\n\n /**\n * Queues a field write and applies it to the shadow.\n * @param field - the field name (E_INVALID_ARGUMENT when the block lacks it or the width differs)\n * @param value - a number for a scalar field, an array of the vector's width otherwise\n */\n set(field: string, value: number | readonly number[]): void {\n const width = fieldWidth(fieldTypeOf(this.block, field));\n const ok = width === 1 ? typeof value === \"number\" : typeof value !== \"number\" && value.length === width;\n if (!ok) {\n throw invalidArgument(\n \"value\",\n value,\n `a value of width ${width}`,\n `state field ${field} takes a value of width ${width}`,\n );\n }\n this.shadow.set(field, value);\n this.queued.set(field, value);\n }\n\n /**\n * The host shadow of a field: the last value set, or the last landed header's value.\n * @param field - the field name\n * @returns the value\n */\n get(field: string): number | readonly number[] {\n const value = this.shadow.get(field);\n if (value === undefined) {\n throw invalidArgument(\n \"field\",\n field,\n this.block.fields.map((f) => f[0]),\n `state block has no field ${field}`,\n );\n }\n return value;\n }\n\n /** Every field back to 0 and the queue cleared (load()). */\n reset(): void {\n this.shadow.clear();\n this.queued.clear();\n const zero = this.block.read(new DataView(new ArrayBuffer(this.block.byteLength)));\n for (const [name, value] of Object.entries(zero)) {\n this.shadow.set(name, value);\n }\n }\n\n /**\n * The byte image of the shadow (the block's own writer, D20).\n * @returns block.byteLength bytes\n */\n headerBytes(): ArrayBuffer {\n const bytes = new ArrayBuffer(this.block.byteLength);\n this.block.write(new DataView(bytes), Object.fromEntries(this.shadow));\n return bytes;\n }\n\n /**\n * Refreshes the shadow from a landed header; a field set since the last flush keeps its queued value.\n * @param view - the landed header\n */\n absorb(view: DataView): void {\n for (const [name, value] of Object.entries(this.block.read(view))) {\n if (!this.queued.has(name)) {\n this.shadow.set(name, value);\n }\n }\n }\n\n /**\n * The fields set since the last flush; clears the queue.\n * @returns the field names\n */\n takeQueued(): string[] {\n const fields = [...this.queued.keys()];\n this.queued.clear();\n return fields;\n }\n\n /** Drops the queue (after load() wrote the whole header). */\n clearQueued(): void {\n this.queued.clear();\n }\n}\n\n/** One batch from the step() call that created it until its readback settled (PLAN DECISION 7). */\ninterface PendingBatch {\n readonly k: number;\n readonly generation: number;\n readonly promise: Promise<void>;\n readonly resolve: () => void;\n readonly reject: (error: Error) => void;\n id: number;\n submitted: SubmittedBatch | null;\n stale: boolean;\n startedAt: number;\n sceneOffset: number;\n stateOffset: number;\n profile: ReadbackRequest | null;\n}\n\n/**\n * A pending record whose promise the simulation settles.\n * @param k - iterations of the batch\n * @param generation - the generation at the step() call\n * @returns the record\n */\nfunction createPending(k: number, generation: number): PendingBatch {\n let resolveFn: () => void = () => undefined;\n let rejectFn: (error: Error) => void = () => undefined;\n const promise = new Promise<void>((resolve, reject) => {\n resolveFn = resolve;\n rejectFn = reject;\n });\n return {\n k,\n generation,\n promise,\n resolve: () => {\n resolveFn();\n },\n reject: (error: Error) => {\n rejectFn(error);\n },\n id: 0,\n submitted: null,\n stale: false,\n startedAt: 0,\n sceneOffset: 0,\n stateOffset: 0,\n profile: null,\n };\n}\n\n/** The simulation's buffers of one load() (spec 7.3) plus the name -> Binding map the model and inspect() read. */\ninterface SimulationBuffers {\n readonly positions: GPUBuffer;\n readonly scene: GPUBuffer;\n readonly fixed: GPUBuffer;\n readonly partials: GPUBuffer;\n readonly state: GPUBuffer;\n readonly model: ReadonlyMap<string, { readonly buffer: GPUBuffer; readonly spec: BufferSpec }>;\n readonly bindings: ReadonlyMap<string, Binding>;\n readonly traceRegionBytes: number;\n}\n\n/** The registered expanded weight column of the current load (re-expanded only when column.version changed). */\ninterface WeightsUpload {\n readonly serial: number;\n readonly column: object;\n readonly version: number;\n readonly data: F32;\n readonly upload: ArrayBinding;\n}\n\n// ============================================================ the simulation\n\n/**\n * The shared layout state machine (spec 7.19): buffers, in-flight batches, readback, settle window, fixed mask,\n * setPosition overrides, trace, batch driver; consumes a ForceModel by composition.\n */\nexport class ForceSimulation<\n Options extends CommonLayoutOptions & SimulationOptions,\n Stats extends LayoutStatsBase,\n> implements GpuLayoutSimulation<Options, Stats> {\n readonly ctx: GpuContext;\n readonly model: ForceModel<Options, Stats>;\n readonly tuning: ResolvedLayoutTuning;\n /**\n * The uniform ring, sized (maxInFlight + 1) x MAX_ITERATIONS_PER_STEP slots at construction (CONTRACT DECISION:\n * reserve() wraps to 0 when the tail is short, so maxInFlight batches of up to MAX_ITERATIONS_PER_STEP slots\n * plus one wasted tail always fit without a slot being rewritten while a submitted batch still reads it; hence\n * setParams cannot change maxInFlight, 3.13 forceatlas2.ts).\n * @internal\n */\n readonly ring: UniformRing;\n /**\n * Present when ctx.debug.inspect is true: reads back any named buffer (a shared name, a BufferSpec name,\n * \"force\", \"state\", \"trace\") after the last submitted kernel; resolves a Float32Array except for \"fixed\",\n * \"trace\" (raw words) which resolve Uint32Array.\n */\n inspect?: (name: string) => Promise<Float32Array | Uint32Array>;\n /**\n * Present when ctx.debug.inspect is true: records ONE iteration truncated after stage `upTo` (a model stage\n * name), submits, awaits it (no readback into positions, no stats update).\n * @internal\n */\n debugRunStages?: (upTo: string) => Promise<void>;\n\n private readonly resolveOptions: (patch: Partial<Options>, current: Options) => Options;\n private readonly maxInFlight: number;\n private readonly label: string;\n private readonly traceBytes: number;\n private readonly writer: HeaderWriter;\n private readonly overrideList = new Map<number, number>();\n private readonly pending: PendingBatch[] = [];\n private readonly unregisterLost: () => void;\n private optionsValue: Options;\n private stateValue: \"created\" | \"loaded\" | \"disposed\" = \"created\";\n private generationValue = 0;\n private tierValue: \"exact\" | \"grid\";\n private dimValue: 2 | 3;\n private snapshot: GraphSnapshot | null = null;\n private serial: number | null = null;\n private owner: F32 | null = null;\n private n = 0;\n private scale = 1;\n private center: [number, number, number] = [0, 0, 0];\n private buffers: SimulationBuffers | null = null;\n private core: CoreBinding | null = null;\n private resources: ModelResources | null = null;\n private weightsUpload: WeightsUpload | null = null;\n private ready: Promise<void> = Promise.resolve();\n private submitChain: Promise<void> = Promise.resolve();\n private fixedWords: U32 = new Uint32Array(0);\n private fixedDirty = false;\n private iterationsSubmitted = 0;\n private iterationsDoneValue = 0;\n private settledCountValue = 0;\n private settledValue = false;\n private firstPending = true;\n private statsValue: Stats | null = null;\n private lastPassTimingsValue: readonly PassTiming[] | null = null;\n private lastSubmittedBatchIdValue = 0;\n /** The id of the last batch submitted BEFORE the most recent reheat() (PLAN DECISION 21); 0 = none. */\n private reheatedAfterBatchId = 0;\n private coalescedValue = 0;\n private torndown = false;\n\n /**\n * Creates a simulation over a context and a model (state \"created\"; load() makes it \"loaded\").\n * @param ctx - the context (ready)\n * @param model - the force model\n * @param options - the option record (defaults applied by the caller's factory)\n * @param tuning - the resolved GPU tuning\n * @param resolve - how setParams merges a patch into the current record\n */\n constructor(\n ctx: GpuContext,\n model: ForceModel<Options, Stats>,\n options: Options,\n tuning: ResolvedLayoutTuning,\n resolve: (patch: Partial<Options>, current: Options) => Options,\n ) {\n ctx.assertReady();\n requireFields(model.params, SHARED_PARAM_FIELDS, \"model.params\");\n requireFields(model.state, SHARED_STATE_FIELDS, \"model.state\");\n if (model.params.byteLength > UNIFORM_SLOT_BYTES) {\n throw invalidArgument(\n \"model.params\",\n model.params.byteLength,\n `<= ${UNIFORM_SLOT_BYTES} bytes`,\n \"the params block must fit one ring slot\",\n );\n }\n if (model.state.byteLength > STATE_HEADER_BYTES) {\n throw invalidArgument(\n \"model.state\",\n model.state.byteLength,\n `<= ${STATE_HEADER_BYTES} bytes`,\n \"the state block must fit the state header\",\n );\n }\n if (model.stages.length === 0) {\n throw invalidArgument(\n \"model.stages\",\n model.stages,\n \"at least one stage name\",\n \"a model declares its stages\",\n );\n }\n const maxInFlight = options.maxInFlight ?? FA2_DEFAULTS.maxInFlight;\n if (!Number.isInteger(maxInFlight) || maxInFlight < 1) {\n throw invalidArgument(\n \"maxInFlight\",\n maxInFlight,\n \"an integer >= 1\",\n `maxInFlight must be an integer >= 1, got ${maxInFlight}`,\n );\n }\n const dim = options.dim ?? FA2_DEFAULTS.dim;\n if (dim !== 2 && dim !== 3) {\n throw invalidArgument(\"dim\", dim, \"2 or 3\", `dim must be 2 or 3, got ${String(dim)}`);\n }\n // scale and center are validated now so a bad option never reaches load()\n scaleOf(options);\n centerOf(options);\n simulationCounter++;\n this.ctx = ctx;\n this.model = model;\n this.tuning = tuning;\n this.resolveOptions = resolve;\n this.optionsValue = options;\n this.maxInFlight = maxInFlight;\n this.dimValue = dim;\n this.tierValue = tuning.repulsion === \"grid\" ? \"grid\" : \"exact\";\n this.label = `${model.kind}#${simulationCounter}`;\n this.traceBytes = model.trace.byteLength;\n this.writer = new HeaderWriter(model.state);\n this.ring = new UniformRing(\n ctx.device,\n ctx.allocator,\n (maxInFlight + 1) * MAX_ITERATIONS_PER_STEP,\n `${this.label}/ring`,\n );\n this.unregisterLost = ctx.onLost((info) => {\n this.onDeviceLost(info);\n });\n if (ctx.debug.inspect) {\n this.inspect = (name: string): Promise<Float32Array | Uint32Array> => this.inspectBuffer(name);\n this.debugRunStages = (upTo: string): Promise<void> => this.runStages(upTo);\n }\n }\n\n // ---------------------------------------------------------------- read-only state\n\n /**\n * \"created\" | \"loaded\" | \"disposed\".\n * @returns the state\n */\n get state(): \"created\" | \"loaded\" | \"disposed\" {\n return this.stateValue;\n }\n\n /**\n * The current options record (defaults applied).\n * @returns the record\n */\n get options(): Options {\n return this.optionsValue;\n }\n\n /**\n * The repulsion tier of the current load (spec 7.8).\n * @returns the tier\n */\n get tier(): \"exact\" | \"grid\" {\n return this.tierValue;\n }\n\n /**\n * The profiler's per-pass timings of the last landed batch (pass order; the grid tier's `fa2-k1` /\n * `fa2-attraction` / `fa2-grid` / `fa2-to-scene` rows give T-7's attraction figure, P4 PD-16), or null before a\n * batch landed or without `timestamp-query`.\n * @internal\n * @returns the timings\n */\n get lastPassTimings(): readonly PassTiming[] | null {\n return this.lastPassTimingsValue;\n }\n\n /**\n * The generation counter bumped by every load() (stale readbacks are discarded).\n * @internal\n * @returns the generation\n */\n get generation(): number {\n return this.generationValue;\n }\n\n /**\n * Nodes of the current load (0 before load()).\n * @returns the node count\n */\n get nodeCount(): number {\n return this.n;\n }\n\n /**\n * 2 or 3, fixed at construction (setParams({ dim }) is rejected, spec 7.13).\n * @returns the dimension\n */\n get dim(): 2 | 3 {\n return this.dimValue;\n }\n\n /**\n * iterationsDone >= the budget OR settledCount >= settleWindow of the last completed batch (spec 7.17); true for an empty graph.\n * @returns whether the layout is settled\n */\n get settled(): boolean {\n return this.settledValue;\n }\n\n /**\n * Batches created by step() and not yet landed (PLAN DECISION 7: counted from the step() call).\n * @returns the count\n */\n get inFlight(): number {\n return this.pending.length;\n }\n\n /**\n * Iterations landed since load() or the last reheat().\n * @returns the count\n */\n get iterationsDone(): number {\n return this.iterationsDoneValue;\n }\n\n /**\n * The stats of the last completed batch; before one lands, the host-written header decoded through the model\n * with an empty trace and msPerIteration null.\n * @returns the stats\n */\n get stats(): Stats {\n if (this.statsValue !== null) {\n return this.statsValue;\n }\n const header = new DataView(this.writer.headerBytes());\n const trace = new DataView(new ArrayBuffer(0));\n return withMs(this.model.readStats(header, trace), null);\n }\n\n /**\n * The override list (spec 7.12): rows whose readback is skipped while a batch older than the write is in flight.\n * @internal\n * @returns row -> lastSubmittedBatchId at the write\n */\n get overrides(): ReadonlyMap<number, number> {\n return this.overrideList;\n }\n\n /**\n * The last submitted batch id.\n * @internal\n * @returns the id (0 before any submit)\n */\n get lastSubmittedBatchId(): number {\n return this.lastSubmittedBatchIdValue;\n }\n\n /**\n * Number of step() calls that returned an existing batch's promise instead of submitting (spec 7.19 item 3;\n * read by test/helpers/frame-loop.ts).\n * @internal\n * @returns the count\n */\n get coalesced(): number {\n return this.coalescedValue;\n }\n\n // ---------------------------------------------------------------- load\n\n /**\n * Uploads the snapshot's core, seeds the NaN rows of `positions`, repacks it into layout-unit vec4f with the\n * mass in .w, writes the initial state, starts the model's compile + bind and enters \"loaded\" (spec 7.19; a\n * load() during flight bumps the generation and discards the in-flight batches). Order of the checks (PLAN\n * DECISION 16): E_DISPOSED, the context's assertReady, E_SNAPSHOT (directed), E_TOO_LARGE (nodeCount), the\n * positions array, the tuning, then the core upload and model.inputs() BEFORE any state is touched.\n * PLAN DECISION 10: nodeCount 0 loads with no GPU work at all. PLAN DECISION 11: the tier is resolved here\n * and \"grid\" is E_UNSUPPORTED until P4. PLAN DECISION 17: a same-size load() keeps the buffers and re-zeroes\n * partials, the trace region and every `zero: true` model buffer.\n * @param snapshot - an undirected snapshot\n * @param positions - the owner's stride-3 scene-unit array (NaN rows are seeded in place)\n */\n load(snapshot: GraphSnapshot, positions: F32): void {\n this.assertNotDisposed();\n this.ctx.assertReady();\n if (snapshot.directed) {\n throw new WebGpuGraphError(\n \"E_SNAPSHOT\",\n \"a layout needs an undirected snapshot: pass toUndirected().snapshot\",\n {\n reason: \"directed\",\n serial: snapshot.serial,\n },\n );\n }\n const n = snapshot.nodeCount;\n if (n > MAX_1D_ITEMS) {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${n} nodes exceed ${MAX_1D_ITEMS} (the third partials level is P4)`,\n {\n needed: n,\n limit: MAX_1D_ITEMS,\n path: \"partials\",\n algorithm: this.model.kind,\n },\n );\n }\n if (positions.length !== 3 * n) {\n throw invalidArgument(\n \"positions\",\n positions.length,\n 3 * n,\n `positions has ${positions.length} entries, expected ${3 * n}`,\n );\n }\n if (isSharedBuffer(positions.buffer)) {\n throw invalidArgument(\n \"positions\",\n \"SharedArrayBuffer\",\n \"an ArrayBuffer-backed Float32Array\",\n \"positions must not be backed by a SharedArrayBuffer\",\n );\n }\n const scale = scaleOf(this.optionsValue);\n const center = centerOf(this.optionsValue);\n const tier = tierFor(this.tuning, n);\n const positionsBytes = 16 * n;\n if (positionsBytes > this.ctx.caps.limits.maxBufferSize) {\n throw new WebGpuGraphError(\"E_TOO_LARGE\", `${positionsBytes} bytes of positions exceed maxBufferSize`, {\n needed: positionsBytes,\n limit: this.ctx.caps.limits.maxBufferSize,\n path: \"positions\",\n algorithm: this.model.kind,\n });\n }\n let core: CoreBinding | null = null;\n let tiers: DegreeTiers | null = null;\n let inputs: ModelInputs | null = null;\n if (n > 0) {\n core = this.ctx.residency.core(snapshot);\n if (core.plan === \"windowed\") {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n \"a windowed core cannot be walked by the layout kernels until P4\",\n {\n needed: snapshot.arcCount,\n limit: this.ctx.caps.limits.maxStorageBufferBindingSize,\n path: \"windowed\",\n algorithm: this.model.kind,\n },\n );\n }\n // PD-7 (the 7.3 rule): the permutation is bound iff a row of degree >= 32 exists; the view is uploaded\n // only then, so a low-degree snapshot compiles and runs the same pipelines as before P4\n if (snapshot.degreeOrder().segmentOffsets[2] > 0) {\n tiers = degreeTiersOf(this.ctx.residency.view(snapshot, \"degreeOrder\"));\n }\n inputs = this.model.inputs(snapshot, this.optionsValue);\n if (inputs.mass.length !== n) {\n throw invalidArgument(\n \"nodeMass\",\n inputs.mass.length,\n n,\n `the model resolved ${inputs.mass.length} masses for ${n} nodes`,\n );\n }\n const fixedWords = Math.ceil(n / 32);\n if (inputs.fixed !== undefined && inputs.fixed !== null && inputs.fixed.length < fixedWords) {\n throw invalidArgument(\n \"fixed\",\n inputs.fixed.length,\n fixedWords,\n `the model resolved a fixed mask of ${inputs.fixed.length} words, ${fixedWords} needed for ${n} nodes`,\n );\n }\n }\n\n // ---- every check passed: mutate\n this.generationValue++;\n this.discardPending();\n const resized = this.buffers === null || n !== this.n || snapshot.serial !== this.serial;\n this.snapshot = snapshot;\n this.serial = snapshot.serial;\n this.owner = positions;\n this.n = n;\n this.tierValue = tier;\n this.scale = scale;\n this.center = center;\n this.core = core;\n this.iterationsSubmitted = 0;\n this.iterationsDoneValue = 0;\n this.settledCountValue = 0;\n this.firstPending = true;\n this.statsValue = null;\n this.writer.reset();\n if (resized) {\n this.destroyBuffers();\n this.overrideList.clear();\n this.fixedWords = makeMask(n);\n this.fixedDirty = false;\n }\n if (inputs !== null && inputs.fixed !== undefined && inputs.fixed !== null) {\n this.fixedWords.set(inputs.fixed.subarray(0, Math.ceil(n / 32)));\n this.fixedDirty = true;\n }\n if (n === 0 || core === null || inputs === null) {\n // PLAN DECISION 10: an empty graph loads with no GPU work\n this.weightsUpload = null;\n this.resources = null;\n // keep the chain (PLAN DECISION 20): a bind of the previous load may still be running and the next\n // non-empty load() must start its bind after it; its outcome is irrelevant here\n this.ready = this.ready.catch(() => undefined);\n this.settledValue = true;\n this.stateValue = \"loaded\";\n return;\n }\n const buffers = resized ? this.allocate(n) : this.requireBuffers();\n if (!resized) {\n this.clearKept(buffers);\n }\n this.buffers = buffers;\n const range = this.model.kind === \"fruchtermanReingold\" ? \"fr\" : \"fa2\";\n seedPositions(snapshot, positions, this.optionsValue.seed ?? null, this.dimValue, scale, center, range);\n this.uploadPositions(buffers, positions, inputs.mass);\n const weights = this.resolveWeightsBinding(snapshot, core, inputs.weights);\n const overrides = {\n ...this.model.overrides(this.optionsValue),\n ...graphOverrides(core, tiers?.perm ?? null, weights),\n };\n const resources = this.makeResources(core, tiers, weights, buffers);\n this.resources = resources;\n this.startBind(resources, overrides);\n this.settledValue = false;\n this.stateValue = \"loaded\";\n }\n\n // ---------------------------------------------------------------- step and the batch driver\n\n /**\n * Submits k iterations (spec 7.19 items 1-6): \"created\" -> E_NOT_LOADED; \"disposed\" -> E_DISPOSED; a released\n * snapshot -> E_RELEASED; k outside [1, MAX_ITERATIONS_PER_STEP] -> E_INVALID_ARGUMENT; settled -> resolves at\n * once; inFlight >= maxInFlight -> the OLDEST pending batch's promise (coalesced); else the batch is queued on\n * the submit chain (after the bind promise and allocator.check()) and its promise resolves when its readback\n * landed in the owner's array. The same promise object is returned for every coalesced call. PLAN DECISION 7:\n * the batch counts in `inFlight` from this call, not from its submission.\n * @param iterations - k (default options.iterationsPerStep, default 1)\n * @returns resolves when the batch landed (or was discarded); rejects E_VALIDATION / E_DEVICE_LOST / E_OUT_OF_MEMORY / E_SHADER_COMPILE\n */\n step(iterations?: number): Promise<void> {\n if (this.stateValue === \"created\") {\n return Promise.reject(\n new WebGpuGraphError(\"E_NOT_LOADED\", `${this.label}: load() first`, { state: \"created\" }),\n );\n }\n if (this.stateValue === \"disposed\") {\n return Promise.reject(disposedError(this.label));\n }\n try {\n this.ctx.assertReady();\n } catch (err) {\n return Promise.reject(asError(err));\n }\n const { snapshot } = this;\n if (snapshot !== null && this.ctx.residency.isReleased(snapshot.serial)) {\n return Promise.reject(\n new WebGpuGraphError(\n \"E_RELEASED\",\n `snapshot ${snapshot.serial} was released while ${this.label} used it`,\n {\n serial: snapshot.serial,\n },\n ),\n );\n }\n const k = iterations ?? this.optionsValue.iterationsPerStep ?? FA2_DEFAULTS.iterationsPerStep;\n if (!Number.isInteger(k) || k < 1 || k > MAX_ITERATIONS_PER_STEP) {\n return Promise.reject(\n invalidArgument(\n \"iterations\",\n k,\n `an integer in [1, ${MAX_ITERATIONS_PER_STEP}]`,\n `step(${k}): iterations must be an integer in [1, ${MAX_ITERATIONS_PER_STEP}]`,\n ),\n );\n }\n if (this.settledValue || this.n === 0) {\n return Promise.resolve();\n }\n if (this.pending.length >= this.maxInFlight) {\n this.coalescedValue++;\n return this.pending[0].promise;\n }\n const record = createPending(k, this.generationValue);\n this.pending.push(record);\n this.submitChain = this.submitChain.then(() => this.submitBatch(record));\n return record.promise;\n }\n\n /**\n * Resolves when nothing is in flight (every pending batch landed or was discarded).\n * @returns the promise\n */\n async flush(): Promise<void> {\n while (this.pending.length > 0) {\n await Promise.allSettled(this.pending.map((r) => r.promise));\n }\n }\n\n /**\n * Node batch driver: loops step(batch) until settled, the budget (`maxIter ?? options.maxIter`, PLAN DECISION\n * 1) is reached or the signal aborts (E_ABORTED; the batch in flight at the abort is discarded, spec 5.7 / Q-15).\n * @param options - maxIter, batch (default 8), signal\n * @returns the stats of the last completed batch\n */\n async run(options?: RunOptions): Promise<Stats> {\n this.assertNotDisposed();\n const batch = options?.batch ?? 8;\n if (!Number.isInteger(batch) || batch < 1 || batch > MAX_ITERATIONS_PER_STEP) {\n throw invalidArgument(\n \"batch\",\n batch,\n `an integer in [1, ${MAX_ITERATIONS_PER_STEP}]`,\n \"run(): batch must be an integer in [1, MAX_ITERATIONS_PER_STEP]\",\n );\n }\n const budget = options?.maxIter ?? this.iterationBudget();\n if (Number.isNaN(budget) || budget < 0) {\n throw invalidArgument(\"maxIter\", budget, \"a number >= 0\", \"run(): maxIter must be >= 0\");\n }\n const signal = options?.signal;\n const onAbort = (): void => {\n this.discardPending();\n };\n if (signal !== undefined) {\n if (signal.aborted) {\n throw this.abortedError();\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n try {\n while (!this.settled && this.iterationsDoneValue < budget) {\n if (signal?.aborted === true) {\n throw this.abortedError();\n }\n const k = Math.min(batch, budget - this.iterationsDoneValue);\n await this.step(k);\n }\n if (signal?.aborted === true) {\n throw this.abortedError();\n }\n return this.stats;\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n }\n }\n\n // ---------------------------------------------------------------- pins, drags, reheat, params\n\n /**\n * Copies the mask words (spec 7.12): E_INVALID_ARGUMENT when shorter than ceil(n / 32); the buffer is marked\n * dirty and re-uploaded before the next submit; reheat() iff some bit went 1 -> 0 (an unpin). PLAN DECISION\n * 18: the comparison is bit by bit below n (bits at or above n never count as an unpin).\n * @param mask - the NodeMask (LSB-first words)\n */\n setFixed(mask: NodeMask): void {\n this.assertLoaded();\n const { n } = this;\n const words = Math.ceil(n / 32);\n if (mask.length < words) {\n throw invalidArgument(\n \"mask\",\n mask.length,\n words,\n `setFixed: the mask has ${mask.length} words, ${words} needed for ${n} nodes`,\n );\n }\n let unpinned = false;\n for (let w = 0; w < words && !unpinned; w++) {\n if (this.fixedWords[w] === mask[w]) {\n continue;\n }\n const last = Math.min(n, w * 32 + 32);\n for (let i = w * 32; i < last; i++) {\n if (maskTest(this.fixedWords, i) && !maskTest(mask, i)) {\n unpinned = true;\n break;\n }\n }\n }\n this.fixedWords.set(mask.subarray(0, words));\n this.fixedDirty = true;\n if (unpinned) {\n this.reheat();\n }\n }\n\n /**\n * Writes a scene-unit position (spec 7.12): into the owner's array at once, into the device (layout units, z 0\n * in 2D, 12 bytes at 16 i, queue-ordered before the next submit), into the override list keyed by the last\n * submitted batch id, then reheat(). PLAN DECISION 18: non-finite coordinates are E_INVALID_ARGUMENT.\n * @param index - the node index (< n)\n * @param x - scene x\n * @param y - scene y\n * @param z - scene z (ignored on the device in 2D)\n */\n setPosition(index: number, x: number, y: number, z: number): void {\n this.assertLoaded();\n const { n } = this;\n if (!Number.isInteger(index) || index < 0 || index >= n) {\n throw invalidArgument(\n \"index\",\n index,\n `an integer in [0, ${n})`,\n `setPosition(${index}): index out of range`,\n );\n }\n if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) {\n throw invalidArgument(\n \"position\",\n [x, y, z],\n \"finite coordinates\",\n \"setPosition: coordinates must be finite\",\n );\n }\n const { owner, buffers } = this;\n if (owner === null || buffers === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", `${this.label}: load() first`, { state: this.stateValue });\n }\n owner[3 * index] = x;\n owner[3 * index + 1] = y;\n owner[3 * index + 2] = z;\n const [cx, cy, cz] = this.center;\n const layout = new Float32Array([\n (x - cx) / this.scale,\n (y - cy) / this.scale,\n this.dimValue === 2 ? 0 : (z - cz) / this.scale,\n ]);\n this.ctx.device.queue.writeBuffer(buffers.positions, 16 * index, layout);\n this.overrideList.set(index, this.lastSubmittedBatchIdValue);\n this.reheat();\n }\n\n /**\n * iterationsDone = 0, settledCount = 0 (a queued state write), model.onReheat(writer); nothing else (D8: the\n * speed controller keeps its state). `settled` is recomputed at once (PLAN DECISION 8). Allowed before load().\n * PLAN DECISION 21: the id of the last batch submitted so far is remembered; a batch with that id or an older\n * one was computed from the pre-reheat counter, so its landed settledCount is taken as 0 (see onLanded) and a\n * drag or unpin can never leave the simulation settled through a batch that was already in flight.\n */\n reheat(): void {\n this.assertNotDisposed();\n this.iterationsDoneValue = 0;\n this.settledCountValue = 0;\n this.reheatedAfterBatchId = this.lastSubmittedBatchIdValue;\n this.writer.set(\"settledCount\", 0);\n this.model.onReheat(this.writer);\n this.settledValue = this.computeSettled();\n }\n\n /**\n * Live tuning (spec 3.3, 7.17): `dim` differing from the current -> E_INVALID_ARGUMENT; `maxInFlight` differing\n * -> E_INVALID_ARGUMENT (the ring is sized by it); a non-null `nodeSize` -> E_UNSUPPORTED; the record is\n * replaced through `resolve(patch, current)`; a change of the model's override set (a force LAW) recompiles\n * and re-binds; scale / center changes reach the next batch through the shared params of every slot (the\n * model's toScene reads them); then model.onSetParams(patch, writer) and reheat().\n * @param patch - the fields to change\n */\n setParams(patch: Partial<Options>): void {\n this.assertNotDisposed();\n const current = this.optionsValue;\n const { dim, maxInFlight } = patch;\n if (dim !== undefined && dim !== this.dimValue) {\n throw invalidArgument(\n \"dim\",\n dim,\n this.dimValue,\n \"dim is fixed at construction; graphty-element re-creates the engine on a view-mode switch (spec 7.13)\",\n );\n }\n if (maxInFlight !== undefined && maxInFlight !== this.maxInFlight) {\n throw invalidArgument(\n \"maxInFlight\",\n maxInFlight,\n this.maxInFlight,\n \"maxInFlight is fixed at construction (the uniform ring is sized by it)\",\n );\n }\n const nodeSize = optionField(patch, \"nodeSize\");\n if (nodeSize !== undefined && nodeSize !== null) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"nodeSize (adjustSizes) is deferred (spec 7.14)\", {\n option: \"nodeSize\",\n hint: \"leave nodeSize null; the size correction ships in a later slice\",\n });\n }\n const next = this.resolveOptions(patch, current);\n const scale = scaleOf(next);\n const center = centerOf(next);\n const before = stableKey(this.model.overrides(current));\n const after = stableKey(this.model.overrides(next));\n this.optionsValue = next;\n this.scale = scale;\n this.center = center;\n const { resources, core } = this;\n if (this.stateValue === \"loaded\" && resources !== null && core !== null && before !== after) {\n const overrides = {\n ...this.model.overrides(next),\n ...graphOverrides(core, resources.perm, resources.weights),\n };\n this.startBind(resources, overrides);\n }\n this.model.onSetParams(patch, this.writer);\n this.reheat();\n }\n\n // ---------------------------------------------------------------- dispose and device loss\n\n /**\n * Discards in-flight batches (their promises resolve), destroys every simulation buffer and the ring, trims\n * the pool, unregisters the loss listener; state \"disposed\"; idempotent.\n */\n dispose(): void {\n if (this.stateValue === \"disposed\") {\n return;\n }\n this.stateValue = \"disposed\";\n this.teardown();\n }\n\n // ---------------------------------------------------------------- private: the batch driver\n\n /**\n * The serialised submission of one pending batch: awaits the bind / warm promise and allocator.check(), then\n * records and submits unless the record went stale meanwhile; wires the readback handlers. A record that went\n * stale while waiting (a load() or dispose() superseded it) RESOLVES even when the wait rejected (PLAN\n * DECISION 8: the rejection belongs to the superseded generation -- a bind that failed E_SHADER_COMPILE, or\n * the ring's E_DISPOSED after dispose() tore it down under a running bind).\n * @param record - the pending batch\n */\n private async submitBatch(record: PendingBatch): Promise<void> {\n try {\n await this.ready;\n await this.ctx.allocator.check();\n } catch (err) {\n this.finish(record);\n if (this.isStale(record)) {\n record.resolve();\n return;\n }\n if (hasErrorCode(err, \"E_OUT_OF_MEMORY\")) {\n this.outOfMemory();\n }\n record.reject(asError(err));\n return;\n }\n if (this.isStale(record)) {\n this.finish(record);\n record.resolve();\n return;\n }\n let submitted: SubmittedBatch;\n try {\n submitted = this.recordAndSubmit(record);\n } catch (err) {\n this.finish(record);\n record.reject(asError(err));\n return;\n }\n submitted.readback.then(\n (bytes) => {\n this.onLanded(record, bytes);\n },\n (err: unknown) => {\n this.onFailed(record, err);\n },\n );\n }\n\n /**\n * Flushes the host writes, fills k ring slots, records k iterations (only the last one runs the model's toScene\n * epilogue, PLAN DECISION 2) + the two readbacks into one CommandBatch and submits it (spec 7.19 items 4-5).\n * @param record - the pending batch\n * @returns the submitted batch\n */\n private recordAndSubmit(record: PendingBatch): SubmittedBatch {\n const buffers = this.requireBuffers();\n const { k } = record;\n const { device } = this.ctx;\n if (this.fixedDirty) {\n device.queue.writeBuffer(buffers.fixed, 0, this.fixedWords);\n this.fixedDirty = false;\n }\n this.flushStateWrites(buffers.state);\n const first = this.ring.reserve(k);\n for (let i = 0; i < k; i++) {\n const flags = i === 0 && this.firstPending ? FA2_FLAG_FIRST : 0;\n this.ring.write(first + i, this.model.params, this.paramsForSlot(this.iterationsSubmitted + i, i, flags));\n }\n this.ring.flush();\n const batch = new CommandBatch(this.ctx, `${this.label}/batch`, this.generationValue);\n const beforeEpilogue = this.lastIterationStage();\n for (let i = 0; i < k; i++) {\n // the last iteration records every stage (toScene included); the others stop before the epilogue\n this.model.recordIteration(batch, first + i, this.tierValue, i === k - 1 ? undefined : beforeEpilogue);\n }\n batch.endPass();\n const scene = batch.readback(buffers.scene, 0, 12 * this.n);\n const state = batch.readback(buffers.state, 0, STATE_HEADER_BYTES + k * this.traceBytes);\n const { profiler } = this.ctx;\n const profile = profiler === null ? null : profiler.resolveInto(batch);\n const submitted = batch.submit();\n record.submitted = submitted;\n record.id = submitted.id;\n record.sceneOffset = scene.offset;\n record.stateOffset = state.offset;\n record.profile = profile;\n record.startedAt = performance.now();\n this.lastSubmittedBatchIdValue = submitted.id;\n this.iterationsSubmitted += k;\n this.firstPending = false;\n return submitted;\n }\n\n /**\n * A landed readback (spec 7.19 item 6): stale -> discard; else the scene bytes go into the owner's array row by\n * row (skipping overridden rows, clearing overrides older than this batch), the header refreshes the shadow,\n * the stats are decoded through the model (msPerIteration from the profiler or the wall time, PLAN DECISION 3),\n * iterationsDone += k and settled is recomputed -- with the landed settledCount taken as 0 when the batch was\n * submitted before the last reheat() (PLAN DECISION 21; the header is still absorbed and the stats decoded).\n * @param record - the pending batch\n * @param bytes - the batch's readback bytes\n */\n private onLanded(record: PendingBatch, bytes: ArrayBuffer): void {\n this.finish(record);\n const { owner } = this;\n if (this.isStale(record) || owner === null) {\n record.resolve();\n return;\n }\n try {\n const { k } = record;\n const { n } = this;\n const needed = Math.max(\n record.sceneOffset + 12 * n,\n record.stateOffset + STATE_HEADER_BYTES + k * this.traceBytes,\n );\n if (bytes.byteLength < needed) {\n // a discarded readback resolves with an empty buffer\n record.resolve();\n return;\n }\n this.copyScene(owner, bytes, record);\n const header = new DataView(bytes, record.stateOffset, STATE_HEADER_BYTES);\n const trace = new DataView(bytes, record.stateOffset + STATE_HEADER_BYTES, k * this.traceBytes);\n this.writer.absorb(header);\n const settledCount = this.model.state.readField(header, \"settledCount\");\n if (typeof settledCount !== \"number\") {\n throw invalidArgument(\"settledCount\", settledCount, \"a scalar\", \"settledCount must be a scalar field\");\n }\n const ms = this.batchMilliseconds(record, bytes);\n this.statsValue = withMs(this.model.readStats(header, trace), ms / k);\n this.iterationsDoneValue += k;\n // PLAN DECISION 21: a batch in flight at reheat() carries the pre-reheat settle counter\n this.settledCountValue = record.id <= this.reheatedAfterBatchId ? 0 : settledCount;\n this.settledValue = this.computeSettled();\n record.resolve();\n } catch (err) {\n record.reject(asError(err));\n }\n }\n\n /**\n * A failed readback: a discarded batch's E_ABORTED resolves (PLAN DECISION 8); a lost device rejects\n * E_DEVICE_LOST; everything else (E_VALIDATION, E_DISPOSED) rejects as is.\n * @param record - the pending batch\n * @param err - the rejection\n */\n private onFailed(record: PendingBatch, err: unknown): void {\n this.finish(record);\n if (hasErrorCode(err, \"E_ABORTED\") && this.isStale(record)) {\n record.resolve();\n return;\n }\n if (this.ctx.state === \"lost\" && !hasErrorCode(err, \"E_DEVICE_LOST\")) {\n record.reject(\n new WebGpuGraphError(\"E_DEVICE_LOST\", \"the device was lost while the batch was in flight\", {\n reason: \"unknown\",\n message: asError(err).message,\n }),\n );\n return;\n }\n record.reject(asError(err));\n }\n\n /**\n * Copies the scene bytes of a landed batch into the owner's array, honouring the override list (spec 7.12).\n * @param owner - the owner's array\n * @param bytes - the readback\n * @param record - the batch\n */\n private copyScene(owner: F32, bytes: ArrayBuffer, record: PendingBatch): void {\n const { n } = this;\n const scene = new Float32Array(bytes, record.sceneOffset, 3 * n);\n if (this.overrideList.size === 0) {\n owner.set(scene);\n return;\n }\n for (let i = 0; i < n; i++) {\n const after = this.overrideList.get(i);\n if (after !== undefined && after >= record.id) {\n continue;\n }\n owner[3 * i] = scene[3 * i];\n owner[3 * i + 1] = scene[3 * i + 1];\n owner[3 * i + 2] = scene[3 * i + 2];\n }\n for (const [i, after] of this.overrideList) {\n if (after < record.id) {\n this.overrideList.delete(i);\n }\n }\n }\n\n /**\n * The batch's duration in milliseconds: the profiler's pass timings summed when present and complete, else wall\n * time. The profiler budgets PROFILER_QUERY_SLOTS / 2 passes per batch; the grid tier records three passes per\n * iteration (P4 PD-16), so a grid batch above (PROFILER_QUERY_SLOTS / 2 - 1) / 3 iterations is timed partially:\n * its rows stay in `lastPassTimings` but the duration is the wall time, never the sum of a prefix.\n * @param record - the batch\n * @param bytes - its readback (the profiler's resolve lands in it)\n * @returns milliseconds\n */\n private batchMilliseconds(record: PendingBatch, bytes: ArrayBuffer): number {\n const { profiler } = this.ctx;\n if (profiler !== null && record.profile !== null) {\n const timings = profiler.timings(bytes, record.profile);\n this.lastPassTimingsValue = timings;\n if (timings.length > 0 && !profiler.partial(record.profile)) {\n let ns = 0;\n for (const timing of timings) {\n ns += timing.ns;\n }\n return ns / 1e6;\n }\n }\n return performance.now() - record.startedAt;\n }\n\n /**\n * Whether a record belongs to an earlier generation, was discarded, or the simulation left \"loaded\".\n * @param record - the batch\n * @returns true when its readback must be ignored\n */\n private isStale(record: PendingBatch): boolean {\n return record.stale || this.stateValue !== \"loaded\" || record.generation !== this.generationValue;\n }\n\n /**\n * Removes a record from the pending list (idempotent).\n * @param record - the batch\n */\n private finish(record: PendingBatch): void {\n const at = this.pending.indexOf(record);\n if (at >= 0) {\n this.pending.splice(at, 1);\n }\n }\n\n /** Marks every pending batch stale and discards the submitted ones (their readbacks resolve empty or E_ABORTED). */\n private discardPending(): void {\n for (const record of this.pending) {\n record.stale = true;\n record.submitted?.discard();\n }\n }\n\n /** An OOM surfaced by allocator.check(): every simulation buffer is destroyed and the state returns to \"created\". */\n private outOfMemory(): void {\n this.discardPending();\n this.destroyBuffers();\n this.ctx.allocator.reset();\n this.settledValue = false;\n this.stateValue = \"created\";\n }\n\n /**\n * The E_ABORTED of run().\n * @returns the error\n */\n private abortedError(): WebGpuGraphError {\n return new WebGpuGraphError(\"E_ABORTED\", `${this.label}: run() aborted by the signal`, {\n batchId: this.lastSubmittedBatchIdValue,\n });\n }\n\n // ---------------------------------------------------------------- private: params, state writes, toScene\n\n /**\n * The uniform values of one iteration slot: the model's values with the shared fields on top (PLAN DECISION 6).\n * @param global - the global iteration index (iterationsSubmitted + i)\n * @param index - the slot index within the batch (the trace slot)\n * @param flags - FA2_FLAG_FIRST for the first iteration after load(), else 0; the model's own flag bits are OR-ed in\n * @returns the values\n */\n private paramsForSlot(global: number, index: number, flags: number): UniformValues {\n const [cx, cy, cz] = this.center;\n const model = this.model.paramsFor(global, this.optionsValue);\n const modelFlags = typeof model.flags === \"number\" ? model.flags : 0;\n const shared: UniformValues = {\n n: this.n,\n dim: this.dimValue,\n flags: flags | modelFlags,\n iterationIndex: index,\n seed: this.seedU32(),\n scale: this.scale,\n center: [cx, cy, cz, 0],\n settleThreshold: this.settleThreshold(),\n };\n return { ...model, ...shared };\n }\n\n /**\n * The option seed as a u32 (0 when unseeded), the near-field hash seed of P4.\n * @returns the seed\n */\n private seedU32(): number {\n const { seed } = this.optionsValue;\n if (seed === null || seed === undefined || !Number.isFinite(seed)) {\n return 0;\n }\n return Math.floor(Math.abs(seed)) % 4294967296;\n }\n\n /**\n * Writes the queued state fields, each as one writeBuffer of its own byte range (PLAN DECISION 5).\n * @param state - the state buffer\n */\n private flushStateWrites(state: GPUBuffer): void {\n const fields = this.writer.takeQueued();\n if (fields.length === 0) {\n return;\n }\n const bytes = this.writer.headerBytes();\n const block = this.model.state;\n for (const field of fields) {\n const offset = block.offsetOf(field);\n const size = 4 * fieldWidth(fieldTypeOf(block, field));\n this.ctx.device.queue.writeBuffer(state, offset, bytes, offset, size);\n }\n }\n\n /**\n * The stage that precedes the toScene epilogue in model.stages (the `upTo` of every iteration but the last), or\n * undefined when the model has no epilogue or lists it first (every iteration then records every stage).\n * @returns the stage name or undefined\n */\n private lastIterationStage(): string | undefined {\n const at = this.model.stages.indexOf(EPILOGUE_STAGE);\n if (at <= 0) {\n return undefined;\n }\n return this.model.stages[at - 1];\n }\n\n /**\n * The settle threshold of the current options (FA2_DEFAULTS when absent).\n * @returns the threshold\n */\n private settleThreshold(): number {\n return this.optionsValue.settleThreshold ?? FA2_DEFAULTS.settleThreshold;\n }\n\n /**\n * The settle window of the current options (FA2_DEFAULTS when absent).\n * @returns the window\n */\n private settleWindow(): number {\n return this.optionsValue.settleWindow ?? FA2_DEFAULTS.settleWindow;\n }\n\n /**\n * The iteration budget (PLAN DECISION 1): options.maxIter, else options.iterations, else no budget.\n * @returns the budget\n */\n private iterationBudget(): number {\n const maxIter = optionField(this.optionsValue, \"maxIter\");\n if (typeof maxIter === \"number\") {\n return maxIter;\n }\n const iterations = optionField(this.optionsValue, \"iterations\");\n if (typeof iterations === \"number\") {\n return iterations;\n }\n return Number.POSITIVE_INFINITY;\n }\n\n /**\n * The settle rule of spec 7.17 over the counters of the last completed batch.\n * @returns whether the layout is settled\n */\n private computeSettled(): boolean {\n if (this.stateValue !== \"loaded\") {\n return false;\n }\n return (\n this.n === 0 ||\n this.iterationsDoneValue >= this.iterationBudget() ||\n this.settledCountValue >= this.settleWindow()\n );\n }\n\n // ---------------------------------------------------------------- private: buffers, upload, bind\n\n /**\n * Allocates the shared buffers (spec 7.3 sizes) and the model's BufferSpecs through the allocator (every buffer\n * labelled); a `zero: true` spec must carry COPY_DST so it can be re-zeroed when kept across loads (PLAN\n * DECISION 17). The state buffer is STATE_HEADER_BYTES + MAX_ITERATIONS_PER_STEP x model.trace.byteLength:\n * contract 3.13 writes TRACE_RECORD_BYTES (32, the FA2 record) for the last factor; the model's block is the\n * same number for FA2 and is what the simulation decodes the trace with, so it is the general rule (PLAN\n * DECISION 4) and the constant is not imported here.\n * @param n - the node count (> 0)\n * @returns the buffers and the name -> Binding map\n */\n private allocate(n: number): SimulationBuffers {\n const { allocator } = this.ctx;\n const { label } = this;\n const groups = Math.ceil(n / this.ctx.workgroupSize);\n const traceRegionBytes = MAX_ITERATIONS_PER_STEP * this.traceBytes;\n const storageRw = BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST;\n const positions = allocator.createBuffer({ label: `${label}/positions`, size: 16 * n, usage: storageRw });\n const scene = allocator.createBuffer({\n label: `${label}/scenePositions`,\n size: 12 * n,\n usage: BufferUsage.STORAGE | BufferUsage.COPY_SRC,\n });\n const fixed = allocator.createBuffer({\n label: `${label}/fixed`,\n size: 4 * Math.ceil(n / 32),\n usage: storageRw,\n });\n const partials = allocator.createBuffer({\n label: `${label}/partials`,\n size: PARTIAL_BYTES * groups,\n usage: storageRw,\n });\n const state = allocator.createBuffer({\n label: `${label}/state`,\n size: STATE_HEADER_BYTES + traceRegionBytes,\n usage: storageRw,\n });\n const bindings = new Map<string, Binding>();\n bindings.set(\"positions\", wholeBinding(positions, 16 * n));\n bindings.set(\"scenePositions\", wholeBinding(scene, 12 * n));\n bindings.set(\"fixed\", wholeBinding(fixed, 4 * Math.ceil(n / 32)));\n bindings.set(\"partials\", wholeBinding(partials, PARTIAL_BYTES * groups));\n bindings.set(\"state\", { buffer: state, offset: 0, size: STATE_HEADER_BYTES, window: null });\n bindings.set(\"trace\", { buffer: state, offset: STATE_HEADER_BYTES, size: traceRegionBytes, window: null });\n const model = new Map<string, { readonly buffer: GPUBuffer; readonly spec: BufferSpec }>();\n for (const spec of this.model.buffers(n, this.dimValue)) {\n if (SHARED_BUFFER_NAMES.includes(spec.name) || bindings.has(spec.name)) {\n throw invalidArgument(\n \"BufferSpec.name\",\n spec.name,\n \"a name no other buffer uses\",\n `BufferSpec \"${spec.name}\" reuses a buffer name`,\n );\n }\n if (!Number.isInteger(spec.byteLength) || spec.byteLength <= 0 || spec.byteLength % 4 !== 0) {\n throw invalidArgument(\n \"BufferSpec.byteLength\",\n spec.byteLength,\n \"a positive multiple of 4\",\n `BufferSpec \"${spec.name}\" has byteLength ${spec.byteLength}`,\n );\n }\n if (spec.zero && (spec.usage & BufferUsage.COPY_DST) === 0) {\n throw invalidArgument(\n \"BufferSpec.usage\",\n spec.usage,\n \"COPY_DST on a zero: true spec\",\n `BufferSpec \"${spec.name}\" is zero: true but lacks COPY_DST`,\n );\n }\n const buffer = allocator.createBuffer({\n label: `${label}/${spec.name}`,\n size: spec.byteLength,\n usage: spec.usage,\n });\n model.set(spec.name, { buffer, spec });\n bindings.set(spec.name, wholeBinding(buffer, spec.byteLength));\n }\n return { positions, scene, fixed, partials, state, model, bindings, traceRegionBytes };\n }\n\n /**\n * Re-zeroes the buffers a same-size load() keeps: partials, the trace region and every `zero: true` model buffer.\n * @param buffers - the kept buffers\n */\n private clearKept(buffers: SimulationBuffers): void {\n const { device } = this.ctx;\n const encoder = device.createCommandEncoder({ label: `${this.label}/clear` });\n encoder.clearBuffer(buffers.partials);\n encoder.clearBuffer(buffers.state, STATE_HEADER_BYTES, buffers.traceRegionBytes);\n for (const { buffer, spec } of buffers.model.values()) {\n if (spec.zero) {\n encoder.clearBuffer(buffer);\n }\n }\n device.queue.submit([encoder.finish()]);\n }\n\n /**\n * Destroys every simulation buffer through the allocator (the ring lives on until dispose()). While batches are\n * still in flight the destruction is DEFERRED until their readbacks have settled: the GPU may still be copying\n * out of `scene` / `state` and Dawn's Metal backend (dawn-node 0.4.0 on macOS) has taken the worker process\n * down when a buffer with pending work was destroyed (the Vulkan backends defer internally). The simulation\n * drops its references at once either way, so nothing here is reachable afterwards.\n */\n private destroyBuffers(): void {\n const { buffers } = this;\n if (buffers === null) {\n return;\n }\n this.buffers = null;\n this.resources = null;\n const doomed = [buffers.positions, buffers.scene, buffers.fixed, buffers.partials, buffers.state];\n for (const { buffer } of buffers.model.values()) {\n doomed.push(buffer);\n }\n this.afterInFlight(() => {\n const { allocator } = this.ctx;\n for (const buffer of doomed) {\n allocator.destroy(buffer);\n }\n });\n }\n\n /**\n * Runs `action` now when no submitted batch is in flight, otherwise once every in-flight readback has settled\n * (resolved, discarded or rejected -- the staging slot is returned and the GPU work is done either way).\n * @param action - the destruction to run\n */\n private afterInFlight(action: () => void): void {\n const waits: Promise<unknown>[] = [];\n for (const record of this.pending) {\n if (record.submitted !== null) {\n waits.push(record.submitted.readback.catch(() => undefined));\n }\n }\n if (waits.length === 0) {\n action();\n return;\n }\n void Promise.all(waits).then(action, action);\n }\n\n /**\n * The buffers of the current load.\n * @returns the buffers; E_NOT_LOADED when there are none\n */\n private requireBuffers(): SimulationBuffers {\n const { buffers } = this;\n if (buffers === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", `${this.label}: load() first`, { state: this.stateValue });\n }\n return buffers;\n }\n\n /**\n * Repacks the seeded scene array into layout-unit vec4f (mass in .w, z = 0 in 2D), uploads it, and writes the\n * initial centroid / bbox / rmsRadius / radius (f64 over the f32 values uploaded) with iteration 0,\n * settledCount 0, meanDisplacement 0 into the state header, then model.onLoad(writer) and one whole-header\n * writeBuffer (spec 7.4, 7.17, 7.18).\n * @param buffers - the buffers\n * @param positions - the seeded owner array\n * @param mass - the resolved masses\n */\n private uploadPositions(buffers: SimulationBuffers, positions: F32, mass: F32): void {\n const { n, scale } = this;\n const [cx, cy, cz] = this.center;\n const packed = new Float32Array(4 * n);\n for (let i = 0; i < n; i++) {\n packed[4 * i] = (positions[3 * i] - cx) / scale;\n packed[4 * i + 1] = (positions[3 * i + 1] - cy) / scale;\n packed[4 * i + 2] = this.dimValue === 2 ? 0 : (positions[3 * i + 2] - cz) / scale;\n packed[4 * i + 3] = mass[i];\n }\n this.ctx.device.queue.writeBuffer(buffers.positions, 0, packed);\n let sx = 0;\n let sy = 0;\n let sz = 0;\n const lo = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];\n const hi = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];\n for (let i = 0; i < n; i++) {\n const x = packed[4 * i];\n const y = packed[4 * i + 1];\n const z = packed[4 * i + 2];\n sx += x;\n sy += y;\n sz += z;\n lo[0] = Math.min(lo[0], x);\n lo[1] = Math.min(lo[1], y);\n lo[2] = Math.min(lo[2], z);\n hi[0] = Math.max(hi[0], x);\n hi[1] = Math.max(hi[1], y);\n hi[2] = Math.max(hi[2], z);\n }\n const mx = sx / n;\n const my = sy / n;\n const mz = sz / n;\n let sumSq = 0;\n let maxSq = 0;\n for (let i = 0; i < n; i++) {\n const dx = packed[4 * i] - mx;\n const dy = packed[4 * i + 1] - my;\n const dz = packed[4 * i + 2] - mz;\n const q = dx * dx + dy * dy + dz * dz;\n sumSq += q;\n maxSq = Math.max(maxSq, q);\n }\n const { writer } = this;\n writer.set(\"iteration\", 0);\n writer.set(\"settledCount\", 0);\n writer.set(\"meanDisplacement\", 0);\n writer.set(\"centroid\", [mx, my, mz, 0]);\n writer.set(\"min\", [lo[0], lo[1], lo[2], 0]);\n writer.set(\"max\", [hi[0], hi[1], hi[2], 0]);\n writer.set(\"rmsRadius\", Math.sqrt(sumSq / n));\n writer.set(\"radius\", Math.sqrt(maxSq));\n this.model.onLoad(writer);\n this.ctx.device.queue.writeBuffer(buffers.state, 0, writer.headerBytes());\n writer.clearQueued();\n }\n\n /**\n * The weights binding of a load (3.10): \"arcs\" -> core.weights, \"none\" -> null, \"column\" -> the expanded array\n * registered with residency.array(expanded, \"weights\", snapshot), the previous array object reused when the\n * column and its version are unchanged (so the upload cache finds it).\n * @param snapshot - the snapshot\n * @param core - its core\n * @param resolved - model.inputs().weights\n * @returns the binding for the group-0 weights slot, or null\n */\n private resolveWeightsBinding(\n snapshot: GraphSnapshot,\n core: CoreBinding,\n resolved: ResolvedWeights,\n ): Binding | null {\n if (resolved.source === \"arcs\") {\n this.weightsUpload = null;\n return core.weights;\n }\n if (resolved.source === \"none\" || resolved.data === null || resolved.column === null) {\n this.weightsUpload = null;\n return null;\n }\n const previous = this.weightsUpload;\n const reusable =\n previous !== null &&\n previous.serial === snapshot.serial &&\n previous.column === resolved.column &&\n previous.version === resolved.column.version &&\n previous.data.length === resolved.data.length;\n const data = reusable && previous !== null ? previous.data : resolved.data;\n const upload = this.ctx.residency.array(data, \"weights\", snapshot);\n this.weightsUpload = {\n serial: snapshot.serial,\n column: resolved.column,\n version: resolved.column.version,\n data,\n upload,\n };\n return upload.binding;\n }\n\n /**\n * The ModelResources of a load.\n * @param core - the core\n * @param tiers - the degree tiers, or null when no row has degree >= 32\n * @param weights - the resolved weights binding\n * @param buffers - the buffers\n * @returns the resources\n */\n private makeResources(\n core: CoreBinding,\n tiers: DegreeTiers | null,\n weights: Binding | null,\n buffers: SimulationBuffers,\n ): ModelResources {\n const { bindings } = buffers;\n return {\n device: this.ctx.device,\n caps: this.ctx.caps,\n pipelines: this.ctx.pipelines,\n core,\n perm: tiers?.perm ?? null,\n tiers,\n weights,\n n: this.n,\n dim: this.dimValue,\n tier: this.tierValue,\n ring: this.ring,\n pool: this.ctx.pool,\n buffer: (name: string): Binding => {\n const binding = bindings.get(name);\n if (binding === undefined) {\n throw invalidArgument(\"name\", name, [...bindings.keys()], `no simulation buffer named \"${name}\"`);\n }\n return binding;\n },\n };\n }\n\n /**\n * Chains the compile + bind promise the next step() awaits on the PREVIOUS one (PLAN DECISION 20: binds are\n * serialised on `ready` for load() and setParams() alike, so a superseded load()'s bind either fails its\n * generation check before model.bind() or completes before its successor's bind starts -- it can never bind\n * the model to destroyed buffers AFTER the new bind finished). The previous promise's rejection is swallowed by\n * the chain (it belonged to the superseded generation); this promise's rejection is kept for the next step()\n * (the derived catch only silences the unhandled-rejection warning).\n * @param resources - the resources\n * @param overrides - the merged override set\n */\n private startBind(resources: ModelResources, overrides: Readonly<Record<string, number | boolean>>): void {\n const generation = this.generationValue;\n const run = (): Promise<void> => this.compileAndBind(resources, overrides, generation);\n const promise = this.ready.catch(() => undefined).then(run);\n void promise.catch(() => undefined);\n this.ready = promise;\n }\n\n /**\n * assertDeviceComputes() then warm(model.specs()) then model.bind(); the await re-checks that the load is\n * current before binding.\n *\n * The device self-check sits HERE rather than in submitBatch (its first home) because this promise is the one\n * submitBatch already awaits before every batch: the check is therefore settled before the simulation can\n * submit a single iteration, yet costs the frame loop nothing per batch. An extra await on the per-batch path\n * moves the moment a submission becomes visible to a step() issued in the same tick, which is precisely what\n * coalescing is measured on (test/layouts/frame-loop.test.ts, \"a coalesced step() returns the same promise\").\n * A device that computes incorrectly rejects this promise, so the first step() rejects E_DEVICE_INCORRECT\n * before any position is written; a check that could not RUN rejects with its own error, unchanged.\n * @param resources - the resources\n * @param overrides - the merged override set\n * @param generation - the generation the bind belongs to\n */\n private async compileAndBind(\n resources: ModelResources,\n overrides: Readonly<Record<string, number | boolean>>,\n generation: number,\n ): Promise<void> {\n await assertDeviceComputes(this.ctx);\n const subgroups = this.ctx.caps.features.has(\"subgroups\");\n await this.ctx.pipelines.warm(this.model.specs(overrides, subgroups));\n if (this.stateValue !== \"loaded\" || generation !== this.generationValue) {\n return;\n }\n await this.model.bind(resources, overrides);\n }\n\n // ---------------------------------------------------------------- private: inspect and debug runs\n\n /**\n * inspect(name): flush, read the named buffer back, Uint32Array for the u32 buffers (U32_BUFFER_NAMES), Float32Array otherwise.\n * @param name - a shared or BufferSpec name\n * @returns the words\n */\n private async inspectBuffer(name: string): Promise<Float32Array | Uint32Array> {\n this.assertLoaded();\n const { buffers } = this;\n const binding = buffers?.bindings.get(name);\n if (buffers === null || binding === undefined) {\n throw invalidArgument(\n \"name\",\n name,\n buffers === null ? [] : [...buffers.bindings.keys()],\n `inspect(\"${name}\"): no such buffer`,\n );\n }\n await this.flush();\n const bytes = await this.ctx.readback.read(binding.buffer, binding.size, undefined, binding.offset);\n return U32_BUFFER_NAMES.has(name) ? new Uint32Array(bytes) : new Float32Array(bytes);\n }\n\n /**\n * debugRunStages(upTo): one iteration truncated after a stage, submitted alone after flush(), awaited through\n * a header readback; never advances the counters or the FA2_FLAG_FIRST flag (PLAN DECISION 9).\n * @param upTo - a model stage name\n */\n private async runStages(upTo: string): Promise<void> {\n this.assertLoaded();\n if (!this.model.stages.includes(upTo)) {\n throw invalidArgument(\n \"upTo\",\n upTo,\n [...this.model.stages],\n `debugRunStages(\"${upTo}\"): not a stage of ${this.model.kind}`,\n );\n }\n if (this.n === 0) {\n return;\n }\n await this.flush();\n await this.ready;\n await this.ctx.allocator.check();\n this.assertLoaded();\n const buffers = this.requireBuffers();\n const { device } = this.ctx;\n if (this.fixedDirty) {\n device.queue.writeBuffer(buffers.fixed, 0, this.fixedWords);\n this.fixedDirty = false;\n }\n this.flushStateWrites(buffers.state);\n const slot = this.ring.reserve(1);\n this.ring.write(\n slot,\n this.model.params,\n this.paramsForSlot(this.iterationsSubmitted, 0, this.firstPending ? FA2_FLAG_FIRST : 0),\n );\n this.ring.flush();\n const batch = new CommandBatch(this.ctx, `${this.label}/debug`, this.generationValue);\n this.model.recordIteration(batch, slot, this.tierValue, upTo);\n batch.endPass();\n batch.readback(buffers.state, 0, STATE_HEADER_BYTES);\n const submitted = batch.submit();\n this.lastSubmittedBatchIdValue = submitted.id;\n await submitted.readback;\n }\n\n // ---------------------------------------------------------------- private: lifecycle\n\n /**\n * Device loss (spec 5.7): every pending promise rejects E_DEVICE_LOST, the simulation is disposed.\n * @param info - the loss info\n */\n private onDeviceLost(info: GPUDeviceLostInfo): void {\n if (this.stateValue === \"disposed\") {\n return;\n }\n const error = new WebGpuGraphError(\"E_DEVICE_LOST\", `device lost (${info.reason}): ${info.message}`, {\n reason: info.reason,\n message: info.message,\n });\n const pending = this.pending.splice(0);\n this.stateValue = \"disposed\";\n for (const record of pending) {\n record.stale = true;\n record.reject(error);\n }\n this.teardown();\n }\n\n /** Releases everything once: pending batches discarded, buffers and ring destroyed, pool trimmed, listener unregistered. */\n private teardown(): void {\n if (this.torndown) {\n return;\n }\n this.torndown = true;\n this.discardPending();\n this.destroyBuffers();\n this.afterInFlight(() => {\n this.ring.destroy();\n this.model.dispose?.();\n });\n if (this.ctx.state === \"ready\") {\n this.ctx.pool.trim();\n }\n this.unregisterLost();\n this.core = null;\n this.snapshot = null;\n this.owner = null;\n this.weightsUpload = null;\n }\n\n /** E_DISPOSED after dispose() or device loss. */\n private assertNotDisposed(): void {\n if (this.stateValue === \"disposed\") {\n throw disposedError(this.label);\n }\n }\n\n /** E_NOT_LOADED before load(), E_DISPOSED after dispose(). */\n private assertLoaded(): void {\n if (this.stateValue === \"created\") {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", `${this.label}: load() first`, { state: \"created\" });\n }\n this.assertNotDisposed();\n }\n}\n","/**\n * nodeMass and weight resolution from graph-format primitives only (spec 7.14, 7.5; D28, Q-30): the role-\"mass\"\n * node column first, then outDegree() + 1; weights from the arc array, from a named edge column expanded to arcs\n * with expandEdges, or none. The Record form of nodeMass is rejected with the hint of spec 7.14 (graphty-element\n * writes its nodeMass config as the role column once at engine creation, so both simulations find it the same way\n * and this package parses no ids).\n */\n\nimport { type Column, expandEdges, type F32, type GraphSnapshot, type NodeId } from \"@graphty/graph-format\";\n\nimport { WebGpuGraphError } from \"../errors.js\";\n\n/** The message of spec 7.14 for the Record form of nodeMass. */\nconst NODE_MASS_HINT =\n \"write a role 'mass' node column (nodes.set(name, vec, { role: 'mass', replaceRole: true })) or pass a \" +\n \"Float32Array; @graphty/layout's resolveNodeVector does this on the CPU path\";\n\n/**\n * An E_INVALID_ARGUMENT with the documented details shape.\n * @param argument - the option name\n * @param value - the offending value\n * @param expected - what was expected\n * @param message - the message\n * @returns the error\n */\nfunction invalid(argument: string, value: unknown, expected: unknown, message: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_INVALID_ARGUMENT\", message, { argument, value, expected });\n}\n\n/**\n * Asserts every mass is finite and > 0 (spec 7.14: a mass of 0 would divide the distributed action by zero).\n * @param mass - the masses\n * @param source - what the masses came from, for the message\n */\nfunction checkMass(mass: ArrayLike<number>, source: string): void {\n for (let i = 0; i < mass.length; i++) {\n const v = mass[i];\n if (!Number.isFinite(v) || v <= 0) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `${source}: mass[${i}] = ${v} is not a finite number > 0`,\n {\n argument: \"nodeMass\",\n value: v,\n index: i,\n expected: \"finite masses > 0\",\n },\n );\n }\n }\n}\n\n/**\n * outDegree()[i] + 1 for every node (spec 7.2 \"Mass\" row; one O(n) loop over the cached view).\n * @param s - the snapshot\n * @returns a fresh F32 of nodeCount masses\n */\nfunction degreePlusOne(s: GraphSnapshot): F32 {\n const n = s.nodeCount;\n const degree = s.outDegree();\n const out = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n out[i] = degree[i] + 1;\n }\n return out;\n}\n\n/**\n * The masses of a node column: f32 as is, f64 / u32 / i32 through gpuView (f64 = the cached f32 copy; u32 / i32\n * converted to a fresh F32), u8 through column.data; every other dtype is E_INVALID_ARGUMENT (PLAN DECISION 14).\n * @param s - the snapshot (the column belongs to s.nodes)\n * @param column - the node column\n * @returns nodeCount masses\n */\nfunction massFromColumn(s: GraphSnapshot, column: Column): F32 {\n const { name } = column.meta;\n if (column.meta.components !== 1) {\n throw invalid(\n \"nodeMass\",\n name,\n \"a one-component numeric node column\",\n `node column \"${name}\" has ${column.meta.components} components; a mass column has one`,\n );\n }\n let values: ArrayLike<number>;\n switch (column.dtype) {\n case \"f32\":\n case \"f64\": {\n const view = s.nodes.gpuView(name);\n const out = view instanceof Float32Array ? view : new Float32Array(view);\n checkMass(out, `node column \"${name}\"`);\n return out;\n }\n case \"u32\":\n case \"i32\":\n values = s.nodes.gpuView(name);\n break;\n case \"u8\":\n values = column.data;\n break;\n default:\n throw invalid(\n \"nodeMass\",\n name,\n \"a numeric node column (f32, f64, u32, i32, u8)\",\n `node column \"${name}\" is ${column.dtype}, not numeric`,\n );\n }\n const out = new Float32Array(s.nodeCount);\n for (let i = 0; i < out.length; i++) {\n out[i] = values[i];\n }\n checkMass(out, `node column \"${name}\"`);\n return out;\n}\n\n/**\n * nodeMass resolution by ROLE (spec 7.14): null -> the role-\"mass\" node column when present (any numeric dtype\n * through gpuView, converted to a fresh F32 when not f32), else outDegree()[i] + 1; an F32 of length n -> as is;\n * a column NAME -> nodes.get(name) (numeric); a Record -> E_UNSUPPORTED with the spec's message. Always returns n\n * values, every one finite and > 0.\n * @param s - the snapshot\n * @param spec - the ForceAtlas2Options.nodeMass value\n * @returns nodeCount masses (the caller's array when an F32 was given)\n */\nexport function resolveNodeMass(\n s: GraphSnapshot,\n spec: F32 | string | Readonly<Record<NodeId, number>> | null | undefined,\n): F32 {\n const n = s.nodeCount;\n if (spec === null || spec === undefined) {\n const column = s.nodes.byRole(\"mass\");\n if (column === null) {\n return degreePlusOne(s);\n }\n return massFromColumn(s, column);\n }\n if (spec instanceof Float32Array) {\n if (spec.length !== n) {\n throw invalid(\"nodeMass\", spec.length, `${n} values`, `nodeMass has ${spec.length} values, expected ${n}`);\n }\n checkMass(spec, \"nodeMass\");\n return spec;\n }\n if (typeof spec === \"string\") {\n const column = s.nodes.get(spec);\n if (column === null) {\n throw invalid(\n \"nodeMass\",\n spec,\n \"an existing numeric node column\",\n `nodeMass names node column \"${spec}\", which the snapshot does not hold`,\n );\n }\n return massFromColumn(s, column);\n }\n if (ArrayBuffer.isView(spec)) {\n throw invalid(\n \"nodeMass\",\n \"typed array\",\n \"a Float32Array\",\n \"nodeMass must be a Float32Array, a column name or null\",\n );\n }\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `nodeMass as a Record is not supported on the GPU path: ${NODE_MASS_HINT}`,\n {\n option: \"nodeMass\",\n hint: NODE_MASS_HINT,\n },\n );\n}\n\n/** What resolveWeights found. */\nexport interface ResolvedWeights {\n readonly data: F32 | null;\n readonly source: \"arcs\" | \"column\" | \"none\";\n readonly column: Column | null;\n}\n\n/**\n * Weight resolution (spec 7.5, 7.14): true -> { data: s.weights, source: \"arcs\" } (data null when unweighted ->\n * ones); a string -> a name `s.edges` does not hold is E_INVALID_ARGUMENT (spec 7.14's nodeMass rule applied to\n * weight too), else `column = s.edges.get(name)`, then by `column.dtype`: f32 / f64 / u32 / i32 ->\n * expandEdges(s, s.edges.gpuView(name)) (f64 arrives as gpuView's cached f32 copy; u32 / i32 are converted to a\n * fresh F32; `Column.data` is NOT used because it is U8 for u8 / bool and absent for string / list / json), string /\n * list / json -> the gpuView E_GPU_INELIGIBLE pass-through, u8 / bool / dict -> E_INVALID_ARGUMENT (gpuView returns\n * packed words, not per-edge values); source \"column\", `column` kept for the version check; false / null /\n * undefined -> none. A named column must have one component (PLAN DECISION 15); the weight values are never\n * inspected.\n * @param s - the snapshot\n * @param spec - the ForceAtlas2Options.weight value\n * @returns the resolved weights\n */\nexport function resolveWeights(s: GraphSnapshot, spec: boolean | string | null | undefined): ResolvedWeights {\n if (spec === true) {\n return { data: s.weights, source: \"arcs\", column: null };\n }\n if (spec === false || spec === null || spec === undefined) {\n return { data: null, source: \"none\", column: null };\n }\n if (typeof spec !== \"string\") {\n throw invalid(\n \"weight\",\n spec,\n \"true, false, null or an edge column name\",\n \"weight must be true, false, null or an edge column name\",\n );\n }\n const column = s.edges.get(spec);\n if (column === null) {\n throw invalid(\n \"weight\",\n spec,\n \"an existing numeric edge column\",\n `weight names edge column \"${spec}\", which the snapshot does not hold`,\n );\n }\n if (column.meta.components !== 1) {\n throw invalid(\n \"weight\",\n spec,\n \"a one-component numeric edge column\",\n `edge column \"${spec}\" has ${column.meta.components} components; a weight column has one`,\n );\n }\n switch (column.dtype) {\n case \"f32\":\n case \"f64\":\n case \"u32\":\n case \"i32\": {\n const view = s.edges.gpuView(spec);\n const expanded = expandEdges(s, view);\n const data = expanded instanceof Float32Array ? expanded : new Float32Array(expanded);\n return { data, source: \"column\", column };\n }\n case \"string\":\n case \"list\":\n case \"json\":\n // gpuView throws the GraphFormatError E_GPU_INELIGIBLE, which passes through unchanged (D12)\n s.edges.gpuView(spec);\n throw invalid(\"weight\", spec, \"a numeric edge column\", `edge column \"${spec}\" is ${column.dtype}`);\n default:\n throw invalid(\n \"weight\",\n spec,\n \"an f32 / f64 / u32 / i32 edge column\",\n `edge column \"${spec}\" is ${column.dtype}: its gpuView is packed words, not per-edge values`,\n );\n }\n}\n","/**\n * The option and value helpers every force model's resolver and stats decoder share (P5 PD-7): moved verbatim\n * from src/layouts/forceatlas2.ts (P3-T2) so the Fruchterman-Reingold and spring-electrical models of P5 neither\n * copy them nor import a sibling model; and, since P4-T6, the K2 tier binding and dispatch the three models share\n * (`bindAttraction` / `recordAttraction`, P4 PD-7), so every model's bind() / recordIteration() calls one function\n * instead of holding its own copy. Layout zone.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type DispatchPlan, plan1d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { type UniformValues } from \"../kernel/struct-block.js\";\nimport { graphBindings, kernelSpec } from \"../kernels.js\";\nimport { MID_TIER_LANES } from \"../primitives/core-shape.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ModelResources } from \"./force-simulation.js\";\n\n/** An override record as the kernel layer takes it. */\nexport type Overrides = Readonly<Record<string, number | boolean>>;\n\n/** The K2 (`fa2-attraction`) dispatches of one iteration: `[kernel, bind group, plan]` in dispatch order TIER 2, TIER 1, TIER 0 (only the tiers whose row range is non-empty). */\nexport interface AttractionBound {\n readonly kernels: readonly (readonly [Kernel, BoundKernel, DispatchPlan])[];\n}\n\n/** The group-1 / group-2 bindings of K2 every tier dispatch shares: `pos` (vec4f, mass in w), `force` (stride-3 f32) and the Fa2Params slot of the UniformRing. @public the bindings parameter of bindAttraction */\nexport interface AttractionBindings {\n readonly pos: Binding;\n readonly force: Binding;\n readonly params: Binding;\n}\n\n/**\n * Compiles (through the cache) and binds the `fa2-attraction` pipelines a load needs against the graph group and\n * { pos, force, P } (P4 PD-7): TIER 0 always; TIER 1 when a row of degree 32..1023 exists (`[hiEnd, midEnd)` is\n * non-empty); TIER 2 when a row of degree >= 1024 exists (`hiEnd > 0`). The dispatch plans are one workgroup per\n * row for TIER 2, `WG / 32` rows per workgroup for TIER 1 and one row per thread for TIER 0, over each tier's row\n * count (the K2 body reads its range from `Fa2Params.hiEnd` / `midEnd` / `tierStart` / `tierEnd`). The TIER 1 / 2\n * pipelines compile on the first load that needs them (a one-time cost at that load); a model's `specs()` lists\n * the TIER 0 spec only, because it has no `n` to know which tiers a load needs. A device whose workgroup size is\n * below 32 cannot fold the mid tier: E_UNSUPPORTED { feature: \"fa2-attraction.tiers\" } when a permutation is bound.\n * @param resources - the load's resources (core, tiers, weights, pipelines, caps)\n * @param k2 - the K2 override record of the model (LINLOG / DISTRIBUTED / LAW plus USE_PERM / HAS_WEIGHTS; TIER is overwritten per dispatch)\n * @param bindings - the group-1 / group-2 bindings shared by every tier\n * @returns the bound dispatches in order TIER 2, 1, 0\n */\nexport async function bindAttraction(\n resources: ModelResources,\n k2: Overrides,\n bindings: AttractionBindings,\n): Promise<AttractionBound> {\n const { n, core, perm, tiers, weights, pipelines, caps } = resources;\n const so = tiers?.segmentOffsets;\n const hiEnd = so?.[1] ?? 0;\n const midEnd = so?.[2] ?? 0;\n const ranges: readonly { readonly tier: 0 | 1 | 2; readonly rows: number }[] = [\n { tier: 2, rows: hiEnd },\n { tier: 1, rows: midEnd - hiEnd },\n { tier: 0, rows: n - midEnd },\n ];\n const group = {\n ...graphBindings(core, perm, weights),\n pos: bindings.pos,\n force: bindings.force,\n P: bindings.params,\n };\n const kernels: (readonly [Kernel, BoundKernel, DispatchPlan])[] = [];\n for (const { tier, rows } of ranges) {\n if (tier !== 0 && rows <= 0) {\n continue;\n }\n // sequential on purpose: PipelineCache.get compiles inside a validation scope, one stack per device\n const kernel = await pipelines.kernel(kernelSpec(\"fa2-attraction\", { ...k2, TIER: tier }));\n const wg = kernel.workgroupSize;\n if (tier !== 0 && wg < MID_TIER_LANES) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `fa2-attraction: the mid tier folds ${MID_TIER_LANES} lanes per row, more than the workgroup size ${wg}`,\n { feature: \"fa2-attraction.tiers\" },\n );\n }\n if (rows <= 0) {\n continue;\n }\n let rowsPerGroup = wg;\n if (tier === 2) {\n rowsPerGroup = 1;\n } else if (tier === 1) {\n rowsPerGroup = wg / MID_TIER_LANES;\n }\n kernels.push([kernel, kernel.bind(group), plan1d(rows, rowsPerGroup, caps)]);\n }\n return { kernels };\n}\n\n/**\n * Records the K2 dispatches of one iteration in order TIER 2, TIER 1, TIER 0 with the iteration's params offset.\n * @param pass - the open compute pass\n * @param bound - what bindAttraction produced\n * @param paramsOffset - the UniformRing byte offset of this iteration's Fa2Params\n */\nexport function recordAttraction(pass: GPUComputePassEncoder, bound: AttractionBound, paramsOffset: number): void {\n for (const [kernel, group, plan] of bound.kernels) {\n kernel.dispatch(pass, group, plan, [paramsOffset]);\n }\n}\n\n/** Bytes of the stride-3 f32 force arrays per node. */\nexport const FORCE_BYTES_PER_NODE = 12;\n\n/** The name of the model-owned FillParams buffer (a BufferSpec, reached through ModelResources.buffer). */\nexport const FILL_PARAMS_BUFFER = \"fillParams\";\n\n/** 2^32, the modulus of the u32 seed word (computed with `%`, never a bitwise operator). */\nconst U32_MODULUS = 4294967296;\n\n/**\n * A short, safe rendering of an argument value for error messages (never String() on an object).\n * @param value - the value\n * @returns the rendering\n */\nexport function describeValue(value: unknown): string {\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"string\") {\n return String(value);\n }\n if (typeof value === \"undefined\") {\n return \"undefined\";\n }\n if (typeof value === \"object\" && \"length\" in value && typeof value.length === \"number\") {\n return `[${value.length} values]`;\n }\n return typeof value;\n}\n\n/**\n * The E_INVALID_ARGUMENT error of an option check (contract 3.1: { argument, value, expected }).\n * @param argument - the option name\n * @param value - the value given\n * @param expected - what was expected\n * @returns the error (not thrown here)\n */\nexport function invalid(argument: string, value: unknown, expected: string): WebGpuGraphError {\n return new WebGpuGraphError(\"E_INVALID_ARGUMENT\", `${argument} must be ${expected}; got ${describeValue(value)}`, {\n argument,\n value,\n expected,\n });\n}\n\n/**\n * A numeric option: the given value when defined, else the fallback; validated by `check` (the value is checked as\n * `unknown` so a JS caller's string or object is E_INVALID_ARGUMENT too).\n * @param name - the option name\n * @param given - the value given (undefined = absent)\n * @param fallback - the previous record's value or the default\n * @param check - the range predicate over a finite number\n * @param expected - the range in words (the error message)\n * @returns the value\n */\nexport function pickNumber(\n name: string,\n given: number | undefined,\n fallback: number,\n check: (value: number) => boolean,\n expected: string,\n): number {\n const value: unknown = given === undefined ? fallback : given;\n if (typeof value !== \"number\" || !Number.isFinite(value) || !check(value)) {\n throw invalid(name, value, expected);\n }\n return value;\n}\n\n/**\n * A boolean option: the given value when defined, else the fallback; a non-boolean is E_INVALID_ARGUMENT.\n * @param name - the option name\n * @param given - the value given (undefined = absent)\n * @param fallback - the previous record's value or the default\n * @returns the value\n */\nexport function pickBoolean(name: string, given: boolean | undefined, fallback: boolean): boolean {\n const value: unknown = given === undefined ? fallback : given;\n if (typeof value !== \"boolean\") {\n throw invalid(name, value, \"a boolean\");\n }\n return value;\n}\n\n/**\n * The layout dimension: 2 or 3.\n * @param given - the value given (undefined = absent)\n * @param fallback - the previous record's value or the default\n * @returns 2 or 3\n */\nexport function pickDim(given: 2 | 3 | undefined, fallback: 2 | 3): 2 | 3 {\n const value: unknown = given === undefined ? fallback : given;\n if (value !== 2 && value !== 3) {\n throw invalid(\"dim\", value, \"2 or 3\");\n }\n return value;\n}\n\n/**\n * The scene-unit center: an array-like of 2 (z = 0) or 3 finite numbers.\n * @param given - the value given (undefined = absent)\n * @param fallback - the previous record's value or the default\n * @returns the three components\n */\nexport function pickCenter(\n given: ArrayLike<number> | undefined,\n fallback: readonly [number, number, number],\n): readonly [number, number, number] {\n if (given === undefined) {\n return fallback;\n }\n const expected = \"an array of 2 or 3 finite numbers\";\n const value: unknown = given;\n if (typeof value !== \"object\" || value === null || !(\"length\" in value)) {\n throw invalid(\"center\", given, expected);\n }\n const { length } = value;\n if (length !== 2 && length !== 3) {\n throw invalid(\"center\", given, expected);\n }\n const x: unknown = given[0];\n const y: unknown = given[1];\n const z: unknown = length === 3 ? given[2] : 0;\n if (\n typeof x !== \"number\" ||\n typeof y !== \"number\" ||\n typeof z !== \"number\" ||\n !Number.isFinite(x) ||\n !Number.isFinite(y) ||\n !Number.isFinite(z)\n ) {\n throw invalid(\"center\", given, expected);\n }\n return [x, y, z];\n}\n\n/**\n * The seed: a finite number, or null (unseeded; 0 keeps the port's \"0 = unseeded\" quirk through the Lcg).\n * @param given - the value given (undefined = absent)\n * @param fallback - the previous record's value or the default\n * @returns the seed or null\n */\nexport function pickSeed(given: number | null | undefined, fallback: number | null): number | null {\n if (given === undefined) {\n return fallback;\n }\n const value: unknown = given;\n if (value !== null && (typeof value !== \"number\" || !Number.isFinite(value))) {\n throw invalid(\"seed\", given, \"a finite number or null\");\n }\n return value;\n}\n\n/**\n * Integer >= 1.\n * @param value - a finite number\n * @returns whether it is a positive integer\n */\nexport function isPositiveInteger(value: number): boolean {\n return Number.isInteger(value) && value >= 1;\n}\n\n/**\n * The u32 word written into Fa2Params.seed: 0 for null, else floor(|seed|) mod 2^32.\n * @param seed - the resolved seed\n * @returns the u32 value\n */\nexport function seedWord(seed: number | null): number {\n if (seed === null) {\n return 0;\n }\n return Math.floor(Math.abs(seed)) % U32_MODULUS;\n}\n\n/**\n * A scalar field of a block's read() result.\n * @param values - the values read\n * @param name - the field name\n * @returns the number\n */\nexport function scalar(values: UniformValues, name: string): number {\n const value = values[name];\n if (typeof value !== \"number\") {\n throw invalid(name, value, \"a scalar field\");\n }\n return value;\n}\n\n/**\n * A vector field of a block's read() result.\n * @param values - the values read\n * @param name - the field name\n * @returns the components\n */\nexport function vector(values: UniformValues, name: string): readonly number[] {\n const value = values[name];\n if (typeof value === \"number\") {\n throw invalid(name, value, \"a vector field\");\n }\n return value;\n}\n\n/**\n * The override record a kernel gets: its defaults overlaid with the values present in the merged set (contract 3.9:\n * a name a spec does not declare is rejected at compose time, so nothing else is passed through).\n * @param merged - the merged override set of the model (plus USE_PERM / HAS_WEIGHTS from the simulation)\n * @param defaults - the kernel's accepted names with their defaults\n * @returns the kernel's override record, every accepted name explicit\n */\nexport function subset(merged: Overrides, defaults: Overrides): Overrides {\n const out: Record<string, number | boolean> = {};\n for (const name of Object.keys(defaults)) {\n out[name] = name in merged ? merged[name] : defaults[name];\n }\n return out;\n}\n","/**\n * The exact-tier repulsion stage of ForceAtlas2 (spec 7.6, 7.9, 7.10; contract 3.13): K3, the tiled all-pairs\n * repulsion with the gravity term and the swing / traction epilogue, followed by K4, the one-workgroup speed finalize\n * that folds the per-workgroup partials and runs estimateFactor on the device (D15). P1 ships the stage driven over a\n * pass the caller opens (the tests); P3-T2 records it from ForceAtlas2Model.recordIteration without changing these\n * declarations. Both kernels come from the registry (src/kernels.ts) through the pipeline cache, so a distinct\n * override set is a distinct pipeline and the subgroup twin is selected by the device's features (spec 5.1, D16).\n */\n\nimport { EXACT_TILES_PER_PASS } from \"../constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type DispatchPlan, plan1d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { type PipelineCache } from \"../kernel/pipeline-cache.js\";\nimport { type WgslModuleSpec } from \"../kernel/wgsl.js\";\nimport { kernelSpec } from \"../kernels.js\";\nimport { type PlanCaps } from \"../types/context.js\";\nimport { type Binding } from \"../types/memory.js\";\n\n/** The buffers the exact-tier repulsion stage binds (all in layout units; spec 7.3). */\nexport interface RepulsionExactResources {\n readonly pos: Binding;\n readonly state: Binding;\n readonly trace: Binding;\n readonly force: Binding;\n readonly oldForce: Binding;\n readonly fixedMask: Binding;\n readonly partials: Binding;\n readonly params: Binding;\n}\n\n/** The overrides K3 / K4 compile with. */\nexport interface RepulsionExactOverrides {\n readonly SWING_MODE: 0 | 1;\n readonly STRONG_GRAVITY: boolean;\n readonly GRAVITY_CENTER: 0 | 1;\n}\n\n/**\n * Records K3 over `n` nodes as ceil(tiles / EXACT_TILES_PER_PASS) dispatches (issue #87: llvmpipe's per-invocation\n * loop budget), pass p with p + 1 z slices of which only the last works (the kernel reads the pass from\n * `num_workgroups.z`). One pass up to 32,768 nodes at WG 256. Every model's exact tier records K3 through here.\n * ponytail: pass p also launches p idle slices, sum p over P passes; negligible against the O(n^2) pass work (31\n * passes at 1M nodes); a per-pass uniform removes them if they ever show in a profile.\n * @param kernel - the compiled `fa2-repulsion-exact`\n * @param pass - the open compute pass\n * @param bound - the kernel's bound groups\n * @param plan - plan1d(n) of the kernel\n * @param n - the node count\n * @param paramsOffset - the dynamic offset of the Fa2Params slot\n */\nexport function recordExactRepulsion(\n kernel: Kernel,\n pass: GPUComputePassEncoder,\n bound: BoundKernel,\n plan: DispatchPlan,\n n: number,\n paramsOffset: number,\n): void {\n const passes = Math.max(1, Math.ceil(Math.ceil(n / kernel.workgroupSize) / EXACT_TILES_PER_PASS));\n for (let z = 1; z <= passes; z++) {\n kernel.dispatch(pass, bound, { ...plan, z }, [paramsOffset]);\n }\n}\n\n/** K3 (tiled all-pairs repulsion + gravity + the swing / traction epilogue) followed by K4 (the one-workgroup speed finalize) (spec 7.6, 7.10). */\nexport class RepulsionExact {\n /** The overrides both kernels were compiled with (a frozen copy of the argument of create()). */\n readonly overrides: RepulsionExactOverrides;\n\n private readonly caps: PlanCaps;\n private readonly repulsion: Kernel;\n private readonly speedFinalize: Kernel;\n /** Exactly one workgroup of K4 (spec 7.4: \"1 workgroup\"). */\n private readonly finalizePlan: DispatchPlan;\n private boundRepulsion: BoundKernel | null = null;\n private boundSpeedFinalize: BoundKernel | null = null;\n\n /**\n * Holds the two compiled kernels; create() is the only caller.\n * @param repulsion - the K3 kernel\n * @param speedFinalize - the K4 kernel\n * @param caps - the device caps the dispatch planner reads\n * @param overrides - the override set both kernels were compiled with\n */\n private constructor(repulsion: Kernel, speedFinalize: Kernel, caps: PlanCaps, overrides: RepulsionExactOverrides) {\n this.repulsion = repulsion;\n this.speedFinalize = speedFinalize;\n this.caps = caps;\n this.overrides = Object.freeze({\n SWING_MODE: overrides.SWING_MODE,\n STRONG_GRAVITY: overrides.STRONG_GRAVITY,\n GRAVITY_CENTER: overrides.GRAVITY_CENTER,\n });\n this.finalizePlan = plan1d(speedFinalize.workgroupSize, speedFinalize.workgroupSize, caps);\n }\n\n /**\n * Compiles both kernels through the cache (the twin is selected by caps.features).\n * @param pipelines - the context's pipeline cache\n * @param caps - the device caps the dispatch planner reads\n * @param overrides - the SWING_MODE / STRONG_GRAVITY / GRAVITY_CENTER set of this stage\n * @returns the stage, ready for bind()\n */\n static async create(\n pipelines: PipelineCache,\n caps: PlanCaps,\n overrides: RepulsionExactOverrides,\n ): Promise<RepulsionExact> {\n const [repulsionSpec, finalizeSpec] = RepulsionExact.specs(overrides);\n // Sequential on purpose: PipelineCache.get runs createComputePipelineAsync inside a validation scope, and error\n // scopes form one stack per device, so two interleaved compilations would pop each other's scope.\n const repulsion = await pipelines.kernel(repulsionSpec);\n const speedFinalize = await pipelines.kernel(finalizeSpec);\n return new RepulsionExact(repulsion, speedFinalize, caps, overrides);\n }\n\n /**\n * The two specs (for warm() and the compile matrix).\n * @param overrides - the override set of the stage\n * @returns the K3 spec then the K4 spec\n */\n static specs(overrides: RepulsionExactOverrides): readonly [WgslModuleSpec, WgslModuleSpec] {\n return [\n kernelSpec(\"fa2-repulsion-exact\", {\n SWING_MODE: overrides.SWING_MODE,\n STRONG_GRAVITY: overrides.STRONG_GRAVITY,\n GRAVITY_CENTER: overrides.GRAVITY_CENTER,\n }),\n kernelSpec(\"fa2-speed-finalize\", { SWING_MODE: overrides.SWING_MODE }),\n ];\n }\n\n /**\n * Creates the bind groups once per load(): K3 takes pos, state (S), force, oldForce, fixedMask, partials and the\n * params slot; K4 takes partials, state (S), trace (T) and the params slot (the 3.10.1 binding names). The state\n * header and the trace region are two disjoint ranges of one buffer, which Kernel.bind() accepts (no writable alias).\n * @param resources - the buffers of spec 7.3\n */\n bind(resources: RepulsionExactResources): void {\n this.boundRepulsion = this.repulsion.bind({\n pos: resources.pos,\n S: resources.state,\n force: resources.force,\n oldForce: resources.oldForce,\n fixedMask: resources.fixedMask,\n partials: resources.partials,\n P: resources.params,\n });\n this.boundSpeedFinalize = this.speedFinalize.bind({\n partials: resources.partials,\n S: resources.state,\n T: resources.trace,\n P: resources.params,\n });\n }\n\n /**\n * Records K3 (plan1d(n)) then K4 (1 workgroup) with the params slot's dynamic offset.\n * @param pass - the open compute pass of the batch\n * @param n - the node count (rows [0, n) of pos / force)\n * @param paramsOffset - the dynamic offset of this iteration's Fa2Params slot in the uniform ring\n */\n record(pass: GPUComputePassEncoder, n: number, paramsOffset: number): void {\n this.recordRepulsion(pass, n, paramsOffset);\n this.recordSpeedFinalize(pass, paramsOffset);\n }\n\n /**\n * Records K3 only (the inspect() stage split, spec 11.9 item 2).\n * @param pass - the open compute pass\n * @param n - the node count\n * @param paramsOffset - the dynamic offset of the Fa2Params slot\n * @internal\n */\n recordRepulsion(pass: GPUComputePassEncoder, n: number, paramsOffset: number): void {\n const bound = this.bound(this.boundRepulsion, \"recordRepulsion\");\n const plan = plan1d(n, this.repulsion.workgroupSize, this.caps);\n recordExactRepulsion(this.repulsion, pass, bound, plan, n, paramsOffset);\n }\n\n /**\n * Records K4 only.\n * @param pass - the open compute pass\n * @param paramsOffset - the dynamic offset of the Fa2Params slot\n * @internal\n */\n recordSpeedFinalize(pass: GPUComputePassEncoder, paramsOffset: number): void {\n const bound = this.bound(this.boundSpeedFinalize, \"recordSpeedFinalize\");\n this.speedFinalize.dispatch(pass, bound, this.finalizePlan, [paramsOffset]);\n }\n\n /**\n * The bound kernel of a method, or E_NOT_LOADED when bind() has not run.\n * @param bound - the cached BoundKernel, null before bind()\n * @param method - the caller's name for the message\n * @returns the bound kernel\n */\n private bound(bound: BoundKernel | null, method: string): BoundKernel {\n if (bound === null) {\n throw new WebGpuGraphError(\n \"E_NOT_LOADED\",\n `RepulsionExact.${method}(): bind() has not been called for this stage`,\n {\n state: \"unbound\",\n },\n );\n }\n return bound;\n }\n}\n","/**\n * The grid pyramid (spec 6 row 12, 7.7 G4-G5; P4-T9): the planner that records, into the caller's pass, the finest\n * centroids (G4, `grid-centroid`: thread per cell over `cells + outsideCells`, the pseudo-cells included), the hub-cell\n * completion (G4b: `grid-centroid-hub`, one workgroup per hub cell; PD-13) and one `grid-downsample` dispatch per\n * coarser level (G5). G4b is a DIRECT dispatch of one workgroup per word of `hubList` -- the most hub cells the graph\n * can hold -- and the kernel's `h < hubCount[0]` guard idles the workgroups past the count. It was an indirect\n * dispatch from a finalize-written args slot until issue #732: Dawn validates every indirect dispatch with a hidden\n * pass that cost 0.3 to 0.9 ms of device time per iteration, several times the whole grid tier's own work at 10k\n * nodes (the frontier kernels' lesson, docs/decisions/G8.md G8-F5). The idle workgroups cost far less: `hubList` holds\n * `ceil(n / GRID_HUB_CELL)` words, so 977 workgroups at 1M nodes, each reading one word. 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\n * children; the pseudo-cells (indices `cells ..` of level 0) are never children. No atomics touch the sums (design 6 row 12:\n * bitwise reproducible); the only atomics are the hub append and the occupancy max.\n *\n * The named grid buffers (`pyramid`, `hubList`, `hubCounters`) are the caller's (the model's\n * `BufferSpec`s, so `inspect(name)` reaches them); the static params of every level are written\n * ONCE at bind() through the scope's params writer (PD-11), so record() writes no uniform. `src/primitives/**` never\n * imports `src/context.ts`.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d, plan2d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { GRID_LEVEL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GridSpec } from \"./grid.js\";\nimport { type ReduceScope } from \"./reduce.js\";\n\n/**\n * The buffers the pyramid build reads and writes (the model's named buffers). The parameter type of\n * GridPyramidPlanner.bind (knip: exported for the signature, not imported by name).\n * @public\n */\nexport interface GridPyramidBindings {\n /** `array<vec4f>` positions (xyz, mass). */\n readonly pos: Binding;\n /** The `Fa2Params` uniform ring (`dim`, `gridMax`); `record()` takes the iteration's dynamic offset. */\n readonly params: Binding;\n /** `n` words: the sorted node indices (the T8 build). */\n readonly sortedIdx: Binding;\n /** `histWords` (`cells + 2^dim + 1`) words: the exclusive scan of the cell histogram (the T8 build). */\n readonly cellStart: Binding;\n /** `pyramidCells` vec4f: every level, level 0 first with the 2^dim orthant pseudo-cells from index `cells`. */\n readonly pyramid: Binding;\n /** The hub cells' indices, appended by G4 (at least one word; at most `floor(n / (GRID_HUB_CELL + 1))` are ever written, so `ceil(n / GRID_HUB_CELL)` words always suffice). Its word count is G4b's workgroup count. */\n readonly hubList: Binding;\n /** Two u32 (bound whole, at least 8 bytes): `[0]` the hub count, `[1]` the largest cell occupancy; the caller zeroes both before every build (K1, T10). */\n readonly hubCounters: Binding;\n}\n\n/** Where `record()` stops: after level 0 is whole (G4 and G4b) or after every coarser level (G5, the default). */\nexport type GridPyramidStage = \"G4\" | \"G5\";\n\n/** A prepared pyramid build (spec 7.7 G4-G5): binds once per load, records the stages of one iteration into a pass. */\nexport interface GridPyramidPlanner {\n /**\n * Binds the named buffers and writes the static params of every level (PD-11); called once\n * per load (a second call rebinds and writes fresh params, so it belongs to a reload, never to an iteration).\n * @param bindings - the buffers\n */\n bind(bindings: GridPyramidBindings): void;\n /**\n * Records G4, G4b and then G5 for every coarser level at the `Fa2Params` slot `paramsOffset`; `upTo: \"G4\"`\n * stops after G4b (level 0 is whole: G4b is G4's completion).\n * @param pass - the compute pass\n * @param paramsOffset - the dynamic offset of this iteration's `Fa2Params`\n * @param upTo - the last stage to record (default \"G5\")\n */\n record(pass: GPUComputePassEncoder, paramsOffset: number, upTo?: GridPyramidStage): void;\n /** Dispatches the last record() issued: 2 after `upTo: \"G4\"`, `2 + (levels - 1)` for a full record. */\n readonly lastDispatches: number;\n}\n\n/**\n * Prepares the pyramid's pipelines over a scope (G4, G4b and G5; compiles once) so bind() and record()\n * are synchronous. The planner lives exactly as long as the scope.\n * @param scope - the caller's scope (device, caps, cache, scratch, params)\n * @param spec - the grid\n * @returns the planner\n */\nexport async function preparePyramid(scope: ReduceScope, spec: GridSpec): Promise<GridPyramidPlanner> {\n const centroid = await scope.pipelines.kernel(kernelSpec(\"grid-centroid\"));\n const hub = await scope.pipelines.kernel(kernelSpec(\"grid-centroid-hub\"));\n const downsample = await scope.pipelines.kernel(kernelSpec(\"grid-downsample\"));\n return new GridPyramidPlannerImpl(scope, spec, { centroid, hub, downsample });\n}\n\n/** The three kernels of the build. */\ninterface Kernels {\n readonly centroid: Kernel;\n readonly hub: Kernel;\n readonly downsample: Kernel;\n}\n\n/** What bind() prepared: the bound groups and, per coarser level, its bound group with its params offset. */\ninterface Bound {\n readonly centroid: BoundKernel;\n readonly hub: BoundKernel;\n /** G4b's workgroups: one per word of `hubList`. */\n readonly hubSlots: number;\n readonly levels: readonly { readonly bound: BoundKernel; readonly offset: number; readonly parentCells: number }[];\n}\n\n/** The planner: G4, G4b and G5 over one scope. */\nclass GridPyramidPlannerImpl implements GridPyramidPlanner {\n private readonly scope: ReduceScope;\n private readonly spec: GridSpec;\n private readonly kernels: Kernels;\n private bound: Bound | null = null;\n private dispatches = 0;\n\n /**\n * Wraps the resolved kernels; use preparePyramid().\n * @param scope - the caller's scope\n * @param spec - the grid\n * @param kernels - the three kernels\n */\n constructor(scope: ReduceScope, spec: GridSpec, kernels: Kernels) {\n this.scope = scope;\n this.spec = spec;\n this.kernels = kernels;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns the count\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Binds the buffers and writes the static params (see the interface).\n * @param bindings - the buffers\n */\n bind(bindings: GridPyramidBindings): void {\n const { centroid, hub, downsample } = this.kernels;\n const { spec, scope } = this;\n const b = bindings;\n const levels: { readonly bound: BoundKernel; readonly offset: number; readonly parentCells: number }[] = [];\n let parentSide = spec.g;\n for (let level = 0; level + 1 < spec.levels; level++) {\n parentSide /= 2;\n const parentCells = parentSide ** spec.dim;\n const params = scope.params(GRID_LEVEL_PARAMS, {\n childBase: spec.levelOffsets[level],\n parentBase: spec.levelOffsets[level + 1],\n parentSide,\n parentCells,\n depth: spec.dim === 3 ? 2 : 1,\n pad0: 0,\n pad1: 0,\n pad2: 0,\n });\n levels.push({\n bound: downsample.bind({ pyramid: b.pyramid, P: params.binding }),\n offset: params.offset,\n parentCells,\n });\n }\n this.bound = {\n centroid: centroid.bind({\n sortedIdx: b.sortedIdx,\n cellStart: b.cellStart,\n pos: b.pos,\n pyramid: b.pyramid,\n hubList: b.hubList,\n hubCounters: b.hubCounters,\n P: b.params,\n }),\n hub: hub.bind({\n sortedIdx: b.sortedIdx,\n cellStart: b.cellStart,\n pos: b.pos,\n pyramid: b.pyramid,\n hubList: b.hubList,\n hubCount: b.hubCounters,\n P: b.params,\n }),\n hubSlots: Math.floor(b.hubList.size / 4),\n levels,\n };\n }\n\n /**\n * Records the stages (see the interface).\n * @param pass - the compute pass\n * @param paramsOffset - the `Fa2Params` dynamic offset\n * @param upTo - the last stage\n */\n record(pass: GPUComputePassEncoder, paramsOffset: number, upTo?: GridPyramidStage): void {\n const { bound, scope, spec } = this;\n if (bound === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"gridPyramid: record() before bind()\", { argument: \"bind\" });\n }\n const { centroid, hub, downsample } = this.kernels;\n const level0 = spec.cells + spec.outsideCells;\n centroid.dispatch(pass, bound.centroid, plan1d(level0, scope.workgroupSize, scope.caps), [paramsOffset]);\n hub.dispatch(pass, bound.hub, plan2d(bound.hubSlots, scope.caps), [paramsOffset]);\n this.dispatches = 2;\n if ((upTo ?? \"G5\") === \"G4\") {\n return;\n }\n for (const level of bound.levels) {\n downsample.dispatch(pass, level.bound, plan1d(level.parentCells, scope.workgroupSize, scope.caps), [\n level.offset,\n ]);\n this.dispatches += 1;\n }\n }\n}\n","/**\n * The grid-tier repulsion stage of the force models (spec 7.7, 7.4; P4-T10): G1-G3 through the T8 grid build, G4-G5\n * through the T9 pyramid, then G6 (`grid-far-field`) and G7 (`grid-near-field`, K3's pair law and epilogue) over\n * `plan1d(n)`, followed by K4 (`fa2-speed-finalize`) exactly as `RepulsionExact` records it. The named grid buffers\n * are the model's `BufferSpec`s (`buffers()`, so `inspect(name)` reaches them); the anonymous scratch of the sort\n * and the scan and the static params of the pyramid draw on ONE `Lease` of the context's pool taken at `create()`\n * (the scan planner takes its block-sum levels at prepare time) and released by `dispose()` (PD-11, DEP-P4-D: a\n * per-batch lease would rebuild the G2-G4 bind groups every batch; a model creates one stage per bind(), so a stage\n * is bound once). The stage is the ONE class every model reaches the grid tier through (PD-22): the FR and\n * spring-electrical models pass `LAW` 1 / 2 in their override set, which reaches G6's per-cell law and G7's pair law\n * (P4-T13).\n */\n\nimport { GRID_HUB_CELL } from \"../constants.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { type PipelineCache } from \"../kernel/pipeline-cache.js\";\nimport { type UniformBlock, type UniformValues } from \"../kernel/struct-block.js\";\nimport { type WgslModuleSpec } from \"../kernel/wgsl.js\";\nimport { kernelSpec } from \"../kernels.js\";\nimport { type BufferPool } from \"../memory/buffer-pool.js\";\nimport { type Lease } from \"../memory/lease.js\";\nimport {\n type GridBuildPlanner,\n type GridBuildStage,\n gridPyramidBytes,\n type GridSpec,\n prepareGridBuild,\n} from \"../primitives/grid.js\";\nimport { type GridPyramidPlanner, preparePyramid } from \"../primitives/grid-pyramid.js\";\nimport { type ReduceScope } from \"../primitives/reduce.js\";\nimport { type PlanCaps } from \"../types/context.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type BufferSpec } from \"./force-simulation.js\";\nimport { type RepulsionExactOverrides, type RepulsionExactResources } from \"./repulsion-exact.js\";\n\n/** The stage names the grid tier records, in dispatch order (the `upTo` vocabulary of recordRepulsion). */\nconst GRID_STAGES = [\"G1\", \"G2\", \"G3\", \"G4\", \"G5\", \"G6\", \"G7\"] as const;\n\n/** A grid stage name. */\nexport type GridStage = (typeof GRID_STAGES)[number];\n\n/**\n * The buffers the grid-tier repulsion stage binds: the exact tier's plus the named grid buffers of `buffers()`. The\n * parameter type of RepulsionGrid.bind (knip: exported for the signature, not imported by name).\n * @public\n */\nexport interface RepulsionGridResources extends RepulsionExactResources {\n readonly cellKey: Binding;\n readonly cellVal: Binding;\n readonly sortedKey: Binding;\n readonly sortedIdx: Binding;\n readonly cellHist: Binding;\n readonly cellStart: Binding;\n readonly hubList: Binding;\n readonly hubCounters: Binding;\n readonly pyramid: Binding;\n}\n\n/**\n * The override set G6 / G7 / K4 compile with: K3's three plus the repulsion law (0 FA2, 1 FR, 2 coulomb; P4-T13,\n * PD-22).\n * @public\n */\nexport interface RepulsionGridOverrides extends RepulsionExactOverrides {\n readonly LAW: 0 | 1 | 2;\n}\n\n/**\n * What the stage needs of the context to build its scope: the pieces `ModelResources` carries. The parameter type\n * of RepulsionGrid.create (knip: exported for the signature, not imported by name).\n * @public\n */\nexport interface RepulsionGridScope {\n readonly device: GPUDevice;\n readonly caps: PlanCaps;\n readonly pipelines: PipelineCache;\n readonly pool: BufferPool;\n}\n\n/** The storage usage of every grid buffer. */\nconst STORAGE_RW = BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST;\n\n/** The lease the scope's scratch() and params() draw on: taken at create(), null after dispose(). */\ninterface LeaseBox {\n lease: Lease | null;\n}\n\n/**\n * The stage's lease, or E_DISPOSED after dispose().\n * @param box - the stage's lease box\n * @returns the lease\n */\nfunction leaseOf(box: LeaseBox): Lease {\n if (box.lease === null) {\n throw new WebGpuGraphError(\"E_DISPOSED\", \"RepulsionGrid: the stage was disposed\", { label: \"RepulsionGrid\" });\n }\n return box.lease;\n}\n\n/**\n * A uniform buffer of the lease holding one written record of `block` (the pyramid's static params, PD-11).\n * @param device - the device\n * @param lease - the stage's lease\n * @param block - the uniform block\n * @param values - the values to write\n * @returns the whole-buffer binding and a zero dynamic offset\n */\nfunction writeParams(\n device: GPUDevice,\n lease: Lease,\n block: UniformBlock,\n values: UniformValues,\n): { readonly binding: Binding; readonly offset: number } {\n const buffer = lease.uniform(block.byteLength, `grid/${block.name}`);\n const bytes = new ArrayBuffer(block.byteLength);\n block.write(new DataView(bytes), values);\n device.queue.writeBuffer(buffer, 0, bytes);\n return { binding: { buffer, offset: 0, size: block.byteLength, window: null }, offset: 0 };\n}\n\n/**\n * The G6 spec of an override set (the law alone).\n * @param overrides - the override set of the stage\n * @returns the spec\n */\nfunction farFieldSpec(overrides: RepulsionGridOverrides): WgslModuleSpec {\n return kernelSpec(\"grid-far-field\", { LAW: overrides.LAW });\n}\n\n/**\n * The G7 spec of an override set (K3's four).\n * @param overrides - the override set of the stage\n * @returns the spec\n */\nfunction nearFieldSpec(overrides: RepulsionGridOverrides): WgslModuleSpec {\n return kernelSpec(\"grid-near-field\", {\n SWING_MODE: overrides.SWING_MODE,\n STRONG_GRAVITY: overrides.STRONG_GRAVITY,\n GRAVITY_CENTER: overrides.GRAVITY_CENTER,\n LAW: overrides.LAW,\n });\n}\n\n/** The three kernels the stage dispatches itself (the planners hold the others). */\ninterface FieldKernels {\n readonly far: Kernel;\n readonly near: Kernel;\n readonly speedFinalize: Kernel;\n}\n\n/** What bind() produced. */\ninterface Bound {\n readonly far: BoundKernel;\n readonly near: BoundKernel;\n readonly speedFinalize: BoundKernel;\n}\n\n/** G1-G7 then K4 (spec 7.7, 7.4): the grid tier's repulsion stage. */\nexport class RepulsionGrid {\n /** The overrides G6 / G7 / K4 were compiled with (a frozen copy of the argument of create()). */\n readonly overrides: RepulsionGridOverrides;\n /** The grid geometry the stage was prepared for. */\n readonly spec: GridSpec;\n\n private readonly caps: PlanCaps;\n private readonly workgroupSize: number;\n private readonly box: LeaseBox;\n private readonly build: GridBuildPlanner;\n private readonly pyramid: GridPyramidPlanner;\n private readonly far: Kernel;\n private readonly near: Kernel;\n private readonly speedFinalize: Kernel;\n private bound: Bound | null = null;\n\n /**\n * Holds the planners and kernels; create() is the only caller.\n * @param scope - the context pieces\n * @param workgroupSize - the device's workgroup size (every kernel compiles with it)\n * @param overrides - the override set G6 / G7 / K4 were compiled with\n * @param spec - the grid\n * @param box - the lease box the scope's scratch() and params() read\n * @param build - the T8 planner (G1-G3)\n * @param pyramid - the T9 planner (G4-G5)\n * @param kernels - G6 (`far`), G7 (`near`) and K4 (`speedFinalize`)\n */\n private constructor(\n scope: RepulsionGridScope,\n workgroupSize: number,\n overrides: RepulsionGridOverrides,\n spec: GridSpec,\n box: LeaseBox,\n build: GridBuildPlanner,\n pyramid: GridPyramidPlanner,\n kernels: FieldKernels,\n ) {\n this.caps = scope.caps;\n this.box = box;\n this.workgroupSize = workgroupSize;\n this.overrides = Object.freeze({\n SWING_MODE: overrides.SWING_MODE,\n STRONG_GRAVITY: overrides.STRONG_GRAVITY,\n GRAVITY_CENTER: overrides.GRAVITY_CENTER,\n LAW: overrides.LAW,\n });\n this.spec = spec;\n this.build = build;\n this.pyramid = pyramid;\n this.far = kernels.far;\n this.near = kernels.near;\n this.speedFinalize = kernels.speedFinalize;\n }\n\n /**\n * The model-owned buffers of the grid tier (spec 7.3; PD-11): `cellKey` / `cellVal` / `sortedKey` / `sortedIdx`\n * 4n, `cellHist` / `cellStart` 4 histWords (cells + 2^dim + 1) zeroed, `hubList` one word per possible hub cell, `pyramid` 16 B per pyramid cell zeroed. `hubCounters` (16 B, zeroed) is the MODEL's on every\n * tier (PD-14: K1 binds it on the exact tier too). n = 0 reports one node's worth of bytes (spec 3.6).\n * @param n - the node count\n * @param spec - the grid\n * @returns the specs\n */\n static buffers(n: number, spec: GridSpec): readonly BufferSpec[] {\n const words = 4 * Math.max(1, n);\n return [\n { name: \"cellKey\", byteLength: words, usage: STORAGE_RW, zero: false },\n { name: \"cellVal\", byteLength: words, usage: STORAGE_RW, zero: false },\n { name: \"sortedKey\", byteLength: words, usage: STORAGE_RW, zero: false },\n { name: \"sortedIdx\", byteLength: words, usage: STORAGE_RW, zero: false },\n { name: \"cellHist\", byteLength: 4 * spec.histWords, usage: STORAGE_RW, zero: true },\n { name: \"cellStart\", byteLength: 4 * spec.histWords, usage: STORAGE_RW, zero: true },\n {\n name: \"hubList\",\n byteLength: 4 * Math.max(1, Math.ceil(n / GRID_HUB_CELL)),\n usage: STORAGE_RW,\n zero: false,\n },\n { name: \"pyramid\", byteLength: gridPyramidBytes(spec), usage: STORAGE_RW, zero: true },\n ];\n }\n\n /**\n * The module specs of the grid tier under an override set (for warm() and the compile matrix): the build's\n * (G1, the sort path `spec.deterministic` selects, the histogram, the scan, the fill), the pyramid's (G4, the\n * finalize, G4b, G5), G6, G7 and K4.\n * @param overrides - the override set of the stage\n * @param spec - the grid (only its `deterministic` flag matters: the pipeline key carries no geometry)\n * @returns the specs\n */\n static specs(overrides: RepulsionGridOverrides, spec: GridSpec): readonly WgslModuleSpec[] {\n const sort: WgslModuleSpec[] = spec.deterministic\n ? [kernelSpec(\"radix-hist\"), kernelSpec(\"radix-scatter\"), kernelSpec(\"scan-block\"), kernelSpec(\"scan-add\")]\n : [kernelSpec(\"counting-scatter\"), kernelSpec(\"scan-block\"), kernelSpec(\"scan-add\")];\n return [\n kernelSpec(\"grid-cell-key\"),\n ...sort,\n kernelSpec(\"histogram\"),\n kernelSpec(\"fill\"),\n kernelSpec(\"grid-centroid\"),\n kernelSpec(\"grid-centroid-hub\"),\n kernelSpec(\"grid-downsample\"),\n farFieldSpec(overrides),\n nearFieldSpec(overrides),\n kernelSpec(\"fa2-speed-finalize\", { SWING_MODE: overrides.SWING_MODE }),\n ];\n }\n\n /**\n * Compiles every kernel of the tier through the cache (sequentially: PipelineCache.get compiles inside a\n * validation scope, one stack per device) over a scope whose scratch and params draw on the stage's lease.\n * @param scope - the context pieces (device, caps, pipelines, pool)\n * @param workgroupSize - the device's workgroup size\n * @param overrides - the SWING_MODE / STRONG_GRAVITY / GRAVITY_CENTER / LAW set of this stage\n * @param spec - the grid\n * @returns the stage, ready for bind()\n */\n static async create(\n scope: RepulsionGridScope,\n workgroupSize: number,\n overrides: RepulsionGridOverrides,\n spec: GridSpec,\n ): Promise<RepulsionGrid> {\n const box: LeaseBox = { lease: scope.pool.lease() };\n const reduceScope: ReduceScope = {\n device: scope.device,\n caps: scope.caps,\n pipelines: scope.pipelines,\n pool: scope.pool,\n workgroupSize,\n scratch: (byteLength: number, label: string): GPUBuffer => leaseOf(box).storage(byteLength, label),\n params: (\n block: UniformBlock,\n values: UniformValues,\n ): { readonly binding: Binding; readonly offset: number } =>\n writeParams(scope.device, leaseOf(box), block, values),\n };\n try {\n const build = await prepareGridBuild(reduceScope, spec);\n const pyramid = await preparePyramid(reduceScope, spec);\n const far = await scope.pipelines.kernel(farFieldSpec(overrides));\n const near = await scope.pipelines.kernel(nearFieldSpec(overrides));\n const speedFinalize = await scope.pipelines.kernel(\n kernelSpec(\"fa2-speed-finalize\", { SWING_MODE: overrides.SWING_MODE }),\n );\n return new RepulsionGrid(scope, workgroupSize, overrides, spec, box, build, pyramid, {\n far,\n near,\n speedFinalize,\n });\n } catch (error) {\n leaseOf(box).release();\n throw error;\n }\n }\n\n /**\n * Builds every bind group once per load(): the build's and the pyramid's bind() (which take their scratch and\n * write their static params through the lease), then G6, G7 and K4 against the named buffers (the 3.10.1\n * binding names). A second bind() takes fresh scratch from the same lease and the first bind()'s scratch stays\n * held until dispose(): the one lease also holds the prepare-time allocations (the scan's block-sum levels), so\n * it cannot be released on a rebind (the model creates one stage per bind(), so a rebind never happens).\n * @param resources - the buffers of spec 7.3 plus the grid's\n */\n bind(resources: RepulsionGridResources): void {\n leaseOf(this.box);\n const r = resources;\n this.build.bind({\n pos: r.pos,\n state: r.state,\n params: r.params,\n cellKey: r.cellKey,\n cellVal: r.cellVal,\n sortedKey: r.sortedKey,\n sortedIdx: r.sortedIdx,\n cellHist: r.cellHist,\n cellStart: r.cellStart,\n });\n this.pyramid.bind({\n pos: r.pos,\n params: r.params,\n sortedIdx: r.sortedIdx,\n cellStart: r.cellStart,\n pyramid: r.pyramid,\n hubList: r.hubList,\n hubCounters: r.hubCounters,\n });\n this.bound = {\n far: this.far.bind({\n pos: r.pos,\n sortedIdx: r.sortedIdx,\n pyramid: r.pyramid,\n S: r.state,\n force: r.force,\n P: r.params,\n }),\n near: this.near.bind({\n pos: r.pos,\n sortedIdx: r.sortedIdx,\n cellStart: r.cellStart,\n S: r.state,\n force: r.force,\n oldForce: r.oldForce,\n fixedMask: r.fixedMask,\n partials: r.partials,\n P: r.params,\n }),\n speedFinalize: this.speedFinalize.bind({ partials: r.partials, S: r.state, T: r.trace, P: r.params }),\n };\n }\n\n /**\n * Records G1..G7 for `n` nodes with the params slot's dynamic offset, stopping after `upTo` when given (spec 7.4\n * grid sequence; the inspect() stage split, spec 11.9 item 2): G1-G3 through the build planner, G4-G5 through the\n * pyramid planner, then G6 and G7 over plan1d(n).\n * @param pass - the open compute pass of the batch\n * @param n - the node count (in [1, the capacity of the grid buffers])\n * @param paramsOffset - the dynamic offset of this iteration's Fa2Params slot in the uniform ring\n * @param upTo - the last grid stage to record (default \"G7\")\n */\n recordRepulsion(pass: GPUComputePassEncoder, n: number, paramsOffset: number, upTo?: GridStage): void {\n const bound = this.requireBound(\"recordRepulsion\");\n const stop = GRID_STAGES.indexOf(upTo ?? \"G7\");\n let buildStop: GridBuildStage = \"G3\";\n if (stop === 0) {\n buildStop = \"G1\";\n } else if (stop === 1) {\n buildStop = \"G2\";\n }\n this.build.record(pass, n, paramsOffset, buildStop);\n if (stop < 3) {\n return;\n }\n this.pyramid.record(pass, paramsOffset, stop === 3 ? \"G4\" : \"G5\");\n if (stop < 5) {\n return;\n }\n const plan = plan1d(n, this.workgroupSize, this.caps);\n this.far.dispatch(pass, bound.far, plan, [paramsOffset]);\n if (stop < 6) {\n return;\n }\n this.near.dispatch(pass, bound.near, plan, [paramsOffset]);\n }\n\n /**\n * Records K4 only (one workgroup).\n * @param pass - the open compute pass\n * @param paramsOffset - the dynamic offset of the Fa2Params slot\n */\n recordSpeedFinalize(pass: GPUComputePassEncoder, paramsOffset: number): void {\n const bound = this.requireBound(\"recordSpeedFinalize\");\n const one = plan1d(this.speedFinalize.workgroupSize, this.speedFinalize.workgroupSize, this.caps);\n this.speedFinalize.dispatch(pass, bound.speedFinalize, one, [paramsOffset]);\n }\n\n /** Releases the lease (the sort and scan scratch, the static params) and drops the bind groups; idempotent. */\n dispose(): void {\n if (this.box.lease !== null) {\n this.box.lease.release();\n this.box.lease = null;\n }\n for (const kernel of [this.far, this.near, this.speedFinalize]) {\n kernel.invalidate();\n }\n this.bound = null;\n }\n\n /**\n * The bound groups, or E_NOT_LOADED when bind() has not run.\n * @param method - the caller's name for the message\n * @returns the bound groups\n */\n private requireBound(method: string): Bound {\n if (this.bound === null) {\n throw new WebGpuGraphError(\n \"E_NOT_LOADED\",\n `RepulsionGrid.${method}(): bind() has not been called for this stage`,\n {\n state: \"unbound\",\n },\n );\n }\n return this.bound;\n }\n}\n","/**\n * ForceAtlas2 on the exact repulsion tier (spec 7.1-7.18; contract 3.13): the ForceModel that ForceSimulation\n * drives -- the K1 K2 K3 K4 K5 sequence per iteration and toScene per batch (spec 7.4), the override set of the option\n * record (spec 7.2 with the 4.6 NetworkX corrections), the per-iteration Fa2Params values, the controller resets of\n * spec 7.17 and the stats decoder -- plus the two option resolvers and `createForceAtlas2`. Positions are vec4f\n * (xyz + mass) in layout units on the device (D23, 7.18); the speed controller runs on the device (D15); no\n * displacement clamp (D25); K2 runs the degree tiers over `degreeOrder()` (P4 PD-7).\n *\n * Model decisions this file fixes (the plan of P3-T2 lists the reasons): recordIteration with no `upTo` records every\n * stage including toScene; on the exact tier the K1-K5 dispatches of every iteration of one batch share ONE compute\n * pass (opened by the batch's first recordIteration and remembered by batch id) and toScene runs in a second pass\n * that ends it (contract 4.4); the fill kernel takes its FillParams from a model-owned 256-byte uniform buffer\n * (\"fillParams\"); the first iteration after every load() zeroes oldForce with a fill (paper mode). The grid tier\n * (P4-T10) is reached through `RepulsionGrid` when `tierFor(tuning, n)` says so (PD-18): `buffers()` adds the grid\n * buffers, K1 derives the frame under `gridMax > 0` (PD-14), the iteration is recorded as the three passes `fa2-k1`\n * / `fa2-attraction` / `fa2-grid` before `fa2-to-scene` (PD-16), and `stages` is the union list of both tiers\n * (PD-17: `upTo` stops after the last stage recorded at or before its position).\n */\n\nimport { type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport {\n EXACT_MAX_NODES,\n FA2_DEFAULTS,\n GRID_BBOX_MARGIN,\n GRID_EXTENT_FLOOR,\n LAYOUT_TUNING_DEFAULTS,\n MAX_ITERATIONS_PER_STEP,\n SETTLE_FLOOR_UNBOUNDED,\n TRACE_RECORD_BYTES,\n UNIFORM_SLOT_BYTES,\n} from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type CommandBatch } from \"../kernel/batch.js\";\nimport { type DispatchPlan, plan1d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { type UniformBlock, type UniformValues } from \"../kernel/struct-block.js\";\nimport { type WgslModuleSpec } from \"../kernel/wgsl.js\";\nimport { FA2_PARAMS, FA2_STATE, FA2_TRACE, FILL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { arcCountOf } from \"../primitives/core-shape.js\";\nimport { type GridSpec, gridSpecFor } from \"../primitives/grid.js\";\nimport {\n type ForceAtlas2Stats,\n type ForceAtlas2TraceRecord,\n type GpuLayoutSimulation,\n type GpuLayoutTuning,\n type ResolvedLayoutTuning,\n} from \"../types/layout.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ForceAtlas2Options, type ResolvedForceAtlas2Options } from \"../types/options.js\";\nimport {\n type BufferSpec,\n type ForceModel,\n ForceSimulation,\n type ModelInputs,\n type ModelResources,\n type StateWriter,\n tierFor,\n} from \"./force-simulation.js\";\nimport { resolveNodeMass, resolveWeights } from \"./inputs.js\";\nimport {\n type AttractionBound,\n bindAttraction,\n describeValue,\n FILL_PARAMS_BUFFER,\n FORCE_BYTES_PER_NODE,\n invalid,\n isPositiveInteger,\n type Overrides,\n pickBoolean,\n pickCenter,\n pickDim,\n pickNumber,\n pickSeed,\n recordAttraction,\n scalar,\n seedWord,\n subset,\n vector,\n} from \"./model-common.js\";\nimport { RepulsionExact, type RepulsionExactOverrides } from \"./repulsion-exact.js\";\nimport { type GridStage, RepulsionGrid, type RepulsionGridOverrides } from \"./repulsion-grid.js\";\n\n// ============================================================ constants and small helpers\n\n/** The stage names of both tiers in dispatch order plus the per-batch toScene (spec 7.4; contract 3.13; P4 PD-17): the exact tier records K1 K2 K3 K4 K5, the grid tier K1 K2 G1..G7 K4 K5. */\nconst FA2_STAGES = [\"K1\", \"K2\", \"K3\", \"G1\", \"G2\", \"G3\", \"G4\", \"G5\", \"G6\", \"G7\", \"K4\", \"K5\", \"toScene\"] as const;\n\n/** The FA2_STAGES index of the first grid stage, of K4, of K5 and of toScene. */\nconst STAGE_G1 = 3;\nconst STAGE_K4 = 10;\nconst STAGE_K5 = 11;\nconst STAGE_TO_SCENE = 12;\n\n/** The name of the model-owned hub-counter buffer K1 binds on every tier (P4 PD-14). */\nconst HUB_COUNTERS_BUFFER = \"hubCounters\";\n\n/** The one-workgroup dispatch of K1 (spec 7.4). */\nconst ONE_WORKGROUP: DispatchPlan = { x: 1, y: 1, z: 1, items: 1, stride: null };\n\n/** Every override K2 accepts, with its default (contract 3.10.1 plus the two standard graph overrides). */\nconst K2_DEFAULTS: Overrides = { LINLOG: false, DISTRIBUTED: false, TIER: 0, USE_PERM: false, HAS_WEIGHTS: false };\n\n/** Every override K5 accepts, with its default. */\nconst K5_DEFAULTS: Overrides = { SWING_MODE: 0 };\n\n/** The resolved record with no option given: FA2_DEFAULTS plus the null / origin defaults of spec 7.14. */\nconst DEFAULT_RESOLVED: ResolvedForceAtlas2Options = Object.freeze<ResolvedForceAtlas2Options>({\n ...FA2_DEFAULTS,\n nodeMass: null,\n nodeSize: null,\n weight: null,\n center: [0, 0, 0],\n seed: null,\n});\n\n/**\n * The K3 / K4 override values of a merged set (typed for RepulsionExact).\n * @param merged - the merged override set\n * @returns the three K3 / K4 overrides\n */\nfunction repulsionOverrides(merged: Overrides): RepulsionExactOverrides {\n return {\n SWING_MODE: merged.SWING_MODE === 1 ? 1 : 0,\n STRONG_GRAVITY: merged.STRONG_GRAVITY === true,\n GRAVITY_CENTER: merged.GRAVITY_CENTER === 1 ? 1 : 0,\n };\n}\n\n/**\n * The G6 / G7 / K4 override values of a merged set (typed for RepulsionGrid): K3's three and the FA2 law (P4-T13).\n * @param merged - the merged override set\n * @returns the grid stage's overrides\n */\nfunction gridOverrides(merged: Overrides): RepulsionGridOverrides {\n return { ...repulsionOverrides(merged), LAW: 0 };\n}\n\n// ============================================================ the resolvers\n\n/**\n * Applies FA2_DEFAULTS to the option record; validates ranges (spec 7.14; contract 3.13). With `previous` the record\n * is a PATCH over it (an absent or explicitly undefined field keeps the previous value) and `maxInFlight` may not\n * change (the uniform ring is sized by it at construction). `nodeSize` is E_UNSUPPORTED { option: \"nodeSize\" } (the\n * adjustSizes correction is deferred); `dissuadeHubs` is kept and ignored, exactly like the CPU.\n * @param options - the caller's options (or a setParams patch)\n * @param previous - the current resolved record when resolving a patch\n * @returns the frozen resolved record\n */\nexport function resolveForceAtlas2Options(\n options: ForceAtlas2Options | undefined,\n previous?: ResolvedForceAtlas2Options,\n): ResolvedForceAtlas2Options {\n const o: ForceAtlas2Options = options ?? {};\n const base = previous ?? DEFAULT_RESOLVED;\n if (previous !== undefined && o.maxInFlight !== undefined && o.maxInFlight !== previous.maxInFlight) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `maxInFlight cannot change after creation (the uniform ring is sized by it): got ${describeValue(o.maxInFlight)}, current ${previous.maxInFlight}`,\n { argument: \"maxInFlight\", value: o.maxInFlight, expected: previous.maxInFlight },\n );\n }\n const nodeSize = o.nodeSize === undefined ? base.nodeSize : o.nodeSize;\n if (nodeSize !== null) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n \"nodeSize (the adjustSizes correction) is not supported by the GPU ForceAtlas2 yet (spec 7.14)\",\n { option: \"nodeSize\", hint: \"pass nodeSize: null; the size-aware repulsion is deferred (spec 7.2, Q-25)\" },\n );\n }\n const resolved: ResolvedForceAtlas2Options = {\n maxIter: pickNumber(\"maxIter\", o.maxIter, base.maxIter, isPositiveInteger, \"an integer >= 1\"),\n jitterTolerance: pickNumber(\"jitterTolerance\", o.jitterTolerance, base.jitterTolerance, (v) => v > 0, \"> 0\"),\n scalingRatio: pickNumber(\"scalingRatio\", o.scalingRatio, base.scalingRatio, (v) => v > 0, \"> 0\"),\n gravity: pickNumber(\"gravity\", o.gravity, base.gravity, (v) => v >= 0, \">= 0\"),\n strongGravity: pickBoolean(\"strongGravity\", o.strongGravity, base.strongGravity),\n distributedAction: pickBoolean(\"distributedAction\", o.distributedAction, base.distributedAction),\n linlog: pickBoolean(\"linlog\", o.linlog, base.linlog),\n nodeMass: o.nodeMass === undefined ? base.nodeMass : o.nodeMass,\n nodeSize,\n weight: o.weight === undefined ? base.weight : o.weight,\n dissuadeHubs: pickBoolean(\"dissuadeHubs\", o.dissuadeHubs, base.dissuadeHubs),\n dim: pickDim(o.dim, base.dim),\n scale: pickNumber(\"scale\", o.scale, base.scale, (v) => v > 0, \"> 0\"),\n center: pickCenter(o.center, base.center),\n seed: pickSeed(o.seed, base.seed),\n settleThreshold: pickNumber(\"settleThreshold\", o.settleThreshold, base.settleThreshold, (v) => v >= 0, \">= 0\"),\n settleWindow: pickNumber(\n \"settleWindow\",\n o.settleWindow,\n base.settleWindow,\n isPositiveInteger,\n \"an integer >= 1\",\n ),\n iterationsPerStep: pickNumber(\n \"iterationsPerStep\",\n o.iterationsPerStep,\n base.iterationsPerStep,\n (v) => isPositiveInteger(v) && v <= MAX_ITERATIONS_PER_STEP,\n `an integer in [1, ${MAX_ITERATIONS_PER_STEP}]`,\n ),\n maxInFlight: pickNumber(\"maxInFlight\", o.maxInFlight, base.maxInFlight, isPositiveInteger, \"an integer >= 1\"),\n };\n return Object.freeze(resolved);\n}\n\n/**\n * Applies LAYOUT_TUNING_DEFAULTS (spec 7.14; contract 3.3). `nearMax` is an integer >= 2 (P4 DEP-P4-M: the\n * near-field estimator needs at least one sampled entry besides the node itself).\n * @param tuning - the GPU-only knobs given (any object carrying them, e.g. the createForceAtlas2 options)\n * @returns the frozen resolved tuning\n */\nexport function resolveLayoutTuning(tuning: GpuLayoutTuning | undefined): ResolvedLayoutTuning {\n const t: GpuLayoutTuning = tuning ?? {};\n const repulsion: unknown = t.repulsion ?? LAYOUT_TUNING_DEFAULTS.repulsion;\n if (repulsion !== \"exact\" && repulsion !== \"grid\" && repulsion !== \"auto\") {\n throw invalid(\"repulsion\", repulsion, '\"exact\", \"grid\" or \"auto\"');\n }\n const compat: unknown = t.compat ?? LAYOUT_TUNING_DEFAULTS.compat;\n if (compat !== \"paper\" && compat !== \"networkx\") {\n throw invalid(\"compat\", compat, '\"paper\" or \"networkx\"');\n }\n const resolved: ResolvedLayoutTuning = {\n repulsion,\n exactMaxNodes: pickNumber(\n \"exactMaxNodes\",\n t.exactMaxNodes,\n LAYOUT_TUNING_DEFAULTS.exactMaxNodes,\n isPositiveInteger,\n \"an integer >= 1\",\n ),\n nearMax: pickNumber(\n \"nearMax\",\n t.nearMax,\n LAYOUT_TUNING_DEFAULTS.nearMax,\n (v) => isPositiveInteger(v) && v >= 2,\n \"an integer >= 2\",\n ),\n deterministic: pickBoolean(\"deterministic\", t.deterministic, LAYOUT_TUNING_DEFAULTS.deterministic),\n gridMax2D: pickNumber(\n \"gridMax2D\",\n t.gridMax2D,\n LAYOUT_TUNING_DEFAULTS.gridMax2D,\n isPositiveInteger,\n \"an integer >= 1\",\n ),\n gridMax3D: pickNumber(\n \"gridMax3D\",\n t.gridMax3D,\n LAYOUT_TUNING_DEFAULTS.gridMax3D,\n isPositiveInteger,\n \"an integer >= 1\",\n ),\n extentFactor: pickNumber(\n \"extentFactor\",\n t.extentFactor,\n LAYOUT_TUNING_DEFAULTS.extentFactor,\n (v) => v > 0,\n \"> 0\",\n ),\n compat,\n };\n return Object.freeze(resolved);\n}\n\n// ============================================================ the model\n\n/** Everything bind() produced for one load(): the kernels, their bind groups and the dispatch plans of this n. */\ninterface BoundModel {\n readonly n: number;\n /** plan1d(n): K2, K5, toScene (every kernel compiles with the same device-derived WG). */\n readonly plan: DispatchPlan;\n /** plan1d(3n): the fills of force / oldForce (3 words per node). */\n readonly fillPlan: DispatchPlan;\n readonly k1: Kernel;\n readonly k1Bound: BoundKernel;\n /** The K2 tier dispatches (P4 PD-7); null when arcCount === 0 (K2 is not recorded; the fill below zeroes force instead, spec 7.5). */\n readonly attraction: AttractionBound | null;\n /** The exact-tier stage (K3 and K4), or null on the grid tier (P4 PD-18): one tier's kernels compile per load. */\n readonly repulsion: RepulsionExact | null;\n /** The grid-tier stage (G1-G7 and K4), or null on the exact tier (P4 PD-18). */\n readonly grid: RepulsionGrid | null;\n readonly k5: Kernel;\n readonly k5Bound: BoundKernel;\n readonly toScene: Kernel;\n readonly toSceneBound: BoundKernel;\n readonly fill: Kernel;\n /** The fill of `force` (arcCount === 0 only). */\n readonly fillForceBound: BoundKernel | null;\n /** The fill of `oldForce` on the first iteration after load() (paper mode only). */\n readonly fillOldBound: BoundKernel | null;\n}\n\n/** The ForceAtlas2 model (spec 7.4: K1 K2 K3 K4 K5 per iteration on the exact tier, K1 K2 G1..G7 K4 K5 on the grid tier; toScene once per batch). Stages: the union list of PD-17. */\nexport class ForceAtlas2Model implements ForceModel<ForceAtlas2Options, ForceAtlas2Stats> {\n /** The model kind of spec 7.19. */\n readonly kind = \"forceatlas2\";\n /** The stage names in dispatch order (the `upTo` vocabulary of recordIteration and debugRunStages). */\n readonly stages: typeof FA2_STAGES = FA2_STAGES;\n /** Fa2Params: the per-iteration uniform block (the simulation writes the shared fields into it). */\n readonly params: UniformBlock = FA2_PARAMS;\n /** Fa2State: the state header block (the simulation allocates and initialises it through this layout). */\n readonly state: UniformBlock = FA2_STATE;\n /** Fa2Trace: one record per iteration of a batch. */\n readonly trace: UniformBlock = FA2_TRACE;\n /** The resolved GPU-only tuning this model was created with. */\n readonly tuning: ResolvedLayoutTuning;\n\n /**\n * The option record the model holds: the constructor's record, replaced by onSetParams() ONLY. The query hooks\n * (inputs, overrides, paramsFor) never assign it: the simulation calls overrides(next) BEFORE onSetParams(patch)\n * (3.13 setParams: the recompile decision precedes the controller reset), so a hook that tracked the record would\n * hide every law change from onSetParams (PLAN DECISION 12).\n */\n private current: ResolvedForceAtlas2Options;\n /** The resources of the last bind(), or null before the first. */\n private resources: ModelResources | null = null;\n /** The kernels and bind groups of the last bind(), or null before it (and for n === 0). */\n private bound: BoundModel | null = null;\n /** Armed by onLoad(): the next recordIteration zeroes oldForce first (paper mode). */\n private resetOldForce = false;\n /** The grid of the load inputs() last resolved (null on the exact tier): onLoad() writes its frame, specs() lists its kernels. */\n private nextGrid: GridSpec | null = null;\n /**\n * The K1-K5 compute pass of the batch being recorded, keyed by CommandBatch.id (unique per batch): every\n * recordIteration of one batch dispatches into it (ONE pass per batch, contract 4.4); null between batches and\n * after the toScene pass ended it (PLAN DECISION 2).\n */\n private openPass: { readonly id: number; readonly pass: GPUComputePassEncoder } | null = null;\n\n /**\n * Creates the model for one simulation.\n * @param tuning - the resolved GPU-only tuning (compat selects SWING_MODE / GRAVITY_CENTER; repulsion and\n * exactMaxNodes the tier rule)\n * @param resolved - the resolved option record at creation\n */\n constructor(tuning: ResolvedLayoutTuning, resolved: ResolvedForceAtlas2Options) {\n this.tuning = tuning;\n this.current = resolved;\n }\n\n /**\n * The SWING_MODE of this model: 1 in networkx mode (accumulated, position-mixed sums; m|F| local swing), else 0.\n * @returns 0 or 1\n */\n private get swingMode(): 0 | 1 {\n return this.tuning.compat === \"networkx\" ? 1 : 0;\n }\n\n /**\n * force 12n and oldForce 12n (zeroed) in BOTH swing modes (3.10.1: a writable slot is never aliased; mode 1 leaves\n * oldForce unread and unwritten), the 256-byte FillParams uniform buffer the fill dispatches read, the 16-byte\n * `hubCounters` K1 binds on every tier (P4 PD-14), and the grid buffers of `RepulsionGrid.buffers` exactly when\n * `tierFor(tuning, n)` is the grid tier (PD-18). n = 0 reports one node's worth of bytes so no zero-length buffer\n * is ever created (spec 3.6).\n * @param n - the node count\n * @param dim - the layout dimension (the force arrays are stride 3 in both; the grid's geometry differs)\n * @returns the model-owned buffer specs\n */\n buffers(n: number, dim: 2 | 3): readonly BufferSpec[] {\n const bytes = Math.max(1, n) * FORCE_BYTES_PER_NODE;\n const usage = BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST;\n const grid =\n tierFor(this.tuning, n) === \"grid\" ? RepulsionGrid.buffers(n, gridSpecFor(n, dim, this.tuning)) : [];\n return [\n { name: \"force\", byteLength: bytes, usage, zero: true },\n { name: \"oldForce\", byteLength: bytes, usage, zero: true },\n {\n name: FILL_PARAMS_BUFFER,\n byteLength: UNIFORM_SLOT_BYTES,\n usage: BufferUsage.UNIFORM | BufferUsage.COPY_DST,\n zero: false,\n },\n { name: HUB_COUNTERS_BUFFER, byteLength: 16, usage, zero: true },\n ...grid,\n ];\n }\n\n /**\n * { mass: resolveNodeMass(s, resolved.nodeMass), weights: resolveWeights(s, resolved.weight) } (3.13 inputs.ts).\n * Also remembers the grid of this load (`tierFor(tuning, n)`, spec 7.8) for onLoad() and specs(): the simulation\n * calls inputs() first, then onLoad() before bind().\n * @param s - the snapshot being loaded\n * @param options - the simulation's current option record\n * @returns the per-load inputs\n */\n inputs(s: GraphSnapshot, options: ForceAtlas2Options): ModelInputs {\n const resolved = resolveForceAtlas2Options(options, this.current);\n const n = s.nodeCount;\n // resolve first: a throwing mass / weight resolution leaves the remembered grid of the previous load intact\n const inputs = { mass: resolveNodeMass(s, resolved.nodeMass), weights: resolveWeights(s, resolved.weight) };\n this.nextGrid = tierFor(this.tuning, n) === \"grid\" ? gridSpecFor(n, resolved.dim, this.tuning) : null;\n return inputs;\n }\n\n /**\n * { LINLOG, DISTRIBUTED, TIER: 0, SWING_MODE: compat === \"networkx\" ? 1 : 0, STRONG_GRAVITY, GRAVITY_CENTER:\n * compat === \"networkx\" ? 1 : 0 }; USE_PERM / HAS_WEIGHTS are merged in by the simulation from ModelResources\n * (3.10, never from core.hasWeights). A pure query: the simulation calls it with the current AND the next record\n * inside setParams() to decide the recompile, so it never touches the model's record (PLAN DECISION 12).\n * @param options - an option record (the simulation's current one, or the next one of a setParams patch)\n * @returns the model's own override set\n */\n overrides(options: ForceAtlas2Options): Overrides {\n const resolved = resolveForceAtlas2Options(options, this.current);\n const mode = this.swingMode;\n return {\n LINLOG: resolved.linlog,\n DISTRIBUTED: resolved.distributedAction,\n TIER: 0,\n SWING_MODE: mode,\n STRONG_GRAVITY: resolved.strongGravity,\n GRAVITY_CENTER: mode,\n };\n }\n\n /**\n * The seven module specs of an override set in dispatch order -- K1, K2, K3, K4, K5, toScene, fill -- each with\n * only the override names its entry declares (K2 also USE_PERM / HAS_WEIGHTS), for warm() and the compile matrix,\n * followed by the grid tier's specs (`RepulsionGrid.specs`) when the load inputs() last resolved is a grid load\n * (the pipeline key carries no geometry, so the spec's size is immaterial).\n * @param overrides - the merged override set (the model's plus USE_PERM / HAS_WEIGHTS)\n * @param _subgroups - accepted for the ForceModel interface and unused: every reducing FA2 body carries\n * needs: [\"subgroups\"] in its registry entry and the composer picks the twin from caps.features (contract 4.3)\n * @returns the specs\n */\n specs(overrides: Overrides, _subgroups: boolean): readonly WgslModuleSpec[] {\n const [repulsionSpec, speedSpec] = RepulsionExact.specs(repulsionOverrides(overrides));\n const grid =\n this.nextGrid === null\n ? []\n : RepulsionGrid.specs(gridOverrides(overrides), gridSpecFor(EXACT_MAX_NODES + 1, 2, this.tuning));\n return [\n kernelSpec(\"fa2-stats-finalize\"),\n kernelSpec(\"fa2-attraction\", subset(overrides, K2_DEFAULTS)),\n repulsionSpec,\n speedSpec,\n kernelSpec(\"fa2-integrate\", subset(overrides, K5_DEFAULTS)),\n kernelSpec(\"fa2-to-scene\"),\n kernelSpec(\"fill\"),\n ...grid,\n ];\n }\n\n /**\n * Compiles (through the cache) and binds every kernel against the buffers of this load(): K1, K2 over the degree\n * tiers through bindAttraction (or the fill of force when arcCount === 0), K3 + K4 through RepulsionExact, K5,\n * toScene, and the fill of oldForce; writes the FillParams { count: 3n, value: 0, mode: 0 } into the model's\n * uniform buffer. With n === 0 nothing is bound. The K2 TIER 1 / 2 pipelines compile on the first load whose\n * degrees need them (P4 PD-7), a one-time cost at that load.\n * @param resources - the graph, the shared and model buffers, the ring and the cache\n * @param overrides - the merged override set\n */\n async bind(resources: ModelResources, overrides: Overrides): Promise<void> {\n this.dropBound();\n this.resources = resources;\n const { n, pipelines, caps, core, ring, device } = resources;\n if (n === 0) {\n return;\n }\n const pos = resources.buffer(\"positions\");\n const force = resources.buffer(\"force\");\n const params = ring.binding(FA2_PARAMS);\n const hasArcs = core.colIdx !== null;\n const [k1, k5, toScene, fill] = await Promise.all([\n pipelines.kernel(kernelSpec(\"fa2-stats-finalize\")),\n pipelines.kernel(kernelSpec(\"fa2-integrate\", subset(overrides, K5_DEFAULTS))),\n pipelines.kernel(kernelSpec(\"fa2-to-scene\")),\n pipelines.kernel(kernelSpec(\"fill\")),\n ]);\n const repulsion =\n resources.tier === \"grid\"\n ? null\n : await RepulsionExact.create(pipelines, caps, repulsionOverrides(overrides));\n const attraction = hasArcs\n ? await bindAttraction(resources, subset(overrides, K2_DEFAULTS), { pos, force, params })\n : null;\n const grid =\n resources.tier === \"grid\"\n ? await RepulsionGrid.create(\n resources,\n k1.workgroupSize,\n gridOverrides(overrides),\n gridSpecFor(n, resources.dim, this.tuning),\n )\n : null;\n if (this.resources !== resources) {\n // a newer bind() superseded this one while the pipelines compiled; its own bind groups stand\n grid?.dispose();\n return;\n }\n const scene = resources.buffer(\"scenePositions\");\n const fixed = resources.buffer(\"fixed\");\n const partials = resources.buffer(\"partials\");\n const state = resources.buffer(\"state\");\n const trace = resources.buffer(\"trace\");\n const oldForce = resources.buffer(\"oldForce\");\n const fillParamsBuffer = resources.buffer(FILL_PARAMS_BUFFER);\n const fillParams: Binding = {\n buffer: fillParamsBuffer.buffer,\n offset: fillParamsBuffer.offset,\n size: FILL_PARAMS.byteLength,\n window: null,\n };\n const fillBytes = new ArrayBuffer(FILL_PARAMS.byteLength);\n FILL_PARAMS.write(new DataView(fillBytes), { count: 3 * n, value: 0, mode: 0 });\n device.queue.writeBuffer(fillParamsBuffer.buffer, fillParamsBuffer.offset, fillBytes);\n const hubCounters = resources.buffer(HUB_COUNTERS_BUFFER);\n const exact = { pos, state, trace, force, oldForce, fixedMask: fixed, partials, params };\n repulsion?.bind(exact);\n grid?.bind({\n ...exact,\n cellKey: resources.buffer(\"cellKey\"),\n cellVal: resources.buffer(\"cellVal\"),\n sortedKey: resources.buffer(\"sortedKey\"),\n sortedIdx: resources.buffer(\"sortedIdx\"),\n cellHist: resources.buffer(\"cellHist\"),\n cellStart: resources.buffer(\"cellStart\"),\n hubList: resources.buffer(\"hubList\"),\n hubCounters,\n pyramid: resources.buffer(\"pyramid\"),\n });\n const wg = k1.workgroupSize;\n this.bound = {\n n,\n plan: plan1d(n, wg, caps),\n fillPlan: plan1d(3 * n, wg, caps),\n k1,\n // PD-14: on the exact tier K1's grid slots take dummies (cellHist := partials, both read-only; hubCounters\n // is the model's 16-byte buffer on every tier) and the block is dead under gridMax 0\n k1Bound: k1.bind({\n partials,\n S: state,\n T: trace,\n cellHist: grid === null ? partials : resources.buffer(\"cellHist\"),\n hubCounters,\n P: params,\n }),\n attraction,\n repulsion,\n grid,\n k5,\n k5Bound: k5.bind({ force, oldForce, fixedMask: fixed, S: state, pos, partials, P: params }),\n toScene,\n toSceneBound: toScene.bind({ pos, scene, P: params }),\n fill,\n fillForceBound: hasArcs ? null : fill.bind({ dst: force, P: fillParams }),\n fillOldBound: this.swingMode === 0 ? fill.bind({ dst: oldForce, P: fillParams }) : null,\n };\n }\n\n /**\n * The Fa2Params values of one iteration (the simulation overwrites the shared fields n, dim, flags,\n * iterationIndex, seed, scale, center and settleThreshold with the same values plus the flags).\n * @param iteration - the trace slot of the iteration inside its batch\n * @param options - the simulation's current option record\n * @returns the uniform values\n */\n paramsFor(iteration: number, options: ForceAtlas2Options): UniformValues {\n const { n, core, tiers, tier, dim } = this.requireResources();\n const resolved = resolveForceAtlas2Options(options, this.current);\n const { nearMax, extentFactor } = this.tuning;\n const grid = tier === \"grid\" ? gridSpecFor(n, dim, this.tuning) : null;\n // P4 PD-7: TIER 2 reads [0, hiEnd), TIER 1 [hiEnd, midEnd), TIER 0 [tierStart, tierEnd) = [midEnd, n)\n const so = tiers?.segmentOffsets;\n const hiEnd = so?.[1] ?? 0;\n const midEnd = so?.[2] ?? 0;\n return {\n n,\n dim: resolved.dim,\n flags: 0,\n tierStart: midEnd,\n tierEnd: n,\n iterationIndex: iteration,\n seed: seedWord(resolved.seed),\n nearMax,\n scalingRatio: resolved.scalingRatio,\n gravity: resolved.gravity,\n jitterTolerance: resolved.jitterTolerance,\n scale: resolved.scale,\n center: [resolved.center[0], resolved.center[1], resolved.center[2], 0],\n settleThreshold: resolved.settleThreshold,\n extentFactor,\n gridMax: grid?.g ?? 0,\n levels: grid?.levels ?? 0,\n arcBase: 0,\n arcEnd: arcCountOf(core),\n accumulate: 0,\n hiEnd,\n midEnd,\n settleFloor: SETTLE_FLOOR_UNBOUNDED, // ForceAtlas2 does not drift after settling (issue #97)\n };\n }\n\n /**\n * Records one iteration into the batch, stopping after stage `upTo` when given (spec 7.4; debugRunStages /\n * inspect, spec 11.9 item 2; PD-17: `upTo` names a position in the union list and the recording stops after the\n * last stage recorded at or before it, so \"K3\" on the grid tier stops after K2 and \"G5\" on the exact tier after\n * K3). The exact tier: K1, K2 (or the fill of force when arcCount === 0), K3, K4, K5 in the batch's ONE compute\n * pass (opened by the first call of a batch and reused by every later call with the same batch.id, PLAN\n * DECISION 2), then toScene in a second pass that ends it. The grid tier (PD-16): the passes `fa2-k1` (K1),\n * `fa2-attraction` (K2's tiers) and `fa2-grid` (G1-G7, K4, K5) per iteration, then `fa2-to-scene`. The profiler\n * budgets PROFILER_QUERY_SLOTS / 2 = 128 passes per batch, so a grid batch above 42 iterations is timed only in\n * part (the exact tier's two passes per batch always fit): the simulation then reports msPerIteration from the\n * wall time, never from the sum of the timed prefix (`ForceSimulation.batchMilliseconds`). The simulation\n * passes \"K5\" for iterations 0..k-2 and undefined for the last, so toScene runs once per batch. The first call\n * after load() zeroes oldForce before K1 (paper mode). With n === 0 nothing is recorded (PLAN DECISION 9); a\n * call before bind() completed is E_NOT_LOADED (never a silent no-op).\n * @param batch - the batch being recorded\n * @param slot - the UniformRing slot holding this iteration's Fa2Params\n * @param tier - the tier the simulation resolved at load() (the same rule bind() applied, PD-18)\n * @param upTo - a stage name to stop after; undefined records every stage including toScene\n */\n recordIteration(batch: CommandBatch, slot: number, tier: \"exact\" | \"grid\", upTo?: string): void {\n const resources = this.requireResources();\n const stop = upTo === undefined ? STAGE_TO_SCENE : this.stageIndex(upTo);\n const { bound } = this;\n if (bound === null) {\n if (resources.n === 0) {\n return;\n }\n throw new WebGpuGraphError(\n \"E_NOT_LOADED\",\n \"the ForceAtlas2 model is not bound (bind() has not completed)\",\n {\n state: \"loaded\",\n },\n );\n }\n const offset = resources.ring.offsetOf(slot);\n if (tier === \"grid\") {\n this.recordGridIteration(batch, bound, offset, stop);\n return;\n }\n const { repulsion } = bound;\n if (repulsion === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"the ForceAtlas2 model was bound on the grid tier\", {\n state: \"loaded\",\n });\n }\n const pass = this.openPass !== null && this.openPass.id === batch.id ? this.openPass.pass : batch.pass(\"fa2\");\n this.openPass = { id: batch.id, pass };\n this.recordK1(pass, bound, offset);\n if (stop < 1) {\n return;\n }\n this.recordK2(pass, bound, offset);\n if (stop < 2) {\n return;\n }\n repulsion.recordRepulsion(pass, bound.n, offset);\n if (stop < STAGE_K4) {\n return;\n }\n repulsion.recordSpeedFinalize(pass, offset);\n if (stop < STAGE_K5) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < STAGE_TO_SCENE) {\n return;\n }\n this.recordToScene(batch, bound, offset);\n }\n\n /**\n * The grid tier's iteration (PD-16): three compute passes before toScene.\n * @param batch - the batch being recorded\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset of the iteration\n * @param stop - the FA2_STAGES index to stop after\n */\n private recordGridIteration(batch: CommandBatch, bound: BoundModel, offset: number, stop: number): void {\n const { grid } = bound;\n if (grid === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"the ForceAtlas2 model was bound on the exact tier\", {\n state: \"loaded\",\n });\n }\n this.openPass = null;\n this.recordK1(batch.pass(\"fa2-k1\"), bound, offset);\n if (stop < 1) {\n return;\n }\n this.recordK2(batch.pass(\"fa2-attraction\"), bound, offset);\n if (stop < STAGE_G1) {\n return;\n }\n const pass = batch.pass(\"fa2-grid\");\n const gridStop = stop < STAGE_K4 ? (FA2_STAGES[stop] as GridStage) : undefined;\n grid.recordRepulsion(pass, bound.n, offset, gridStop);\n if (stop < STAGE_K4) {\n return;\n }\n grid.recordSpeedFinalize(pass, offset);\n if (stop < STAGE_K5) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < STAGE_TO_SCENE) {\n return;\n }\n this.recordToScene(batch, bound, offset);\n }\n\n /**\n * The oldForce reset of the first iteration after load() (paper mode), then K1 (one workgroup).\n * @param pass - the open compute pass\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset\n */\n private recordK1(pass: GPUComputePassEncoder, bound: BoundModel, offset: number): void {\n if (this.resetOldForce) {\n this.resetOldForce = false;\n if (bound.fillOldBound !== null) {\n bound.fill.dispatch(pass, bound.fillOldBound, bound.fillPlan, [0]);\n }\n }\n bound.k1.dispatch(pass, bound.k1Bound, ONE_WORKGROUP, [offset]);\n }\n\n /**\n * K2's tier dispatches, or the fill of force when the graph has no arcs (spec 7.5).\n * @param pass - the open compute pass\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset\n */\n private recordK2(pass: GPUComputePassEncoder, bound: BoundModel, offset: number): void {\n if (bound.attraction !== null) {\n recordAttraction(pass, bound.attraction, offset);\n } else if (bound.fillForceBound !== null) {\n bound.fill.dispatch(pass, bound.fillForceBound, bound.fillPlan, [0]);\n }\n }\n\n /**\n * The toScene pass that ends the iteration's pass; the batch is complete after it, so nothing reuses the pass.\n * @param batch - the batch\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset\n */\n private recordToScene(batch: CommandBatch, bound: BoundModel, offset: number): void {\n this.openPass = null;\n const scenePass = batch.pass(\"fa2-to-scene\");\n bound.toScene.dispatch(scenePass, bound.toSceneBound, bound.plan, [offset]);\n }\n\n /**\n * speed = 1, speedEfficiency = 1, swing = 1, traction = 1 (mode 1 accumulates from 1; mode 0 overwrites them each\n * iteration, the initial value is irrelevant); arms the oldForce reset of the next recordIteration. On a grid\n * load the frame of the first build (K1 folds nothing on the first iteration): the same six values K1 derives,\n * in f32 with the kernel's order of operations, from the host-written min / max / centroid / rmsRadius.\n * @param state - the state writer of the simulation\n */\n onLoad(state: StateWriter): void {\n state.set(\"speed\", 1);\n state.set(\"speedEfficiency\", 1);\n state.set(\"swing\", 1);\n state.set(\"traction\", 1);\n this.resetOldForce = true;\n if (this.nextGrid !== null) {\n writeGridFrame(state, this.nextGrid, this.tuning.extentFactor);\n }\n }\n\n /**\n * Mode 0: nothing (D8). Mode 1 (networkx): swing = traction = 1 (spec 7.2 \"load() and reheat() reset them to 1\").\n * @param state - the state writer of the simulation\n */\n onReheat(state: StateWriter): void {\n if (this.swingMode === 1) {\n state.set(\"swing\", 1);\n state.set(\"traction\", 1);\n }\n }\n\n /**\n * Resets speed / speedEfficiency to 1 only when linlog, strongGravity or distributedAction changed (spec 7.17);\n * a numeric tweak leaves the controller alone. The patch is validated by the same resolver the simulation uses\n * and applied over the record of the constructor / the previous onSetParams -- the only place `current` moves\n * (PLAN DECISION 12), so the comparison sees the record from BEFORE this setParams even though the simulation\n * already queried overrides(next).\n * @param patch - the setParams patch\n * @param state - the state writer of the simulation\n */\n onSetParams(patch: Partial<ForceAtlas2Options>, state: StateWriter): void {\n const next = resolveForceAtlas2Options(patch, this.current);\n const lawChanged =\n next.linlog !== this.current.linlog ||\n next.strongGravity !== this.current.strongGravity ||\n next.distributedAction !== this.current.distributedAction;\n this.current = next;\n if (lawChanged) {\n state.set(\"speed\", 1);\n state.set(\"speedEfficiency\", 1);\n }\n }\n\n /**\n * Decodes the state header and the k trace records of a completed batch (k = trace.byteLength / 32) into\n * ForceAtlas2Stats: `repulsionTier` is the bound tier, the grid fields are the header's on the grid tier\n * (`maxCellOccupancy` / `outsideGrid`: the counts of the iteration before the last K1) and null on the exact\n * tier; msPerIteration null (the simulation owns the clock).\n * @param state - a DataView over the 256-byte state header\n * @param trace - a DataView over the k Fa2Trace records of the batch\n * @returns the stats\n */\n readStats(state: DataView, trace: DataView): ForceAtlas2Stats {\n const header = FA2_STATE.read(state);\n const centroid = vector(header, \"centroid\");\n const records: ForceAtlas2TraceRecord[] = [];\n const count = Math.floor(trace.byteLength / TRACE_RECORD_BYTES);\n for (let i = 0; i < count; i++) {\n const record = FA2_TRACE.read(trace, i * TRACE_RECORD_BYTES);\n records.push({\n swing: scalar(record, \"swing\"),\n traction: scalar(record, \"traction\"),\n speed: scalar(record, \"speed\"),\n speedEfficiency: scalar(record, \"speedEfficiency\"),\n meanDisplacement: scalar(record, \"meanDisplacement\"),\n settledCount: scalar(record, \"settledCount\"),\n });\n }\n const grid = this.resources?.tier === \"grid\";\n return {\n iteration: scalar(header, \"iteration\"),\n meanDisplacement: scalar(header, \"meanDisplacement\"),\n rmsRadius: scalar(header, \"rmsRadius\"),\n layoutRadius: scalar(header, \"radius\"),\n centroid: [centroid[0], centroid[1], centroid[2]],\n repulsionTier: grid ? \"grid\" : \"exact\",\n maxCellOccupancy: grid ? scalar(header, \"maxCellOccupancy\") : null,\n outsideGrid: grid ? scalar(header, \"outsideGrid\") : null,\n msPerIteration: null,\n swing: scalar(header, \"swing\"),\n traction: scalar(header, \"traction\"),\n speed: scalar(header, \"speed\"),\n speedEfficiency: scalar(header, \"speedEfficiency\"),\n trace: records,\n };\n }\n\n /**\n * The resources of the last bind(), or E_NOT_LOADED before it.\n * @returns the resources\n */\n private requireResources(): ModelResources {\n if (this.resources === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"the ForceAtlas2 model has not been bound (load() first)\", {\n state: \"created\",\n });\n }\n return this.resources;\n }\n\n /**\n * The index of a stage name in FA2_STAGES, or E_INVALID_ARGUMENT.\n * @param upTo - the stage name\n * @returns its index\n */\n private stageIndex(upTo: string): number {\n for (let i = 0; i < FA2_STAGES.length; i++) {\n if (FA2_STAGES[i] === upTo) {\n return i;\n }\n }\n throw invalid(\"upTo\", upTo, FA2_STAGES.join(\" | \"));\n }\n\n /**\n * Releases the grid stage's lease and the bind groups (the simulation calls it from dispose() once every\n * in-flight batch has settled).\n */\n dispose(): void {\n this.dropBound();\n }\n\n /**\n * Drops the bind groups of the previous bind() (the buffers changed) so the cached kernels do not accumulate stale\n * groups across reloads; K3 / K4 live inside RepulsionExact and keep the P1-T6 behaviour; the grid stage\n * releases its lease. Also forgets the pass of a batch recorded before the rebind.\n */\n private dropBound(): void {\n this.openPass = null;\n const { bound } = this;\n if (bound === null) {\n return;\n }\n for (const kernel of [bound.k1, bound.k5, bound.toScene, bound.fill]) {\n kernel.invalidate();\n }\n for (const [kernel] of bound.attraction?.kernels ?? []) {\n kernel.invalidate();\n }\n bound.grid?.dispose();\n this.bound = null;\n }\n}\n\n/**\n * The grid frame of the first build after load() (spec 7.7 geometry table; PD-10): K1's text in f32 with the same\n * order of operations -- `box = (max - min) * GRID_BBOX_MARGIN`, `extent = max(min(max(box), extentFactor *\n * rmsRadius), GRID_EXTENT_FLOOR)`, `cellSize = extent / G`, `gridMin = centroid - extent / 2` (cellSize in `.w`),\n * `invCellSize = 1 / cellSize`, `eps = 0.25 cellSize` -- plus zero counts. Shared with the FR and spring-electrical\n * models' onLoad (P4-T13).\n * @param state - the state writer (min / max / centroid / rmsRadius already written by the simulation)\n * @param spec - the grid of the load\n * @param extentFactor - the tuning's extent factor\n */\nexport function writeGridFrame(state: StateWriter, spec: GridSpec, extentFactor: number): void {\n const f = Math.fround;\n const axis = (name: string): readonly number[] => {\n const value = state.get(name);\n return typeof value === \"number\" ? [value, value, value] : value;\n };\n const min = axis(\"min\");\n const max = axis(\"max\");\n const centroid = axis(\"centroid\");\n const rms = state.get(\"rmsRadius\");\n const box = [0, 1, 2].map((a) => f(f(f(max[a]) - f(min[a])) * f(GRID_BBOX_MARGIN)));\n const bboxExtent = spec.dim === 3 ? Math.max(box[0], box[1], box[2]) : Math.max(box[0], box[1]);\n const rmsTerm = f(f(extentFactor) * f(typeof rms === \"number\" ? rms : 0));\n const extent = Math.max(Math.min(bboxExtent, rmsTerm), f(GRID_EXTENT_FLOOR));\n const cellSize = f(extent / spec.g);\n const half = f(0.5 * extent);\n state.set(\"gridMin\", [f(f(centroid[0]) - half), f(f(centroid[1]) - half), f(f(centroid[2]) - half), cellSize]);\n state.set(\"invCellSize\", f(1 / cellSize));\n state.set(\"eps\", f(0.25 * cellSize));\n state.set(\"outsideGrid\", 0);\n state.set(\"maxCellOccupancy\", 0);\n}\n\n// ============================================================ the factory\n\n/**\n * The resolve callback of the simulation's setParams: the patch over the current record, re-validated (the current\n * record is re-resolved first so the callback is typed without a cast).\n * @param patch - the setParams patch\n * @param current - the simulation's current option record\n * @returns the new record\n */\nfunction resolvePatch(patch: Partial<ForceAtlas2Options>, current: ForceAtlas2Options): ForceAtlas2Options {\n return resolveForceAtlas2Options(patch, resolveForceAtlas2Options(current));\n}\n\n/**\n * Spec 3.3 createForceAtlas2, verbatim: a GpuLayoutSimulation running ForceAtlas2 on the exact or the grid repulsion\n * tier (spec 7.8) with the option defaults of spec 7.14 and the GPU-only tuning of GpuLayoutTuning (contract 3.13\n * \"Contracts\").\n * @param ctx - the context (E_DISPOSED / E_DEVICE_LOST through assertReady)\n * @param options - the ForceAtlas2 options and the GPU-only tuning knobs in one record\n * @returns the simulation in state \"created\"; load() next\n */\nexport function createForceAtlas2(\n ctx: GpuContext,\n options?: ForceAtlas2Options & GpuLayoutTuning,\n): GpuLayoutSimulation<ForceAtlas2Options, ForceAtlas2Stats> {\n ctx.assertReady();\n const resolved = resolveForceAtlas2Options(options);\n const tuning = resolveLayoutTuning(options);\n const model = new ForceAtlas2Model(tuning, resolved);\n return new ForceSimulation<ForceAtlas2Options, ForceAtlas2Stats>(ctx, model, resolved, tuning, resolvePatch);\n}\n","/**\n * Fruchterman-Reingold on the exact or the grid repulsion tier (spec 7.20, 7.8; contract 3.13): the ForceModel that\n * ForceSimulation drives -- the K1 K2 K3 K5 sequence per iteration on the exact tier (K1 K2 G1..G7 K5 on the grid\n * tier, P4-T13) and toScene per batch (no K4: no speed controller), the constant override set (`LAW` 1 on K2 / K3\n * and on G6 / G7, `APPLY` 1 on K5, `STATS_MODE` 1 on K1, PD-1), the per-iteration Fa2Params values\n * with the cooling schedule's temperature (PD-5), the controller resets and the stats decoder -- plus the option\n * resolver and `createFruchtermanReingold`. The model shares FA2's four kernels, buffers and blocks: `oldForce` is\n * allocated, bound and never read (K5 compiles `SWING_MODE = 1`, PD-2 / PD-20); the mass lane is 1 for every node\n * and weights are ignored (PD-11); the `fixed` option resolves at load through ModelInputs.fixed (PD-6); a\n * `setParams({ fixed })` patch is E_INVALID_ARGUMENT (PD-16).\n *\n * The temperature index (PD-5): the simulation hands paramsFor the GLOBAL iteration index, which load() restarts at 0\n * and reheat() does not touch. The model keeps `tempOrigin` (the global index at which the temperature index is 0):\n * onLoad sets it to 0; onReheat arms `pendingReheat`; the first paramsFor(global) after it sets\n * `tempOrigin = global - floor(0.7 * iterations)`, so the temperature restarts at floor(0.7 * iterations) exactly as\n * the CPU's reheat() does. The temperature is `max(0, 0.1 - dt * (global - tempOrigin))`, dt = 0.1 / (iterations + 1);\n * at 0 nothing moves and the settle window closes the run (DEP-P5-C: the budget restarts at 0, the temperature does\n * not).\n *\n * The grid tier (P4-T13, PD-22) is FA2's: `RepulsionGrid` with `LAW` 1 when `tierFor(tuning, n)` says so (PD-18),\n * the grid buffers from `buffers()`, K1's grid block under `gridMax > 0` (PD-14) over the model's own `hubCounters`,\n * the three passes `fr-k1` / `fr-attraction` / `fr-grid` before `fa2-to-scene` (PD-16), and the union stage list\n * (PD-17: `upTo` stops after the last stage recorded at or before its position; K4 is never recorded).\n */\n\nimport { type GraphSnapshot, type NodeMask } from \"@graphty/graph-format\";\n\nimport {\n FA2_FLAG_ADAPTIVE,\n FR_ADAPTIVE_MAX_ITERATIONS,\n FR_DEFAULTS,\n FR_REHEAT_FRACTION,\n FR_START_TEMPERATURE,\n MAX_ITERATIONS_PER_STEP,\n SETTLE_FLOOR_FRACTION,\n TRACE_RECORD_BYTES,\n UNIFORM_SLOT_BYTES,\n} from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type CommandBatch } from \"../kernel/batch.js\";\nimport { type DispatchPlan, plan1d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { type UniformBlock, type UniformValues } from \"../kernel/struct-block.js\";\nimport { type WgslModuleSpec } from \"../kernel/wgsl.js\";\nimport { FA2_PARAMS, FA2_STATE, FA2_TRACE, FILL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { arcCountOf } from \"../primitives/core-shape.js\";\nimport { type GridSpec, gridSpecFor } from \"../primitives/grid.js\";\nimport {\n type FruchtermanReingoldStats,\n type FruchtermanReingoldTraceRecord,\n type GpuLayoutSimulation,\n type GpuLayoutTuning,\n type ResolvedLayoutTuning,\n} from \"../types/layout.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type FruchtermanReingoldOptions, type ResolvedFruchtermanReingoldOptions } from \"../types/options.js\";\nimport {\n type BufferSpec,\n type ForceModel,\n ForceSimulation,\n type ModelInputs,\n type ModelResources,\n type StateWriter,\n tierFor,\n} from \"./force-simulation.js\";\nimport { resolveLayoutTuning, writeGridFrame } from \"./forceatlas2.js\";\nimport {\n type AttractionBound,\n bindAttraction,\n describeValue,\n FILL_PARAMS_BUFFER,\n FORCE_BYTES_PER_NODE,\n invalid,\n isPositiveInteger,\n type Overrides,\n pickCenter,\n pickDim,\n pickNumber,\n pickSeed,\n recordAttraction,\n scalar,\n seedWord,\n subset,\n vector,\n} from \"./model-common.js\";\nimport { recordExactRepulsion } from \"./repulsion-exact.js\";\nimport { type GridStage, RepulsionGrid, type RepulsionGridOverrides } from \"./repulsion-grid.js\";\n\n// ============================================================ constants\n\n/** The stage names of both tiers in dispatch order plus the per-batch toScene (spec 7.20; P4 PD-17: the union list; the exact tier records K1 K2 K3 K5, the grid tier K1 K2 G1..G7 K5, K4 never). */\nconst FR_STAGES = [\"K1\", \"K2\", \"K3\", \"G1\", \"G2\", \"G3\", \"G4\", \"G5\", \"G6\", \"G7\", \"K4\", \"K5\", \"toScene\"] as const;\n\n/** The FR_STAGES index of the first grid stage, of K4, of K5 and of toScene. */\nconst STAGE_G1 = 3;\nconst STAGE_K4 = 10;\nconst STAGE_K5 = 11;\nconst STAGE_TO_SCENE = 12;\n\n/** The name of the model-owned hub-counter buffer K1 binds on every tier (P4 PD-14). */\nconst HUB_COUNTERS_BUFFER = \"hubCounters\";\n\n/** The one-workgroup dispatch of K1 (spec 7.4). */\nconst ONE_WORKGROUP: DispatchPlan = { x: 1, y: 1, z: 1, items: 1, stride: null };\n\n/** The model's override set, constant for every option record (PD-1, PD-20). */\nconst FR_OVERRIDES: Overrides = Object.freeze({\n LINLOG: false,\n DISTRIBUTED: false,\n TIER: 0,\n SWING_MODE: 1,\n STRONG_GRAVITY: false,\n GRAVITY_CENTER: 0,\n LAW: 1,\n APPLY: 1,\n STATS_MODE: 1,\n});\n\n/** The grid stage's override set (G6 / G7 / K4; P4-T13, PD-22): K3's constant three and the FR law. */\nconst FR_GRID_OVERRIDES: RepulsionGridOverrides = Object.freeze({\n SWING_MODE: 1,\n STRONG_GRAVITY: false,\n GRAVITY_CENTER: 0,\n LAW: 1,\n});\n\n/** Every override each kernel accepts, with its default (the names its registry entry declares). */\nconst K1_DEFAULTS: Overrides = { STATS_MODE: 0 };\nconst K2_DEFAULTS: Overrides = {\n LINLOG: false,\n DISTRIBUTED: false,\n TIER: 0,\n USE_PERM: false,\n HAS_WEIGHTS: false,\n LAW: 0,\n};\nconst K3_DEFAULTS: Overrides = { SWING_MODE: 0, STRONG_GRAVITY: false, GRAVITY_CENTER: 0, LAW: 0 };\nconst K5_DEFAULTS: Overrides = { SWING_MODE: 0, APPLY: 0 };\n\n/** The resolved record with no option given: FR_DEFAULTS plus the null / origin defaults. */\nconst DEFAULT_RESOLVED: ResolvedFruchtermanReingoldOptions = Object.freeze<ResolvedFruchtermanReingoldOptions>({\n ...FR_DEFAULTS,\n center: [0, 0, 0],\n seed: null,\n});\n\n// ============================================================ the resolver\n\n/**\n * The `k` option: undefined keeps the fallback; null, 0 and NaN mean the auto default (null); else a finite\n * number > 0.\n * @param given - the value given\n * @param fallback - the previous record's value or the default\n * @returns k or null\n */\nfunction resolveK(given: number | null | undefined, fallback: number | null): number | null {\n if (given === undefined) {\n return fallback;\n }\n if (given === null || given === 0 || Number.isNaN(given)) {\n return null;\n }\n return pickNumber(\"k\", given, 1, (v) => v > 0, \"> 0 or null\");\n}\n\n/**\n * The `cooling` option: undefined keeps the fallback; else one of the two schedule names.\n * @param given - the value given\n * @param fallback - the previous record's value or the default\n * @returns the schedule\n */\nfunction pickCooling(given: unknown, fallback: \"linear\" | \"adaptive\"): \"linear\" | \"adaptive\" {\n if (given === undefined) {\n return fallback;\n }\n if (given === \"linear\" || given === \"adaptive\") {\n return given;\n }\n throw invalid(\"cooling\", given, '\"linear\" | \"adaptive\"');\n}\n\n/**\n * Applies FR_DEFAULTS to the option record and validates every range (spec 7.20, 9.3). `k`: null, 0 and NaN mean the\n * auto default `1 / sqrt(n)` (the CPU's `if (!k)`, `layout/src/simulation/fruchterman-reingold.ts:140-152`); a\n * negative or infinite k is E_INVALID_ARGUMENT. `iterations` is an integer >= 0 (0: settled at load); under\n * `cooling: \"adaptive\"` it is only the run's cap and a fresh record without one gets FR_ADAPTIVE_MAX_ITERATIONS. `fixed` is a\n * NodeMask, a bool node column name or null. With `previous` the record is a PATCH over it and `maxInFlight` may not\n * change (the uniform ring is sized by it at construction).\n * @param options - the caller's options (or a setParams patch)\n * @param previous - the current resolved record when resolving a patch\n * @returns the frozen resolved record\n */\nexport function resolveFruchtermanReingoldOptions(\n options: FruchtermanReingoldOptions | undefined,\n previous?: ResolvedFruchtermanReingoldOptions,\n): ResolvedFruchtermanReingoldOptions {\n const o: FruchtermanReingoldOptions = options ?? {};\n const base = previous ?? DEFAULT_RESOLVED;\n if (previous !== undefined && o.maxInFlight !== undefined && o.maxInFlight !== previous.maxInFlight) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `maxInFlight cannot change after creation (the uniform ring is sized by it): got ${describeValue(o.maxInFlight)}, current ${previous.maxInFlight}`,\n { argument: \"maxInFlight\", value: o.maxInFlight, expected: previous.maxInFlight },\n );\n }\n const fixed: unknown = o.fixed === undefined ? base.fixed : o.fixed;\n if (fixed !== null && typeof fixed !== \"string\" && !(fixed instanceof Uint32Array)) {\n throw invalid(\"fixed\", fixed, \"a NodeMask (Uint32Array), the name of a bool node column, or null\");\n }\n const cooling = pickCooling(o.cooling, base.cooling);\n // under adaptive cooling `iterations` is only a cap: a fresh record without one gets the adaptive budget, not the schedule's 50\n const iterationsFallback =\n previous === undefined && cooling === \"adaptive\" && o.iterations === undefined\n ? FR_ADAPTIVE_MAX_ITERATIONS\n : base.iterations;\n const resolved: ResolvedFruchtermanReingoldOptions = {\n k: resolveK(o.k, base.k),\n iterations: pickNumber(\n \"iterations\",\n o.iterations,\n iterationsFallback,\n (v) => Number.isInteger(v) && v >= 0,\n \"an integer >= 0\",\n ),\n cooling,\n fixed: fixed as NodeMask | string | null,\n dim: pickDim(o.dim, base.dim),\n scale: pickNumber(\"scale\", o.scale, base.scale, (v) => v > 0, \"> 0\"),\n center: pickCenter(o.center, base.center),\n seed: pickSeed(o.seed, base.seed),\n settleThreshold: pickNumber(\"settleThreshold\", o.settleThreshold, base.settleThreshold, (v) => v >= 0, \">= 0\"),\n settleWindow: pickNumber(\n \"settleWindow\",\n o.settleWindow,\n base.settleWindow,\n isPositiveInteger,\n \"an integer >= 1\",\n ),\n iterationsPerStep: pickNumber(\n \"iterationsPerStep\",\n o.iterationsPerStep,\n base.iterationsPerStep,\n (v) => isPositiveInteger(v) && v <= MAX_ITERATIONS_PER_STEP,\n `an integer in [1, ${MAX_ITERATIONS_PER_STEP}]`,\n ),\n maxInFlight: pickNumber(\"maxInFlight\", o.maxInFlight, base.maxInFlight, isPositiveInteger, \"an integer >= 1\"),\n };\n return Object.freeze(resolved);\n}\n\n/**\n * The fixed mask of a load (spec 7.12; the rule of `layout/src/simulation/fruchterman-reingold.ts:576-606` minus its\n * \"previous pins\" clause, which ForceSimulation.load() implements by keeping the words on a same-size reload): a\n * string names a bool node column (E_INVALID_ARGUMENT when absent or not bool); a mask is copied; null takes the\n * role-\"fixed\" bool column when present, else null (leave the words as they are).\n * @param s - the snapshot being loaded\n * @param spec - the resolved `fixed` option\n * @returns the mask words to apply at load, or null\n */\nfunction resolveFixed(s: GraphSnapshot, spec: NodeMask | string | null): NodeMask | null {\n const words = Math.ceil(s.nodeCount / 32);\n if (typeof spec === \"string\") {\n const column = s.nodes.get(spec);\n if (column === null) {\n throw invalid(\n \"fixed\",\n spec,\n `the name of a bool node column (the snapshot holds no node column \"${spec}\")`,\n );\n }\n if (column.dtype !== \"bool\") {\n throw invalid(\"fixed\", spec, `the name of a bool node column (\"${spec}\" is ${column.dtype})`);\n }\n return new Uint32Array(column.data.subarray(0, words));\n }\n if (spec !== null) {\n if (spec.length < words) {\n throw invalid(\"fixed\", spec.length, `a mask of at least ${words} words for ${s.nodeCount} nodes`);\n }\n return new Uint32Array(spec.subarray(0, words));\n }\n const byRole = s.nodes.byRole(\"fixed\");\n if (byRole !== null && byRole.dtype === \"bool\") {\n return new Uint32Array(byRole.data.subarray(0, words));\n }\n return null;\n}\n\n// ============================================================ the model\n\n/** Everything bind() produced for one load(): the kernels, their bind groups and the dispatch plans of this n. */\ninterface BoundModel {\n readonly n: number;\n /** plan1d(n): K2, K3, K5, toScene. */\n readonly plan: DispatchPlan;\n /** plan1d(3n): the fill of force (3 words per node). */\n readonly fillPlan: DispatchPlan;\n readonly k1: Kernel;\n readonly k1Bound: BoundKernel;\n /** The K2 tier dispatches (P4 PD-7); null when arcCount === 0 (K2 is not recorded; the fill below zeroes force instead, spec 7.5). */\n readonly attraction: AttractionBound | null;\n /** K3 and its bind group, or null on the grid tier (P4 PD-18): one tier's kernels compile per load. */\n readonly k3: Kernel | null;\n readonly k3Bound: BoundKernel | null;\n /** The grid-tier stage (G1-G7), or null on the exact tier (P4 PD-18). */\n readonly grid: RepulsionGrid | null;\n readonly k5: Kernel;\n readonly k5Bound: BoundKernel;\n readonly toScene: Kernel;\n readonly toSceneBound: BoundKernel;\n readonly fill: Kernel;\n /** The fill of `force` (arcCount === 0 only). */\n readonly fillForceBound: BoundKernel | null;\n}\n\n/** The Fruchterman-Reingold model (spec 7.20: K1 K2 K3 K5 per iteration on the exact tier, K1 K2 G1..G7 K5 on the grid tier; toScene once per batch). Stages: the union list of PD-17. */\nexport class FruchtermanReingoldModel implements ForceModel<FruchtermanReingoldOptions, FruchtermanReingoldStats> {\n /** The model kind of spec 7.19. */\n readonly kind = \"fruchtermanReingold\";\n /** The stage names in dispatch order (the `upTo` vocabulary of recordIteration and debugRunStages). */\n readonly stages: typeof FR_STAGES = FR_STAGES;\n /** Fa2Params: the per-iteration uniform block (the simulation writes the shared fields into it). */\n readonly params: UniformBlock = FA2_PARAMS;\n /** Fa2State: the state header block. */\n readonly state: UniformBlock = FA2_STATE;\n /** Fa2Trace: one record per iteration of a batch. */\n readonly trace: UniformBlock = FA2_TRACE;\n /** The resolved GPU-only tuning this model was created with. */\n readonly tuning: ResolvedLayoutTuning;\n\n /** The option record the model holds: the constructor's record, replaced by onSetParams() ONLY (as FA2's). */\n private current: ResolvedFruchtermanReingoldOptions;\n /** The global iteration index at which the temperature index is 0 (PD-5). */\n private tempOrigin = 0;\n /** Armed by onReheat(); consumed by the next paramsFor(), which re-anchors tempOrigin (PD-5). */\n private pendingReheat = false;\n private resources: ModelResources | null = null;\n private bound: BoundModel | null = null;\n /** The grid of the load inputs() last resolved (null on the exact tier): onLoad() writes its frame, specs() lists its kernels. */\n private nextGrid: GridSpec | null = null;\n /** The K1-K5 compute pass of the batch being recorded, keyed by CommandBatch.id (one pass per batch, contract 4.4). */\n private openPass: { readonly id: number; readonly pass: GPUComputePassEncoder } | null = null;\n\n /**\n * Creates the model for one simulation.\n * @param tuning - the resolved GPU-only tuning (the tier rule; compat has no effect on this model)\n * @param resolved - the resolved option record at creation\n */\n constructor(tuning: ResolvedLayoutTuning, resolved: ResolvedFruchtermanReingoldOptions) {\n this.tuning = tuning;\n this.current = resolved;\n }\n\n /**\n * force 12n and oldForce 12n (zeroed; bound and never read, PD-2), the 256-byte FillParams uniform buffer the\n * fill dispatch reads, the 16-byte `hubCounters` K1 binds on every tier (P4 PD-14), and the grid buffers of\n * `RepulsionGrid.buffers` exactly when `tierFor(tuning, n)` is the grid tier (PD-18). n = 0 reports one node's\n * worth of bytes so no zero-length buffer is ever created.\n * @param n - the node count\n * @param dim - the layout dimension (the force arrays are stride 3 in both; the grid's geometry differs)\n * @returns the model-owned buffer specs\n */\n buffers(n: number, dim: 2 | 3): readonly BufferSpec[] {\n const bytes = Math.max(1, n) * FORCE_BYTES_PER_NODE;\n const usage = BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST;\n const grid =\n tierFor(this.tuning, n) === \"grid\" ? RepulsionGrid.buffers(n, gridSpecFor(n, dim, this.tuning)) : [];\n return [\n { name: \"force\", byteLength: bytes, usage, zero: true },\n { name: \"oldForce\", byteLength: bytes, usage, zero: true },\n {\n name: FILL_PARAMS_BUFFER,\n byteLength: UNIFORM_SLOT_BYTES,\n usage: BufferUsage.UNIFORM | BufferUsage.COPY_DST,\n zero: false,\n },\n { name: HUB_COUNTERS_BUFFER, byteLength: 16, usage, zero: true },\n ...grid,\n ];\n }\n\n /**\n * Mass 1 for every node and no weights (PD-11: FR has no mass and ignores weights), the fixed mask of the\n * `fixed` option applied at load (PD-6). Also remembers the grid of this load (`tierFor(tuning, n)`, spec 7.8)\n * for onLoad() and specs(): the simulation calls inputs() first, then onLoad() before bind().\n * @param s - the snapshot being loaded\n * @param options - the simulation's current option record\n * @returns the per-load inputs\n */\n inputs(s: GraphSnapshot, options: FruchtermanReingoldOptions): ModelInputs {\n const resolved = resolveFruchtermanReingoldOptions(options, this.current);\n // resolve first: a throwing mask resolution leaves the remembered grid of the previous load intact\n const inputs: ModelInputs = {\n mass: new Float32Array(s.nodeCount).fill(1),\n weights: { data: null, source: \"none\", column: null },\n fixed: resolveFixed(s, resolved.fixed),\n };\n const n = s.nodeCount;\n this.nextGrid = tierFor(this.tuning, n) === \"grid\" ? gridSpecFor(n, resolved.dim, this.tuning) : null;\n return inputs;\n }\n\n /**\n * The constant FR override set (PD-1): no option changes a law, so setParams never recompiles.\n * @param _options - an option record (unused: the set is constant)\n * @returns the model's own override set\n */\n overrides(_options: FruchtermanReingoldOptions): Overrides {\n return FR_OVERRIDES;\n }\n\n /**\n * The six module specs of an override set in dispatch order -- K1, K2, K3, K5, toScene, fill -- each with only the\n * override names its entry declares (K2 also USE_PERM / HAS_WEIGHTS), for warm() and the compile matrix,\n * followed by the grid tier's specs (`RepulsionGrid.specs` under FR_GRID_OVERRIDES) when the load inputs() last\n * resolved is a grid load (the pipeline key carries no geometry).\n * @param overrides - the merged override set (the model's plus USE_PERM / HAS_WEIGHTS)\n * @param _subgroups - accepted for the ForceModel interface and unused (the composer picks the twin from caps)\n * @returns the specs\n */\n specs(overrides: Overrides, _subgroups: boolean): readonly WgslModuleSpec[] {\n const grid = this.nextGrid === null ? [] : RepulsionGrid.specs(FR_GRID_OVERRIDES, this.nextGrid);\n return [\n kernelSpec(\"fa2-stats-finalize\", subset(overrides, K1_DEFAULTS)),\n kernelSpec(\"fa2-attraction\", subset(overrides, K2_DEFAULTS)),\n kernelSpec(\"fa2-repulsion-exact\", subset(overrides, K3_DEFAULTS)),\n kernelSpec(\"fa2-integrate\", subset(overrides, K5_DEFAULTS)),\n kernelSpec(\"fa2-to-scene\"),\n kernelSpec(\"fill\"),\n ...grid,\n ];\n }\n\n /**\n * Compiles (through the cache) and binds every kernel against the buffers of this load(): K1, K2 over the degree\n * tiers through bindAttraction (or the fill of force when arcCount === 0), K3 on the exact tier or G1-G7 through\n * RepulsionGrid on the grid tier (PD-18), K5, toScene; writes the FillParams { count: 3n, value: 0, mode: 0 }\n * into the model's uniform buffer. With n === 0 nothing is bound. The K2 TIER 1 / 2 pipelines compile on the\n * first load whose degrees need them (P4 PD-7).\n * @param resources - the graph, the shared and model buffers, the ring and the cache\n * @param overrides - the merged override set\n */\n async bind(resources: ModelResources, overrides: Overrides): Promise<void> {\n this.dropBound();\n this.resources = resources;\n const { n, pipelines, caps, core, ring, device } = resources;\n if (n === 0) {\n return;\n }\n const pos = resources.buffer(\"positions\");\n const force = resources.buffer(\"force\");\n const params = ring.binding(FA2_PARAMS);\n const hasArcs = core.colIdx !== null;\n // sequential on purpose: PipelineCache.get compiles inside a validation scope, one stack per device\n const k1 = await pipelines.kernel(kernelSpec(\"fa2-stats-finalize\", subset(overrides, K1_DEFAULTS)));\n const attraction = hasArcs\n ? await bindAttraction(resources, subset(overrides, K2_DEFAULTS), { pos, force, params })\n : null;\n const k3 =\n resources.tier === \"grid\"\n ? null\n : await pipelines.kernel(kernelSpec(\"fa2-repulsion-exact\", subset(overrides, K3_DEFAULTS)));\n const k5 = await pipelines.kernel(kernelSpec(\"fa2-integrate\", subset(overrides, K5_DEFAULTS)));\n const toScene = await pipelines.kernel(kernelSpec(\"fa2-to-scene\"));\n const fill = await pipelines.kernel(kernelSpec(\"fill\"));\n const grid =\n resources.tier === \"grid\"\n ? await RepulsionGrid.create(\n resources,\n k1.workgroupSize,\n FR_GRID_OVERRIDES,\n gridSpecFor(n, resources.dim, this.tuning),\n )\n : null;\n if (this.resources !== resources) {\n // a newer bind() superseded this one while the pipelines compiled; its own bind groups stand\n grid?.dispose();\n return;\n }\n const scene = resources.buffer(\"scenePositions\");\n const fixed = resources.buffer(\"fixed\");\n const partials = resources.buffer(\"partials\");\n const state = resources.buffer(\"state\");\n const trace = resources.buffer(\"trace\");\n const oldForce = resources.buffer(\"oldForce\");\n const fillParamsBuffer = resources.buffer(FILL_PARAMS_BUFFER);\n const fillParams: Binding = {\n buffer: fillParamsBuffer.buffer,\n offset: fillParamsBuffer.offset,\n size: FILL_PARAMS.byteLength,\n window: null,\n };\n const fillBytes = new ArrayBuffer(FILL_PARAMS.byteLength);\n FILL_PARAMS.write(new DataView(fillBytes), { count: 3 * n, value: 0, mode: 0 });\n device.queue.writeBuffer(fillParamsBuffer.buffer, fillParamsBuffer.offset, fillBytes);\n const hubCounters = resources.buffer(HUB_COUNTERS_BUFFER);\n grid?.bind({\n pos,\n state,\n trace,\n force,\n oldForce,\n fixedMask: fixed,\n partials,\n params,\n cellKey: resources.buffer(\"cellKey\"),\n cellVal: resources.buffer(\"cellVal\"),\n sortedKey: resources.buffer(\"sortedKey\"),\n sortedIdx: resources.buffer(\"sortedIdx\"),\n cellHist: resources.buffer(\"cellHist\"),\n cellStart: resources.buffer(\"cellStart\"),\n hubList: resources.buffer(\"hubList\"),\n hubCounters,\n pyramid: resources.buffer(\"pyramid\"),\n });\n const wg = k1.workgroupSize;\n this.bound = {\n n,\n plan: plan1d(n, wg, caps),\n fillPlan: plan1d(3 * n, wg, caps),\n k1,\n // PD-14: on the exact tier K1's cellHist slot takes a dummy (partials, both read-only) and the block is\n // dead under gridMax 0; hubCounters is the model's 16-byte buffer on every tier\n k1Bound: k1.bind({\n partials,\n S: state,\n T: trace,\n cellHist: grid === null ? partials : resources.buffer(\"cellHist\"),\n hubCounters,\n P: params,\n }),\n attraction,\n k3,\n k3Bound: k3?.bind({ pos, S: state, force, oldForce, fixedMask: fixed, partials, P: params }) ?? null,\n grid,\n k5,\n k5Bound: k5.bind({ force, oldForce, fixedMask: fixed, S: state, pos, partials, P: params }),\n toScene,\n toSceneBound: toScene.bind({ pos, scene, P: params }),\n fill,\n fillForceBound: hasArcs ? null : fill.bind({ dst: force, P: fillParams }),\n };\n }\n\n /**\n * The Fa2Params values of one iteration: the FA2 fields at their neutral values (scalingRatio, gravity and\n * jitterTolerance 0), `frK` = k or 1 / sqrt(n), and this iteration's temperature (PD-5 anchors here). Under\n * `cooling: \"adaptive\"` the flags carry FA2_FLAG_ADAPTIVE and the kernels take the temperature from the state\n * block instead (K1 updates it, K5 reads it); the uniform's value is then the start temperature and unused. The\n * simulation overwrites the shared fields with the same values and OR-s in its own flags.\n * @param iteration - the GLOBAL iteration index\n * @param options - the simulation's current option record\n * @returns the uniform values\n */\n paramsFor(iteration: number, options: FruchtermanReingoldOptions): UniformValues {\n const { n, core, tiers, tier, dim } = this.requireResources();\n const resolved = resolveFruchtermanReingoldOptions(options, this.current);\n const { nearMax, extentFactor } = this.tuning;\n const adaptive = resolved.cooling === \"adaptive\";\n const grid = tier === \"grid\" ? gridSpecFor(n, dim, this.tuning) : null;\n // P4 PD-7: TIER 2 reads [0, hiEnd), TIER 1 [hiEnd, midEnd), TIER 0 [tierStart, tierEnd) = [midEnd, n)\n const so = tiers?.segmentOffsets;\n const hiEnd = so?.[1] ?? 0;\n const midEnd = so?.[2] ?? 0;\n return {\n n,\n dim: resolved.dim,\n flags: adaptive ? FA2_FLAG_ADAPTIVE : 0,\n tierStart: midEnd,\n tierEnd: n,\n iterationIndex: iteration,\n seed: seedWord(resolved.seed),\n nearMax,\n scalingRatio: 0,\n gravity: 0,\n jitterTolerance: 0,\n scale: resolved.scale,\n center: [resolved.center[0], resolved.center[1], resolved.center[2], 0],\n settleThreshold: resolved.settleThreshold,\n extentFactor,\n gridMax: grid?.g ?? 0,\n levels: grid?.levels ?? 0,\n arcBase: 0,\n arcEnd: arcCountOf(core),\n accumulate: 0,\n hiEnd,\n midEnd,\n frK: resolved.k ?? 1 / Math.sqrt(n),\n settleFloor: SETTLE_FLOOR_FRACTION.fruchtermanReingold * (resolved.k ?? 1 / Math.sqrt(n)),\n temperature: adaptive ? FR_START_TEMPERATURE : this.temperatureAt(iteration, resolved),\n };\n }\n\n /**\n * Records one iteration into the batch, stopping after stage `upTo` when given (PD-17: `upTo` names a position\n * in the union list and the recording stops after the last stage recorded at or before it, so \"K3\" on the grid\n * tier stops after K2 and \"G5\" on the exact tier after K3). The exact tier: K1, K2 (or the fill of force when\n * arcCount === 0), K3, K5 in the batch's ONE compute pass (opened by the first call of a batch and reused by\n * every later call with the same batch.id), then toScene in a second pass that ends it. The grid tier (PD-16):\n * the passes `fr-k1` (K1), `fr-attraction` (K2's tiers) and `fr-grid` (G1-G7, K5) per iteration, then\n * `fa2-to-scene`. With n === 0 nothing is recorded; a call before bind() completed is E_NOT_LOADED (never a\n * silent no-op).\n * @param batch - the batch being recorded\n * @param slot - the UniformRing slot holding this iteration's Fa2Params\n * @param tier - the tier the simulation resolved at load() (the same rule bind() applied, PD-18)\n * @param upTo - a stage name to stop after; undefined records every stage including toScene\n */\n recordIteration(batch: CommandBatch, slot: number, tier: \"exact\" | \"grid\", upTo?: string): void {\n const resources = this.requireResources();\n const stop = upTo === undefined ? STAGE_TO_SCENE : this.stageIndex(upTo);\n const { bound } = this;\n if (bound === null) {\n if (resources.n === 0) {\n return;\n }\n throw new WebGpuGraphError(\n \"E_NOT_LOADED\",\n \"the Fruchterman-Reingold model is not bound (bind() has not completed)\",\n { state: \"loaded\" },\n );\n }\n const offset = resources.ring.offsetOf(slot);\n if (tier === \"grid\") {\n this.recordGridIteration(batch, bound, offset, stop);\n return;\n }\n const { k3, k3Bound } = bound;\n if (k3 === null || k3Bound === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"the Fruchterman-Reingold model was bound on the grid tier\", {\n state: \"loaded\",\n });\n }\n const pass = this.openPass !== null && this.openPass.id === batch.id ? this.openPass.pass : batch.pass(\"fr\");\n this.openPass = { id: batch.id, pass };\n bound.k1.dispatch(pass, bound.k1Bound, ONE_WORKGROUP, [offset]);\n if (stop < 1) {\n return;\n }\n this.recordK2(pass, bound, offset);\n if (stop < 2) {\n return;\n }\n recordExactRepulsion(k3, pass, k3Bound, bound.plan, bound.n, offset);\n if (stop < STAGE_K5) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < STAGE_TO_SCENE) {\n return;\n }\n this.recordToScene(batch, bound, offset);\n }\n\n /**\n * The grid tier's iteration (PD-16): three compute passes before toScene; no K4.\n * @param batch - the batch being recorded\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset of the iteration\n * @param stop - the FR_STAGES index to stop after\n */\n private recordGridIteration(batch: CommandBatch, bound: BoundModel, offset: number, stop: number): void {\n const { grid } = bound;\n if (grid === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"the Fruchterman-Reingold model was bound on the exact tier\", {\n state: \"loaded\",\n });\n }\n this.openPass = null;\n bound.k1.dispatch(batch.pass(\"fr-k1\"), bound.k1Bound, ONE_WORKGROUP, [offset]);\n if (stop < 1) {\n return;\n }\n this.recordK2(batch.pass(\"fr-attraction\"), bound, offset);\n if (stop < STAGE_G1) {\n return;\n }\n const pass = batch.pass(\"fr-grid\");\n const gridStop = stop < STAGE_K4 ? (FR_STAGES[stop] as GridStage) : undefined;\n grid.recordRepulsion(pass, bound.n, offset, gridStop);\n if (stop < STAGE_K5) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < STAGE_TO_SCENE) {\n return;\n }\n this.recordToScene(batch, bound, offset);\n }\n\n /**\n * K2's tier dispatches, or the fill of force when the graph has no arcs (spec 7.5).\n * @param pass - the open compute pass\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset\n */\n private recordK2(pass: GPUComputePassEncoder, bound: BoundModel, offset: number): void {\n if (bound.attraction !== null) {\n recordAttraction(pass, bound.attraction, offset);\n } else if (bound.fillForceBound !== null) {\n bound.fill.dispatch(pass, bound.fillForceBound, bound.fillPlan, [0]);\n }\n }\n\n /**\n * The toScene pass that ends the iteration's pass; the batch is complete after it, so nothing reuses the pass.\n * @param batch - the batch\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset\n */\n private recordToScene(batch: CommandBatch, bound: BoundModel, offset: number): void {\n this.openPass = null;\n const scenePass = batch.pass(\"fa2-to-scene\");\n bound.toScene.dispatch(scenePass, bound.toSceneBound, bound.plan, [offset]);\n }\n\n /**\n * temperature = 0.1 (what stats reads before the first batch lands), kineticEnergy = 0; the temperature index\n * restarts at 0 (PD-5). On a grid load the frame of the first build (K1 folds nothing on the first iteration).\n * @param state - the state writer of the simulation\n */\n onLoad(state: StateWriter): void {\n this.resetAdaptive(state);\n state.set(\"kineticEnergy\", 0);\n this.tempOrigin = 0;\n this.pendingReheat = false;\n if (this.nextGrid !== null) {\n writeGridFrame(state, this.nextGrid, this.tuning.extentFactor);\n }\n }\n\n /**\n * temperature = 0.1, the adaptive controller's energy = +infinity (the first fold always counts as a fall) and\n * its progress counter = 0: the state K1 reads under `cooling: \"adaptive\"`, and what stats reads before the first\n * batch lands under either schedule.\n * @param state - the state writer of the simulation\n */\n private resetAdaptive(state: StateWriter): void {\n state.set(\"temperature\", FR_START_TEMPERATURE);\n state.set(\"frEnergy\", Number.POSITIVE_INFINITY);\n state.set(\"frProgress\", 0);\n }\n\n /**\n * Arms the re-anchoring of the temperature index at floor(0.7 * iterations), placed by the next paramsFor (PD-5);\n * under `cooling: \"adaptive\"` restarts the controller at the start temperature instead.\n * @param state - the state writer of the simulation\n */\n onReheat(state: StateWriter): void {\n this.pendingReheat = true;\n if (this.current.cooling === \"adaptive\") {\n this.resetAdaptive(state);\n }\n }\n\n /**\n * Replaces the record (a new k or budget takes effect at the next paramsFor: a new dt, a new frK; no recompile).\n * The PD-16 `fixed` check already ran in the simulation's resolve callback.\n * @param patch - the setParams patch\n * @param _state - the state writer of the simulation (nothing to write)\n */\n onSetParams(patch: Partial<FruchtermanReingoldOptions>, _state: StateWriter): void {\n this.current = resolveFruchtermanReingoldOptions(patch, this.current);\n }\n\n /**\n * Decodes the state header and the k trace records of a completed batch into FruchtermanReingoldStats:\n * `repulsionTier` is the bound tier, the grid fields are the header's on the grid tier and null on the exact\n * tier, msPerIteration null (the simulation owns the clock), the temperature K1 wrote.\n * @param state - a DataView over the 256-byte state header\n * @param trace - a DataView over the k Fa2Trace records of the batch\n * @returns the stats\n */\n readStats(state: DataView, trace: DataView): FruchtermanReingoldStats {\n const header = FA2_STATE.read(state);\n const centroid = vector(header, \"centroid\");\n const records: FruchtermanReingoldTraceRecord[] = [];\n const count = Math.floor(trace.byteLength / TRACE_RECORD_BYTES);\n for (let i = 0; i < count; i++) {\n const record = FA2_TRACE.read(trace, i * TRACE_RECORD_BYTES);\n records.push({\n temperature: scalar(record, \"modelScalar\"),\n meanDisplacement: scalar(record, \"meanDisplacement\"),\n settledCount: scalar(record, \"settledCount\"),\n });\n }\n const grid = this.resources?.tier === \"grid\";\n return {\n iteration: scalar(header, \"iteration\"),\n meanDisplacement: scalar(header, \"meanDisplacement\"),\n rmsRadius: scalar(header, \"rmsRadius\"),\n layoutRadius: scalar(header, \"radius\"),\n centroid: [centroid[0], centroid[1], centroid[2]],\n repulsionTier: grid ? \"grid\" : \"exact\",\n maxCellOccupancy: grid ? scalar(header, \"maxCellOccupancy\") : null,\n outsideGrid: grid ? scalar(header, \"outsideGrid\") : null,\n msPerIteration: null,\n temperature: scalar(header, \"temperature\"),\n trace: records,\n };\n }\n\n /**\n * The temperature of a global iteration (PD-5): a pending reheat re-anchors tempOrigin so this iteration's\n * temperature index is floor(0.7 * iterations); then max(0, 0.1 - dt * index), dt = 0.1 / (iterations + 1).\n * @param global - the global iteration index\n * @param resolved - the current record\n * @returns the temperature (f64; the uniform slot rounds it to f32)\n */\n private temperatureAt(global: number, resolved: ResolvedFruchtermanReingoldOptions): number {\n if (this.pendingReheat) {\n this.tempOrigin = global - Math.floor(FR_REHEAT_FRACTION * resolved.iterations);\n this.pendingReheat = false;\n }\n const dt = FR_START_TEMPERATURE / (resolved.iterations + 1);\n return Math.max(0, FR_START_TEMPERATURE - dt * (global - this.tempOrigin));\n }\n\n /**\n * The resources of the last bind(), or E_NOT_LOADED before it.\n * @returns the resources\n */\n private requireResources(): ModelResources {\n if (this.resources === null) {\n throw new WebGpuGraphError(\n \"E_NOT_LOADED\",\n \"the Fruchterman-Reingold model has not been bound (load() first)\",\n { state: \"created\" },\n );\n }\n return this.resources;\n }\n\n /**\n * The index of a stage name in FR_STAGES, or E_INVALID_ARGUMENT.\n * @param upTo - the stage name\n * @returns its index\n */\n private stageIndex(upTo: string): number {\n for (let i = 0; i < FR_STAGES.length; i++) {\n if (FR_STAGES[i] === upTo) {\n return i;\n }\n }\n throw invalid(\"upTo\", upTo, FR_STAGES.join(\" | \"));\n }\n\n /** Releases the grid stage's lease and the bind groups (the simulation calls it from dispose() once every in-flight batch has settled). */\n dispose(): void {\n this.dropBound();\n }\n\n /** Drops the bind groups of the previous bind() (the buffers changed), releases the grid stage's lease and forgets the pass of a batch recorded before the rebind. */\n private dropBound(): void {\n this.openPass = null;\n const { bound } = this;\n if (bound === null) {\n return;\n }\n for (const kernel of [bound.k1, bound.k5, bound.toScene, bound.fill]) {\n kernel.invalidate();\n }\n bound.k3?.invalidate();\n for (const [kernel] of bound.attraction?.kernels ?? []) {\n kernel.invalidate();\n }\n bound.grid?.dispose();\n this.bound = null;\n }\n}\n\n// ============================================================ the factory\n\n/**\n * The resolve callback of the simulation's setParams: the PD-16 `fixed` check first (fixed is applied at load; a\n * rejected patch leaves the simulation unchanged because ForceSimulation.setParams runs this before any state moves),\n * then the patch over the current record, re-validated.\n * @param patch - the setParams patch\n * @param current - the simulation's current option record\n * @returns the new record\n */\nfunction resolvePatch(\n patch: Partial<FruchtermanReingoldOptions>,\n current: FruchtermanReingoldOptions,\n): FruchtermanReingoldOptions {\n if (\"fixed\" in patch) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"setParams({ fixed }) is not a live option (spec 7.12)\", {\n argument: \"fixed\",\n value: patch.fixed,\n expected: \"absent\",\n hint: \"use setFixed(mask); fixed is applied at load()\",\n });\n }\n return resolveFruchtermanReingoldOptions(patch, resolveFruchtermanReingoldOptions(current));\n}\n\n/**\n * Spec 3.3 createFruchtermanReingold, verbatim: a GpuLayoutSimulation running Fruchterman-Reingold on the exact or\n * the grid repulsion tier (spec 7.8) with the option defaults of spec 7.20 and the GPU-only tuning of GpuLayoutTuning.\n * @param ctx - the context (E_DISPOSED / E_DEVICE_LOST through assertReady)\n * @param options - the Fruchterman-Reingold options and the GPU-only tuning knobs in one record\n * @returns the simulation in state \"created\"; load() next\n */\nexport function createFruchtermanReingold(\n ctx: GpuContext,\n options?: FruchtermanReingoldOptions & GpuLayoutTuning,\n): GpuLayoutSimulation<FruchtermanReingoldOptions, FruchtermanReingoldStats> {\n ctx.assertReady();\n const resolved = resolveFruchtermanReingoldOptions(options);\n const tuning = resolveLayoutTuning(options);\n const model = new FruchtermanReingoldModel(tuning, resolved);\n return new ForceSimulation<FruchtermanReingoldOptions, FruchtermanReingoldStats>(\n ctx,\n model,\n resolved,\n tuning,\n resolvePatch,\n );\n}\n","/**\n * The spring-electrical preset on the exact or the grid repulsion tier (spec 7.20 \"the preset\", 7.8; contract 3.13):\n * ngraph.forcelayout's physics under ngraph's option names and defaults -- Coulomb repulsion `-g m_i m_j / d^2` (K3,\n * LAW 2; G6 / G7 with LAW 2 on the grid tier, P4-T13), Hooke springs\n * `k_s (d - L)` (K2, LAW 2), drag and the semi-implicit Euler step with the unit speed clamp over a per-node velocity\n * (K5, APPLY 2), the kinetic energy folded into the trace (K1, STATS_MODE 2; PD-4) -- as the ForceModel that\n * ForceSimulation drives over the four FA2 kernels K1 K2 K3 K5 per iteration and toScene per batch. No K4: there is no\n * speed controller. The velocity is the model's `velocity` buffer bound into the `oldForce` slot of K3 and K5 (PD-2),\n * left alone by the FA2 text because the model compiles `SWING_MODE = 1` (PD-20). Mass is `1 + degree / 3` and the\n * weights are ignored (PD-11); `SpringElectricalOptions.gravity` is ngraph's Coulomb constant, written into\n * `Fa2Params.coulomb` while FA2's centre gravity is 0 (PD-12). Settlement is the shared rule of spec 7.17\n * (DEP-P5-A); `reheat()` leaves the velocities alone (ngraph has no reheat).\n *\n * Model decisions this file shares with forceatlas2.ts: on the exact tier the K1-K5 dispatches of one batch share ONE\n * compute pass and toScene runs in a second pass that ends it; the fill kernel takes its FillParams from a model-owned\n * 256-byte uniform buffer. The grid tier (P4-T13, PD-22) is FA2's: `RepulsionGrid` with `LAW` 2 when `tierFor(tuning,\n * n)` says so (PD-18), the grid buffers from `buffers()`, K1's grid block under `gridMax > 0` (PD-14) over the model's\n * own `hubCounters`, the three passes `se-k1` / `se-attraction` / `se-grid` before `se-to-scene` (PD-16), and the\n * union stage list (PD-17; K4 is never recorded).\n */\n\nimport { type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport {\n MAX_ITERATIONS_PER_STEP,\n SE_DEFAULTS,\n SE_SCALE_REFERENCE_NODES,\n SETTLE_FLOOR_FRACTION,\n SETTLE_FLOOR_REFERENCE_NODES,\n TRACE_RECORD_BYTES,\n UNIFORM_SLOT_BYTES,\n} from \"../constants.js\";\nimport { type GpuContext } from \"../context.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type CommandBatch } from \"../kernel/batch.js\";\nimport { type DispatchPlan, plan1d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { type UniformBlock, type UniformValues } from \"../kernel/struct-block.js\";\nimport { type WgslModuleSpec } from \"../kernel/wgsl.js\";\nimport { FA2_PARAMS, FA2_STATE, FA2_TRACE, FILL_PARAMS, kernelSpec } from \"../kernels.js\";\nimport { arcCountOf } from \"../primitives/core-shape.js\";\nimport { type GridSpec, gridSpecFor } from \"../primitives/grid.js\";\nimport {\n type GpuLayoutSimulation,\n type GpuLayoutTuning,\n type ResolvedLayoutTuning,\n type SpringElectricalStats,\n type SpringElectricalTraceRecord,\n} from \"../types/layout.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type ResolvedSpringElectricalOptions, type SpringElectricalOptions } from \"../types/options.js\";\nimport {\n type BufferSpec,\n type ForceModel,\n ForceSimulation,\n type ModelInputs,\n type ModelResources,\n type StateWriter,\n tierFor,\n} from \"./force-simulation.js\";\nimport { resolveLayoutTuning, writeGridFrame } from \"./forceatlas2.js\";\nimport {\n type AttractionBound,\n bindAttraction,\n describeValue,\n FILL_PARAMS_BUFFER,\n FORCE_BYTES_PER_NODE,\n invalid,\n isPositiveInteger,\n type Overrides,\n pickCenter,\n pickDim,\n pickNumber,\n pickSeed,\n recordAttraction,\n scalar,\n seedWord,\n subset,\n vector,\n} from \"./model-common.js\";\nimport { recordExactRepulsion } from \"./repulsion-exact.js\";\nimport { type GridStage, RepulsionGrid, type RepulsionGridOverrides } from \"./repulsion-grid.js\";\n\n// ============================================================ constants\n\n/** The stage names of both tiers in dispatch order plus the per-batch toScene (spec 7.20; P4 PD-17: the union list; the exact tier records K1 K2 K3 K5, the grid tier K1 K2 G1..G7 K5, K4 never). */\nconst SE_STAGES = [\"K1\", \"K2\", \"K3\", \"G1\", \"G2\", \"G3\", \"G4\", \"G5\", \"G6\", \"G7\", \"K4\", \"K5\", \"toScene\"] as const;\n\n/** The SE_STAGES index of the first grid stage, of K4, of K5 and of toScene. */\nconst STAGE_G1 = 3;\nconst STAGE_K4 = 10;\nconst STAGE_K5 = 11;\nconst STAGE_TO_SCENE = 12;\n\n/** The name of the model-owned hub-counter buffer K1 binds on every tier (P4 PD-14). */\nconst HUB_COUNTERS_BUFFER = \"hubCounters\";\n\n/** The one-workgroup dispatch of K1. */\nconst ONE_WORKGROUP: DispatchPlan = { x: 1, y: 1, z: 1, items: 1, stride: null };\n\n/** The model's constant override set (PD-1, PD-20): the spring / coulomb laws, ngraph's Euler step, the kinetic-energy statistic, SWING_MODE 1 so the FA2 text never touches the oldForce slot. */\nconst SE_OVERRIDES: Overrides = Object.freeze({\n LINLOG: false,\n DISTRIBUTED: false,\n TIER: 0,\n SWING_MODE: 1,\n STRONG_GRAVITY: false,\n GRAVITY_CENTER: 0,\n LAW: 2,\n APPLY: 2,\n STATS_MODE: 2,\n});\n\n/** The grid stage's override set (G6 / G7 / K4; P4-T13, PD-22): K3's constant three and the coulomb law. */\nconst SE_GRID_OVERRIDES: RepulsionGridOverrides = Object.freeze({\n SWING_MODE: 1,\n STRONG_GRAVITY: false,\n GRAVITY_CENTER: 0,\n LAW: 2,\n});\n\n/** Every override K1 accepts, with its default. */\nconst K1_DEFAULTS: Overrides = { STATS_MODE: 0 };\n\n/** Every override K2 accepts, with its default (plus the two standard graph overrides). */\nconst K2_DEFAULTS: Overrides = {\n LINLOG: false,\n DISTRIBUTED: false,\n TIER: 0,\n USE_PERM: false,\n HAS_WEIGHTS: false,\n LAW: 0,\n};\n\n/** Every override K3 accepts, with its default. */\nconst K3_DEFAULTS: Overrides = { SWING_MODE: 0, STRONG_GRAVITY: false, GRAVITY_CENTER: 0, LAW: 0 };\n\n/** Every override K5 accepts, with its default. */\nconst K5_DEFAULTS: Overrides = { SWING_MODE: 0, APPLY: 0 };\n\n/** The name of the model's velocity buffer (bound into the `oldForce` slot of K3 / K5, PD-2). */\nconst VELOCITY_BUFFER = \"velocity\";\n\n/** The resolved record with no option given: SE_DEFAULTS plus the origin centre and the null seed; the two force constants null = size-scaled at load. */\nconst DEFAULT_RESOLVED: ResolvedSpringElectricalOptions = Object.freeze<ResolvedSpringElectricalOptions>({\n ...SE_DEFAULTS,\n gravity: null,\n springCoefficient: null,\n center: [0, 0, 0],\n seed: null,\n});\n\n/**\n * The size factor of the default force constants: 1 up to SE_SCALE_REFERENCE_NODES nodes (ngraph's constants as\n * they are), then SE_SCALE_REFERENCE_NODES / n, so the per-node force stays at the level ngraph's constants were\n * tuned for instead of pinning every node at the unit speed clamp.\n * @param n - the node count\n * @returns the factor in (0, 1]\n */\nexport function springSizeFactor(n: number): number {\n return Math.min(1, SE_SCALE_REFERENCE_NODES / Math.max(1, n));\n}\n\n/**\n * An optional force constant: undefined keeps the fallback; null means the size-scaled default; else a finite number\n * passing `ok`.\n * @param name - the option name\n * @param given - the value given\n * @param fallback - the previous record's value or the default\n * @param ok - the range predicate\n * @param range - the range text of the error\n * @returns the number or null\n */\nfunction pickNullable(\n name: string,\n given: unknown,\n fallback: number | null,\n ok: (v: number) => boolean,\n range: string,\n): number | null {\n if (given === undefined) {\n return fallback;\n }\n if (given === null) {\n return null;\n }\n return pickNumber(name, given as number | undefined, 1, ok, `${range} or null`);\n}\n\n// ============================================================ the resolver\n\n/**\n * Applies SE_DEFAULTS to the option record; validates ranges (spec 7.20; ngraph's constraints): `springLength` > 0,\n * `springCoefficient` > 0, `dragCoefficient` >= 0, `timeStep` > 0, `gravity` any finite number (negative repels; ngraph's\n * comment: \"if you make it positive nodes start attract each other\"). `gravity` and `springCoefficient` left out (or\n * null) resolve to null: ngraph's constant times springSizeFactor(n), applied in paramsFor once n is known. With `previous` the record is a PATCH over it and\n * `maxInFlight` may not change (the uniform ring is sized by it at construction).\n * @param options - the caller's options (or a setParams patch)\n * @param previous - the current resolved record when resolving a patch\n * @returns the frozen resolved record\n */\nexport function resolveSpringElectricalOptions(\n options: SpringElectricalOptions | undefined,\n previous?: ResolvedSpringElectricalOptions,\n): ResolvedSpringElectricalOptions {\n const o: SpringElectricalOptions = options ?? {};\n const base = previous ?? DEFAULT_RESOLVED;\n if (previous !== undefined && o.maxInFlight !== undefined && o.maxInFlight !== previous.maxInFlight) {\n throw new WebGpuGraphError(\n \"E_INVALID_ARGUMENT\",\n `maxInFlight cannot change after creation (the uniform ring is sized by it): got ${describeValue(o.maxInFlight)}, current ${previous.maxInFlight}`,\n { argument: \"maxInFlight\", value: o.maxInFlight, expected: previous.maxInFlight },\n );\n }\n const resolved: ResolvedSpringElectricalOptions = {\n springLength: pickNumber(\"springLength\", o.springLength, base.springLength, (v) => v > 0, \"> 0\"),\n springCoefficient: pickNullable(\n \"springCoefficient\",\n o.springCoefficient,\n base.springCoefficient,\n (v) => v > 0,\n \"> 0\",\n ),\n gravity: pickNullable(\"gravity\", o.gravity, base.gravity, () => true, \"a finite number (negative repels)\"),\n dragCoefficient: pickNumber(\"dragCoefficient\", o.dragCoefficient, base.dragCoefficient, (v) => v >= 0, \">= 0\"),\n timeStep: pickNumber(\"timeStep\", o.timeStep, base.timeStep, (v) => v > 0, \"> 0\"),\n dim: pickDim(o.dim, base.dim),\n scale: pickNumber(\"scale\", o.scale, base.scale, (v) => v > 0, \"> 0\"),\n center: pickCenter(o.center, base.center),\n seed: pickSeed(o.seed, base.seed),\n settleThreshold: pickNumber(\"settleThreshold\", o.settleThreshold, base.settleThreshold, (v) => v >= 0, \">= 0\"),\n settleWindow: pickNumber(\n \"settleWindow\",\n o.settleWindow,\n base.settleWindow,\n isPositiveInteger,\n \"an integer >= 1\",\n ),\n iterationsPerStep: pickNumber(\n \"iterationsPerStep\",\n o.iterationsPerStep,\n base.iterationsPerStep,\n (v) => isPositiveInteger(v) && v <= MAX_ITERATIONS_PER_STEP,\n `an integer in [1, ${MAX_ITERATIONS_PER_STEP}]`,\n ),\n maxInFlight: pickNumber(\"maxInFlight\", o.maxInFlight, base.maxInFlight, isPositiveInteger, \"an integer >= 1\"),\n };\n return Object.freeze(resolved);\n}\n\n// ============================================================ the model\n\n/** Everything bind() produced for one load(): the kernels, their bind groups and the dispatch plans of this n. */\ninterface BoundModel {\n readonly n: number;\n /** plan1d(n): K2, K3, K5, toScene. */\n readonly plan: DispatchPlan;\n /** plan1d(3n): the fill of force (arcCount === 0 only). */\n readonly fillPlan: DispatchPlan;\n readonly k1: Kernel;\n readonly k1Bound: BoundKernel;\n /** The K2 tier dispatches (P4 PD-7); null when arcCount === 0 (K2 is not recorded; the fill below zeroes force instead). */\n readonly attraction: AttractionBound | null;\n /** K3 and its bind group, or null on the grid tier (P4 PD-18): one tier's kernels compile per load. */\n readonly k3: Kernel | null;\n readonly k3Bound: BoundKernel | null;\n /** The grid-tier stage (G1-G7), or null on the exact tier (P4 PD-18). */\n readonly grid: RepulsionGrid | null;\n readonly k5: Kernel;\n readonly k5Bound: BoundKernel;\n readonly toScene: Kernel;\n readonly toSceneBound: BoundKernel;\n readonly fill: Kernel;\n /** The fill of `force` (arcCount === 0 only). */\n readonly fillForceBound: BoundKernel | null;\n}\n\n/**\n * The mass of the preset: `1 + degree / 3` per node (ngraph index.js:391-395; the undirected snapshot's outDegree is\n * the degree), as the Float32Array the simulation packs into pos.w.\n * @param s - the snapshot\n * @returns n masses\n */\nfunction massOf(s: GraphSnapshot): Float32Array<ArrayBuffer> {\n const degree = s.outDegree();\n const out = new Float32Array(s.nodeCount);\n for (let i = 0; i < s.nodeCount; i++) {\n out[i] = 1 + degree[i] / 3;\n }\n return out;\n}\n\n/** The spring-electrical model (spec 7.20: K1 K2 K3 K5 per iteration on the exact tier, K1 K2 G1..G7 K5 on the grid tier; toScene once per batch). Stages: the union list of PD-17. */\nexport class SpringElectricalModel implements ForceModel<SpringElectricalOptions, SpringElectricalStats> {\n /** The model kind of spec 7.19. */\n readonly kind = \"springElectrical\";\n /** The stage names in dispatch order (the `upTo` vocabulary of recordIteration and debugRunStages). */\n readonly stages: typeof SE_STAGES = SE_STAGES;\n /** Fa2Params: the per-iteration uniform block (the simulation writes the shared fields into it). */\n readonly params: UniformBlock = FA2_PARAMS;\n /** Fa2State: the state header block. */\n readonly state: UniformBlock = FA2_STATE;\n /** Fa2Trace: one record per iteration of a batch. */\n readonly trace: UniformBlock = FA2_TRACE;\n /** The resolved GPU-only tuning this model was created with (only `repulsion` / `exactMaxNodes` / `nearMax` / `extentFactor` matter here). */\n readonly tuning: ResolvedLayoutTuning;\n\n /** The option record the model holds: the constructor's record, replaced by onSetParams() ONLY (the query hooks never assign it). */\n private current: ResolvedSpringElectricalOptions;\n /** The resources of the last bind(), or null before the first. */\n private resources: ModelResources | null = null;\n /** The kernels and bind groups of the last bind(), or null before it (and for n === 0). */\n private bound: BoundModel | null = null;\n /** The grid of the load inputs() last resolved (null on the exact tier): onLoad() writes its frame, specs() lists its kernels. */\n private nextGrid: GridSpec | null = null;\n /** The K1-K5 compute pass of the batch being recorded, keyed by CommandBatch.id; null between batches. */\n private openPass: { readonly id: number; readonly pass: GPUComputePassEncoder } | null = null;\n\n /**\n * Creates the model for one simulation.\n * @param tuning - the resolved GPU-only tuning\n * @param resolved - the resolved option record at creation\n */\n constructor(tuning: ResolvedLayoutTuning, resolved: ResolvedSpringElectricalOptions) {\n this.tuning = tuning;\n this.current = resolved;\n }\n\n /**\n * force 12n (zeroed), velocity 12n (zeroed: every load() starts at rest, `allocate()` / `clearKept()` honour\n * `zero`), the 256-byte FillParams uniform buffer, the 16-byte `hubCounters` K1 binds on every tier (P4 PD-14),\n * and the grid buffers of `RepulsionGrid.buffers` exactly when `tierFor(tuning, n)` is the grid tier (PD-18).\n * n = 0 reports one node's worth of bytes so no zero-length buffer is ever created.\n * @param n - the node count\n * @param dim - the layout dimension (the arrays are stride 3 in both; the grid's geometry differs)\n * @returns the model-owned buffer specs\n */\n buffers(n: number, dim: 2 | 3): readonly BufferSpec[] {\n const bytes = Math.max(1, n) * FORCE_BYTES_PER_NODE;\n const usage = BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST;\n const grid =\n tierFor(this.tuning, n) === \"grid\" ? RepulsionGrid.buffers(n, gridSpecFor(n, dim, this.tuning)) : [];\n return [\n { name: \"force\", byteLength: bytes, usage, zero: true },\n { name: VELOCITY_BUFFER, byteLength: bytes, usage, zero: true },\n {\n name: FILL_PARAMS_BUFFER,\n byteLength: UNIFORM_SLOT_BYTES,\n usage: BufferUsage.UNIFORM | BufferUsage.COPY_DST,\n zero: false,\n },\n { name: HUB_COUNTERS_BUFFER, byteLength: 16, usage, zero: true },\n ...grid,\n ];\n }\n\n /**\n * { mass: 1 + degree / 3, weights: none } (PD-11): the preset has no mass or weight option, and K2 compiles\n * HAS_WEIGHTS = false. No `fixed` (setFixed is the live API). Also remembers the grid of this load\n * (`tierFor(tuning, n)`, spec 7.8) for onLoad() and specs(): the simulation calls inputs() first, then onLoad()\n * before bind().\n * @param s - the snapshot being loaded\n * @param options - the simulation's current option record (its dimension picks the grid's geometry)\n * @returns the per-load inputs\n */\n inputs(s: GraphSnapshot, options: SpringElectricalOptions): ModelInputs {\n const { dim } = resolveSpringElectricalOptions(options, this.current);\n const n = s.nodeCount;\n this.nextGrid = tierFor(this.tuning, n) === \"grid\" ? gridSpecFor(n, dim, this.tuning) : null;\n return { mass: massOf(s), weights: { data: null, source: \"none\", column: null } };\n }\n\n /**\n * The constant SE_OVERRIDES (PD-1): no option changes a law, so setParams never recompiles.\n * @param _options - an option record (unused)\n * @returns the model's own override set\n */\n overrides(_options: SpringElectricalOptions): Overrides {\n return SE_OVERRIDES;\n }\n\n /**\n * The six module specs of an override set in dispatch order -- K1, K2, K3, K5, toScene, fill -- each with only the\n * override names its entry declares (K2 also USE_PERM / HAS_WEIGHTS), for warm() and the compile matrix,\n * followed by the grid tier's specs (`RepulsionGrid.specs` under SE_GRID_OVERRIDES) when the load inputs() last\n * resolved is a grid load (the pipeline key carries no geometry).\n * @param overrides - the merged override set (the model's plus USE_PERM / HAS_WEIGHTS)\n * @param _subgroups - accepted for the ForceModel interface and unused (the composer picks the twin from caps)\n * @returns the specs\n */\n specs(overrides: Overrides, _subgroups: boolean): readonly WgslModuleSpec[] {\n const grid = this.nextGrid === null ? [] : RepulsionGrid.specs(SE_GRID_OVERRIDES, this.nextGrid);\n return [\n kernelSpec(\"fa2-stats-finalize\", subset(overrides, K1_DEFAULTS)),\n kernelSpec(\"fa2-attraction\", subset(overrides, K2_DEFAULTS)),\n kernelSpec(\"fa2-repulsion-exact\", subset(overrides, K3_DEFAULTS)),\n kernelSpec(\"fa2-integrate\", subset(overrides, K5_DEFAULTS)),\n kernelSpec(\"fa2-to-scene\"),\n kernelSpec(\"fill\"),\n ...grid,\n ];\n }\n\n /**\n * Compiles (through the cache) and binds every kernel against the buffers of this load(): K1, K2 over the degree\n * tiers through bindAttraction (or the fill of force when arcCount === 0), K3 on the exact tier or G1-G7 through\n * RepulsionGrid on the grid tier (PD-18), K5, with the velocity in the `oldForce` slot of K3 / G7 / K5 (PD-2),\n * toScene; writes the FillParams { count: 3n, value: 0, mode: 0 } into the model's uniform buffer. With n === 0\n * nothing is bound. The K2 TIER 1 / 2 pipelines compile on the first load whose degrees need them (P4 PD-7).\n * @param resources - the graph, the shared and model buffers, the ring and the cache\n * @param overrides - the merged override set\n */\n async bind(resources: ModelResources, overrides: Overrides): Promise<void> {\n this.dropBound();\n this.resources = resources;\n const { n, pipelines, caps, core, ring, device } = resources;\n if (n === 0) {\n return;\n }\n const pos = resources.buffer(\"positions\");\n const force = resources.buffer(\"force\");\n const params = ring.binding(FA2_PARAMS);\n const hasArcs = core.colIdx !== null;\n const [k1, k5, toScene, fill] = await Promise.all([\n pipelines.kernel(kernelSpec(\"fa2-stats-finalize\", subset(overrides, K1_DEFAULTS))),\n pipelines.kernel(kernelSpec(\"fa2-integrate\", subset(overrides, K5_DEFAULTS))),\n pipelines.kernel(kernelSpec(\"fa2-to-scene\")),\n pipelines.kernel(kernelSpec(\"fill\")),\n ]);\n const k3 =\n resources.tier === \"grid\"\n ? null\n : await pipelines.kernel(kernelSpec(\"fa2-repulsion-exact\", subset(overrides, K3_DEFAULTS)));\n const attraction = hasArcs\n ? await bindAttraction(resources, subset(overrides, K2_DEFAULTS), { pos, force, params })\n : null;\n const grid =\n resources.tier === \"grid\"\n ? await RepulsionGrid.create(\n resources,\n k1.workgroupSize,\n SE_GRID_OVERRIDES,\n gridSpecFor(n, resources.dim, this.tuning),\n )\n : null;\n if (this.resources !== resources) {\n // a newer bind() superseded this one while the pipelines compiled; its own bind groups stand\n grid?.dispose();\n return;\n }\n const scene = resources.buffer(\"scenePositions\");\n const fixed = resources.buffer(\"fixed\");\n const partials = resources.buffer(\"partials\");\n const state = resources.buffer(\"state\");\n const trace = resources.buffer(\"trace\");\n const velocity = resources.buffer(VELOCITY_BUFFER);\n const fillParamsBuffer = resources.buffer(FILL_PARAMS_BUFFER);\n const fillParams: Binding = {\n buffer: fillParamsBuffer.buffer,\n offset: fillParamsBuffer.offset,\n size: FILL_PARAMS.byteLength,\n window: null,\n };\n const fillBytes = new ArrayBuffer(FILL_PARAMS.byteLength);\n FILL_PARAMS.write(new DataView(fillBytes), { count: 3 * n, value: 0, mode: 0 });\n device.queue.writeBuffer(fillParamsBuffer.buffer, fillParamsBuffer.offset, fillBytes);\n const hubCounters = resources.buffer(HUB_COUNTERS_BUFFER);\n grid?.bind({\n pos,\n state,\n trace,\n force,\n oldForce: velocity,\n fixedMask: fixed,\n partials,\n params,\n cellKey: resources.buffer(\"cellKey\"),\n cellVal: resources.buffer(\"cellVal\"),\n sortedKey: resources.buffer(\"sortedKey\"),\n sortedIdx: resources.buffer(\"sortedIdx\"),\n cellHist: resources.buffer(\"cellHist\"),\n cellStart: resources.buffer(\"cellStart\"),\n hubList: resources.buffer(\"hubList\"),\n hubCounters,\n pyramid: resources.buffer(\"pyramid\"),\n });\n const wg = k1.workgroupSize;\n this.bound = {\n n,\n plan: plan1d(n, wg, caps),\n fillPlan: plan1d(3 * n, wg, caps),\n k1,\n // PD-14: on the exact tier K1's cellHist slot takes a dummy (partials, both read-only) and the block is\n // dead under gridMax 0; hubCounters is the model's 16-byte buffer on every tier\n k1Bound: k1.bind({\n partials,\n S: state,\n T: trace,\n cellHist: grid === null ? partials : resources.buffer(\"cellHist\"),\n hubCounters,\n P: params,\n }),\n attraction,\n k3,\n k3Bound:\n k3?.bind({ pos, S: state, force, oldForce: velocity, fixedMask: fixed, partials, P: params }) ?? null,\n grid,\n k5,\n k5Bound: k5.bind({ force, oldForce: velocity, fixedMask: fixed, S: state, pos, partials, P: params }),\n toScene,\n toSceneBound: toScene.bind({ pos, scene, P: params }),\n fill,\n fillForceBound: hasArcs ? null : fill.bind({ dst: force, P: fillParams }),\n };\n }\n\n /**\n * The Fa2Params values of one iteration: the shared fields, the FA2 fields at 0 (no centre gravity, PD-12; no\n * FR temperature) and ngraph's five constants with `gravity` in `coulomb`.\n * @param iteration - the global iteration index\n * @param options - the simulation's current option record\n * @returns the uniform values\n */\n paramsFor(iteration: number, options: SpringElectricalOptions): UniformValues {\n const { n, core, tiers, tier, dim } = this.requireResources();\n const resolved = resolveSpringElectricalOptions(options, this.current);\n const { nearMax, extentFactor } = this.tuning;\n const grid = tier === \"grid\" ? gridSpecFor(n, dim, this.tuning) : null;\n // P4 PD-7: TIER 2 reads [0, hiEnd), TIER 1 [hiEnd, midEnd), TIER 0 [tierStart, tierEnd) = [midEnd, n)\n const so = tiers?.segmentOffsets;\n const hiEnd = so?.[1] ?? 0;\n const midEnd = so?.[2] ?? 0;\n return {\n n,\n dim: resolved.dim,\n flags: 0,\n tierStart: midEnd,\n tierEnd: n,\n iterationIndex: iteration,\n seed: seedWord(resolved.seed),\n nearMax,\n scalingRatio: 0,\n gravity: 0,\n jitterTolerance: 0,\n scale: resolved.scale,\n center: [resolved.center[0], resolved.center[1], resolved.center[2], 0],\n settleThreshold: resolved.settleThreshold,\n extentFactor,\n gridMax: grid?.g ?? 0,\n levels: grid?.levels ?? 0,\n arcBase: 0,\n arcEnd: arcCountOf(core),\n accumulate: 0,\n hiEnd,\n midEnd,\n frK: 0,\n temperature: 0,\n springLength: resolved.springLength,\n settleFloor:\n SETTLE_FLOOR_FRACTION.springElectrical *\n resolved.springLength *\n (SETTLE_FLOOR_REFERENCE_NODES / Math.max(n, 1)) ** 0.25,\n springCoefficient: resolved.springCoefficient ?? SE_DEFAULTS.springCoefficient * springSizeFactor(n),\n coulomb: resolved.gravity ?? SE_DEFAULTS.gravity * springSizeFactor(n),\n dragCoefficient: resolved.dragCoefficient,\n timeStep: resolved.timeStep,\n };\n }\n\n /**\n * Records one iteration into the batch, stopping after stage `upTo` when given (PD-17: `upTo` names a position\n * in the union list and the recording stops after the last stage recorded at or before it, so \"K3\" on the grid\n * tier stops after K2 and \"G5\" on the exact tier after K3). The exact tier: K1, K2 (or the fill of force when\n * arcCount === 0), K3, K5 in the batch's ONE compute pass, then toScene in a second pass that ends it. The grid\n * tier (PD-16): the passes `se-k1` (K1), `se-attraction` (K2's tiers) and `se-grid` (G1-G7, K5) per iteration,\n * then `se-to-scene`. With n === 0 nothing is recorded; a call before bind() completed is E_NOT_LOADED.\n * @param batch - the batch being recorded\n * @param slot - the UniformRing slot holding this iteration's Fa2Params\n * @param tier - the tier the simulation resolved at load() (the same rule bind() applied, PD-18)\n * @param upTo - a stage name to stop after; undefined records every stage including toScene\n */\n recordIteration(batch: CommandBatch, slot: number, tier: \"exact\" | \"grid\", upTo?: string): void {\n const resources = this.requireResources();\n const stop = upTo === undefined ? STAGE_TO_SCENE : this.stageIndex(upTo);\n const { bound } = this;\n if (bound === null) {\n if (resources.n === 0) {\n return;\n }\n throw new WebGpuGraphError(\n \"E_NOT_LOADED\",\n \"the spring-electrical model is not bound (bind() has not completed)\",\n { state: \"loaded\" },\n );\n }\n const offset = resources.ring.offsetOf(slot);\n if (tier === \"grid\") {\n this.recordGridIteration(batch, bound, offset, stop);\n return;\n }\n const { k3, k3Bound } = bound;\n if (k3 === null || k3Bound === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"the spring-electrical model was bound on the grid tier\", {\n state: \"loaded\",\n });\n }\n const pass = this.openPass !== null && this.openPass.id === batch.id ? this.openPass.pass : batch.pass(\"se\");\n this.openPass = { id: batch.id, pass };\n bound.k1.dispatch(pass, bound.k1Bound, ONE_WORKGROUP, [offset]);\n if (stop < 1) {\n return;\n }\n this.recordK2(pass, bound, offset);\n if (stop < 2) {\n return;\n }\n recordExactRepulsion(k3, pass, k3Bound, bound.plan, bound.n, offset);\n if (stop < STAGE_K5) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < STAGE_TO_SCENE) {\n return;\n }\n this.recordToScene(batch, bound, offset);\n }\n\n /**\n * The grid tier's iteration (PD-16): three compute passes before toScene; no K4.\n * @param batch - the batch being recorded\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset of the iteration\n * @param stop - the SE_STAGES index to stop after\n */\n private recordGridIteration(batch: CommandBatch, bound: BoundModel, offset: number, stop: number): void {\n const { grid } = bound;\n if (grid === null) {\n throw new WebGpuGraphError(\"E_NOT_LOADED\", \"the spring-electrical model was bound on the exact tier\", {\n state: \"loaded\",\n });\n }\n this.openPass = null;\n bound.k1.dispatch(batch.pass(\"se-k1\"), bound.k1Bound, ONE_WORKGROUP, [offset]);\n if (stop < 1) {\n return;\n }\n this.recordK2(batch.pass(\"se-attraction\"), bound, offset);\n if (stop < STAGE_G1) {\n return;\n }\n const pass = batch.pass(\"se-grid\");\n const gridStop = stop < STAGE_K4 ? (SE_STAGES[stop] as GridStage) : undefined;\n grid.recordRepulsion(pass, bound.n, offset, gridStop);\n if (stop < STAGE_K5) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < STAGE_TO_SCENE) {\n return;\n }\n this.recordToScene(batch, bound, offset);\n }\n\n /**\n * K2's tier dispatches, or the fill of force when the graph has no arcs (spec 7.5).\n * @param pass - the open compute pass\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset\n */\n private recordK2(pass: GPUComputePassEncoder, bound: BoundModel, offset: number): void {\n if (bound.attraction !== null) {\n recordAttraction(pass, bound.attraction, offset);\n } else if (bound.fillForceBound !== null) {\n bound.fill.dispatch(pass, bound.fillForceBound, bound.fillPlan, [0]);\n }\n }\n\n /**\n * The toScene pass that ends the iteration's pass; the batch is complete after it, so nothing reuses the pass.\n * @param batch - the batch\n * @param bound - the bound model\n * @param offset - the Fa2Params dynamic offset\n */\n private recordToScene(batch: CommandBatch, bound: BoundModel, offset: number): void {\n this.openPass = null;\n const scenePass = batch.pass(\"se-to-scene\");\n bound.toScene.dispatch(scenePass, bound.toSceneBound, bound.plan, [offset]);\n }\n\n /**\n * kineticEnergy = 0 and temperature = 0 in the header (the velocities start at 0 through the buffer's `zero`);\n * on a grid load the frame of the first build (K1 folds nothing on the first iteration).\n * @param state - the state writer of the simulation\n */\n onLoad(state: StateWriter): void {\n state.set(\"kineticEnergy\", 0);\n state.set(\"temperature\", 0);\n if (this.nextGrid !== null) {\n writeGridFrame(state, this.nextGrid, this.tuning.extentFactor);\n }\n }\n\n /**\n * Nothing: the velocities carry on (ngraph has no reheat; a drag lands in the next batch through the override\n * list, spec 7.12).\n * @param _state - the state writer of the simulation (unused)\n */\n onReheat(_state: StateWriter): void {\n // intentionally empty (D8; DEP-P5-A)\n }\n\n /**\n * Replaces the record with the patch applied (every option is a numeric tweak; nothing recompiles, no reset).\n * @param patch - the setParams patch\n * @param _state - the state writer of the simulation (unused)\n */\n onSetParams(patch: Partial<SpringElectricalOptions>, _state: StateWriter): void {\n this.current = resolveSpringElectricalOptions(patch, this.current);\n }\n\n /**\n * Decodes the state header and the k trace records of a completed batch into SpringElectricalStats:\n * `repulsionTier` is the bound tier, the grid fields are the header's on the grid tier and null on the exact\n * tier; msPerIteration null (the simulation owns the clock); `kineticEnergy` is the last folded value (one\n * iteration behind the last integrate, PD-4).\n * @param state - a DataView over the 256-byte state header\n * @param trace - a DataView over the k Fa2Trace records of the batch\n * @returns the stats\n */\n readStats(state: DataView, trace: DataView): SpringElectricalStats {\n const header = FA2_STATE.read(state);\n const centroid = vector(header, \"centroid\");\n const records: SpringElectricalTraceRecord[] = [];\n const count = Math.floor(trace.byteLength / TRACE_RECORD_BYTES);\n for (let i = 0; i < count; i++) {\n const record = FA2_TRACE.read(trace, i * TRACE_RECORD_BYTES);\n records.push({\n kineticEnergy: scalar(record, \"modelScalar\"),\n meanDisplacement: scalar(record, \"meanDisplacement\"),\n settledCount: scalar(record, \"settledCount\"),\n });\n }\n const grid = this.resources?.tier === \"grid\";\n return {\n iteration: scalar(header, \"iteration\"),\n meanDisplacement: scalar(header, \"meanDisplacement\"),\n rmsRadius: scalar(header, \"rmsRadius\"),\n layoutRadius: scalar(header, \"radius\"),\n centroid: [centroid[0], centroid[1], centroid[2]],\n repulsionTier: grid ? \"grid\" : \"exact\",\n maxCellOccupancy: grid ? scalar(header, \"maxCellOccupancy\") : null,\n outsideGrid: grid ? scalar(header, \"outsideGrid\") : null,\n msPerIteration: null,\n kineticEnergy: scalar(header, \"kineticEnergy\"),\n trace: records,\n };\n }\n\n /**\n * The resources of the last bind(), or E_NOT_LOADED before it.\n * @returns the resources\n */\n private requireResources(): ModelResources {\n if (this.resources === null) {\n throw new WebGpuGraphError(\n \"E_NOT_LOADED\",\n \"the spring-electrical model has not been bound (load() first)\",\n { state: \"created\" },\n );\n }\n return this.resources;\n }\n\n /**\n * The index of a stage name in SE_STAGES, or E_INVALID_ARGUMENT.\n * @param upTo - the stage name\n * @returns its index\n */\n private stageIndex(upTo: string): number {\n for (let i = 0; i < SE_STAGES.length; i++) {\n if (SE_STAGES[i] === upTo) {\n return i;\n }\n }\n throw invalid(\"upTo\", upTo, SE_STAGES.join(\" | \"));\n }\n\n /** Releases the grid stage's lease and the bind groups (the simulation calls it from dispose() once every in-flight batch has settled). */\n dispose(): void {\n this.dropBound();\n }\n\n /** Drops the bind groups of the previous bind() (the buffers changed), releases the grid stage's lease and forgets the pass of a batch recorded before the rebind. */\n private dropBound(): void {\n this.openPass = null;\n const { bound } = this;\n if (bound === null) {\n return;\n }\n for (const kernel of [bound.k1, bound.k5, bound.toScene, bound.fill]) {\n kernel.invalidate();\n }\n bound.k3?.invalidate();\n for (const [kernel] of bound.attraction?.kernels ?? []) {\n kernel.invalidate();\n }\n bound.grid?.dispose();\n this.bound = null;\n }\n}\n\n// ============================================================ the factory\n\n/**\n * The resolve callback of the simulation's setParams: the patch over the current record, re-validated.\n * @param patch - the setParams patch\n * @param current - the simulation's current option record\n * @returns the new record\n */\nfunction resolvePatch(\n patch: Partial<SpringElectricalOptions>,\n current: SpringElectricalOptions,\n): SpringElectricalOptions {\n return resolveSpringElectricalOptions(patch, resolveSpringElectricalOptions(current));\n}\n\n/**\n * Spec 3.3 createSpringElectrical, verbatim: a GpuLayoutSimulation running ngraph's spring-electrical model on the\n * exact or the grid repulsion tier (spec 7.8) with ngraph's defaults (spec 7.20) and the GPU-only tuning of\n * GpuLayoutTuning.\n * @param ctx - the context (E_DISPOSED / E_DEVICE_LOST through assertReady)\n * @param options - the spring-electrical options and the GPU-only tuning knobs in one record\n * @returns the simulation in state \"created\"; load() next\n */\nexport function createSpringElectrical(\n ctx: GpuContext,\n options?: SpringElectricalOptions & GpuLayoutTuning,\n): GpuLayoutSimulation<SpringElectricalOptions, SpringElectricalStats> {\n ctx.assertReady();\n const resolved = resolveSpringElectricalOptions(options);\n const tuning = resolveLayoutTuning(options);\n const model = new SpringElectricalModel(tuning, resolved);\n return new ForceSimulation<SpringElectricalOptions, SpringElectricalStats>(\n ctx,\n model,\n resolved,\n tuning,\n resolvePatch,\n );\n}\n","/**\n * createAccelerator (spec 3.3, 9; contract 3.14): the injectable object that satisfies the CPU packages'\n * AlgorithmAccelerator and LayoutAccelerator interfaces (spec 9.2, 9.3). Both are the REAL declarations,\n * `LayoutAccelerator` from `@graphty/layout` (W1b, layout half) and `AlgorithmAccelerator` from\n * `@graphty/algorithms` (W1b, algorithms half), `import type`d by src/types/accelerator.ts, so the object built\n * here is checked against the CPU packages' own contracts. It carries P3's `forceAtlas2`, `release` and `dispose`,\n * P5's `fruchtermanReingold` and `springElectrical` (the two other layout members of spec 9.3, landed together once\n * both models were green, P5 PD-19), P7's seven algorithm members (spec 8.2, 8.3; M8b-T8, PD-14) and P8's four\n * traversal members (spec 8.4; P8-T13 PD-16, PD-19: `breadthFirstSearch`, `sssp`, `bellmanFord`,\n * `closenessCentrality`, each taking the seam's own option type), `allPairsShortestPath` (design 8.7), P11's\n * `triangleCount` and `labelPropagation`, Boruvka's `minimumSpanningTree`, and nothing else: the CPU-side dispatchers\n * (`accelerated()`, `createSimulation()`) test `acc.betweennessCentrality !== undefined` /\n * `acc.fruchtermanReingold !== undefined` and route to the CPU when the member is absent (spec 2.4 row \"method\n * missing\"), so a method the GPU does not implement must not exist here -- never a throwing stub. The remaining\n * algorithm members arrive one per shipped algorithm from P9.\n */\n\nimport { type F32, type F64, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { allPairsShortestPath } from \"./algorithms/all-pairs.js\";\nimport { bellmanFord } from \"./algorithms/bellman-ford.js\";\nimport { betweennessCentrality, edgeBetweennessCentrality } from \"./algorithms/betweenness.js\";\nimport { breadthFirstSearch } from \"./algorithms/bfs.js\";\nimport { closenessCentrality } from \"./algorithms/closeness.js\";\nimport { connectedComponents } from \"./algorithms/components.js\";\nimport { labelPropagation } from \"./algorithms/label-propagation.js\";\nimport { minimumSpanningTree } from \"./algorithms/mst.js\";\nimport { pageRank, personalizedPageRank } from \"./algorithms/pagerank.js\";\nimport { eigenvectorCentrality, hits, katzCentrality } from \"./algorithms/spectral.js\";\nimport { sssp } from \"./algorithms/sssp.js\";\nimport { triangleCount } from \"./algorithms/triangles.js\";\nimport { type GpuContext } from \"./context.js\";\nimport { WebGpuGraphError } from \"./errors.js\";\nimport { createForceAtlas2 } from \"./layouts/forceatlas2.js\";\nimport { createFruchtermanReingold } from \"./layouts/fruchterman-reingold.js\";\nimport { createSpringElectrical } from \"./layouts/spring-electrical.js\";\nimport {\n type AcceleratorOptions,\n type BetweennessAcceleratorOptions,\n type BfsOptions,\n type ClosenessAcceleratorOptions,\n type GpuAccelerator,\n type HitsOptionsLike,\n type MstOptions,\n type SsspOptions,\n} from \"./types/accelerator.js\";\nimport {\n type ComponentsOptions,\n type EigenvectorOptions,\n type GpuClosenessResult,\n type GpuHitsResult,\n type GpuLabelResult,\n type GpuPageRankResult,\n type GpuScoresResult,\n type HitsOptions,\n type KatzOptions,\n type PageRankOptions,\n} from \"./types/algorithms.js\";\nimport { type GpuApspResult } from \"./types/all-pairs.js\";\nimport { type GpuBetweennessResult, type GpuEdgeScoresResult } from \"./types/betweenness.js\";\nimport {\n type ForceAtlas2Stats,\n type FruchtermanReingoldStats,\n type GpuLayoutSimulation,\n type GpuLayoutTuning,\n type SpringElectricalStats,\n} from \"./types/layout.js\";\nimport {\n type ForceAtlas2Options,\n type FruchtermanReingoldOptions,\n type SpringElectricalOptions,\n} from \"./types/options.js\";\nimport { type GpuMstResult, type GpuTriangleResult } from \"./types/structure.js\";\nimport { type GpuBellmanFordResult, type GpuBfsResult, type GpuSsspResult } from \"./types/traversal.js\";\n\n/** The `algorithms` record of AcceleratorOptions (spec 3.3), named for the copy helpers. */\ntype AlgorithmDefaults = NonNullable<AcceleratorOptions[\"algorithms\"]>;\n\n/** The `algorithms.betweenness` record of AcceleratorOptions (spec 3.3: the `k` / `sources` defaults until A2). */\ntype BetweennessDefaults = NonNullable<AlgorithmDefaults[\"betweenness\"]>;\n\n/**\n * Frozen copy of the betweenness defaults; `sources` is copied into a fresh frozen array so a later mutation of\n * the caller's list is never seen by the accelerator.\n * @param defaults - the caller's record\n * @returns the frozen copy\n */\nfunction copyBetweenness(defaults: BetweennessDefaults): BetweennessDefaults {\n const copy: { k?: number | undefined; sources?: readonly number[] | undefined } = { ...defaults };\n if (defaults.sources !== undefined) {\n copy.sources = Object.freeze([...defaults.sources]);\n }\n return Object.freeze(copy);\n}\n\n/**\n * A betweenness call's options with the accelerator's `algorithms.betweenness` defaults applied: the defaults supply\n * `sources` / `k` only when the call names neither, so a call's own sampling always wins whole. The defaults serve\n * graphs of every size, so they are fitted to this one: a default `sources` list keeps only the indices below\n * `nodeCount` (and then wins over a default `k`), and a default `k` of `nodeCount` or more runs every vertex.\n * @param defaults - the frozen defaults, if any\n * @param options - the call's options\n * @param nodeCount - the snapshot's vertex count\n * @returns the options the driver runs with\n */\nfunction withBetweennessDefaults(\n defaults: BetweennessDefaults | undefined,\n options: BetweennessAcceleratorOptions | undefined,\n nodeCount: number,\n): BetweennessAcceleratorOptions | undefined {\n if (defaults === undefined || options?.sources !== undefined || options?.k !== undefined) {\n return options;\n }\n if (defaults.sources !== undefined) {\n return { ...options, sources: defaults.sources.filter((v) => v < nodeCount) };\n }\n return { ...options, k: defaults.k !== undefined && defaults.k < nodeCount ? defaults.k : undefined };\n}\n\n/**\n * Frozen copy of the algorithms record, one level deeper for `betweenness`.\n * @param algorithms - the caller's record\n * @returns the frozen copy\n */\nfunction copyAlgorithms(algorithms: AlgorithmDefaults): AlgorithmDefaults {\n const copy: { betweenness?: BetweennessDefaults | undefined } = { ...algorithms };\n if (algorithms.betweenness !== undefined) {\n copy.betweenness = copyBetweenness(algorithms.betweenness);\n }\n return Object.freeze(copy);\n}\n\n/**\n * The frozen deep copy of the accelerator options (spec 3.3 GpuAccelerator.options: \"the tuning defaults given\n * to createAccelerator; frozen\"; contract 3.14): the record, its `layout` tuning, its `algorithms` record, the\n * `betweenness` record and the `sources` list are each fresh frozen objects, so neither the caller's later edits\n * nor a consumer's writes can change what the accelerator's simulations inherit.\n * @param options - the caller's options, or undefined\n * @returns the frozen copy (an empty frozen record when nothing was given)\n */\nfunction freezeOptions(options: AcceleratorOptions | undefined): Readonly<AcceleratorOptions> {\n if (options === undefined) {\n return Object.freeze({});\n }\n const copy: { layout?: GpuLayoutTuning | undefined; algorithms?: AlgorithmDefaults | undefined } = { ...options };\n if (options.layout !== undefined) {\n copy.layout = Object.freeze({ ...options.layout });\n }\n if (options.algorithms !== undefined) {\n copy.algorithms = copyAlgorithms(options.algorithms);\n }\n return Object.freeze(copy);\n}\n\n/**\n * Spec 3.3 createAccelerator, verbatim: the object implementing AlgorithmAccelerator & LayoutAccelerator\n * structurally; P3's forceAtlas2, release and dispose, P5's fruchtermanReingold and springElectrical (the same\n * `{ ...o, ...options.layout }` shape as forceAtlas2) plus P7's seven algorithm members and P8's four traversal\n * members and the two betweenness members, each a delegation to its algorithm with `ctx.assertReady()` first. Only\n * the betweenness members consult the accelerator's algorithm defaults (`algorithms.betweenness` supplies `sources` /\n * `k` when a call names neither). One per call (the app creates one and injects\n * it, spec 2.4); `kind` is \"webgpu\"; `options` is a frozen deep copy; `forceAtlas2(o)` is\n * `createForceAtlas2(ctx, { ...o, ...options.layout })`, so the GPU tuning given here wins over anything the\n * CPU-typed option object carries (spec 3.3: tuning never comes from the caller of the accelerator method);\n * `release(s)` is `ctx.release(s)`; `dispose()` is `ctx.dispose()`.\n * @param ctx - the context every simulation the accelerator creates runs on\n * @param options - GPU-only defaults inherited by every simulation (`layout`) and, from P9, the algorithm defaults\n * @returns the injectable accelerator\n * @throws E_DISPOSED / E_DEVICE_LOST from `ctx.assertReady()` (here and inside every creating member); `forceAtlas2()`\n * also throws what createForceAtlas2 throws (E_UNSUPPORTED for `nodeSize`, E_INVALID_ARGUMENT for a bad range), and\n * `fruchtermanReingold()` / `springElectrical()` what their factories throw (E_INVALID_ARGUMENT for a bad range)\n */\nexport function createAccelerator(ctx: GpuContext, options?: AcceleratorOptions): GpuAccelerator {\n ctx.assertReady();\n const frozen = freezeOptions(options);\n return {\n kind: \"webgpu\",\n harmonicCloseness: true,\n ctx,\n options: frozen,\n /**\n * The ForceAtlas2 simulation with this accelerator's layout tuning (spec 3.3; contract 3.14).\n * @param o - the CPU option type (spec 9.3 ForceAtlas2Options); GPU tuning keys come from `options.layout`\n * @returns a fresh simulation in state \"created\"\n */\n forceAtlas2(o?: ForceAtlas2Options): GpuLayoutSimulation<ForceAtlas2Options, ForceAtlas2Stats> {\n ctx.assertReady();\n return createForceAtlas2(ctx, { ...o, ...frozen.layout });\n },\n /**\n * The Fruchterman-Reingold simulation with this accelerator's layout tuning (spec 3.3, 7.20; P5).\n * @param o - the CPU option type (spec 9.3 FruchtermanReingoldOptions); GPU tuning keys come from `options.layout`\n * @returns a fresh simulation in state \"created\"\n */\n fruchtermanReingold(\n o?: FruchtermanReingoldOptions,\n ): GpuLayoutSimulation<FruchtermanReingoldOptions, FruchtermanReingoldStats> {\n ctx.assertReady();\n return createFruchtermanReingold(ctx, { ...o, ...frozen.layout });\n },\n /**\n * The spring-electrical preset with this accelerator's layout tuning (spec 3.3, 7.20; P5).\n * @param o - the CPU option type (spec 9.3 SpringElectricalOptions, ngraph's names)\n * @returns a fresh simulation in state \"created\"\n */\n springElectrical(\n o?: SpringElectricalOptions,\n ): GpuLayoutSimulation<SpringElectricalOptions, SpringElectricalStats> {\n ctx.assertReady();\n return createSpringElectrical(ctx, { ...o, ...frozen.layout });\n },\n /**\n * PageRank on the device (spec 8.2; contract 3.14).\n * @param gs - the snapshot\n * @param o - the CPU option record (spec 9.2 PageRankOptions)\n * @returns the f32 scores with `precision: \"f32\"` (spec 9.7)\n */\n async pageRank(gs: GraphSnapshot, o?: PageRankOptions): Promise<GpuPageRankResult> {\n ctx.assertReady();\n return await pageRank(ctx, gs, o);\n },\n /**\n * Personalized PageRank on the device (spec 8.2; contract 3.14). The mirror admits an f64 personalization\n * (spec 9.2 `F32 | F64`); the kernel reads f32, so an f64 vector is narrowed on the host first.\n * @param gs - the snapshot\n * @param personalization - one finite non-negative mass per node, not all zero\n * @param o - the CPU option record (spec 9.2 PageRankOptions)\n * @returns the f32 scores with `precision: \"f32\"` (spec 9.7)\n */\n async personalizedPageRank(\n gs: GraphSnapshot,\n personalization: F32 | F64,\n o?: PageRankOptions,\n ): Promise<GpuPageRankResult> {\n ctx.assertReady();\n const mass = personalization instanceof Float32Array ? personalization : Float32Array.from(personalization);\n return await personalizedPageRank(ctx, gs, mass, o);\n },\n /**\n * HITS hubs and authorities on the device (spec 8.2; contract 3.14).\n * @param gs - the snapshot\n * @param o - the CPU option record (spec 9.2 HitsOptions)\n * @returns hubs and authorities with `precision: \"f32\"` (spec 9.7)\n */\n async hits(gs: GraphSnapshot, o?: HitsOptions): Promise<GpuHitsResult> {\n ctx.assertReady();\n return await hits(ctx, gs, o);\n },\n /**\n * Eigenvector centrality on the device (spec 8.2; contract 3.14).\n * @param gs - the snapshot\n * @param o - the CPU option record (spec 9.2 EigenvectorOptions)\n * @returns the f32 scores with `precision: \"f32\"` (spec 9.7)\n */\n async eigenvectorCentrality(gs: GraphSnapshot, o?: EigenvectorOptions): Promise<GpuScoresResult> {\n ctx.assertReady();\n return await eigenvectorCentrality(ctx, gs, o);\n },\n /**\n * Katz centrality on the device (spec 8.2; contract 3.14).\n * @param gs - the snapshot\n * @param o - the CPU option record (spec 9.2 KatzOptions)\n * @returns the f32 scores with `precision: \"f32\"` (spec 9.7)\n */\n async katzCentrality(gs: GraphSnapshot, o?: KatzOptions): Promise<GpuScoresResult> {\n ctx.assertReady();\n return await katzCentrality(ctx, gs, o);\n },\n /**\n * Weakly connected components on the device (spec 8.3; contract 3.14): WCC semantics on directed input.\n * @param gs - the snapshot\n * @param o - `renumber` (default true); the mirror passes none\n * @returns the labels, the count and groups() (spec 9.7 LabelResultLike)\n */\n async connectedComponents(gs: GraphSnapshot, o?: ComponentsOptions): Promise<GpuLabelResult> {\n ctx.assertReady();\n return await connectedComponents(ctx, gs, o);\n },\n /**\n * The same algorithm as `connectedComponents` under the mirror's other name (spec 3.3, 9.2).\n * @param gs - the snapshot\n * @param o - `renumber` (default true); the mirror passes none\n * @returns the labels, the count and groups() (spec 9.7 LabelResultLike)\n */\n async weaklyConnectedComponents(gs: GraphSnapshot, o?: ComponentsOptions): Promise<GpuLabelResult> {\n ctx.assertReady();\n return await connectedComponents(ctx, gs, o);\n },\n /**\n * Breadth-first search on the device (spec 8.4; P8-T13). The result is bitwise reproducible (P8 PD-14).\n * @param gs - the snapshot\n * @param source - the source node index\n * @param o - the seam's `BfsOptions` (`maxDepth`)\n * @returns depth, parent, the level-grouped order, visitedCount, levels and switches (spec 3.3 line 830)\n */\n async breadthFirstSearch(gs: GraphSnapshot, source: number, o?: BfsOptions): Promise<GpuBfsResult> {\n ctx.assertReady();\n return await breadthFirstSearch(ctx, gs, source, o);\n },\n /**\n * Single-source shortest paths on the device (spec 8.4; P8-T13): the near-far queue over f32 distances, or the\n * breadth-first route when every weight is one.\n * @param gs - the snapshot\n * @param source - the source node index\n * @param o - the seam's `SsspOptions` (`cutoff`, `weights`)\n * @returns dist, predArc and reachedCount (spec 3.3 line 831)\n */\n async sssp(gs: GraphSnapshot, source: number, o?: SsspOptions): Promise<GpuSsspResult> {\n ctx.assertReady();\n return await sssp(ctx, gs, source, o);\n },\n /**\n * Bellman-Ford on the device with negative-cycle detection (spec 8.4; P8-T13).\n * @param gs - the snapshot\n * @param source - the source node index\n * @param o - the seam's `SsspOptions` (`cutoff`, `weights`)\n * @returns dist, predArc, reachedCount and hasNegativeCycle (spec 3.3 line 832)\n */\n async bellmanFord(gs: GraphSnapshot, source: number, o?: SsspOptions): Promise<GpuBellmanFordResult> {\n ctx.assertReady();\n return await bellmanFord(ctx, gs, source, o);\n },\n /**\n * Betweenness centrality on the device (spec 8.4): exact, or sampled through `sources` / `k` (the call's own,\n * else the accelerator's `algorithms.betweenness` defaults), the unscaled sum over the sources run.\n * `endpoints: true` is refused.\n * @param gs - the snapshot\n * @param o - the seam's `BetweennessAcceleratorOptions`\n * @returns the f32 scores with `sourcesUsed` and `sigmaOverflow`\n */\n async betweennessCentrality(\n gs: GraphSnapshot,\n o?: BetweennessAcceleratorOptions,\n ): Promise<GpuBetweennessResult> {\n ctx.assertReady();\n return await betweennessCentrality(\n ctx,\n gs,\n withBetweennessDefaults(frozen.algorithms?.betweenness, o, gs.nodeCount),\n );\n },\n /**\n * Edge betweenness on the device (spec 8.4): one score per edge, arcs summed and halved when undirected; sampling\n * and defaults as `betweennessCentrality`.\n * @param gs - the snapshot\n * @param o - the seam's `BetweennessAcceleratorOptions`\n * @returns the f32 per-edge scores with `sourcesUsed` and `sigmaOverflow`\n */\n async edgeBetweennessCentrality(\n gs: GraphSnapshot,\n o?: BetweennessAcceleratorOptions,\n ): Promise<GpuEdgeScoresResult> {\n ctx.assertReady();\n return await edgeBetweennessCentrality(\n ctx,\n gs,\n withBetweennessDefaults(frozen.algorithms?.betweenness, o, gs.nodeCount),\n );\n },\n /**\n * Closeness centrality on the device (spec 8.4): the all-pairs sweep with a row sum on small and\n * weighted graphs, the bit-parallel multi-source search otherwise, one `sssp` per source for a weighted graph\n * above the all-pairs ceiling. `maxIterations` / `tolerance` are refused when defined (P8 PD-25).\n * @param gs - the snapshot\n * @param o - `weighted`, `harmonic` (exact runs), and a sampled run's `sources` (undirected snapshots only)\n * @returns the f32 scores with `precision: \"f32\"` (spec 9.7) and `sourcesUsed`\n */\n async closenessCentrality(gs: GraphSnapshot, o?: ClosenessAcceleratorOptions): Promise<GpuClosenessResult> {\n ctx.assertReady();\n return await closenessCentrality(ctx, gs, o);\n },\n /**\n * All-pairs shortest paths on the device (design 8.7): blocked Floyd-Warshall, `E_TOO_LARGE` above the device's\n * storage-binding ceiling. The seam passes `SsspOptions`; neither of its keys has an all-pairs meaning, so a\n * defined `cutoff` (it would change what `+Infinity` means) or `weights` (a per-arc override is a different\n * matrix from the snapshot's resident column) is `E_UNSUPPORTED { option }`, never silently dropped.\n * @param gs - the snapshot\n * @param o - the seam's `SsspOptions`; both keys refused when defined\n * @returns the row-major `n x n` distances and `n` (spec 3.3 line 835)\n */\n async allPairsShortestPath(gs: GraphSnapshot, o?: SsspOptions): Promise<GpuApspResult> {\n ctx.assertReady();\n for (const key of [\"cutoff\", \"weights\"] as const) {\n if (o?.[key] !== undefined) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", `allPairsShortestPath: ${key} is not supported`, {\n option: key,\n hint: \"all-pairs shortest paths runs over the snapshot's own weights with no cutoff\",\n });\n }\n }\n return await allPairsShortestPath(ctx, gs);\n },\n /**\n * Triangle counting with the clustering coefficient and the transitivity (design 8.5; P11).\n * @param gs - the snapshot\n * @returns perNode, total, coefficient and transitivity\n */\n async triangleCount(gs: GraphSnapshot): Promise<GpuTriangleResult> {\n ctx.assertReady();\n return await triangleCount(ctx, gs);\n },\n /**\n * Label propagation (design 8.6; P11): `maxIterations` and `weighted` are honoured, `tolerance` is refused when\n * defined (a label propagation stops at a fixed point, not below a tolerance).\n * @param gs - the snapshot\n * @param o - the seam's placeholder `HitsOptionsLike`\n * @returns the labels dense in first-seen order, the community count and groups()\n */\n async labelPropagation(gs: GraphSnapshot, o?: HitsOptionsLike): Promise<GpuLabelResult> {\n ctx.assertReady();\n if (o?.tolerance !== undefined) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"labelPropagation: tolerance has no meaning here\", {\n option: \"tolerance\",\n hint: \"label propagation stops at a fixed point or after maxIterations passes\",\n });\n }\n return await labelPropagation(ctx, gs, { maxIterations: o?.maxIterations, weighted: o?.weighted });\n },\n /**\n * Boruvka's minimum spanning forest (design 8.5; P11-T4): the forest of the total edge order (weight, then\n * edge index), which is the one `kruskalMST` accepts. The seam's per-arc `weights` override is refused when\n * defined: the forest runs over the snapshot's own edge weights.\n * @param gs - the snapshot\n * @param o - the seam's `MstOptions`; `weights` refused when defined\n * @returns the forest's logical edge indices and its f64 total weight\n */\n async minimumSpanningTree(gs: GraphSnapshot, o?: MstOptions): Promise<GpuMstResult> {\n ctx.assertReady();\n if (o?.weights !== undefined) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"minimumSpanningTree: weights is not supported\", {\n option: \"weights\",\n hint: \"the spanning forest runs over the snapshot's own edge weights\",\n });\n }\n return await minimumSpanningTree(ctx, gs);\n },\n /**\n * Destroys every device buffer recorded for the snapshot (spec 4.5); delegates to ctx.release.\n * @param s - the snapshot the app is done with\n */\n release(s: GraphSnapshot): void {\n ctx.release(s);\n },\n /**\n * Disposes the context (spec 2.8); delegates to ctx.dispose, idempotent.\n */\n dispose(): void {\n ctx.dispose();\n },\n };\n}\n"],"names":["U32_MAX","messageOf","decl","IDENTIFIER","stripComments","isSharedBuffer","invalid","entry","CORE_ORDER","ARC_INDEXED","record","bindings","resolve","assertCount","scalar","checkRecordArguments","RING_SLOTS","whole","checkWords","ALGORITHM","checkDest","bindingOf","aborted","wordOf","recordFill","pass","submit","level","back","block","resolveWeights","sum","finite","vector","ROUNDS_PER_BATCH","coreOf","bound","empty","graph","params","resultOf","settled","normaliser","normalised","run","s","out","STAGE_G1","STAGE_K4","STAGE_K5","STAGE_TO_SCENE","HUB_COUNTERS_BUFFER","ONE_WORKGROUP","K2_DEFAULTS","K5_DEFAULTS","DEFAULT_RESOLVED","grid","resolvePatch","K1_DEFAULTS","K3_DEFAULTS"],"mappings":"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A;AAAA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACIlC,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACT/B,MAAM;AAAA;AAAA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACSpC,MAAM;AAAA;AAAA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACGlC,MAAM;AAAA;AAAA,EAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACVjC,MAAM;AAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACNrC,MAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACgBhC,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACV/B,MAAM;AAAA;AAAA,EAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACMtC,MAAM;AAAA;AAAA,EAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACDnC,MAAM;AAAA;AAAA,EAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACKnC,MAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACFhC,MAAM;AAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACLrC,MAAM;AAAA;AAAA,EAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACmBzC,MAAM;AAAA;AAAA,EAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AC1BtC,MAAM;AAAA;AAAA,EAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACFvC,MAAM;AAAA;AAAA,EAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACCtC,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACK/B,MAAM;AAAA;AAAA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACPlC,MAAM;AAAA;AAAA,EAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACEvC,MAAM;AAAA;AAAA,EAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACEnC,MAAM;AAAA;AAAA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACFpC,MAAM;AAAA;AAAA,EAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACkB9B,MAAM;AAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACTrC,MAAM;AAAA;AAAA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACFpC,MAAM;AAAA;AAAA,EAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACFzC,MAAM;AAAA;AAAA,EAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACWxC,MAAM;AAAA;AAAA,EAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACdxC,MAAM;AAAA;AAAA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACLlC,MAAM;AAAA;AAAA,EAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AC+C5B,MAAM;AAAA;AAAA,EAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AC7CxC,MAAM;AAAA;AAAA,EAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAnC,MAAM;AAAA;AAAA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACDpC,MAAM;AAAA;AAAA,EAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACDvC,MAAM;AAAA;AAAA,EAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACQtC,MAAM;AAAA;AAAA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACIpC,MAAM;AAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACOrC,MAAM;AAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACnBrC,MAAM;AAAA;AAAA,EAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACCjC,MAAM;AAAA;AAAA,EAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACExC,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACG/B,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACC/B,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACL/B,MAAM;AAAA;AAAA,EAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACGnC,MAAM;AAAA;AAAA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACGlC,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACN/B,MAAM;AAAA;AAAA,EAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAjC,MAAM;AAAA;AAAA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACCpC,MAAM;AAAA;AAAA,EAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACF9B,MAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACFhC,MAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACE/B,MAAM;AAAA;AAAA,EAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACoBjC,MAAM;AAAA;AAAA,EAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACDvC,MAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACChC,MAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACEhC,MAAM;AAAA;AAAA,EAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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"}
|