@graphty/webgpu-graph-algorithms 0.6.3 → 0.6.4

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 (167) hide show
  1. package/README.md +62 -32
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{context-BXqgCifx.js → context-Dvq-Cc6v.js} +71 -25
  4. package/dist/chunks/context-Dvq-Cc6v.js.map +1 -0
  5. package/dist/node.js +1 -1
  6. package/dist/src/accelerator.d.ts +8 -6
  7. package/dist/src/accelerator.d.ts.map +1 -1
  8. package/dist/src/accelerator.js +57 -6
  9. package/dist/src/accelerator.js.map +1 -1
  10. package/dist/src/algorithms/bellman-ford.d.ts +60 -0
  11. package/dist/src/algorithms/bellman-ford.d.ts.map +1 -0
  12. package/dist/src/algorithms/bellman-ford.js +301 -0
  13. package/dist/src/algorithms/bellman-ford.js.map +1 -0
  14. package/dist/src/algorithms/bfs.d.ts +67 -0
  15. package/dist/src/algorithms/bfs.d.ts.map +1 -0
  16. package/dist/src/algorithms/bfs.js +534 -0
  17. package/dist/src/algorithms/bfs.js.map +1 -0
  18. package/dist/src/algorithms/closeness.d.ts +53 -0
  19. package/dist/src/algorithms/closeness.d.ts.map +1 -0
  20. package/dist/src/algorithms/closeness.js +323 -0
  21. package/dist/src/algorithms/closeness.js.map +1 -0
  22. package/dist/src/algorithms/scope.d.ts +5 -3
  23. package/dist/src/algorithms/scope.d.ts.map +1 -1
  24. package/dist/src/algorithms/scope.js +3 -0
  25. package/dist/src/algorithms/scope.js.map +1 -1
  26. package/dist/src/algorithms/sssp.d.ts +71 -0
  27. package/dist/src/algorithms/sssp.d.ts.map +1 -0
  28. package/dist/src/algorithms/sssp.js +585 -0
  29. package/dist/src/algorithms/sssp.js.map +1 -0
  30. package/dist/src/constants.d.ts +12 -0
  31. package/dist/src/constants.d.ts.map +1 -1
  32. package/dist/src/constants.js +12 -0
  33. package/dist/src/constants.js.map +1 -1
  34. package/dist/src/index.d.ts +8 -2
  35. package/dist/src/index.d.ts.map +1 -1
  36. package/dist/src/index.js +7 -1
  37. package/dist/src/index.js.map +1 -1
  38. package/dist/src/kernel/prelude.d.ts +4 -4
  39. package/dist/src/kernel/prelude.d.ts.map +1 -1
  40. package/dist/src/kernel/prelude.js +39 -5
  41. package/dist/src/kernel/prelude.js.map +1 -1
  42. package/dist/src/kernel/uniform-ring.d.ts +8 -0
  43. package/dist/src/kernel/uniform-ring.d.ts.map +1 -1
  44. package/dist/src/kernel/uniform-ring.js +13 -0
  45. package/dist/src/kernel/uniform-ring.js.map +1 -1
  46. package/dist/src/kernels.d.ts +44 -4
  47. package/dist/src/kernels.d.ts.map +1 -1
  48. package/dist/src/kernels.js +371 -3
  49. package/dist/src/kernels.js.map +1 -1
  50. package/dist/src/primitives/advance.d.ts +62 -0
  51. package/dist/src/primitives/advance.d.ts.map +1 -0
  52. package/dist/src/primitives/advance.js +95 -0
  53. package/dist/src/primitives/advance.js.map +1 -0
  54. package/dist/src/primitives/compact.d.ts +89 -0
  55. package/dist/src/primitives/compact.d.ts.map +1 -0
  56. package/dist/src/primitives/compact.js +233 -0
  57. package/dist/src/primitives/compact.js.map +1 -0
  58. package/dist/src/primitives/core-shape.d.ts +22 -1
  59. package/dist/src/primitives/core-shape.d.ts.map +1 -1
  60. package/dist/src/primitives/core-shape.js +33 -3
  61. package/dist/src/primitives/core-shape.js.map +1 -1
  62. package/dist/src/primitives/frontier.d.ts +156 -0
  63. package/dist/src/primitives/frontier.d.ts.map +1 -0
  64. package/dist/src/primitives/frontier.js +259 -0
  65. package/dist/src/primitives/frontier.js.map +1 -0
  66. package/dist/src/types/accelerator.d.ts +16 -7
  67. package/dist/src/types/accelerator.d.ts.map +1 -1
  68. package/dist/src/types/traversal.d.ts +53 -0
  69. package/dist/src/types/traversal.d.ts.map +1 -0
  70. package/dist/src/types/traversal.js +10 -0
  71. package/dist/src/types/traversal.js.map +1 -0
  72. package/dist/src/wgsl/advance-expand.wgsl.d.ts +19 -0
  73. package/dist/src/wgsl/advance-expand.wgsl.d.ts.map +1 -0
  74. package/dist/src/wgsl/advance-expand.wgsl.js +69 -0
  75. package/dist/src/wgsl/advance-expand.wgsl.js.map +1 -0
  76. package/dist/src/wgsl/bf-relax.wgsl.d.ts +22 -0
  77. package/dist/src/wgsl/bf-relax.wgsl.d.ts.map +1 -0
  78. package/dist/src/wgsl/bf-relax.wgsl.js +58 -0
  79. package/dist/src/wgsl/bf-relax.wgsl.js.map +1 -0
  80. package/dist/src/wgsl/bfs-bitset-build.wgsl.d.ts +15 -0
  81. package/dist/src/wgsl/bfs-bitset-build.wgsl.d.ts.map +1 -0
  82. package/dist/src/wgsl/bfs-bitset-build.wgsl.js +24 -0
  83. package/dist/src/wgsl/bfs-bitset-build.wgsl.js.map +1 -0
  84. package/dist/src/wgsl/bfs-bottom-up.wgsl.d.ts +20 -0
  85. package/dist/src/wgsl/bfs-bottom-up.wgsl.d.ts.map +1 -0
  86. package/dist/src/wgsl/bfs-bottom-up.wgsl.js +67 -0
  87. package/dist/src/wgsl/bfs-bottom-up.wgsl.js.map +1 -0
  88. package/dist/src/wgsl/bfs-contract.wgsl.d.ts +20 -0
  89. package/dist/src/wgsl/bfs-contract.wgsl.d.ts.map +1 -0
  90. package/dist/src/wgsl/bfs-contract.wgsl.js +55 -0
  91. package/dist/src/wgsl/bfs-contract.wgsl.js.map +1 -0
  92. package/dist/src/wgsl/bfs-fused.wgsl.d.ts +25 -0
  93. package/dist/src/wgsl/bfs-fused.wgsl.d.ts.map +1 -0
  94. package/dist/src/wgsl/bfs-fused.wgsl.js +78 -0
  95. package/dist/src/wgsl/bfs-fused.wgsl.js.map +1 -0
  96. package/dist/src/wgsl/bfs-unvisited-flags.wgsl.d.ts +18 -0
  97. package/dist/src/wgsl/bfs-unvisited-flags.wgsl.d.ts.map +1 -0
  98. package/dist/src/wgsl/bfs-unvisited-flags.wgsl.js +42 -0
  99. package/dist/src/wgsl/bfs-unvisited-flags.wgsl.js.map +1 -0
  100. package/dist/src/wgsl/closeness-reduce.wgsl.d.ts +17 -0
  101. package/dist/src/wgsl/closeness-reduce.wgsl.d.ts.map +1 -0
  102. package/dist/src/wgsl/closeness-reduce.wgsl.js +65 -0
  103. package/dist/src/wgsl/closeness-reduce.wgsl.js.map +1 -0
  104. package/dist/src/wgsl/closeness-sweep.wgsl.d.ts +20 -0
  105. package/dist/src/wgsl/closeness-sweep.wgsl.d.ts.map +1 -0
  106. package/dist/src/wgsl/closeness-sweep.wgsl.js +96 -0
  107. package/dist/src/wgsl/closeness-sweep.wgsl.js.map +1 -0
  108. package/dist/src/wgsl/compact-scatter.wgsl.d.ts +9 -0
  109. package/dist/src/wgsl/compact-scatter.wgsl.d.ts.map +1 -0
  110. package/dist/src/wgsl/compact-scatter.wgsl.js +17 -0
  111. package/dist/src/wgsl/compact-scatter.wgsl.js.map +1 -0
  112. package/dist/src/wgsl/dedupe-claim.wgsl.d.ts +10 -0
  113. package/dist/src/wgsl/dedupe-claim.wgsl.d.ts.map +1 -0
  114. package/dist/src/wgsl/dedupe-claim.wgsl.js +19 -0
  115. package/dist/src/wgsl/dedupe-claim.wgsl.js.map +1 -0
  116. package/dist/src/wgsl/dedupe-filter.wgsl.d.ts +12 -0
  117. package/dist/src/wgsl/dedupe-filter.wgsl.d.ts.map +1 -0
  118. package/dist/src/wgsl/dedupe-filter.wgsl.js +46 -0
  119. package/dist/src/wgsl/dedupe-filter.wgsl.js.map +1 -0
  120. package/dist/src/wgsl/frontier-finalize.wgsl.d.ts +59 -0
  121. package/dist/src/wgsl/frontier-finalize.wgsl.d.ts.map +1 -0
  122. package/dist/src/wgsl/frontier-finalize.wgsl.js +210 -0
  123. package/dist/src/wgsl/frontier-finalize.wgsl.js.map +1 -0
  124. package/dist/src/wgsl/sssp-pred.wgsl.d.ts +28 -0
  125. package/dist/src/wgsl/sssp-pred.wgsl.d.ts.map +1 -0
  126. package/dist/src/wgsl/sssp-pred.wgsl.js +80 -0
  127. package/dist/src/wgsl/sssp-pred.wgsl.js.map +1 -0
  128. package/dist/src/wgsl/sssp-relax.wgsl.d.ts +30 -0
  129. package/dist/src/wgsl/sssp-relax.wgsl.d.ts.map +1 -0
  130. package/dist/src/wgsl/sssp-relax.wgsl.js +72 -0
  131. package/dist/src/wgsl/sssp-relax.wgsl.js.map +1 -0
  132. package/dist/webgpu-graph-algorithms.js +3207 -377
  133. package/dist/webgpu-graph-algorithms.js.map +1 -1
  134. package/package.json +5 -4
  135. package/src/accelerator.ts +65 -7
  136. package/src/algorithms/bellman-ford.ts +387 -0
  137. package/src/algorithms/bfs.ts +626 -0
  138. package/src/algorithms/closeness.ts +395 -0
  139. package/src/algorithms/scope.ts +13 -3
  140. package/src/algorithms/sssp.ts +767 -0
  141. package/src/constants.ts +12 -0
  142. package/src/index.ts +14 -1
  143. package/src/kernel/prelude.ts +39 -4
  144. package/src/kernel/uniform-ring.ts +14 -0
  145. package/src/kernels.ts +450 -6
  146. package/src/primitives/advance.ts +130 -0
  147. package/src/primitives/compact.ts +323 -0
  148. package/src/primitives/core-shape.ts +41 -3
  149. package/src/primitives/frontier.ts +388 -0
  150. package/src/types/accelerator.ts +18 -5
  151. package/src/types/traversal.ts +56 -0
  152. package/src/wgsl/advance-expand.wgsl.ts +68 -0
  153. package/src/wgsl/bf-relax.wgsl.ts +57 -0
  154. package/src/wgsl/bfs-bitset-build.wgsl.ts +23 -0
  155. package/src/wgsl/bfs-bottom-up.wgsl.ts +66 -0
  156. package/src/wgsl/bfs-contract.wgsl.ts +54 -0
  157. package/src/wgsl/bfs-fused.wgsl.ts +77 -0
  158. package/src/wgsl/bfs-unvisited-flags.wgsl.ts +41 -0
  159. package/src/wgsl/closeness-reduce.wgsl.ts +64 -0
  160. package/src/wgsl/closeness-sweep.wgsl.ts +95 -0
  161. package/src/wgsl/compact-scatter.wgsl.ts +16 -0
  162. package/src/wgsl/dedupe-claim.wgsl.ts +18 -0
  163. package/src/wgsl/dedupe-filter.wgsl.ts +45 -0
  164. package/src/wgsl/frontier-finalize.wgsl.ts +209 -0
  165. package/src/wgsl/sssp-pred.wgsl.ts +79 -0
  166. package/src/wgsl/sssp-relax.wgsl.ts +71 -0
  167. package/dist/chunks/context-BXqgCifx.js.map +0 -1
