@graphty/webgpu-graph-algorithms 0.4.1 → 0.5.1
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 +27 -21
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-CRbw2Wyo.js → context-BR7fx3vR.js} +47 -5
- package/dist/chunks/context-BR7fx3vR.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/accelerator.d.ts +15 -12
- package/dist/src/accelerator.d.ts.map +1 -1
- package/dist/src/accelerator.js +35 -12
- package/dist/src/accelerator.js.map +1 -1
- package/dist/src/constants.d.ts +47 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +47 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +8 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/prelude.d.ts.map +1 -1
- package/dist/src/kernel/prelude.js +4 -1
- package/dist/src/kernel/prelude.js.map +1 -1
- package/dist/src/kernels.d.ts +3 -3
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +27 -11
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/force-simulation.d.ts +3 -1
- package/dist/src/layouts/force-simulation.d.ts.map +1 -1
- package/dist/src/layouts/force-simulation.js +13 -3
- package/dist/src/layouts/force-simulation.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts +1 -3
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +2 -191
- package/dist/src/layouts/forceatlas2.js.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.d.ts +195 -0
- package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -0
- package/dist/src/layouts/fruchterman-reingold.js +579 -0
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -0
- package/dist/src/layouts/model-common.d.ts +102 -0
- package/dist/src/layouts/model-common.d.ts.map +1 -0
- package/dist/src/layouts/model-common.js +198 -0
- package/dist/src/layouts/model-common.js.map +1 -0
- package/dist/src/layouts/spring-electrical.d.ts +179 -0
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -0
- package/dist/src/layouts/spring-electrical.js +508 -0
- package/dist/src/layouts/spring-electrical.js.map +1 -0
- package/dist/src/types/accelerator.d.ts +14 -157
- package/dist/src/types/accelerator.d.ts.map +1 -1
- package/dist/src/types/accelerator.js +4 -5
- package/dist/src/types/accelerator.js.map +1 -1
- package/dist/src/types/algorithms.d.ts +1 -1
- package/dist/src/types/algorithms.js +1 -1
- package/dist/src/types/layout.d.ts +32 -0
- package/dist/src/types/layout.d.ts.map +1 -1
- package/dist/src/types/options.d.ts +43 -1
- package/dist/src/types/options.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +5 -2
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-attraction.wgsl.js +6 -1
- package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-integrate.wgsl.d.ts +7 -2
- package/dist/src/wgsl/fa2-integrate.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-integrate.wgsl.js +28 -2
- package/dist/src/wgsl/fa2-integrate.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +4 -2
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +14 -5
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +8 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +33 -0
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/webgpu-graph-algorithms.js +1358 -284
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +6 -3
- package/src/accelerator.ts +49 -14
- package/src/constants.ts +70 -0
- package/src/index.ts +19 -8
- package/src/kernel/prelude.ts +6 -0
- package/src/kernels.ts +27 -11
- package/src/layouts/force-simulation.ts +20 -3
- package/src/layouts/forceatlas2.ts +17 -220
- package/src/layouts/fruchterman-reingold.ts +737 -0
- package/src/layouts/model-common.ts +228 -0
- package/src/layouts/spring-electrical.ts +666 -0
- package/src/types/accelerator.ts +58 -174
- package/src/types/algorithms.ts +1 -1
- package/src/types/layout.ts +36 -0
- package/src/types/options.ts +45 -1
- package/src/wgsl/fa2-attraction.wgsl.ts +6 -1
- package/src/wgsl/fa2-integrate.wgsl.ts +28 -2
- package/src/wgsl/fa2-repulsion-exact.wgsl.ts +14 -5
- package/src/wgsl/fa2-stats-finalize.wgsl.ts +33 -0
- package/dist/chunks/context-CRbw2Wyo.js.map +0 -1
|
@@ -50,22 +50,30 @@ import {
|
|
|
50
50
|
type StateWriter,
|
|
51
51
|
} from "./force-simulation.js";
|
|
52
52
|
import { resolveNodeMass, resolveWeights } from "./inputs.js";
|
|
53
|
+
import {
|
|
54
|
+
describeValue,
|
|
55
|
+
FILL_PARAMS_BUFFER,
|
|
56
|
+
FORCE_BYTES_PER_NODE,
|
|
57
|
+
invalid,
|
|
58
|
+
isPositiveInteger,
|
|
59
|
+
type Overrides,
|
|
60
|
+
pickBoolean,
|
|
61
|
+
pickCenter,
|
|
62
|
+
pickDim,
|
|
63
|
+
pickNumber,
|
|
64
|
+
pickSeed,
|
|
65
|
+
scalar,
|
|
66
|
+
seedWord,
|
|
67
|
+
subset,
|
|
68
|
+
vector,
|
|
69
|
+
} from "./model-common.js";
|
|
53
70
|
import { RepulsionExact, type RepulsionExactOverrides } from "./repulsion-exact.js";
|
|
54
71
|
|
|
55
72
|
// ============================================================ constants and small helpers
|
|
56
73
|
|
|
57
|
-
/** An override record as the kernel layer takes it. */
|
|
58
|
-
type Overrides = Readonly<Record<string, number | boolean>>;
|
|
59
|
-
|
|
60
74
|
/** The stage names of one iteration in dispatch order plus the per-batch toScene (spec 7.4; contract 3.13). */
|
|
61
75
|
const FA2_STAGES = ["K1", "K2", "K3", "K4", "K5", "toScene"] as const;
|
|
62
76
|
|
|
63
|
-
/** Bytes of the stride-3 f32 force arrays per node. */
|
|
64
|
-
const FORCE_BYTES_PER_NODE = 12;
|
|
65
|
-
|
|
66
|
-
/** The name of the model-owned FillParams buffer (a BufferSpec, reached through ModelResources.buffer). */
|
|
67
|
-
const FILL_PARAMS_BUFFER = "fillParams";
|
|
68
|
-
|
|
69
77
|
/** The one-workgroup dispatch of K1 (spec 7.4). */
|
|
70
78
|
const ONE_WORKGROUP: DispatchPlan = { x: 1, y: 1, z: 1, items: 1, stride: null };
|
|
71
79
|
|
|
@@ -75,9 +83,6 @@ const K2_DEFAULTS: Overrides = { LINLOG: false, DISTRIBUTED: false, TIER: 0, USE
|
|
|
75
83
|
/** Every override K5 accepts, with its default. */
|
|
76
84
|
const K5_DEFAULTS: Overrides = { SWING_MODE: 0 };
|
|
77
85
|
|
|
78
|
-
/** 2^32, the modulus of the u32 seed word (computed with `%`, never a bitwise operator). */
|
|
79
|
-
const U32_MODULUS = 4294967296;
|
|
80
|
-
|
|
81
86
|
/** The resolved record with no option given: FA2_DEFAULTS plus the null / origin defaults of spec 7.14. */
|
|
82
87
|
const DEFAULT_RESOLVED: ResolvedForceAtlas2Options = Object.freeze<ResolvedForceAtlas2Options>({
|
|
83
88
|
...FA2_DEFAULTS,
|
|
@@ -88,214 +93,6 @@ const DEFAULT_RESOLVED: ResolvedForceAtlas2Options = Object.freeze<ResolvedForce
|
|
|
88
93
|
seed: null,
|
|
89
94
|
});
|
|
90
95
|
|
|
91
|
-
/**
|
|
92
|
-
* A short, safe rendering of an argument value for error messages (never String() on an object).
|
|
93
|
-
* @param value - the value
|
|
94
|
-
* @returns the rendering
|
|
95
|
-
*/
|
|
96
|
-
function describeValue(value: unknown): string {
|
|
97
|
-
if (value === null) {
|
|
98
|
-
return "null";
|
|
99
|
-
}
|
|
100
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
|
|
101
|
-
return String(value);
|
|
102
|
-
}
|
|
103
|
-
if (typeof value === "undefined") {
|
|
104
|
-
return "undefined";
|
|
105
|
-
}
|
|
106
|
-
if (typeof value === "object" && "length" in value && typeof value.length === "number") {
|
|
107
|
-
return `[${value.length} values]`;
|
|
108
|
-
}
|
|
109
|
-
return typeof value;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* The E_INVALID_ARGUMENT error of an option check (contract 3.1: { argument, value, expected }).
|
|
114
|
-
* @param argument - the option name
|
|
115
|
-
* @param value - the value given
|
|
116
|
-
* @param expected - what was expected
|
|
117
|
-
* @returns the error (not thrown here)
|
|
118
|
-
*/
|
|
119
|
-
function invalid(argument: string, value: unknown, expected: string): WebGpuGraphError {
|
|
120
|
-
return new WebGpuGraphError("E_INVALID_ARGUMENT", `${argument} must be ${expected}; got ${describeValue(value)}`, {
|
|
121
|
-
argument,
|
|
122
|
-
value,
|
|
123
|
-
expected,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* A numeric option: the given value when defined, else the fallback; validated by `check` (the value is checked as
|
|
129
|
-
* `unknown` so a JS caller's string or object is E_INVALID_ARGUMENT too).
|
|
130
|
-
* @param name - the option name
|
|
131
|
-
* @param given - the value given (undefined = absent)
|
|
132
|
-
* @param fallback - the previous record's value or the default
|
|
133
|
-
* @param check - the range predicate over a finite number
|
|
134
|
-
* @param expected - the range in words (the error message)
|
|
135
|
-
* @returns the value
|
|
136
|
-
*/
|
|
137
|
-
function pickNumber(
|
|
138
|
-
name: string,
|
|
139
|
-
given: number | undefined,
|
|
140
|
-
fallback: number,
|
|
141
|
-
check: (value: number) => boolean,
|
|
142
|
-
expected: string,
|
|
143
|
-
): number {
|
|
144
|
-
const value: unknown = given === undefined ? fallback : given;
|
|
145
|
-
if (typeof value !== "number" || !Number.isFinite(value) || !check(value)) {
|
|
146
|
-
throw invalid(name, value, expected);
|
|
147
|
-
}
|
|
148
|
-
return value;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* A boolean option: the given value when defined, else the fallback; a non-boolean is E_INVALID_ARGUMENT.
|
|
153
|
-
* @param name - the option name
|
|
154
|
-
* @param given - the value given (undefined = absent)
|
|
155
|
-
* @param fallback - the previous record's value or the default
|
|
156
|
-
* @returns the value
|
|
157
|
-
*/
|
|
158
|
-
function pickBoolean(name: string, given: boolean | undefined, fallback: boolean): boolean {
|
|
159
|
-
const value: unknown = given === undefined ? fallback : given;
|
|
160
|
-
if (typeof value !== "boolean") {
|
|
161
|
-
throw invalid(name, value, "a boolean");
|
|
162
|
-
}
|
|
163
|
-
return value;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* The layout dimension: 2 or 3.
|
|
168
|
-
* @param given - the value given (undefined = absent)
|
|
169
|
-
* @param fallback - the previous record's value or the default
|
|
170
|
-
* @returns 2 or 3
|
|
171
|
-
*/
|
|
172
|
-
function pickDim(given: 2 | 3 | undefined, fallback: 2 | 3): 2 | 3 {
|
|
173
|
-
const value: unknown = given === undefined ? fallback : given;
|
|
174
|
-
if (value !== 2 && value !== 3) {
|
|
175
|
-
throw invalid("dim", value, "2 or 3");
|
|
176
|
-
}
|
|
177
|
-
return value;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* The scene-unit center: an array-like of 2 (z = 0) or 3 finite numbers.
|
|
182
|
-
* @param given - the value given (undefined = absent)
|
|
183
|
-
* @param fallback - the previous record's value or the default
|
|
184
|
-
* @returns the three components
|
|
185
|
-
*/
|
|
186
|
-
function pickCenter(
|
|
187
|
-
given: ArrayLike<number> | undefined,
|
|
188
|
-
fallback: readonly [number, number, number],
|
|
189
|
-
): readonly [number, number, number] {
|
|
190
|
-
if (given === undefined) {
|
|
191
|
-
return fallback;
|
|
192
|
-
}
|
|
193
|
-
const expected = "an array of 2 or 3 finite numbers";
|
|
194
|
-
const value: unknown = given;
|
|
195
|
-
if (typeof value !== "object" || value === null || !("length" in value)) {
|
|
196
|
-
throw invalid("center", given, expected);
|
|
197
|
-
}
|
|
198
|
-
const { length } = value;
|
|
199
|
-
if (length !== 2 && length !== 3) {
|
|
200
|
-
throw invalid("center", given, expected);
|
|
201
|
-
}
|
|
202
|
-
const x: unknown = given[0];
|
|
203
|
-
const y: unknown = given[1];
|
|
204
|
-
const z: unknown = length === 3 ? given[2] : 0;
|
|
205
|
-
if (
|
|
206
|
-
typeof x !== "number" ||
|
|
207
|
-
typeof y !== "number" ||
|
|
208
|
-
typeof z !== "number" ||
|
|
209
|
-
!Number.isFinite(x) ||
|
|
210
|
-
!Number.isFinite(y) ||
|
|
211
|
-
!Number.isFinite(z)
|
|
212
|
-
) {
|
|
213
|
-
throw invalid("center", given, expected);
|
|
214
|
-
}
|
|
215
|
-
return [x, y, z];
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* The seed: a finite number, or null (unseeded; 0 keeps the port's "0 = unseeded" quirk through the Lcg).
|
|
220
|
-
* @param given - the value given (undefined = absent)
|
|
221
|
-
* @param fallback - the previous record's value or the default
|
|
222
|
-
* @returns the seed or null
|
|
223
|
-
*/
|
|
224
|
-
function pickSeed(given: number | null | undefined, fallback: number | null): number | null {
|
|
225
|
-
if (given === undefined) {
|
|
226
|
-
return fallback;
|
|
227
|
-
}
|
|
228
|
-
const value: unknown = given;
|
|
229
|
-
if (value !== null && (typeof value !== "number" || !Number.isFinite(value))) {
|
|
230
|
-
throw invalid("seed", given, "a finite number or null");
|
|
231
|
-
}
|
|
232
|
-
return value;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Integer >= 1.
|
|
237
|
-
* @param value - a finite number
|
|
238
|
-
* @returns whether it is a positive integer
|
|
239
|
-
*/
|
|
240
|
-
function isPositiveInteger(value: number): boolean {
|
|
241
|
-
return Number.isInteger(value) && value >= 1;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* The u32 word written into Fa2Params.seed: 0 for null, else floor(|seed|) mod 2^32.
|
|
246
|
-
* @param seed - the resolved seed
|
|
247
|
-
* @returns the u32 value
|
|
248
|
-
*/
|
|
249
|
-
function seedWord(seed: number | null): number {
|
|
250
|
-
if (seed === null) {
|
|
251
|
-
return 0;
|
|
252
|
-
}
|
|
253
|
-
return Math.floor(Math.abs(seed)) % U32_MODULUS;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* A scalar field of a block's read() result.
|
|
258
|
-
* @param values - the values read
|
|
259
|
-
* @param name - the field name
|
|
260
|
-
* @returns the number
|
|
261
|
-
*/
|
|
262
|
-
function scalar(values: UniformValues, name: string): number {
|
|
263
|
-
const value = values[name];
|
|
264
|
-
if (typeof value !== "number") {
|
|
265
|
-
throw invalid(name, value, "a scalar field");
|
|
266
|
-
}
|
|
267
|
-
return value;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* A vector field of a block's read() result.
|
|
272
|
-
* @param values - the values read
|
|
273
|
-
* @param name - the field name
|
|
274
|
-
* @returns the components
|
|
275
|
-
*/
|
|
276
|
-
function vector(values: UniformValues, name: string): readonly number[] {
|
|
277
|
-
const value = values[name];
|
|
278
|
-
if (typeof value === "number") {
|
|
279
|
-
throw invalid(name, value, "a vector field");
|
|
280
|
-
}
|
|
281
|
-
return value;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* The override record a kernel gets: its defaults overlaid with the values present in the merged set (contract 3.9:
|
|
286
|
-
* a name a spec does not declare is rejected at compose time, so nothing else is passed through).
|
|
287
|
-
* @param merged - the merged override set of the model (plus USE_PERM / HAS_WEIGHTS from the simulation)
|
|
288
|
-
* @param defaults - the kernel's accepted names with their defaults
|
|
289
|
-
* @returns the kernel's override record, every accepted name explicit
|
|
290
|
-
*/
|
|
291
|
-
function subset(merged: Overrides, defaults: Overrides): Overrides {
|
|
292
|
-
const out: Record<string, number | boolean> = {};
|
|
293
|
-
for (const name of Object.keys(defaults)) {
|
|
294
|
-
out[name] = name in merged ? merged[name] : defaults[name];
|
|
295
|
-
}
|
|
296
|
-
return out;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
96
|
/**
|
|
300
97
|
* The K3 / K4 override values of a merged set (typed for RepulsionExact).
|
|
301
98
|
* @param merged - the merged override set
|