@graphty/webgpu-graph-algorithms 0.6.19 → 0.6.21
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/dist/src/algorithms/bellman-ford.d.ts +1 -1
- package/dist/src/algorithms/bellman-ford.js +2 -2
- package/dist/src/algorithms/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/power-iteration.d.ts.map +1 -1
- package/dist/src/algorithms/power-iteration.js +3 -0
- package/dist/src/algorithms/power-iteration.js.map +1 -1
- package/dist/src/wgsl/bf-relax.wgsl.d.ts +5 -2
- package/dist/src/wgsl/bf-relax.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/bf-relax.wgsl.js +9 -4
- package/dist/src/wgsl/bf-relax.wgsl.js.map +1 -1
- package/dist/webgpu-graph-algorithms.js +6 -3
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +4 -4
- package/src/algorithms/bellman-ford.ts +3 -3
- package/src/algorithms/power-iteration.ts +3 -0
- package/src/wgsl/bf-relax.wgsl.ts +9 -4
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.21",
|
|
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",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"homepage": "https://github.com/graphty-org/graphty-monorepo/tree/master/webgpu-graph-algorithms#readme",
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@webgpu/types": "^0.1.72",
|
|
64
|
-
"@graphty/graph-format": "^1.2.
|
|
64
|
+
"@graphty/graph-format": "^1.2.6"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"@graphty/algorithms": "^1.0.0 || ^2.0.0 || ^3.0.0",
|
|
@@ -95,8 +95,8 @@
|
|
|
95
95
|
"vite": "^7.0.5",
|
|
96
96
|
"vitest": "4.1.11",
|
|
97
97
|
"webgpu": "0.4.0",
|
|
98
|
-
"@graphty/algorithms": "^3.1.
|
|
99
|
-
"@graphty/layout": "^2.0.
|
|
98
|
+
"@graphty/algorithms": "^3.1.5",
|
|
99
|
+
"@graphty/layout": "^2.0.6"
|
|
100
100
|
},
|
|
101
101
|
"scripts": {
|
|
102
102
|
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `changed` after it IS `hasNegativeCycle`; the last batch is clamped so the reported round count never exceeds
|
|
9
9
|
* `n - 1`. `dist` holds f32 bit patterns and the claim is a BOUNDED compare-exchange (PD-12: `MAX_RETRIES`, because
|
|
10
10
|
* with a negative distance the bit-pattern order reverses and `atomicMin` is wrong, and WGSL lets the exchange fail
|
|
11
|
-
* spuriously): a lane that exhausts the bound raises `retryExhausted`, which the driver treats as changed and runs
|
|
11
|
+
* spuriously; only those spurious failures count, never a loss to another lane's improvement, issue #470): a lane that exhausts the bound raises `retryExhausted`, which the driver treats as changed and runs
|
|
12
12
|
* on -- the lost update is retried by the next round, which examines every edge anyway -- and tallies for the tests;
|
|
13
13
|
* raised in the decision round it is E_VALIDATION, never a guess.
|
|
14
14
|
*
|
|
@@ -74,7 +74,7 @@ const ALGORITHM = "bellmanFord";
|
|
|
74
74
|
/** Design 8.4: the changed flag is read every 8 rounds (one `mapAsync` per batch). */
|
|
75
75
|
const ROUNDS_PER_BATCH = 8;
|
|
76
76
|
|
|
77
|
-
/** PD-12: the compare-exchange
|
|
77
|
+
/** PD-12: the bound on one lane's SPURIOUS compare-exchange failures (a loss to another lane is not counted, issue #470). */
|
|
78
78
|
const MAX_RETRIES = 16;
|
|
79
79
|
|
|
80
80
|
/**
|
|
@@ -89,7 +89,7 @@ const RING_SLOTS = MAX_LEVELS_PER_SUBMIT + 16;
|
|
|
89
89
|
* @internal
|
|
90
90
|
*/
|
|
91
91
|
export interface BellmanFordTuning {
|
|
92
|
-
/** The compare-exchange retry bound per lane (default `MAX_RETRIES`); 1 makes
|
|
92
|
+
/** The compare-exchange retry bound per lane (default `MAX_RETRIES`), on spurious failures only; 1 makes the first one exhaust it. */
|
|
93
93
|
readonly maxRetries?: number | undefined;
|
|
94
94
|
/** Rounds recorded per batch (default `ROUNDS_PER_BATCH`), each batch one readback of the flags. */
|
|
95
95
|
readonly roundsPerBatch?: number | undefined;
|
|
@@ -124,6 +124,9 @@ export function coreOf(ctx: GpuContext, s: GraphSnapshot, algorithm: string): Co
|
|
|
124
124
|
* @returns the reverse core
|
|
125
125
|
*/
|
|
126
126
|
export function reverseOf(ctx: GpuContext, s: GraphSnapshot): CoreBinding {
|
|
127
|
+
// core() is what records (or re-records, after a release) the snapshot in the residency; Katz binds only this
|
|
128
|
+
// view, so without it a released snapshot is E_RELEASED instead of uploaded again (issue #623)
|
|
129
|
+
ctx.residency.core(s, ["rowPtr"]);
|
|
127
130
|
const view = ctx.residency.view(s, "reverse");
|
|
128
131
|
return coreOfView(view, view.scalars.arcCount[0]);
|
|
129
132
|
}
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
* the values for NON-NEGATIVE floats only (PD-9); with a negative distance the bit-pattern order reverses, so the
|
|
9
9
|
* claim is a compare-exchange loop on the pattern: read, compute, compare as floats, try to exchange. WGSL lets
|
|
10
10
|
* `atomicCompareExchangeWeak` fail spuriously, so the loop is BOUNDED (PD-12: `P.maxRetries`, the driver's
|
|
11
|
-
* `MAX_RETRIES
|
|
11
|
+
* `MAX_RETRIES`) -- on SPURIOUS failures only (`old_value == cur`). A failure that returns another value lost to
|
|
12
|
+
* another lane's successful exchange, which strictly lowered `dist[v]`; that happens at most once per edge into
|
|
13
|
+
* `v` per round, so those iterations are bounded by the in-degree and never counted (issue #470: counted, 32
|
|
14
|
+
* descending candidates in one 32-wide subgroup needed 31 attempts and exhausted 16). A lane that exhausts it sets `flags[1]`
|
|
12
15
|
* (`retryExhausted`): the driver treats the round as changed and runs on, so the lost update is retried by the next
|
|
13
16
|
* round, which examines every edge anyway; a bound hit in the decision round is E_VALIDATION, never a guess. A
|
|
14
17
|
* successful exchange sets `flags[0]` (`changed`); the driver stops when a batch of rounds changed nothing, and a
|
|
@@ -26,9 +29,11 @@ fn relax(v: u32, nd: f32) {
|
|
|
26
29
|
if (!(nd < bitcast<f32>(cur))) { break; } // no improvement; +Inf is greater than every finite nd
|
|
27
30
|
let r = atomicCompareExchangeWeak(&dist[v], cur, bitcast<u32>(nd));
|
|
28
31
|
if (r.exchanged) { atomicStore(&flags[0], 1u); break; } // changed
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
if (r.old_value == cur) { // a spurious failure: the only kind the bound counts
|
|
33
|
+
tries = tries + 1u;
|
|
34
|
+
if (tries >= P.maxRetries) { atomicStore(&flags[1], 1u); break; } // retryExhausted (PD-12)
|
|
35
|
+
}
|
|
36
|
+
cur = r.old_value; // else another lane's improvement won (issue #470)
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
39
|
|