@graphty/webgpu-graph-algorithms 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -52
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-BR7fx3vR.js → context-BXqgCifx.js} +190 -40
- package/dist/chunks/context-BXqgCifx.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/algorithms/components.d.ts.map +1 -1
- package/dist/src/algorithms/components.js +12 -13
- package/dist/src/algorithms/components.js.map +1 -1
- package/dist/src/algorithms/degree.d.ts +6 -8
- package/dist/src/algorithms/degree.d.ts.map +1 -1
- package/dist/src/algorithms/degree.js +58 -35
- package/dist/src/algorithms/degree.js.map +1 -1
- package/dist/src/algorithms/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/pagerank.js +16 -14
- package/dist/src/algorithms/pagerank.js.map +1 -1
- package/dist/src/algorithms/power-iteration.d.ts +2 -2
- package/dist/src/algorithms/power-iteration.d.ts.map +1 -1
- package/dist/src/algorithms/power-iteration.js +17 -14
- package/dist/src/algorithms/power-iteration.js.map +1 -1
- package/dist/src/constants.d.ts +38 -8
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +38 -8
- package/dist/src/constants.js.map +1 -1
- package/dist/src/errors.d.ts +3 -2
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +2 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +6 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/dispatch.d.ts +8 -3
- package/dist/src/kernel/dispatch.d.ts.map +1 -1
- package/dist/src/kernel/dispatch.js +18 -7
- package/dist/src/kernel/dispatch.js.map +1 -1
- package/dist/src/kernel/kernel.d.ts +30 -1
- package/dist/src/kernel/kernel.d.ts.map +1 -1
- package/dist/src/kernel/kernel.js +49 -5
- package/dist/src/kernel/kernel.js.map +1 -1
- package/dist/src/kernel/prelude.d.ts.map +1 -1
- package/dist/src/kernel/prelude.js +6 -1
- package/dist/src/kernel/prelude.js.map +1 -1
- package/dist/src/kernel/profiler.d.ts +15 -3
- package/dist/src/kernel/profiler.d.ts.map +1 -1
- package/dist/src/kernel/profiler.js +27 -4
- package/dist/src/kernel/profiler.js.map +1 -1
- package/dist/src/kernels.d.ts +17 -7
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +323 -16
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/calibrate.d.ts +51 -0
- package/dist/src/layouts/calibrate.d.ts.map +1 -0
- package/dist/src/layouts/calibrate.js +172 -0
- package/dist/src/layouts/calibrate.js.map +1 -0
- package/dist/src/layouts/force-simulation.d.ts +39 -4
- package/dist/src/layouts/force-simulation.d.ts.map +1 -1
- package/dist/src/layouts/force-simulation.js +71 -19
- package/dist/src/layouts/force-simulation.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts +107 -36
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +296 -100
- package/dist/src/layouts/forceatlas2.js.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.d.ts +73 -27
- package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.js +230 -70
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -1
- package/dist/src/layouts/model-common.d.ts +41 -3
- package/dist/src/layouts/model-common.d.ts.map +1 -1
- package/dist/src/layouts/model-common.js +74 -3
- package/dist/src/layouts/model-common.js.map +1 -1
- package/dist/src/layouts/repulsion-grid.d.ts +152 -0
- package/dist/src/layouts/repulsion-grid.d.ts.map +1 -0
- package/dist/src/layouts/repulsion-grid.js +318 -0
- package/dist/src/layouts/repulsion-grid.js.map +1 -0
- package/dist/src/layouts/spring-electrical.d.ts +75 -30
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -1
- package/dist/src/layouts/spring-electrical.js +231 -74
- package/dist/src/layouts/spring-electrical.js.map +1 -1
- package/dist/src/memory/residency.d.ts +6 -2
- package/dist/src/memory/residency.d.ts.map +1 -1
- package/dist/src/memory/residency.js +84 -14
- package/dist/src/memory/residency.js.map +1 -1
- package/dist/src/primitives/core-shape.d.ts +38 -2
- package/dist/src/primitives/core-shape.d.ts.map +1 -1
- package/dist/src/primitives/core-shape.js +71 -3
- package/dist/src/primitives/core-shape.js.map +1 -1
- package/dist/src/primitives/grid-pyramid.d.ts +71 -0
- package/dist/src/primitives/grid-pyramid.d.ts.map +1 -0
- package/dist/src/primitives/grid-pyramid.js +143 -0
- package/dist/src/primitives/grid-pyramid.js.map +1 -0
- package/dist/src/primitives/grid.d.ts +118 -0
- package/dist/src/primitives/grid.d.ts.map +1 -0
- package/dist/src/primitives/grid.js +225 -0
- package/dist/src/primitives/grid.js.map +1 -0
- package/dist/src/primitives/histogram.d.ts +67 -0
- package/dist/src/primitives/histogram.d.ts.map +1 -0
- package/dist/src/primitives/histogram.js +190 -0
- package/dist/src/primitives/histogram.js.map +1 -0
- package/dist/src/primitives/radix-sort.d.ts +75 -0
- package/dist/src/primitives/radix-sort.d.ts.map +1 -0
- package/dist/src/primitives/radix-sort.js +168 -0
- package/dist/src/primitives/radix-sort.js.map +1 -0
- package/dist/src/primitives/scan.d.ts +44 -0
- package/dist/src/primitives/scan.d.ts.map +1 -0
- package/dist/src/primitives/scan.js +151 -0
- package/dist/src/primitives/scan.js.map +1 -0
- package/dist/src/primitives/segmented-reduce.d.ts +25 -17
- package/dist/src/primitives/segmented-reduce.d.ts.map +1 -1
- package/dist/src/primitives/segmented-reduce.js +166 -47
- package/dist/src/primitives/segmented-reduce.js.map +1 -1
- package/dist/src/primitives/spmv.d.ts +18 -14
- package/dist/src/primitives/spmv.d.ts.map +1 -1
- package/dist/src/primitives/spmv.js +94 -58
- package/dist/src/primitives/spmv.js.map +1 -1
- package/dist/src/primitives/verify.d.ts +49 -0
- package/dist/src/primitives/verify.d.ts.map +1 -0
- package/dist/src/primitives/verify.js +229 -0
- package/dist/src/primitives/verify.js.map +1 -0
- package/dist/src/types/context.d.ts +53 -0
- package/dist/src/types/context.d.ts.map +1 -1
- package/dist/src/types/layout.d.ts +20 -0
- package/dist/src/types/layout.d.ts.map +1 -1
- package/dist/src/wgsl/counting-scatter.wgsl.d.ts +8 -0
- package/dist/src/wgsl/counting-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/counting-scatter.wgsl.js +17 -0
- package/dist/src/wgsl/counting-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +23 -11
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-attraction.wgsl.js +98 -20
- package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +6 -2
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +22 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.js +30 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js +29 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-centroid.wgsl.js +29 -0
- package/dist/src/wgsl/grid-centroid.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-downsample.wgsl.d.ts +7 -0
- package/dist/src/wgsl/grid-downsample.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-downsample.wgsl.js +28 -0
- package/dist/src/wgsl/grid-downsample.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts +13 -0
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-far-field.wgsl.js +98 -0
- package/dist/src/wgsl/grid-far-field.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts +19 -0
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-near-field.wgsl.js +129 -0
- package/dist/src/wgsl/grid-near-field.wgsl.js.map +1 -0
- package/dist/src/wgsl/histogram.wgsl.d.ts +7 -0
- package/dist/src/wgsl/histogram.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/histogram.wgsl.js +15 -0
- package/dist/src/wgsl/histogram.wgsl.js.map +1 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.d.ts +8 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.js +26 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.js.map +1 -0
- package/dist/src/wgsl/radix-hist.wgsl.d.ts +9 -0
- package/dist/src/wgsl/radix-hist.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/radix-hist.wgsl.js +31 -0
- package/dist/src/wgsl/radix-hist.wgsl.js.map +1 -0
- package/dist/src/wgsl/radix-scatter.wgsl.d.ts +9 -0
- package/dist/src/wgsl/radix-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/radix-scatter.wgsl.js +40 -0
- package/dist/src/wgsl/radix-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/scan-add.wgsl.d.ts +6 -0
- package/dist/src/wgsl/scan-add.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/scan-add.wgsl.js +14 -0
- package/dist/src/wgsl/scan-add.wgsl.js.map +1 -0
- package/dist/src/wgsl/scan-block.wgsl.d.ts +8 -0
- package/dist/src/wgsl/scan-block.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/scan-block.wgsl.js +30 -0
- package/dist/src/wgsl/scan-block.wgsl.js.map +1 -0
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +22 -8
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/segmented-reduce.wgsl.js +84 -15
- package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -1
- package/dist/src/wgsl/spmv-pull.wgsl.d.ts +22 -11
- package/dist/src/wgsl/spmv-pull.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/spmv-pull.wgsl.js +110 -36
- package/dist/src/wgsl/spmv-pull.wgsl.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/webgpu-graph-algorithms.js +3815 -1003
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +5 -4
- package/src/algorithms/components.ts +12 -16
- package/src/algorithms/degree.ts +58 -43
- package/src/algorithms/pagerank.ts +20 -18
- package/src/algorithms/power-iteration.ts +19 -18
- package/src/constants.ts +38 -8
- package/src/errors.ts +3 -1
- package/src/index.ts +14 -4
- package/src/kernel/dispatch.ts +18 -7
- package/src/kernel/kernel.ts +59 -5
- package/src/kernel/prelude.ts +9 -0
- package/src/kernel/profiler.ts +28 -4
- package/src/kernels.ts +356 -18
- package/src/layouts/calibrate.ts +187 -0
- package/src/layouts/force-simulation.ts +91 -23
- package/src/layouts/forceatlas2.ts +331 -106
- package/src/layouts/fruchterman-reingold.ts +255 -74
- package/src/layouts/model-common.ts +98 -3
- package/src/layouts/repulsion-grid.ts +451 -0
- package/src/layouts/spring-electrical.ts +257 -78
- package/src/memory/residency.ts +126 -20
- package/src/primitives/core-shape.ts +91 -4
- package/src/primitives/grid-pyramid.ts +221 -0
- package/src/primitives/grid.ts +349 -0
- package/src/primitives/histogram.ts +273 -0
- package/src/primitives/radix-sort.ts +246 -0
- package/src/primitives/scan.ts +197 -0
- package/src/primitives/segmented-reduce.ts +214 -56
- package/src/primitives/spmv.ts +125 -65
- package/src/primitives/verify.ts +249 -0
- package/src/types/context.ts +56 -0
- package/src/types/layout.ts +22 -0
- package/src/wgsl/counting-scatter.wgsl.ts +16 -0
- package/src/wgsl/fa2-attraction.wgsl.ts +98 -20
- package/src/wgsl/fa2-stats-finalize.wgsl.ts +22 -1
- package/src/wgsl/grid-cell-key.wgsl.ts +29 -0
- package/src/wgsl/grid-centroid-hub.wgsl.ts +28 -0
- package/src/wgsl/grid-centroid.wgsl.ts +28 -0
- package/src/wgsl/grid-downsample.wgsl.ts +27 -0
- package/src/wgsl/grid-far-field.wgsl.ts +97 -0
- package/src/wgsl/grid-near-field.wgsl.ts +128 -0
- package/src/wgsl/histogram.wgsl.ts +14 -0
- package/src/wgsl/indirect-finalize.wgsl.ts +25 -0
- package/src/wgsl/radix-hist.wgsl.ts +30 -0
- package/src/wgsl/radix-scatter.wgsl.ts +39 -0
- package/src/wgsl/scan-add.wgsl.ts +13 -0
- package/src/wgsl/scan-block.wgsl.ts +29 -0
- package/src/wgsl/segmented-reduce.wgsl.ts +84 -15
- package/src/wgsl/spmv-pull.wgsl.ts +110 -36
- package/dist/chunks/context-BR7fx3vR.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webgpu-graph-algorithms.js","sources":["../src/kernel/dispatch.ts","../src/kernel/struct-block.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/pr-finalize.wgsl.ts","../src/wgsl/pr-scale.wgsl.ts","../src/wgsl/reduce.wgsl.ts","../src/wgsl/segmented-reduce.wgsl.ts","../src/wgsl/spmv-pull.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/algorithms/degree.ts","../src/kernel/batch.ts","../src/kernel/uniform-ring.ts","../src/algorithms/scope.ts","../src/algorithms/components.ts","../src/primitives/core-shape.ts","../src/primitives/segmented-reduce.ts","../src/primitives/spmv.ts","../src/algorithms/pagerank.ts","../src/algorithms/power-iteration.ts","../src/algorithms/spectral.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/layouts/forceatlas2.ts","../src/layouts/fruchterman-reingold.ts","../src/layouts/spring-electrical.ts","../src/accelerator.ts"],"sourcesContent":["/**\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). */\nexport interface DispatchPlan {\n readonly x: number;\n readonly y: number;\n readonly z: 1;\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 a device-side finalize kernel writes for a count. P1-P3: throws E_UNSUPPORTED { feature: \"planIndirect\" } (lead f).\n * @param count - the device-side count\n * @param wg - the workgroup size\n * @param caps - the capability table\n */\nexport function planIndirect(count: number, wg: number, caps: PlanCaps): DispatchPlan {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"planIndirect lands with the indirect dispatch of P4 (spec 5.4)\", {\n feature: \"planIndirect\",\n hint: `count ${count}, wg ${wg}, limit ${perDimension(caps)}`,\n });\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 `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 thread-per-row gather of the\n * attraction force over the undirected CSR rows (both arcs present, so the sum is symmetric with no atomics), the\n * linear or linlog law, the optional weights, the distributed-action division by the mass in `pos.w`, written as\n * the FIRST writer of `force` each iteration. P3 ships the thread-per-row tier over `[tierStart, tierEnd)` = `[0, n)`\n * with `USE_PERM = false`; the subgroup / workgroup tiers arrive with P4 (`TIER`). `LAW` (P5, spec 7.20) picks the\n * pair law: 0 = the FA2 text, 1 = Fruchterman-Reingold `d^2 / k` (unfloored), 2 = ngraph's Hooke spring\n * `k_s (d - L)`; under 1 / 2 the models compile `LINLOG = false` and `HAS_WEIGHTS = false`, and the law overwrites\n * `w` so weights are ignored either way.\n *\n * Body only (spec 3.5, D9); normative text (contract 4.5); the K2 sabotage mutations (P3-T5) are textual edits of it.\n */\n\n/** The K2 body: entry point `attraction`; an early return is legal here because no barrier follows (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}\n\n@compute @workgroup_size(WG)\nfn attraction(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let row = linear_id(wid, lid.x) + P.tierStart;\n if (row >= P.tierEnd) { return; } // no barrier follows in this tier (3.5 rule 1)\n let i = select(row, perm[row], USE_PERM);\n let pi = pos[i]; // xyz + mass in one load (D23)\n var f = vec3f(0.0);\n for (var a = rowPtr[i]; a < rowPtr[i + 1u]; a = a + 1u) {\n let j = colIdx[a];\n if (j == i) { continue; } // a self-loop exerts no force\n var w = 1.0;\n if (HAS_WEIGHTS) { w = weights[a]; }\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 if (DISTRIBUTED) { f = f / pi.w; }\n store_force(i, f); // overwrites: attraction is the first writer of force each iteration\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 */\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(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\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 for (var t = 0u; t < tiles; 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 // 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.\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 <= P.settleThreshold * S.rmsRadius);\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 (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 `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 `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 `segmented-reduce` kernel body (spec 6 row 3; contract 4.5), TIER 0 = thread-per-row: one invocation per row\n * of [P.start, P.end) folds the VALUE snippet over the row's arcs inside the bound window [P.arcBase, P.arcEnd) and\n * writes out[i] as f32; a row with no arcs gets the identity element (0 for sum, F32_MAX for min, -F32_MAX for\n * max). The mid / high degree tiers (TIER 1 / 2 over degreeOrder()) land at P4. The body is normative: a sabotage\n * mutation (test/helpers/sabotage.ts) is a textual edit of it, so it is not restyled.\n */\n\n/**\n * Entry point `segmented_reduce`; overrides OP (0 sum, 1 min, 2 max) and TIER (0); snippet slot VALUE: statements\n * assigning `v` from `row`, `arc`, `nbr`, `weight` (`target` 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; }\n\n@compute @workgroup_size(WG)\nfn segmented_reduce(@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 acc = identity();\n for (var arc = a0; arc < a1; arc = arc + 1u) {\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 out[i] = select(acc, comb(out[i], acc), P.accumulate == 1u);\n}\n`;\n","/**\n * The `spmv-pull` kernel body (spec 6 row 9, 8.2; PD-1 of the M8b plan): one invocation per row of the REVERSE\n * adjacency, grid-stride over `[0, P.n)`, folding `weight * xNorm[nbr]` over the row's in-arcs in chunks of 64\n * terms (a two-level f32 sum: the chunk absorbs the rounding of 64 terms, the row total the rounding of the chunk\n * count, so a 10,000-arc hub row loses about 200 rounding steps instead of 10,000; Kahan compensation is not used\n * because Metal's shader compiler folds `((acc + term) - acc) - term` to zero whatever hides it) and writing\n * `rankOut[v] = beta * pv + alpha * (sum + danglingMass * pv)`, where `pv` is `personalization[v]` when\n * HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise. PageRank sets alpha to the\n * damping factor, beta to `1 - alpha` and USE_DANGLING; HITS and eigenvector set alpha 1, beta 0, uniformP 0; Katz\n * sets alpha to the attenuation, beta to its constant and uniformP 1. 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\n/** Entry point `spmv_pull`; overrides HAS_PERSONALIZATION and USE_DANGLING plus the standard USE_PERM / HAS_WEIGHTS. */\nexport const spmvPullWgsl = /* wgsl */ `\n@compute @workgroup_size(WG)\nfn spmv_pull(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n var dangling = 0.0;\n if (USE_DANGLING) { dangling = partials[0].danglingMass; }\n let first = linear_id(wid, lid.x);\n for (var row = first; row < P.n; row = row + P.stride) {\n let v = select(row, perm[row], USE_PERM);\n let a0 = max(rowPtr[v], P.arcBase);\n let a1 = min(rowPtr[v + 1u], P.arcEnd);\n var acc = 0.0;\n var chunk = 0.0;\n var inChunk = 0u;\n for (var arc = a0; arc < a1; arc = arc + 1u) {\n let nbr = colIdx[arc - P.arcBase]; // \\`target\\` is a WGSL reserved word (spec 16.2)\n var weight = 1.0;\n if (HAS_WEIGHTS) { weight = weights[arc - P.arcBase]; }\n // two-level sum: 64 terms into chunk, chunk into acc (see the header; no compensation, no select)\n chunk = chunk + (weight * xNorm[nbr]);\n inChunk = inChunk + 1u;\n if (inChunk == 64u) {\n acc = acc + chunk;\n chunk = 0.0;\n inChunk = 0u;\n }\n }\n acc = acc + chunk;\n var pv = P.uniformP;\n if (HAS_PERSONALIZATION) { pv = personalization[v]; }\n rankOut[v] = (P.beta * pv) + (P.alpha * (acc + (dangling * pv)));\n }\n}\n`;\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. 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 { 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 { prFinalizeWgsl } from \"./wgsl/pr-finalize.wgsl.js\";\nimport { prScaleWgsl } from \"./wgsl/pr-scale.wgsl.js\";\nimport { reduceWgsl } from \"./wgsl/reduce.wgsl.js\";\nimport { segmentedReduceWgsl } from \"./wgsl/segmented-reduce.wgsl.js\";\nimport { spmvPullWgsl } from \"./wgsl/spmv-pull.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-P3 and P7 (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\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\" | \"P7\";\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, 128 B; spec 7.3): the per-iteration ForceAtlas2 parameters -- `n` @0, `dim` @4, `flags` @8 (bit 0 = FA2_FLAG_FIRST), `tierStart` @12, `tierEnd` @16, `iterationIndex` @20, `seed` @24, `nearMax` @28, `scalingRatio` @32, `gravity` @36, `jitterTolerance` @40, `scale` @44, `center` @48 (xyz, w 0), `settleThreshold` @64, `extentFactor` @68, `gridMax` @72, `levels` @76, `pad` @80 (reserved for the P4 GridSpec); 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, `pad1` @124; 128 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 [\"pad\", \"vec4f\"],\n [\"frK\", \"f32\"],\n [\"temperature\", \"f32\"],\n [\"springLength\", \"f32\"],\n [\"springCoefficient\", \"f32\"],\n [\"coulomb\", \"f32\"],\n [\"dragCoefficient\", \"f32\"],\n [\"timeStep\", \"f32\"],\n [\"pad1\", \"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), `reserved0` @120 (vec2f), `reserved1` .. `reserved8` @128 .. @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 [\"reserved1\", \"vec4f\"],\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), `pad0` @28. */\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 [\"pad0\", \"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// ---- 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; the degreeOrder tiers land at P4) plus the standard USE_PERM / HAS_WEIGHTS; 5 storage bindings; one snippet slot. */\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: [],\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); 3 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(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 thread-per-row attraction gather over the CSR rows (the first writer of `force` each iteration); LINLOG / DISTRIBUTED / TIER 0 plus the standard USE_PERM / HAS_WEIGHTS; LAW 0 FA2 / 1 FR / 2 spring (P5); 6 storage bindings. */\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: [],\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 grid-stride pull SpMV over the reverse adjacency; HAS_PERSONALIZATION / USE_DANGLING plus the standard USE_PERM / HAS_WEIGHTS; 8 storage bindings (the design's count). */\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 ],\n uniforms: [SPMV_PARAMS, PR_PARTIAL],\n needs: [],\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/**\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, so every member of `KernelId` is present and the\n * 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});\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 * `degree(ctx, s)` -- the walking-skeleton algorithm, kept public as a diagnostic (spec 3.3, 11.5): the out-degree of\n * every node computed on the device by the row-walking `degree` kernel (4.5) over the resident core of the snapshot,\n * with the group-0 dummy-binding pattern of spec 3.5 (`colIdx` in the `weights` slot when the snapshot is unweighted,\n * `rowPtr` in the `perm` slot because P1-P3 pass no row permutation, so `USE_PERM` is false). The result equals\n * `snapshot.outDegree()`; the point of the kernel is to prove the upload, bind, dispatch and readback path end to end\n * on every adapter (bitwise identical across adapters, spec 11.5), not to be faster than the CPU (the README says\n * so).\n *\n * Contract (3.12): `ctx.assertReady()` first; `nodeCount === 0` returns an empty `Uint32Array` (or `dest`) with no\n * GPU work (spec 5.6: there is no work, which is not a fallback); an already-aborted `signal` is `E_ABORTED` before\n * any work; `dest` must be a `Uint32Array` of length n over an `ArrayBuffer`; a windowed core is `E_TOO_LARGE\n * { path: \"windowed\", algorithm: \"degree\" }` until P4 executes windows -- `residency.core()` (3.8) throws that error\n * itself with `algorithm: null` before it would ever return a windowed `CoreBinding`, so `degree` catches it and\n * re-throws the same error with `algorithm: \"degree\"` (the 3.12 detail) instead of testing `core.plan`, which never\n * observes \"windowed\" in P1-P3; `arcCount === 0` skips the dispatch (only `rowPtr` is resident)\n * and the result is zeros; otherwise ONE dispatch over rows [0, n) with `accumulate = 0` (every row is written, so no\n * fill precedes it), a readback into the result, `onProgress(1, 1)`, and the scratch returned in a finally. Two runs\n * are bitwise identical (spec 11.9 item 4).\n */\n\nimport { type GraphSnapshot, type U32 } from \"@graphty/graph-format\";\n\nimport { type GpuContext } from \"../context.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { isWebGpuGraphError, WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { graphBindings, graphOverrides, kernelSpec, RANGE_PARAMS } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\n\n/**\n * Validates `options.dest` for a 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 `degree: 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 * Uploads (or finds) the core through the residency; a windowed plan, which the residency reports as `E_TOO_LARGE\n * { path: \"windowed\", algorithm: null }` (3.8), is re-thrown with `algorithm: \"degree\"` (3.12) and its other details\n * (`needed`, `limit`, `path`) kept. Every other error passes through untouched.\n * @param ctx - the context whose residency holds the core\n * @param s - the snapshot\n * @returns the resident core binding (arena or perArray)\n */\nfunction coreOf(ctx: GpuContext, s: GraphSnapshot): CoreBinding {\n try {\n return ctx.residency.core(s);\n } catch (error: unknown) {\n if (isWebGpuGraphError(error) && error.code === \"E_TOO_LARGE\" && error.details.path === \"windowed\") {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n \"degree: the arc arrays need a windowed upload, which P1-P3 plan but do not execute\",\n { ...error.details, algorithm: \"degree\" },\n );\n }\n throw error;\n }\n}\n\n/**\n * The walking-skeleton kernel, kept public as a diagnostic (spec 3.3): out-degree per node through the row-walking\n * gather with the USE_PERM dummy pattern; equals snapshot.outDegree().\n * @param ctx - the context whose device runs the kernel\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - dest / signal / onProgress (spec 3.3). PLAN DECISION: spelled `?: GpuRunOptions` rather than the\n * contract's `?: GpuRunOptions | undefined` because the root ESLint rule no-duplicate-type-constituents rejects the\n * explicit undefined on an optional parameter (the call signature is identical; P1-T3 made the same choice).\n * @returns the out-degree of every node, index-aligned (`dest` itself when given)\n */\nexport async function degree(ctx: GpuContext, s: GraphSnapshot, options?: GpuRunOptions): Promise<U32> {\n ctx.assertReady();\n const n = s.nodeCount;\n const dest = checkDest(options?.dest, n);\n if (options?.signal?.aborted) {\n throw new WebGpuGraphError(\"E_ABORTED\", \"degree: the signal was aborted before any work started\", {});\n }\n if (n === 0) {\n options?.onProgress?.(1, 1);\n return dest ?? new Uint32Array(0);\n }\n const core = coreOf(ctx, s);\n if (s.arcCount === 0) {\n const zeros = dest ?? new Uint32Array(n);\n zeros.fill(0);\n options?.onProgress?.(1, 1);\n return zeros;\n }\n const byteLength = n * 4;\n const out = ctx.pool.acquire(\n byteLength,\n BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST,\n \"degree/out\",\n );\n const params = ctx.pool.acquire(\n RANGE_PARAMS.byteLength,\n BufferUsage.UNIFORM | BufferUsage.COPY_DST,\n \"degree/params\",\n );\n try {\n await ctx.allocator.check();\n const kernel = await ctx.pipelines.kernel(kernelSpec(\"degree\", graphOverrides(core, null)));\n const bytes = new ArrayBuffer(RANGE_PARAMS.byteLength);\n RANGE_PARAMS.write(new DataView(bytes), { start: 0, end: n, arcBase: 0, arcEnd: s.arcCount, accumulate: 0, n });\n ctx.device.queue.writeBuffer(params, 0, bytes);\n const outBinding: Binding = { buffer: out, offset: 0, size: byteLength, window: null };\n const paramsBinding: Binding = { buffer: params, offset: 0, size: RANGE_PARAMS.byteLength, window: null };\n const bound = kernel.bind({ ...graphBindings(core, null), out: outBinding, P: paramsBinding });\n const encoder = ctx.device.createCommandEncoder({ label: \"degree\" });\n const pass = encoder.beginComputePass({ label: \"degree\" });\n kernel.dispatch(pass, bound, plan1d(n, ctx.workgroupSize, ctx.caps), [0]);\n pass.end();\n ctx.device.queue.submit([encoder.finish()]);\n ctx.assertReady();\n const result = await ctx.readback.read(out, byteLength, dest ?? undefined);\n ctx.assertReady();\n options?.onProgress?.(1, 1);\n return dest ?? new Uint32Array(result);\n } finally {\n ctx.pool.release(params);\n ctx.pool.release(out);\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 * 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 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.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 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 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.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 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. */\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}\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 };\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 { isWebGpuGraphError, 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 { 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 (`E_TOO_LARGE { path: \"windowed\", algorithm: null }`, spec 3.8) is re-thrown\n * with the algorithm name (3.12). Transcribed from degree.ts, whose coreOf is module-private.\n * @param ctx - the context\n * @param s - the snapshot\n * @returns the core binding\n */\nfunction coreOf(ctx: GpuContext, s: GraphSnapshot): CoreBinding {\n try {\n return ctx.residency.core(s);\n } catch (error: unknown) {\n if (isWebGpuGraphError(error) && error.code === \"E_TOO_LARGE\" && error.details.path === \"windowed\") {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${ALGORITHM}: the arc arrays need a windowed upload, which P1-P3 plan but do not execute`,\n { ...error.details, algorithm: ALGORITHM },\n );\n }\n throw error;\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 * 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).\n * @param labels - the labels\n * @param count - the block count\n * @returns the result\n */\nfunction 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 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`, { batchId: submitted.id });\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 shape helpers every core-walking primitive shares (spec 4.1): the row count and the arc count a CoreBinding\n * implies, the windowed rejection of P4, 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 Binding } from \"../types/memory.js\";\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 * Rejects a windowed core (executed at P4).\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 executed at P4`, {\n feature: `${primitive}.windowed`,\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).\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 const colIdx = v.bindings.colIdx ?? null;\n const weights = v.bindings.weights ?? null;\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 hasWeights: weights !== null,\n });\n}\n","/**\n * The segmented (per-row) reduction primitive of spec 6 row 3 in its thread-per-row tier (P2-P3): one invocation per\n * CSR row folds the caller's VALUE snippet over the row's arcs into `out[row]` (f32), a row with no arcs receiving\n * the identity element. The degree tiers of degreeOrder() (subgroup-per-row for the mid tier, workgroup-per-row for\n * the high tier) land at P4; until then `tiers !== null` is E_UNSUPPORTED and USE_PERM is always false (the perm\n * slot carries the rowPtr dummy of graphBindings). The row and arc counts come from the core's binding sizes: the\n * residency binds every array at its exact byte length (contract 3.8), so rowPtr is 4(n + 1) bytes and colIdx\n * 4 x arcCount.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type Kernel } from \"../kernel/kernel.js\";\nimport { graphBindings, graphOverrides, kernelSpec, RANGE_PARAMS } from \"../kernels.js\";\nimport { type CoreBinding } from \"../memory/residency.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { assertNotWindowed, rowCountOf } from \"./core-shape.js\";\nimport { type ReduceOp, type ReduceScope } from \"./reduce.js\";\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/** 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 (P2-P3: the thread-per-row tier only; `tiers !== null` -> E_UNSUPPORTED { feature: \"segmentedReduce.tiers\" } until P4). */\nexport interface SegmentedReducePlanner {\n /** Records one dispatch over rows [0, n) (tiers null) 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}\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/** The thread-per-row planner: ONE `segmented-reduce` dispatch with TIER 0 over every row. */\nclass ThreadPerRowPlanner implements SegmentedReducePlanner {\n private readonly scope: ReduceScope;\n private readonly kernel: Kernel;\n private readonly hasWeights: boolean;\n private readonly accumulate: boolean;\n\n /**\n * Wraps a compiled thread-per-row pipeline with the pattern it was compiled for.\n * @param scope - the scope the pipeline was prepared in\n * @param kernel - the compiled kernel\n * @param hasWeights - the HAS_WEIGHTS the pipeline was compiled with\n * @param accumulate - whether record() combines into out instead of overwriting\n */\n constructor(scope: ReduceScope, kernel: Kernel, hasWeights: boolean, accumulate: boolean) {\n this.scope = scope;\n this.kernel = kernel;\n this.hasWeights = hasWeights;\n this.accumulate = accumulate;\n }\n\n /**\n * Records the dispatch: rows [0, n), arcs [0, arcCount), plan1d(n); nothing for n = 0 (no zero-length binding is\n * ever created).\n * @param pass - the pass to record into\n * @param core - a core with the SAME weights pattern as the one prepared (any snapshot)\n * @param out - at least 4n bytes of f32\n */\n record(pass: GPUComputePassEncoder, core: CoreBinding, out: Binding): void {\n assertNotWindowed(core, \"segmentedReduce\");\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 (n === 0) {\n return;\n }\n const arcCount = core.colIdx === null ? 0 : core.colIdx.size / 4;\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 const params = this.scope.params(RANGE_PARAMS, {\n start: 0,\n end: n,\n arcBase: 0,\n arcEnd: arcCount,\n accumulate: this.accumulate ? 1 : 0,\n n,\n });\n const bound = this.kernel.bind({ ...graphBindings(core, null), out, P: params.binding });\n this.kernel.dispatch(pass, bound, plan1d(n, this.scope.workgroupSize, this.scope.caps), [params.offset]);\n }\n}\n\n/**\n * Prepares the thread-per-row pipeline for a snapshot's dummy pattern (USE_PERM, HAS_WEIGHTS) and snippet.\n * @param scope - the reduce scope (pipelines, pool, params writer)\n * @param core - the core whose weights pattern selects HAS_WEIGHTS (USE_PERM is false: no tiers at P2)\n * @param options - operator, snippet, tiers (must be null), accumulate\n * @returns the planner\n */\nexport async function prepareSegmentedReduce(\n scope: ReduceScope,\n core: CoreBinding,\n options: SegmentedReduceOptions,\n): Promise<SegmentedReducePlanner> {\n if (options.tiers !== null) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"segmentedReduce: the degree tiers land at P4; pass tiers: null\", {\n feature: \"segmentedReduce.tiers\",\n });\n }\n assertNotWindowed(core, \"segmentedReduce\");\n const op = opCode(options.op);\n validateValueSnippet(options.valueSnippet);\n const overrides = { ...graphOverrides(core, null), OP: op, TIER: 0 };\n const spec = kernelSpec(\"segmented-reduce\", overrides, { VALUE: options.valueSnippet });\n const kernel = await scope.pipelines.kernel(spec);\n return new ThreadPerRowPlanner(scope, kernel, core.weights !== null, options.accumulate === true);\n}\n","/**\n * The pull SpMV primitive of spec 6 row 9 / 8.2 in its thread-per-row tier (P7; M8b plan PD-1 / PD-2): one\n * grid-stride dispatch of the `spmv-pull` module over the rows of a REVERSE adjacency, each invocation folding\n * `weight * xNorm[nbr]` over its row's in-arcs (Kahan-compensated, f32) 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. The in-degree tiers of `reverseDegreeOrder()` land at P4 (PD-2): `tiers !== null` is\n * E_UNSUPPORTED and USE_PERM is always false (the perm slot carries the rowPtr dummy of graphBindings). The row and\n * arc counts come from the core's binding sizes exactly as segmentedReduce derives them.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { 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, rowCountOf } from \"./core-shape.js\";\nimport { type ReduceScope } from \"./reduce.js\";\nimport { type DegreeTiers } from \"./segmented-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 tiers (must be null at P7). */\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 over the rows of a reverse core into a pass. */\nexport interface SpmvPullPlanner {\n /** Records the dispatch over rows [0, n) of `rev` writing rankOut[v] (f32) per row; nothing for n = 0. */\n record(pass: GPUComputePassEncoder, rev: CoreBinding, resources: SpmvResources, coefficients: SpmvCoefficients): void;\n /** Dispatches the last record() issued (1, or 0 for n = 0). */\n readonly lastDispatches: number;\n}\n\n/** The thread-per-row planner: ONE `spmv-pull` dispatch, grid-stride over every row. */\nclass SpmvPullPlannerImpl implements SpmvPullPlanner {\n private readonly scope: ReduceScope;\n private readonly kernel: Kernel;\n private readonly weights: Binding | null | undefined;\n private dispatches = 0;\n\n /**\n * Wraps a compiled pipeline with the weights choice it was compiled for.\n * @param scope - the scope the pipeline was prepared in\n * @param kernel - the compiled kernel\n * @param weights - the weights option the pipeline's HAS_WEIGHTS was derived from; record() binds the same way\n */\n constructor(scope: ReduceScope, kernel: Kernel, weights: Binding | null | undefined) {\n this.scope = scope;\n this.kernel = kernel;\n this.weights = weights;\n }\n\n /**\n * Dispatches the last record() issued.\n * @returns 1, or 0 when the last record covered no rows\n */\n get lastDispatches(): number {\n return this.dispatches;\n }\n\n /**\n * Records the dispatch: rows [0, n), arcs [0, arcCount), planGridStride(n); nothing for n = 0 (no zero-length\n * binding is ever created). `personalization ?? xNorm` follows the group-0 dummy rule: both slots are\n * storage-ro, so the 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)\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 plan = planGridStride(n, this.scope.workgroupSize, this.scope.caps);\n if (plan.x === 0) {\n this.dispatches = 0;\n return;\n }\n const params = this.scope.params(SPMV_PARAMS, {\n n,\n arcBase: 0,\n arcEnd: arcCountOf(rev),\n stride: plan.stride ?? n,\n alpha: coefficients.alpha,\n beta: coefficients.beta,\n uniformP: coefficients.uniformP,\n pad0: 0,\n });\n const bound = this.kernel.bind({\n ...graphBindings(rev, null, 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 this.kernel.dispatch(pass, bound, plan, [params.offset]);\n this.dispatches = 1;\n }\n}\n\n/**\n * Prepares the thread-per-row pull pipeline for a reverse core's weights pattern and the two variant flags.\n * @param scope - the reduce scope (pipelines, params writer)\n * @param rev - the reverse core whose weights pattern selects HAS_WEIGHTS (USE_PERM is false: no tiers at P7)\n * @param options - personalization, dangling, weights, tiers (must be null)\n * @returns the planner\n */\nexport async function prepareSpmvPull(\n scope: ReduceScope,\n rev: CoreBinding,\n options: SpmvPullOptions,\n): Promise<SpmvPullPlanner> {\n if (options.tiers !== null) {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"spmvPull: the in-degree tiers land at P4; pass tiers: null\", {\n feature: \"spmvPull.tiers\",\n });\n }\n assertNotWindowed(rev, \"spmvPull\");\n const spec = kernelSpec(\"spmv-pull\", {\n ...graphOverrides(rev, null, options.weights),\n HAS_PERSONALIZATION: options.personalization,\n USE_DANGLING: options.dangling,\n });\n const kernel = await scope.pipelines.kernel(spec);\n return new SpmvPullPlannerImpl(scope, kernel, options.weights);\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 { isWebGpuGraphError, 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 { coreOfView } from \"../primitives/core-shape.js\";\nimport { prepareSegmentedReduce } from \"../primitives/segmented-reduce.js\";\nimport { prepareSpmvPull } from \"../primitives/spmv.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; a smaller ring wraps onto a slot the same batch still reads. */\nconst RING_SLOTS = 2 * PR_BATCH + 1;\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 (`E_TOO_LARGE { path: \"windowed\", algorithm: null }`, spec 3.8) is re-thrown\n * with the algorithm name (3.12). Transcribed from degree.ts, whose coreOf is module-private.\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 try {\n return ctx.residency.core(s);\n } catch (error: unknown) {\n if (isWebGpuGraphError(error) && error.code === \"E_TOO_LARGE\" && error.details.path === \"windowed\") {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${algorithm}: the arc arrays need a windowed upload, which P1-P3 plan but do not execute`,\n { ...error.details, algorithm },\n );\n }\n throw error;\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 * 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 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 { scores: dest ?? new Float32Array(0), iterations: 0, converged: true, danglingMass: 0, precision: \"f32\" };\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 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 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 const pass = batch.pass(\"iterations\");\n if (iterationsRun === 0) {\n normaliser.record(pass, weightedCore, outWeightSumBinding);\n }\n for (let i = 0; i < k; 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 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 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 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: folded.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(`${personalization.constructor.name}(${personalization.length})`, `a Float32Array of length ${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 * 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 { isWebGpuGraphError, 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 { coreOfView } from \"../primitives/core-shape.js\";\nimport { prepareSpmvPull } from \"../primitives/spmv.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`). */\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 (`E_TOO_LARGE { path: \"windowed\", algorithm: null }`, spec 3.8) is re-thrown\n * with the algorithm name (3.12). Transcribed from degree.ts, whose coreOf is module-private.\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 try {\n return ctx.residency.core(s);\n } catch (error: unknown) {\n if (isWebGpuGraphError(error) && error.code === \"E_TOO_LARGE\" && error.details.path === \"windowed\") {\n throw new WebGpuGraphError(\n \"E_TOO_LARGE\",\n `${algorithm}: the arc arrays need a windowed upload, which P1-P3 plan but do not execute`,\n { ...error.details, algorithm },\n );\n }\n throw error;\n }\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 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 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 for (let i = 0; i < k; 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 = { rankIn, rankPrev: rankOut, outWeightSum: rankIn, xNorm, partials, P: params.binding };\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 (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: 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 * 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 * 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]. 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 }\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 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 ArrayBinding, type CoreBinding } from \"../memory/residency.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 readonly perm: Binding | 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 /** 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}\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 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).\n * @param tuning - the resolved tuning\n * @param n - the node count\n * @returns \"exact\" or \"grid\"\n */\nfunction 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 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 (\"exact\" until P4 lifts the grid tier).\n * @returns the tier\n */\n get tier(): \"exact\" | \"grid\" {\n return this.tierValue;\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 if (tier === \"grid\") {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n `the grid repulsion tier lands at P4 (n = ${n}, exactMaxNodes = ${this.tuning.exactMaxNodes})`,\n {\n feature: \"repulsion.grid\",\n hint: 'pass repulsion: \"exact\" or raise exactMaxNodes',\n },\n );\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 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 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 = { ...this.model.overrides(this.optionsValue), ...graphOverrides(core, null, weights) };\n const resources = this.makeResources(core, 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 = { ...this.model.overrides(next), ...graphOverrides(core, null, resources.weights) };\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, else wall time.\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 if (timings.length > 0) {\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 weights - the resolved weights binding\n * @param buffers - the buffers\n * @returns the resources\n */\n private makeResources(core: CoreBinding, weights: Binding | null, buffers: SimulationBuffers): 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: null,\n weights,\n n: this.n,\n dim: this.dimValue,\n tier: this.tierValue,\n ring: this.ring,\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 * warm(model.specs()) then model.bind(); the await re-checks that the load is current before binding.\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 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 \"fixed\" and \"trace\", 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 name === \"fixed\" || name === \"trace\" ? 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 });\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 (PD-7): moved verbatim from\n * src/layouts/forceatlas2.ts (P3-T2) so the Fruchterman-Reingold and spring-electrical models of P5 neither copy\n * them nor import a sibling model. Layout zone; imports errors.ts only.\n */\n\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { type UniformValues } from \"../kernel/struct-block.js\";\n\n/** An override record as the kernel layer takes it. */\nexport type Overrides = Readonly<Record<string, number | boolean>>;\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 { 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/** 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 this.repulsion.dispatch(pass, bound, plan, [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 * 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 thread-per-row tier over [0, n) with USE_PERM false (P3, spec 7.5).\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; the K1-K5 dispatches of every iteration of one batch share ONE compute pass (opened by the\n * batch's first recordIteration and remembered by batch id) and toScene runs in a second pass that ends it (contract\n * 4.4); the fill kernel takes its FillParams from a model-owned 256-byte uniform buffer (\"fillParams\"); the first\n * iteration after every load() zeroes oldForce with a fill (paper mode); `repulsion: \"grid\"` is E_UNSUPPORTED at\n * load() for any n and `\"auto\"` above exactMaxNodes.\n */\n\nimport { type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport {\n FA2_DEFAULTS,\n LAYOUT_TUNING_DEFAULTS,\n MAX_ITERATIONS_PER_STEP,\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, graphBindings, kernelSpec } from \"../kernels.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} from \"./force-simulation.js\";\nimport { resolveNodeMass, resolveWeights } from \"./inputs.js\";\nimport {\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 scalar,\n seedWord,\n subset,\n vector,\n} from \"./model-common.js\";\nimport { RepulsionExact, type RepulsionExactOverrides } from \"./repulsion-exact.js\";\n\n// ============================================================ constants and small helpers\n\n/** The stage names of one iteration in dispatch order plus the per-batch toScene (spec 7.4; contract 3.13). */\nconst FA2_STAGES = [\"K1\", \"K2\", \"K3\", \"K4\", \"K5\", \"toScene\"] as const;\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// ============================================================ 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); the grid knobs are validated and stored but only `repulsion`,\n * `exactMaxNodes`, `deterministic` and `compat` have an effect in P3 (contract 3.3).\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(\"nearMax\", t.nearMax, LAYOUT_TUNING_DEFAULTS.nearMax, isPositiveInteger, \"an integer >= 1\"),\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 readonly k2: Kernel;\n /** null when arcCount === 0 (K2 is not recorded; the fill below zeroes force instead, spec 7.5). */\n readonly k2Bound: BoundKernel | null;\n readonly repulsion: RepulsionExact;\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; toScene once per batch). Stages: [\"K1\", \"K2\", \"K3\", \"K4\", \"K5\", \"toScene\"]. */\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: readonly [\"K1\", \"K2\", \"K3\", \"K4\", \"K5\", \"toScene\"] = 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 /**\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), plus the 256-byte FillParams uniform buffer the fill dispatches read. n = 0\n * reports one node's worth of bytes so no zero-length buffer 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)\n * @returns the three 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 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 ];\n }\n\n /**\n * { mass: resolveNodeMass(s, resolved.nodeMass), weights: resolveWeights(s, resolved.weight) } (3.13 inputs.ts),\n * after the tier rule of spec 7.8 / lead f: `repulsion: \"grid\"` is E_UNSUPPORTED { feature: \"repulsion.grid\" }\n * for any n and `\"auto\"` when n > exactMaxNodes (the grid tier lands in P4); `\"exact\"` always runs.\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 { repulsion, exactMaxNodes } = this.tuning;\n const n = s.nodeCount;\n if (repulsion === \"grid\" || (repulsion === \"auto\" && n > exactMaxNodes)) {\n throw new WebGpuGraphError(\n \"E_UNSUPPORTED\",\n repulsion === \"grid\"\n ? 'repulsion: \"grid\" is not available yet (the grid tier lands in P4)'\n : `the graph has ${n} nodes, above exactMaxNodes ${exactMaxNodes}, and the grid tier lands in P4`,\n {\n feature: \"repulsion.grid\",\n hint: 'pass repulsion: \"exact\" (or raise exactMaxNodes) to run the exact tier at this size',\n },\n );\n }\n return { mass: resolveNodeMass(s, resolved.nodeMass), weights: resolveWeights(s, resolved.weight) };\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 * @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 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 ];\n }\n\n /**\n * Compiles (through the cache) and binds every kernel against the buffers of this load(): K1, K2 (or the fill of\n * force when arcCount === 0), K3 + K4 through RepulsionExact, K5, toScene, and the fill of oldForce; writes the\n * FillParams { count: 3n, value: 0, mode: 0 } into the model's uniform buffer. With n === 0 nothing is bound.\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, perm, ring, device } = resources;\n if (n === 0) {\n return;\n }\n const [k1, k2, k5, toScene, fill] = await Promise.all([\n pipelines.kernel(kernelSpec(\"fa2-stats-finalize\")),\n pipelines.kernel(kernelSpec(\"fa2-attraction\", subset(overrides, K2_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 repulsion = await RepulsionExact.create(pipelines, caps, repulsionOverrides(overrides));\n if (this.resources !== resources) {\n // a newer bind() superseded this one while the pipelines compiled; its own bind groups stand\n return;\n }\n const pos = resources.buffer(\"positions\");\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 force = resources.buffer(\"force\");\n const oldForce = resources.buffer(\"oldForce\");\n const fillParamsBuffer = resources.buffer(FILL_PARAMS_BUFFER);\n const params = ring.binding(FA2_PARAMS);\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 hasArcs = core.colIdx !== null;\n repulsion.bind({ pos, state, trace, force, oldForce, fixedMask: fixed, partials, params });\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 k1Bound: k1.bind({ partials, S: state, T: trace, P: params }),\n k2,\n k2Bound: hasArcs\n ? k2.bind({ ...graphBindings(core, perm, resources.weights), pos, force, P: params })\n : null,\n repulsion,\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 } = this.requireResources();\n const resolved = resolveForceAtlas2Options(options, this.current);\n const { nearMax, extentFactor } = this.tuning;\n return {\n n,\n dim: resolved.dim,\n flags: 0,\n tierStart: 0,\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: 0,\n levels: 0,\n pad: [0, 0, 0, 0],\n };\n }\n\n /**\n * Records one iteration into the batch: K1, K2 (or the fill of force when arcCount === 0), K3, K4, K5 in the\n * batch's ONE K1-K5 compute pass (opened by the first call of a batch and reused by every later call with the\n * same batch.id, PLAN DECISION 2), then toScene in a second pass that ends it, stopping after stage `upTo` when\n * given (spec 7.4; debugRunStages / inspect, spec 11.9 item 2). The simulation passes \"K5\" for iterations\n * 0..k-2 and undefined for the last, so toScene runs once per batch. The first call after load() zeroes\n * oldForce before K1 (paper mode). With n === 0 nothing is recorded (PLAN DECISION 9); a call before bind()\n * 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 - \"exact\" (the grid tier is E_UNSUPPORTED until P4; the simulation never passes \"grid\")\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 if (tier === \"grid\") {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"the grid repulsion tier lands in P4\", {\n feature: \"repulsion.grid\",\n hint: 'pass repulsion: \"exact\"',\n });\n }\n const resources = this.requireResources();\n const stop = upTo === undefined ? FA2_STAGES.length - 1 : 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 const pass = this.openPass !== null && this.openPass.id === batch.id ? this.openPass.pass : batch.pass(\"fa2\");\n this.openPass = { id: batch.id, pass };\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 if (stop < 1) {\n return;\n }\n if (bound.k2Bound !== null) {\n bound.k2.dispatch(pass, bound.k2Bound, bound.plan, [offset]);\n } else if (bound.fillForceBound !== null) {\n bound.fill.dispatch(pass, bound.fillForceBound, bound.fillPlan, [0]);\n }\n if (stop < 2) {\n return;\n }\n bound.repulsion.recordRepulsion(pass, bound.n, offset);\n if (stop < 3) {\n return;\n }\n bound.repulsion.recordSpeedFinalize(pass, offset);\n if (stop < 4) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < 5) {\n return;\n }\n // the second pass ends the K1-K5 pass; the batch is complete after toScene, so nothing reuses it\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.\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 }\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: the exact tier with null grid fields; 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 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: \"exact\",\n maxCellOccupancy: null,\n 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 * 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. Also forgets the pass\n * 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.k2, bound.k5, bound.toScene, bound.fill]) {\n kernel.invalidate();\n }\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 (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 repulsion tier with\n * the option defaults of spec 7.14 and the GPU-only tuning of GpuLayoutTuning (contract 3.13 \"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 repulsion tier (spec 7.20; contract 3.13): the ForceModel that ForceSimulation\n * drives -- the K1 K2 K3 K5 sequence per iteration and toScene per batch (no K4: no speed controller), the constant\n * override set (`LAW` 1 on K2 / K3, `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\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 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, graphBindings, kernelSpec } from \"../kernels.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} from \"./force-simulation.js\";\nimport { resolveLayoutTuning } from \"./forceatlas2.js\";\nimport {\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 scalar,\n seedWord,\n subset,\n vector,\n} from \"./model-common.js\";\n\n// ============================================================ constants\n\n/** The stage names of one iteration in dispatch order plus the per-batch toScene (spec 7.20: no K4). */\nconst FR_STAGES = [\"K1\", \"K2\", \"K3\", \"K5\", \"toScene\"] as const;\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/** 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 readonly k2: Kernel;\n /** null when arcCount === 0 (K2 is not recorded; the fill below zeroes force instead, spec 7.5). */\n readonly k2Bound: BoundKernel | null;\n readonly k3: Kernel;\n readonly k3Bound: BoundKernel;\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; toScene once per batch). Stages: [\"K1\", \"K2\", \"K3\", \"K5\", \"toScene\"]. */\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: readonly [\"K1\", \"K2\", \"K3\", \"K5\", \"toScene\"] = 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 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) plus the 256-byte FillParams uniform buffer the\n * fill dispatch reads. 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 force arrays are stride 3 in both)\n * @returns the three 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 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 ];\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). The tier rule is the simulation's (load() throws for the grid tier\n * before calling this).\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 return {\n mass: new Float32Array(s.nodeCount).fill(1),\n weights: { data: null, source: \"none\", column: null },\n fixed: resolveFixed(s, resolved.fixed),\n };\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 * @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 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 ];\n }\n\n /**\n * Compiles (through the cache) and binds every kernel against the buffers of this load(): K1, K2 (or the fill of\n * force when arcCount === 0), K3, K5, toScene; writes the FillParams { count: 3n, value: 0, mode: 0 } into the\n * model's uniform buffer. With n === 0 nothing is bound.\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, perm, ring, device } = resources;\n if (n === 0) {\n return;\n }\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 k2 = await pipelines.kernel(kernelSpec(\"fa2-attraction\", subset(overrides, K2_DEFAULTS)));\n const k3 = 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 if (this.resources !== resources) {\n // a newer bind() superseded this one while the pipelines compiled; its own bind groups stand\n return;\n }\n const pos = resources.buffer(\"positions\");\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 force = resources.buffer(\"force\");\n const oldForce = resources.buffer(\"oldForce\");\n const fillParamsBuffer = resources.buffer(FILL_PARAMS_BUFFER);\n const params = ring.binding(FA2_PARAMS);\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 hasArcs = core.colIdx !== null;\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 k1Bound: k1.bind({ partials, S: state, T: trace, P: params }),\n k2,\n k2Bound: hasArcs\n ? k2.bind({ ...graphBindings(core, perm, resources.weights), pos, force, P: params })\n : null,\n k3,\n k3Bound: k3.bind({ pos, S: state, force, oldForce, fixedMask: fixed, partials, P: params }),\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 } = this.requireResources();\n const resolved = resolveFruchtermanReingoldOptions(options, this.current);\n const { nearMax, extentFactor } = this.tuning;\n const adaptive = resolved.cooling === \"adaptive\";\n return {\n n,\n dim: resolved.dim,\n flags: adaptive ? FA2_FLAG_ADAPTIVE : 0,\n tierStart: 0,\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: 0,\n levels: 0,\n pad: [0, 0, 0, 0],\n frK: 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: K1, K2 (or the fill of force when arcCount === 0), K3, K5 in the batch's\n * ONE compute pass (opened by the first call of a batch and reused by every later call with the same batch.id),\n * then toScene in a second pass that ends it, stopping after stage `upTo` when given. With n === 0 nothing is\n * recorded; a 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 - \"exact\" (the grid tier is E_UNSUPPORTED until P4)\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 if (tier === \"grid\") {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"the grid repulsion tier lands in P4\", {\n feature: \"repulsion.grid\",\n hint: 'pass repulsion: \"exact\"',\n });\n }\n const resources = this.requireResources();\n const stop = upTo === undefined ? FR_STAGES.length - 1 : 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 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 if (bound.k2Bound !== null) {\n bound.k2.dispatch(pass, bound.k2Bound, bound.plan, [offset]);\n } else if (bound.fillForceBound !== null) {\n bound.fill.dispatch(pass, bound.fillForceBound, bound.fillPlan, [0]);\n }\n if (stop < 2) {\n return;\n }\n bound.k3.dispatch(pass, bound.k3Bound, bound.plan, [offset]);\n if (stop < 3) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < 4) {\n return;\n }\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).\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 }\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: the exact\n * tier with null grid fields, 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 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: \"exact\",\n maxCellOccupancy: null,\n 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 /** Drops the bind groups of the previous bind() (the buffers changed) 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.k2, bound.k3, bound.k5, bound.toScene, bound.fill]) {\n kernel.invalidate();\n }\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\n * repulsion tier 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 repulsion tier (spec 7.20 \"the preset\"; contract 3.13): ngraph.forcelayout's\n * physics under ngraph's option names and defaults -- Coulomb repulsion `-g m_i m_j / d^2` (K3, LAW 2), 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: the K1-K5 dispatches of one batch share ONE compute pass and\n * toScene runs in a second pass that ends it; the fill kernel takes its FillParams from a model-owned 256-byte uniform\n * buffer; `repulsion: \"grid\"` is E_UNSUPPORTED at load() (the simulation's tier rule).\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 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, graphBindings, kernelSpec } from \"../kernels.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} from \"./force-simulation.js\";\nimport { resolveLayoutTuning } from \"./forceatlas2.js\";\nimport {\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 scalar,\n seedWord,\n subset,\n vector,\n} from \"./model-common.js\";\n\n// ============================================================ constants\n\n/** The stage names of one iteration in dispatch order plus the per-batch toScene (no K4: spec 7.20). */\nconst SE_STAGES = [\"K1\", \"K2\", \"K3\", \"K5\", \"toScene\"] as const;\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/** 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 readonly k2: Kernel;\n /** null when arcCount === 0 (K2 is not recorded; the fill below zeroes force instead). */\n readonly k2Bound: BoundKernel | null;\n readonly k3: Kernel;\n readonly k3Bound: BoundKernel;\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; toScene once per batch). Stages: [\"K1\", \"K2\", \"K3\", \"K5\", \"toScene\"]. */\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: readonly [\"K1\", \"K2\", \"K3\", \"K5\", \"toScene\"] = 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 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`) and the 256-byte FillParams uniform buffer. n = 0 reports one node's worth of bytes so no zero-length\n * buffer is ever created.\n * @param n - the node count\n * @param _dim - the layout dimension (the arrays are stride 3 in both)\n * @returns the three 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 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 ];\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). The tier rule is the simulation's (load() throws\n * E_UNSUPPORTED for the grid tier before calling this).\n * @param s - the snapshot being loaded\n * @param _options - the simulation's current option record (unused: nothing in it affects the inputs)\n * @returns the per-load inputs\n */\n inputs(s: GraphSnapshot, _options: SpringElectricalOptions): ModelInputs {\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 * @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 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 ];\n }\n\n /**\n * Compiles (through the cache) and binds every kernel against the buffers of this load(): K1, K2 (or the fill of\n * force when arcCount === 0), K3 and K5 with the velocity in their `oldForce` slot (PD-2), toScene; writes the\n * FillParams { count: 3n, value: 0, mode: 0 } into the model's uniform buffer. With n === 0 nothing is bound.\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, perm, ring, device } = resources;\n if (n === 0) {\n return;\n }\n const [k1, k2, k3, k5, toScene, fill] = await Promise.all([\n pipelines.kernel(kernelSpec(\"fa2-stats-finalize\", subset(overrides, K1_DEFAULTS))),\n pipelines.kernel(kernelSpec(\"fa2-attraction\", subset(overrides, K2_DEFAULTS))),\n pipelines.kernel(kernelSpec(\"fa2-repulsion-exact\", subset(overrides, K3_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 if (this.resources !== resources) {\n // a newer bind() superseded this one while the pipelines compiled; its own bind groups stand\n return;\n }\n const pos = resources.buffer(\"positions\");\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 force = resources.buffer(\"force\");\n const velocity = resources.buffer(VELOCITY_BUFFER);\n const fillParamsBuffer = resources.buffer(FILL_PARAMS_BUFFER);\n const params = ring.binding(FA2_PARAMS);\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 hasArcs = core.colIdx !== null;\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 k1Bound: k1.bind({ partials, S: state, T: trace, P: params }),\n k2,\n k2Bound: hasArcs\n ? k2.bind({ ...graphBindings(core, perm, resources.weights), pos, force, P: params })\n : null,\n k3,\n k3Bound: k3.bind({ pos, S: state, force, oldForce: velocity, fixedMask: fixed, partials, P: params }),\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 } = this.requireResources();\n const resolved = resolveSpringElectricalOptions(options, this.current);\n const { nearMax, extentFactor } = this.tuning;\n return {\n n,\n dim: resolved.dim,\n flags: 0,\n tierStart: 0,\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: 0,\n levels: 0,\n pad: [0, 0, 0, 0],\n frK: 0,\n temperature: 0,\n springLength: resolved.springLength,\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: K1, K2 (or the fill of force when arcCount === 0), K3, K5 in the batch's\n * ONE K1-K5 compute pass, then toScene in a second pass that ends it, stopping after stage `upTo` when given.\n * 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 - \"exact\" (the grid tier is E_UNSUPPORTED; the simulation never passes \"grid\")\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 if (tier === \"grid\") {\n throw new WebGpuGraphError(\"E_UNSUPPORTED\", \"the grid repulsion tier lands in P4\", {\n feature: \"repulsion.grid\",\n hint: 'pass repulsion: \"exact\"',\n });\n }\n const resources = this.requireResources();\n const stop = upTo === undefined ? SE_STAGES.length - 1 : 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 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 if (bound.k2Bound !== null) {\n bound.k2.dispatch(pass, bound.k2Bound, bound.plan, [offset]);\n } else if (bound.fillForceBound !== null) {\n bound.fill.dispatch(pass, bound.fillForceBound, bound.fillPlan, [0]);\n }\n if (stop < 2) {\n return;\n }\n bound.k3.dispatch(pass, bound.k3Bound, bound.plan, [offset]);\n if (stop < 3) {\n return;\n }\n bound.k5.dispatch(pass, bound.k5Bound, bound.plan, [offset]);\n if (stop < 4) {\n return;\n }\n // the second pass ends the K1-K5 pass; the batch is complete after toScene, so nothing reuses it\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 * @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 }\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: the exact\n * tier with null grid fields; msPerIteration null (the simulation owns the clock); `kineticEnergy` is the last\n * folded value (one 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 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: \"exact\",\n maxCellOccupancy: null,\n 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 /** Drops the bind groups of the previous bind() (the buffers changed) 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.k2, bound.k3, bound.k5, bound.toScene, bound.fill]) {\n kernel.invalidate();\n }\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 repulsion tier with ngraph's defaults (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 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) and P7's seven algorithm members (spec 8.2, 8.3; M8b-T8, PD-14) and nothing\n * else: the CPU-side dispatchers (`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 P8.\n */\n\nimport { type F32, type F64, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { connectedComponents } from \"./algorithms/components.js\";\nimport { pageRank, personalizedPageRank } from \"./algorithms/pagerank.js\";\nimport { eigenvectorCentrality, hits, katzCentrality } from \"./algorithms/spectral.js\";\nimport { type GpuContext } from \"./context.js\";\nimport { createForceAtlas2 } from \"./layouts/forceatlas2.js\";\nimport { createFruchtermanReingold } from \"./layouts/fruchterman-reingold.js\";\nimport { createSpringElectrical } from \"./layouts/spring-electrical.js\";\nimport { type AcceleratorOptions, type GpuAccelerator } from \"./types/accelerator.js\";\nimport {\n type ComponentsOptions,\n type EigenvectorOptions,\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 {\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\";\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 * 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, each a delegation to\n * its algorithm with `ctx.assertReady()` first. The accelerator's algorithm defaults are not consulted by any of\n * them: only `betweenness` has any, and it belongs to P9. 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 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(o?: SpringElectricalOptions): 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 * 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":["scalar","checkDest","coreOf","s","resolve","RING_SLOTS","bindingOf","pass","r","aborted","invalid","normalised","run","finite","q","degree","out","ONE_WORKGROUP","K2_DEFAULTS","K5_DEFAULTS","DEFAULT_RESOLVED","resolvePatch","K1_DEFAULTS","K3_DEFAULTS"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACGrC,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;ACLpC,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;ACCzC,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;ACOxC,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;ACVxC,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;ACK5B,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;ACL/B,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;ACI9B,MAAM;AAAA;AAAA,EAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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"}
|
|
1
|
+
{"version":3,"file":"webgpu-graph-algorithms.js","sources":["../src/kernel/uniform-ring.ts","../src/kernel/dispatch.ts","../src/kernel/struct-block.ts","../src/wgsl/counting-scatter.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/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/histogram.wgsl.ts","../src/wgsl/indirect-finalize.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/scan-add.wgsl.ts","../src/wgsl/scan-block.wgsl.ts","../src/wgsl/segmented-reduce.wgsl.ts","../src/wgsl/spmv-pull.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/scan.ts","../src/primitives/verify.ts","../src/primitives/core-shape.ts","../src/algorithms/degree.ts","../src/kernel/batch.ts","../src/algorithms/scope.ts","../src/algorithms/components.ts","../src/primitives/segmented-reduce.ts","../src/primitives/spmv.ts","../src/algorithms/pagerank.ts","../src/algorithms/power-iteration.ts","../src/algorithms/spectral.ts","../src/primitives/histogram.ts","../src/primitives/radix-sort.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","../src/layouts/calibrate.ts"],"sourcesContent":["/**\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 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.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 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 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.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 * 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). */\nexport interface DispatchPlan {\n readonly x: number;\n readonly y: number;\n readonly z: 1;\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 `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 `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 */\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(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\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 for (var t = 0u; t < tiles; 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 // 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 <= P.settleThreshold * S.rmsRadius);\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 S.outsideGrid = cellHist[cells]; // the previous iteration's pseudo-cell count (0 after load)\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 * 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 the outside pseudo-cell `cells` otherwise; `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; // the outside pseudo-cell (7.7)\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 pseudo-cell included; 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()) { return; } // cells [0, cells]: the pseudo-cell is index cells; 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 hub cell of hubList, dispatched\n * indirectly from hubArgs (the T1 finalize over hubCounters[0]); 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-cell, index cells of level 0, is never a child). 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 outside pseudo-cell's centroid; for an outside\n * node the coarsest level in full and 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)`, `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 level_base(level: u32) -> u32 { // the pyramid index of level L's cell 0 (level 0 carries the pseudo-cell at index 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, 1u, 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 let d2 = dot(d, d) + 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 f = f + cell_force(pi, pyramid[grid_cells()]); // the outside pseudo-cell as one far-field term\n } else {\n for (var cz = 0; cz <= zTop; cz = cz + 1) { // an outside node: the coarsest level in full, no pseudo-cell (it would include itself)\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 outside pseudo-cell alone 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 f = cell_sum(i, pi, grid_cells(), true); // an outside node: the pseudo-cell alone\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 `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 + 1). 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 `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 `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 `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). This file is the only importer of src/wgsl/** (spec 3.2; 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 { countingScatterWgsl } from \"./wgsl/counting-scatter.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 { 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 { histogramWgsl } from \"./wgsl/histogram.wgsl.js\";\nimport { indirectFinalizeWgsl } from \"./wgsl/indirect-finalize.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 { 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 { 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-P3 and P7 (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\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\";\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, 128 B; spec 7.3): the per-iteration ForceAtlas2 parameters -- `n` @0, `dim` @4, `flags` @8 (bit 0 = FA2_FLAG_FIRST), `tierStart` @12, `tierEnd` @16, `iterationIndex` @20, `seed` @24, `nearMax` @28, `scalingRatio` @32, `gravity` @36, `jitterTolerance` @40, `scale` @44, `center` @48 (xyz, w 0), `settleThreshold` @64, `extentFactor` @68, `gridMax` @72, `levels` @76, `arcBase` @80 / `arcEnd` @84 (the bound arc window of K2, 0 and arcCount in the layout), `accumulate` @88 (1 combines into `force`: the windowed pattern), `hiEnd` @92 / `midEnd` @124 (the degreeOrder tier boundaries, PD-7; both 0 without a permutation); the P5 model fields (PD-3): `frK` @96 (the FR optimal distance), `temperature` @100 (the FR temperature of this iteration), `springLength` @104, `springCoefficient` @108, `coulomb` @112 (ngraph's `gravity`, negative repels), `dragCoefficient` @116, `timeStep` @120; 128 B. */\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]);\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// ---- 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 `G^dim`; `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 pseudo-cell included), the serial mass-weighted sum in sorted order into level 0, the occupancy max into `hubCounters[1]`, hub cells (> GRID_HUB_CELL) appended to `hubList`; 6 storage bindings. */\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 hub cell, dispatched indirectly, a WG-strided sum through `wg_reduce_vec4` guarded by `h < hubCount[0]`; 6 storage bindings (`hubCount` is a read-only view of `hubCounters`). */\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 pseudo-cell; the loop bounds are `P.levels` / `P.gridMax`; LAW 0 FA2 / 1 FR / 2 coulomb per cell (P4-T13, PD-22); 5 storage bindings. */\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/**\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, so every member of `KernelId` is present and the\n * 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});\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 `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 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/**\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).\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 const colIdx = v.bindings.colIdx ?? null;\n const weights = v.bindings.weights ?? null;\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 * `degree(ctx, s)` -- the walking-skeleton algorithm, kept public as a diagnostic (spec 3.3, 11.5): the out-degree of\n * every node computed on the device by the row-walking `degree` kernel (4.5) over the resident core of the snapshot,\n * with the group-0 dummy-binding pattern of spec 3.5 (`colIdx` in the `weights` slot when the snapshot is unweighted,\n * `rowPtr` in the `perm` slot because P1-P3 pass no row permutation, so `USE_PERM` is false). The result equals\n * `snapshot.outDegree()`; the point of the kernel is to prove the upload, bind, dispatch and readback path end to end\n * on every adapter (bitwise identical across adapters, spec 11.5), not to be faster than the CPU (the README says\n * so).\n *\n * Contract (3.12): `ctx.assertReady()` first; `nodeCount === 0` returns an empty `Uint32Array` (or `dest`) with no\n * GPU work (spec 5.6: there is no work, which is not a fallback); an already-aborted `signal` is `E_ABORTED` before\n * any work; `dest` must be a `Uint32Array` of length n over an `ArrayBuffer`; `arcCount === 0` skips the dispatch\n * (only `rowPtr` is resident) and the result is zeros; otherwise ONE dispatch over rows [0, n) with `accumulate = 0`\n * (every row is written, so no fill precedes it) -- or, on a windowed core (spec 4.2, PD-8), a `fill` of zeros and\n * one dispatch per window over its rows with `arcBase = w.start`, `arcEnd = w.end`, `accumulate = 1`, so a row split\n * across windows adds its partial counts -- a readback into the result, `onProgress(1, 1)`, and the scratch returned\n * in a finally. Two runs are bitwise identical (spec 11.9 item 4).\n */\n\nimport { type GraphSnapshot, type U32 } from \"@graphty/graph-format\";\n\nimport { type GpuContext } from \"../context.js\";\nimport { BufferUsage } from \"../device/webgpu-constants.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { plan1d } from \"../kernel/dispatch.js\";\nimport { type UniformBlock, type UniformValues } from \"../kernel/struct-block.js\";\nimport { FILL_PARAMS, graphBindings, graphOverrides, kernelSpec, RANGE_PARAMS } from \"../kernels.js\";\nimport { windowBinding } from \"../primitives/core-shape.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type Binding } from \"../types/memory.js\";\nimport { type GpuRunOptions } from \"../types/run.js\";\n\n/**\n * Validates `options.dest` for a 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 `degree: 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 * One pool-acquired uniform buffer holding one params record (a params buffer per dispatch; the caller releases\n * `pooled` in its finally).\n * @param ctx - the context whose pool and queue are used\n * @param pooled - the list the buffer is appended to for release\n * @param block - the uniform block\n * @param values - the record's values\n * @returns the whole-buffer binding\n */\nfunction paramsBinding(ctx: GpuContext, pooled: GPUBuffer[], block: UniformBlock, values: UniformValues): Binding {\n const buffer = ctx.pool.acquire(block.byteLength, BufferUsage.UNIFORM | BufferUsage.COPY_DST, \"degree/params\");\n pooled.push(buffer);\n const bytes = new ArrayBuffer(block.byteLength);\n block.write(new DataView(bytes), values);\n ctx.device.queue.writeBuffer(buffer, 0, bytes);\n return { buffer, offset: 0, size: block.byteLength, window: null };\n}\n\n/**\n * The walking-skeleton kernel, kept public as a diagnostic (spec 3.3): out-degree per node through the row-walking\n * gather with the USE_PERM dummy pattern; equals snapshot.outDegree().\n * @param ctx - the context whose device runs the kernel\n * @param s - the snapshot (uploaded through ctx.residency, or found there)\n * @param options - dest / signal / onProgress (spec 3.3). PLAN DECISION: spelled `?: GpuRunOptions` rather than the\n * contract's `?: GpuRunOptions | undefined` because the root ESLint rule no-duplicate-type-constituents rejects the\n * explicit undefined on an optional parameter (the call signature is identical; P1-T3 made the same choice).\n * @returns the out-degree of every node, index-aligned (`dest` itself when given)\n */\nexport async function degree(ctx: GpuContext, s: GraphSnapshot, options?: GpuRunOptions): Promise<U32> {\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\", \"degree: the signal was aborted before any work started\", {});\n }\n if (n === 0) {\n options?.onProgress?.(1, 1);\n return dest ?? new Uint32Array(0);\n }\n const core = ctx.residency.core(s);\n if (s.arcCount === 0) {\n const zeros = dest ?? new Uint32Array(n);\n zeros.fill(0);\n options?.onProgress?.(1, 1);\n return zeros;\n }\n const byteLength = n * 4;\n const out = ctx.pool.acquire(\n byteLength,\n BufferUsage.STORAGE | BufferUsage.COPY_SRC | BufferUsage.COPY_DST,\n \"degree/out\",\n );\n const pooled: GPUBuffer[] = [];\n const params = (block: UniformBlock, values: UniformValues): Binding => paramsBinding(ctx, pooled, block, values);\n try {\n await ctx.allocator.check();\n const kernel = await ctx.pipelines.kernel(kernelSpec(\"degree\", graphOverrides(core, null)));\n const outBinding: Binding = { buffer: out, offset: 0, size: byteLength, window: null };\n const encoder = ctx.device.createCommandEncoder({ label: \"degree\" });\n const pass = encoder.beginComputePass({ label: \"degree\" });\n if (core.windows === null) {\n const P = params(RANGE_PARAMS, { start: 0, end: n, arcBase: 0, arcEnd: s.arcCount, accumulate: 0, n });\n const bound = kernel.bind({ ...graphBindings(core, null), out: outBinding, P });\n kernel.dispatch(pass, bound, plan1d(n, ctx.workgroupSize, ctx.caps), [0]);\n } else {\n const fill = await ctx.pipelines.kernel(kernelSpec(\"fill\"));\n const zero = fill.bind({ dst: outBinding, P: params(FILL_PARAMS, { count: n, value: 0, mode: 0 }) });\n fill.dispatch(pass, zero, plan1d(n, ctx.workgroupSize, ctx.caps), [0]);\n for (const w of core.windows) {\n const windowed = {\n ...core,\n colIdx: windowBinding(core, \"colIdx\", w),\n weights: core.weights === null ? null : windowBinding(core, \"weights\", w),\n };\n const P = params(RANGE_PARAMS, {\n start: w.rowFirst,\n end: w.rowLast + 1,\n arcBase: w.start,\n arcEnd: w.end,\n accumulate: 1,\n n,\n });\n const bound = kernel.bind({ ...graphBindings(windowed, null), out: outBinding, P });\n kernel.dispatch(pass, bound, plan1d(w.rowLast - w.rowFirst + 1, ctx.workgroupSize, ctx.caps), [0]);\n }\n }\n pass.end();\n ctx.device.queue.submit([encoder.finish()]);\n ctx.assertReady();\n const result = await ctx.readback.read(out, byteLength, dest ?? undefined);\n ctx.assertReady();\n options?.onProgress?.(1, 1);\n return dest ?? new Uint32Array(result);\n } finally {\n for (const buffer of pooled) {\n ctx.pool.release(buffer);\n }\n ctx.pool.release(out);\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 * 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. */\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}\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 };\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).\n * @param labels - the labels\n * @param count - the block count\n * @returns the result\n */\nfunction 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 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 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 * 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; a smaller ring wraps onto a slot the same batch still reads. */\nconst RING_SLOTS = 2 * PR_BATCH + 1;\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 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 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 const pass = batch.pass(\"iterations\");\n if (iterationsRun === 0) {\n normaliser.record(pass, weightedCore, outWeightSumBinding);\n }\n for (let i = 0; i < k; 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 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 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 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: folded.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 * 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`). */\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 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 for (let i = 0; i < k; 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 (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 * 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 * 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 `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 * 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 `cells + 2` words: every real cell, the outside pseudo-cell at index `cells`\n * and one more so `cellStart[cells + 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-cell is index `cells`. */\n readonly cells: number;\n /** `cells + 2`: 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 + 1` (the pseudo-cell), 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,521 pyramid cells in 2D, 2,396,737 in 3D (the design's counts plus the\n * pseudo-cell).\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 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 ? 1 : 0));\n s /= 2;\n }\n return {\n dim,\n g,\n levels,\n cells,\n histWords: cells + 2,\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-cell included): 38,347,792 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 /** `cells + 2` words: the per-cell counts. */\n readonly cellHist: Binding;\n /** `cells + 2` 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]. 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 }\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 \"hubArgs\",\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 { 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/** 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 this.repulsion.dispatch(pass, bound, plan, [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 + 1`, the pseudo-cell included), the hub-cell\n * completion (G4a: the T1 `indirect-finalize` over `hubCounters[0]` into `hubArgs` with `wg = 1`, so the finalize's\n * `ceil(count / wg)` is ONE workgroup per hub cell; G4b: `grid-centroid-hub`, one workgroup per hub cell, dispatched\n * indirectly; PD-13, DEP-P4-I) and one `grid-downsample` dispatch per coarser\n * level (G5). Level 0 holds `[sum m x, sum m y, sum m z, sum m]` per cell; every parent is the sum of its 2^dim\n * children; the pseudo-cell (index `cells` of level 0) is never a child. 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`, `hubArgs`) are the caller's (the model's\n * `BufferSpec`s, so `inspect(name)` reaches them); the static params of the finalize and 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 { type DispatchPlan, plan1d } from \"../kernel/dispatch.js\";\nimport { type BoundKernel, type Kernel } from \"../kernel/kernel.js\";\nimport { GRID_LEVEL_PARAMS, INDIRECT_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 /** `cells + 2` 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 pseudo-cell at 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). */\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 /** One 16-byte indirect args slot with the INDIRECT usage: G4a writes it, G4b dispatches from it. */\n readonly hubArgs: Binding;\n}\n\n/** Where `record()` stops: after level 0 is whole (G4, G4a 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 the finalize and 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, G4a, G4b and then G5 for every coarser level at the `Fa2Params` slot `paramsOffset`; `upTo: \"G4\"`\n * stops after G4b (level 0 is whole: G4a and G4b are 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: 3 after `upTo: \"G4\"`, `3 + (levels - 1)` for a full record. */\n readonly lastDispatches: number;\n}\n\n/**\n * Prepares the pyramid's pipelines over a scope (G4, the finalize, 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 finalize = await scope.pipelines.kernel(kernelSpec(\"indirect-finalize\"));\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, finalize, hub, downsample });\n}\n\n/** The four kernels of the build. */\ninterface Kernels {\n readonly centroid: Kernel;\n readonly finalize: 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 hubArgs: Binding;\n readonly centroid: BoundKernel;\n readonly finalize: BoundKernel;\n readonly finalizeOffset: number;\n readonly hub: BoundKernel;\n readonly levels: readonly { readonly bound: BoundKernel; readonly offset: number; readonly parentCells: number }[];\n}\n\n/** The planner: G4, G4a, 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 four 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, finalize, hub, downsample } = this.kernels;\n const { spec, scope } = this;\n const b = bindings;\n const finalizeParams = scope.params(INDIRECT_PARAMS, {\n countIndex: 0,\n wg: 1, // the finalize plans ceil(count / wg) workgroups over ITEMS; G4b's item is a hub cell, one workgroup each\n slot: 0,\n pad0: 0,\n });\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 hubArgs: b.hubArgs,\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 finalize: finalize.bind({ counters: b.hubCounters, args: b.hubArgs, P: finalizeParams.binding }),\n finalizeOffset: finalizeParams.offset,\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 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, finalize, hub, downsample } = this.kernels;\n const one: DispatchPlan = { x: 1, y: 1, z: 1, items: 1, stride: null };\n centroid.dispatch(pass, bound.centroid, plan1d(spec.cells + 1, scope.workgroupSize, scope.caps), [paramsOffset]);\n finalize.dispatch(pass, bound.finalize, one, [bound.finalizeOffset]);\n hub.dispatchIndirect(pass, bound.hub, bound.hubArgs, 0, [paramsOffset]);\n this.dispatches = 3;\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, INDIRECT_ARGS_STRIDE, 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 hubArgs: 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 (cells + 2) zeroed, `hubList` one word per possible hub cell, `hubArgs` one\n * indirect slot, `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: \"hubArgs\", byteLength: INDIRECT_ARGS_STRIDE, usage: STORAGE_RW | BufferUsage.INDIRECT, zero: true },\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(\"indirect-finalize\"),\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 hubArgs: r.hubArgs,\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 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 hubArgs: resources.buffer(\"hubArgs\"),\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 };\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 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 { 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 hubArgs: resources.buffer(\"hubArgs\"),\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 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 k3.dispatch(pass, k3Bound, bound.plan, [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 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 { 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 hubArgs: resources.buffer(\"hubArgs\"),\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 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 k3.dispatch(pass, k3Bound, bound.plan, [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) and P7's seven algorithm members (spec 8.2, 8.3; M8b-T8, PD-14) and nothing\n * else: the CPU-side dispatchers (`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 P8.\n */\n\nimport { type F32, type F64, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { connectedComponents } from \"./algorithms/components.js\";\nimport { pageRank, personalizedPageRank } from \"./algorithms/pagerank.js\";\nimport { eigenvectorCentrality, hits, katzCentrality } from \"./algorithms/spectral.js\";\nimport { type GpuContext } from \"./context.js\";\nimport { createForceAtlas2 } from \"./layouts/forceatlas2.js\";\nimport { createFruchtermanReingold } from \"./layouts/fruchterman-reingold.js\";\nimport { createSpringElectrical } from \"./layouts/spring-electrical.js\";\nimport { type AcceleratorOptions, type GpuAccelerator } from \"./types/accelerator.js\";\nimport {\n type ComponentsOptions,\n type EigenvectorOptions,\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 {\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\";\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 * 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, each a delegation to\n * its algorithm with `ctx.assertReady()` first. The accelerator's algorithm defaults are not consulted by any of\n * them: only `betweenness` has any, and it belongs to P9. 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 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(o?: SpringElectricalOptions): 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 * 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","/**\n * calibrateLayout (spec 2.2, 7.8, D26; contract 3.3): the layout-tier micro-benchmark a consumer runs ONCE, off the\n * critical path, to measure the exact / grid crossover on the actual device. For every probed size it builds a seeded\n * G(n, 10n) snapshot, runs ForceAtlas2 on the exact tier and on the grid tier -- one untimed `step(1)` after\n * `load()` (which warms every pipeline through `PipelineCache.warm` of the model's specs, so the first timed step\n * compiles nothing) and then TIMED_ITERATIONS timed `step(1)` calls whose `stats.msPerIteration` (the profiler's GPU\n * time when \"timestamp-query\" was granted, else the batch wall time) are averaged -- and releases the probe.\n *\n * PLAN DECISION PD-23 (P4-T14): `src/` cannot import `test/helpers` or `benchmarks/`, so the probe graphs are built\n * here from the package's own LCG (`Lcg`, seed.ts) with a fixed seed, and the spec 7.8 rule is re-implemented in\n * `suggestedExactMaxNodes` below; its twin is `exactMaxNodesFromLadder` in benchmarks/layout-exact.bench.ts (the\n * one copy the G3 / G4 records apply to the committed baselines), which test/layouts/calibrate.test.ts compares it\n * with. The function reads `caps` for nothing: never `caps.software` (spec 7.8, Q-6), so on a software adapter it\n * returns honest numbers a caller can compare in shape, never in value.\n */\n\nimport { fromEdgeArrays, type GraphSnapshot } from \"@graphty/graph-format\";\n\nimport { type GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { assertDeviceComputes } from \"../primitives/verify.js\";\nimport { type CalibrateOptions, type GpuCalibration } from \"../types/layout.js\";\nimport { createForceAtlas2 } from \"./forceatlas2.js\";\nimport { Lcg } from \"./seed.js\";\n\n/** The default probe sizes (spec 2.2): the 8k-65k subset of the exact ladder of spec 7.8 / 10.4 T-4. */\nexport const CALIBRATE_SIZES: readonly number[] = [8_192, 16_384, 32_768, 65_536];\n\n/** The spec 7.8 per-iteration budget of the exact tier, milliseconds (the twin of EXACT_BUDGET_MS in benchmarks/layout-exact.bench.ts). */\nconst BUDGET_MS = 4;\n\n/** Edges per node of every probe graph (E = 10n, the density of the exact ladder). */\nconst EDGES_PER_NODE = 10;\n\n/** Timed iterations per size and tier (spec 2.2: \"10 timed iterations\"). */\nconst TIMED_ITERATIONS = 10;\n\n/** The seed of every probe graph and of the simulation's own LCG. */\nconst SEED = 12345;\n\n/**\n * A seeded G(n, 10n) probe snapshot (self-loops and parallels allowed, unweighted, undirected).\n * @param n - the node count\n * @returns the snapshot\n */\nfunction probeSnapshot(n: number): GraphSnapshot {\n const m = EDGES_PER_NODE * n;\n const rng = new Lcg(SEED);\n const src = new Uint32Array(m);\n const dst = new Uint32Array(m);\n for (let e = 0; e < m; e++) {\n src[e] = Math.floor(rng.next() * n);\n dst[e] = Math.floor(rng.next() * n);\n }\n return fromEdgeArrays({ directed: false, nodeCount: n, src, dst }, { label: `calibrate/${n}` });\n}\n\n/**\n * The mean ms per iteration of one tier at one size: one untimed step after load(), then TIMED_ITERATIONS timed\n * steps (reheat() before each so a settled simulation never short-circuits). With the profiler (a device that granted\n * \"timestamp-query\") the sample is the GPU time of the iteration's passes, the quantity the spec 7.8 rule reads; without\n * it the sample is the step's wall time, which also carries the JS submit and the 12n-byte readback -- a fixed cost of\n * ~1-2 ms on a discrete card that is the same for either tier, so the wall ratio understates the grid tier's\n * advantage at every size and the crossover it suggests is, if anything, too high.\n * @param ctx - the context\n * @param snapshot - the probe snapshot\n * @param tier - the repulsion tier to force\n * @returns milliseconds per iteration\n */\nasync function probeTier(ctx: GpuContext, snapshot: GraphSnapshot, tier: \"exact\" | \"grid\"): Promise<number> {\n const n = snapshot.nodeCount;\n const positions = new Float32Array(3 * n).fill(Number.NaN);\n const sim = createForceAtlas2(ctx, {\n dim: 2,\n seed: SEED,\n maxIter: 1_000_000,\n iterationsPerStep: 1,\n maxInFlight: 1,\n repulsion: tier,\n compat: \"paper\",\n });\n try {\n sim.load(snapshot, positions);\n await sim.step(1);\n let total = 0;\n for (let i = 0; i < TIMED_ITERATIONS; i++) {\n sim.reheat();\n const start = performance.now();\n await sim.step(1);\n const wall = performance.now() - start;\n total += sim.stats.msPerIteration ?? wall;\n }\n return total / TIMED_ITERATIONS;\n } finally {\n sim.dispose();\n }\n}\n\n/**\n * The largest power of two that is <= n (the twin of floorPow2 in benchmarks/layout-exact.bench.ts).\n * @param n - a number >= 1\n * @returns the largest power of two not above n\n */\nfunction floorPow2(n: number): number {\n let p = 1;\n while (p * 2 <= n) {\n p *= 2;\n }\n return p;\n}\n\n/**\n * The spec 7.8 rule over the probed sizes (the twin of exactMaxNodesFromLadder(rows, budget, gridRows) in\n * benchmarks/layout-exact.bench.ts, which test/layouts/calibrate.test.ts compares it with): the largest probed n with\n * exactMs(n) <= BUDGET_MS and exactMs(n) <= gridMs(n), rounded down to a power of two.\n *\n * CONTRACT DECISION (the review of P4-T14; spec 2.2 is silent): when NO probed size satisfies the rule -- the grid\n * tier faster than the exact tier at every probe (the RTX 4070 SUPER with the default sizes: the grid beats the exact\n * tier from 4k up), or every probe over the budget -- the benchmark twin throws and hands the value to an owner\n * decision (spec 10.4), which a library call cannot do. The answer here is then the largest power of two STRICTLY\n * BELOW the smallest probe (1 when the smallest probe is 1): the exact tier runs at no probed size, the unprobed range\n * below keeps the exact tier (whose cost falls with n^2 and is the oracle), and the value is distinguishable from a\n * rule answer, which is never below floorPow2(min(sizes)). A caller that wants the crossover itself probes smaller\n * sizes (the T-4 ladder from 1k); one that wants the exact tier nowhere passes `repulsion: \"grid\"`.\n * @param sizes - the probed sizes (integers >= 1)\n * @param exactMs - ms per iteration of the exact tier per size\n * @param gridMs - ms per iteration of the grid tier per size\n * @returns the suggested exactMaxNodes\n */\nexport function suggestedExactMaxNodes(\n sizes: readonly number[],\n exactMs: Readonly<Record<number, number>>,\n gridMs: Readonly<Record<number, number>>,\n): number {\n let best = 0;\n for (const n of sizes) {\n if (exactMs[n] <= BUDGET_MS && exactMs[n] <= gridMs[n] && n > best) {\n best = n;\n }\n }\n return floorPow2(best === 0 ? Math.max(1, Math.min(...sizes) - 1) : best);\n}\n\n/**\n * Spec 2.2 calibrateLayout, verbatim: measures ms per iteration of the exact and the grid repulsion tier at every\n * probed size on THIS device and suggests `exactMaxNodes` by the spec 7.8 rule (`suggestedExactMaxNodes` above, with\n * its below-the-range answer when no probed size qualifies). Every probe graph is built here and released before the\n * call returns; `firstCallMs` is the wall time of the whole call (pipeline compilation included the first time). The\n * app passes `suggestedExactMaxNodes` through `createAccelerator(ctx, { layout: { exactMaxNodes } })`; the package\n * never calls this implicitly and `\"auto\"` never depends on `caps.software`.\n * @param ctx - the context (E_DISPOSED / E_DEVICE_LOST through assertReady)\n * @param options - the probe sizes (positive integers; default CALIBRATE_SIZES)\n * @returns the calibration record\n */\nexport async function calibrateLayout(ctx: GpuContext, options?: CalibrateOptions): Promise<GpuCalibration> {\n ctx.assertReady();\n await assertDeviceComputes(ctx);\n const sizes = options?.sizes ?? CALIBRATE_SIZES;\n if (!Array.isArray(sizes) || sizes.length === 0 || !sizes.every((n) => Number.isInteger(n) && n >= 1)) {\n throw new WebGpuGraphError(\"E_INVALID_ARGUMENT\", \"sizes must be a non-empty list of integers >= 1\", {\n argument: \"sizes\",\n value: sizes,\n expected: \"a non-empty list of integers >= 1\",\n });\n }\n const start = performance.now();\n const exactMsPerIter: Record<number, number> = {};\n const gridMsPerIter: Record<number, number> = {};\n for (const n of sizes) {\n const snapshot = probeSnapshot(n);\n try {\n exactMsPerIter[n] = await probeTier(ctx, snapshot, \"exact\");\n gridMsPerIter[n] = await probeTier(ctx, snapshot, \"grid\");\n } finally {\n ctx.release(snapshot);\n }\n }\n const largest = Math.max(...sizes);\n const pairs = largest * (largest - 1);\n return {\n pairsPerSecond: (pairs / exactMsPerIter[largest]) * 1000,\n exactMsPerIter,\n gridMsPerIter,\n suggestedExactMaxNodes: suggestedExactMaxNodes(sizes, exactMsPerIter, gridMsPerIter),\n firstCallMs: performance.now() - start,\n };\n}\n"],"names":["y","scalar","U32_MAX","checkRecordArguments","RING_SLOTS","whole","w","v","checkDest","resolve","x","coreOf","bindingOf","pass","aborted","invalid","normalised","run","floorPow2","s","finite","degree","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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACCzC,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;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;ACC5B,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;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;ACApC,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;ACMtC,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;ACMpC,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;ACZrC,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;ACIxC,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;ACJ9B,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;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"}
|