@graphty/webgpu-graph-algorithms 0.6.24 → 0.6.25

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 (59) hide show
  1. package/LICENSE +1 -1
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{context-B40Z6lV_.js → context-BZY6SMsM.js} +41 -35
  4. package/dist/chunks/context-BZY6SMsM.js.map +1 -0
  5. package/dist/node.js +1 -1
  6. package/dist/src/algorithms/betweenness.d.ts +24 -9
  7. package/dist/src/algorithms/betweenness.d.ts.map +1 -1
  8. package/dist/src/algorithms/betweenness.js +105 -39
  9. package/dist/src/algorithms/betweenness.js.map +1 -1
  10. package/dist/src/constants.d.ts +11 -0
  11. package/dist/src/constants.d.ts.map +1 -1
  12. package/dist/src/constants.js +11 -0
  13. package/dist/src/constants.js.map +1 -1
  14. package/dist/src/kernel/prelude.d.ts.map +1 -1
  15. package/dist/src/kernel/prelude.js +4 -1
  16. package/dist/src/kernel/prelude.js.map +1 -1
  17. package/dist/src/kernels.d.ts +4 -4
  18. package/dist/src/kernels.d.ts.map +1 -1
  19. package/dist/src/kernels.js +43 -13
  20. package/dist/src/kernels.js.map +1 -1
  21. package/dist/src/types/betweenness.d.ts +5 -2
  22. package/dist/src/types/betweenness.d.ts.map +1 -1
  23. package/dist/src/wgsl/bc-backward.wgsl.d.ts +5 -2
  24. package/dist/src/wgsl/bc-backward.wgsl.d.ts.map +1 -1
  25. package/dist/src/wgsl/bc-backward.wgsl.js +12 -3
  26. package/dist/src/wgsl/bc-backward.wgsl.js.map +1 -1
  27. package/dist/src/wgsl/bc-count.wgsl.d.ts +22 -0
  28. package/dist/src/wgsl/bc-count.wgsl.d.ts.map +1 -0
  29. package/dist/src/wgsl/bc-count.wgsl.js +46 -0
  30. package/dist/src/wgsl/bc-count.wgsl.js.map +1 -0
  31. package/dist/src/wgsl/bc-edge-gather.wgsl.d.ts +3 -2
  32. package/dist/src/wgsl/bc-edge-gather.wgsl.d.ts.map +1 -1
  33. package/dist/src/wgsl/bc-edge-gather.wgsl.js +10 -2
  34. package/dist/src/wgsl/bc-edge-gather.wgsl.js.map +1 -1
  35. package/dist/src/wgsl/bc-finalize.wgsl.d.ts +4 -3
  36. package/dist/src/wgsl/bc-finalize.wgsl.d.ts.map +1 -1
  37. package/dist/src/wgsl/bc-finalize.wgsl.js +5 -3
  38. package/dist/src/wgsl/bc-finalize.wgsl.js.map +1 -1
  39. package/dist/src/wgsl/bc-forward-edge.wgsl.d.ts +2 -2
  40. package/dist/src/wgsl/bc-forward-edge.wgsl.js +2 -2
  41. package/dist/src/wgsl/bc-forward.wgsl.d.ts +4 -2
  42. package/dist/src/wgsl/bc-forward.wgsl.d.ts.map +1 -1
  43. package/dist/src/wgsl/bc-forward.wgsl.js +4 -2
  44. package/dist/src/wgsl/bc-forward.wgsl.js.map +1 -1
  45. package/dist/webgpu-graph-algorithms.js +171 -47
  46. package/dist/webgpu-graph-algorithms.js.map +1 -1
  47. package/package.json +3 -3
  48. package/src/algorithms/betweenness.ts +155 -48
  49. package/src/constants.ts +11 -0
  50. package/src/kernel/prelude.ts +4 -0
  51. package/src/kernels.ts +45 -13
  52. package/src/types/betweenness.ts +5 -2
  53. package/src/wgsl/bc-backward.wgsl.ts +12 -3
  54. package/src/wgsl/bc-count.wgsl.ts +45 -0
  55. package/src/wgsl/bc-edge-gather.wgsl.ts +10 -2
  56. package/src/wgsl/bc-finalize.wgsl.ts +5 -3
  57. package/src/wgsl/bc-forward-edge.wgsl.ts +2 -2
  58. package/src/wgsl/bc-forward.wgsl.ts +4 -2
  59. package/dist/chunks/context-B40Z6lV_.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { W as WebGpuGraphError, U as UNIFORM_SLOT_BYTES, B as BufferUsage, M as MAX_WORKGROUPS_PER_DIM, a as WGSL_RESERVED_WORDS, S as STATE_HEADER_BYTES, d as deviceLostError, i as isWebGpuGraphError, b as U32_MAX$2, c as MAX_LEVELS_PER_SUBMIT, R as RADIX_BINS, F as FUSED_FRONTIER_MAX, e as BEAMER_BETA, f as SSSP_DELTA_FACTOR, g as F32_INF_BITS, h as BC_EDGE_PARALLEL_GAMMA, j as BC_BATCH_BUDGET_FRACTION, k as BC_MAX_BATCH, l as BC_BACKWARD_LEVELS_PER_SUBMIT, A as APSP_MAX_DISPATCHES_PER_SUBMIT, m as APSP_TILE, n as GROUP_ROW_THREAD_MAX, o as GROUP_ROW_THREAD_LIMIT, p as GROUP_HASH_LOAD_FACTOR, P as PARALLEL_MERGE_LIMIT, L as LABEL_PROP_PASSES_PER_SUBMIT, q as BORUVKA_ROUNDS_PER_SUBMIT, r as GRID_COARSEST_SIDE, s as GRID_MIN_SIDE, t as GRID_SORT_BITS, u as FA2_DEFAULTS, v as MAX_ITERATIONS_PER_STEP, w as MAX_1D_ITEMS, x as hasErrorCode, y as FA2_FLAG_FIRST, z as PARTIAL_BYTES, E as EXACT_TILES_PER_PASS, I as INDIRECT_ARGS_STRIDE, C as GRID_HUB_CELL, D as LAYOUT_TUNING_DEFAULTS, H as EXACT_MAX_NODES, J as SETTLE_FLOOR_UNBOUNDED, T as TRACE_RECORD_BYTES, K as GRID_BBOX_MARGIN, N as GRID_EXTENT_FLOOR, O as FR_ADAPTIVE_MAX_ITERATIONS, Q as FR_START_TEMPERATURE, V as FA2_FLAG_ADAPTIVE, X as SETTLE_FLOOR_FRACTION, Y as FR_REHEAT_FRACTION, Z as FR_DEFAULTS, _ as SE_DEFAULTS, $ as SETTLE_FLOOR_REFERENCE_NODES, a0 as SE_SCALE_REFERENCE_NODES } from "./chunks/context-B40Z6lV_.js";
