wgblas 0.1.0

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 (43) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +161 -0
  3. package/dist/wgblas.browser.js +422 -0
  4. package/index.d.mts +94 -0
  5. package/index.mjs +16 -0
  6. package/package.json +127 -0
  7. package/src/classes/GpuVector.d.mts +69 -0
  8. package/src/classes/GpuVector.mjs +33 -0
  9. package/src/devdocs.mjs +81 -0
  10. package/src/index.mjs +4 -0
  11. package/src/init.mjs +105 -0
  12. package/src/isamax/isamax.d.mts +46 -0
  13. package/src/isamax/isamax.mjs +115 -0
  14. package/src/random/random.d.mts +61 -0
  15. package/src/random/random.mjs +11 -0
  16. package/src/sasum/sasum.d.mts +44 -0
  17. package/src/sasum/sasum.mjs +98 -0
  18. package/src/saxpy/saxpy.d.mts +54 -0
  19. package/src/saxpy/saxpy.mjs +90 -0
  20. package/src/scopy/scopy.d.mts +50 -0
  21. package/src/scopy/scopy.mjs +87 -0
  22. package/src/sdot/sdot.d.mts +52 -0
  23. package/src/sdot/sdot.mjs +118 -0
  24. package/src/shaders/browser-shaders.mjs +27 -0
  25. package/src/shaders/index.mjs +27 -0
  26. package/src/snrm2/snrm2.d.mts +44 -0
  27. package/src/snrm2/snrm2.mjs +100 -0
  28. package/src/srot/srot.d.mts +62 -0
  29. package/src/srot/srot.mjs +95 -0
  30. package/src/srotm/srotm.d.mts +60 -0
  31. package/src/srotm/srotm.mjs +94 -0
  32. package/src/sscal/sscal.d.mts +46 -0
  33. package/src/sscal/sscal.mjs +71 -0
  34. package/src/sswap/sswap.d.mts +50 -0
  35. package/src/sswap/sswap.mjs +90 -0
  36. package/src/util/benchmark.mjs +103 -0
  37. package/src/util/bindgroup.mjs +22 -0
  38. package/src/util/buffer.mjs +160 -0
  39. package/src/util/compute.mjs +52 -0
  40. package/src/util/index.mjs +12 -0
  41. package/src/util/pipeline.mjs +82 -0
  42. package/src/util/result.mjs +19 -0
  43. package/src/util/workgroup.mjs +31 -0
