@graphty/webgpu-graph-algorithms 0.6.4 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/browser.js +1 -1
  2. package/dist/chunks/{context-Dvq-Cc6v.js → context-hzGggHeM.js} +28 -30
  3. package/dist/chunks/context-hzGggHeM.js.map +1 -0
  4. package/dist/node.js +1 -1
  5. package/dist/src/algorithms/bfs.d.ts +1 -1
  6. package/dist/src/algorithms/bfs.js +1 -1
  7. package/dist/src/algorithms/scope.d.ts +3 -3
  8. package/dist/src/algorithms/scope.d.ts.map +1 -1
  9. package/dist/src/algorithms/scope.js +0 -2
  10. package/dist/src/algorithms/scope.js.map +1 -1
  11. package/dist/src/algorithms/sssp.d.ts +4 -3
  12. package/dist/src/algorithms/sssp.d.ts.map +1 -1
  13. package/dist/src/algorithms/sssp.js +4 -3
  14. package/dist/src/algorithms/sssp.js.map +1 -1
  15. package/dist/src/constants.d.ts +0 -2
  16. package/dist/src/constants.d.ts.map +1 -1
  17. package/dist/src/constants.js +0 -2
  18. package/dist/src/constants.js.map +1 -1
  19. package/dist/src/kernels.d.ts +8 -7
  20. package/dist/src/kernels.d.ts.map +1 -1
  21. package/dist/src/kernels.js +12 -15
  22. package/dist/src/kernels.js.map +1 -1
  23. package/dist/src/primitives/advance.d.ts +3 -2
  24. package/dist/src/primitives/advance.d.ts.map +1 -1
  25. package/dist/src/primitives/advance.js.map +1 -1
  26. package/dist/src/primitives/frontier.d.ts +33 -38
  27. package/dist/src/primitives/frontier.d.ts.map +1 -1
  28. package/dist/src/primitives/frontier.js +23 -32
  29. package/dist/src/primitives/frontier.js.map +1 -1
  30. package/dist/src/wgsl/frontier-finalize.wgsl.d.ts +24 -30
  31. package/dist/src/wgsl/frontier-finalize.wgsl.d.ts.map +1 -1
  32. package/dist/src/wgsl/frontier-finalize.wgsl.js +36 -82
  33. package/dist/src/wgsl/frontier-finalize.wgsl.js.map +1 -1
  34. package/dist/webgpu-graph-algorithms.js +27 -86
  35. package/dist/webgpu-graph-algorithms.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/algorithms/bfs.ts +1 -1
  38. package/src/algorithms/scope.ts +3 -10
  39. package/src/algorithms/sssp.ts +4 -3
  40. package/src/constants.ts +0 -2
  41. package/src/kernels.ts +12 -15
  42. package/src/primitives/advance.ts +5 -4
  43. package/src/primitives/frontier.ts +40 -56
  44. package/src/wgsl/frontier-finalize.wgsl.ts +36 -82
  45. package/dist/chunks/context-Dvq-Cc6v.js.map +0 -1
@@ -30,7 +30,8 @@
30
30
  import { type Kernel } from "../kernel/kernel.js";
31
31
  import { type CoreBinding } from "../memory/residency.js";
32
32
  import { type CoreWindow } from "./core-shape.js";
33
- import { type Frontier, type FrontierScope } from "./frontier.js";
33
+ import { type Frontier } from "./frontier.js";
34
+ import { type ReduceScope } from "./reduce.js";
34
35
  /** A prepared advance (design 6 row 8): records one expansion of a frontier per level. */
