wgblas 1.2.1 → 2.0.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/LICENSE +1 -1
- package/README.md +36 -54
- package/dist/wgblas.browser.js +779 -34
- package/index.d.mts +13 -0
- package/index.mjs +8 -0
- package/package.json +55 -2
- package/src/dasum/dasum.d.mts +2 -2
- package/src/dasum/dasum.mjs +6 -4
- package/src/idamax/idamax.d.mts +51 -0
- package/src/idamax/idamax.mjs +128 -0
- package/src/init.mjs +9 -1
- package/src/isamax/isamax.d.mts +1 -1
- package/src/sasum/sasum.d.mts +1 -1
- package/src/saxpy/saxpy.d.mts +1 -1
- package/src/scopy/scopy.d.mts +1 -1
- package/src/sdot/sdot.d.mts +1 -1
- package/src/sgemm/sgemm.d.mts +102 -0
- package/src/sgemm/sgemm.mjs +195 -0
- package/src/sgemmtr/sgemmtr.d.mts +104 -0
- package/src/sgemmtr/sgemmtr.mjs +203 -0
- package/src/sgemv/sgemv.d.mts +1 -38
- package/src/sgemv/sgemv.mjs +4 -0
- package/src/sger/sger.d.mts +1 -34
- package/src/sger/sger.mjs +2 -0
- package/src/shaders/block_transfer.wgsl +42 -0
- package/src/shaders/browser-shaders.mjs +26 -0
- package/src/shaders/dasum.wgsl +3 -2
- package/src/shaders/f64/dekker.wgsl +4 -85
- package/src/shaders/f64/utils/abs.wgsl +10 -0
- package/src/shaders/f64/utils/add.wgsl +77 -0
- package/src/shaders/f64/utils/equal.wgsl +7 -0
- package/src/shaders/f64/utils/greater.wgsl +12 -0
- package/src/shaders/f64/utils/multiply.wgsl +81 -0
- package/src/shaders/idamax.wgsl +96 -0
- package/src/shaders/reduction/argmaxF64.wgsl +50 -0
- package/src/shaders/reduction/sumF64.wgsl +2 -2
- package/src/shaders/sgemm_large.wgsl +117 -0
- package/src/shaders/sgemm_small.wgsl +112 -0
- package/src/shaders/sgemmtr_large.wgsl +117 -0
- package/src/shaders/sgemmtr_small.wgsl +110 -0
- package/src/shaders/symmetrize.wgsl +31 -0
- package/src/shaders/triangularize.wgsl +44 -0
- package/src/snrm2/snrm2.d.mts +1 -1
- package/src/srot/srot.d.mts +1 -1
- package/src/srotm/srotm.d.mts +1 -1
- package/src/sscal/sscal.d.mts +1 -1
- package/src/sswap/sswap.d.mts +1 -1
- package/src/ssymm/ssymm.d.mts +103 -0
- package/src/ssymm/ssymm.mjs +209 -0
- package/src/ssymv/ssymv.d.mts +1 -36
- package/src/ssymv/ssymv.mjs +2 -0
- package/src/ssyr/ssyr.d.mts +1 -30
- package/src/ssyr/ssyr.mjs +2 -0
- package/src/ssyr2/ssyr2.d.mts +1 -34
- package/src/ssyr2/ssyr2.mjs +2 -0
- package/src/ssyr2k/ssyr2k.d.mts +100 -0
- package/src/ssyr2k/ssyr2k.mjs +201 -0
- package/src/ssyrk/ssyrk.d.mts +90 -0
- package/src/ssyrk/ssyrk.mjs +176 -0
- package/src/strmm/strmm.d.mts +100 -0
- package/src/strmm/strmm.mjs +211 -0
- package/src/strmv/strmv.d.mts +1 -36
- package/src/strmv/strmv.mjs +2 -0
- package/src/strsm/strsm.d.mts +99 -0
- package/src/strsm/strsm.mjs +342 -0
- package/src/strsv/strsv.d.mts +1 -32
- package/src/strsv/strsv.mjs +2 -0
- package/src/util/buffer.mjs +4 -2
- package/src/util/compute.mjs +6 -3
- package/src/util/f64.mjs +3 -3
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import {
|
|
2
|
+
uploadBuffer,
|
|
3
|
+
createParamsBuffer,
|
|
4
|
+
createStorageBuffer,
|
|
5
|
+
stageReadback,
|
|
6
|
+
destroyBuffers,
|
|
7
|
+
} from "../util/buffer.mjs";
|
|
8
|
+
import { createBindGroup } from "../util/bindgroup.mjs";
|
|
9
|
+
import { beginTimedEncoder, encodePass, submit } from "../util/compute.mjs";
|
|
10
|
+
import { extractResult } from "../util/result.mjs";
|
|
11
|
+
import { resolveTimestamp, extractTimestamp } from "../util/benchmark.mjs";
|
|
12
|
+
import { getPipeline } from "../util/pipeline.mjs";
|
|
13
|
+
import { GpuMatrix } from "../classes/GpuMatrix.mjs";
|
|
14
|
+
|
|
15
|
+
const BM_SMALL = 32, BN_SMALL = 32; // sgemm_small.wgsl's block tile
|
|
16
|
+
const BM_LARGE = 64, BN_LARGE = 64; // sgemm_large.wgsl's block tile
|
|
17
|
+
const LARGE_TILE_WORKGROUP_THRESHOLD = 36; // same threshold sgemm/sgemmtr/ssyrk/ssymm use
|
|
18
|
+
const TRI_WG = 8; // triangularize.wgsl's @workgroup_size(8, 8)
|
|
19
|
+
|
|
20
|
+
// strmm: B := alpha*op(A)*B (side='left') or alpha*B*op(A) (side='right'), A
|
|
21
|
+
// triangular. Triangularize then sgemm, one command encoder. B is both
|
|
22
|
+
// input and output, so gemm writes to a fresh buffer (no aliasing race),
|
|
23
|
+
// copied back into B (GpuMatrix) or read back directly (Float32Array).
|
|
24
|
+
export async function strmm(
|
|
25
|
+
device, side, uplo, transA, diag, m, n, alpha, A, lda, B, ldb, layout = "row-major",
|
|
26
|
+
) {
|
|
27
|
+
const AIsGpu = A instanceof GpuMatrix;
|
|
28
|
+
const BIsGpu = B instanceof GpuMatrix;
|
|
29
|
+
const isUnit = diag === "unit";
|
|
30
|
+
|
|
31
|
+
if (!(device instanceof GPUDevice))
|
|
32
|
+
throw new Error("device must be a GPUDevice.");
|
|
33
|
+
if (side !== "left" && side !== "right")
|
|
34
|
+
throw new Error("side must be 'left' or 'right'.");
|
|
35
|
+
if (uplo !== "lower" && uplo !== "upper")
|
|
36
|
+
throw new Error("uplo must be 'lower' or 'upper'.");
|
|
37
|
+
if (transA !== "no-transpose" && transA !== "transpose")
|
|
38
|
+
throw new Error("transA must be 'no-transpose' or 'transpose'.");
|
|
39
|
+
if (!isUnit && diag !== "non-unit")
|
|
40
|
+
throw new Error("diag must be 'unit' or 'non-unit'.");
|
|
41
|
+
if (layout !== "row-major" && layout !== "column-major")
|
|
42
|
+
throw new Error("layout must be 'row-major' or 'column-major'.");
|
|
43
|
+
if (typeof alpha !== "number")
|
|
44
|
+
throw new Error("alpha must be a number.");
|
|
45
|
+
if (Number.isNaN(alpha)) throw new Error("alpha must not be NaN.");
|
|
46
|
+
if (!Number.isFinite(alpha)) throw new Error("alpha must be finite.");
|
|
47
|
+
if (!Number.isInteger(m) || !Number.isInteger(n) || !Number.isInteger(lda) || !Number.isInteger(ldb))
|
|
48
|
+
throw new Error("m, n, lda, and ldb must be integers.");
|
|
49
|
+
if (!AIsGpu && !(A instanceof Float32Array))
|
|
50
|
+
throw new Error("A must be a Float32Array or GpuMatrix.");
|
|
51
|
+
if (!BIsGpu && !(B instanceof Float32Array))
|
|
52
|
+
throw new Error("B must be a Float32Array or GpuMatrix.");
|
|
53
|
+
if (AIsGpu !== BIsGpu)
|
|
54
|
+
throw new Error("A and B must both be GpuMatrix or both be Float32Array.");
|
|
55
|
+
if (m < 0 || n < 0) throw new Error("m and n must be non-negative.");
|
|
56
|
+
if (m === 0 || n === 0) return BIsGpu ? {} : { B };
|
|
57
|
+
|
|
58
|
+
const effLayoutA = AIsGpu ? A.layout : layout;
|
|
59
|
+
const effLayoutB = BIsGpu ? B.layout : layout;
|
|
60
|
+
|
|
61
|
+
// A: triangular, order = m (side='left') or n (side='right').
|
|
62
|
+
const aOrder = side === "left" ? m : n;
|
|
63
|
+
if (lda < aOrder) throw new Error("lda must be >= " + (side === "left" ? "m" : "n") + ".");
|
|
64
|
+
if (AIsGpu) {
|
|
65
|
+
if (lda !== A.lda) throw new Error("lda must match A.lda when A is a GpuMatrix.");
|
|
66
|
+
if (A.rows < aOrder || A.cols < aOrder) throw new Error("A is too small for the given m/n and side.");
|
|
67
|
+
} else if (A.length < (aOrder - 1) * lda + aOrder) {
|
|
68
|
+
throw new Error("A does not have enough elements for the given dimensions and lda.");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// B: always m x n, overwritten in place with the same ldb.
|
|
72
|
+
const bOuter = effLayoutB === "column-major" ? n : m;
|
|
73
|
+
const bInner = effLayoutB === "column-major" ? m : n;
|
|
74
|
+
if (ldb < bInner)
|
|
75
|
+
throw new Error(`ldb must be >= ${effLayoutB === "column-major" ? "rows" : "cols"} of B as stored.`);
|
|
76
|
+
if (BIsGpu) {
|
|
77
|
+
if (ldb !== B.lda) throw new Error("ldb must match B.lda when B is a GpuMatrix.");
|
|
78
|
+
if (B.rows < m || B.cols < n) throw new Error("B is too small for the given m and n.");
|
|
79
|
+
} else if (B.length < (bOuter - 1) * ldb + bInner) {
|
|
80
|
+
throw new Error("B does not have enough elements for the given dimensions and ldb.");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// A isn't symmetric: column-major = genuine transpose, so flip transA;
|
|
84
|
+
// transposing also swaps which triangle looks stored, so flip uplo too.
|
|
85
|
+
const uploEffA = effLayoutA === "column-major" ? (uplo === "lower" ? "upper" : "lower") : uplo;
|
|
86
|
+
const transEffA = effLayoutA === "column-major" ? (transA === "no-transpose" ? "transpose" : "no-transpose") : transA;
|
|
87
|
+
|
|
88
|
+
const transB = effLayoutB === "column-major" ? "transpose" : "no-transpose";
|
|
89
|
+
const transDense = "no-transpose"; // Adense already embodies op(A)
|
|
90
|
+
|
|
91
|
+
// X*Y (X=Adense,Y=B for side='left', swapped for 'right'). Column-major
|
|
92
|
+
// output: compute (B_out)^T instead — sgemm's own trick, same as ssymm's.
|
|
93
|
+
let mg = m, ng = n;
|
|
94
|
+
const kg = aOrder;
|
|
95
|
+
let transX = side === "left" ? transDense : transB;
|
|
96
|
+
let transY = side === "left" ? transB : transDense;
|
|
97
|
+
const flip = (t) => (t === "no-transpose" ? "transpose" : "no-transpose");
|
|
98
|
+
let swapXY = side === "right";
|
|
99
|
+
if (effLayoutB === "column-major") {
|
|
100
|
+
[transX, transY] = [flip(transY), flip(transX)];
|
|
101
|
+
swapXY = !swapXY;
|
|
102
|
+
[mg, ng] = [ng, mg];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const ldDense = aOrder; // Adense is tightly packed, row-major
|
|
106
|
+
const largeWgX = Math.ceil(ng / BN_LARGE);
|
|
107
|
+
const largeWgY = Math.ceil(mg / BM_LARGE);
|
|
108
|
+
const useLargeTile = largeWgX * largeWgY >= LARGE_TILE_WORKGROUP_THRESHOLD;
|
|
109
|
+
const gemmPipeline = await getPipeline(device, useLargeTile ? "sgemm_large" : "sgemm_small");
|
|
110
|
+
const triPipeline = await getPipeline(device, "triangularize");
|
|
111
|
+
const gemmWgCount = useLargeTile
|
|
112
|
+
? {
|
|
113
|
+
x: Math.min(largeWgX, device.limits.maxComputeWorkgroupsPerDimension),
|
|
114
|
+
y: Math.min(largeWgY, device.limits.maxComputeWorkgroupsPerDimension),
|
|
115
|
+
}
|
|
116
|
+
: {
|
|
117
|
+
x: Math.min(Math.ceil(ng / BN_SMALL), device.limits.maxComputeWorkgroupsPerDimension),
|
|
118
|
+
y: Math.min(Math.ceil(mg / BM_SMALL), device.limits.maxComputeWorkgroupsPerDimension),
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const ABuffer = AIsGpu ? A._buf : uploadBuffer(A, "strmm-A", false);
|
|
122
|
+
// readback=true (COPY_SRC): BBuffer is also the source that seeds outBuffer.
|
|
123
|
+
const BBuffer = BIsGpu ? B._buf : uploadBuffer(B, "strmm-B", true);
|
|
124
|
+
const AdenseBuffer = createStorageBuffer(aOrder * ldDense * 4, "strmm-Adense");
|
|
125
|
+
// COPY_DST: seeded from B's own content before gemm runs, so stride-padding
|
|
126
|
+
// gaps (never written by gemm's tight m x n loop) keep B's original bytes
|
|
127
|
+
// instead of reading back as zero. COPY_SRC: read back / adopted by B after.
|
|
128
|
+
const outBuffer = createStorageBuffer(
|
|
129
|
+
bOuter * ldb * 4, "strmm-out", GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
|
|
130
|
+
);
|
|
131
|
+
let triParams = null, gemmParams = null;
|
|
132
|
+
let outBufferAdopted = false; // true once B._buf is repointed at outBuffer
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
triParams = createParamsBuffer(
|
|
136
|
+
[
|
|
137
|
+
{ value: aOrder, type: "u32" },
|
|
138
|
+
{ value: lda, type: "u32" },
|
|
139
|
+
{ value: ldDense, type: "u32" },
|
|
140
|
+
{ value: uploEffA === "upper" ? 1 : 0, type: "u32" },
|
|
141
|
+
{ value: transEffA === "transpose" ? 1 : 0, type: "u32" },
|
|
142
|
+
{ value: isUnit ? 1 : 0, type: "u32" },
|
|
143
|
+
],
|
|
144
|
+
"strmm-tri-params",
|
|
145
|
+
);
|
|
146
|
+
const triBindGroup = createBindGroup(triPipeline.getBindGroupLayout(0), [ABuffer, AdenseBuffer, triParams]);
|
|
147
|
+
|
|
148
|
+
// X/Y buffers and their own ld, matching swapXY above.
|
|
149
|
+
const XBuffer = swapXY ? BBuffer : AdenseBuffer;
|
|
150
|
+
const ldX = swapXY ? ldb : ldDense;
|
|
151
|
+
const YBuffer = swapXY ? AdenseBuffer : BBuffer;
|
|
152
|
+
const ldY = swapXY ? ldDense : ldb;
|
|
153
|
+
|
|
154
|
+
gemmParams = createParamsBuffer(
|
|
155
|
+
[
|
|
156
|
+
{ value: mg, type: "u32" },
|
|
157
|
+
{ value: ng, type: "u32" },
|
|
158
|
+
{ value: kg, type: "u32" },
|
|
159
|
+
{ value: alpha, type: "f32" },
|
|
160
|
+
{ value: 0.0, type: "f32" }, // beta — strmm has no C accumulation term
|
|
161
|
+
{ value: ldX, type: "u32" },
|
|
162
|
+
{ value: ldY, type: "u32" },
|
|
163
|
+
{ value: ldb, type: "u32" },
|
|
164
|
+
{ value: transX === "transpose" ? 1 : 0, type: "u32" },
|
|
165
|
+
{ value: transY === "transpose" ? 1 : 0, type: "u32" },
|
|
166
|
+
],
|
|
167
|
+
"strmm-gemm-params",
|
|
168
|
+
);
|
|
169
|
+
const gemmBindGroup = createBindGroup(gemmPipeline.getBindGroupLayout(0), [XBuffer, YBuffer, outBuffer, gemmParams]);
|
|
170
|
+
|
|
171
|
+
const { commandEncoder, querySet } = beginTimedEncoder();
|
|
172
|
+
// Seed outBuffer with B's own bytes first, so gemm's tight m x n write
|
|
173
|
+
// leaves stride-padding gaps holding B's original content, not zero.
|
|
174
|
+
// BBuffer may be larger than outBuffer (e.g. a validation-test baseline
|
|
175
|
+
// over-provisioned for a bigger ldb it might later be substituted with).
|
|
176
|
+
commandEncoder.copyBufferToBuffer(BBuffer, 0, outBuffer, 0, Math.min(BBuffer.size, outBuffer.size));
|
|
177
|
+
const triDesc = querySet ? { timestampWrites: { querySet, beginningOfPassWriteIndex: 0 } } : undefined;
|
|
178
|
+
const gemmDesc = querySet ? { timestampWrites: { querySet, endOfPassWriteIndex: 1 } } : undefined;
|
|
179
|
+
encodePass(commandEncoder, triPipeline, triBindGroup, { x: Math.ceil(aOrder / TRI_WG), y: Math.ceil(aOrder / TRI_WG) }, triDesc);
|
|
180
|
+
encodePass(commandEncoder, gemmPipeline, gemmBindGroup, gemmWgCount, gemmDesc);
|
|
181
|
+
|
|
182
|
+
const ts = resolveTimestamp(commandEncoder, querySet);
|
|
183
|
+
const readBuffer = BIsGpu ? null : stageReadback(commandEncoder, outBuffer);
|
|
184
|
+
|
|
185
|
+
submit(commandEncoder);
|
|
186
|
+
|
|
187
|
+
const gpuTimeMs = await extractTimestamp(ts);
|
|
188
|
+
|
|
189
|
+
if (BIsGpu) {
|
|
190
|
+
// Adopt outBuffer as B's own backing buffer instead of copying into the
|
|
191
|
+
// old one (B._buf has no COPY_DST usage) — cheaper and avoids needing
|
|
192
|
+
// an extra buffer-usage flag on every GpuMatrix for this one routine.
|
|
193
|
+
destroyBuffers(B._buf);
|
|
194
|
+
B._buf = outBuffer;
|
|
195
|
+
outBufferAdopted = true;
|
|
196
|
+
if (gpuTimeMs !== undefined) return { gpuTimeMs };
|
|
197
|
+
return {};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const result = await extractResult(readBuffer, Float32Array);
|
|
201
|
+
if (gpuTimeMs !== undefined) return { B: result, gpuTimeMs };
|
|
202
|
+
return { B: result };
|
|
203
|
+
} finally {
|
|
204
|
+
if (!AIsGpu) destroyBuffers(ABuffer);
|
|
205
|
+
if (!BIsGpu) destroyBuffers(BBuffer);
|
|
206
|
+
destroyBuffers(AdenseBuffer);
|
|
207
|
+
if (!outBufferAdopted) destroyBuffers(outBuffer);
|
|
208
|
+
if (triParams) destroyBuffers(triParams);
|
|
209
|
+
if (gemmParams) destroyBuffers(gemmParams);
|
|
210
|
+
}
|
|
211
|
+
}
|
package/src/strmv/strmv.d.mts
CHANGED
|
@@ -44,41 +44,6 @@ export declare function strmv(
|
|
|
44
44
|
layout?: 'row-major' | 'column-major',
|
|
45
45
|
): Promise<{ y: Float32Array; gpuTimeMs?: number }>;
|
|
46
46
|
|
|
47
|
-
/**
|
|
48
|
-
* Performs the triangular matrix-vector operation y = op(A) * x
|
|
49
|
-
*
|
|
50
|
-
* A is kept GPU-resident; x and y are CPU Float32Arrays. `A`'s own `layout`
|
|
51
|
-
* (set at `GpuMatrix.from` time) determines the operation — there is no
|
|
52
|
-
* separate `layout` argument here.
|
|
53
|
-
*
|
|
54
|
-
* @param device - GPUDevice from `init()`
|
|
55
|
-
* @param uplo - `'lower'` to use the lower triangle, `'upper'` to use the upper triangle
|
|
56
|
-
* @param trans - `'no-transpose'` for A, `'transpose'` for A^T
|
|
57
|
-
* @param diag - `'unit'` to treat the diagonal as all-ones (A's diagonal is not read), `'non-unit'` to read it
|
|
58
|
-
* @param n - order of the matrix A
|
|
59
|
-
* @param A - GpuMatrix, GPU-resident
|
|
60
|
-
* @param lda - leading dimension of A (must equal A.lda)
|
|
61
|
-
* @param x - Float32Array input vector
|
|
62
|
-
* @param incx - stride for x (must be a positive integer)
|
|
63
|
-
* @param y - Float32Array output vector
|
|
64
|
-
* @param incy - stride for y (must be a positive integer)
|
|
65
|
-
* @see <a href="https://github.com/manit2004/wgblas/blob/main/src/strmv/strmv.mjs#L15">Source code: strmv.mjs (L15)</a>
|
|
66
|
-
* @category BLAS Level 2
|
|
67
|
-
*/
|
|
68
|
-
export declare function strmv(
|
|
69
|
-
device: GPUDevice,
|
|
70
|
-
uplo: 'lower' | 'upper',
|
|
71
|
-
trans: 'no-transpose' | 'transpose',
|
|
72
|
-
diag: 'unit' | 'non-unit',
|
|
73
|
-
n: number,
|
|
74
|
-
A: GpuMatrix,
|
|
75
|
-
lda: number,
|
|
76
|
-
x: Float32Array,
|
|
77
|
-
incx: number,
|
|
78
|
-
y: Float32Array,
|
|
79
|
-
incy: number,
|
|
80
|
-
): Promise<{ y: Float32Array; gpuTimeMs?: number }>;
|
|
81
|
-
|
|
82
47
|
/**
|
|
83
48
|
* Performs the triangular matrix-vector operation y = op(A) * x
|
|
84
49
|
*
|
|
@@ -86,7 +51,7 @@ export declare function strmv(
|
|
|
86
51
|
* `layout` (set at `GpuMatrix.from` time) determines the operation — there is
|
|
87
52
|
* no separate `layout` argument here.
|
|
88
53
|
*
|
|
89
|
-
* {@includeCode ../../examples/strmv/
|
|
54
|
+
* {@includeCode ../../examples/strmv/gpu.strmv.js}
|
|
90
55
|
*
|
|
91
56
|
* @param device - GPUDevice from `init()`
|
|
92
57
|
* @param uplo - `'lower'` to use the lower triangle, `'upper'` to use the upper triangle
|
package/src/strmv/strmv.mjs
CHANGED
|
@@ -54,6 +54,8 @@ export async function strmv(device, uplo, trans, diag, n, A, lda, x, incx, y, in
|
|
|
54
54
|
);
|
|
55
55
|
if (xIsGpu && !AIsGpu)
|
|
56
56
|
throw new Error("A must be a GpuMatrix when x and y are GpuVectors.");
|
|
57
|
+
if (AIsGpu && !xIsGpu)
|
|
58
|
+
throw new Error("x and y must be GpuVectors when A is a GpuMatrix.");
|
|
57
59
|
if (AIsGpu && yIsGpu && A._buf === y._buf)
|
|
58
60
|
throw new Error("A and y must not reference the same GPU buffer.");
|
|
59
61
|
if (AIsGpu && lda !== A.lda)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { GpuMatrix } from "../classes/GpuMatrix.mjs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Solves the triangular matrix equation
|
|
5
|
+
* op(A) * X = alpha * B (`side='left'`) or
|
|
6
|
+
* X * op(A) = alpha * B (`side='right'`), overwriting `B` with the
|
|
7
|
+
* solution `X` — `A` is triangular, only its `uplo` triangle stored; `B` is
|
|
8
|
+
* a general m×n matrix.
|
|
9
|
+
*
|
|
10
|
+
* - `side='left'`: `A` is m×m — solves `op(A)*X = alpha*B`
|
|
11
|
+
* - `side='right'`: `A` is n×n — solves `X*op(A) = alpha*B`
|
|
12
|
+
*
|
|
13
|
+
* Blocked substitution (strsv's own technique, generalized to a matrix
|
|
14
|
+
* RHS): strsv_invert_block + sgemm, both unmodified. A near-zero diagonal
|
|
15
|
+
* entry amplifies error, same as any triangular solve.
|
|
16
|
+
*
|
|
17
|
+
* {@includeCode ../../examples/strsm/strsm.js}
|
|
18
|
+
*
|
|
19
|
+
* **Browser (standalone HTML):**
|
|
20
|
+
* {@includeCode ../../examples/strsm/web/strsm.html}
|
|
21
|
+
*
|
|
22
|
+
* @param device - GPUDevice from `init()`
|
|
23
|
+
* @param side - `'left'` to solve op(A)*X=alpha*B, `'right'` to solve X*op(A)=alpha*B
|
|
24
|
+
* @param uplo - `'lower'` if only `A`'s lower triangle is stored, `'upper'` for upper
|
|
25
|
+
* @param transA - `'no-transpose'` for A, `'transpose'` for A^T
|
|
26
|
+
* @param diag - `'unit'` to treat A's diagonal as all-ones (A's diagonal is not read), `'non-unit'` to read it
|
|
27
|
+
* @param m - rows of B
|
|
28
|
+
* @param n - columns of B
|
|
29
|
+
* @param alpha - scalar multiplier for B
|
|
30
|
+
* @param A - Float32Array, triangular, row-major or column-major (see `layout`)
|
|
31
|
+
* @param lda - leading dimension of A as stored
|
|
32
|
+
* @param B - Float32Array input/output matrix, overwritten with the solution, row-major or column-major
|
|
33
|
+
* @param ldb - leading dimension of B as stored
|
|
34
|
+
* @param layout - storage layout shared by A/B when they're Float32Array
|
|
35
|
+
* (default: `'row-major'`) — column-major A is a genuine transpose (A isn't
|
|
36
|
+
* symmetric like ssymm's), so both `transA` and `uplo` are adjusted
|
|
37
|
+
* internally to compensate
|
|
38
|
+
* @returns the solution X, written into B, as a Float32Array
|
|
39
|
+
* @see <a href="https://github.com/manit2004/wgblas/blob/main/src/strsm/strsm.mjs#L25">Source code: strsm.mjs (L25)</a>
|
|
40
|
+
* @category BLAS Level 3
|
|
41
|
+
*/
|
|
42
|
+
export declare function strsm(
|
|
43
|
+
device: GPUDevice,
|
|
44
|
+
side: 'left' | 'right',
|
|
45
|
+
uplo: 'lower' | 'upper',
|
|
46
|
+
transA: 'no-transpose' | 'transpose',
|
|
47
|
+
diag: 'unit' | 'non-unit',
|
|
48
|
+
m: number,
|
|
49
|
+
n: number,
|
|
50
|
+
alpha: number,
|
|
51
|
+
A: Float32Array,
|
|
52
|
+
lda: number,
|
|
53
|
+
B: Float32Array,
|
|
54
|
+
ldb: number,
|
|
55
|
+
layout?: 'row-major' | 'column-major',
|
|
56
|
+
): Promise<{ B: Float32Array; gpuTimeMs?: number }>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Solves the triangular matrix equation
|
|
60
|
+
* op(A) * X = alpha * B (`side='left'`) or
|
|
61
|
+
* X * op(A) = alpha * B (`side='right'`), overwriting `B` in place with `X`.
|
|
62
|
+
*
|
|
63
|
+
* A and B are both kept GPU-resident. Each matrix's own `layout` (set at
|
|
64
|
+
* `GpuMatrix.from` time) determines the operation — there is no separate
|
|
65
|
+
* `layout` argument here. A and B must both be GpuMatrix or both be
|
|
66
|
+
* Float32Array — mixing is not supported.
|
|
67
|
+
*
|
|
68
|
+
* {@includeCode ../../examples/strsm/gpu.strsm.js}
|
|
69
|
+
*
|
|
70
|
+
* @param device - GPUDevice from `init()`
|
|
71
|
+
* @param side - `'left'` to solve op(A)*X=alpha*B, `'right'` to solve X*op(A)=alpha*B
|
|
72
|
+
* @param uplo - `'lower'` if only `A`'s lower triangle is stored, `'upper'` for upper
|
|
73
|
+
* @param transA - `'no-transpose'` for A, `'transpose'` for A^T
|
|
74
|
+
* @param diag - `'unit'` to treat A's diagonal as all-ones (A's diagonal is not read), `'non-unit'` to read it
|
|
75
|
+
* @param m - rows of B
|
|
76
|
+
* @param n - columns of B
|
|
77
|
+
* @param alpha - scalar multiplier for B
|
|
78
|
+
* @param A - GpuMatrix, triangular
|
|
79
|
+
* @param lda - leading dimension of A (must equal A.lda)
|
|
80
|
+
* @param B - GpuMatrix (overwritten in place with the solution)
|
|
81
|
+
* @param ldb - leading dimension of B (must equal B.lda)
|
|
82
|
+
* @returns no B — it stays GPU-resident; call `B.read()` yourself for a CPU readback (see the example)
|
|
83
|
+
* @see <a href="https://github.com/manit2004/wgblas/blob/main/src/strsm/strsm.mjs#L25">Source code: strsm.mjs (L25)</a>
|
|
84
|
+
* @category BLAS Level 3
|
|
85
|
+
*/
|
|
86
|
+
export declare function strsm(
|
|
87
|
+
device: GPUDevice,
|
|
88
|
+
side: 'left' | 'right',
|
|
89
|
+
uplo: 'lower' | 'upper',
|
|
90
|
+
transA: 'no-transpose' | 'transpose',
|
|
91
|
+
diag: 'unit' | 'non-unit',
|
|
92
|
+
m: number,
|
|
93
|
+
n: number,
|
|
94
|
+
alpha: number,
|
|
95
|
+
A: GpuMatrix,
|
|
96
|
+
lda: number,
|
|
97
|
+
B: GpuMatrix,
|
|
98
|
+
ldb: number,
|
|
99
|
+
): Promise<{ gpuTimeMs?: number }>;
|