@graphty/webgpu-graph-algorithms 0.6.26 → 0.6.28
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 +56 -6
- package/dist/acquire.d.ts +2 -0
- package/dist/browser.js +18 -1
- package/dist/browser.js.map +1 -1
- package/dist/chunks/accelerator-B-FjQwaA.js +19173 -0
- package/dist/chunks/accelerator-B-FjQwaA.js.map +1 -0
- package/dist/chunks/managed-D_GdQtnu.js +98 -0
- package/dist/chunks/managed-D_GdQtnu.js.map +1 -0
- package/dist/node.js +18 -1
- package/dist/node.js.map +1 -1
- package/dist/src/accelerator.d.ts.map +1 -1
- package/dist/src/accelerator.js +5 -3
- package/dist/src/accelerator.js.map +1 -1
- package/dist/src/algorithms/all-pairs.d.ts.map +1 -1
- package/dist/src/algorithms/all-pairs.js +72 -47
- package/dist/src/algorithms/all-pairs.js.map +1 -1
- package/dist/src/algorithms/betweenness.d.ts +1 -1
- package/dist/src/algorithms/betweenness.js +2 -2
- package/dist/src/algorithms/closeness.d.ts +45 -42
- package/dist/src/algorithms/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/closeness.js +295 -226
- package/dist/src/algorithms/closeness.js.map +1 -1
- package/dist/src/browser/index.d.ts +10 -0
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +22 -0
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/constants.d.ts +13 -3
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +13 -3
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernels.d.ts +14 -4
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +62 -28
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/force-simulation.d.ts.map +1 -1
- package/dist/src/layouts/force-simulation.js +0 -1
- package/dist/src/layouts/force-simulation.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +0 -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 +0 -1
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -1
- package/dist/src/layouts/repulsion-grid.d.ts +1 -3
- package/dist/src/layouts/repulsion-grid.d.ts.map +1 -1
- package/dist/src/layouts/repulsion-grid.js +1 -6
- package/dist/src/layouts/repulsion-grid.js.map +1 -1
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -1
- package/dist/src/layouts/spring-electrical.js +0 -1
- package/dist/src/layouts/spring-electrical.js.map +1 -1
- package/dist/src/managed.d.ts +11 -0
- package/dist/src/managed.d.ts.map +1 -0
- package/dist/src/managed.js +129 -0
- package/dist/src/managed.js.map +1 -0
- package/dist/src/node/index.d.ts +11 -0
- package/dist/src/node/index.d.ts.map +1 -1
- package/dist/src/node/index.js +21 -0
- package/dist/src/node/index.js.map +1 -1
- package/dist/src/primitives/grid-pyramid.d.ts +16 -15
- package/dist/src/primitives/grid-pyramid.d.ts.map +1 -1
- package/dist/src/primitives/grid-pyramid.js +20 -28
- package/dist/src/primitives/grid-pyramid.js.map +1 -1
- package/dist/src/types/accelerator.d.ts +2 -0
- package/dist/src/types/accelerator.d.ts.map +1 -1
- package/dist/src/types/managed.d.ts +81 -0
- package/dist/src/types/managed.d.ts.map +1 -0
- package/dist/src/types/managed.js +7 -0
- package/dist/src/types/managed.js.map +1 -0
- package/dist/src/wgsl/bc-forward.wgsl.d.ts +1 -1
- package/dist/src/wgsl/bc-forward.wgsl.js +1 -1
- package/dist/src/wgsl/closeness-level.wgsl.d.ts +37 -0
- package/dist/src/wgsl/closeness-level.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-level.wgsl.js +204 -0
- package/dist/src/wgsl/closeness-level.wgsl.js.map +1 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.d.ts +11 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.js +42 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +2 -2
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js +2 -2
- package/dist/webgpu-graph-algorithms.js +142 -15586
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +10 -4
- package/src/accelerator.ts +5 -3
- package/src/algorithms/all-pairs.ts +86 -56
- package/src/algorithms/betweenness.ts +2 -2
- package/src/algorithms/closeness.ts +353 -256
- package/src/browser/index.ts +37 -0
- package/src/constants.ts +13 -3
- package/src/kernels.ts +65 -36
- package/src/layouts/force-simulation.ts +0 -1
- package/src/layouts/forceatlas2.ts +0 -1
- package/src/layouts/fruchterman-reingold.ts +0 -1
- package/src/layouts/repulsion-grid.ts +2 -7
- package/src/layouts/spring-electrical.ts +0 -1
- package/src/managed.ts +172 -0
- package/src/node/index.ts +36 -0
- package/src/primitives/grid-pyramid.ts +29 -41
- package/src/types/accelerator.ts +2 -0
- package/src/types/managed.ts +86 -0
- package/src/wgsl/bc-forward.wgsl.ts +1 -1
- package/src/wgsl/closeness-level.wgsl.ts +203 -0
- package/src/wgsl/closeness-rowsum.wgsl.ts +41 -0
- package/src/wgsl/grid-centroid-hub.wgsl.ts +2 -2
- package/dist/chunks/context-BZY6SMsM.js +0 -3615
- package/dist/chunks/context-BZY6SMsM.js.map +0 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts +0 -20
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts.map +0 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.js +0 -69
- package/dist/src/wgsl/closeness-reduce.wgsl.js.map +0 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts +0 -22
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts.map +0 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.js +0 -106
- package/dist/src/wgsl/closeness-sweep.wgsl.js.map +0 -1
- package/src/wgsl/closeness-reduce.wgsl.ts +0 -68
- package/src/wgsl/closeness-sweep.wgsl.ts +0 -105
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphty/webgpu-graph-algorithms",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.28",
|
|
4
4
|
"description": "WebGPU-accelerated graph algorithms and layouts over the @graphty/graph-format snapshot, for Node (Dawn) and browsers",
|
|
5
5
|
"author": "Adam Powers <apowers@ato.ms>",
|
|
6
6
|
"type": "module",
|
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
"types": "./dist/node.d.ts",
|
|
22
22
|
"import": "./dist/node.js",
|
|
23
23
|
"default": "./dist/node.js"
|
|
24
|
+
},
|
|
25
|
+
"./acquire": {
|
|
26
|
+
"types": "./dist/acquire.d.ts",
|
|
27
|
+
"browser": "./dist/browser.js",
|
|
28
|
+
"node": "./dist/node.js",
|
|
29
|
+
"default": "./dist/browser.js"
|
|
24
30
|
}
|
|
25
31
|
},
|
|
26
32
|
"sideEffects": false,
|
|
@@ -61,7 +67,7 @@
|
|
|
61
67
|
"homepage": "https://github.com/graphty-org/graphty-monorepo/tree/master/webgpu-graph-algorithms#readme",
|
|
62
68
|
"dependencies": {
|
|
63
69
|
"@webgpu/types": "^0.1.72",
|
|
64
|
-
"@graphty/graph-format": "^1.
|
|
70
|
+
"@graphty/graph-format": "^1.3.0"
|
|
65
71
|
},
|
|
66
72
|
"peerDependencies": {
|
|
67
73
|
"@graphty/algorithms": "^1.0.0 || ^2.0.0 || ^3.0.0",
|
|
@@ -95,8 +101,8 @@
|
|
|
95
101
|
"vite": "^7.0.5",
|
|
96
102
|
"vitest": "4.1.11",
|
|
97
103
|
"webgpu": "0.4.0",
|
|
98
|
-
"@graphty/layout": "^2.0
|
|
99
|
-
"@graphty/algorithms": "^3.
|
|
104
|
+
"@graphty/layout": "^2.2.0",
|
|
105
|
+
"@graphty/algorithms": "^3.3.0"
|
|
100
106
|
},
|
|
101
107
|
"scripts": {
|
|
102
108
|
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
|
package/src/accelerator.ts
CHANGED
|
@@ -175,6 +175,7 @@ export function createAccelerator(ctx: GpuContext, options?: AcceleratorOptions)
|
|
|
175
175
|
const frozen = freezeOptions(options);
|
|
176
176
|
return {
|
|
177
177
|
kind: "webgpu",
|
|
178
|
+
harmonicCloseness: true,
|
|
178
179
|
ctx,
|
|
179
180
|
options: frozen,
|
|
180
181
|
/**
|
|
@@ -357,10 +358,11 @@ export function createAccelerator(ctx: GpuContext, options?: AcceleratorOptions)
|
|
|
357
358
|
);
|
|
358
359
|
},
|
|
359
360
|
/**
|
|
360
|
-
* Closeness centrality on the device (spec 8.4
|
|
361
|
-
*
|
|
361
|
+
* Closeness centrality on the device (spec 8.4): the all-pairs sweep with a row sum on small and
|
|
362
|
+
* weighted graphs, the bit-parallel multi-source search otherwise, one `sssp` per source for a weighted graph
|
|
363
|
+
* above the all-pairs ceiling. `maxIterations` / `tolerance` are refused when defined (P8 PD-25).
|
|
362
364
|
* @param gs - the snapshot
|
|
363
|
-
* @param o - `weighted`, and a sampled run's `sources` (undirected snapshots only)
|
|
365
|
+
* @param o - `weighted`, `harmonic` (exact runs), and a sampled run's `sources` (undirected snapshots only)
|
|
364
366
|
* @returns the f32 scores with `precision: "f32"` (spec 9.7) and `sourcesUsed`
|
|
365
367
|
*/
|
|
366
368
|
async closenessCentrality(gs: GraphSnapshot, o?: ClosenessAcceleratorOptions): Promise<GpuClosenessResult> {
|
|
@@ -34,14 +34,18 @@ import { APSP_PARAMS, FILL_PARAMS, graphBindings, graphOverrides, kernelSpec } f
|
|
|
34
34
|
import { assertWholeCore } from "../primitives/core-shape.js";
|
|
35
35
|
import { assertDeviceComputes } from "../primitives/verify.js";
|
|
36
36
|
import { type ApspOptions, type GpuApspResult } from "../types/all-pairs.js";
|
|
37
|
+
import { type Binding } from "../types/memory.js";
|
|
37
38
|
import { type GpuRunOptions } from "../types/run.js";
|
|
38
|
-
import { algorithmScope } from "./scope.js";
|
|
39
|
+
import { type AlgorithmScope, algorithmScope } from "./scope.js";
|
|
39
40
|
import { aborted, bindingOf, checkDest } from "./sssp.js";
|
|
40
41
|
|
|
41
42
|
const ALGORITHM = "allPairsShortestPath";
|
|
42
43
|
|
|
43
|
-
/**
|
|
44
|
-
|
|
44
|
+
/**
|
|
45
|
+
* The rounds one submit holds by default: three dispatches per round.
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export const DEFAULT_ROUNDS_PER_SUBMIT = Math.floor(APSP_MAX_DISPATCHES_PER_SUBMIT / 3);
|
|
45
49
|
|
|
46
50
|
/**
|
|
47
51
|
* The knobs the tests need and nothing public offers.
|
|
@@ -79,6 +83,83 @@ export function allPairsCeiling(limits: Pick<GPUSupportedLimits, "maxStorageBuff
|
|
|
79
83
|
return { maxNodes, limit, limitName };
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
/**
|
|
87
|
+
* The blocked sweep itself, shared with closeness's all-pairs route: the `n x n` matrix leased from `scope`, filled,
|
|
88
|
+
* initialised from the arcs and swept to the shortest distances, every submit awaited; the matrix stays on the device.
|
|
89
|
+
* The caller has checked the ceiling and the weights.
|
|
90
|
+
* @internal
|
|
91
|
+
* @param ctx - the context
|
|
92
|
+
* @param s - the snapshot (n > 0)
|
|
93
|
+
* @param scope - the scope that leases the matrix and the params records (`min(roundsPerSubmit, blocks) + 2` slots)
|
|
94
|
+
* @param weighted - true sums the snapshot's weights, false counts hops
|
|
95
|
+
* @param roundsPerSubmit - the rounds recorded per submit
|
|
96
|
+
* @param options - signal / onProgress (rounds done of `ceil(n / 32)`)
|
|
97
|
+
* @param algorithm - the name errors carry
|
|
98
|
+
* @returns the matrix binding (`4 n^2` bytes, row-major, `dist[i * n + j]` from `i` to `j`)
|
|
99
|
+
*/
|
|
100
|
+
export async function sweepAllPairs(
|
|
101
|
+
ctx: GpuContext,
|
|
102
|
+
s: GraphSnapshot,
|
|
103
|
+
scope: AlgorithmScope,
|
|
104
|
+
weighted: boolean,
|
|
105
|
+
roundsPerSubmit: number,
|
|
106
|
+
options: GpuRunOptions | undefined,
|
|
107
|
+
algorithm: string,
|
|
108
|
+
): Promise<Binding> {
|
|
109
|
+
const n = s.nodeCount;
|
|
110
|
+
const core = ctx.residency.core(s);
|
|
111
|
+
assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, algorithm);
|
|
112
|
+
const blocks = Math.ceil(n / APSP_TILE);
|
|
113
|
+
const wg = ctx.workgroupSize;
|
|
114
|
+
const bytes = 4 * n * n;
|
|
115
|
+
const matrix = bindingOf(scope.scratch(bytes, "dist"), bytes);
|
|
116
|
+
await ctx.allocator.check();
|
|
117
|
+
const weightsBinding = weighted ? undefined : null;
|
|
118
|
+
const fill = await ctx.pipelines.kernel(kernelSpec("fill"));
|
|
119
|
+
const init = await ctx.pipelines.kernel(kernelSpec("apsp-init", graphOverrides(core, null, weightsBinding)));
|
|
120
|
+
const phases = await Promise.all(
|
|
121
|
+
[0, 1, 2].map((phase) => ctx.pipelines.kernel(kernelSpec("apsp-fw", { PHASE: phase }))),
|
|
122
|
+
);
|
|
123
|
+
const graph = graphBindings(core, null, weightsBinding);
|
|
124
|
+
const others = blocks - 1;
|
|
125
|
+
const phasePlans = [plan2d(1, ctx.caps), plan2d(2 * others, ctx.caps), plan2d(others * others, ctx.caps)];
|
|
126
|
+
|
|
127
|
+
for (let first = 0; first < blocks; first += roundsPerSubmit) {
|
|
128
|
+
const batch = new CommandBatch(ctx, `${algorithm}/sweep`);
|
|
129
|
+
const pass = batch.pass("apsp");
|
|
130
|
+
if (first === 0) {
|
|
131
|
+
const fillParams = scope.params(FILL_PARAMS, { count: n * n, value: F32_INF_BITS, mode: 0, pad0: 0 });
|
|
132
|
+
fill.dispatch(pass, fill.bind({ dst: matrix, P: fillParams.binding }), plan1d(n * n, wg, ctx.caps), [
|
|
133
|
+
fillParams.offset,
|
|
134
|
+
]);
|
|
135
|
+
const initParams = scope.params(APSP_PARAMS, { n, round: 0, blocks, infBits: F32_INF_BITS });
|
|
136
|
+
init.dispatch(pass, init.bind({ ...graph, dist: matrix, P: initParams.binding }), plan1d(n, wg, ctx.caps), [
|
|
137
|
+
initParams.offset,
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
const last = Math.min(first + roundsPerSubmit, blocks);
|
|
141
|
+
for (let round = first; round < last; round++) {
|
|
142
|
+
const params = scope.params(APSP_PARAMS, { n, round, blocks, infBits: F32_INF_BITS });
|
|
143
|
+
for (let phase = 0; phase < 3; phase++) {
|
|
144
|
+
const kernel = phases[phase];
|
|
145
|
+
kernel.dispatch(pass, kernel.bind({ dist: matrix, P: params.binding }), phasePlans[phase], [
|
|
146
|
+
params.offset,
|
|
147
|
+
]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
batch.endPass();
|
|
151
|
+
scope.flush();
|
|
152
|
+
const submitted = batch.submit();
|
|
153
|
+
await submitted.readback;
|
|
154
|
+
ctx.assertReady();
|
|
155
|
+
options?.onProgress?.(last, blocks);
|
|
156
|
+
if (options?.signal?.aborted) {
|
|
157
|
+
throw aborted(algorithm, submitted.id);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return matrix;
|
|
161
|
+
}
|
|
162
|
+
|
|
82
163
|
/**
|
|
83
164
|
* All-pairs shortest paths with the test knobs; `allPairsShortestPath` is this with an empty tuning.
|
|
84
165
|
* @internal
|
|
@@ -145,61 +226,10 @@ export async function allPairsWithTuning(
|
|
|
145
226
|
return { dist, n };
|
|
146
227
|
}
|
|
147
228
|
await assertDeviceComputes(ctx);
|
|
148
|
-
const
|
|
149
|
-
assertWholeCore(core, s.arcCount, ctx.caps.limits.maxStorageBufferBindingSize, ALGORITHM);
|
|
150
|
-
const blocks = Math.ceil(n / APSP_TILE);
|
|
151
|
-
const scope = algorithmScope(ctx, ALGORITHM, Math.min(roundsPerSubmit, blocks) + 2);
|
|
229
|
+
const scope = algorithmScope(ctx, ALGORITHM, Math.min(roundsPerSubmit, Math.ceil(n / APSP_TILE)) + 2);
|
|
152
230
|
try {
|
|
153
|
-
const
|
|
231
|
+
const matrix = await sweepAllPairs(ctx, s, scope, weighted, roundsPerSubmit, options, ALGORITHM);
|
|
154
232
|
const bytes = 4 * n * n;
|
|
155
|
-
const matrix = bindingOf(scope.scratch(bytes, "dist"), bytes);
|
|
156
|
-
await ctx.allocator.check();
|
|
157
|
-
const weightsBinding = weighted ? undefined : null;
|
|
158
|
-
const fill = await ctx.pipelines.kernel(kernelSpec("fill"));
|
|
159
|
-
const init = await ctx.pipelines.kernel(kernelSpec("apsp-init", graphOverrides(core, null, weightsBinding)));
|
|
160
|
-
const phases = await Promise.all(
|
|
161
|
-
[0, 1, 2].map((phase) => ctx.pipelines.kernel(kernelSpec("apsp-fw", { PHASE: phase }))),
|
|
162
|
-
);
|
|
163
|
-
const graph = graphBindings(core, null, weightsBinding);
|
|
164
|
-
const others = blocks - 1;
|
|
165
|
-
const phasePlans = [plan2d(1, ctx.caps), plan2d(2 * others, ctx.caps), plan2d(others * others, ctx.caps)];
|
|
166
|
-
|
|
167
|
-
for (let first = 0; first < blocks; first += roundsPerSubmit) {
|
|
168
|
-
const batch = new CommandBatch(ctx, `${ALGORITHM}/sweep`);
|
|
169
|
-
const pass = batch.pass("apsp");
|
|
170
|
-
if (first === 0) {
|
|
171
|
-
const fillParams = scope.params(FILL_PARAMS, { count: n * n, value: F32_INF_BITS, mode: 0, pad0: 0 });
|
|
172
|
-
fill.dispatch(pass, fill.bind({ dst: matrix, P: fillParams.binding }), plan1d(n * n, wg, ctx.caps), [
|
|
173
|
-
fillParams.offset,
|
|
174
|
-
]);
|
|
175
|
-
const initParams = scope.params(APSP_PARAMS, { n, round: 0, blocks, infBits: F32_INF_BITS });
|
|
176
|
-
init.dispatch(
|
|
177
|
-
pass,
|
|
178
|
-
init.bind({ ...graph, dist: matrix, P: initParams.binding }),
|
|
179
|
-
plan1d(n, wg, ctx.caps),
|
|
180
|
-
[initParams.offset],
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
const last = Math.min(first + roundsPerSubmit, blocks);
|
|
184
|
-
for (let round = first; round < last; round++) {
|
|
185
|
-
const params = scope.params(APSP_PARAMS, { n, round, blocks, infBits: F32_INF_BITS });
|
|
186
|
-
for (let phase = 0; phase < 3; phase++) {
|
|
187
|
-
const kernel = phases[phase];
|
|
188
|
-
kernel.dispatch(pass, kernel.bind({ dist: matrix, P: params.binding }), phasePlans[phase], [
|
|
189
|
-
params.offset,
|
|
190
|
-
]);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
batch.endPass();
|
|
194
|
-
scope.flush();
|
|
195
|
-
const submitted = batch.submit();
|
|
196
|
-
await submitted.readback;
|
|
197
|
-
ctx.assertReady();
|
|
198
|
-
options?.onProgress?.(last, blocks);
|
|
199
|
-
if (options?.signal?.aborted) {
|
|
200
|
-
throw aborted(ALGORITHM, submitted.id);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
233
|
await ctx.readback.read(matrix.buffer, bytes, dist);
|
|
204
234
|
ctx.assertReady();
|
|
205
235
|
return { dist, n };
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*
|
|
31
31
|
* The batch size k is planned from the device limits at 16 bytes per (node, source) -- the three arrays design 4.7
|
|
32
32
|
* counts plus the 4-byte log entry it omits -- as `min(floor(maxStorageBufferBindingSize / 4n), floor(0.25 x
|
|
33
|
-
* maxBufferSize / 16n),
|
|
33
|
+
* maxBufferSize / 16n), BC_MAX_BATCH)` (256), at least 1 (`planBatchSize`); a graph whose single source does not fit one binding is
|
|
34
34
|
* E_TOO_LARGE. The forward form is chosen per batch: the first batch runs `bc-forward`; a later one runs the
|
|
35
35
|
* edge-parallel form when the previous batch's level count -- the MAXIMUM depth over its sources, the only depth
|
|
36
36
|
* figure the host has, which over-estimates the median of design 8.4's rule and so errs toward the frontier form --
|
|
@@ -153,7 +153,7 @@ interface RawBetweenness {
|
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
155
|
* The source batch size (design 8.4, 10.1): `min(floor(maxStorageBufferBindingSize / 4n), floor(0.25 x maxBufferSize /
|
|
156
|
-
* 16n),
|
|
156
|
+
* 16n), BC_MAX_BATCH, remaining)`, at least 1. Each of the four `n x k` arrays is one binding of `4 n k` bytes, and the batch's
|
|
157
157
|
* four together stay inside a quarter of the largest buffer.
|
|
158
158
|
* @internal
|
|
159
159
|
* @param n - the vertex count (>= 1)
|