@@ -0,0 +1,534 @@
1
+ /**
2
+ * Breadth-first search on the device (design 8.4, 3.3 line 807, 9.7; P8-T6 / P8-T7 / P8-T8, the P8 plan's PD-5 /
3
+ * PD-6 / PD-7 / PD-14 / PD-18 / PD-21 / PD-23 / PD-24 / PD-26 / DEP-P8-B): the direction-optimizing traversal over
4
+ * the `Frontier` of P8-T4, every per-level choice made ON THE DEVICE. Every level is eight recorded dispatches, all
5
+ * DIRECT (2026-09-25, docs/decisions/G8.md G8-F5: Dawn validates every `dispatchWorkgroupsIndirect` with an internal
6
+ * clamp pass costing about 0.4 ms of device time whether or not it dispatches anything, in Node and in Chromium
7
+ * alike, and that was 97 % of a traversal's wall time) -- `frontier-finalize` role 0 (the level boundary: rotates
8
+ * the counts, advances `level`, decides `done`, evaluates Beamer's test and CHOOSES, writing the choice into the
9
+ * block's `path` word: 3 bottom-up, 2 fused for a top-down frontier below `fusedMax` entries, 1 two-phase for any
10
+ * other, 0 done), `advance-expand` (the frontier's rows into the edge queue), `frontier-finalize` role 1 (clamps
11
+ * `edgeCount`, or, when the edge queue overflowed, sets `path` 4 for the fused retry, PD-23), `bfs-contract` (the
12
+ * claim `atomicMin(&depth[v], level + 1)`, the winners packed into the next vertex queue), `bfs-fused` (one workgroup
13
+ * per frontier entry with the same claim inline and no edge queue; the fused level and the retry alike), then the
14
+ * bottom-up trio: a `fill` zeroing the frontier bitset, `bfs-bitset-build` setting the frontier's bits, and
15
+ * `bfs-bottom-up` sweeping the unvisited list over the REVERSE core (each unvisited vertex reads its in-neighbours
16
+ * until the first one in the bitset and claims itself). Every kernel is a grid-stride dispatch of a host-planned
17
+ * grid (`planGridStride`) that loops to its count word and reads the path word first, so exactly one path does the
18
+ * level's work and the others cost one uniform load per workgroup. The unvisited set Beamer's test is against (PD-18) is rebuilt exactly once per submit, before
19
+ * the levels, by `bfs-unvisited-flags` plus `compact` over an iota queue, and maintained between rebuilds by
20
+ * subtraction inside the selector (whose JSDoc states the boundary rule). The host records `MAX_LEVELS_PER_SUBMIT`
21
+ * levels into ONE command buffer, submits, and reads four bytes, the `done` word (PD-7): a road network has
22
+ * thousands of levels and a per-level `mapAsync` would be slower than the CPU. A level recorded past the end is a
23
+ * no-op (its boundary finds `done` set, zeroes its slots and moves no counter), so the loop needs no diameter and
24
+ * ends on `done`; a traversal has at most `n` levels, so more submits than that is E_VALIDATION, never a hang. The
25
+ * thresholds are uniform fields (`FUSED_FRONTIER_MAX`; alpha derived as `max(1, floor(arcCount / n))`, PD-21;
26
+ * `BEAMER_BETA`; `mode 1` pinning top-down -- each unless the tuning says otherwise), so a test forces any path
27
+ * without recompiling; the block's `fusedLevels` / `twoPhaseLevels` / `bottomUpLevels` / `overflowLevels` /
28
+ * `switches` words record which path each level took.
29
+ *
30
+ * There is no dedupe (DEP-P8-B, PD-5): the edge queue holds duplicates -- a vertex with three frontier neighbours
31
+ * appears three times -- but for one level exactly one invocation observes `INVALID_INDEX` at `depth[v]` and
32
+ * exactly that one appends `v`, so the next vertex frontier is duplicate-free by construction and an ownership
33
+ * dedupe would have nothing to remove. `parent` is not written by the claim (PD-24): `sssp-pred` in `MODE 1` runs
34
+ * once over the settled depths and writes the SMALLEST `u` with `depth[u] + 1 == depth[v]` and an arc `u -> v`, so
35
+ * it is bitwise reproducible where a claim-time parent would be a scheduling accident. `order` (PD-14) is one
36
+ * stable radix sort of the node indices by `depth`: grouped by level, ascending by index within a level,
37
+ * `INVALID_INDEX` last, and the first `visitedCount` values are the result. The result batch stages every array
38
+ * into one staging slot, so a traversal maps `ceil(levels / 32) + 1` buffers in all.
39
+ *
40
+ * `maxDepth` reaches the device as a `u32` field of `FrontierParams`, and the uniform writer refuses anything that
41
+ * is not an integer in `[0, 2^32 - 1]`; the host therefore normalises it first, to exactly the CPU port's rule
42
+ * (`algorithms/src/indexed/bfs.ts`: a node at depth `d >= maxDepth` is reached and not expanded, unbounded when
43
+ * absent). The tuning entry `bfsWithTuning` (PD-26) is what the tests drive; nothing public exposes it.
44
+ *
45
+ * A core whose `colIdx` exceeds `maxStorageBufferBindingSize` is bound as arc windows and EXECUTED (P8-T12, DEP-P8-E
46
+ * lifted for the frontier family): `advance-expand`, `bfs-fused` and `sssp-pred` run once per window of the
47
+ * forward core and `bfs-bottom-up` once per window of the reverse core, every window its own dispatch with its own
48
+ * `FrontierParams` record carrying the window's owned arc range (`coreWindows`), and the claims, being `atomicMin`s
49
+ * and an `INVALID_INDEX` entry test, are idempotent across windows. The ring is sized per run by `bfsRingSlots`.
50
+ */
51
+ import { INVALID_INDEX } from "@graphty/graph-format";
52
+ import { BEAMER_BETA, FUSED_FRONTIER_MAX, MAX_LEVELS_PER_SUBMIT, U32_MAX } from "../constants.js";
53
+ import { WebGpuGraphError } from "../errors.js";
54
+ import { CommandBatch } from "../kernel/batch.js";
55
+ import { plan1d, planGridStride } from "../kernel/dispatch.js";
56
+ import { FILL_PARAMS, FRONTIER_COUNTERS, FRONTIER_PARAMS, graphBindings, graphOverrides, kernelSpec, } from "../kernels.js";
57
+ import { prepareAdvance } from "../primitives/advance.js";
58
+ import { prepareCompact } from "../primitives/compact.js";
59
+ import { coreOfView, coreWindows } from "../primitives/core-shape.js";
60
+ import { prepareFrontier, W } from "../primitives/frontier.js";
61
+ import { prepareRadixSort, radixHistBytes } from "../primitives/radix-sort.js";
62
+ import { assertDeviceComputes } from "../primitives/verify.js";
63
+ import { algorithmScope } from "./scope.js";
64
+ const ALGORITHM = "breadthFirstSearch";
65
+ /**
66
+ * Params slots of the ring, COUNTED per run (P8-T12), because `UniformRing.reserve` wraps to slot 0 when a submit's
67
+ * records outrun the ring and silently overwrites a record the submit still reads; the ring's `overruns` counts
68
+ * exactly that reuse, `AlgorithmScope.ringOverruns()` exposes it, and the faked-limit test holds it at 0 for the
69
+ * whole run. The bound per level is `5 + 4 x windows`: five recorded once per level (`frontier-finalize` twice,
70
+ * `bfs-contract`, the bits `fill`, `bfs-bitset-build`) and four re-issued once per arc window (`advance-expand`,
71
+ * `bfs-fused`, the fused retry, `bfs-bottom-up`). The driver as built writes fewer -- the contract and the bitset
72
+ * build share one window-free record, a window's two fused dispatches share one, the bits fill has one record per
73
+ * submit, and a directed snapshot's reverse view is one window whatever the forward core's count -- so at most
74
+ * `3 + 3 x windows` per level, and the bound holds with room. The 16 covers the per-submit rebuild
75
+ * (`bfs-unvisited-flags` and `compact`, whose scan is at most 9 dispatches for any n below 2^32, so 10, plus the
76
+ * bits fill). The result batch flushes in its own submit, so the ring must hold IT too, and its size grows with `n`,
77
+ * not with the cadence: the iota `fill`, the radix sort's four passes of one record plus its scan's `2 x levels - 1`
78
+ * (the table is `256 x ceil(n / WG)` words and a level covers `WG` of them, so four levels for any n below 2^32 at
79
+ * the package's WG of 256), the `pred` `fill` and `sssp-pred` once per window -- `2 + 4 x 8 + windows = 34 + windows`
80
+ * at most, which a small cadence undercuts (built 2026-09-25: `(5 + 4) x 1 + 16 = 25` slots against the 27 a
81
+ * 262,143-node result batch records wrapped over the radix sort's own records and returned a wrong `order`, silently
82
+ * -- the plan's `19 + windows` count had no scan level in it). The slot count is therefore the larger of the two
83
+ * batches. At one window and `MAX_LEVELS_PER_SUBMIT` it is P8-T6's 304; test/device/constants.test.ts pins the
84
+ * arithmetic.
85
+ * @internal
86
+ * @param windows - the forward core's arc windows (1 when it is not windowed)
87
+ * @param levelsPerSubmit - the levels recorded per submit
88
+ * @returns the ring's slot count
89
+ */
90
+ export function bfsRingSlots(windows, levelsPerSubmit) {
91
+ return Math.max((5 + 4 * windows) * levelsPerSubmit + 16, RESULT_BATCH_SLOTS + windows);
92
+ }
93
+ /** The result batch's records before its per-window `sssp-pred` dispatches: two `fill`s and the 32-bit radix sort's four passes of at most eight records each (see `bfsRingSlots`). */
94
+ const RESULT_BATCH_SLOTS = 2 + 4 * 8;
95
+ /**
96
+ * The CPU port's `maxDepth` as a `u32`: `U32_MAX` (no cap) when absent, `NaN` (`d >= NaN` never holds) or at or
97
+ * above `U32_MAX` (which covers `Infinity`); otherwise `max(0, ceil(maxDepth))` -- `2.5` behaves as 3 because
98
+ * `d >= 2.5` first holds at `d == 3`, and a negative value gives 0, the source alone, because `0 >= -1` already holds.
99
+ * @param maxDepth - the caller's option
100
+ * @returns the value the uniform carries
101
+ */
102
+ function normaliseMaxDepth(maxDepth) {
103
+ if (maxDepth === undefined || Number.isNaN(maxDepth) || maxDepth >= U32_MAX) {
104
+ return U32_MAX;
105
+ }
106
+ return Math.max(0, Math.ceil(maxDepth));
107
+ }
108
+ /**
109
+ * Validates `options.dest` for a depth result of `n` elements.
110
+ * @param dest - the caller's destination array, if any
111
+ * @param n - the node count
112
+ * @returns the destination as a U32, or null when none was given
113
+ */
114
+ function checkDest(dest, n) {
115
+ if (dest === undefined) {
116
+ return null;
117
+ }
118
+ if (dest instanceof Uint32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {
119
+ return dest;
120
+ }
121
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${ALGORITHM}: dest must be a Uint32Array of length ${n} over an ArrayBuffer`, {
122
+ argument: "dest",
123
+ value: `${dest.constructor.name}(${dest.length})`,
124
+ expected: `Uint32Array(${n}) over an ArrayBuffer`,
125
+ });
126
+ }
127
+ /**
128
+ * Whole-buffer binding of a scratch buffer over its first `size` bytes.
129
+ * @param buffer - the buffer
130
+ * @param size - the bound byte length
131
+ * @returns the binding
132
+ */
133
+ function bindingOf(buffer, size) {
134
+ return { buffer, offset: 0, size, window: null };
135
+ }
136
+ /**
137
+ * A degree view's one array on the device (the `outDegree` / `inDegree` views of P7, one u32 per vertex).
138
+ * @param ctx - the context
139
+ * @param s - the snapshot
140
+ * @param name - the view
141
+ * @returns the binding
142
+ */
143
+ function degreeView(ctx, s, name) {
144
+ const { bindings } = ctx.residency.view(s, name);
145
+ const { [name]: binding } = bindings;
146
+ if (binding === undefined) {
147
+ throw new WebGpuGraphError("E_VALIDATION", `${ALGORITHM}: the ${name} view has no ${name} binding`, {
148
+ label: `${ALGORITHM}/${name}`,
149
+ message: `the ${name} view has no ${name} binding`,
150
+ });
151
+ }
152
+ return binding;
153
+ }
154
+ /**
155
+ * The E_ABORTED error of a signal.
156
+ * @param batchId - the last submitted batch, when one exists
157
+ * @returns the error
158
+ */
159
+ function aborted(batchId) {
160
+ return new WebGpuGraphError("E_ABORTED", `${ALGORITHM}: the signal was aborted`, batchId === undefined ? {} : { batchId });
161
+ }
162
+ /**
163
+ * One scalar word of a decoded block (every FrontierCounters field is a u32, so anything else is a decoder bug).
164
+ * @param block - the decoded block
165
+ * @param name - the field
166
+ * @returns the word
167
+ */
168
+ function wordOf(block, name) {
169
+ const value = block[name];
170
+ if (typeof value !== "number") {
171
+ throw new WebGpuGraphError("E_VALIDATION", `${ALGORITHM}: counters.${name} did not decode to a number`, {
172
+ label: `${ALGORITHM}/counters`,
173
+ message: `the field ${name} did not decode to a number`,
174
+ });
175
+ }
176
+ return value;
177
+ }
178
+ /**
179
+ * Breadth-first search with the test knobs of PD-26; `breadthFirstSearch` is this with an empty tuning.
180
+ * @internal
181
+ * @param ctx - the context whose device runs the kernels
182
+ * @param s - the snapshot (uploaded through ctx.residency, or found there)
183
+ * @param source - the source node index
184
+ * @param options - `maxDepth`, plus dest / signal / onProgress
185
+ * @param tuning - the knobs
186
+ * @returns the depths, parents, order, visited count, level count and switches
187
+ */
188
+ export async function bfsWithTuning(ctx, s, source, options, tuning) {
189
+ ctx.assertReady();
190
+ await assertDeviceComputes(ctx);
191
+ const n = s.nodeCount;
192
+ if (!Number.isInteger(source) || source < 0 || source >= n) {
193
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${ALGORITHM}: source ${source} is outside [0, ${n})`, {
194
+ argument: "source",
195
+ value: source,
196
+ expected: `an integer in [0, ${n})`,
197
+ });
198
+ }
199
+ const levelsPerSubmit = tuning.levelsPerSubmit ?? MAX_LEVELS_PER_SUBMIT;
200
+ if (!Number.isInteger(levelsPerSubmit) || levelsPerSubmit < 1 || levelsPerSubmit > MAX_LEVELS_PER_SUBMIT) {
201
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${ALGORITHM}: levelsPerSubmit must be an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`, {
202
+ argument: "levelsPerSubmit",
203
+ value: levelsPerSubmit,
204
+ expected: `an integer in [1, ${MAX_LEVELS_PER_SUBMIT}]`,
205
+ });
206
+ }
207
+ const dest = checkDest(options?.dest, n);
208
+ const maxDepth = normaliseMaxDepth(options?.maxDepth);
209
+ const predKind = tuning.predKind ?? 1;
210
+ if (options?.signal?.aborted) {
211
+ throw aborted();
212
+ }
213
+ const core = ctx.residency.core(s);
214
+ // a windowed core (colIdx above the binding limit) is executed, not refused (P8-T12 lifts DEP-P8-E): every
215
+ // frontier-walking kernel is dispatched once per arc window with the window's owned range in its record
216
+ const forward = coreWindows(core);
217
+ // the bottom-up sweep walks in-neighbours over the reverse core: on an undirected snapshot the forward arrays
218
+ // themselves (graph-format invariant I7; P7's residency aliases them, so a windowed core's windows ARE the
219
+ // reverse's), on a directed one the reverse VIEW, which spec 4.3 never windows -- so a directed snapshot whose
220
+ // reverse adjacency exceeds one binding is refused here, as the residency refuses the undirected view, instead
221
+ // of failing at the device's bind-group validation
222
+ if (s.directed && 4 * s.arcCount > ctx.caps.limits.maxStorageBufferBindingSize) {
223
+ throw new WebGpuGraphError("E_TOO_LARGE", `${ALGORITHM}: the reverse adjacency of a directed snapshot (${4 * s.arcCount} bytes) needs arc windows, which no view executes (spec 4.3); the bottom-up sweep binds it whole`, {
224
+ needed: 4 * s.arcCount,
225
+ limit: ctx.caps.limits.maxStorageBufferBindingSize,
226
+ path: "windowed",
227
+ algorithm: ALGORITHM,
228
+ });
229
+ }
230
+ const reverse = s.directed ? coreOfView(ctx.residency.view(s, "reverse"), s.arcCount) : core;
231
+ const backward = coreWindows(reverse);
232
+ // the two degree views the unvisited rebuild reads (P8-T8)
233
+ const outDegree = degreeView(ctx, s, "outDegree");
234
+ const inDegree = degreeView(ctx, s, "inDegree");
235
+ const scope = algorithmScope(ctx, ALGORITHM, bfsRingSlots(forward.length, levelsPerSubmit));
236
+ tuning.onScope?.(scope);
237
+ try {
238
+ const bytes = 4 * n;
239
+ const wg = ctx.workgroupSize;
240
+ const depth = bindingOf(scope.scratch(bytes, "depth"), bytes);
241
+ // the sweep's input, one buffer in two regions: the unvisited list at word 0 and the frontier bitset at
242
+ // word bitsBase = roundUp(n, 64), so the bits region's byte offset is 256-aligned and fill can bind it alone
243
+ const bitsBase = Math.ceil(n / 64) * 64;
244
+ const bitsWords = Math.ceil(n / 32);
245
+ const sweepBytes = 4 * (bitsBase + bitsWords);
246
+ const sweepIn = bindingOf(scope.scratch(sweepBytes, "sweep-in"), sweepBytes);
247
+ const unvisitedList = { buffer: sweepIn.buffer, offset: 0, size: bytes, window: null };
248
+ const frontierBits = {
249
+ buffer: sweepIn.buffer,
250
+ offset: 4 * bitsBase,
251
+ size: 4 * bitsWords,
252
+ window: null,
253
+ };
254
+ const flags = bindingOf(scope.scratch(bytes, "unvisited-flags"), bytes);
255
+ const iota = bindingOf(scope.scratch(bytes, "iota"), bytes);
256
+ const compactCount = bindingOf(scope.scratch(4, "compact-count"), 4);
257
+ await ctx.allocator.check();
258
+ const planner = await prepareFrontier(scope, n, s.arcCount, tuning.edgeCapacity);
259
+ const advance = await prepareAdvance(scope, core);
260
+ const compact = await prepareCompact(scope);
261
+ const contract = await ctx.pipelines.kernel(kernelSpec("bfs-contract"));
262
+ const fused = await ctx.pipelines.kernel(kernelSpec("bfs-fused", graphOverrides(core, null)));
263
+ const bitset = await ctx.pipelines.kernel(kernelSpec("bfs-bitset-build"));
264
+ const bottomUp = await ctx.pipelines.kernel(kernelSpec("bfs-bottom-up", graphOverrides(reverse, null)));
265
+ const unvisited = await ctx.pipelines.kernel(kernelSpec("bfs-unvisited-flags"));
266
+ const pred = await ctx.pipelines.kernel(kernelSpec("sssp-pred", { ...graphOverrides(core, null), MODE: 1 }));
267
+ const fill = await ctx.pipelines.kernel(kernelSpec("fill"));
268
+ const sort = await prepareRadixSort(scope);
269
+ const { frontier } = planner;
270
+ const { counters } = frontier;
271
+ const { queue } = ctx.device;
272
+ const fillPlan = plan1d(n, wg, ctx.caps);
273
+ // the level kernels are DIRECT grid-stride dispatches gated by the selector's path word (word 24): the plan
274
+ // bounds the grid, the kernel loops to its count word. The contract walks the edge queue and the bitset build
275
+ // the frontier from one record, so one plan covers both; bfs-fused is one workgroup per entry and takes the
276
+ // plan's GROUP count as its stride (planGridStride's cap applies to the groups)
277
+ const levelPlan = planGridStride(Math.max(n, frontier.edgeCapacity), wg, ctx.caps);
278
+ const sweepPlan = planGridStride(n, wg, ctx.caps);
279
+ const fusedPlan = planGridStride(n * wg, wg, ctx.caps);
280
+ const bitsPlan = plan1d(bitsWords, wg, ctx.caps);
281
+ const recordFill = (pass, dst, value, mode) => {
282
+ const params = scope.params(FILL_PARAMS, { count: n, value, mode, pad0: 0 });
283
+ fill.dispatch(pass, fill.bind({ dst, P: params.binding }), fillPlan, [params.offset]);
284
+ };
285
+ const flagsPlan = planGridStride(n, wg, ctx.caps);
286
+ /**
287
+ * The rebuild of the unvisited set (PD-18), recorded at the top of every submit before its levels.
288
+ * @param pass - the compute pass
289
+ */
290
+ const recordRebuild = (pass) => {
291
+ const params = scope.params(FRONTIER_PARAMS, { wg, n, stride: flagsPlan.stride ?? n });
292
+ const bound = unvisited.bind({ outDegree, inDegree, depth, flags, counters, P: params.binding });
293
+ unvisited.dispatch(pass, bound, flagsPlan, [params.offset]);
294
+ compact.record(pass, {
295
+ queue: iota,
296
+ flags,
297
+ count: n,
298
+ out: unvisitedList,
299
+ outCount: compactCount,
300
+ outIndex: 0,
301
+ });
302
+ };
303
+ const submit = (batch) => {
304
+ scope.flush();
305
+ return batch.submit();
306
+ };
307
+ // setup: depth = INVALID_INDEX everywhere and the iota queue compact reads; then the source at 0 and the
308
+ // seeded block, both queue writes ordered before the first level submit (the seed is rotated in by the
309
+ // first boundary, P8-T4)
310
+ const setup = new CommandBatch(ctx, `${ALGORITHM}/setup`);
311
+ const setupPass = setup.pass("fill");
312
+ recordFill(setupPass, depth, INVALID_INDEX, 0);
313
+ recordFill(setupPass, iota, 0, 1);
314
+ setup.endPass();
315
+ await submit(setup).readback;
316
+ ctx.assertReady();
317
+ queue.writeBuffer(depth.buffer, depth.offset + 4 * source, Uint32Array.of(0));
318
+ frontier.reset(queue, source, { nextFrontierCount: 1, level: U32_MAX });
319
+ // the levels: MAX_LEVELS_PER_SUBMIT per submit, four bytes back (PD-7); Beamer's test chooses the direction
320
+ // per level (mode 0; mode 1 pins top-down), with the fused path below fusedMax (P8-T7)
321
+ const fields = {
322
+ mode: tuning.direction === "top-down" ? 1 : 0,
323
+ alpha: tuning.alpha ?? Math.max(1, Math.floor(s.arcCount / n)),
324
+ beta: tuning.beta ?? BEAMER_BETA,
325
+ fusedMax: tuning.fusedMax ?? FUSED_FRONTIER_MAX,
326
+ maxDepth,
327
+ };
328
+ let levelsRecorded = 0;
329
+ let submits = 0;
330
+ for (;;) {
331
+ // the rebuild (PD-18): the three unvisited words zeroed by a queue write ordered before this submit,
332
+ // then the flags kernel and compact at the top of the pass, unconditionally, never per level
333
+ queue.writeBuffer(counters.buffer, counters.offset + 4 * W.unvisitedCount, new Uint32Array(3));
334
+ const batch = new CommandBatch(ctx, `${ALGORITHM}/levels`);
335
+ const pass = batch.pass("bfs");
336
+ recordRebuild(pass);
337
+ const bitsParams = scope.params(FILL_PARAMS, { count: bitsWords, value: 0, mode: 0, pad0: 0 });
338
+ const boundBitsFill = fill.bind({ dst: frontierBits, P: bitsParams.binding });
339
+ for (let level = 0; level < levelsPerSubmit; level++) {
340
+ planner.recordFinalize(pass, 0, level, { ...fields, firstOfSubmit: Math.min(level, 2) });
341
+ advance.record(pass, frontier);
342
+ planner.recordFinalize(pass, 1, level, fields);
343
+ // one window-free record serves the contract and the bitset build, which read no arc; the kernels that
344
+ // walk arcs (the fused dispatch, the sweep) get one record per window below (P8-T12)
345
+ const params = scope.params(FRONTIER_PARAMS, {
346
+ wg,
347
+ n,
348
+ edgeCapacity: frontier.edgeCapacity,
349
+ arcBase: 0,
350
+ arcEnd: s.arcCount,
351
+ bitsBase,
352
+ stride: levelPlan.stride ?? wg,
353
+ });
354
+ const boundContract = contract.bind({
355
+ edgeQueue: frontier.edgeQueue,
356
+ counters,
357
+ depth,
358
+ frontierOut: frontier.output,
359
+ P: params.binding,
360
+ });
361
+ contract.dispatch(pass, boundContract, levelPlan, [params.offset]);
362
+ // the fused path (role 0's choice) and the overflow retry (role 1's, PD-23): ONE dispatch per window that
363
+ // the path word turns into the level's work or into nothing (the claim is idempotent across windows)
364
+ for (const w of forward) {
365
+ const fusedParams = scope.params(FRONTIER_PARAMS, {
366
+ wg,
367
+ n,
368
+ edgeCapacity: frontier.edgeCapacity,
369
+ arcBase: w.arcBase,
370
+ arcEnd: w.arcEnd,
371
+ stride: fusedPlan.x * fusedPlan.y,
372
+ });
373
+ const boundFused = fused.bind({
374
+ ...graphBindings(w.core, null),
375
+ frontierIn: frontier.input,
376
+ counters,
377
+ depth,
378
+ frontierOut: frontier.output,
379
+ P: fusedParams.binding,
380
+ });
381
+ fused.dispatch(pass, boundFused, fusedPlan, [fusedParams.offset]);
382
+ }
383
+ // the bottom-up level (role 0's choice under Beamer's test, P8-T8): the bitset zeroed (every level: a
384
+ // top-down level zeroes bits nobody reads, cheaper than a gate), the frontier's bits set, the unvisited
385
+ // list swept over the reverse core
386
+ fill.dispatch(pass, boundBitsFill, bitsPlan, [bitsParams.offset]);
387
+ const boundBitset = bitset.bind({
388
+ frontierIn: frontier.input,
389
+ counters,
390
+ bits: sweepIn,
391
+ P: params.binding,
392
+ });
393
+ bitset.dispatch(pass, boundBitset, levelPlan, [params.offset]);
394
+ // the sweep once per window of the REVERSE core (an entry claimed in one window is skipped in the next)
395
+ for (const w of backward) {
396
+ const sweepParams = scope.params(FRONTIER_PARAMS, {
397
+ wg,
398
+ n,
399
+ arcBase: w.arcBase,
400
+ arcEnd: w.arcEnd,
401
+ bitsBase,
402
+ stride: sweepPlan.stride ?? wg,
403
+ });
404
+ const boundSweep = bottomUp.bind({
405
+ ...graphBindings(w.core, null),
406
+ sweepIn,
407
+ counters,
408
+ depth,
409
+ frontierOut: frontier.output,
410
+ P: sweepParams.binding,
411
+ });
412
+ bottomUp.dispatch(pass, boundSweep, sweepPlan, [sweepParams.offset]);
413
+ }
414
+ frontier.swap();
415
+ }
416
+ batch.endPass();
417
+ const doneRequest = batch.readback(counters.buffer, counters.offset + 4 * W.done, 4);
418
+ const inspect = tuning.onLevel === undefined
419
+ ? null
420
+ : {
421
+ block: batch.readback(counters.buffer, counters.offset, FRONTIER_COUNTERS.byteLength),
422
+ frontier: batch.readback(frontier.input.buffer, frontier.input.offset, frontier.input.size),
423
+ count: batch.readback(compactCount.buffer, compactCount.offset, 4),
424
+ };
425
+ const submitted = submit(batch);
426
+ const back = await submitted.readback;
427
+ levelsRecorded += levelsPerSubmit;
428
+ submits += 1;
429
+ ctx.assertReady();
430
+ if (options?.signal?.aborted) {
431
+ throw aborted(submitted.id);
432
+ }
433
+ options?.onProgress?.(Math.min(levelsRecorded, n), n);
434
+ if (inspect !== null && tuning.onLevel !== undefined) {
435
+ const block = FRONTIER_COUNTERS.read(new DataView(back), inspect.block.offset);
436
+ const claimed = new Uint32Array(back, inspect.frontier.offset, wordOf(block, "nextFrontierCount"));
437
+ const rebuilt = new Uint32Array(back, inspect.count.offset, 1)[0];
438
+ tuning.onLevel(levelsRecorded - 1, block, claimed.slice(), rebuilt);
439
+ }
440
+ if (new Uint32Array(back, doneRequest.offset, 1)[0] !== 0) {
441
+ break;
442
+ }
443
+ if (submits > n + 1) {
444
+ throw new WebGpuGraphError("E_VALIDATION", `${ALGORITHM}: the done flag never rose in ${submits} submits (a traversal has at most ${n} levels)`, { label: ALGORITHM, message: `the done flag never rose in ${submits} submits` });
445
+ }
446
+ }
447
+ // the result batch: order by one stable radix sort of the node indices by depth (PD-14), parent by the
448
+ // post-pass in depth mode (PD-24), then every array through ONE staging slot
449
+ const keys = bindingOf(scope.scratch(bytes, "order/keys"), bytes);
450
+ const vals = bindingOf(scope.scratch(bytes, "order/vals"), bytes);
451
+ const histBytes = radixHistBytes(n, wg);
452
+ const scratch = {
453
+ keys: bindingOf(scope.scratch(bytes, "order/keys-scratch"), bytes),
454
+ vals: bindingOf(scope.scratch(bytes, "order/vals-scratch"), bytes),
455
+ hist: bindingOf(scope.scratch(histBytes, "order/hist"), histBytes),
456
+ offsets: bindingOf(scope.scratch(histBytes, "order/offsets"), histBytes),
457
+ };
458
+ const parent = bindingOf(scope.scratch(bytes, "parent"), bytes);
459
+ const result = new CommandBatch(ctx, `${ALGORITHM}/result`);
460
+ result.copy(depth, keys, bytes);
461
+ const pass = result.pass("result");
462
+ recordFill(pass, vals, 0, 1);
463
+ const sorted = sort.record(pass, keys, vals, n, 32, scratch);
464
+ recordFill(pass, parent, INVALID_INDEX, 0);
465
+ // the post-pass once per arc window (its atomicMin admits the same smallest parent whichever window holds the arc)
466
+ const predPlan = planGridStride(n, wg, ctx.caps);
467
+ for (const w of forward) {
468
+ const predParams = scope.params(FRONTIER_PARAMS, {
469
+ wg,
470
+ n,
471
+ arcBase: w.arcBase,
472
+ arcEnd: w.arcEnd,
473
+ predKind,
474
+ source,
475
+ stride: predPlan.stride ?? n,
476
+ });
477
+ const predBound = pred.bind({
478
+ ...graphBindings(w.core, null),
479
+ dist: depth,
480
+ pred: parent,
481
+ P: predParams.binding,
482
+ });
483
+ pred.dispatch(pass, predBound, predPlan, [predParams.offset]);
484
+ }
485
+ result.endPass();
486
+ const depthRequest = result.readback(depth.buffer, depth.offset, bytes);
487
+ const parentRequest = result.readback(parent.buffer, parent.offset, bytes);
488
+ const orderRequest = result.readback(sorted.vals.buffer, sorted.vals.offset, bytes);
489
+ const blockRequest = result.readback(counters.buffer, counters.offset, FRONTIER_COUNTERS.byteLength);
490
+ const back = await submit(result).readback;
491
+ ctx.assertReady();
492
+ const block = FRONTIER_COUNTERS.read(new DataView(back), blockRequest.offset);
493
+ const visitedCount = wordOf(block, "visitedCount");
494
+ if (visitedCount > n) {
495
+ // every vertex is claimed at most once, so a count above n is a kernel bug (a claim that lets two
496
+ // same-level claimants append), never a result to return
497
+ throw new WebGpuGraphError("E_VALIDATION", `${ALGORITHM}: visitedCount ${visitedCount} exceeds the ${n} vertices (a duplicate claim)`, {
498
+ label: `${ALGORITHM}/visitedCount`,
499
+ message: `the device counted ${visitedCount} visits of ${n} vertices`,
500
+ });
501
+ }
502
+ const level = wordOf(block, "level");
503
+ // done by an empty frontier (the level word already counts the boundary that found it), or by maxDepth with
504
+ // a reached-but-unexpanded level
505
+ const levels = wordOf(block, "frontierCount") === 0 ? level : level + 1;
506
+ const depthOut = dest ?? new Uint32Array(n);
507
+ depthOut.set(new Uint32Array(back, depthRequest.offset, n));
508
+ return {
509
+ depth: depthOut,
510
+ parent: new Uint32Array(back, parentRequest.offset, n).slice(),
511
+ order: new Uint32Array(back, orderRequest.offset, visitedCount).slice(),
512
+ visitedCount,
513
+ levels,
514
+ switches: wordOf(block, "switches"),
515
+ };
516
+ }
517
+ finally {
518
+ scope.dispose();
519
+ }
520
+ }
521
+ /**
522
+ * Breadth-first search on the device (spec 3.3 line 807, design 8.4, 9.7): `depth` exact, `parent` the smallest
523
+ * predecessor one depth down (PD-24), `order` grouped by depth and ascending by index within a depth (PD-14), all
524
+ * bitwise reproducible; `maxDepth` as the CPU port reads it (a node at the cap is reached and not expanded).
525
+ * @param ctx - the context whose device runs the kernels
526
+ * @param s - the snapshot (uploaded through ctx.residency, or found there)
527
+ * @param source - the source node index (E_INVALID_ARGUMENT outside `[0, n)`, so the empty graph refuses every source)
528
+ * @param options - `maxDepth`, plus dest (a Uint32Array of length n for `depth`) / signal / onProgress
529
+ * @returns the depths, parents, order, visited count, level count and switches (the direction changes Beamer's test made on the device)
530
+ */
531
+ export function breadthFirstSearch(ctx, s, source, options) {
532
+ return bfsWithTuning(ctx, s, source, options, {});
533
+ }
534
+ //# sourceMappingURL=bfs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bfs.js","sourceRoot":"","sources":["../../../src/algorithms/bfs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Closeness centrality on the device (design 8.4, 3.3 line 810, 9.7; P8-T11, the P8 plan's PD-13 / PD-19 / PD-25 /
3
+ * DEP-P8-E / DEP-P8-F): `score[s] = 1 / sumDist_s`, with `sumDist_s` the exact sum of the finite distances from `s`
4
+ * to every OTHER node -- an unreached node adds nothing -- and `0` when nothing is reached. No reached factor and no
5
+ * Wasserman-Faust scaling: this is EXACTLY the legacy default (`normalized: false`) of `closenessCentrality` in
6
+ * `@graphty/algorithms`, the number graphty-element's closeness panel shows today, so a future `indexed` port has one
7
+ * number to match (the NetworkX form is 33x it on karate and could never have been substituted silently).
8
+ *
9
+ * The unweighted route is ONE bit-parallel multi-source search per batch of 32 sources (`ceil(n / 32)` batches):
10
+ * the batch's state is one `bits` buffer of four regions of `bitsBase = roundUp(n, 64)` words (`visited`, two
11
+ * frontier regions that swap by the level's parity, `flags`), bit `s` of word `v` meaning "source `s` has reached /
12
+ * is at / is next at `v`"; a level is, all host-recorded, `closeness-reduce` role 0 (the boundary: `done` from the
13
+ * previous level's compacted count, the level's claims folded into the exact 64-bit per-source sums at `level + 1`),
14
+ * `compact` of the flags into the frontier list, two `fill`s zeroing the level's next region and the flags (AFTER
15
+ * the compaction that consumed them), and `closeness-sweep` (the block-mapped expansion with the claim inline, a
16
+ * direct grid-stride dispatch looping to the list's count). `MAX_LEVELS_PER_SUBMIT` levels per submit and
17
+ * one readback per submit (the `done` word and the 512-byte `perSource` block together, so the finished batch needs
18
+ * no extra map); the host folds `sumHi x 2^32 + sumLo` into `1 / sum` in f64 and stores f32. The weighted route
19
+ * (`weighted` true on a snapshot whose column is not all ones) is one `sssp` per source with the sums reduced on the
20
+ * host between calls: design 8.4's own answer, slow and correct. `weighted` defaults to the snapshot's `flags.weighted`;
21
+ * `weighted: false` on a weighted snapshot ignores the column by request and sweeps; `weighted: true` over unit
22
+ * weights or no column sweeps too (every `sssp` would route to a BFS anyway). `maxIterations` and `tolerance` are the
23
+ * seam's placeholder keys and an exact traversal has neither, so a defined value is REFUSED before any device work
24
+ * (`E_UNSUPPORTED { option }`, the package's rule for an option it does not implement, PD-25); `undefined` is legal.
25
+ * `iterations` reports the source batches run (the sources, on the weighted route), `converged` is always true.
26
+ *
27
+ * Cost, stated so nobody is surprised: closeness is O(n x m) on any device -- at 1M nodes it is 31,250 batches of a
28
+ * full multi-source traversal, minutes on the card, and no target in design 10.4 asks for less. `compact.record`
29
+ * leases its offsets and the scan's block sums afresh on every call, once per LEVEL here, so the planner is given a
30
+ * scope whose `scratch` hands the same buffer back for the same label and size: the dispatches of one pass run in
31
+ * order, a level's scan overwrites the previous level's, and the run holds one set instead of `levels x batches`.
32
+ * The sweep keeps DEP-P8-E's refusal of a windowed core (`assertWholeCore`): the bit-parallel claim needs the whole
33
+ * arc array bound. The tuning entry `closenessWithTuning` (PD-26's shape) is what the tests drive; nothing public
34
+ * exposes it.
35
+ */
36
+ import { type GraphSnapshot } from "@graphty/graph-format";
37
+ import { type GpuContext } from "../context.js";
38
+ import { type HitsOptionsLike } from "../types/accelerator.js";
39
+ import { type GpuScoresResult } from "../types/algorithms.js";
40
+ import { type GpuRunOptions } from "../types/run.js";
41
+ /**
42
+ * Closeness centrality on the device (spec 3.3 line 810, design 8.4, 9.7): `scores[s] = 1 / sumDist_s` over the finite
43
+ * distances from `s` to every other node, `0` when nothing is reached -- the legacy default of `@graphty/algorithms`'
44
+ * `closenessCentrality`, unweighted by one bit-parallel multi-source search per 32 sources, weighted by one `sssp`
45
+ * per source; `weighted` defaults to the snapshot's flag, `maxIterations` / `tolerance` are refused when defined
46
+ * (PD-25). `iterations` is the source batches run and `converged` is always true.
47
+ * @param ctx - the context whose device runs the kernels
48
+ * @param s - the snapshot (uploaded through ctx.residency, or found there)
49
+ * @param options - the seam's `HitsOptionsLike`, plus dest (a Float32Array of length n for `scores`) / signal / onProgress
50
+ * @returns the scores, the batches run, `converged: true` and `precision: "f32"`
51
+ */
52
+ export declare function closenessCentrality(ctx: GpuContext, s: GraphSnapshot, options?: HitsOptionsLike & GpuRunOptions): Promise<GpuScoresResult>;
53
+ //# sourceMappingURL=closeness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closeness.d.ts","sourceRoot":"","sources":["../../../src/algorithms/closeness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAY,KAAK,aAAa,EAAY,MAAM,uBAAuB,CAAC;AAG/E,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAiBhD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA8TrD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAC/B,GAAG,EAAE,UAAU,EACf,CAAC,EAAE,aAAa,EAChB,OAAO,CAAC,EAAE,eAAe,GAAG,aAAa,GAC1C,OAAO,CAAC,eAAe,CAAC,CAE1B"}