2
- import { a1, G, a2, a3, a4, a5 } from "./chunks/context-B40Z6lV_.js";
1
+ import { W as WebGpuGraphError, U as UNIFORM_SLOT_BYTES, B as BufferUsage, M as MAX_WORKGROUPS_PER_DIM, a as WGSL_RESERVED_WORDS, S as STATE_HEADER_BYTES, d as deviceLostError, i as isWebGpuGraphError, b as U32_MAX$2, c as MAX_LEVELS_PER_SUBMIT, R as RADIX_BINS, F as FUSED_FRONTIER_MAX, e as BEAMER_BETA, f as SSSP_DELTA_FACTOR, g as F32_INF_BITS, h as BC_EDGE_PARALLEL_GAMMA, j as BC_BATCH_BUDGET_FRACTION, k as BC_MAX_BATCH, l as BC_BACKWARD_LEVELS_PER_SUBMIT, m as BC_COUNT_MAX_GROUPS, A as APSP_MAX_DISPATCHES_PER_SUBMIT, n as APSP_TILE, o as GROUP_ROW_THREAD_MAX, p as GROUP_ROW_THREAD_LIMIT, q as GROUP_HASH_LOAD_FACTOR, P as PARALLEL_MERGE_LIMIT, L as LABEL_PROP_PASSES_PER_SUBMIT, r as BORUVKA_ROUNDS_PER_SUBMIT, s as GRID_COARSEST_SIDE, t as GRID_MIN_SIDE, u as GRID_SORT_BITS, v as FA2_DEFAULTS, w as MAX_ITERATIONS_PER_STEP, x as MAX_1D_ITEMS, y as hasErrorCode, z as FA2_FLAG_FIRST, C as PARTIAL_BYTES, E as EXACT_TILES_PER_PASS, I as INDIRECT_ARGS_STRIDE, D as GRID_HUB_CELL, H as LAYOUT_TUNING_DEFAULTS, J as EXACT_MAX_NODES, K as SETTLE_FLOOR_UNBOUNDED, T as TRACE_RECORD_BYTES, N as GRID_BBOX_MARGIN, O as GRID_EXTENT_FLOOR, Q as FR_ADAPTIVE_MAX_ITERATIONS, V as FR_START_TEMPERATURE, X as FA2_FLAG_ADAPTIVE, Y as SETTLE_FLOOR_FRACTION, Z as FR_REHEAT_FRACTION, _ as FR_DEFAULTS, $ as SE_DEFAULTS, a0 as SETTLE_FLOOR_REFERENCE_NODES, a1 as SE_SCALE_REFERENCE_NODES } from "./chunks/context-BZY6SMsM.js";
2
+ import { a2, G, a3, a4, a5, a6 } from "./chunks/context-BZY6SMsM.js";
3
3
  import { renumberPartition, INVALID_INDEX, foldArcs, makeMask, maskTest, expandEdges, fromEdgeArrays } from "@graphty/graph-format";