35
36
  export interface AdvancePlanner {
36
37
  /** The compiled `advance-expand` kernel (so `bfs-fused` can share its bind groups' shape). */
@@ -58,5 +59,5 @@ export interface AdvancePlanner {
58
59
  * @param core - the resident core arrays of the snapshot the frontier walks (windowed or not)
59
60
  * @returns the planner
60
61
  */
61
- export declare function prepareAdvance(scope: FrontierScope, core: CoreBinding): Promise<AdvancePlanner>;
62
+ export declare function prepareAdvance(scope: ReduceScope, core: CoreBinding): Promise<AdvancePlanner>;
62
63
  //# sourceMappingURL=advance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"advance.d.ts","sourceRoot":"","sources":["../../../src/primitives/advance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,UAAU,EAA2B,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAElE,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC3B,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6GAA6G;IAC7G,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CACjE;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAGrG"}
1
+ {"version":3,"file":"advance.d.ts","sourceRoot":"","sources":["../../../src/primitives/advance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,UAAU,EAA2B,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC3B,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6GAA6G;IAC7G,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CACjE;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAGnG"}
@@ -1 +1 @@
1
- {"version":3,"file":"advance.js","sourceRoot":"","sources":["../../../src/primitives/advance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3F,OAAO,EAAmB,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAuB3E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAoB,EAAE,IAAiB;IACxE,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACtG,OAAO,IAAI,kBAAkB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED,gEAAgE;AAChE,MAAM,kBAAkB;IAMpB;;;;;OAKG;IACH,YAAY,KAAoB,EAAE,IAAiB,EAAE,MAAc;QAC/D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,IAA2B,EAAE,QAAkB;QAClD,IAAI,QAAQ,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,+BAA+B,QAAQ,CAAC,CAAC,uBAAuB,IAAI,CAAC,CAAC,OAAO,EAC7E;gBACI,QAAQ,EAAE,UAAU;gBACpB,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACjB,QAAQ,EAAE,IAAI,CAAC,CAAC;aACnB,CACJ,CAAC;QACN,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QACvB,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,uCAAuC;QACjH,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE;gBACzC,EAAE,EAAE,KAAK,CAAC,aAAa;gBACvB,YAAY,EAAE,QAAQ,CAAC,YAAY;gBACnC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBACb,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,aAAa;aAC7C,CAAC,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC3B,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC9B,UAAU,EAAE,QAAQ,CAAC,KAAK;gBAC1B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,CAAC,EAAE,MAAM,CAAC,OAAO;aACpB,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC;CACJ"}
1
+ {"version":3,"file":"advance.js","sourceRoot":"","sources":["../../../src/primitives/advance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3F,OAAO,EAAmB,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwB3E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAkB,EAAE,IAAiB;IACtE,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACtG,OAAO,IAAI,kBAAkB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAED,gEAAgE;AAChE,MAAM,kBAAkB;IAMpB;;;;;OAKG;IACH,YAAY,KAAkB,EAAE,IAAiB,EAAE,MAAc;QAC7D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,IAA2B,EAAE,QAAkB;QAClD,IAAI,QAAQ,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,+BAA+B,QAAQ,CAAC,CAAC,uBAAuB,IAAI,CAAC,CAAC,OAAO,EAC7E;gBACI,QAAQ,EAAE,UAAU;gBACpB,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACjB,QAAQ,EAAE,IAAI,CAAC,CAAC;aACnB,CACJ,CAAC;QACN,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QACvB,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,uCAAuC;QACjH,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE;gBACzC,EAAE,EAAE,KAAK,CAAC,aAAa;gBACvB,YAAY,EAAE,QAAQ,CAAC,YAAY;gBACnC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBACb,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,aAAa;aAC7C,CAAC,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC3B,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC9B,UAAU,EAAE,QAAQ,CAAC,KAAK;gBAC1B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,CAAC,EAAE,MAAM,CAAC,OAAO;aACpB,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC;CACJ"}
@@ -1,38 +1,40 @@
1
1
  /**
2
2
  * The `Frontier` of design 6 row 7 and the device-side dispatch selector of design 5.4 (P8-T4; the P8 plan's PD-1,
3
- * PD-3, PD-8, PD-23, DEP-P8-A, DEP-P8-C). A traversal's per-level state is two n-slot vertex queues, ONE 24-word
3
+ * PD-3, PD-8, PD-23, DEP-P8-A, DEP-P8-C). A traversal's per-level state is two n-slot vertex queues, ONE 25-word
4
4
  * counters block (every counter of the phase is a word of it: a four-byte word is never a legal storage-binding
5
- * offset, and the selector must reach every count it acts on through one binding), the indirect args buffer of
6
- * `MAX_LEVELS_PER_SUBMIT x FRONTIER_CANDIDATES` 16-byte slots, and the edge queue. The host never reads a counter
7
- * inside a submit: `frontier-finalize`, one lane, runs at the START of every level (role 0: rotates
8
- * `nextFrontierCount` into `frontierCount`, advances `level`, decides `done`, writes this level's slots) and again once
9
- * the edge queue is filled (role 1: clamps `edgeCount`, sizes the contract slot, or on an overflow --
10
- * `edgeCountUnclamped > edgeCapacity` -- sizes the fused-retry slot instead, PD-23), and the kernels that follow
11
- * dispatch indirectly from those slots. The host records up to `MAX_LEVELS_PER_SUBMIT` levels per submit and reads
12
- * `done` (four bytes) once per submit; a boundary that finds `done` set zeroes its slots and moves no counter, so the
13
- * recorded levels past the end are no-ops and the counters freeze at the finishing boundary's values.
5
+ * offset, and the selector must reach every count it acts on through one binding) and the edge queue. The host
6
+ * never reads a counter inside a submit: `frontier-finalize`, one lane, runs at the START of every level (role 0:
7
+ * rotates `nextFrontierCount` into `frontierCount`, advances `level`, decides `done`, chooses the level's path) and
8
+ * again once the edge queue is filled (role 1: clamps `edgeCount`, or on an overflow -- `edgeCountUnclamped >
9
+ * edgeCapacity` -- switches the path to the fused retry, PD-23). The choice is the block's `path` word (`W.path`,
10
+ * word 24); every level kernel is a direct grid-stride dispatch that reads it first and does nothing unless the
11
+ * word names it (design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md: the seven indirect slots the
12
+ * selector once wrote per level cost about 0.4 ms of Dawn validation each and were 97 % of a traversal's wall
13
+ * time; they and their args buffer are gone). The host records up to `MAX_LEVELS_PER_SUBMIT` levels per submit and
14
+ * reads `done` (four bytes) once per submit; a boundary that finds `done` set writes path 0 and moves no counter,
15
+ * so the recorded levels past the end are no-ops and the counters freeze at the finishing boundary's values.
14
16
  *
15
17
  * The seed: `frontierCount` is NEVER seeded, because the first boundary rotates it out unread. A BFS driver calls
16
18
  * `reset(queue, source, { nextFrontierCount: 1, level: U32_MAX })`: the first boundary rotates the 1 in, adds it into
17
19
  * `visitedCount`, and wraps `level` to 0, so the level-0 expansion claims the source's neighbours at `level + 1 == 1`.
18
20
  * `reset` is a queue write, ordered before the submit that follows, and it puts the source on side 0.
19
21
  *
20
- * Every buffer comes from the caller's ONE lease (`scope.scratch`, `scope.indirect`) so the algorithm's dispose()
22
+ * Every buffer comes from the caller's ONE lease (`scope.scratch`) so the algorithm's dispose()
21
23
  * releases them together (design 4.4). The two vertex queues are two BUFFERS, never two ranges of one: `Kernel.bind`
22
24
  * rejects one buffer bound read-only and read-write in one dispatch even for disjoint ranges. `src/primitives/**`
23
25
  * never imports `src/context.ts`.
24
26
  */
25
27
  import { type Binding } from "../types/memory.js";
26
28
  import { type ReduceScope } from "./reduce.js";
27
- /** The seven indirect slots of one level (`FRONTIER_CANDIDATES`), by the kernel that dispatches from each. */
28
- export declare const SLOT: Readonly<{
29
- expand: 0;
30
- contract: 1;
29
+ /** The values of the `path` word (`W.path`): what a level's kernels run; every level kernel reads it first. */
30
+ export declare const PATH: Readonly<{
31
+ none: 0;
32
+ twoPhase: 1;
31
33
  fused: 2;
32
- fillBits: 3;
33
- bitset: 4;
34
- bottomUp: 5;
35
- fusedRetry: 6;
34
+ bottomUp: 3;
35
+ fusedRetry: 4;
36
+ near: 5;
37
+ far: 6;
36
38
  }>;
37
39
  /** The words of the counters block (`FRONTIER_COUNTERS`), by index: byte offset 4 x word; no driver types a number. */
38
40
  export declare const W: Readonly<{
@@ -64,21 +66,14 @@ export declare const W: Readonly<{
64
66
  }>;
65
67
  /** The words a `reset` seeds (every other word is zeroed). */
66
68
  export type FrontierSeed = Readonly<Partial<Record<keyof typeof W, number>>>;
67
- /** A ReduceScope that can also lease an INDIRECT buffer (the args of the frontier); `algorithmScope` is one. */
68
- export interface FrontierScope extends ReduceScope {
69
- /** A STORAGE | INDIRECT | COPY_DST | COPY_SRC buffer of the scope's lease. */
70
- indirect(byteLength: number, label: string): GPUBuffer;
71
- }
72
- /** The `FrontierParams` fields a caller passes to `recordFinalize`; the planner fills `role`, `slotBase`, `wg`, `edgeCapacity` and `n` itself. A missing field is written as 0. */
69
+ /** The `FrontierParams` fields a caller passes to `recordFinalize`; the planner fills `role`, `wg`, `edgeCapacity` and `n` itself. A missing field is written as 0. */
73
70
  export type FrontierFinalizeFields = Readonly<Partial<Record<"alpha" | "beta" | "fusedMax" | "maxDepth" | "mode" | "cutoffBits" | "arcBase" | "arcEnd" | "predKind" | "bitsBase" | "source" | "stride" | "firstOfSubmit" | "iteration", number>>>;
74
- /** The frontier queue of design 6 row 7: two vertex queues, the counters block, the args buffer and the edge queue, all leased by the caller's scope. */
71
+ /** The frontier queue of design 6 row 7: two vertex queues, the counters block and the edge queue, all leased by the caller's scope. */
75
72
  export declare class Frontier {
76
73
  /** The two n-slot u32 vertex queues (`vertices[side]` is the input of the current level). */
77
74
  readonly vertices: readonly [Binding, Binding];
78
- /** The `FrontierCounters` block, 96 B, bound by every kernel as `array<atomic<u32>>`. */
75
+ /** The `FrontierCounters` block, 112 B, bound by every kernel as `array<atomic<u32>>`. */
79
76
  readonly counters: Binding;
80
- /** The indirect args, `MAX_LEVELS_PER_SUBMIT x FRONTIER_CANDIDATES` 16-byte slots (usage INDIRECT | STORAGE | COPY_DST | COPY_SRC). */
81
- readonly args: Binding;
82
77
  /** The edge queue: `edgeCapacity` entries of u32 (the target vertex of an arc). */
83
78
  readonly edgeQueue: Binding;
84
79
  /** How many entries the edge queue holds; role 1 clamps `edgeCount` to it and detects an overflow above it. */
@@ -90,12 +85,11 @@ export declare class Frontier {
90
85
  * Wraps the leased buffers; use prepareFrontier().
91
86
  * @param vertices - the two vertex queues
92
87
  * @param counters - the counters block
93
- * @param args - the args buffer
94
88
  * @param edgeQueue - the edge queue
95
89
  * @param edgeCapacity - the edge queue's entry count
96
90
  * @param n - the vertex count
97
91
  */
98
- constructor(vertices: readonly [Binding, Binding], counters: Binding, args: Binding, edgeQueue: Binding, edgeCapacity: number, n: number);
92
+ constructor(vertices: readonly [Binding, Binding], counters: Binding, edgeQueue: Binding, edgeCapacity: number, n: number);
99
93
  /**
100
94
  * Which vertex queue is the input of the current level (a host-side index between two cached bind-group sets).
101
95
  * @returns 0 or 1
@@ -114,7 +108,7 @@ export declare class Frontier {
114
108
  /** Flips the two vertex queues; the counts rotate inside the block, so nothing else moves. */
115
109
  swap(): void;
116
110
  /**
117
- * Seeds a traversal: one `queue.writeBuffer` of the whole 96-byte block (zero except the caller's words) and one of
111
+ * Seeds a traversal: one `queue.writeBuffer` of the whole 112-byte block (zero except the caller's words) and one of
118
112
  * `vertices[0][0] = source`, both ordered before the submit that follows; the source is on side 0 afterwards.
119
113
  * `frontierCount` is not a word to seed: the first boundary rotates word 1 into it (the BFS seed is
120
114
  * `{ nextFrontierCount: 1, level: U32_MAX }`). A source outside `[0, n)`, an unknown word or a value that is not a
@@ -127,13 +121,14 @@ export declare class Frontier {
127
121
  }
128
122
  /** A prepared frontier (design 6 row 7): the leased queue and the recorded selector dispatches. */
129
123
  export interface FrontierPlanner {
130
- /** The queue the planner sizes the slots of. */
124
+ /** The queue the planner's selector rotates and chooses the path of. */
131
125
  readonly frontier: Frontier;
132
126
  /**
133
127
  * Records one `frontier-finalize` dispatch (one workgroup) in `role` for `level` of the current submit: one
134
- * `FrontierParams` record with `slotBase = level x FRONTIER_CANDIDATES`, `wg`, `edgeCapacity` and `n` filled by the
135
- * planner and every other field from `fields`. A level outside `[0, MAX_LEVELS_PER_SUBMIT)` or a role outside
136
- * `[0, 3]` is E_INVALID_ARGUMENT before anything is recorded.
128
+ * `FrontierParams` record with `wg`, `edgeCapacity` and `n` filled by the planner and every other field from
129
+ * `fields`. A level outside `[0, MAX_LEVELS_PER_SUBMIT)` (the selector addresses nothing by level any more, but
130
+ * the host's submit cadence still is the bound) or a role outside `[0, 3]` is E_INVALID_ARGUMENT before
131
+ * anything is recorded.
137
132
  * @param pass - the compute pass
138
133
  * @param role - 0 the level boundary, 1 the edge-queue role (2 and 3 are P8-T9's)
139
134
  * @param level - the level inside the submit
@@ -146,11 +141,11 @@ export interface FrontierPlanner {
146
141
  * edge capacity defaults to `max(1, min(arcCount, floor(maxStorageBufferBindingSize / 4)))` (never a zero-length
147
142
  * buffer: the one-node graph has no arcs); a test passes a small one to force the overflow path. The planner lives
148
143
  * exactly as long as the scope: never use it after the scope's dispose().
149
- * @param scope - the caller's scope (device, caps, cache, scratch, indirect, params)
144
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
150
145
  * @param n - the vertex count
151
146
  * @param arcCount - the arc count (the natural edge-queue size)
152
147
  * @param edgeCapacity - the edge queue's entry count, when the caller chooses it (an integer >= 1)
153
148
  * @returns the planner
154
149
  */
155
- export declare function prepareFrontier(scope: FrontierScope, n: number, arcCount: number, edgeCapacity?: number): Promise<FrontierPlanner>;
150
+ export declare function prepareFrontier(scope: ReduceScope, n: number, arcCount: number, edgeCapacity?: number): Promise<FrontierPlanner>;
156
151
  //# sourceMappingURL=frontier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontier.d.ts","sourceRoot":"","sources":["../../../src/primitives/frontier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,8GAA8G;AAC9G,eAAO,MAAM,IAAI,EAAE,QAAQ,CAAC;IACxB,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,EAAE,CAAC,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,CAAC;IACZ,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,EAAE,CAAC,CAAC;IACZ,UAAU,EAAE,CAAC,CAAC;CACjB,CAA2G,CAAC;AAE7G,uHAAuH;AACvH,eAAO,MAAM,CAAC,EAAE,QAAQ,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC;IACjB,iBAAiB,EAAE,CAAC,CAAC;IACrB,iBAAiB,EAAE,CAAC,CAAC;IACrB,iBAAiB,EAAE,CAAC,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC;IACjB,cAAc,EAAE,CAAC,CAAC;IAClB,kBAAkB,EAAE,CAAC,CAAC;IACtB,gBAAgB,EAAE,CAAC,CAAC;IACpB,SAAS,EAAE,CAAC,CAAC;IACb,kBAAkB,EAAE,CAAC,CAAC;IACtB,cAAc,EAAE,EAAE,CAAC;IACnB,KAAK,EAAE,EAAE,CAAC;IACV,YAAY,EAAE,EAAE,CAAC;IACjB,QAAQ,EAAE,EAAE,CAAC;IACb,SAAS,EAAE,EAAE,CAAC;IACd,IAAI,EAAE,EAAE,CAAC;IACT,WAAW,EAAE,EAAE,CAAC;IAChB,WAAW,EAAE,EAAE,CAAC;IAChB,cAAc,EAAE,EAAE,CAAC;IACnB,cAAc,EAAE,EAAE,CAAC;IACnB,QAAQ,EAAE,EAAE,CAAC;IACb,YAAY,EAAE,EAAE,CAAC;IACjB,aAAa,EAAE,EAAE,CAAC;IAClB,SAAS,EAAE,EAAE,CAAC;IACd,IAAI,EAAE,EAAE,CAAC;CACZ,CA0BC,CAAC;AAEH,8DAA8D;AAC9D,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAE7E,gHAAgH;AAChH,MAAM,WAAW,aAAc,SAAQ,WAAW;IAC9C,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1D;AAED,mLAAmL;AACnL,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CACzC,OAAO,CACH,MAAM,CACA,OAAO,GACP,MAAM,GACN,UAAU,GACV,UAAU,GACV,MAAM,GACN,YAAY,GACZ,SAAS,GACT,QAAQ,GACR,UAAU,GACV,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,eAAe,GACf,WAAW,EACb,MAAM,CACT,CACJ,CACJ,CAAC;AAoCF,yJAAyJ;AACzJ,qBAAa,QAAQ;IACjB,6FAA6F;IAC7F,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,uIAAuI;IACvI,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,+GAA+G;IAC/G,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,SAAS,CAAY;IAE7B;;;;;;;;OAQG;gBAEC,QAAQ,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,EACrC,QAAQ,EAAE,OAAO,EACjB,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,OAAO,EAClB,YAAY,EAAE,MAAM,EACpB,CAAC,EAAE,MAAM;IAUb;;;OAGG;IACH,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAEhB;IAED;;;OAGG;IACH,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED;;;OAGG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,8FAA8F;IAC9F,IAAI,IAAI,IAAI;IAIZ;;;;;;;;;OASG;IACH,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;CAcnE;AAED,mGAAmG;AACnG,MAAM,WAAW,eAAe;IAC5B,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B;;;;;;;;;OASG;IACH,cAAc,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAClH;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACjC,KAAK,EAAE,aAAa,EACpB,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,eAAe,CAAC,CAuC1B"}
1
+ {"version":3,"file":"frontier.d.ts","sourceRoot":"","sources":["../../../src/primitives/frontier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAOH,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,+GAA+G;AAC/G,eAAO,MAAM,IAAI,EAAE,QAAQ,CAAC;IACxB,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,CAAC,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,CAAC;IACZ,UAAU,EAAE,CAAC,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;IACR,GAAG,EAAE,CAAC,CAAC;CACV,CAAkG,CAAC;AAEpG,uHAAuH;AACvH,eAAO,MAAM,CAAC,EAAE,QAAQ,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC;IACjB,iBAAiB,EAAE,CAAC,CAAC;IACrB,iBAAiB,EAAE,CAAC,CAAC;IACrB,iBAAiB,EAAE,CAAC,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC;IACjB,cAAc,EAAE,CAAC,CAAC;IAClB,kBAAkB,EAAE,CAAC,CAAC;IACtB,gBAAgB,EAAE,CAAC,CAAC;IACpB,SAAS,EAAE,CAAC,CAAC;IACb,kBAAkB,EAAE,CAAC,CAAC;IACtB,cAAc,EAAE,EAAE,CAAC;IACnB,KAAK,EAAE,EAAE,CAAC;IACV,YAAY,EAAE,EAAE,CAAC;IACjB,QAAQ,EAAE,EAAE,CAAC;IACb,SAAS,EAAE,EAAE,CAAC;IACd,IAAI,EAAE,EAAE,CAAC;IACT,WAAW,EAAE,EAAE,CAAC;IAChB,WAAW,EAAE,EAAE,CAAC;IAChB,cAAc,EAAE,EAAE,CAAC;IACnB,cAAc,EAAE,EAAE,CAAC;IACnB,QAAQ,EAAE,EAAE,CAAC;IACb,YAAY,EAAE,EAAE,CAAC;IACjB,aAAa,EAAE,EAAE,CAAC;IAClB,SAAS,EAAE,EAAE,CAAC;IACd,IAAI,EAAE,EAAE,CAAC;CACZ,CA0BC,CAAC;AAEH,8DAA8D;AAC9D,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAE7E,uKAAuK;AACvK,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CACzC,OAAO,CACH,MAAM,CACA,OAAO,GACP,MAAM,GACN,UAAU,GACV,UAAU,GACV,MAAM,GACN,YAAY,GACZ,SAAS,GACT,QAAQ,GACR,UAAU,GACV,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,eAAe,GACf,WAAW,EACb,MAAM,CACT,CACJ,CACJ,CAAC;AAoCF,wIAAwI;AACxI,qBAAa,QAAQ;IACjB,6FAA6F;IAC7F,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,0FAA0F;IAC1F,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,+GAA+G;IAC/G,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,SAAS,CAAY;IAE7B;;;;;;;OAOG;gBAEC,QAAQ,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,EACrC,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,OAAO,EAClB,YAAY,EAAE,MAAM,EACpB,CAAC,EAAE,MAAM;IASb;;;OAGG;IACH,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAEhB;IAED;;;OAGG;IACH,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED;;;OAGG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,8FAA8F;IAC9F,IAAI,IAAI,IAAI;IAIZ;;;;;;;;;OASG;IACH,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;CAcnE;AAED,mGAAmG;AACnG,MAAM,WAAW,eAAe;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAClH;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACjC,KAAK,EAAE,WAAW,EAClB,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,eAAe,CAAC,CAgC1B"}
@@ -1,34 +1,35 @@
1
1
  /**
2
2
  * The `Frontier` of design 6 row 7 and the device-side dispatch selector of design 5.4 (P8-T4; the P8 plan's PD-1,
3
- * PD-3, PD-8, PD-23, DEP-P8-A, DEP-P8-C). A traversal's per-level state is two n-slot vertex queues, ONE 24-word
3
+ * PD-3, PD-8, PD-23, DEP-P8-A, DEP-P8-C). A traversal's per-level state is two n-slot vertex queues, ONE 25-word
4
4
  * counters block (every counter of the phase is a word of it: a four-byte word is never a legal storage-binding
5
- * offset, and the selector must reach every count it acts on through one binding), the indirect args buffer of
6
- * `MAX_LEVELS_PER_SUBMIT x FRONTIER_CANDIDATES` 16-byte slots, and the edge queue. The host never reads a counter
7
- * inside a submit: `frontier-finalize`, one lane, runs at the START of every level (role 0: rotates
8
- * `nextFrontierCount` into `frontierCount`, advances `level`, decides `done`, writes this level's slots) and again once
9
- * the edge queue is filled (role 1: clamps `edgeCount`, sizes the contract slot, or on an overflow --
10
- * `edgeCountUnclamped > edgeCapacity` -- sizes the fused-retry slot instead, PD-23), and the kernels that follow
11
- * dispatch indirectly from those slots. The host records up to `MAX_LEVELS_PER_SUBMIT` levels per submit and reads
12
- * `done` (four bytes) once per submit; a boundary that finds `done` set zeroes its slots and moves no counter, so the
13
- * recorded levels past the end are no-ops and the counters freeze at the finishing boundary's values.
5
+ * offset, and the selector must reach every count it acts on through one binding) and the edge queue. The host
6
+ * never reads a counter inside a submit: `frontier-finalize`, one lane, runs at the START of every level (role 0:
7
+ * rotates `nextFrontierCount` into `frontierCount`, advances `level`, decides `done`, chooses the level's path) and
8
+ * again once the edge queue is filled (role 1: clamps `edgeCount`, or on an overflow -- `edgeCountUnclamped >
9
+ * edgeCapacity` -- switches the path to the fused retry, PD-23). The choice is the block's `path` word (`W.path`,
10
+ * word 24); every level kernel is a direct grid-stride dispatch that reads it first and does nothing unless the
11
+ * word names it (design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md: the seven indirect slots the
12
+ * selector once wrote per level cost about 0.4 ms of Dawn validation each and were 97 % of a traversal's wall
13
+ * time; they and their args buffer are gone). The host records up to `MAX_LEVELS_PER_SUBMIT` levels per submit and
14
+ * reads `done` (four bytes) once per submit; a boundary that finds `done` set writes path 0 and moves no counter,
15
+ * so the recorded levels past the end are no-ops and the counters freeze at the finishing boundary's values.
14
16
  *
15
17
  * The seed: `frontierCount` is NEVER seeded, because the first boundary rotates it out unread. A BFS driver calls
16
18
  * `reset(queue, source, { nextFrontierCount: 1, level: U32_MAX })`: the first boundary rotates the 1 in, adds it into
17
19
  * `visitedCount`, and wraps `level` to 0, so the level-0 expansion claims the source's neighbours at `level + 1 == 1`.
18
20
  * `reset` is a queue write, ordered before the submit that follows, and it puts the source on side 0.
19
21
  *
20
- * Every buffer comes from the caller's ONE lease (`scope.scratch`, `scope.indirect`) so the algorithm's dispose()
22
+ * Every buffer comes from the caller's ONE lease (`scope.scratch`) so the algorithm's dispose()
21
23
  * releases them together (design 4.4). The two vertex queues are two BUFFERS, never two ranges of one: `Kernel.bind`
22
24
  * rejects one buffer bound read-only and read-write in one dispatch even for disjoint ranges. `src/primitives/**`
23
25
  * never imports `src/context.ts`.
24
26
  */
25
- import { FRONTIER_CANDIDATES, MAX_LEVELS_PER_SUBMIT, U32_MAX } from "../constants.js";
27
+ import { MAX_LEVELS_PER_SUBMIT, U32_MAX } from "../constants.js";
26
28
  import { WebGpuGraphError } from "../errors.js";
27
29
  import { plan1d } from "../kernel/dispatch.js";
28
- import { INDIRECT_ARGS_STRIDE } from "../kernel/kernel.js";
29
30
  import { FRONTIER_COUNTERS, FRONTIER_PARAMS, kernelSpec } from "../kernels.js";
30
- /** The seven indirect slots of one level (`FRONTIER_CANDIDATES`), by the kernel that dispatches from each. */
31
- export const SLOT = Object.freeze({ expand: 0, contract: 1, fused: 2, fillBits: 3, bitset: 4, bottomUp: 5, fusedRetry: 6 });
31
+ /** The values of the `path` word (`W.path`): what a level's kernels run; every level kernel reads it first. */
32
+ export const PATH = Object.freeze({ none: 0, twoPhase: 1, fused: 2, bottomUp: 3, fusedRetry: 4, near: 5, far: 6 });
32
33
  /** The words of the counters block (`FRONTIER_COUNTERS`), by index: byte offset 4 x word; no driver types a number. */
33
34
  export const W = Object.freeze({
34
35
  frontierCount: 0,
@@ -88,22 +89,20 @@ function assertCount(argument, value) {
88
89
  });
89
90
  }
90
91
  }
91
- /** The frontier queue of design 6 row 7: two vertex queues, the counters block, the args buffer and the edge queue, all leased by the caller's scope. */
92
+ /** The frontier queue of design 6 row 7: two vertex queues, the counters block and the edge queue, all leased by the caller's scope. */
92
93
  export class Frontier {
93
94
  /**
94
95
  * Wraps the leased buffers; use prepareFrontier().
95
96
  * @param vertices - the two vertex queues
96
97
  * @param counters - the counters block
97
- * @param args - the args buffer
98
98
  * @param edgeQueue - the edge queue
99
99
  * @param edgeCapacity - the edge queue's entry count
100
100
  * @param n - the vertex count
101
101
  */
102
- constructor(vertices, counters, args, edgeQueue, edgeCapacity, n) {
102
+ constructor(vertices, counters, edgeQueue, edgeCapacity, n) {
103
103
  this.sideIndex = 0;
104
104
  this.vertices = vertices;
105
105
  this.counters = counters;
106
- this.args = args;
107
106
  this.edgeQueue = edgeQueue;
108
107
  this.edgeCapacity = edgeCapacity;
109
108
  this.n = n;
@@ -134,7 +133,7 @@ export class Frontier {
134
133
  this.sideIndex = this.sideIndex === 0 ? 1 : 0;
135
134
  }
136
135
  /**
137
- * Seeds a traversal: one `queue.writeBuffer` of the whole 96-byte block (zero except the caller's words) and one of
136
+ * Seeds a traversal: one `queue.writeBuffer` of the whole 112-byte block (zero except the caller's words) and one of
138
137
  * `vertices[0][0] = source`, both ordered before the submit that follows; the source is on side 0 afterwards.
139
138
  * `frontierCount` is not a word to seed: the first boundary rotates word 1 into it (the BFS seed is
140
139
  * `{ nextFrontierCount: 1, level: U32_MAX }`). A source outside `[0, n)`, an unknown word or a value that is not a
@@ -163,7 +162,7 @@ export class Frontier {
163
162
  * edge capacity defaults to `max(1, min(arcCount, floor(maxStorageBufferBindingSize / 4)))` (never a zero-length
164
163
  * buffer: the one-node graph has no arcs); a test passes a small one to force the overflow path. The planner lives
165
164
  * exactly as long as the scope: never use it after the scope's dispose().
166
- * @param scope - the caller's scope (device, caps, cache, scratch, indirect, params)
165
+ * @param scope - the caller's scope (device, caps, cache, scratch, params)
167
166
  * @param n - the vertex count
168
167
  * @param arcCount - the arc count (the natural edge-queue size)
169
168
  * @param edgeCapacity - the edge queue's entry count, when the caller chooses it (an integer >= 1)
@@ -182,7 +181,6 @@ export async function prepareFrontier(scope, n, arcCount, edgeCapacity) {
182
181
  }
183
182
  const kernel = await scope.pipelines.kernel(kernelSpec("frontier-finalize"));
184
183
  const queueBytes = 4 * Math.max(1, n);
185
- const argsBytes = MAX_LEVELS_PER_SUBMIT * FRONTIER_CANDIDATES * INDIRECT_ARGS_STRIDE;
186
184
  const vertices = [
187
185
  { buffer: scope.scratch(queueBytes, "frontier/vertices-0"), offset: 0, size: queueBytes, window: null },
188
186
  { buffer: scope.scratch(queueBytes, "frontier/vertices-1"), offset: 0, size: queueBytes, window: null },
@@ -193,22 +191,16 @@ export async function prepareFrontier(scope, n, arcCount, edgeCapacity) {
193
191
  size: FRONTIER_COUNTERS.byteLength,
194
192
  window: null,
195
193
  };
196
- const args = {
197
- buffer: scope.indirect(argsBytes, "frontier/args"),
198
- offset: 0,
199
- size: argsBytes,
200
- window: null,
201
- };
202
194
  const edgeQueue = {
203
195
  buffer: scope.scratch(4 * capacity, "frontier/edge-queue"),
204
196
  offset: 0,
205
197
  size: 4 * capacity,
206
198
  window: null,
207
199
  };
208
- const frontier = new Frontier(vertices, counters, args, edgeQueue, capacity, n);
200
+ const frontier = new Frontier(vertices, counters, edgeQueue, capacity, n);
209
201
  return new FrontierPlannerImpl(scope, kernel, frontier);
210
202
  }
211
- /** The planner: the selector kernel bound once to the frontier's block and args. */
203
+ /** The planner: the selector kernel bound once to the frontier's block. */
212
204
  class FrontierPlannerImpl {
213
205
  /**
214
206
  * Wraps the resolved kernel; use prepareFrontier().
@@ -247,12 +239,11 @@ class FrontierPlannerImpl {
247
239
  const params = scope.params(FRONTIER_PARAMS, {
248
240
  ...definedWords(fields),
249
241
  role,
250
- slotBase: level * FRONTIER_CANDIDATES,
251
242
  wg: scope.workgroupSize,
252
243
  edgeCapacity: frontier.edgeCapacity,
253
244
  n: frontier.n,
254
245
  });
255
- const bound = this.kernel.bind({ counters: frontier.counters, args: frontier.args, P: params.binding });
246
+ const bound = this.kernel.bind({ counters: frontier.counters, P: params.binding });
256
247
  this.kernel.dispatch(pass, bound, plan1d(1, scope.workgroupSize, scope.caps), [params.offset]);
257
248
  }
258
249
  }
@@ -1 +1 @@
1
- {"version":3,"file":"frontier.js","sourceRoot":"","sources":["../../../src/primitives/frontier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"frontier.js","sourceRoot":"","sources":["../../../src/primitives/frontier.ts"],"names":[],"mappings":"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"}
@@ -1,31 +1,33 @@
1
1
  /**
2
2
  * The `frontier-finalize` kernel body (design 5.4, 6 row 7; P8-T4, the P8 plan's PD-3 / PD-23 / DEP-P8-C): the
3
3
  * device-side selector of the frontier family. One workgroup, one lane, no barrier after the early return (spec 3.5
4
- * rule 1). It is recorded TWICE per level, in two roles chosen by `P.role`, because a level's dispatch sizes become
5
- * known at two moments: role 0 runs at the START of a level -- rotates `nextFrontierCount` into `frontierCount`,
6
- * advances `level`, decides `done` (an empty frontier, or `level >= P.maxDepth`), chooses the path and writes this
7
- * level's seven 16-byte slots at `P.slotBase`; role 1 runs once the edge queue is filled -- clamps `edgeCount` to
8
- * `P.edgeCapacity`, sizes the contract slot, or, when `edgeCountUnclamped` exceeds the capacity, zeroes it and sizes
9
- * the fused-retry slot from `frontierCount` instead (PD-23). Two rules: a boundary that finds `done` set zeroes its
10
- * slots and moves no counter word (the host records levels past the end); role 1 counts a two-phase level only when
11
- * role 0 chose one, which it reads from slot 0's `x` (a storage write of one dispatch is visible to the next of the
12
- * same pass). The `(x, y)` arithmetic is `indirect-finalize`'s verbatim (P4), so a count above 2^32 - wg cannot wrap
13
- * and a group count above MAX_WORKGROUPS_PER_DIM splits in 2D; slots 2 and 6 are sized one WORKGROUP per entry for
14
- * `bfs-fused`; slots 3, 4 and 5 (the bits fill over `ceil(n / 32)` words, the bitset build over the frontier, the sweep
15
- * over the unvisited list) are the bottom-up level's.
4
+ * rule 1). It is recorded TWICE per level, in two roles chosen by `P.role`, because a level's counts become known at
5
+ * two moments: role 0 runs at the START of a level -- rotates `nextFrontierCount` into `frontierCount`, advances
6
+ * `level`, decides `done` (an empty frontier, or `level >= P.maxDepth`) and chooses the path; role 1 runs once the
7
+ * edge queue is filled -- clamps `edgeCount` to `P.edgeCapacity`, or, when `edgeCountUnclamped` exceeds the
8
+ * capacity, switches the path to the fused retry over `frontierCount` (PD-23). The decision is ONE word of the
9
+ * counters block, `path` (word 24): 0 nothing (done, or a level past the end), 1 two-phase, 2 fused, 3 bottom-up,
10
+ * 4 the fused retry (role 1), 5 a near SSSP round, 6 a far one (role 2). Every level kernel is a direct grid-stride
11
+ * dispatch that reads that word first and runs only when it names it (decision record
12
+ * design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md: Dawn's validation of an indirect dispatch cost
13
+ * about 0.4 ms of device time each, and the seven indirect slots this kernel once wrote per level were 97 % of a
14
+ * traversal's wall time; the slots and their args buffer are gone). Two rules: a boundary that finds `done` set
15
+ * moves no counter word (the host records levels past the end); role 1 counts a two-phase level only when role 0
16
+ * chose one, which it reads from the path word (a storage write of one dispatch is visible to the next of the same
17
+ * pass).
16
18
  *
17
19
  * Roles 2 and 3 are the SSSP round boundary of the near-far loop (P8-T9, PD-20), over the same block read in its
18
20
  * SSSP sense (word 1 the raw near half's appends, 21 the raw far half's, 0 and 20 the deduped pile counts, 22 the
19
- * threshold, 23 the delta, 4 the previous threshold, 14 the round's mode) and the same seven slots: role 2 finds a
20
- * non-empty raw near half and sizes the near dedupe (slots 0 and 1, count word 1, output word 0) in mode 0; finds it
21
- * empty and the far half not, raises the threshold by the delta (one f32 add; an add that returns the threshold
21
+ * threshold, 23 the delta, 4 the previous threshold, 14 the round's mode): role 2 finds a non-empty raw near half
22
+ * and sizes the near dedupe (count word 1, output word 0; the dedupe's count in word 8) in mode 0; finds it empty
23
+ * and the far half not, raises the threshold by the delta (one f32 add; an add that returns the threshold
22
24
  * unchanged sets `done 3`, the host's E_UNSUPPORTED), remembers the previous threshold in word 4 and sizes the far
23
- * dedupe (slots 3 and 4, count word 21, output word 20) in mode 1; finds both empty and sets `done 1`; and finds a
24
- * raw half above the capacity and sets `done 2` (the host's E_TOO_LARGE). It counts a round in `level` when it
25
- * picks a mode and NOT at the done boundary, so `level` at the end is the number of relax rounds dispatched; a
26
- * boundary that finds `done` set obeys rule 1. Role 3 runs once the dedupe has landed: mode 0 sizes slot 2 (the
27
- * relax over nearIn) from word 0 and restarts the raw near half (word 1 to 0); mode 1 sizes slot 5 (the pass-through
28
- * over farIn) from word 20 and restarts the raw far half (word 21 to 0).
25
+ * dedupe (count word 21, output word 20; the dedupe's count in word 9) in mode 1; finds both empty and sets
26
+ * `done 1`; and finds a raw half above the capacity and sets `done 2` (the host's E_TOO_LARGE). It counts a round in
27
+ * `level` when it picks a mode and NOT at the done boundary, so `level` at the end is the number of relax rounds
28
+ * dispatched; a boundary that finds `done` set obeys rule 1. Role 3 runs once the dedupe has landed and restarts the
29
+ * raw half the round consumed: mode 0 restarts the raw near half (word 1 to 0), mode 1 the raw far half (word 21
30
+ * to 0); the relax kernels size themselves from words 0 and 20.
29
31
  *
30
32
  * Beamer's test (P8-T8, PD-21), evaluated at every boundary BEFORE the `done` branch (so a switch can be counted at
31
33
  * the done boundary too, which the host model of the tests mirrors): top-down switches to bottom-up when
@@ -46,14 +48,6 @@
46
48
  * overstated m_u makes the switch INTO bottom-up harder, never easier -- and the next submit's rebuild makes it
47
49
  * exact again. Body only (spec 3.5, D9); the text is normative: the sabotage rows of test/helpers/sabotage.ts are
48
50
  * textual edits of it.
49
- *
50
- * Since 2026-09-25 nothing dispatches FROM the slots (G8-F5: Dawn's validation of an indirect dispatch cost about
51
- * 0.4 ms of device time each, whether or not it dispatched anything, and the seven slots of thirty-two recorded
52
- * levels were 97 % of a traversal's wall time). Every level kernel is a direct grid-stride dispatch that reads the
53
- * `path` word (24) this kernel writes -- 0 nothing (done, or a level past the end), 1 two-phase, 2 fused, 3
54
- * bottom-up, 4 the fused retry (role 1), 5 a near SSSP round, 6 a far one (role 2) -- and the SSSP dedupes read
55
- * their counts from words 8 and 9, which role 2 writes. The slots stay as the selector's recorded decision, read
56
- * back by the frontier tests; deleting them with those tests is the follow-up.
57
51
  */
58
- export declare const frontierFinalizeWgsl = "\nfn write_slot_groups(slot: u32, groups: u32, count: u32) { // groups workgroups, split in 2D above the per-dim limit\n var x = groups;\n var y = 1u;\n if (groups > MAX_WORKGROUPS_PER_DIM) {\n x = MAX_WORKGROUPS_PER_DIM;\n y = (groups + MAX_WORKGROUPS_PER_DIM - 1u) / MAX_WORKGROUPS_PER_DIM;\n }\n let base = 4u * (P.slotBase + slot); // 16-byte slots: (x, y, 1, count)\n args[base] = x; args[base + 1u] = y; args[base + 2u] = 1u; args[base + 3u] = count;\n}\nfn write_slot(slot: u32, count: u32) { // one INVOCATION per entry: ceil(count / wg) workgroups\n let groups = count / P.wg + select(0u, 1u, count % P.wg != 0u); // ceil(count / wg) without the u32 wrap (indirect-finalize's rule)\n write_slot_groups(slot, groups, count);\n}\nfn zero_slot(slot: u32) {\n let base = 4u * (P.slotBase + slot);\n args[base] = 0u; args[base + 1u] = 0u; args[base + 2u] = 1u; args[base + 3u] = 0u;\n}\n\n@compute @workgroup_size(WG)\nfn frontier_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x != 0u) { return; } // one lane; no barrier follows (3.5 rule 1)\n if (P.role == 0u) { // the level boundary\n if (atomicLoad(&counters[15]) != 0u) { // done already: a no-op level the host recorded past the end\n for (var s = 0u; s < 7u; s = s + 1u) { zero_slot(s); } // this slotBase holds the previous submit's args\n return; // no counter word moves (P8-T6's levels formula reads them)\n }\n let finished = atomicLoad(&counters[0]);\n let next = atomicLoad(&counters[1]);\n let degSum = atomicLoad(&counters[2]);\n atomicStore(&counters[3], finished); // prevFrontierCount\n atomicStore(&counters[4], degSum); // prevDegreeSum\n atomicStore(&counters[0], next); // the rotation\n atomicStore(&counters[1], 0u);\n atomicStore(&counters[2], 0u);\n atomicStore(&counters[8], 0u); // edgeCount\n atomicStore(&counters[9], 0u); // edgeCountUnclamped\n atomicStore(&counters[12], atomicLoad(&counters[12]) + next); // visitedCount\n if (P.firstOfSubmit >= 1u) { // b = the boundary's index inside its submit, clamped to 2 (P8-T8, PD-18)\n atomicStore(&counters[5], atomicLoad(&counters[5]) - next); // unvisitedCount (exact): F_b was inside the submit's rebuilt sum iff b >= 1\n }\n if (P.firstOfSubmit >= 2u) {\n atomicStore(&counters[6], atomicLoad(&counters[6]) - degSum); // unvisitedDegreeSum (one level stale): F_{b-1} was inside it iff b >= 2\n }\n let level = atomicLoad(&counters[11]) + 1u; // the seed is U32_MAX, so the first boundary lands on 0\n atomicStore(&counters[11], level);\n let done = (next == 0u) || (level >= P.maxDepth);\n atomicStore(&counters[15], select(0u, 1u, done));\n var direction = atomicLoad(&counters[14]);\n if (P.mode == 1u) {\n direction = 0u; // top-down only (the test seam)\n } else if (direction == 0u) {\n if (degSum > atomicLoad(&counters[6]) / P.alpha && next > finished) { direction = 1u; } // m_f > m_u / alpha and growing\n } else {\n if (next * P.beta < atomicLoad(&counters[5]) && next < finished) { direction = 0u; } // next * beta < unvisited and shrinking\n }\n if (direction != atomicLoad(&counters[14])) { atomicStore(&counters[13], atomicLoad(&counters[13]) + 1u); } // switches\n var path = 0u; // word 24: what the level's kernels run (0 nothing, 1 two-phase, 2 fused, 3 bottom-up; role 1 writes 4 for the retry)\n if (done) {\n for (var s = 0u; s < 7u; s = s + 1u) { zero_slot(s); }\n } else if (direction == 1u) { // the bottom-up level (P8-T8): the bits fill, the bitset build, the sweep\n zero_slot(0u); zero_slot(1u); zero_slot(2u); zero_slot(6u);\n write_slot(3u, (P.n + 31u) / 32u); write_slot(4u, next); write_slot(5u, atomicLoad(&counters[7]));\n path = 3u;\n atomicStore(&counters[19], atomicLoad(&counters[19]) + 1u);\n } else if (next < P.fusedMax) { // P8-T7 makes this branch reachable (fusedMax is 0 until then)\n zero_slot(0u); zero_slot(1u); zero_slot(3u); zero_slot(4u); zero_slot(5u); zero_slot(6u);\n write_slot_groups(2u, next, next); // bfs-fused is one WORKGROUP per frontier entry\n path = 2u;\n atomicStore(&counters[17], atomicLoad(&counters[17]) + 1u);\n } else {\n zero_slot(2u); zero_slot(3u); zero_slot(4u); zero_slot(5u);\n write_slot(0u, next); // slots 1 and 6 are role 1's\n path = 1u;\n }\n atomicStore(&counters[14], direction);\n atomicStore(&counters[24], path);\n } else if (P.role == 1u) { // the edge queue is filled\n if (args[4u * P.slotBase] == 0u) { // role 0 did not choose the two-phase path (done, fused or bottom-up): nothing to size, nothing to count\n zero_slot(1u); zero_slot(6u);\n return;\n }\n let clamped = min(atomicLoad(&counters[8]), P.edgeCapacity);\n atomicStore(&counters[8], clamped);\n if (atomicLoad(&counters[9]) > P.edgeCapacity) { // PD-23: the fused retry\n let entries = atomicLoad(&counters[0]);\n zero_slot(1u); write_slot_groups(6u, entries, entries); // one workgroup per frontier entry, as slot 2\n atomicStore(&counters[24], 4u); // the path word: bfs-fused runs the retry, bfs-contract nothing\n atomicStore(&counters[10], atomicLoad(&counters[10]) + 1u);\n atomicStore(&counters[17], atomicLoad(&counters[17]) + 1u);\n } else {\n write_slot(1u, clamped); zero_slot(6u);\n atomicStore(&counters[18], atomicLoad(&counters[18]) + 1u); // twoPhaseLevels counts the CHOICE role 0 made, even for zero edges (P8-T7 Step 4's invariant)\n }\n } else if (P.role == 2u) { // the SSSP round boundary (P8-T9, PD-20): which pile this round relaxes\n atomicStore(&counters[8], 0u); // the dedupe counts (words 8 and 9, the SSSP sense) and the path word: nothing unless a pile is chosen below\n atomicStore(&counters[9], 0u);\n atomicStore(&counters[24], 0u);\n if (atomicLoad(&counters[15]) != 0u) { // done already: a no-op round the host recorded past the end (rule 1)\n for (var s = 0u; s < 7u; s = s + 1u) { zero_slot(s); }\n return;\n }\n let nearRaw = atomicLoad(&counters[1]); // the raw near half's appends, unclamped\n let farRaw = atomicLoad(&counters[21]); // the raw far half's appends, unclamped\n if (nearRaw > P.edgeCapacity || farRaw > P.edgeCapacity) { // a pile overflowed its half: the host raises E_TOO_LARGE\n atomicStore(&counters[15], 2u);\n for (var s = 0u; s < 7u; s = s + 1u) { zero_slot(s); }\n return;\n }\n zero_slot(2u); zero_slot(5u); zero_slot(6u); // role 3 sizes the relax slots once the piles are deduped\n if (nearRaw != 0u) { // a near round: dedupe the near half into nearIn\n atomicStore(&counters[0], 0u); // the deduped near count, accumulated by dedupe-filter\n atomicStore(&counters[14], 0u); // mode 0\n write_slot(0u, nearRaw); write_slot(1u, nearRaw); // dedupe-claim, dedupe-filter over the near half\n atomicStore(&counters[8], nearRaw); // the near dedupe's count word\n atomicStore(&counters[24], 5u); // the path word: sssp-relax role 0 runs, role 1 nothing\n zero_slot(3u); zero_slot(4u);\n atomicStore(&counters[11], atomicLoad(&counters[11]) + 1u); // rounds dispatched (the done boundary is not counted)\n } else if (farRaw != 0u) { // the near pile is empty: raise the threshold and re-bucket the far pile\n let threshold = bitcast<f32>(atomicLoad(&counters[22]));\n let raised = threshold + bitcast<f32>(atomicLoad(&counters[23])); // ONE f32 add on the bit patterns (PD-9)\n if (raised == threshold) { // the delta is below the threshold's ulp: the host raises E_UNSUPPORTED\n atomicStore(&counters[15], 3u);\n for (var s = 0u; s < 7u; s = s + 1u) { zero_slot(s); }\n return;\n }\n atomicStore(&counters[4], atomicLoad(&counters[22])); // prevThresholdBits: what the pass-through drops below\n atomicStore(&counters[22], bitcast<u32>(raised));\n atomicStore(&counters[20], 0u); // the deduped far count, accumulated by dedupe-filter\n atomicStore(&counters[14], 1u); // mode 1\n zero_slot(0u); zero_slot(1u);\n write_slot(3u, farRaw); write_slot(4u, farRaw); // dedupe-claim, dedupe-filter over the far half\n atomicStore(&counters[9], farRaw); // the far dedupe's count word\n atomicStore(&counters[24], 6u); // the path word: sssp-relax role 1 runs, role 0 nothing\n atomicStore(&counters[11], atomicLoad(&counters[11]) + 1u);\n } else { // both piles empty: finished\n atomicStore(&counters[15], 1u);\n for (var s = 0u; s < 7u; s = s + 1u) { zero_slot(s); }\n }\n } else if (P.role == 3u) { // the piles are deduped: size the relax\n if (atomicLoad(&counters[15]) != 0u) { return; } // role 2 zeroed every slot of the round\n if (atomicLoad(&counters[14]) == 0u) {\n write_slot(2u, atomicLoad(&counters[0])); // the near round over nearIn\n atomicStore(&counters[1], 0u); // the raw near half restarts\n } else {\n write_slot(5u, atomicLoad(&counters[20])); // the pass-through over farIn\n atomicStore(&counters[21], 0u); // the raw far half restarts (the pass-through re-appends what stays far)\n }\n }\n}\n";
52
+ export declare const frontierFinalizeWgsl = "\n@compute @workgroup_size(WG)\nfn frontier_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x != 0u) { return; } // one lane; no barrier follows (3.5 rule 1)\n if (P.role == 0u) { // the level boundary\n if (atomicLoad(&counters[15]) != 0u) { // done already: a no-op level the host recorded past the end\n atomicStore(&counters[24], 0u); // the path word is the only word that moves (P8-T6's levels formula reads the rest)\n return;\n }\n let finished = atomicLoad(&counters[0]);\n let next = atomicLoad(&counters[1]);\n let degSum = atomicLoad(&counters[2]);\n atomicStore(&counters[3], finished); // prevFrontierCount\n atomicStore(&counters[4], degSum); // prevDegreeSum\n atomicStore(&counters[0], next); // the rotation\n atomicStore(&counters[1], 0u);\n atomicStore(&counters[2], 0u);\n atomicStore(&counters[8], 0u); // edgeCount\n atomicStore(&counters[9], 0u); // edgeCountUnclamped\n atomicStore(&counters[12], atomicLoad(&counters[12]) + next); // visitedCount\n if (P.firstOfSubmit >= 1u) { // b = the boundary's index inside its submit, clamped to 2 (P8-T8, PD-18)\n atomicStore(&counters[5], atomicLoad(&counters[5]) - next); // unvisitedCount (exact): F_b was inside the submit's rebuilt sum iff b >= 1\n }\n if (P.firstOfSubmit >= 2u) {\n atomicStore(&counters[6], atomicLoad(&counters[6]) - degSum); // unvisitedDegreeSum (one level stale): F_{b-1} was inside it iff b >= 2\n }\n let level = atomicLoad(&counters[11]) + 1u; // the seed is U32_MAX, so the first boundary lands on 0\n atomicStore(&counters[11], level);\n let done = (next == 0u) || (level >= P.maxDepth);\n atomicStore(&counters[15], select(0u, 1u, done));\n var direction = atomicLoad(&counters[14]);\n if (P.mode == 1u) {\n direction = 0u; // top-down only (the test seam)\n } else if (direction == 0u) {\n if (degSum > atomicLoad(&counters[6]) / P.alpha && next > finished) { direction = 1u; } // m_f > m_u / alpha and growing\n } else {\n if (next * P.beta < atomicLoad(&counters[5]) && next < finished) { direction = 0u; } // next * beta < unvisited and shrinking\n }\n if (direction != atomicLoad(&counters[14])) { atomicStore(&counters[13], atomicLoad(&counters[13]) + 1u); } // switches\n var path = 0u; // word 24: what the level's kernels run (0 nothing, 1 two-phase, 2 fused, 3 bottom-up; role 1 writes 4 for the retry)\n if (done) {\n path = 0u;\n } else if (direction == 1u) { // the bottom-up level (P8-T8): the bits fill, the bitset build, the sweep\n path = 3u;\n atomicStore(&counters[19], atomicLoad(&counters[19]) + 1u);\n } else if (next < P.fusedMax) { // P8-T7 makes this branch reachable (fusedMax is 0 until then)\n path = 2u; // bfs-fused: one WORKGROUP per frontier entry\n atomicStore(&counters[17], atomicLoad(&counters[17]) + 1u);\n } else {\n path = 1u; // advance-expand, then role 1 and bfs-contract\n }\n atomicStore(&counters[14], direction);\n atomicStore(&counters[24], path);\n } else if (P.role == 1u) { // the edge queue is filled\n if (atomicLoad(&counters[24]) != 1u) { // role 0 did not choose the two-phase path (done, fused or bottom-up): nothing to clamp, nothing to count\n return;\n }\n let clamped = min(atomicLoad(&counters[8]), P.edgeCapacity);\n atomicStore(&counters[8], clamped);\n if (atomicLoad(&counters[9]) > P.edgeCapacity) { // PD-23: the fused retry\n atomicStore(&counters[24], 4u); // the path word: bfs-fused runs the retry over frontierCount, bfs-contract nothing\n atomicStore(&counters[10], atomicLoad(&counters[10]) + 1u);\n atomicStore(&counters[17], atomicLoad(&counters[17]) + 1u);\n } else {\n atomicStore(&counters[18], atomicLoad(&counters[18]) + 1u); // twoPhaseLevels counts the CHOICE role 0 made, even for zero edges (P8-T7 Step 4's invariant)\n }\n } else if (P.role == 2u) { // the SSSP round boundary (P8-T9, PD-20): which pile this round relaxes\n atomicStore(&counters[8], 0u); // the dedupe counts (words 8 and 9, the SSSP sense) and the path word: nothing unless a pile is chosen below\n atomicStore(&counters[9], 0u);\n atomicStore(&counters[24], 0u);\n if (atomicLoad(&counters[15]) != 0u) { // done already: a no-op round the host recorded past the end (rule 1)\n return;\n }\n let nearRaw = atomicLoad(&counters[1]); // the raw near half's appends, unclamped\n let farRaw = atomicLoad(&counters[21]); // the raw far half's appends, unclamped\n if (nearRaw > P.edgeCapacity || farRaw > P.edgeCapacity) { // a pile overflowed its half: the host raises E_TOO_LARGE\n atomicStore(&counters[15], 2u);\n return;\n }\n if (nearRaw != 0u) { // a near round: dedupe the near half into nearIn\n atomicStore(&counters[0], 0u); // the deduped near count, accumulated by dedupe-filter\n atomicStore(&counters[14], 0u); // mode 0\n atomicStore(&counters[8], nearRaw); // the near dedupe's count word (dedupe-claim, dedupe-filter over the near half)\n atomicStore(&counters[24], 5u); // the path word: sssp-relax role 0 runs, role 1 nothing\n atomicStore(&counters[11], atomicLoad(&counters[11]) + 1u); // rounds dispatched (the done boundary is not counted)\n } else if (farRaw != 0u) { // the near pile is empty: raise the threshold and re-bucket the far pile\n let threshold = bitcast<f32>(atomicLoad(&counters[22]));\n let raised = threshold + bitcast<f32>(atomicLoad(&counters[23])); // ONE f32 add on the bit patterns (PD-9)\n if (raised == threshold) { // the delta is below the threshold's ulp: the host raises E_UNSUPPORTED\n atomicStore(&counters[15], 3u);\n return;\n }\n atomicStore(&counters[4], atomicLoad(&counters[22])); // prevThresholdBits: what the pass-through drops below\n atomicStore(&counters[22], bitcast<u32>(raised));\n atomicStore(&counters[20], 0u); // the deduped far count, accumulated by dedupe-filter\n atomicStore(&counters[14], 1u); // mode 1\n atomicStore(&counters[9], farRaw); // the far dedupe's count word (dedupe-claim, dedupe-filter over the far half)\n atomicStore(&counters[24], 6u); // the path word: sssp-relax role 1 runs, role 0 nothing\n atomicStore(&counters[11], atomicLoad(&counters[11]) + 1u);\n } else { // both piles empty: finished\n atomicStore(&counters[15], 1u);\n }\n } else if (P.role == 3u) { // the piles are deduped: restart the raw half the round consumed\n if (atomicLoad(&counters[15]) != 0u) { return; } // role 2 chose no pile this round\n if (atomicLoad(&counters[14]) == 0u) {\n atomicStore(&counters[1], 0u); // the raw near half restarts (sssp-relax role 0 sizes itself from word 0)\n } else {\n atomicStore(&counters[21], 0u); // the raw far half restarts (the pass-through re-appends what stays far; role 1 sizes itself from word 20)\n }\n }\n}\n";
59
53
  //# sourceMappingURL=frontier-finalize.wgsl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontier-finalize.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/frontier-finalize.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,eAAO,MAAM,oBAAoB,0mWAuJhC,CAAC"}
1
+ {"version":3,"file":"frontier-finalize.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/frontier-finalize.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,eAAO,MAAM,oBAAoB,spRA+GhC,CAAC"}