package/package.json ADDED
@@ -0,0 +1,127 @@
1
+ {
2
+ "name": "wgblas",
3
+ "version": "0.1.0",
4
+ "description": "BLAS on WebGPU",
5
+ "type": "module",
6
+ "main": "index.mjs",
7
+ "types": "./index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./index.mjs",
11
+ "types": "./index.d.mts"
12
+ },
13
+ "./browser": "./dist/wgblas.browser.js",
14
+ "./classes/GpuVector": {
15
+ "import": "./src/classes/GpuVector.mjs",
16
+ "types": "./src/classes/GpuVector.d.mts"
17
+ },
18
+ "./random": {
19
+ "import": "./src/random/random.mjs",
20
+ "types": "./src/random/random.d.mts"
21
+ },
22
+ "./sscal": {
23
+ "import": "./src/sscal/sscal.mjs",
24
+ "types": "./src/sscal/sscal.d.mts"
25
+ },
26
+ "./sswap": {
27
+ "import": "./src/sswap/sswap.mjs",
28
+ "types": "./src/sswap/sswap.d.mts"
29
+ },
30
+ "./saxpy": {
31
+ "import": "./src/saxpy/saxpy.mjs",
32
+ "types": "./src/saxpy/saxpy.d.mts"
33
+ },
34
+ "./scopy": {
35
+ "import": "./src/scopy/scopy.mjs",
36
+ "types": "./src/scopy/scopy.d.mts"
37
+ },
38
+ "./sdot": {
39
+ "import": "./src/sdot/sdot.mjs",
40
+ "types": "./src/sdot/sdot.d.mts"
41
+ },
42
+ "./sasum": {
43
+ "import": "./src/sasum/sasum.mjs",
44
+ "types": "./src/sasum/sasum.d.mts"
45
+ },
46
+ "./snrm2": {
47
+ "import": "./src/snrm2/snrm2.mjs",
48
+ "types": "./src/snrm2/snrm2.d.mts"
49
+ },
50
+ "./isamax": {
51
+ "import": "./src/isamax/isamax.mjs",
52
+ "types": "./src/isamax/isamax.d.mts"
53
+ },
54
+ "./srot": {
55
+ "import": "./src/srot/srot.mjs",
56
+ "types": "./src/srot/srot.d.mts"
57
+ },
58
+ "./srotm": {
59
+ "import": "./src/srotm/srotm.mjs",
60
+ "types": "./src/srotm/srotm.d.mts"
61
+ }
62
+ },
63
+ "files": [
64
+ "index.mjs",
65
+ "index.d.mts",
66
+ "src/**/*.mjs",
67
+ "src/**/*.d.mts",
68
+ "dist/wgblas.browser.js"
69
+ ],
70
+ "repository": {
71
+ "type": "git",
72
+ "url": "git+https://github.com/manit2004/wgblas.git"
73
+ },
74
+ "keywords": [
75
+ "BLAS",
76
+ "WebGPU"
77
+ ],
78
+ "author": "Manit Roy",
79
+ "license": "Apache-2.0",
80
+ "engines": {
81
+ "node": ">=22.22.2"
82
+ },
83
+ "bugs": {
84
+ "url": "https://github.com/manit2004/wgblas/issues"
85
+ },
86
+ "homepage": "https://github.com/manit2004/wgblas#readme",
87
+ "dependencies": {
88
+ "webgpu": "^0.4.0"
89
+ },
90
+ "devDependencies": {
91
+ "@eslint/js": "^10.0.1",
92
+ "@stdlib/blas-base-isamax": "^0.1.1",
93
+ "@stdlib/blas-base-sasum": "^0.3.1",
94
+ "@stdlib/blas-base-saxpy": "^0.3.1",
95
+ "@stdlib/blas-base-scopy": "^0.3.1",
96
+ "@stdlib/blas-base-sdot": "^0.3.1",
97
+ "@stdlib/blas-base-snrm2": "^0.3.1",
98
+ "@stdlib/blas-base-srot": "^0.2.1",
99
+ "@stdlib/blas-base-srotm": "^0.2.1",
100
+ "@stdlib/blas-base-sscal": "^0.3.1",
101
+ "@stdlib/blas-base-sswap": "^0.3.1",
102
+ "@stdlib/random-array-uniform": "^0.2.2",
103
+ "@stdlib/random-base-uniform": "^0.2.3",
104
+ "esbuild": "^0.28.1",
105
+ "eslint": "^10.6.0",
106
+ "fast-check": "^4.8.0",
107
+ "globals": "^17.7.0",
108
+ "husky": "^9.1.7",
109
+ "lint-staged": "^17.0.8",
110
+ "prettier": "^3.9.4",
111
+ "typedoc": "^0.28.19",
112
+ "typescript": "^6.0.3",
113
+ "vite": "^8.0.16"
114
+ },
115
+ "scripts": {
116
+ "prepare": "husky",
117
+ "build:browser": "node scripts/build-browser.mjs",
118
+ "docs": "npx typedoc && npm run build:browser",
119
+ "prepublishOnly": "npm run build:browser"
120
+ },
121
+ "lint-staged": {
122
+ "*.{js,mjs,cjs}": [
123
+ "prettier --write",
124
+ "eslint"
125
+ ]
126
+ }
127
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Represents a Float32Array stored in GPU memory.
3
+ *
4
+ * @see <a href="https://github.com/manit2004/wgblas/blob/main/src/classes/GpuVector.mjs#L7">Source code: GpuVector.mjs (L7)</a>
5
+ * @see [MDN: GPUBuffer](https://developer.mozilla.org/en-US/docs/Web/API/GPUBuffer)
6
+ * @category Classes
7
+ */
8
+ export declare class GpuVector {
9
+ /** @internal */
10
+ readonly _buf: GPUBuffer;
11
+
12
+ /** Number of elements in the vector. */
13
+ readonly length: number;
14
+
15
+ // TODO: widen to Float32ArrayConstructor | Float64ArrayConstructor when Float64 support is added
16
+ /** Typed array constructor used when reading data back from the GPU. */
17
+ readonly dtype: Float32ArrayConstructor;
18
+
19
+ /**
20
+ * Uploads a Float32Array to GPU memory.
21
+ *
22
+ * @param data - input vector data
23
+ * @returns GpuVector backed by a GPU buffer
24
+ *
25
+ * @example
26
+ * ```js
27
+ * import { init, GpuVector } from "wgblas";
28
+ *
29
+ * await init();
30
+ * const vec = GpuVector.from(new Float32Array([1, 2, 3, 4]));
31
+ * console.log("length:", vec.length, "dtype:", vec.dtype.name);
32
+ * ```
33
+ */
34
+ static from(data: Float32Array): GpuVector;
35
+
36
+ // TODO: return type will widen to Promise<Float32Array | Float64Array> when Float64 support is added
37
+ /**
38
+ * Reads the vector data back from GPU memory.
39
+ *
40
+ * @returns vector data as a Float32Array
41
+ *
42
+ * @example
43
+ * ```js
44
+ * import { init, GpuVector } from "wgblas";
45
+ *
46
+ * await init();
47
+ * const vec = GpuVector.from(new Float32Array([1, 2, 3, 4]));
48
+ * const data = await vec.read();
49
+ * console.log(data);
50
+ * ```
51
+ */
52
+ read(): Promise<Float32Array>;
53
+
54
+ /**
55
+ * Destroys the underlying GPU buffer. Call when the vector is no longer needed
56
+ * to free GPU memory — especially important in long-running programs.
57
+ *
58
+ * @example
59
+ * ```js
60
+ * import { init, GpuVector } from "wgblas";
61
+ *
62
+ * await init();
63
+ * const vec = GpuVector.from(new Float32Array([1, 2, 3, 4]));
64
+ * vec.destroy();
65
+ * console.log("GPU buffer released");
66
+ * ```
67
+ */
68
+ destroy(): void;
69
+ }
@@ -0,0 +1,33 @@
1
+ import { getDevice } from "../init.mjs";
2
+ import { uploadBuffer, stageReadback } from "../util/buffer.mjs";
3
+ import { extractResult } from "../util/result.mjs";
4
+
5
+ //TODO: Need to update this when we support Float64Array.
6
+
7
+ export class GpuVector {
8
+ constructor(buffer, length, dtype = Float32Array) {
9
+ this._buf = buffer;
10
+ this.length = length;
11
+ this.dtype = dtype;
12
+ }
13
+
14
+ static from(data) {
15
+ if (!(data instanceof Float32Array)) {
16
+ throw new Error("GpuVector.from expects a Float32Array.");
17
+ }
18
+ const buf = uploadBuffer(data, "gpu-vector", true);
19
+ return new GpuVector(buf, data.length, data.constructor);
20
+ }
21
+
22
+ async read() {
23
+ const device = getDevice();
24
+ const enc = device.createCommandEncoder();
25
+ const rb = stageReadback(enc, this._buf);
26
+ device.queue.submit([enc.finish()]);
27
+ return extractResult(rb, this.dtype);
28
+ }
29
+
30
+ destroy() {
31
+ this._buf.destroy();
32
+ }
33
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * A repo tour for contributors, learners, and anyone curious how a GPU BLAS
3
+ * library is built. Each section mirrors a major folder or system in the
4
+ * repository and explains the reasoning behind it — not just what the code
5
+ * does, but why it is shaped the way it is.
6
+ *
7
+ * ## What is BLAS?
8
+ *
9
+ * BLAS (Basic Linear Algebra Subprograms) is a standard API for vector and
10
+ * matrix operations — dot products, norms, scalar multiplies, matrix-vector
11
+ * products. It is the computational backbone of numerical computing, machine
12
+ * learning frameworks, and scientific software. The reference spec lives at
13
+ * [netlib.org/blas](https://www.netlib.org/blas/).
14
+ *
15
+ * GPUs are well-suited for BLAS: operations like saxpy (y = αx + y) are
16
+ * embarrassingly parallel — each element is independent — so thousands of GPU
17
+ * threads can work simultaneously. NVIDIA's
18
+ * [cuBLAS](https://docs.nvidia.com/cuda/cublas/) is the canonical example;
19
+ * this library applies the same idea to the browser via WebGPU.
20
+ *
21
+ * ## What is WebGPU?
22
+ *
23
+ * WebGPU is the modern browser GPU API, shipping in Chrome 113+ and Firefox
24
+ * nightly. It lets JavaScript programs upload data to the GPU, run compute
25
+ * programs on it, and read results back — without plugins or native code.
26
+ *
27
+ * > **Note:** WGSL does not support `f64` natively, so this library currently
28
+ * > implements single-precision (`f32`) routines only.
29
+ *
30
+ * ## What is a compute shader?
31
+ *
32
+ * Each routine runs a **compute shader** written in WGSL (a GPU program that
33
+ * runs thousands of instances in parallel, each processing one element). WebGPU
34
+ * has vertex and fragment shaders for graphics too — compute shaders are
35
+ * specifically for general computation. This library only uses compute shaders,
36
+ * so we call them simply "shaders" throughout.
37
+ *
38
+ * ## New to GPU programming?
39
+ *
40
+ * Read these two chapters from the CUDA Programming Guide — the mental models
41
+ * transfer directly to WebGPU; only the terminology changes. Then come back here.
42
+ *
43
+ * - [Introduction](https://docs.nvidia.com/cuda/cuda-programming-guide/01-introduction/introduction.html) —
44
+ * why GPUs exist, GPU vs CPU design philosophy
45
+ * - [Programming Model](https://docs.nvidia.com/cuda/cuda-programming-guide/01-introduction/programming-model.html) —
46
+ * threads, blocks, grids, warps, memory hierarchy
47
+ *
48
+ * ### CUDA → WebGPU terminology
49
+ *
50
+ * | CUDA | WebGPU |
51
+ * |---|---|
52
+ * | Thread | Invocation |
53
+ * | Thread block | Workgroup |
54
+ * | Grid | Dispatch |
55
+ * | `__global__` function | `@compute` shader |
56
+ * | `threadIdx.x` | `local_invocation_id` |
57
+ * | `blockIdx.x` | `workgroup_id` |
58
+ * | `blockDim.x` | `@workgroup_size(N)` |
59
+ * | Shared memory | `var<workgroup>` |
60
+ * | Global memory | Storage buffer |
61
+ * | `cudaMemcpy` host→device | `device.queue.writeBuffer` |
62
+ * | `cudaMemcpy` device→host | `mapAsync` + `getMappedRange` |
63
+ *
64
+ * ## WebGPU resources
65
+ *
66
+ * - [WebGPU Fundamentals](https://webgpufundamentals.org/webgpu/lessons/webgpu-fundamentals.html#a-run-computations-on-the-gpu) —
67
+ * running computations on the GPU
68
+ * - [WebGPU Compute Shaders](https://webgpufundamentals.org/webgpu/lessons/webgpu-compute-shaders.html)
69
+ * - [GPU Compute with WebGPU](https://developer.chrome.com/docs/capabilities/web-apis/gpu-compute?hl=en) —
70
+ * Chrome's practical guide to compute pipelines
71
+ * - [Chrome WebGPU overview](https://developer.chrome.com/docs/web-platform/webgpu/overview?hl=en)
72
+ *
73
+ * ### Further reading
74
+ *
75
+ * - [Chrome "New in WebGPU" series](https://developer.chrome.com/tags/new-in-webgpu) —
76
+ * feature-by-feature changelog with code examples
77
+ * - [MDN WebGPU API](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API)
78
+ * - [W3C WebGPU spec](https://www.w3.org/TR/webgpu/)
79
+ *
80
+ * @module devdocs
81
+ */
package/src/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * {@include ./README.md}
3
+ * @module devdocs/blas-routines
4
+ */
package/src/init.mjs ADDED
@@ -0,0 +1,105 @@
1
+ import { benchmarkMode } from "./util/benchmark.mjs";
2
+
3
+ let _device = null;
4
+ let _adapter = null;
5
+ let _gpu = null; // eslint-disable-line no-unused-vars
6
+ let _benchmarkEnabled = false;
7
+
8
+
9
+ // ── Public API ───────────────────────────────────────────────────────────────
10
+
11
+ export async function init({
12
+ powerPreference = "high-performance",
13
+ benchmark = false,
14
+ } = {}) {
15
+ if (_device) {
16
+ return _device;
17
+ }
18
+
19
+ let gpu;
20
+ // Browser exposes WebGPU natively via navigator.gpu.
21
+ // Node.js has no navigator, so we polyfill using the "webgpu" npm package which also
22
+ // injects WebGPU globals (GPUBufferUsage, GPUShaderStage, etc.) into globalThis.
23
+ if (typeof window === "undefined") {
24
+ const { create, globals } = await import("webgpu");
25
+ Object.assign(globalThis, globals);
26
+ gpu = create([]);
27
+ _gpu = gpu;
28
+ } else {
29
+ gpu = navigator.gpu;
30
+ }
31
+
32
+ if (!gpu) {
33
+ throw new Error("WebGPU not supported in this environment.");
34
+ }
35
+
36
+ _adapter =
37
+ (await gpu.requestAdapter({ powerPreference })) ??
38
+ (await gpu.requestAdapter());
39
+ if (!_adapter) {
40
+ throw new Error("No WebGPU adapter found.");
41
+ }
42
+
43
+ _benchmarkEnabled = benchmark;
44
+ _device = await _adapter.requestDevice(benchmarkMode(_adapter, benchmark));
45
+ // Fires for any GPU error not caught by a pushErrorScope/popErrorScope pair — surfaces silent GPU failures to the console.
46
+ // See: https://developer.mozilla.org/en-US/docs/Web/API/GPUDevice/uncapturederror_event
47
+ _device.addEventListener("uncapturederror", (e) => {
48
+ console.error("Uncaptured GPU error:", e.error.message);
49
+ });
50
+
51
+ return _device;
52
+ }
53
+
54
+ export function cleanup() {
55
+ if (_device) {
56
+ _device.destroy();
57
+ _device = null;
58
+ }
59
+ _adapter = null;
60
+ _gpu = null;
61
+ _benchmarkEnabled = false;
62
+ }
63
+
64
+ export function gpuName() {
65
+ if (!_adapter) {
66
+ throw new Error("WebGPU adapter not initialized — call init() first.");
67
+ }
68
+ const { device, description } = _adapter.info;
69
+ return {
70
+ description: description || "unknown",
71
+ device: device || "unknown",
72
+ };
73
+ }
74
+
75
+ // ── Library internals (not part of the public API) ───────────────────────────
76
+
77
+ /** @returns {boolean} whether benchmark mode was enabled in the last `init()` call */
78
+ export function isBenchmarkEnabled() {
79
+ return _benchmarkEnabled;
80
+ }
81
+
82
+ /**
83
+ * Returns the active `GPUDevice`. Throws if `init()` has not been called.
84
+ * @returns {GPUDevice}
85
+ * @throws {Error} if the device is not initialized
86
+ */
87
+ export function getDevice() {
88
+ if (!_device) {
89
+ throw new Error("WebGPU device not initialized — call init() first.");
90
+ }
91
+ return _device;
92
+ }
93
+
94
+ /**
95
+ * Returns the active `GPUAdapter`. Throws if `init()` has not been called.
96
+ * @returns {GPUAdapter}
97
+ * @throws {Error} if the adapter is not initialized
98
+ */
99
+ export function getAdapter() {
100
+ if (!_adapter) {
101
+ throw new Error("WebGPU adapter not initialized — call init() first.");
102
+ }
103
+ return _adapter;
104
+ }
105
+
@@ -0,0 +1,46 @@
1
+ import { GpuVector } from "../classes/GpuVector.mjs";
2
+
3
+ /**
4
+ * Returns the 0-based index of the element with the largest absolute value.
5
+ * Ties are broken in favour of the lower index, matching CBLAS behaviour.
6
+ *
7
+ * {@includeCode ../../examples/isamax/isamax.js}
8
+ *
9
+ * **Browser (standalone HTML):**
10
+ * {@includeCode ../../examples/isamax/web/isamax.html}
11
+ *
12
+ * @param device - GPUDevice from `init()`
13
+ * @param n - number of elements (must be a positive integer)
14
+ * @param x - Float32Array input vector
15
+ * @param incx - stride for x (must be a positive integer)
16
+ * @returns 0-based index of max |x[i]|
17
+ * @see <a href="https://github.com/manit2004/wgblas/blob/main/src/isamax/isamax.mjs#L18">Source code: isamax.mjs (L18)</a>
18
+ * @category BLAS Level 1
19
+ */
20
+ export declare function isamax(
21
+ device: GPUDevice,
22
+ n: number,
23
+ x: Float32Array,
24
+ incx: number,
25
+ ): Promise<{ index: number } | { index: number; gpuTimeMs: number }>;
26
+
27
+ /**
28
+ * Returns the 0-based index of the element with the largest absolute value.
29
+ * Ties are broken in favour of the lower index, matching CBLAS behaviour.
30
+ *
31
+ * {@includeCode ../../examples/isamax/gpuvec.isamax.js}
32
+ *
33
+ * @param device - GPUDevice from `init()`
34
+ * @param n - number of elements (must be a positive integer)
35
+ * @param x - GpuVector input vector
36
+ * @param incx - stride for x (must be a positive integer)
37
+ * @returns 0-based index of max |x[i]|
38
+ * @see <a href="https://github.com/manit2004/wgblas/blob/main/src/isamax/isamax.mjs#L18">Source code: isamax.mjs (L18)</a>
39
+ * @category BLAS Level 1
40
+ */
41
+ export declare function isamax(
42
+ device: GPUDevice,
43
+ n: number,
44
+ x: GpuVector,
45
+ incx: number,
46
+ ): Promise<{ index: number } | { index: number; gpuTimeMs: number }>;
@@ -0,0 +1,115 @@
1
+ import {
2
+ uploadBuffer,
3
+ createStorageBuffer,
4
+ createParamsBuffer,
5
+ createResultBuffer,
6
+ stageReadback,
7
+ destroyBuffers,
8
+ } from "../util/buffer.mjs";
9
+ import { createBindGroup } from "../util/bindgroup.mjs";
10
+ import { runComputePass, submit } from "../util/compute.mjs";
11
+ import { extractTimestamp } from "../util/benchmark.mjs";
12
+ import { extractResult } from "../util/result.mjs";
13
+ import { getPipeline } from "../util/pipeline.mjs";
14
+ import { GpuVector } from "../classes/GpuVector.mjs";
15
+
16
+ const WGS = 64;
17
+
18
+ export async function isamax(device, n, x, incx) {
19
+ const xIsGpu = x instanceof GpuVector;
20
+
21
+ if (!(device instanceof GPUDevice))
22
+ throw new Error("device must be a GPUDevice.");
23
+ if (!Number.isInteger(n) || !Number.isInteger(incx))
24
+ throw new Error("n and incx must be integers.");
25
+ if (incx <= 0) throw new Error("incx must be positive.");
26
+ if (!xIsGpu && !(x instanceof Float32Array))
27
+ throw new Error("x must be a Float32Array or GpuVector.");
28
+ if (n <= 0) return { index: 0 };
29
+ if (x.length < (n - 1) * incx + 1)
30
+ throw new Error(
31
+ "x does not have enough elements for the given n and incx.",
32
+ );
33
+
34
+ const pipelineMain = await getPipeline(device, "isamax");
35
+ const pipelineReduce = await getPipeline(device, "reduction/argmax");
36
+
37
+ const xBuffer = xIsGpu ? x._buf : uploadBuffer(x, "isamax-x", false);
38
+ const partialsValBuffer = createStorageBuffer(
39
+ 2 * WGS * 4,
40
+ "isamax-partials-val",
41
+ ); //to hold 2*WGS partial max values of f32
42
+ const partialsIdxBuffer = createStorageBuffer(
43
+ 2 * WGS * 4,
44
+ "isamax-partials-idx",
45
+ ); //to hold 2*WGS partial max indices of u32
46
+ const resultBuffer = createResultBuffer(4, "isamax-result"); // u32 index
47
+ const paramsBuffer = createParamsBuffer(
48
+ [
49
+ { value: n, type: "u32" },
50
+ { value: incx, type: "u32" },
51
+ ],
52
+ "isamax-params",
53
+ );
54
+
55
+ const bgMain = createBindGroup(pipelineMain.getBindGroupLayout(0), [
56
+ xBuffer,
57
+ partialsValBuffer,
58
+ partialsIdxBuffer,
59
+ paramsBuffer,
60
+ ]);
61
+ const { commandEncoder: enc1, ts: ts1 } = runComputePass(
62
+ pipelineMain,
63
+ bgMain,
64
+ 2 * WGS,
65
+ ); //dispatch 2*WGS workgroups
66
+
67
+ submit(enc1);
68
+
69
+ const bgReduce = createBindGroup(pipelineReduce.getBindGroupLayout(0), [
70
+ partialsValBuffer,
71
+ partialsIdxBuffer,
72
+ resultBuffer,
73
+ ]);
74
+ const { commandEncoder: enc2, ts: ts2 } = runComputePass(
75
+ pipelineReduce,
76
+ bgReduce,
77
+ 1,
78
+ ); // dispatch 1 workgroup to reduce the partial sums to a single result
79
+ const readBuffer = stageReadback(enc2, resultBuffer);
80
+
81
+ submit(enc2);
82
+
83
+ const [gpuTime1, gpuTime2, idxArr] = await Promise.all([
84
+ extractTimestamp(ts1),
85
+ extractTimestamp(ts2),
86
+ extractResult(readBuffer, Uint32Array),
87
+ ]);
88
+
89
+ const index = idxArr[0];
90
+
91
+ if (xIsGpu) {
92
+ destroyBuffers(
93
+ partialsValBuffer,
94
+ partialsIdxBuffer,
95
+ resultBuffer,
96
+ paramsBuffer,
97
+ readBuffer,
98
+ );
99
+ if (gpuTime1 !== undefined && gpuTime2 !== undefined)
100
+ return { index, gpuTimeMs: gpuTime1 + gpuTime2 };
101
+ return { index };
102
+ }
103
+
104
+ destroyBuffers(
105
+ xBuffer,
106
+ partialsValBuffer,
107
+ partialsIdxBuffer,
108
+ resultBuffer,
109
+ paramsBuffer,
110
+ readBuffer,
111
+ );
112
+ if (gpuTime1 !== undefined && gpuTime2 !== undefined)
113
+ return { index, gpuTimeMs: gpuTime1 + gpuTime2 };
114
+ return { index };
115
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Returns a Float32Array of n random values uniformly sampled from [low, high).
3
+ *
4
+ * @param n - number of elements
5
+ * @param low - lower bound (default: -1)
6
+ * @param high - upper bound (default: 1)
7
+ *
8
+ * @example Default range [-1, 1)
9
+ * ```js
10
+ * import { randomFloat32Array } from "wgblas";
11
+ *
12
+ * const x = randomFloat32Array(4);
13
+ * console.log(x); // Float32Array [ -0.42, 0.81, -0.07, 0.55 ]
14
+ * ```
15
+ *
16
+ * @example Custom range [0, 10)
17
+ * ```js
18
+ * import { randomFloat32Array } from "wgblas";
19
+ *
20
+ * const x = randomFloat32Array(4, 0, 10);
21
+ * console.log(x);
22
+ * ```
23
+ * @see <a href="https://github.com/manit2004/wgblas/blob/main/src/random/random.mjs#L1">Source code: random.mjs (L1)</a>
24
+ * @category Utilities
25
+ */
26
+ export declare function randomFloat32Array(
27
+ n: number,
28
+ low?: number,
29
+ high?: number,
30
+ ): Float32Array;
31
+
32
+ /**
33
+ * Returns a Float64Array of n random values uniformly sampled from [low, high).
34
+ *
35
+ * @param n - number of elements
36
+ * @param low - lower bound (default: -1)
37
+ * @param high - upper bound (default: 1)
38
+ *
39
+ * @example Default range [-1, 1)
40
+ * ```js
41
+ * import { randomFloat64Array } from "wgblas";
42
+ *
43
+ * const x = randomFloat64Array(4);
44
+ * console.log(x); // Float64Array [ -0.42, 0.81, -0.07, 0.55 ]
45
+ * ```
46
+ *
47
+ * @example Custom range [0, 10)
48
+ * ```js
49
+ * import { randomFloat64Array } from "wgblas";
50
+ *
51
+ * const x = randomFloat64Array(4, 0, 10);
52
+ * console.log(x);
53
+ * ```
54
+ * @see <a href="https://github.com/manit2004/wgblas/blob/main/src/random/random.mjs#L7">Source code: random.mjs (L7)</a>
55
+ * @category Utilities
56
+ */
57
+ export declare function randomFloat64Array(
58
+ n: number,
59
+ low?: number,
60
+ high?: number,
61
+ ): Float64Array;
@@ -0,0 +1,11 @@
1
+ export function randomFloat32Array(n, low = -1, high = 1) {
2
+ const x = new Float32Array(n);
3
+ for (let i = 0; i < n; i++) x[i] = low + Math.random() * (high - low);
4
+ return x;
5
+ }
6
+
7
+ export function randomFloat64Array(n, low = -1, high = 1) {
8
+ const x = new Float64Array(n);
9
+ for (let i = 0; i < n; i++) x[i] = low + Math.random() * (high - low);
10
+ return x;
11
+ }