4
4
  class UniformRing {
5
5
  /**
@@ -722,6 +722,11 @@ fn apsp_init(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id
722
722
  const bcBackwardWgsl = (
723
723
  /* wgsl */
724
724
  `
725
+ fn sigma_of(word: u32) -> f32 { // a stored count: u32, or f32 bits when SCALED
726
+ if (SCALED) { return bitcast<f32>(word); }
727
+ return f32(word);
728
+ }
729
+
725
730
  @compute @workgroup_size(WG)
726
731
  fn bc_backward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
727
732
  for (var i = linear_id(wid, lid.x); i < P.count; i = i + P.stride) {
@@ -729,12 +734,13 @@ fn bc_backward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_
729
734
  let w = t % P.n;
730
735
  let base = t - w; // s * n
731
736
  let succ = depthK[t] + 1u;
732
- let sw = f32(sigmaK[t]);
737
+ let sw = sigma_of(sigmaK[t]);
738
+ let shift = select(0i, sigma_shift(levelMax[depthK[t]]), SCALED); // the scale step to the successors' depth
733
739
  var acc = 0.0;
734
740
  for (var a = rowPtr[w]; a < rowPtr[w + 1u]; a = a + 1u) {
735
741
  let v = base + colIdx[a];
736
742
  if (depthK[v] == succ) { // v is a successor of w for source s
737
- acc = acc + (sw / f32(sigmaK[v])) * (1.0 + deltaK[v]);
743
+ acc = acc + ldexp(sw / sigma_of(sigmaK[v]), -shift) * (1.0 + deltaK[v]);
738
744
  }
739
745
  }
740
746
  deltaK[t] = acc; // written once per (w, s)
@@ -742,9 +748,42 @@ fn bc_backward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_
742
748
  }
743
749
  `
744
750
  );
