@graphty/webgpu-graph-algorithms 0.6.5 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -17
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-hzGggHeM.js → context-DiSr6eiz.js} +32 -18
- package/dist/chunks/context-DiSr6eiz.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/algorithms/bfs.d.ts +10 -6
- package/dist/src/algorithms/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/bfs.js +32 -9
- package/dist/src/algorithms/bfs.js.map +1 -1
- package/dist/src/constants.d.ts +33 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +33 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernel/dispatch.d.ts +2 -2
- package/dist/src/kernel/dispatch.d.ts.map +1 -1
- package/dist/src/kernel/kernel.d.ts +1 -1
- package/dist/src/kernel/kernel.js +2 -2
- package/dist/src/kernel/kernel.js.map +1 -1
- package/dist/src/kernel/prelude.d.ts.map +1 -1
- package/dist/src/kernel/prelude.js +2 -1
- package/dist/src/kernel/prelude.js.map +1 -1
- package/dist/src/kernels.d.ts +10 -7
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +33 -9
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +2 -1
- package/dist/src/layouts/forceatlas2.js.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.js +4 -2
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -1
- package/dist/src/layouts/repulsion-exact.d.ts +16 -0
- package/dist/src/layouts/repulsion-exact.d.ts.map +1 -1
- package/dist/src/layouts/repulsion-exact.js +21 -1
- package/dist/src/layouts/repulsion-exact.js.map +1 -1
- package/dist/src/layouts/repulsion-grid.d.ts +1 -1
- package/dist/src/layouts/repulsion-grid.js +1 -1
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -1
- package/dist/src/layouts/spring-electrical.js +6 -2
- package/dist/src/layouts/spring-electrical.js.map +1 -1
- package/dist/src/primitives/frontier.d.ts +1 -0
- package/dist/src/primitives/frontier.d.ts.map +1 -1
- package/dist/src/primitives/frontier.js +1 -0
- package/dist/src/primitives/frontier.js.map +1 -1
- package/dist/src/primitives/grid-pyramid.d.ts +4 -4
- package/dist/src/primitives/grid-pyramid.d.ts.map +1 -1
- package/dist/src/primitives/grid-pyramid.js +4 -3
- package/dist/src/primitives/grid-pyramid.js.map +1 -1
- package/dist/src/primitives/grid.d.ts +13 -10
- package/dist/src/primitives/grid.d.ts.map +1 -1
- package/dist/src/primitives/grid.js +10 -7
- package/dist/src/primitives/grid.js.map +1 -1
- package/dist/src/wgsl/advance-expand.wgsl.d.ts +4 -3
- package/dist/src/wgsl/advance-expand.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/advance-expand.wgsl.js +4 -3
- package/dist/src/wgsl/advance-expand.wgsl.js.map +1 -1
- package/dist/src/wgsl/bfs-bottom-up.wgsl.d.ts +4 -3
- package/dist/src/wgsl/bfs-bottom-up.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/bfs-bottom-up.wgsl.js +4 -3
- package/dist/src/wgsl/bfs-bottom-up.wgsl.js.map +1 -1
- package/dist/src/wgsl/bfs-fused.wgsl.d.ts +6 -6
- package/dist/src/wgsl/bfs-fused.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/bfs-fused.wgsl.js +6 -6
- package/dist/src/wgsl/bfs-next-degree.wgsl.d.ts +23 -0
- package/dist/src/wgsl/bfs-next-degree.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bfs-next-degree.wgsl.js +34 -0
- package/dist/src/wgsl/bfs-next-degree.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +4 -1
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +18 -2
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +4 -2
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
- package/dist/src/wgsl/frontier-finalize.wgsl.d.ts +21 -20
- package/dist/src/wgsl/frontier-finalize.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/frontier-finalize.wgsl.js +26 -25
- package/dist/src/wgsl/frontier-finalize.wgsl.js.map +1 -1
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts +3 -2
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/grid-cell-key.wgsl.js +4 -2
- package/dist/src/wgsl/grid-cell-key.wgsl.js.map +1 -1
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts +3 -2
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/grid-centroid.wgsl.js +3 -2
- package/dist/src/wgsl/grid-centroid.wgsl.js.map +1 -1
- package/dist/src/wgsl/grid-downsample.wgsl.d.ts +1 -1
- package/dist/src/wgsl/grid-downsample.wgsl.js +1 -1
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts +6 -4
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/grid-far-field.wgsl.js +15 -8
- package/dist/src/wgsl/grid-far-field.wgsl.js.map +1 -1
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts +2 -2
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/grid-near-field.wgsl.js +6 -2
- package/dist/src/wgsl/grid-near-field.wgsl.js.map +1 -1
- package/dist/src/wgsl/histogram.wgsl.d.ts +1 -1
- package/dist/src/wgsl/histogram.wgsl.js +1 -1
- package/dist/webgpu-graph-algorithms.js +124 -40
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +3 -3
- package/src/algorithms/bfs.ts +33 -9
- package/src/algorithms/pagerank.ts +19 -5
- package/src/algorithms/power-iteration.ts +8 -2
- package/src/constants.ts +35 -0
- package/src/kernel/dispatch.ts +2 -2
- package/src/kernel/kernel.ts +2 -2
- package/src/kernel/prelude.ts +2 -0
- package/src/kernels.ts +35 -9
- package/src/layouts/forceatlas2.ts +2 -0
- package/src/layouts/fruchterman-reingold.ts +4 -1
- package/src/layouts/repulsion-exact.ts +29 -1
- package/src/layouts/repulsion-grid.ts +1 -1
- package/src/layouts/spring-electrical.ts +8 -1
- package/src/memory/residency.ts +14 -4
- package/src/primitives/frontier.ts +2 -0
- package/src/primitives/grid-pyramid.ts +6 -5
- package/src/primitives/grid.ts +17 -12
- package/src/wgsl/advance-expand.wgsl.ts +4 -3
- package/src/wgsl/bfs-bottom-up.wgsl.ts +4 -3
- package/src/wgsl/bfs-fused.wgsl.ts +6 -6
- package/src/wgsl/bfs-next-degree.wgsl.ts +33 -0
- package/src/wgsl/fa2-repulsion-exact.wgsl.ts +18 -2
- package/src/wgsl/fa2-stats-finalize.wgsl.ts +4 -2
- package/src/wgsl/frontier-finalize.wgsl.ts +26 -25
- package/src/wgsl/grid-cell-key.wgsl.ts +4 -2
- package/src/wgsl/grid-centroid.wgsl.ts +3 -2
- package/src/wgsl/grid-downsample.wgsl.ts +1 -1
- package/src/wgsl/grid-far-field.wgsl.ts +15 -8
- package/src/wgsl/grid-near-field.wgsl.ts +6 -2
- package/src/wgsl/histogram.wgsl.ts +1 -1
- package/dist/chunks/context-hzGggHeM.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 GRID_COARSEST_SIDE, j as GRID_MIN_SIDE, k as GRID_SORT_BITS, l as FA2_DEFAULTS, m as MAX_ITERATIONS_PER_STEP, n as MAX_1D_ITEMS, o as hasErrorCode, p as FA2_FLAG_FIRST, P as PARTIAL_BYTES, I as INDIRECT_ARGS_STRIDE, q as GRID_HUB_CELL, L as LAYOUT_TUNING_DEFAULTS,
|
|
2
|
-
import {
|
|
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 GRID_COARSEST_SIDE, j as GRID_MIN_SIDE, k as GRID_SORT_BITS, l as FA2_DEFAULTS, m as MAX_ITERATIONS_PER_STEP, n as MAX_1D_ITEMS, o as hasErrorCode, p as FA2_FLAG_FIRST, P as PARTIAL_BYTES, E as EXACT_TILES_PER_PASS, I as INDIRECT_ARGS_STRIDE, q as GRID_HUB_CELL, L as LAYOUT_TUNING_DEFAULTS, r as EXACT_MAX_NODES, s as SETTLE_FLOOR_UNBOUNDED, T as TRACE_RECORD_BYTES, t as GRID_BBOX_MARGIN, u as GRID_EXTENT_FLOOR, v as FR_ADAPTIVE_MAX_ITERATIONS, w as FR_START_TEMPERATURE, x as FA2_FLAG_ADAPTIVE, y as SETTLE_FLOOR_FRACTION, z as FR_REHEAT_FRACTION, A as FR_DEFAULTS, C as SE_DEFAULTS, D as SETTLE_FLOOR_REFERENCE_NODES, H as SE_SCALE_REFERENCE_NODES } from "./chunks/context-DiSr6eiz.js";
|
|
2
|
+
import { J, G, K, N, O, Q } from "./chunks/context-DiSr6eiz.js";
|
|
3
3
|
import { renumberPartition, INVALID_INDEX, makeMask, maskTest, expandEdges, fromEdgeArrays } from "@graphty/graph-format";
|
|
4
4
|
class UniformRing {
|
|
5
5
|
/**
|
|
@@ -217,7 +217,7 @@ function planGridStride(items, wg, caps, maxGroups) {
|
|
|
217
217
|
if (items === 0) {
|
|
218
218
|
return { x: 0, y: 1, z: 1, items, stride: null };
|
|
219
219
|
}
|
|
220
|
-
const cap = Math.min(caps.software ? 64 : 4096, perDimension(caps));
|
|
220
|
+
const cap = Math.min(maxGroups ?? (caps.software ? 64 : 4096), perDimension(caps));
|
|
221
221
|
const groups = Math.min(Math.ceil(items / wg), cap);
|
|
222
222
|
return { x: groups, y: 1, z: 1, items, stride: groups * wg };
|
|
223
223
|
}
|
|
@@ -582,7 +582,7 @@ fn advance_expand(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocati
|
|
|
582
582
|
if (lid.x == 0u) {
|
|
583
583
|
base = atomicAdd(&counters[8], aggregate); // edgeCount: ONE reservation per workgroup, not one per arc
|
|
584
584
|
atomicAdd(&counters[9], aggregate); // edgeCountUnclamped: the overflow detector (PD-23)
|
|
585
|
-
atomicAdd(&counters[2], aggregate); // frontierDegreeSum:
|
|
585
|
+
atomicAdd(&counters[2], aggregate); // frontierDegreeSum: what this level expanded (the inspect seam)
|
|
586
586
|
}
|
|
587
587
|
workgroupBarrier();
|
|
588
588
|
for (var p = lid.x; p < aggregate; p = p + WG) { // strip [0, aggregate): lane j takes j, j + WG, ...
|
|
@@ -773,7 +773,7 @@ fn bfs_fused(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id
|
|
|
773
773
|
let d = select(0u, a1 - a0, a1 > a0);
|
|
774
774
|
wdeg = d;
|
|
775
775
|
wstart = a0;
|
|
776
|
-
atomicAdd(&counters[2], d); // frontierDegreeSum, so
|
|
776
|
+
atomicAdd(&counters[2], d); // frontierDegreeSum, so the inspect seam sees fused levels too
|
|
777
777
|
}
|
|
778
778
|
let deg = workgroupUniformLoad(&wdeg); // uniform: the loop below may hold barriers
|
|
779
779
|
let start = workgroupUniformLoad(&wstart);
|
|
@@ -805,6 +805,21 @@ fn bfs_fused(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id
|
|
|
805
805
|
}
|
|
806
806
|
`
|
|
807
807
|
);
|
|
808
|
+
const bfsNextDegreeWgsl = (
|
|
809
|
+
/* wgsl */
|
|
810
|
+
`
|
|
811
|
+
@compute @workgroup_size(WG)
|
|
812
|
+
fn bfs_next_degree(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
813
|
+
let count = select(0u, atomicLoad(&counters[1]), atomicLoad(&counters[24]) != 0u); // nextFrontierCount, on a level that claimed (the path word)
|
|
814
|
+
var sum = 0u;
|
|
815
|
+
for (var i = linear_id(wid, lid.x); i < count; i = i + P.stride) { // no barrier inside: the trip count is per lane
|
|
816
|
+
sum = sum + outDegree[frontier[i]];
|
|
817
|
+
}
|
|
818
|
+
let total = wg_reduce_u32(sum, lid.x, 0u); // the prelude's workgroup sum; uniform: after the loop
|
|
819
|
+
if (lid.x == 0u) { atomicAdd(&counters[25], total); } // nextDegreeSum: ONE atomic per workgroup
|
|
820
|
+
}
|
|
821
|
+
`
|
|
822
|
+
);
|
|
808
823
|
const bfsUnvisitedFlagsWgsl = (
|
|
809
824
|
/* wgsl */
|
|
810
825
|
`
|
|
@@ -1265,14 +1280,23 @@ fn gravity_force(pi: vec4f) -> vec3f { // spec 7.9: cent
|
|
|
1265
1280
|
}
|
|
1266
1281
|
|
|
1267
1282
|
@compute @workgroup_size(WG)
|
|
1268
|
-
fn repulsion(
|
|
1283
|
+
fn repulsion(
|
|
1284
|
+
@builtin(workgroup_id) wid: vec3<u32>,
|
|
1285
|
+
@builtin(local_invocation_id) lid: vec3<u32>,
|
|
1286
|
+
@builtin(num_workgroups) nwg: vec3<u32>,
|
|
1287
|
+
) {
|
|
1288
|
+
// issue #87: pass p of the tile range is dispatched with p + 1 z slices; only the last slice works, so the pass
|
|
1289
|
+
// index needs no uniform. Uniform: keyed on workgroup_id and num_workgroups only.
|
|
1290
|
+
if (wid.z + 1u < nwg.z) { return; }
|
|
1269
1291
|
let i = linear_id(wid, lid.x);
|
|
1270
1292
|
let valid = i < P.n;
|
|
1271
1293
|
var pi = vec4f(0.0);
|
|
1272
1294
|
if (valid) { pi = pos[i]; }
|
|
1273
1295
|
var f = vec3f(0.0);
|
|
1274
1296
|
let tiles = (P.n + WG - 1u) / WG;
|
|
1275
|
-
|
|
1297
|
+
let tileBegin = (nwg.z - 1u) * EXACT_TILES_PER_PASS;
|
|
1298
|
+
let tileEnd = min(tiles, tileBegin + EXACT_TILES_PER_PASS);
|
|
1299
|
+
for (var t = tileBegin; t < tileEnd; t = t + 1u) {
|
|
1276
1300
|
let j = t * WG + lid.x;
|
|
1277
1301
|
if (j < P.n) { tile[lid.x] = pos[j]; } else { tile[lid.x] = vec4f(0.0); } // guarded fill; mass 0 marks the pad
|
|
1278
1302
|
workgroupBarrier(); // uniform: every invocation reaches it
|
|
@@ -1295,6 +1319,10 @@ fn repulsion(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id
|
|
|
1295
1319
|
}
|
|
1296
1320
|
workgroupBarrier();
|
|
1297
1321
|
}
|
|
1322
|
+
if (tileEnd < tiles) { // an earlier pass: its partial sum only (uniform: P.n, nwg)
|
|
1323
|
+
if (valid) { store_force(i, load_force(i) + f); }
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1298
1326
|
// epilogue (7.9, 7.10): gravity and force += under the guard, the swing / traction reduction outside it
|
|
1299
1327
|
var sw = 0.0;
|
|
1300
1328
|
var tr = 0.0;
|
|
@@ -1400,7 +1428,7 @@ fn stats_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
|
1400
1428
|
S.radius = sqrt(max(tHi.w, 0.0)); // max |p - centroid| about the same previous centroid as rmsRadius (K5 puts |q|^2 in max.w)
|
|
1401
1429
|
let meanDisp = select(tDisp / f32(tFree), 0.0, tFree == 0u); // all-fixed: 0, never NaN (7.4)
|
|
1402
1430
|
S.meanDisplacement = meanDisp;
|
|
1403
|
-
S.settledCount = select(0u, S.settledCount + 1u, meanDisp <= P.settleThreshold * S.rmsRadius);
|
|
1431
|
+
S.settledCount = select(0u, S.settledCount + 1u, meanDisp <= min(P.settleThreshold * S.rmsRadius, P.settleFloor)); // relative AND absolute (issue #97)
|
|
1404
1432
|
}
|
|
1405
1433
|
S.iteration = S.iteration + 1u;
|
|
1406
1434
|
T[P.iterationIndex].meanDisplacement = S.meanDisplacement;
|
|
@@ -1418,7 +1446,9 @@ fn stats_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
|
1418
1446
|
S.invCellSize = 1.0 / cellSize;
|
|
1419
1447
|
S.eps = 0.25 * cellSize;
|
|
1420
1448
|
}
|
|
1421
|
-
|
|
1449
|
+
var outside = 0u; // the previous iteration's pseudo-cell counts, one per orthant (issue #90; 0 after load)
|
|
1450
|
+
for (var o = 0u; o < select(4u, 8u, P.dim == 3u); o = o + 1u) { outside = outside + cellHist[cells + o]; }
|
|
1451
|
+
S.outsideGrid = outside;
|
|
1422
1452
|
S.maxCellOccupancy = atomicLoad(&hubCounters[1]);
|
|
1423
1453
|
atomicStore(&hubCounters[0], 0u);
|
|
1424
1454
|
atomicStore(&hubCounters[1], 0u);
|
|
@@ -1486,19 +1516,19 @@ fn frontier_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
|
1486
1516
|
let finished = atomicLoad(&counters[0]);
|
|
1487
1517
|
let next = atomicLoad(&counters[1]);
|
|
1488
1518
|
let degSum = atomicLoad(&counters[2]);
|
|
1519
|
+
let nextDeg = atomicLoad(&counters[25]); // deg(F_b), summed by bfs-next-degree when F_b was claimed (issue #391)
|
|
1489
1520
|
atomicStore(&counters[3], finished); // prevFrontierCount
|
|
1490
1521
|
atomicStore(&counters[4], degSum); // prevDegreeSum
|
|
1491
1522
|
atomicStore(&counters[0], next); // the rotation
|
|
1492
1523
|
atomicStore(&counters[1], 0u);
|
|
1493
1524
|
atomicStore(&counters[2], 0u);
|
|
1525
|
+
atomicStore(&counters[25], 0u); // the next level's claims sum from 0
|
|
1494
1526
|
atomicStore(&counters[8], 0u); // edgeCount
|
|
1495
1527
|
atomicStore(&counters[9], 0u); // edgeCountUnclamped
|
|
1496
1528
|
atomicStore(&counters[12], atomicLoad(&counters[12]) + next); // visitedCount
|
|
1497
|
-
if (P.firstOfSubmit >= 1u) { // b = the boundary's index inside its submit, clamped
|
|
1498
|
-
atomicStore(&counters[5], atomicLoad(&counters[5]) - next);
|
|
1499
|
-
|
|
1500
|
-
if (P.firstOfSubmit >= 2u) {
|
|
1501
|
-
atomicStore(&counters[6], atomicLoad(&counters[6]) - degSum); // unvisitedDegreeSum (one level stale): F_{b-1} was inside it iff b >= 2
|
|
1529
|
+
if (P.firstOfSubmit >= 1u) { // b = the boundary's index inside its submit, clamped (P8-T8, PD-18): F_b was inside the submit's rebuilt sums iff b >= 1
|
|
1530
|
+
atomicStore(&counters[5], atomicLoad(&counters[5]) - next); // unvisitedCount, exact
|
|
1531
|
+
atomicStore(&counters[6], atomicLoad(&counters[6]) - nextDeg); // unvisitedDegreeSum, exact (issue #391: no longer one level stale)
|
|
1502
1532
|
}
|
|
1503
1533
|
let level = atomicLoad(&counters[11]) + 1u; // the seed is U32_MAX, so the first boundary lands on 0
|
|
1504
1534
|
atomicStore(&counters[11], level);
|
|
@@ -1508,7 +1538,7 @@ fn frontier_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
|
1508
1538
|
if (P.mode == 1u) {
|
|
1509
1539
|
direction = 0u; // top-down only (the test seam)
|
|
1510
1540
|
} else if (direction == 0u) {
|
|
1511
|
-
if (
|
|
1541
|
+
if (nextDeg > atomicLoad(&counters[6]) / P.alpha && next > finished) { direction = 1u; } // m_f > m_u / alpha and growing, m_f the degree of the frontier about to be expanded
|
|
1512
1542
|
} else {
|
|
1513
1543
|
if (next * P.beta < atomicLoad(&counters[5]) && next < finished) { direction = 0u; } // next * beta < unvisited and shrinking
|
|
1514
1544
|
}
|
|
@@ -1603,7 +1633,8 @@ fn grid_cell_key(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocatio
|
|
|
1603
1633
|
let g = i32(P.gridMax);
|
|
1604
1634
|
var inside = c.x >= 0 && c.x < g && c.y >= 0 && c.y < g;
|
|
1605
1635
|
if (P.dim == 3u) { inside = inside && c.z >= 0 && c.z < g; }
|
|
1606
|
-
var key = cells;
|
|
1636
|
+
var key = cells + select(0u, 1u, c.x >= g / 2) + select(0u, 2u, c.y >= g / 2); // an outside pseudo-cell: its orthant (issue #90)
|
|
1637
|
+
if (P.dim == 3u) { key = key + select(0u, 4u, c.z >= g / 2); }
|
|
1607
1638
|
if (inside) {
|
|
1608
1639
|
key = u32(c.x) + P.gridMax * u32(c.y);
|
|
1609
1640
|
if (P.dim == 3u) { key = key + P.gridMax * P.gridMax * u32(c.z); }
|
|
@@ -1621,7 +1652,7 @@ fn grid_cells() -> u32 { return P.gridMax * P.gridMax * select(1u, P.gridMax, P.
|
|
|
1621
1652
|
@compute @workgroup_size(WG)
|
|
1622
1653
|
fn grid_centroid(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
1623
1654
|
let c = linear_id(wid, lid.x);
|
|
1624
|
-
if (c
|
|
1655
|
+
if (c >= grid_cells() + select(4u, 8u, P.dim == 3u)) { return; } // cells [0, cells + 2^dim): the pseudo-cells follow the real ones; no barrier follows
|
|
1625
1656
|
let start = cellStart[c];
|
|
1626
1657
|
let count = cellStart[c + 1u] - start;
|
|
1627
1658
|
atomicMax(&hubCounters[1], count); // maxCellOccupancy, read by K1 next iteration
|
|
@@ -1699,11 +1730,12 @@ fn store_force(i: u32, f: vec3f) {
|
|
|
1699
1730
|
}
|
|
1700
1731
|
fn grid_cells() -> u32 { return P.gridMax * P.gridMax * select(1u, P.gridMax, P.dim == 3u); }
|
|
1701
1732
|
fn grid_side(level: u32) -> u32 { return P.gridMax >> level; }
|
|
1702
|
-
fn
|
|
1733
|
+
fn outside_cells() -> u32 { return select(4u, 8u, P.dim == 3u); } // one pseudo-cell per orthant (issue #90)
|
|
1734
|
+
fn level_base(level: u32) -> u32 { // the pyramid index of level L's cell 0 (level 0 carries the pseudo-cells at cells ..)
|
|
1703
1735
|
var base = 0u;
|
|
1704
1736
|
for (var l = 0u; l < level; l = l + 1u) {
|
|
1705
1737
|
let s = grid_side(l);
|
|
1706
|
-
base = base + s * s * select(1u, s, P.dim == 3u) + select(0u,
|
|
1738
|
+
base = base + s * s * select(1u, s, P.dim == 3u) + select(0u, outside_cells(), l == 0u);
|
|
1707
1739
|
}
|
|
1708
1740
|
return base;
|
|
1709
1741
|
}
|
|
@@ -1714,7 +1746,9 @@ fn cell_at(level: u32, cx: i32, cy: i32, cz: i32) -> u32 {
|
|
|
1714
1746
|
fn cell_force(pi: vec4f, q: vec4f) -> vec3f { // one far-field term, softened by state.eps (7.7)
|
|
1715
1747
|
if (q.w <= 0.0) { return vec3f(0.0); } // an empty cell
|
|
1716
1748
|
let d = pi.xyz - q.xyz / q.w; // to the mass-weighted centroid
|
|
1717
|
-
|
|
1749
|
+
var d2 = dot(d, d);
|
|
1750
|
+
if (LAW == 0u) { d2 = max(d2, FA2_DIST_FLOOR_SQ); } // FA2 alone floors d >= 0.01, as K3 and G7 do (issue #89); FR and coulomb are unfloored (7.20)
|
|
1751
|
+
d2 = d2 + S.eps * S.eps;
|
|
1718
1752
|
if (LAW == 1u) { return d * (P.frK * P.frK * q.w / d2); } // LAW 1 (FR, 7.20): k^2 / d per node, q.w nodes at the centroid
|
|
1719
1753
|
if (LAW == 2u) { return d * (-P.coulomb * pi.w * q.w / (d2 * sqrt(d2))); } // LAW 2 (coulomb): -g m_i M_cell / d^2
|
|
1720
1754
|
return d * (P.scalingRatio * pi.w * q.w / d2); // LAW 0 (FA2): |F| = k m_i M_cell / d
|
|
@@ -1763,9 +1797,11 @@ fn grid_far_field(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocati
|
|
|
1763
1797
|
}
|
|
1764
1798
|
}
|
|
1765
1799
|
}
|
|
1766
|
-
|
|
1800
|
+
for (var o = 0u; o < outside_cells(); o = o + 1u) { // every outside pseudo-cell: one far-field term per orthant
|
|
1801
|
+
f = f + cell_force(pi, pyramid[grid_cells() + o]);
|
|
1802
|
+
}
|
|
1767
1803
|
} else {
|
|
1768
|
-
for (var cz = 0; cz <= zTop; cz = cz + 1) { // an outside node: the coarsest level in full, no pseudo-cell (
|
|
1804
|
+
for (var cz = 0; cz <= zTop; cz = cz + 1) { // an outside node: the coarsest level in full, no pseudo-cell (G7 sums them pair by pair)
|
|
1769
1805
|
for (var cy = 0; cy < ts; cy = cy + 1) {
|
|
1770
1806
|
for (var cx = 0; cx < ts; cx = cx + 1) {
|
|
1771
1807
|
f = f + cell_force(pi, pyramid[cell_at(top, cx, cy, cz)]);
|
|
@@ -1867,7 +1903,11 @@ fn grid_near_field(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocat
|
|
|
1867
1903
|
}
|
|
1868
1904
|
}
|
|
1869
1905
|
} else {
|
|
1870
|
-
|
|
1906
|
+
var own = grid_cells() + select(0u, 1u, c0.x >= g / 2) + select(0u, 2u, c0.y >= g / 2); // G1's orthant key
|
|
1907
|
+
if (P.dim == 3u) { own = own + select(0u, 4u, c0.z >= g / 2); }
|
|
1908
|
+
for (var o = grid_cells(); o < grid_cells() + select(4u, 8u, P.dim == 3u); o = o + 1u) { // an outside node: every outside pseudo-cell
|
|
1909
|
+
f = f + cell_sum(i, pi, o, o == own);
|
|
1910
|
+
}
|
|
1871
1911
|
}
|
|
1872
1912
|
}
|
|
1873
1913
|
// epilogue (7.9, 7.10): gravity and force += under the guard, the swing / traction reduction outside it (K3's text)
|
|
@@ -2589,7 +2629,8 @@ const FA2_PARAMS = UniformBlock.define("Fa2Params", [
|
|
|
2589
2629
|
["coulomb", "f32"],
|
|
2590
2630
|
["dragCoefficient", "f32"],
|
|
2591
2631
|
["timeStep", "f32"],
|
|
2592
|
-
["midEnd", "u32"]
|
|
2632
|
+
["midEnd", "u32"],
|
|
2633
|
+
["settleFloor", "f32"]
|
|
2593
2634
|
]);
|
|
2594
2635
|
const FA2_STATE = UniformBlock.define(
|
|
2595
2636
|
"Fa2State",
|
|
@@ -2763,7 +2804,8 @@ const FRONTIER_COUNTERS = UniformBlock.define(
|
|
|
2763
2804
|
["nextFarCount", "u32"],
|
|
2764
2805
|
["thresholdBits", "u32"],
|
|
2765
2806
|
["deltaBits", "u32"],
|
|
2766
|
-
["path", "u32"]
|
|
2807
|
+
["path", "u32"],
|
|
2808
|
+
["nextDegreeSum", "u32"]
|
|
2767
2809
|
],
|
|
2768
2810
|
{ layout: "storage" }
|
|
2769
2811
|
);
|
|
@@ -3489,6 +3531,22 @@ const BFS_UNVISITED_FLAGS = {
|
|
|
3489
3531
|
snippetSlots: [],
|
|
3490
3532
|
phase: "P8"
|
|
3491
3533
|
};
|
|
3534
|
+
const BFS_NEXT_DEGREE = {
|
|
3535
|
+
id: "bfs-next-degree",
|
|
3536
|
+
body: bfsNextDegreeWgsl,
|
|
3537
|
+
entryPoint: "bfs_next_degree",
|
|
3538
|
+
bindings: [
|
|
3539
|
+
decl(1, 0, "frontier", "storage-ro", "array<u32>"),
|
|
3540
|
+
decl(1, 1, "outDegree", "storage-ro", "array<u32>"),
|
|
3541
|
+
decl(1, 2, "counters", "storage", "array<atomic<u32>>"),
|
|
3542
|
+
decl(2, 0, "P", "uniform", "FrontierParams")
|
|
3543
|
+
],
|
|
3544
|
+
overrideDecls: [],
|
|
3545
|
+
uniforms: [FRONTIER_PARAMS],
|
|
3546
|
+
needs: ["subgroups"],
|
|
3547
|
+
snippetSlots: [],
|
|
3548
|
+
phase: "P8"
|
|
3549
|
+
};
|
|
3492
3550
|
const SSSP_RELAX = {
|
|
3493
3551
|
id: "sssp-relax",
|
|
3494
3552
|
body: ssspRelaxWgsl,
|
|
@@ -3600,6 +3658,7 @@ const REGISTRY = Object.freeze({
|
|
|
3600
3658
|
"bfs-bottom-up": BFS_BOTTOM_UP,
|
|
3601
3659
|
"bfs-bitset-build": BFS_BITSET_BUILD,
|
|
3602
3660
|
"bfs-unvisited-flags": BFS_UNVISITED_FLAGS,
|
|
3661
|
+
"bfs-next-degree": BFS_NEXT_DEGREE,
|
|
3603
3662
|
"sssp-relax": SSSP_RELAX,
|
|
3604
3663
|
"bf-relax": BF_RELAX,
|
|
3605
3664
|
"closeness-sweep": CLOSENESS_SWEEP,
|
|
@@ -5747,7 +5806,8 @@ const W = Object.freeze({
|
|
|
5747
5806
|
nextFarCount: 21,
|
|
5748
5807
|
thresholdBits: 22,
|
|
5749
5808
|
deltaBits: 23,
|
|
5750
|
-
path: 24
|
|
5809
|
+
path: 24,
|
|
5810
|
+
nextDegreeSum: 25
|
|
5751
5811
|
});
|
|
5752
5812
|
function definedWords(words) {
|
|
5753
5813
|
const out = {};
|
|
@@ -6082,6 +6142,7 @@ class RadixSortPlannerImpl {
|
|
|
6082
6142
|
}
|
|
6083
6143
|
}
|
|
6084
6144
|
const ALGORITHM$3 = "breadthFirstSearch";
|
|
6145
|
+
const NEXT_DEGREE_MAX_GROUPS = 128;
|
|
6085
6146
|
function bfsRingSlots(windows, levelsPerSubmit) {
|
|
6086
6147
|
return Math.max((5 + 4 * windows) * levelsPerSubmit + 16, RESULT_BATCH_SLOTS + windows);
|
|
6087
6148
|
}
|
|
@@ -6216,6 +6277,7 @@ async function bfsWithTuning(ctx, s, source, options, tuning) {
|
|
|
6216
6277
|
const bitset = await ctx.pipelines.kernel(kernelSpec("bfs-bitset-build"));
|
|
6217
6278
|
const bottomUp = await ctx.pipelines.kernel(kernelSpec("bfs-bottom-up", graphOverrides(reverse, null)));
|
|
6218
6279
|
const unvisited = await ctx.pipelines.kernel(kernelSpec("bfs-unvisited-flags"));
|
|
6280
|
+
const nextDegree = await ctx.pipelines.kernel(kernelSpec("bfs-next-degree"));
|
|
6219
6281
|
const pred = await ctx.pipelines.kernel(kernelSpec("sssp-pred", { ...graphOverrides(core, null), MODE: 1 }));
|
|
6220
6282
|
const fill = await ctx.pipelines.kernel(kernelSpec("fill"));
|
|
6221
6283
|
const sort = await prepareRadixSort(scope);
|
|
@@ -6225,6 +6287,7 @@ async function bfsWithTuning(ctx, s, source, options, tuning) {
|
|
|
6225
6287
|
const fillPlan = plan1d(n, wg, ctx.caps);
|
|
6226
6288
|
const levelPlan = planGridStride(Math.max(n, frontier.edgeCapacity), wg, ctx.caps);
|
|
6227
6289
|
const sweepPlan = planGridStride(n, wg, ctx.caps);
|
|
6290
|
+
const degreePlan = planGridStride(n, wg, ctx.caps, NEXT_DEGREE_MAX_GROUPS);
|
|
6228
6291
|
const fusedPlan = planGridStride(n * wg, wg, ctx.caps);
|
|
6229
6292
|
const bitsPlan = plan1d(bitsWords, wg, ctx.caps);
|
|
6230
6293
|
const recordFill = (pass2, dst, value, mode) => {
|
|
@@ -6275,7 +6338,7 @@ async function bfsWithTuning(ctx, s, source, options, tuning) {
|
|
|
6275
6338
|
const bitsParams = scope.params(FILL_PARAMS, { count: bitsWords, value: 0, mode: 0, pad0: 0 });
|
|
6276
6339
|
const boundBitsFill = fill.bind({ dst: frontierBits, P: bitsParams.binding });
|
|
6277
6340
|
for (let level2 = 0; level2 < levelsPerSubmit; level2++) {
|
|
6278
|
-
planner.recordFinalize(pass2, 0, level2, { ...fields, firstOfSubmit: Math.min(level2,
|
|
6341
|
+
planner.recordFinalize(pass2, 0, level2, { ...fields, firstOfSubmit: Math.min(level2, 1) });
|
|
6279
6342
|
advance.record(pass2, frontier);
|
|
6280
6343
|
planner.recordFinalize(pass2, 1, level2, fields);
|
|
6281
6344
|
const params = scope.params(FRONTIER_PARAMS, {
|
|
@@ -6341,6 +6404,14 @@ async function bfsWithTuning(ctx, s, source, options, tuning) {
|
|
|
6341
6404
|
});
|
|
6342
6405
|
bottomUp.dispatch(pass2, boundSweep, sweepPlan, [sweepParams.offset]);
|
|
6343
6406
|
}
|
|
6407
|
+
const degreeParams = scope.params(FRONTIER_PARAMS, { wg, n, stride: degreePlan.stride ?? wg });
|
|
6408
|
+
const boundDegree = nextDegree.bind({
|
|
6409
|
+
frontier: frontier.output,
|
|
6410
|
+
outDegree,
|
|
6411
|
+
counters,
|
|
6412
|
+
P: degreeParams.binding
|
|
6413
|
+
});
|
|
6414
|
+
nextDegree.dispatch(pass2, boundDegree, degreePlan, [degreeParams.offset]);
|
|
6344
6415
|
frontier.swap();
|
|
6345
6416
|
}
|
|
6346
6417
|
batch.endPass();
|
|
@@ -7504,10 +7575,11 @@ function gridSpecFor(n, dim, tuning) {
|
|
|
7504
7575
|
levels++;
|
|
7505
7576
|
}
|
|
7506
7577
|
const cells = g ** dim;
|
|
7578
|
+
const outsideCells = 2 ** dim;
|
|
7507
7579
|
const levelOffsets = [0];
|
|
7508
7580
|
let s = g;
|
|
7509
7581
|
for (let level = 0; level + 1 < levels; level++) {
|
|
7510
|
-
levelOffsets.push(levelOffsets[level] + s ** dim + (level === 0 ?
|
|
7582
|
+
levelOffsets.push(levelOffsets[level] + s ** dim + (level === 0 ? outsideCells : 0));
|
|
7511
7583
|
s /= 2;
|
|
7512
7584
|
}
|
|
7513
7585
|
return {
|
|
@@ -7515,7 +7587,8 @@ function gridSpecFor(n, dim, tuning) {
|
|
|
7515
7587
|
g,
|
|
7516
7588
|
levels,
|
|
7517
7589
|
cells,
|
|
7518
|
-
|
|
7590
|
+
outsideCells,
|
|
7591
|
+
histWords: cells + outsideCells + 1,
|
|
7519
7592
|
levelOffsets: Object.freeze(levelOffsets),
|
|
7520
7593
|
pyramidCells: levelOffsets[levels - 1] + GRID_COARSEST_SIDE ** dim,
|
|
7521
7594
|
deterministic: tuning.deterministic
|
|
@@ -9831,6 +9904,12 @@ function subset(merged, defaults) {
|
|
|
9831
9904
|
}
|
|
9832
9905
|
return out;
|
|
9833
9906
|
}
|
|
9907
|
+
function recordExactRepulsion(kernel, pass, bound, plan, n, paramsOffset) {
|
|
9908
|
+
const passes = Math.max(1, Math.ceil(Math.ceil(n / kernel.workgroupSize) / EXACT_TILES_PER_PASS));
|
|
9909
|
+
for (let z = 1; z <= passes; z++) {
|
|
9910
|
+
kernel.dispatch(pass, bound, { ...plan, z }, [paramsOffset]);
|
|
9911
|
+
}
|
|
9912
|
+
}
|
|
9834
9913
|
class RepulsionExact {
|
|
9835
9914
|
/**
|
|
9836
9915
|
* Holds the two compiled kernels; create() is the only caller.
|
|
@@ -9923,7 +10002,7 @@ class RepulsionExact {
|
|
|
9923
10002
|
recordRepulsion(pass, n, paramsOffset) {
|
|
9924
10003
|
const bound = this.bound(this.boundRepulsion, "recordRepulsion");
|
|
9925
10004
|
const plan = plan1d(n, this.repulsion.workgroupSize, this.caps);
|
|
9926
|
-
this.repulsion
|
|
10005
|
+
recordExactRepulsion(this.repulsion, pass, bound, plan, n, paramsOffset);
|
|
9927
10006
|
}
|
|
9928
10007
|
/**
|
|
9929
10008
|
* Records K4 only.
|
|
@@ -10056,7 +10135,8 @@ class GridPyramidPlannerImpl {
|
|
|
10056
10135
|
}
|
|
10057
10136
|
const { centroid, finalize, hub, downsample } = this.kernels;
|
|
10058
10137
|
const one = { x: 1, y: 1, z: 1, items: 1, stride: null };
|
|
10059
|
-
|
|
10138
|
+
const level0 = spec.cells + spec.outsideCells;
|
|
10139
|
+
centroid.dispatch(pass, bound.centroid, plan1d(level0, scope.workgroupSize, scope.caps), [paramsOffset]);
|
|
10060
10140
|
finalize.dispatch(pass, bound.finalize, one, [bound.finalizeOffset]);
|
|
10061
10141
|
hub.dispatchIndirect(pass, bound.hub, bound.hubArgs, 0, [paramsOffset]);
|
|
10062
10142
|
this.dispatches = 3;
|
|
@@ -10129,7 +10209,7 @@ class RepulsionGrid {
|
|
|
10129
10209
|
}
|
|
10130
10210
|
/**
|
|
10131
10211
|
* The model-owned buffers of the grid tier (spec 7.3; PD-11): `cellKey` / `cellVal` / `sortedKey` / `sortedIdx`
|
|
10132
|
-
* 4n, `cellHist` / `cellStart` 4 (cells + 2) zeroed, `hubList` one word per possible hub cell, `hubArgs` one
|
|
10212
|
+
* 4n, `cellHist` / `cellStart` 4 histWords (cells + 2^dim + 1) zeroed, `hubList` one word per possible hub cell, `hubArgs` one
|
|
10133
10213
|
* indirect slot, `pyramid` 16 B per pyramid cell zeroed. `hubCounters` (16 B, zeroed) is the MODEL's on every
|
|
10134
10214
|
* tier (PD-14: K1 binds it on the exact tier too). n = 0 reports one node's worth of bytes (spec 3.6).
|
|
10135
10215
|
* @param n - the node count
|
|
@@ -10725,7 +10805,9 @@ class ForceAtlas2Model {
|
|
|
10725
10805
|
arcEnd: arcCountOf(core),
|
|
10726
10806
|
accumulate: 0,
|
|
10727
10807
|
hiEnd,
|
|
10728
|
-
midEnd
|
|
10808
|
+
midEnd,
|
|
10809
|
+
settleFloor: SETTLE_FLOOR_UNBOUNDED
|
|
10810
|
+
// ForceAtlas2 does not drift after settling (issue #97)
|
|
10729
10811
|
};
|
|
10730
10812
|
}
|
|
10731
10813
|
/**
|
|
@@ -11424,6 +11506,7 @@ class FruchtermanReingoldModel {
|
|
|
11424
11506
|
hiEnd,
|
|
11425
11507
|
midEnd,
|
|
11426
11508
|
frK: resolved.k ?? 1 / Math.sqrt(n),
|
|
11509
|
+
settleFloor: SETTLE_FLOOR_FRACTION.fruchtermanReingold * (resolved.k ?? 1 / Math.sqrt(n)),
|
|
11427
11510
|
temperature: adaptive ? FR_START_TEMPERATURE : this.temperatureAt(iteration, resolved)
|
|
11428
11511
|
};
|
|
11429
11512
|
}
|
|
@@ -11476,7 +11559,7 @@ class FruchtermanReingoldModel {
|
|
|
11476
11559
|
if (stop < 2) {
|
|
11477
11560
|
return;
|
|
11478
11561
|
}
|
|
11479
|
-
k3
|
|
11562
|
+
recordExactRepulsion(k3, pass, k3Bound, bound.plan, bound.n, offset);
|
|
11480
11563
|
if (stop < STAGE_K5$1) {
|
|
11481
11564
|
return;
|
|
11482
11565
|
}
|
|
@@ -12055,6 +12138,7 @@ class SpringElectricalModel {
|
|
|
12055
12138
|
frK: 0,
|
|
12056
12139
|
temperature: 0,
|
|
12057
12140
|
springLength: resolved.springLength,
|
|
12141
|
+
settleFloor: SETTLE_FLOOR_FRACTION.springElectrical * resolved.springLength * (SETTLE_FLOOR_REFERENCE_NODES / Math.max(n, 1)) ** 0.25,
|
|
12058
12142
|
springCoefficient: resolved.springCoefficient ?? SE_DEFAULTS.springCoefficient * springSizeFactor(n),
|
|
12059
12143
|
coulomb: resolved.gravity ?? SE_DEFAULTS.gravity * springSizeFactor(n),
|
|
12060
12144
|
dragCoefficient: resolved.dragCoefficient,
|
|
@@ -12108,7 +12192,7 @@ class SpringElectricalModel {
|
|
|
12108
12192
|
if (stop < 2) {
|
|
12109
12193
|
return;
|
|
12110
12194
|
}
|
|
12111
|
-
k3
|
|
12195
|
+
recordExactRepulsion(k3, pass, k3Bound, bound.plan, bound.n, offset);
|
|
12112
12196
|
if (stop < STAGE_K5) {
|
|
12113
12197
|
return;
|
|
12114
12198
|
}
|
|
@@ -12594,7 +12678,7 @@ async function calibrateLayout(ctx, options) {
|
|
|
12594
12678
|
};
|
|
12595
12679
|
}
|
|
12596
12680
|
export {
|
|
12597
|
-
|
|
12681
|
+
J as ARC_WINDOW_ALIGN,
|
|
12598
12682
|
EXACT_MAX_NODES,
|
|
12599
12683
|
FA2_DEFAULTS,
|
|
12600
12684
|
FR_DEFAULTS,
|
|
@@ -12602,10 +12686,10 @@ export {
|
|
|
12602
12686
|
LAYOUT_TUNING_DEFAULTS,
|
|
12603
12687
|
MAX_1D_ITEMS,
|
|
12604
12688
|
MAX_WORKGROUPS_PER_DIM,
|
|
12605
|
-
|
|
12689
|
+
K as PASSTHROUGH_FORMAT_CODES,
|
|
12606
12690
|
SE_DEFAULTS,
|
|
12607
|
-
|
|
12608
|
-
|
|
12691
|
+
N as STORAGE_ALIGN,
|
|
12692
|
+
O as WORKGROUP_SIZE,
|
|
12609
12693
|
WebGpuGraphError,
|
|
12610
12694
|
bellmanFord,
|
|
12611
12695
|
breadthFirstSearch,
|
|
@@ -12620,7 +12704,7 @@ export {
|
|
|
12620
12704
|
eigenvectorCentrality,
|
|
12621
12705
|
hasErrorCode,
|
|
12622
12706
|
hits,
|
|
12623
|
-
|
|
12707
|
+
Q as isSoftwareAdapter,
|
|
12624
12708
|
isWebGpuGraphError,
|
|
12625
12709
|
katzCentrality,
|
|
12626
12710
|
pageRank,
|