wgblas 2.2.1 → 2.3.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.
- package/README.md +5 -2
- package/dist/wgblas.browser.js +1082 -57
- package/index.d.mts +7 -0
- package/index.mjs +7 -0
- package/package.json +40 -4
- package/src/dgemv/dgemv.d.mts +92 -0
- package/src/dgemv/dgemv.mjs +247 -0
- package/src/dger/dger.d.mts +80 -0
- package/src/dger/dger.mjs +213 -0
- package/src/dsymv/dsymv.d.mts +84 -0
- package/src/dsymv/dsymv.mjs +227 -0
- package/src/dsyr/dsyr.d.mts +73 -0
- package/src/dsyr/dsyr.mjs +171 -0
- package/src/dsyr2/dsyr2.d.mts +81 -0
- package/src/dsyr2/dsyr2.mjs +214 -0
- package/src/dtrmv/dtrmv.d.mts +84 -0
- package/src/dtrmv/dtrmv.mjs +219 -0
- package/src/dtrsv/dtrsv.d.mts +79 -0
- package/src/dtrsv/dtrsv.mjs +331 -0
- package/src/shaders/dgemv_n.wgsl +112 -0
- package/src/shaders/dgemv_t.wgsl +102 -0
- package/src/shaders/dger.wgsl +77 -0
- package/src/shaders/dsymv.wgsl +125 -0
- package/src/shaders/dsyr.wgsl +84 -0
- package/src/shaders/dsyr2.wgsl +95 -0
- package/src/shaders/dtrmv.wgsl +111 -0
- package/src/shaders/dtrsv_apply_inverse.wgsl +60 -0
- package/src/shaders/dtrsv_invert_block.wgsl +148 -0
- package/src/shaders/dtrsv_update.wgsl +111 -0
- package/src/shaders/index.mjs +63 -0
package/index.d.mts
CHANGED
|
@@ -36,8 +36,15 @@ export { ssymv } from "./src/ssymv/ssymv.mjs";
|
|
|
36
36
|
export { strmv } from "./src/strmv/strmv.mjs";
|
|
37
37
|
export { strsv } from "./src/strsv/strsv.mjs";
|
|
38
38
|
export { sger } from "./src/sger/sger.mjs";
|
|
39
|
+
export { dger } from "./src/dger/dger.mjs";
|
|
39
40
|
export { ssyr } from "./src/ssyr/ssyr.mjs";
|
|
41
|
+
export { dsyr } from "./src/dsyr/dsyr.mjs";
|
|
40
42
|
export { ssyr2 } from "./src/ssyr2/ssyr2.mjs";
|
|
43
|
+
export { dsyr2 } from "./src/dsyr2/dsyr2.mjs";
|
|
44
|
+
export { dgemv } from "./src/dgemv/dgemv.mjs";
|
|
45
|
+
export { dsymv } from "./src/dsymv/dsymv.mjs";
|
|
46
|
+
export { dtrmv } from "./src/dtrmv/dtrmv.mjs";
|
|
47
|
+
export { dtrsv } from "./src/dtrsv/dtrsv.mjs";
|
|
41
48
|
export { sgemm } from "./src/sgemm/sgemm.mjs";
|
|
42
49
|
export { sgemmtr } from "./src/sgemmtr/sgemmtr.mjs";
|
|
43
50
|
export { ssyrk } from "./src/ssyrk/ssyrk.mjs";
|
package/index.mjs
CHANGED
|
@@ -34,8 +34,15 @@ export { ssymv } from "./src/ssymv/ssymv.mjs";
|
|
|
34
34
|
export { strmv } from "./src/strmv/strmv.mjs";
|
|
35
35
|
export { strsv } from "./src/strsv/strsv.mjs";
|
|
36
36
|
export { sger } from "./src/sger/sger.mjs";
|
|
37
|
+
export { dger } from "./src/dger/dger.mjs";
|
|
37
38
|
export { ssyr } from "./src/ssyr/ssyr.mjs";
|
|
39
|
+
export { dsyr } from "./src/dsyr/dsyr.mjs";
|
|
38
40
|
export { ssyr2 } from "./src/ssyr2/ssyr2.mjs";
|
|
41
|
+
export { dsyr2 } from "./src/dsyr2/dsyr2.mjs";
|
|
42
|
+
export { dgemv } from "./src/dgemv/dgemv.mjs";
|
|
43
|
+
export { dsymv } from "./src/dsymv/dsymv.mjs";
|
|
44
|
+
export { dtrmv } from "./src/dtrmv/dtrmv.mjs";
|
|
45
|
+
export { dtrsv } from "./src/dtrsv/dtrsv.mjs";
|
|
39
46
|
export { sgemm } from "./src/sgemm/sgemm.mjs";
|
|
40
47
|
export { sgemmtr } from "./src/sgemmtr/sgemmtr.mjs";
|
|
41
48
|
export { ssyrk } from "./src/ssyrk/ssyrk.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wgblas",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "BLAS on WebGPU",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.mjs",
|
|
@@ -135,14 +135,42 @@
|
|
|
135
135
|
"types": "./src/sger/sger.d.mts",
|
|
136
136
|
"import": "./src/sger/sger.mjs"
|
|
137
137
|
},
|
|
138
|
+
"./dger": {
|
|
139
|
+
"types": "./src/dger/dger.d.mts",
|
|
140
|
+
"import": "./src/dger/dger.mjs"
|
|
141
|
+
},
|
|
138
142
|
"./ssyr": {
|
|
139
143
|
"types": "./src/ssyr/ssyr.d.mts",
|
|
140
144
|
"import": "./src/ssyr/ssyr.mjs"
|
|
141
145
|
},
|
|
146
|
+
"./dsyr": {
|
|
147
|
+
"types": "./src/dsyr/dsyr.d.mts",
|
|
148
|
+
"import": "./src/dsyr/dsyr.mjs"
|
|
149
|
+
},
|
|
142
150
|
"./ssyr2": {
|
|
143
151
|
"types": "./src/ssyr2/ssyr2.d.mts",
|
|
144
152
|
"import": "./src/ssyr2/ssyr2.mjs"
|
|
145
153
|
},
|
|
154
|
+
"./dsyr2": {
|
|
155
|
+
"types": "./src/dsyr2/dsyr2.d.mts",
|
|
156
|
+
"import": "./src/dsyr2/dsyr2.mjs"
|
|
157
|
+
},
|
|
158
|
+
"./dgemv": {
|
|
159
|
+
"types": "./src/dgemv/dgemv.d.mts",
|
|
160
|
+
"import": "./src/dgemv/dgemv.mjs"
|
|
161
|
+
},
|
|
162
|
+
"./dsymv": {
|
|
163
|
+
"types": "./src/dsymv/dsymv.d.mts",
|
|
164
|
+
"import": "./src/dsymv/dsymv.mjs"
|
|
165
|
+
},
|
|
166
|
+
"./dtrmv": {
|
|
167
|
+
"types": "./src/dtrmv/dtrmv.d.mts",
|
|
168
|
+
"import": "./src/dtrmv/dtrmv.mjs"
|
|
169
|
+
},
|
|
170
|
+
"./dtrsv": {
|
|
171
|
+
"types": "./src/dtrsv/dtrsv.d.mts",
|
|
172
|
+
"import": "./src/dtrsv/dtrsv.mjs"
|
|
173
|
+
},
|
|
146
174
|
"./sgemm": {
|
|
147
175
|
"types": "./src/sgemm/sgemm.d.mts",
|
|
148
176
|
"import": "./src/sgemm/sgemm.mjs"
|
|
@@ -230,11 +258,18 @@
|
|
|
230
258
|
"@stdlib/blas-base-daxpy": "^0.4.1",
|
|
231
259
|
"@stdlib/blas-base-dcopy": "^0.4.1",
|
|
232
260
|
"@stdlib/blas-base-ddot": "^0.4.1",
|
|
261
|
+
"@stdlib/blas-base-dgemv": "^0.1.1",
|
|
262
|
+
"@stdlib/blas-base-dger": "^0.1.1",
|
|
233
263
|
"@stdlib/blas-base-dnrm2": "^0.4.1",
|
|
234
264
|
"@stdlib/blas-base-drot": "^0.1.1",
|
|
235
265
|
"@stdlib/blas-base-drotm": "^0.2.1",
|
|
236
266
|
"@stdlib/blas-base-dscal": "^0.4.1",
|
|
237
267
|
"@stdlib/blas-base-dswap": "^0.4.1",
|
|
268
|
+
"@stdlib/blas-base-dsymv": "^0.1.1",
|
|
269
|
+
"@stdlib/blas-base-dsyr": "^0.1.1",
|
|
270
|
+
"@stdlib/blas-base-dsyr2": "^0.1.1",
|
|
271
|
+
"@stdlib/blas-base-dtrmv": "^0.1.1",
|
|
272
|
+
"@stdlib/blas-base-dtrsv": "^0.1.1",
|
|
238
273
|
"@stdlib/blas-base-idamax": "^0.1.1",
|
|
239
274
|
"@stdlib/blas-base-isamax": "^0.1.1",
|
|
240
275
|
"@stdlib/blas-base-sasum": "^0.3.1",
|
|
@@ -263,6 +298,7 @@
|
|
|
263
298
|
"fast-check": "^4.8.0",
|
|
264
299
|
"globals": "^17.7.0",
|
|
265
300
|
"husky": "^9.1.7",
|
|
301
|
+
"jscpd": "^5.3.0",
|
|
266
302
|
"lint-staged": "^17.0.8",
|
|
267
303
|
"prettier": "^3.9.4",
|
|
268
304
|
"publint": "^0.3.24",
|
|
@@ -275,10 +311,10 @@
|
|
|
275
311
|
"scripts": {
|
|
276
312
|
"prepare": "husky",
|
|
277
313
|
"build:browser": "node scripts/build-browser.mjs",
|
|
278
|
-
"docs": "npx typedoc && npm run build:browser",
|
|
314
|
+
"docs": "npx typedoc && node scripts/gen-sitemap.mjs && npm run build:browser",
|
|
279
315
|
"prepublishOnly": "npm run build:browser",
|
|
280
|
-
"coverage": "c8 --reporter=text --reporter=html node --test $(find tests \\( -name 'test.*.js' -o -name 'gpustorage.*.js' \\))",
|
|
281
|
-
"cpd": "jscpd src",
|
|
316
|
+
"coverage": "c8 --reporter=text --reporter=html --reporter=lcov node --test $(find tests \\( -name 'test.*.js' -o -name 'gpustorage.*.js' \\))",
|
|
317
|
+
"cpd": "jscpd src -r html -o jscpd/",
|
|
282
318
|
"size": "npm run build:browser && size-limit"
|
|
283
319
|
},
|
|
284
320
|
"lint-staged": {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { GpuVector } from "../classes/GpuVector.mjs";
|
|
2
|
+
import { GpuMatrix } from "../classes/GpuMatrix.mjs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Performs the matrix-vector operation $$y \leftarrow \alpha \mathrm{op}(A) x + \beta y$$
|
|
6
|
+
* in double precision (double-double emulation — WGSL has no native f64 type).
|
|
7
|
+
*
|
|
8
|
+
* - `trans='no-transpose'`: op(A) = A, x is length n, y is length m
|
|
9
|
+
* - `trans='transpose'`: op(A) = A^T, x is length m, y is length n
|
|
10
|
+
*
|
|
11
|
+
* A is an m×n matrix stored in row-major order. `lda` is the leading dimension
|
|
12
|
+
* (number of doubles between the start of consecutive rows — must be >= n).
|
|
13
|
+
*
|
|
14
|
+
* {@includeCode ../../examples/dgemv/dgemv.js}
|
|
15
|
+
*
|
|
16
|
+
* **Browser (standalone HTML):**
|
|
17
|
+
* {@includeCode ../../examples/dgemv/web/dgemv.html}
|
|
18
|
+
*
|
|
19
|
+
* @param device - GPUDevice from `init()`
|
|
20
|
+
* @param trans - `'no-transpose'` for A, `'transpose'` for A^T
|
|
21
|
+
* @param m - number of rows in A
|
|
22
|
+
* @param n - number of columns in A
|
|
23
|
+
* @param alpha - scalar multiplier for op(A)*x
|
|
24
|
+
* @param A - Float64Array, row-major or column-major (see `layout`), at least
|
|
25
|
+
* (m-1)*lda+n elements for row-major or (n-1)*lda+m elements for column-major
|
|
26
|
+
* @param lda - leading dimension of A (>= n for row-major, >= m for column-major)
|
|
27
|
+
* @param x - Float64Array input vector
|
|
28
|
+
* @param incx - stride for x (must be a positive integer)
|
|
29
|
+
* @param beta - scalar multiplier for y
|
|
30
|
+
* @param y - Float64Array input/output vector
|
|
31
|
+
* @param incy - stride for y (must be a positive integer)
|
|
32
|
+
* @param layout - storage layout of `A` (default: `'row-major'`); column-major
|
|
33
|
+
* swaps the effective `m`/`n` and flips `trans` internally (op(A) stays
|
|
34
|
+
* what you asked for either way — x/y keep their original lengths)
|
|
35
|
+
* @see <a href="https://github.com/manit2004/wgblas/blob/main/src/dgemv/dgemv.mjs#L20">Source code: dgemv.mjs (L20)</a>
|
|
36
|
+
* @category BLAS Level 2
|
|
37
|
+
*/
|
|
38
|
+
export declare function dgemv(
|
|
39
|
+
device: GPUDevice,
|
|
40
|
+
trans: 'no-transpose' | 'transpose',
|
|
41
|
+
m: number,
|
|
42
|
+
n: number,
|
|
43
|
+
alpha: number,
|
|
44
|
+
A: Float64Array,
|
|
45
|
+
lda: number,
|
|
46
|
+
x: Float64Array,
|
|
47
|
+
incx: number,
|
|
48
|
+
beta: number,
|
|
49
|
+
y: Float64Array,
|
|
50
|
+
incy: number,
|
|
51
|
+
layout?: 'row-major' | 'column-major',
|
|
52
|
+
): Promise<{ y: Float64Array; gpuTimeMs?: number }>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Performs the matrix-vector operation $$y \leftarrow \alpha \mathrm{op}(A) x + \beta y$$
|
|
56
|
+
* in double precision (double-double emulation).
|
|
57
|
+
*
|
|
58
|
+
* x and y are kept resident on the GPU. A must be a GpuMatrix (Float64Array-
|
|
59
|
+
* backed); its own `layout` (set at `GpuMatrix.from` time) determines the
|
|
60
|
+
* operation — there is no separate `layout` argument here.
|
|
61
|
+
*
|
|
62
|
+
* {@includeCode ../../examples/dgemv/gpu.dgemv.js}
|
|
63
|
+
*
|
|
64
|
+
* @param device - GPUDevice from `init()`
|
|
65
|
+
* @param trans - `'no-transpose'` for A, `'transpose'` for A^T
|
|
66
|
+
* @param m - number of rows in A
|
|
67
|
+
* @param n - number of columns in A
|
|
68
|
+
* @param alpha - scalar multiplier for op(A)*x
|
|
69
|
+
* @param A - GpuMatrix (Float64Array-backed)
|
|
70
|
+
* @param lda - leading dimension of A (must equal A.lda)
|
|
71
|
+
* @param x - GpuVector input vector (Float64Array-backed, not mutated)
|
|
72
|
+
* @param incx - stride for x (must be a positive integer)
|
|
73
|
+
* @param beta - scalar multiplier for y
|
|
74
|
+
* @param y - GpuVector input/output vector (Float64Array-backed, mutated in place)
|
|
75
|
+
* @param incy - stride for y (must be a positive integer)
|
|
76
|
+
* @see <a href="https://github.com/manit2004/wgblas/blob/main/src/dgemv/dgemv.mjs#L20">Source code: dgemv.mjs (L20)</a>
|
|
77
|
+
* @category BLAS Level 2
|
|
78
|
+
*/
|
|
79
|
+
export declare function dgemv(
|
|
80
|
+
device: GPUDevice,
|
|
81
|
+
trans: 'no-transpose' | 'transpose',
|
|
82
|
+
m: number,
|
|
83
|
+
n: number,
|
|
84
|
+
alpha: number,
|
|
85
|
+
A: GpuMatrix,
|
|
86
|
+
lda: number,
|
|
87
|
+
x: GpuVector,
|
|
88
|
+
incx: number,
|
|
89
|
+
beta: number,
|
|
90
|
+
y: GpuVector,
|
|
91
|
+
incy: number,
|
|
92
|
+
): Promise<{ gpuTimeMs?: number }>;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import {
|
|
2
|
+
uploadBuffer,
|
|
3
|
+
createParamsBuffer,
|
|
4
|
+
stageReadback,
|
|
5
|
+
destroyBuffers,
|
|
6
|
+
} from "../util/buffer.mjs";
|
|
7
|
+
import { createBindGroup } from "../util/bindgroup.mjs";
|
|
8
|
+
import { runComputePass, submit } from "../util/compute.mjs";
|
|
9
|
+
import { extractResult } from "../util/result.mjs";
|
|
10
|
+
import { extractTimestamp } from "../util/benchmark.mjs";
|
|
11
|
+
import { getPipeline } from "../util/pipeline.mjs";
|
|
12
|
+
import { requireWorkgroups } from "../util/workgroup.mjs";
|
|
13
|
+
import { GpuVector } from "../classes/GpuVector.mjs";
|
|
14
|
+
import { GpuMatrix } from "../classes/GpuMatrix.mjs";
|
|
15
|
+
import { splitDoubleDouble, mergeDoubleDouble } from "../util/f64.mjs";
|
|
16
|
+
import { requireGpuDevice, requireSameDevice } from "../util/device.mjs";
|
|
17
|
+
|
|
18
|
+
// dgemv: y := alpha * op(A) * x + beta * y, double-double (Dekker) f64
|
|
19
|
+
// emulation of sgemv — A, x, y, alpha, and beta are each split into an f32
|
|
20
|
+
// (hi, lo) pair; WGSL has no f64 type.
|
|
21
|
+
export async function dgemv(
|
|
22
|
+
device,
|
|
23
|
+
trans,
|
|
24
|
+
m,
|
|
25
|
+
n,
|
|
26
|
+
alpha,
|
|
27
|
+
A,
|
|
28
|
+
lda,
|
|
29
|
+
x,
|
|
30
|
+
incx,
|
|
31
|
+
beta,
|
|
32
|
+
y,
|
|
33
|
+
incy,
|
|
34
|
+
layout = "row-major",
|
|
35
|
+
) {
|
|
36
|
+
const AIsGpu = A instanceof GpuMatrix;
|
|
37
|
+
const xIsGpu = x instanceof GpuVector;
|
|
38
|
+
const yIsGpu = y instanceof GpuVector;
|
|
39
|
+
|
|
40
|
+
requireGpuDevice(device);
|
|
41
|
+
requireSameDevice(device, "dgemv", { A, x, y });
|
|
42
|
+
if (trans !== "no-transpose" && trans !== "transpose")
|
|
43
|
+
throw new Error("trans must be 'no-transpose' or 'transpose'.");
|
|
44
|
+
if (layout !== "row-major" && layout !== "column-major")
|
|
45
|
+
throw new Error("layout must be 'row-major' or 'column-major'.");
|
|
46
|
+
if (typeof alpha !== "number") throw new Error("alpha must be a number.");
|
|
47
|
+
if (Number.isNaN(alpha)) throw new Error("alpha must not be NaN.");
|
|
48
|
+
if (!Number.isFinite(alpha)) throw new Error("alpha must be finite.");
|
|
49
|
+
if (typeof beta !== "number") throw new Error("beta must be a number.");
|
|
50
|
+
if (Number.isNaN(beta)) throw new Error("beta must not be NaN.");
|
|
51
|
+
if (!Number.isFinite(beta)) throw new Error("beta must be finite.");
|
|
52
|
+
if (
|
|
53
|
+
!Number.isInteger(m) ||
|
|
54
|
+
!Number.isInteger(n) ||
|
|
55
|
+
!Number.isInteger(incx) ||
|
|
56
|
+
!Number.isInteger(incy) ||
|
|
57
|
+
!Number.isInteger(lda)
|
|
58
|
+
)
|
|
59
|
+
throw new Error("m, n, incx, incy, and lda must be integers.");
|
|
60
|
+
if (incx <= 0 || incy <= 0)
|
|
61
|
+
throw new Error("incx and incy must be positive.");
|
|
62
|
+
if (!AIsGpu && !(A instanceof Float64Array))
|
|
63
|
+
throw new Error("A must be a Float64Array or GpuMatrix.");
|
|
64
|
+
if (AIsGpu && A.dtype !== Float64Array)
|
|
65
|
+
throw new Error("A must be a Float64Array-backed GpuMatrix.");
|
|
66
|
+
if (!xIsGpu && !(x instanceof Float64Array))
|
|
67
|
+
throw new Error("x must be a Float64Array or GpuVector.");
|
|
68
|
+
if (!yIsGpu && !(y instanceof Float64Array))
|
|
69
|
+
throw new Error("y must be a Float64Array or GpuVector.");
|
|
70
|
+
if (xIsGpu && x.dtype !== Float64Array)
|
|
71
|
+
throw new Error("x must be a Float64Array-backed GpuVector.");
|
|
72
|
+
if (yIsGpu && y.dtype !== Float64Array)
|
|
73
|
+
throw new Error("y must be a Float64Array-backed GpuVector.");
|
|
74
|
+
if (xIsGpu !== yIsGpu)
|
|
75
|
+
throw new Error(
|
|
76
|
+
"x and y must be the same type (both Float64Array or both GpuVector).",
|
|
77
|
+
);
|
|
78
|
+
if (xIsGpu && !AIsGpu)
|
|
79
|
+
throw new Error("A must be a GpuMatrix when x and y are GpuVectors.");
|
|
80
|
+
if (AIsGpu && !xIsGpu)
|
|
81
|
+
throw new Error("x and y must be GpuVectors when A is a GpuMatrix.");
|
|
82
|
+
if (xIsGpu && x._buf === y._buf)
|
|
83
|
+
throw new Error(
|
|
84
|
+
"x and y must not reference the same GPU buffer when both are GpuVectors.",
|
|
85
|
+
);
|
|
86
|
+
if (AIsGpu && yIsGpu && A._buf === y._buf)
|
|
87
|
+
throw new Error("A and y must not reference the same GPU buffer.");
|
|
88
|
+
if (AIsGpu && lda !== A.lda)
|
|
89
|
+
throw new Error("lda must match A.lda when A is a GpuMatrix.");
|
|
90
|
+
if (AIsGpu && (A.rows < m || A.cols < n))
|
|
91
|
+
throw new Error("A is too small for the given m and n.");
|
|
92
|
+
if (m < 0 || n < 0) throw new Error("m and n must be non-negative.");
|
|
93
|
+
if (m === 0 || n === 0) return yIsGpu ? {} : { y };
|
|
94
|
+
|
|
95
|
+
// Column-major A reinterpreted row-major is A^T — swap to the kernel's
|
|
96
|
+
// view of m/n/trans now that the shape checks above are done.
|
|
97
|
+
const effLayout = AIsGpu ? A.layout : layout;
|
|
98
|
+
if (effLayout === "column-major") {
|
|
99
|
+
[m, n] = [n, m];
|
|
100
|
+
trans = trans === "no-transpose" ? "transpose" : "no-transpose";
|
|
101
|
+
}
|
|
102
|
+
const isNoTrans = trans === "no-transpose";
|
|
103
|
+
|
|
104
|
+
// NoTrans: x has n elements, y has m elements; Trans: x has m elements, y has n elements.
|
|
105
|
+
const xLen = isNoTrans ? n : m;
|
|
106
|
+
const yLen = isNoTrans ? m : n;
|
|
107
|
+
|
|
108
|
+
if (lda < n) throw new Error("lda must be >= n.");
|
|
109
|
+
if (!AIsGpu && A.length < (m - 1) * lda + n)
|
|
110
|
+
throw new Error(
|
|
111
|
+
"A does not have enough elements for the given m, n, and lda.",
|
|
112
|
+
);
|
|
113
|
+
if (x.length < (xLen - 1) * incx + 1)
|
|
114
|
+
throw new Error(
|
|
115
|
+
"x does not have enough elements for the given dimensions and incx.",
|
|
116
|
+
);
|
|
117
|
+
if (y.length < (yLen - 1) * incy + 1)
|
|
118
|
+
throw new Error(
|
|
119
|
+
"y does not have enough elements for the given dimensions and incy.",
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const f64Deps = ["f64/dekker", "f64/utils/add", "f64/utils/multiply"];
|
|
123
|
+
const shaderName = isNoTrans ? "dgemv_n" : "dgemv_t";
|
|
124
|
+
const entryPoint = isNoTrans ? "dgemv_n_main" : "dgemv_t_main";
|
|
125
|
+
const pipeline = await getPipeline(
|
|
126
|
+
device,
|
|
127
|
+
[...f64Deps, shaderName],
|
|
128
|
+
entryPoint,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const { hi: alphaHi, lo: alphaLo } = splitDoubleDouble(
|
|
132
|
+
new Float64Array([alpha]),
|
|
133
|
+
);
|
|
134
|
+
const { hi: betaHi, lo: betaLo } = splitDoubleDouble(
|
|
135
|
+
new Float64Array([beta]),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
let AHiBuffer = null;
|
|
139
|
+
let ALoBuffer = null;
|
|
140
|
+
let xHiBuffer = null;
|
|
141
|
+
let xLoBuffer = null;
|
|
142
|
+
let yHiBuffer = null;
|
|
143
|
+
let yLoBuffer = null;
|
|
144
|
+
let paramsBuffer = null;
|
|
145
|
+
let readHiBuffer = null;
|
|
146
|
+
let readLoBuffer = null;
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
if (AIsGpu) {
|
|
150
|
+
AHiBuffer = A._buf;
|
|
151
|
+
ALoBuffer = A._loBuf;
|
|
152
|
+
} else {
|
|
153
|
+
const ASplit = splitDoubleDouble(A);
|
|
154
|
+
AHiBuffer = uploadBuffer(device, ASplit.hi, "dgemv-AHi", false);
|
|
155
|
+
ALoBuffer = uploadBuffer(device, ASplit.lo, "dgemv-ALo", false);
|
|
156
|
+
}
|
|
157
|
+
if (xIsGpu) {
|
|
158
|
+
xHiBuffer = x._buf;
|
|
159
|
+
xLoBuffer = x._loBuf;
|
|
160
|
+
} else {
|
|
161
|
+
const xSplit = splitDoubleDouble(x);
|
|
162
|
+
xHiBuffer = uploadBuffer(device, xSplit.hi, "dgemv-xHi", false);
|
|
163
|
+
xLoBuffer = uploadBuffer(device, xSplit.lo, "dgemv-xLo", false);
|
|
164
|
+
}
|
|
165
|
+
if (yIsGpu) {
|
|
166
|
+
yHiBuffer = y._buf;
|
|
167
|
+
yLoBuffer = y._loBuf;
|
|
168
|
+
} else {
|
|
169
|
+
const ySplit = splitDoubleDouble(y);
|
|
170
|
+
yHiBuffer = uploadBuffer(device, ySplit.hi, "dgemv-yHi", true);
|
|
171
|
+
yLoBuffer = uploadBuffer(device, ySplit.lo, "dgemv-yLo", true);
|
|
172
|
+
}
|
|
173
|
+
paramsBuffer = createParamsBuffer(
|
|
174
|
+
device,
|
|
175
|
+
[
|
|
176
|
+
{ value: m, type: "u32" },
|
|
177
|
+
{ value: n, type: "u32" },
|
|
178
|
+
{ value: alphaHi[0], type: "f32" },
|
|
179
|
+
{ value: alphaLo[0], type: "f32" },
|
|
180
|
+
{ value: betaHi[0], type: "f32" },
|
|
181
|
+
{ value: betaLo[0], type: "f32" },
|
|
182
|
+
{ value: incx, type: "u32" },
|
|
183
|
+
{ value: incy, type: "u32" },
|
|
184
|
+
{ value: lda, type: "u32" },
|
|
185
|
+
],
|
|
186
|
+
"dgemv-params",
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const bindGroup = createBindGroup(device, pipeline.getBindGroupLayout(0), [
|
|
190
|
+
AHiBuffer,
|
|
191
|
+
ALoBuffer,
|
|
192
|
+
xHiBuffer,
|
|
193
|
+
xLoBuffer,
|
|
194
|
+
yHiBuffer,
|
|
195
|
+
yLoBuffer,
|
|
196
|
+
paramsBuffer,
|
|
197
|
+
]);
|
|
198
|
+
|
|
199
|
+
// NoTrans: one workgroup per row — dgemv_n.wgsl is a grid-stride loop, so
|
|
200
|
+
// clamping here only costs parallelism. Trans: one thread per output
|
|
201
|
+
// column, and dgemv_t.wgsl indexes straight off global_invocation_id
|
|
202
|
+
// (masked, not skipped, for out-of-range columns), so an over-limit
|
|
203
|
+
// dispatch must be refused, not truncated.
|
|
204
|
+
const wgCount = isNoTrans
|
|
205
|
+
? Math.min(m, device.limits.maxComputeWorkgroupsPerDimension)
|
|
206
|
+
: requireWorkgroups(device, "dgemv", yLen);
|
|
207
|
+
const { commandEncoder, ts } = runComputePass(
|
|
208
|
+
device,
|
|
209
|
+
pipeline,
|
|
210
|
+
bindGroup,
|
|
211
|
+
wgCount,
|
|
212
|
+
);
|
|
213
|
+
readHiBuffer = yIsGpu
|
|
214
|
+
? null
|
|
215
|
+
: stageReadback(device, commandEncoder, yHiBuffer);
|
|
216
|
+
readLoBuffer = yIsGpu
|
|
217
|
+
? null
|
|
218
|
+
: stageReadback(device, commandEncoder, yLoBuffer);
|
|
219
|
+
|
|
220
|
+
submit(device, commandEncoder);
|
|
221
|
+
|
|
222
|
+
const gpuTimeMs = await extractTimestamp(ts);
|
|
223
|
+
|
|
224
|
+
if (yIsGpu) {
|
|
225
|
+
if (gpuTimeMs !== undefined) return { gpuTimeMs };
|
|
226
|
+
return {};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const hi = await extractResult(readHiBuffer, Float32Array);
|
|
230
|
+
readHiBuffer = null;
|
|
231
|
+
const lo = await extractResult(readLoBuffer, Float32Array);
|
|
232
|
+
readLoBuffer = null;
|
|
233
|
+
const result = mergeDoubleDouble(hi, lo);
|
|
234
|
+
if (gpuTimeMs !== undefined) return { y: result, gpuTimeMs };
|
|
235
|
+
return { y: result };
|
|
236
|
+
} finally {
|
|
237
|
+
if (!AIsGpu && AHiBuffer) destroyBuffers(AHiBuffer);
|
|
238
|
+
if (!AIsGpu && ALoBuffer) destroyBuffers(ALoBuffer);
|
|
239
|
+
if (!xIsGpu && xHiBuffer) destroyBuffers(xHiBuffer);
|
|
240
|
+
if (!xIsGpu && xLoBuffer) destroyBuffers(xLoBuffer);
|
|
241
|
+
if (!yIsGpu && yHiBuffer) destroyBuffers(yHiBuffer);
|
|
242
|
+
if (!yIsGpu && yLoBuffer) destroyBuffers(yLoBuffer);
|
|
243
|
+
if (paramsBuffer) destroyBuffers(paramsBuffer);
|
|
244
|
+
if (readHiBuffer) destroyBuffers(readHiBuffer);
|
|
245
|
+
if (readLoBuffer) destroyBuffers(readLoBuffer);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { GpuVector } from "../classes/GpuVector.mjs";
|
|
2
|
+
import { GpuMatrix } from "../classes/GpuMatrix.mjs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Performs the rank-1 update $$A \leftarrow \alpha x y^{T} + A$$ in double
|
|
6
|
+
* precision (double-double emulation — WGSL has no native f64 type).
|
|
7
|
+
*
|
|
8
|
+
* A is an m×n matrix stored in row-major order, updated in place. `lda` is
|
|
9
|
+
* the leading dimension (number of doubles between the start of consecutive
|
|
10
|
+
* rows — must be >= n).
|
|
11
|
+
*
|
|
12
|
+
* {@includeCode ../../examples/dger/dger.js}
|
|
13
|
+
*
|
|
14
|
+
* **Browser (standalone HTML):**
|
|
15
|
+
* {@includeCode ../../examples/dger/web/dger.html}
|
|
16
|
+
*
|
|
17
|
+
* @param device - GPUDevice from `init()`
|
|
18
|
+
* @param m - number of rows in A (length of x)
|
|
19
|
+
* @param n - number of columns in A (length of y)
|
|
20
|
+
* @param alpha - scalar multiplier for x*y^T
|
|
21
|
+
* @param x - Float64Array input vector, length at least (m-1)*incx+1
|
|
22
|
+
* @param incx - stride for x (must be a positive integer)
|
|
23
|
+
* @param y - Float64Array input vector, length at least (n-1)*incy+1
|
|
24
|
+
* @param incy - stride for y (must be a positive integer)
|
|
25
|
+
* @param A - Float64Array, row-major or column-major (see `layout`), at least
|
|
26
|
+
* (m-1)*lda+n elements for row-major or (n-1)*lda+m elements for column-major
|
|
27
|
+
* @param lda - leading dimension of A (>= n for row-major, >= m for column-major)
|
|
28
|
+
* @param layout - storage layout of `A` (default: `'row-major'`)
|
|
29
|
+
* @see <a href="https://github.com/manit2004/wgblas/blob/main/src/dger/dger.mjs#L18">Source code: dger.mjs (L18)</a>
|
|
30
|
+
* @category BLAS Level 2
|
|
31
|
+
*/
|
|
32
|
+
export declare function dger(
|
|
33
|
+
device: GPUDevice,
|
|
34
|
+
m: number,
|
|
35
|
+
n: number,
|
|
36
|
+
alpha: number,
|
|
37
|
+
x: Float64Array,
|
|
38
|
+
incx: number,
|
|
39
|
+
y: Float64Array,
|
|
40
|
+
incy: number,
|
|
41
|
+
A: Float64Array,
|
|
42
|
+
lda: number,
|
|
43
|
+
layout?: 'row-major' | 'column-major',
|
|
44
|
+
): Promise<{ A: Float64Array; gpuTimeMs?: number }>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Performs the rank-1 update $$A \leftarrow \alpha x y^{T} + A$$ in double
|
|
48
|
+
* precision (double-double emulation).
|
|
49
|
+
*
|
|
50
|
+
* x, y, and A are all kept resident on the GPU. `A`'s own `layout` (set at
|
|
51
|
+
* `GpuMatrix.from` time) determines the operation — there is no separate
|
|
52
|
+
* `layout` argument here.
|
|
53
|
+
*
|
|
54
|
+
* {@includeCode ../../examples/dger/gpu.dger.js}
|
|
55
|
+
*
|
|
56
|
+
* @param device - GPUDevice from `init()`
|
|
57
|
+
* @param m - number of rows in A
|
|
58
|
+
* @param n - number of columns in A
|
|
59
|
+
* @param alpha - scalar multiplier for x*y^T
|
|
60
|
+
* @param x - GpuVector input vector (Float64Array-backed, not mutated)
|
|
61
|
+
* @param incx - stride for x (must be a positive integer)
|
|
62
|
+
* @param y - GpuVector input vector (Float64Array-backed, not mutated)
|
|
63
|
+
* @param incy - stride for y (must be a positive integer)
|
|
64
|
+
* @param A - GpuMatrix (Float64Array-backed), mutated in place
|
|
65
|
+
* @param lda - leading dimension of A (must equal A.lda)
|
|
66
|
+
* @see <a href="https://github.com/manit2004/wgblas/blob/main/src/dger/dger.mjs#L18">Source code: dger.mjs (L18)</a>
|
|
67
|
+
* @category BLAS Level 2
|
|
68
|
+
*/
|
|
69
|
+
export declare function dger(
|
|
70
|
+
device: GPUDevice,
|
|
71
|
+
m: number,
|
|
72
|
+
n: number,
|
|
73
|
+
alpha: number,
|
|
74
|
+
x: GpuVector,
|
|
75
|
+
incx: number,
|
|
76
|
+
y: GpuVector,
|
|
77
|
+
incy: number,
|
|
78
|
+
A: GpuMatrix,
|
|
79
|
+
lda: number,
|
|
80
|
+
): Promise<{ gpuTimeMs?: number }>;
|