751
+ const bcCountWgsl = (
752
+ /* wgsl */
753
+ `
754
+ @compute @workgroup_size(WG)
755
+ fn bc_count(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
756
+ let level = atomicLoad(&counters[11]);
757
+ let start = ends[level + 1u]; // the boundary closed the claim-from level here
758
+ let count = atomicLoad(&counters[26]) - start; // stackTop: what the forward dispatch appended
759
+ let shift = sigma_shift(atomicLoad(&levelMax[level]));
760
+ for (var i = linear_id(wid, lid.x); i < count; i = i + P.stride) {
761
+ let t = S[start + i]; // s * n + x, at depth level + 1
762
+ let x = t % P.n;
763
+ let base = t - x; // s * n
764
+ var acc = 0.0;
765
+ for (var a = rowPtr[x]; a < rowPtr[x + 1u]; a = a + 1u) { // the in-arcs (v, x)
766
+ let v = base + colIdx[a];
767
+ if (depthK[v] == level) { acc = acc + bitcast<f32>(sigmaK[v]); } // every predecessor's paths, CSR order
768
+ }
769
+ let sigma = ldexp(acc, -shift);
770
+ let bits = bitcast<u32>(sigma);
771
+ sigmaK[t] = bits;
772
+ let exponent = (bits >> 23u) & 0xffu;
773
+ if (exponent == 0u || exponent == 0xffu) { atomicOr(&counters[27], 1u); } // out of f32's normal range
774
+ atomicMax(&levelMax[level + 1u], bits);
775
+ }
776
+ }
777
+ `
778
+ );
745
779
  const bcEdgeGatherWgsl = (
746
780
  /* wgsl */
747
781
  `
782
+ fn sigma_of(word: u32) -> f32 { // a stored count: u32, or f32 bits when SCALED
783
+ if (SCALED) { return bitcast<f32>(word); }
784
+ return f32(word);
785
+ }
786
+
748
787
  @compute @workgroup_size(WG)
749
788
  fn bc_edge_gather(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
750
789
  for (var a = linear_id(wid, lid.x); a < P.count; a = a + P.stride) {
@@ -762,7 +801,9 @@ fn bc_edge_gather(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocati
762
801
  let base = s * P.n;
763
802
  let dw = depthK[base + w];
764
803
  if (dw != INVALID_INDEX && depthK[base + nbr] == dw + 1u) { // (w, nbr) is on a shortest path from s
765
- acc = acc + (f32(sigmaK[base + w]) / f32(sigmaK[base + nbr])) * (1.0 + deltaK[base + nbr]);
804
+ let shift = select(0i, sigma_shift(levelMax[dw]), SCALED);
805
+ let ratio = ldexp(sigma_of(sigmaK[base + w]) / sigma_of(sigmaK[base + nbr]), -shift);
806
+ acc = acc + ratio * (1.0 + deltaK[base + nbr]);
766
807
  }
767
808
  }
768
809
  arcScores[a] = acc;
@@ -780,8 +821,9 @@ fn bc_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {
780
821
  for (var i = 0u; i < P.k; i = i + 1u) {
781
822
  let t = S[i];
782
823
  depthK[t] = 0u; // the source is at depth 0
783
- sigmaK[t] = 1u; // with one shortest path, itself
824
+ sigmaK[t] = select(1u, bitcast<u32>(1.0), SCALED); // with one shortest path, itself (f32 bits when SCALED)
784
825
  }
826
+ levelMax[0] = bitcast<u32>(1.0); // the largest count at depth 0
785
827
  ends[0] = 0u;
786
828
  atomicStore(&counters[26], P.k); // stackTop: the seeds are the log's first k entries
787
829
  atomicStore(&counters[27], 0u); // sigmaOverflow
@@ -865,7 +907,7 @@ fn bc_forward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_i
865
907
  if (atomicLoad(&depthK[x]) == INVALID_INDEX) { // the pre-check of design 16.1
866
908
  won = atomicMin(&depthK[x], next) == INVALID_INDEX; // the claim: the one winner appends
867
909
  }
868
- if (atomicLoad(&depthK[x]) == next) { // the count: EVERY arc on a shortest path adds
910
+ if (!SCALED && atomicLoad(&depthK[x]) == next) { // the count: EVERY arc on a shortest path adds
869
911
  let add = atomicLoad(&sigmaK[origin]);
870
912
  let old = atomicAdd(&sigmaK[x], add);
871
913
  if (old + add < old) { atomicOr(&counters[27], 1u); } // the u32 wrap, reported
@@ -900,7 +942,7 @@ fn claim(x: u32, next: u32) -> bool {
900
942
  }
901
943
 
902
944
  fn count_paths(origin: u32, x: u32, next: u32) {
903
- if (atomicLoad(&depthK[x]) == next) { // every arc on a shortest path adds
945
+ if (!SCALED && atomicLoad(&depthK[x]) == next) { // every arc on a shortest path adds
904
946
  let add = atomicLoad(&sigmaK[origin]);
905
947
  let old = atomicAdd(&sigmaK[x], add);
906
948
  if (old + add < old) { atomicOr(&counters[27], 1u); } // the u32 wrap, reported
@@ -4381,9 +4423,10 @@ const BC_FINALIZE = {
4381
4423
  decl(1, 2, "S", "storage-ro", "array<u32>"),
4382
4424
  decl(1, 3, "depthK", "storage", "array<u32>"),
4383
4425
  decl(1, 4, "sigmaK", "storage", "array<u32>"),
4426
+ decl(1, 5, "levelMax", "storage", "array<u32>"),
4384
4427
  decl(2, 0, "P", "uniform", "BcParams")
4385
4428
  ],
4386
- overrideDecls: [],
4429
+ overrideDecls: [{ name: "SCALED", type: "bool", default: false }],
4387
4430
  uniforms: [BC_PARAMS],
4388
4431
  needs: [],
4389
4432
  snippetSlots: [],
@@ -4403,7 +4446,7 @@ const BC_FORWARD = {
4403
4446
  decl(1, 6, "sigmaK", "storage", "array<atomic<u32>>"),
4404
4447
  decl(2, 0, "P", "uniform", "BcParams")
4405
4448
  ],
4406
- overrideDecls: [],
4449
+ overrideDecls: [{ name: "SCALED", type: "bool", default: false }],
4407
4450
  uniforms: [BC_PARAMS],
4408
4451
  needs: [],
4409
4452
  snippetSlots: [],
@@ -4420,9 +4463,10 @@ const BC_BACKWARD = {
4420
4463
  decl(1, 3, "depthK", "storage-ro", "array<u32>"),
4421
4464
  decl(1, 4, "sigmaK", "storage-ro", "array<u32>"),
4422
4465
  decl(1, 5, "deltaK", "storage", "array<f32>"),
4466
+ decl(1, 6, "levelMax", "storage-ro", "array<u32>"),
4423
4467
  decl(2, 0, "P", "uniform", "BcParams")
4424
4468
  ],
4425
- overrideDecls: [],
4469
+ overrideDecls: [{ name: "SCALED", type: "bool", default: false }],
4426
4470
  uniforms: [BC_PARAMS],
4427
4471
  needs: [],
4428
4472
  snippetSlots: [],
@@ -4454,9 +4498,10 @@ const BC_EDGE_GATHER = {
4454
4498
  decl(1, 3, "sigmaK", "storage-ro", "array<u32>"),
4455
4499
  decl(1, 4, "deltaK", "storage-ro", "array<f32>"),
4456
4500
  decl(1, 5, "arcScores", "storage", "array<f32>"),
4501
+ decl(1, 6, "levelMax", "storage-ro", "array<u32>"),
4457
4502
  decl(2, 0, "P", "uniform", "BcParams")
4458
4503
  ],
4459
- overrideDecls: [],
4504
+ overrideDecls: [{ name: "SCALED", type: "bool", default: false }],
4460
4505
  uniforms: [BC_PARAMS],
4461
4506
  needs: [],
4462
4507
  snippetSlots: [],
@@ -4476,7 +4521,31 @@ const BC_FORWARD_EDGE = {
4476
4521
  decl(1, 6, "sigmaK", "storage", "array<atomic<u32>>"),
4477
4522
  decl(2, 0, "P", "uniform", "BcParams")
4478
4523
  ],
4479
- overrideDecls: [{ name: "UNDIRECTED", type: "bool", default: false }],
4524
+ overrideDecls: [
4525
+ { name: "UNDIRECTED", type: "bool", default: false },
4526
+ { name: "SCALED", type: "bool", default: false }
4527
+ ],
4528
+ uniforms: [BC_PARAMS],
4529
+ needs: [],
4530
+ snippetSlots: [],
4531
+ phase: "P9"
4532
+ };
4533
+ const BC_COUNT = {
4534
+ id: "bc-count",
4535
+ body: bcCountWgsl,
4536
+ entryPoint: "bc_count",
4537
+ bindings: [
4538
+ decl(1, 0, "rowPtr", "storage-ro", "array<u32>"),
4539
+ decl(1, 1, "colIdx", "storage-ro", "array<u32>"),
4540
+ decl(1, 2, "S", "storage-ro", "array<u32>"),
4541
+ decl(1, 3, "ends", "storage-ro", "array<u32>"),
4542
+ decl(1, 4, "counters", "storage", "array<atomic<u32>>"),
4543
+ decl(1, 5, "depthK", "storage-ro", "array<u32>"),
4544
+ decl(1, 6, "sigmaK", "storage", "array<u32>"),
4545
+ decl(1, 7, "levelMax", "storage", "array<atomic<u32>>"),
4546
+ decl(2, 0, "P", "uniform", "BcParams")
4547
+ ],
4548
+ overrideDecls: [],
4480
4549
  uniforms: [BC_PARAMS],
4481
4550
  needs: [],
4482
4551
  snippetSlots: [],
@@ -4733,6 +4802,7 @@ const REGISTRY = Object.freeze({
4733
4802
  "bc-forward": BC_FORWARD,
4734
4803
  "bc-backward": BC_BACKWARD,
4735
4804
  "bc-gather": BC_GATHER,
4805
+ "bc-count": BC_COUNT,
4736
4806
  "bc-edge-gather": BC_EDGE_GATHER,
4737
4807
  "bc-forward-edge": BC_FORWARD_EDGE,
4738
4808
  "apsp-init": APSP_INIT,
@@ -8300,7 +8370,7 @@ async function bellmanFord(ctx, s, source, options) {
8300
8370
  const ALGORITHM$5 = "betweennessCentrality";
8301
8371
  const BYTES_PER_NODE_SOURCE = 16;
8302
8372
  const SAMPLE_SEED = 2654435769;
8303
- const RING_SLOTS$4 = BC_BACKWARD_LEVELS_PER_SUBMIT + 16;
8373
+ const RING_SLOTS$4 = Math.max(3 * MAX_LEVELS_PER_SUBMIT, BC_BACKWARD_LEVELS_PER_SUBMIT) + 16;
8304
8374
  function planBatchSize(n, remaining, limits) {
8305
8375
  const needed = 4 * (n + 2);
8306
8376
  if (needed > limits.maxStorageBufferBindingSize) {
@@ -8356,6 +8426,26 @@ function resolveSources(options, n) {
8356
8426
  }
8357
8427
  return Array.from({ length: n }, (_, i) => i);
8358
8428
  }
8429
+ async function modeKernels(ctx, s, core, withForwardEdge, withEdges, scaled) {
8430
+ const SCALED = scaled;
8431
+ const [finalize, forward, backward] = await Promise.all(
8432
+ ["bc-finalize", "bc-forward", "bc-backward"].map(
8433
+ (id) => ctx.pipelines.kernel(kernelSpec(id, { SCALED }))
8434
+ )
8435
+ );
8436
+ const forwardEdge = withForwardEdge ? await ctx.pipelines.kernel(kernelSpec("bc-forward-edge", { UNDIRECTED: !s.directed, SCALED })) : null;
8437
+ const edgeGather = withEdges ? await ctx.pipelines.kernel(kernelSpec("bc-edge-gather", { SCALED })) : null;
8438
+ let count = null;
8439
+ if (scaled) {
8440
+ const reverse = s.directed ? reverseOf(ctx, s) : core;
8441
+ count = {
8442
+ kernel: await ctx.pipelines.kernel(kernelSpec("bc-count")),
8443
+ rowPtr: reverse.rowPtr,
8444
+ colIdx: reverse.colIdx ?? reverse.rowPtr
8445
+ };
8446
+ }
8447
+ return { finalize, forward, forwardEdge, backward, edgeGather, count };
8448
+ }
8359
8449
  function recordFill(state, pass, dst, count, value) {
8360
8450
  const { scope, fill, ctx } = state;
8361
8451
  const params = scope.params(FILL_PARAMS, { count, value, mode: 0, pad0: 0 });
@@ -8363,9 +8453,9 @@ function recordFill(state, pass, dst, count, value) {
8363
8453
  params.offset
8364
8454
  ]);
8365
8455
  }
8366
- function recordBc(state, pass, kernel, resources, fields, items) {
8456
+ function recordBc(state, pass, kernel, resources, fields, items, maxGroups) {
8367
8457
  const { scope, ctx } = state;
8368
- const plan = planGridStride(items, ctx.workgroupSize, ctx.caps);
8458
+ const plan = planGridStride(items, ctx.workgroupSize, ctx.caps, maxGroups);
8369
8459
  const params = scope.params(BC_PARAMS, { ...fields, stride: plan.stride ?? 0 });
8370
8460
  let bound = state.bound.get(kernel);
8371
8461
  if (bound === void 0) {
@@ -8384,8 +8474,8 @@ async function submit(state, batch, signal) {
8384
8474
  }
8385
8475
  return back;
8386
8476
  }
8387
- async function runBatch(state, sources, form, levelsPerSubmit, tuning, signal) {
8388
- const { ctx, n, S, ends, depthK, sigmaK, deltaK, counters } = state;
8477
+ async function runBatch(state, mode, sources, form, levelsPerSubmit, tuning, signal) {
8478
+ const { ctx, n, S, ends, levelMax, depthK, sigmaK, deltaK, counters } = state;
8389
8479
  const k = sources.length;
8390
8480
  const words = n * k;
8391
8481
  const seeds = Uint32Array.from(sources, (v, s) => s * n + v);
@@ -8403,15 +8493,18 @@ async function runBatch(state, sources, form, levelsPerSubmit, tuning, signal) {
8403
8493
  recordFill(state, pass, depthK, words, 4294967295);
8404
8494
  recordFill(state, pass, sigmaK, words, 0);
8405
8495
  recordFill(state, pass, deltaK, words, 0);
8406
- recordBc(state, pass, state.finalize, { counters, ends, S, depthK, sigmaK }, { n, k, role: 1 }, 1);
8496
+ if (mode.count !== null) {
8497
+ recordFill(state, pass, levelMax, n + 2, 0);
8498
+ }
8499
+ recordBc(state, pass, mode.finalize, { counters, ends, S, depthK, sigmaK, levelMax }, { n, k, role: 1 }, 1);
8407
8500
  }
8408
8501
  for (let level = 0; level < levelsPerSubmit; level++) {
8409
- recordBc(state, pass, state.finalize, { counters, ends, S, depthK, sigmaK }, { n, k, role: 0 }, 1);
8410
- if (form === "edge" && state.forwardEdge !== null && state.edgeSrc !== null && state.edgeDst !== null) {
8502
+ recordBc(state, pass, mode.finalize, { counters, ends, S, depthK, sigmaK, levelMax }, { n, k, role: 0 }, 1);
8503
+ if (form === "edge" && mode.forwardEdge !== null && state.edgeSrc !== null && state.edgeDst !== null) {
8411
8504
  recordBc(
8412
8505
  state,
8413
8506
  pass,
8414
- state.forwardEdge,
8507
+ mode.forwardEdge,
8415
8508
  { edgeSrc: state.edgeSrc, edgeDst: state.edgeDst, S, ends, counters, depthK, sigmaK },
8416
8509
  forwardFields,
8417
8510
  forwardItems
@@ -8420,12 +8513,24 @@ async function runBatch(state, sources, form, levelsPerSubmit, tuning, signal) {
8420
8513
  recordBc(
8421
8514
  state,
8422
8515
  pass,
8423
- state.forward,
8516
+ mode.forward,
8424
8517
  { rowPtr: state.rowPtr, colIdx: state.colIdx, S, ends, counters, depthK, sigmaK },
8425
8518
  forwardFields,
8426
8519
  forwardItems
8427
8520
  );
8428
8521
  }
8522
+ if (mode.count !== null) {
8523
+ const { kernel, rowPtr, colIdx } = mode.count;
8524
+ recordBc(
8525
+ state,
8526
+ pass,
8527
+ kernel,
8528
+ { rowPtr, colIdx, S, ends, counters, depthK, sigmaK, levelMax },
8529
+ { n, k },
8530
+ words,
8531
+ BC_COUNT_MAX_GROUPS
8532
+ );
8533
+ }
8429
8534
  }
8430
8535
  recorded += levelsPerSubmit;
8431
8536
  batch.endPass();
@@ -8438,6 +8543,9 @@ async function runBatch(state, sources, form, levelsPerSubmit, tuning, signal) {
8438
8543
  levels = words32[W.level];
8439
8544
  overflow = words32[W.sigmaOverflow] !== 0;
8440
8545
  endsWords = new Uint32Array(back, endsRequest.offset, endsCount).slice(0, levels + 1);
8546
+ if (overflow && mode.count === null) {
8547
+ return { levels, wrapped: true, overflow: false };
8548
+ }
8441
8549
  } else if (recorded > n + 2) {
8442
8550
  throw new WebGpuGraphError("E_VALIDATION", `${ALGORITHM$5}: the done flag never rose in ${recorded} levels`, {
8443
8551
  label: ALGORITHM$5,
@@ -8461,20 +8569,28 @@ async function runBatch(state, sources, form, levelsPerSubmit, tuning, signal) {
8461
8569
  recordBc(
8462
8570
  state,
8463
8571
  pass,
8464
- state.backward,
8465
- { rowPtr: state.rowPtr, colIdx: state.colIdx, S, depthK, sigmaK, deltaK },
8572
+ mode.backward,
8573
+ { rowPtr: state.rowPtr, colIdx: state.colIdx, S, depthK, sigmaK, deltaK, levelMax },
8466
8574
  { n, k, start, count },
8467
8575
  count
8468
8576
  );
8469
8577
  }
8470
8578
  if (last) {
8471
8579
  recordBc(state, pass, state.gather, { deltaK, bc: state.bc }, { n, k }, n);
8472
- if (state.edgeGather !== null && state.arcScores !== null) {
8580
+ if (mode.edgeGather !== null && state.arcScores !== null) {
8473
8581
  recordBc(
8474
8582
  state,
8475
8583
  pass,
8476
- state.edgeGather,
8477
- { rowPtr: state.rowPtr, colIdx: state.colIdx, depthK, sigmaK, deltaK, arcScores: state.arcScores },
8584
+ mode.edgeGather,
8585
+ {
8586
+ rowPtr: state.rowPtr,
8587
+ colIdx: state.colIdx,
8588
+ depthK,
8589
+ sigmaK,
8590
+ deltaK,
8591
+ arcScores: state.arcScores,
8592
+ levelMax
8593
+ },
8478
8594
  { n, k, count: state.arcCount },
8479
8595
  state.arcCount
8480
8596
  );
@@ -8500,12 +8616,13 @@ async function runBatch(state, sources, form, levelsPerSubmit, tuning, signal) {
8500
8616
  forward: form,
8501
8617
  levels,
8502
8618
  ends: endsWords.slice(),
8619
+ scaled: mode.count !== null,
8503
8620
  sigmaOverflow: overflow,
8504
8621
  depthK: arrays?.depthK ?? null,
8505
8622
  sigmaK: arrays?.sigmaK ?? null,
8506
8623
  deltaK: arrays?.deltaK ?? null
8507
8624
  });
8508
- return { levels, overflow };
8625
+ return { levels, wrapped: false, overflow };
8509
8626
  }
8510
8627
  async function runRaw(ctx, s, sources, withEdges, tuning, options) {
8511
8628
  const n = s.nodeCount;
@@ -8526,19 +8643,17 @@ async function runRaw(ctx, s, sources, withEdges, tuning, options) {
8526
8643
  const arrayBytes = 4 * n * kMax;
8527
8644
  const lease = (bytes, label) => bindingOf(scope.scratch(bytes, label), bytes);
8528
8645
  const arcBytes = 4 * Math.max(1, s.arcCount);
8529
- const [fill, finalize, forward, backward, gather] = await Promise.all(
8530
- ["fill", "bc-finalize", "bc-forward", "bc-backward", "bc-gather"].map(
8531
- (id) => ctx.pipelines.kernel(kernelSpec(id))
8532
- )
8646
+ const [fill, gather] = await Promise.all(
8647
+ ["fill", "bc-gather"].map((id) => ctx.pipelines.kernel(kernelSpec(id)))
8533
8648
  );
8534
- const forwardEdge = edgeView === null ? null : await ctx.pipelines.kernel(kernelSpec("bc-forward-edge", { UNDIRECTED: !s.directed }));
8535
- const edgeGather = withEdges ? await ctx.pipelines.kernel(kernelSpec("bc-edge-gather")) : null;
8649
+ const exact = await modeKernels(ctx, s, core, edgeView !== null, withEdges, false);
8536
8650
  const state = {
8537
8651
  ctx,
8538
8652
  scope,
8539
8653
  n,
8540
8654
  S: lease(arrayBytes, "S"),
8541
8655
  ends: lease(4 * (n + 2), "ends"),
8656
+ levelMax: lease(4 * (n + 2), "level-max"),
8542
8657
  depthK: lease(arrayBytes, "depthK"),
8543
8658
  sigmaK: lease(arrayBytes, "sigmaK"),
8544
8659
  deltaK: lease(arrayBytes, "deltaK"),
@@ -8552,12 +8667,9 @@ async function runRaw(ctx, s, sources, withEdges, tuning, options) {
8552
8667
  edgeCount,
8553
8668
  arcCount: s.arcCount,
8554
8669
  fill,
8555
- finalize,
8556
- forward,
8557
- forwardEdge,
8558
- backward,
8559
8670
  gather,
8560
- edgeGather,
8671
+ exact,
8672
+ scaled: null,
8561
8673
  bound: /* @__PURE__ */ new Map()
8562
8674
  };
8563
8675
  await ctx.allocator.check();
@@ -8578,11 +8690,23 @@ async function runRaw(ctx, s, sources, withEdges, tuning, options) {
8578
8690
  if (pinned === "auto" && previousLevels >= 0) {
8579
8691
  form = previousLevels < BC_EDGE_PARALLEL_GAMMA * Math.log2(n) ? "edge" : "frontier";
8580
8692
  }
8581
- if (state.forwardEdge === null) {
8693
+ if (state.exact.forwardEdge === null) {
8582
8694
  form = "frontier";
8583
8695
  }
8584
8696
  const batch = sources.slice(start, start + k);
8585
- const outcome = await runBatch(state, batch, form, levelsPerSubmit, tuning, options?.signal);
8697
+ let outcome = await runBatch(
8698
+ state,
8699
+ state.scaled ?? state.exact,
8700
+ batch,
8701
+ form,
8702
+ levelsPerSubmit,
8703
+ tuning,
8704
+ options?.signal
8705
+ );
8706
+ if (outcome.wrapped) {
8707
+ state.scaled ??= await modeKernels(ctx, s, core, edgeView !== null, withEdges, true);
8708
+ outcome = await runBatch(state, state.scaled, batch, form, levelsPerSubmit, tuning, options?.signal);
8709
+ }
8586
8710
  overflow = overflow || outcome.overflow;
8587
8711
  previousLevels = outcome.levels;
8588
8712
  start += k;
@@ -15508,7 +15632,7 @@ async function calibrateLayout(ctx, options) {
15508
15632
  };
15509
15633
  }
15510
15634
  export {
15511
- a1 as ARC_WINDOW_ALIGN,
15635
+ a2 as ARC_WINDOW_ALIGN,
15512
15636
  EXACT_MAX_NODES,
15513
15637
  FA2_DEFAULTS,
15514
15638
  FR_DEFAULTS,
@@ -15516,10 +15640,10 @@ export {
15516
15640
  LAYOUT_TUNING_DEFAULTS,
15517
15641
  MAX_1D_ITEMS,
15518
15642
  MAX_WORKGROUPS_PER_DIM,
15519
- a2 as PASSTHROUGH_FORMAT_CODES,
15643
+ a3 as PASSTHROUGH_FORMAT_CODES,
15520
15644
  SE_DEFAULTS,
15521
- a3 as STORAGE_ALIGN,
15522
- a4 as WORKGROUP_SIZE,
15645
+ a4 as STORAGE_ALIGN,
15646
+ a5 as WORKGROUP_SIZE,
15523
15647
  WebGpuGraphError,
15524
15648
  allPairsShortestPath,
15525
15649
  bellmanFord,
@@ -15537,7 +15661,7 @@ export {
15537
15661
  eigenvectorCentrality,
15538
15662
  hasErrorCode,
15539
15663
  hits,
15540
- a5 as isSoftwareAdapter,
15664
+ a6 as isSoftwareAdapter,
15541
15665
  isWebGpuGraphError,
15542
15666
  katzCentrality,
15543
15667
  labelPropagation,