umap-web 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgpu.js","names":["device","ctx: GpuContext","ctx","knnWgsl","dist: Float32Array","idx: Int32Array","normsBuf: GPUBuffer","qnormsBuf: GPUBuffer","cache","sgdWgsl","alpha","edgeBindGroups: GPUBindGroup[]","info: { epoch: number; nEpochs: number; phase: string; embedding?: Float32Array }","b","spmvWgsl","emb"],"sources":["../src/backends/webgpu/device.ts","../src/backends/webgpu/kernels/knn.wgsl","../src/backends/webgpu/knn.ts","../src/backends/webgpu/kernels/sgd.wgsl","../src/backends/webgpu/layout.ts","../src/backends/webgpu/kernels/spmv.wgsl","../src/backends/webgpu/spectral.ts","../src/backends/webgpu/index.ts"],"sourcesContent":["/**\n * WebGPU device acquisition (§5.4): injected device/provider or navigator.gpu,\n * elevated limits up to adapter limits. Device loss is tracked on the context\n * (kernels check it at loop boundaries and raise a typed UmapBackendError; the\n * estimator falls back to CPU under backend 'auto' — see DECISIONS D-017), and\n * every kernel runs inside validation + out-of-memory error scopes so GPU\n * failures surface as typed errors instead of silent zero-filled readbacks.\n */\n\nimport { UmapBackendError } from '../../types.js';\n\nexport interface GpuContext {\n device: GPUDevice;\n adapterInfo: { vendor: string; architecture: string; device: string; description: string };\n limits: { maxStorageBufferBindingSize: number; maxBufferSize: number; maxWorkgroupsX: number };\n timestamps: boolean;\n injected: boolean;\n /** set when the device reports loss; kernels must stop using the context */\n lost: { reason: string; message: string } | null;\n}\n\nexport type DeviceProvider = GPUDevice | (() => Promise<GPUDevice>) | Promise<GPUDevice>;\n\nfunction trackLost(ctx: GpuContext): void {\n ctx.device.lost\n .then((info) => {\n ctx.lost = { reason: String(info.reason), message: info.message };\n })\n .catch(() => {\n ctx.lost = { reason: 'unknown', message: 'device.lost rejected' };\n });\n}\n\n/** Throw (typed) if the device reported loss. */\nexport function assertUsable(ctx: GpuContext, stage: string): void {\n if (ctx.lost) {\n throw new UmapBackendError(\n `GPU device lost during ${stage} (${ctx.lost.reason}): ${ctx.lost.message}`,\n );\n }\n}\n\n/**\n * Validate a planned buffer against the granted limits BEFORE creating it —\n * an oversized storage binding is an async validation error that would\n * otherwise surface as silently zero-filled results on low-limit adapters.\n */\nexport function ensureBufferFits(\n ctx: GpuContext,\n stage: string,\n name: string,\n byteLength: number,\n): void {\n if (byteLength > ctx.limits.maxBufferSize) {\n throw new UmapBackendError(\n `${stage}: buffer '${name}' (${byteLength} bytes) exceeds this device's ` +\n `maxBufferSize (${ctx.limits.maxBufferSize}); the dataset is too large for this GPU`,\n );\n }\n if (byteLength > ctx.limits.maxStorageBufferBindingSize) {\n throw new UmapBackendError(\n `${stage}: buffer '${name}' (${byteLength} bytes) exceeds this device's ` +\n `maxStorageBufferBindingSize (${ctx.limits.maxStorageBufferBindingSize}); ` +\n 'the dataset is too large for this GPU',\n );\n }\n}\n\n/**\n * Push validation + out-of-memory scopes; the returned closer pops them and\n * throws a typed error when either scope caught anything. The closer is\n * idempotent so kernels can also invoke it from a finally block (keeping the\n * device's scope stack balanced when the body throws first).\n */\nexport function beginErrorScopes(device: GPUDevice): (stage: string) => Promise<void> {\n device.pushErrorScope('out-of-memory');\n device.pushErrorScope('validation');\n let popped = false;\n return async (stage: string) => {\n if (popped) return;\n popped = true;\n const validation = await device.popErrorScope();\n const oom = await device.popErrorScope();\n if (oom) {\n throw new UmapBackendError(`${stage}: GPU out of memory: ${oom.message}`);\n }\n if (validation) {\n throw new UmapBackendError(`${stage}: GPU validation error: ${validation.message}`);\n }\n };\n}\n\nexport async function acquireGpu(provided?: DeviceProvider): Promise<GpuContext> {\n if (provided) {\n const device =\n typeof provided === 'function'\n ? await provided()\n : await Promise.resolve(provided as GPUDevice | Promise<GPUDevice>);\n const ctx: GpuContext = {\n device,\n adapterInfo: {\n vendor: 'injected',\n architecture: 'injected',\n device: '',\n description: 'user-provided GPUDevice',\n },\n limits: {\n maxStorageBufferBindingSize: device.limits.maxStorageBufferBindingSize,\n maxBufferSize: device.limits.maxBufferSize,\n maxWorkgroupsX: device.limits.maxComputeWorkgroupsPerDimension,\n },\n timestamps: device.features.has('timestamp-query'),\n injected: true,\n lost: null,\n };\n trackLost(ctx);\n return ctx;\n }\n const gpu = (globalThis.navigator as Navigator & { gpu?: GPU })?.gpu;\n if (!gpu) {\n throw new UmapBackendError('WebGPU is not available (navigator.gpu undefined)');\n }\n const adapter = await gpu.requestAdapter();\n if (!adapter) {\n throw new UmapBackendError('WebGPU adapter unavailable (requestAdapter returned null)');\n }\n const wantTimestamps = adapter.features.has('timestamp-query');\n const device = await adapter.requestDevice({\n requiredLimits: {\n maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize,\n maxBufferSize: adapter.limits.maxBufferSize,\n },\n requiredFeatures: wantTimestamps ? (['timestamp-query'] as GPUFeatureName[]) : [],\n });\n const info = adapter.info;\n const ctx: GpuContext = {\n device,\n adapterInfo: {\n vendor: info?.vendor ?? 'unknown',\n architecture: info?.architecture ?? 'unknown',\n device: info?.device ?? '',\n description: info?.description ?? '',\n },\n limits: {\n maxStorageBufferBindingSize: device.limits.maxStorageBufferBindingSize,\n maxBufferSize: device.limits.maxBufferSize,\n maxWorkgroupsX: device.limits.maxComputeWorkgroupsPerDimension,\n },\n timestamps: device.features.has('timestamp-query'),\n injected: false,\n lost: null,\n };\n trackLost(ctx);\n return ctx;\n}\n\nexport function createBuffer(\n device: GPUDevice,\n data: Float32Array | Int32Array | Uint32Array,\n usage: GPUBufferUsageFlags,\n): GPUBuffer {\n const buf = device.createBuffer({ size: Math.ceil(data.byteLength / 4) * 4, usage });\n device.queue.writeBuffer(buf, 0, data.buffer, data.byteOffset, data.byteLength);\n return buf;\n}\n\nexport async function readBuffer(\n device: GPUDevice,\n src: GPUBuffer,\n byteLength: number,\n): Promise<ArrayBuffer> {\n const staging = device.createBuffer({\n size: Math.ceil(byteLength / 4) * 4,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\n });\n try {\n const enc = device.createCommandEncoder();\n enc.copyBufferToBuffer(src, 0, staging, 0, staging.size);\n device.queue.submit([enc.finish()]);\n await staging.mapAsync(GPUMapMode.READ);\n const out = staging.getMappedRange().slice(0);\n staging.unmap();\n return out;\n } catch (e) {\n throw e instanceof UmapBackendError\n ? e\n : new UmapBackendError(`GPU readback failed: ${(e as Error).message}`);\n } finally {\n staging.destroy();\n }\n}\n","\"// Tiled brute-force kNN (§A3): 256 queries per workgroup (one per thread),\\n// candidate tiles of 64 rows staged through workgroup memory as vec4 chunks,\\n// per-thread private top-k (k <= 32). No n×n buffer ever exists; fits the\\n// default 16 KB workgroup-storage and 8-storage-buffer limits.\\n//\\n// Data layout: rows padded to d4 = ceil(d/4) vec4s (zero padding is neutral for\\n// every supported metric). metricKind: 0 = squared euclidean, 1 = alternative\\n// cosine (log2(sqrt(nx*ny)/dot)), 2 = manhattan, 3 = hamming (raw count; /d on\\n// CPU), 4 = alternative jaccard. correlation = kind 1 on row-centered data.\\n\\nstruct Params {\\n n: u32, // candidate rows\\n d4: u32, // vec4s per row\\n k: u32, // neighbors (<= 32)\\n metricKind: u32,\\n nQueries: u32,\\n candStart: u32,\\n candEnd: u32,\\n pad0: u32,\\n}\\n\\n@group(0) @binding(0) var<storage, read> data: array<vec4<f32>>; // n x d4\\n@group(0) @binding(1) var<storage, read> queries: array<vec4<f32>>; // nQueries x d4\\n@group(0) @binding(2) var<storage, read_write> outDist: array<f32>;\\n@group(0) @binding(3) var<storage, read_write> outIdx: array<i32>;\\n@group(0) @binding(4) var<uniform> params: Params;\\n@group(0) @binding(5) var<storage, read> norms: array<f32>;\\n@group(0) @binding(6) var<storage, read> qnorms: array<f32>;\\n\\nconst TQ: u32 = 256u; // queries per workgroup\\nconst TC: u32 = 64u; // candidate tile rows\\nconst DC4: u32 = 8u; // vec4s per dimension chunk (32 floats)\\nconst KMAX: u32 = 32u;\\nconst FLOAT32_MAX: f32 = 3.4028234663852886e38;\\n\\nvar<workgroup> cTile: array<vec4<f32>, 512>; // TC x DC4\\n\\n@compute @workgroup_size(256)\\nfn knnQueryTile(\\n @builtin(workgroup_id) wg: vec3<u32>,\\n @builtin(local_invocation_id) lid: vec3<u32>,\\n) {\\n let qLocal = lid.x;\\n let qRow = wg.x * TQ + qLocal;\\n let isActive = qRow < params.nQueries;\\n\\n var heapDist: array<f32, KMAX>;\\n var heapIdx: array<i32, KMAX>;\\n let k = params.k;\\n for (var i = 0u; i < KMAX; i = i + 1u) {\\n heapDist[i] = FLOAT32_MAX;\\n heapIdx[i] = -1;\\n }\\n if (isActive && params.candStart > 0u) {\\n for (var i = 0u; i < k; i = i + 1u) {\\n heapDist[i] = outDist[qRow * k + i];\\n heapIdx[i] = outIdx[qRow * k + i];\\n }\\n }\\n var worst = 0u;\\n var worstVal = -FLOAT32_MAX;\\n for (var i = 0u; i < k; i = i + 1u) {\\n if (heapDist[i] > worstVal) { worstVal = heapDist[i]; worst = i; }\\n }\\n\\n var acc: array<f32, TC>;\\n var acc2: array<f32, TC>;\\n\\n var cBase = params.candStart;\\n loop {\\n if (cBase >= params.candEnd) { break; }\\n let tileLen = min(TC, params.candEnd - cBase);\\n\\n for (var t = 0u; t < TC; t = t + 1u) { acc[t] = 0.0; acc2[t] = 0.0; }\\n\\n var dBase = 0u; // vec4 offset within the row\\n loop {\\n if (dBase >= params.d4) { break; }\\n let chunk = min(DC4, params.d4 - dBase);\\n workgroupBarrier();\\n // cooperative tile load: 512 vec4 slots over 256 threads (2 each)\\n for (var li = qLocal; li < TC * DC4; li = li + 256u) {\\n let row = li / DC4;\\n let slot = li % DC4;\\n if (row < tileLen && slot < chunk) {\\n cTile[li] = data[(cBase + row) * params.d4 + dBase + slot];\\n } else {\\n cTile[li] = vec4<f32>(0.0);\\n }\\n }\\n workgroupBarrier();\\n if (isActive) {\\n // fully-unrolled registers (dynamic private-array indexing spills to local\\n // memory on Metal); zero vec4s are neutral for every metric here\\n let qb = qRow * params.d4 + dBase;\\n var q0 = vec4<f32>(0.0);\\n var q1 = vec4<f32>(0.0);\\n var q2 = vec4<f32>(0.0);\\n var q3 = vec4<f32>(0.0);\\n var q4 = vec4<f32>(0.0);\\n var q5 = vec4<f32>(0.0);\\n var q6 = vec4<f32>(0.0);\\n var q7 = vec4<f32>(0.0);\\n q0 = queries[qb];\\n if (chunk > 1u) { q1 = queries[qb + 1u]; }\\n if (chunk > 2u) { q2 = queries[qb + 2u]; }\\n if (chunk > 3u) { q3 = queries[qb + 3u]; }\\n if (chunk > 4u) { q4 = queries[qb + 4u]; }\\n if (chunk > 5u) { q5 = queries[qb + 5u]; }\\n if (chunk > 6u) { q6 = queries[qb + 6u]; }\\n if (chunk > 7u) { q7 = queries[qb + 7u]; }\\n switch params.metricKind {\\n case 0u: {\\n for (var t = 0u; t < tileLen; t = t + 1u) {\\n let tb = t * DC4;\\n let d0 = q0 - cTile[tb];\\n let d1 = q1 - cTile[tb + 1u];\\n let d2 = q2 - cTile[tb + 2u];\\n let d3 = q3 - cTile[tb + 3u];\\n let d4v = q4 - cTile[tb + 4u];\\n let d5 = q5 - cTile[tb + 5u];\\n let d6 = q6 - cTile[tb + 6u];\\n let d7 = q7 - cTile[tb + 7u];\\n let s = d0 * d0 + d1 * d1 + d2 * d2 + d3 * d3 + d4v * d4v + d5 * d5 + d6 * d6 + d7 * d7;\\n acc[t] = acc[t] + s.x + s.y + s.z + s.w;\\n }\\n }\\n case 1u: {\\n for (var t = 0u; t < tileLen; t = t + 1u) {\\n let tb = t * DC4;\\n let s = q0 * cTile[tb] + q1 * cTile[tb + 1u] + q2 * cTile[tb + 2u] + q3 * cTile[tb + 3u]\\n + q4 * cTile[tb + 4u] + q5 * cTile[tb + 5u] + q6 * cTile[tb + 6u] + q7 * cTile[tb + 7u];\\n acc[t] = acc[t] + s.x + s.y + s.z + s.w;\\n }\\n }\\n case 2u: {\\n for (var t = 0u; t < tileLen; t = t + 1u) {\\n let tb = t * DC4;\\n let s = abs(q0 - cTile[tb]) + abs(q1 - cTile[tb + 1u]) + abs(q2 - cTile[tb + 2u]) + abs(q3 - cTile[tb + 3u])\\n + abs(q4 - cTile[tb + 4u]) + abs(q5 - cTile[tb + 5u]) + abs(q6 - cTile[tb + 6u]) + abs(q7 - cTile[tb + 7u]);\\n acc[t] = acc[t] + s.x + s.y + s.z + s.w;\\n }\\n }\\n case 3u: {\\n // hamming: padded zero lanes compare equal on both sides — neutral\\n for (var t = 0u; t < tileLen; t = t + 1u) {\\n let tb = t * DC4;\\n let s = select(vec4<f32>(0.0), vec4<f32>(1.0), q0 != cTile[tb]) +\\n select(vec4<f32>(0.0), vec4<f32>(1.0), q1 != cTile[tb + 1u]) +\\n select(vec4<f32>(0.0), vec4<f32>(1.0), q2 != cTile[tb + 2u]) +\\n select(vec4<f32>(0.0), vec4<f32>(1.0), q3 != cTile[tb + 3u]) +\\n select(vec4<f32>(0.0), vec4<f32>(1.0), q4 != cTile[tb + 4u]) +\\n select(vec4<f32>(0.0), vec4<f32>(1.0), q5 != cTile[tb + 5u]) +\\n select(vec4<f32>(0.0), vec4<f32>(1.0), q6 != cTile[tb + 6u]) +\\n select(vec4<f32>(0.0), vec4<f32>(1.0), q7 != cTile[tb + 7u]);\\n acc[t] = acc[t] + s.x + s.y + s.z + s.w;\\n }\\n }\\n default: {\\n for (var t = 0u; t < tileLen; t = t + 1u) {\\n let tb = t * DC4;\\n var eq = vec4<f32>(0.0);\\n var nz = vec4<f32>(0.0);\\n let c0 = cTile[tb];\\n let c1 = cTile[tb + 1u];\\n let c2 = cTile[tb + 2u];\\n let c3 = cTile[tb + 3u];\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q0 != vec4<f32>(0.0)) & (c0 != vec4<f32>(0.0)));\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q1 != vec4<f32>(0.0)) & (c1 != vec4<f32>(0.0)));\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q2 != vec4<f32>(0.0)) & (c2 != vec4<f32>(0.0)));\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q3 != vec4<f32>(0.0)) & (c3 != vec4<f32>(0.0)));\\n let c4 = cTile[tb + 4u];\\n let c5 = cTile[tb + 5u];\\n let c6 = cTile[tb + 6u];\\n let c7 = cTile[tb + 7u];\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q4 != vec4<f32>(0.0)) & (c4 != vec4<f32>(0.0)));\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q5 != vec4<f32>(0.0)) & (c5 != vec4<f32>(0.0)));\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q6 != vec4<f32>(0.0)) & (c6 != vec4<f32>(0.0)));\\n eq = eq + select(vec4<f32>(0.0), vec4<f32>(1.0), (q7 != vec4<f32>(0.0)) & (c7 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q0 != vec4<f32>(0.0)) | (c0 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q1 != vec4<f32>(0.0)) | (c1 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q2 != vec4<f32>(0.0)) | (c2 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q3 != vec4<f32>(0.0)) | (c3 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q4 != vec4<f32>(0.0)) | (c4 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q5 != vec4<f32>(0.0)) | (c5 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q6 != vec4<f32>(0.0)) | (c6 != vec4<f32>(0.0)));\\n nz = nz + select(vec4<f32>(0.0), vec4<f32>(1.0), (q7 != vec4<f32>(0.0)) | (c7 != vec4<f32>(0.0)));\\n acc[t] = acc[t] + eq.x + eq.y + eq.z + eq.w;\\n acc2[t] = acc2[t] + nz.x + nz.y + nz.z + nz.w;\\n }\\n }\\n }\\n }\\n dBase = dBase + DC4;\\n }\\n\\n if (isActive) {\\n for (var t = 0u; t < tileLen; t = t + 1u) {\\n var dist: f32;\\n switch params.metricKind {\\n case 0u, 2u, 3u: { dist = acc[t]; }\\n case 1u: {\\n let nx = qnorms[qRow];\\n let ny = norms[cBase + t];\\n if (nx == 0.0 && ny == 0.0) {\\n dist = 0.0;\\n } else if (nx == 0.0 || ny == 0.0 || acc[t] <= 0.0) {\\n dist = FLOAT32_MAX;\\n } else {\\n dist = log2(sqrt(nx * ny) / acc[t]);\\n }\\n }\\n default: {\\n if (acc2[t] == 0.0) {\\n dist = 0.0;\\n } else if (acc[t] == 0.0) {\\n dist = FLOAT32_MAX;\\n } else {\\n dist = -log2(acc[t] / acc2[t]);\\n }\\n }\\n }\\n if (dist < worstVal) {\\n heapDist[worst] = dist;\\n heapIdx[worst] = i32(cBase + t);\\n worstVal = -FLOAT32_MAX;\\n for (var i = 0u; i < k; i = i + 1u) {\\n if (heapDist[i] > worstVal) { worstVal = heapDist[i]; worst = i; }\\n }\\n }\\n }\\n }\\n cBase = cBase + TC;\\n }\\n\\n if (isActive) {\\n for (var i = 0u; i < k; i = i + 1u) {\\n outDist[qRow * k + i] = heapDist[i];\\n outIdx[qRow * k + i] = heapIdx[i];\\n }\\n }\\n}\\n\\n// squared norms (cosine family); outDist reused as the norms output\\n@compute @workgroup_size(256)\\nfn rowNorms(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let row = gid.x;\\n if (row >= params.n) { return; }\\n var s = vec4<f32>(0.0);\\n for (var c = 0u; c < params.d4; c = c + 1u) {\\n let v = data[row * params.d4 + c];\\n s = s + v * v;\\n }\\n outDist[row] = s.x + s.y + s.z + s.w;\\n}\\n\"","/**\n * GPU brute-force kNN driver (§A3): streams candidate ranges (watchdog-safe\n * dispatch sizes), per-row ascending sort + distance correction on readback.\n */\n\nimport type { KnnGraph, Matrix } from '../../types.js';\nimport { throwIfAborted, UmapBackendError } from '../../types.js';\nimport {\n assertUsable,\n beginErrorScopes,\n createBuffer,\n ensureBufferFits,\n type GpuContext,\n readBuffer,\n} from './device.js';\nimport knnWgsl from './kernels/knn.wgsl';\n\nexport type GpuMetricKind = 0 | 1 | 2 | 3 | 4; // sqeuclidean | altcosine | manhattan | hamming | altjaccard\n\nexport interface GpuMetricPlan {\n kind: GpuMetricKind;\n /** center rows before upload (correlation) */\n center: boolean;\n correction: (d: number) => number;\n}\n\n/** GPU support matrix (§4.3). Returns null for unsupported metrics. */\nexport function gpuMetricPlan(name: string): GpuMetricPlan | null {\n switch (name) {\n case 'euclidean':\n case 'l2':\n return { kind: 0, center: false, correction: (d) => Math.sqrt(d) };\n case 'sqeuclidean':\n return { kind: 0, center: false, correction: (d) => d };\n case 'cosine':\n return { kind: 1, center: false, correction: (d) => 1.0 - 2.0 ** -d };\n case 'correlation':\n return { kind: 1, center: true, correction: (d) => 1.0 - 2.0 ** -d };\n case 'manhattan':\n case 'taxicab':\n case 'l1':\n return { kind: 2, center: false, correction: (d) => d };\n case 'hamming':\n return { kind: 3, center: false, correction: (d) => d }; // ÷d applied by the driver\n case 'jaccard':\n return { kind: 4, center: false, correction: (d) => 1.0 - 2.0 ** -d };\n default:\n return null;\n }\n}\n\nconst PARAMS_SIZE = 32;\n\ninterface KnnPipelines {\n module: GPUShaderModule;\n tile: GPUComputePipeline;\n norms: GPUComputePipeline;\n}\n\nconst pipelineCache = new WeakMap<GPUDevice, KnnPipelines>();\n\nfunction getPipelines(device: GPUDevice): KnnPipelines {\n let p = pipelineCache.get(device);\n if (!p) {\n const module = device.createShaderModule({ code: knnWgsl });\n p = {\n module,\n tile: device.createComputePipeline({\n layout: 'auto',\n compute: { module, entryPoint: 'knnQueryTile' },\n }),\n norms: device.createComputePipeline({\n layout: 'auto',\n compute: { module, entryPoint: 'rowNorms' },\n }),\n };\n pipelineCache.set(device, p);\n }\n return p;\n}\n\nexport interface GpuKnnOptions {\n /** candidates per dispatch (watchdog safety); tuned by data size */\n candChunk?: number;\n onProgress?: (done: number, total: number) => void;\n signal?: AbortSignal;\n}\n\n/**\n * kNN of `queries` against `data` (self-kNN when they alias) in INTERNAL metric\n * space; returns corrected, ascending-sorted results.\n */\nexport async function gpuKnn(\n ctx: GpuContext,\n X: Matrix,\n queries: Matrix | null,\n k: number,\n plan: GpuMetricPlan,\n { candChunk, onProgress, signal }: GpuKnnOptions = {},\n): Promise<KnnGraph> {\n if (k > 32) throw new UmapBackendError('GPU kNN supports k <= 32');\n const device = ctx.device;\n const n = X.rows;\n const d = X.cols;\n const d4 = Math.ceil(d / 4);\n const dPad = d4 * 4;\n const nQueries = queries === null ? n : queries.rows;\n\n // validate planned allocations against the granted limits up front (§A12):\n // an oversized storage binding would otherwise fail asynchronously and read\n // back as silent zeros on low-limit adapters\n assertUsable(ctx, 'gpuKnn');\n ensureBufferFits(ctx, 'gpuKnn', 'data', n * dPad * 4);\n if (queries !== null) ensureBufferFits(ctx, 'gpuKnn', 'queries', nQueries * dPad * 4);\n ensureBufferFits(ctx, 'gpuKnn', 'outDistances', nQueries * k * 4);\n ensureBufferFits(ctx, 'gpuKnn', 'outIndices', nQueries * k * 4);\n\n // pad rows to vec4 boundaries (zero padding is metric-neutral), center for correlation\n const padRows = (src: Float32Array, rows: number, center: boolean): Float32Array => {\n if (dPad === d && !center) return src; // already vec4-aligned — zero-copy\n const out = new Float32Array(rows * dPad);\n for (let i = 0; i < rows; i++) {\n let mu = 0;\n if (center) {\n for (let c = 0; c < d; c++) mu += src[i * d + c]!;\n mu /= d;\n }\n for (let c = 0; c < d; c++) out[i * dPad + c] = src[i * d + c]! - mu;\n }\n return out;\n };\n const hostData = padRows(X.data, n, plan.center);\n const sameQuery = queries === null;\n const nq = sameQuery ? n : queries!.rows;\n const hostQ = sameQuery ? hostData : padRows(queries!.data, nq, plan.center);\n\n const pipes = getPipelines(device);\n // every buffer is tracked and destroyed in the finally below — abort or a\n // validation failure must not leak GPU memory (injected devices accumulate)\n const scratch = new Set<GPUBuffer>();\n const track = (buf: GPUBuffer): GPUBuffer => {\n scratch.add(buf);\n return buf;\n };\n const endScopes = beginErrorScopes(device);\n let dist: Float32Array;\n let idx: Int32Array;\n try {\n const dataBuf = track(\n createBuffer(device, hostData, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST),\n );\n const qBuf = sameQuery\n ? dataBuf\n : track(createBuffer(device, hostQ, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST));\n const outDist = track(\n device.createBuffer({\n size: nq * k * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n }),\n );\n const outIdx = track(\n device.createBuffer({\n size: nq * k * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n }),\n );\n const paramsBuf = track(\n device.createBuffer({\n size: PARAMS_SIZE,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n }),\n );\n const dummy = track(device.createBuffer({ size: 4, usage: GPUBufferUsage.STORAGE }));\n\n // norms (cosine family)\n let normsBuf: GPUBuffer = dummy;\n let qnormsBuf: GPUBuffer = dummy;\n if (plan.kind === 1) {\n normsBuf = track(\n device.createBuffer({\n size: n * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n }),\n );\n const np = track(\n device.createBuffer({\n size: PARAMS_SIZE,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n }),\n );\n device.queue.writeBuffer(np, 0, new Uint32Array([n, d4, k, plan.kind, n, 0, n, 0]));\n const bg = device.createBindGroup({\n layout: pipes.norms.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: dataBuf } },\n { binding: 2, resource: { buffer: normsBuf } },\n { binding: 4, resource: { buffer: np } },\n ],\n });\n const enc = device.createCommandEncoder();\n const pass = enc.beginComputePass();\n pass.setPipeline(pipes.norms);\n pass.setBindGroup(0, bg);\n pass.dispatchWorkgroups(Math.ceil(n / 256));\n pass.end();\n device.queue.submit([enc.finish()]);\n if (sameQuery) {\n qnormsBuf = normsBuf;\n } else {\n qnormsBuf = track(\n device.createBuffer({\n size: nq * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n }),\n );\n const qp = track(\n device.createBuffer({\n size: PARAMS_SIZE,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n }),\n );\n device.queue.writeBuffer(qp, 0, new Uint32Array([nq, d4, k, plan.kind, nq, 0, nq, 0]));\n const bgq = device.createBindGroup({\n layout: pipes.norms.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: qBuf } },\n { binding: 2, resource: { buffer: qnormsBuf } },\n { binding: 4, resource: { buffer: qp } },\n ],\n });\n const enc2 = device.createCommandEncoder();\n const pass2 = enc2.beginComputePass();\n pass2.setPipeline(pipes.norms);\n pass2.setBindGroup(0, bgq);\n pass2.dispatchWorkgroups(Math.ceil(nq / 256));\n pass2.end();\n device.queue.submit([enc2.finish()]);\n }\n }\n\n const bindGroup = device.createBindGroup({\n layout: pipes.tile.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: dataBuf } },\n { binding: 1, resource: { buffer: qBuf } },\n { binding: 2, resource: { buffer: outDist } },\n { binding: 3, resource: { buffer: outIdx } },\n { binding: 4, resource: { buffer: paramsBuf } },\n { binding: 5, resource: { buffer: normsBuf } },\n { binding: 6, resource: { buffer: qnormsBuf } },\n ],\n });\n\n // watchdog-safe candidate streaming: budget ≈ 6e10 madd per dispatch\n const chunk = candChunk ?? Math.max(4096, Math.min(n, Math.floor(6e10 / Math.max(1, nq * d))));\n const wgCount = Math.ceil(nq / 256);\n for (let cs = 0; cs < n; cs += chunk) {\n throwIfAborted(signal);\n assertUsable(ctx, 'gpuKnn');\n const ce = Math.min(n, cs + chunk);\n device.queue.writeBuffer(paramsBuf, 0, new Uint32Array([n, d4, k, plan.kind, nq, cs, ce, 0]));\n const enc = device.createCommandEncoder();\n const pass = enc.beginComputePass();\n pass.setPipeline(pipes.tile);\n pass.setBindGroup(0, bindGroup);\n pass.dispatchWorkgroups(wgCount);\n pass.end();\n device.queue.submit([enc.finish()]);\n await device.queue.onSubmittedWorkDone();\n onProgress?.(ce, n);\n }\n await endScopes('gpuKnn');\n assertUsable(ctx, 'gpuKnn');\n\n dist = new Float32Array(await readBuffer(device, outDist, nq * k * 4));\n idx = new Int32Array(await readBuffer(device, outIdx, nq * k * 4));\n } finally {\n // balance the scope stack even when the body threw first\n await endScopes('gpuKnn').catch(() => {});\n for (const b of scratch) b.destroy();\n }\n\n // per-row ascending sort + correction (final output space)\n const indices = new Int32Array(nq * k);\n const distances = new Float32Array(nq * k);\n const order = new Array<number>(k);\n for (let i = 0; i < nq; i++) {\n for (let j = 0; j < k; j++) order[j] = j;\n order.sort((a, b) => dist[i * k + a]! - dist[i * k + b]!);\n for (let j = 0; j < k; j++) {\n const o = order[j]!;\n let raw = dist[i * k + o]!;\n if (plan.kind === 3) raw /= d; // hamming: kernel returns the mismatch count\n indices[i * k + j] = idx[i * k + o]!;\n distances[i * k + j] = raw >= 3.4e38 ? Infinity : plan.correction(raw);\n }\n }\n return { indices, distances, k };\n}\n","\"// SGD layout kernels (§A2). Two strategies, both implemented and measured\\n// (DECISIONS D-011):\\n// (A) vertexGather — one thread per head vertex walking its CSR edge range;\\n// writes only its own row (conflict-free by ownership; Hogwild reads).\\n// (B) edgeAtomic — one thread per edge; fixed-point atomicAdd on i32 embedding\\n// (scale 2^20), converted to/from f32 by pack/unpack kernels. Epochs run\\n// as ordered sub-batches; reads come from the previous sub-batch's\\n// snapshot (binding 11), making the result bit-deterministic per seed.\\n\\nstruct LayoutParams {\\n nVertices: u32,\\n nEdges: u32,\\n dim: u32,\\n epoch: u32,\\n alpha: f32,\\n a: f32,\\n b: f32,\\n gamma: f32,\\n negativeSampleRate: f32,\\n moveOther: u32,\\n scale: f32, // fixed-point scale for edgeAtomic\\n pad0: u32,\\n}\\n\\n// Ordered sub-batch of the edge list for one edgeAtomic dispatch. Epochs are\\n// split into sequential sub-batches so an edge sees the committed updates of\\n// every earlier sub-batch — approximating the CPU's in-order (Gauss–Seidel)\\n// update visibility instead of one epoch-wide racy dispatch.\\nstruct BatchParams {\\n edgeOffset: u32,\\n edgeCount: u32,\\n}\\n\\n@group(0) @binding(0) var<storage, read_write> embedding: array<f32>;\\n@group(0) @binding(1) var<storage, read> head: array<i32>;\\n@group(0) @binding(2) var<storage, read> tail: array<i32>;\\n@group(0) @binding(3) var<storage, read> epochsPerSample: array<f32>;\\n// schedule[e] = epoch_of_next_sample; schedule[nEdges + e] = epoch_of_next_negative\\n@group(0) @binding(4) var<storage, read_write> schedule: array<f32>;\\n@group(0) @binding(6) var<storage, read_write> rngStates: array<u32>; // 3 per vertex (A) / per edge (B)\\n@group(0) @binding(7) var<uniform> P: LayoutParams;\\n@group(0) @binding(8) var<storage, read> rowPtr: array<u32>; // vertexGather CSR\\n@group(0) @binding(9) var<storage, read_write> embeddingFx: array<atomic<i32>>; // edgeAtomic\\n@group(0) @binding(10) var<uniform> B: BatchParams;\\n// Fixed-point coordinate snapshot: the committed state after the previous\\n// sub-batch. edgeAtomic reads ONLY from here and atomically accumulates into\\n// embeddingFx, so every thread sees identical inputs regardless of scheduling\\n// and i32 adds commute exactly — the layout is bit-deterministic per seed.\\n@group(0) @binding(11) var<storage, read> snapFx: array<i32>;\\n\\nconst CLIP: f32 = 4.0;\\n\\nfn tau_step(s: ptr<function, vec3<u32>>) -> i32 {\\n var s0 = (*s).x;\\n var s1 = (*s).y;\\n var s2 = (*s).z;\\n s0 = ((s0 & 0xfffffffeu) << 12u) ^ (((s0 << 13u) ^ s0) >> 19u);\\n s1 = ((s1 & 0xfffffff8u) << 4u) ^ (((s1 << 2u) ^ s1) >> 25u);\\n s2 = ((s2 & 0xfffffff0u) << 17u) ^ (((s2 << 3u) ^ s2) >> 11u);\\n (*s) = vec3<u32>(s0, s1, s2);\\n return i32(s0 ^ s1 ^ s2);\\n}\\n\\nfn clipv(v: f32) -> f32 {\\n return clamp(v, -CLIP, CLIP);\\n}\\n\\n// ---------------------------------------------------------------------------\\n// (A) vertexGather: thread = head vertex; edges rowPtr[v]..rowPtr[v+1]\\n// ---------------------------------------------------------------------------\\n\\n@compute @workgroup_size(256)\\nfn vertexGather(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let v = gid.x;\\n if (v >= P.nVertices) { return; }\\n let dim = P.dim;\\n let n = f32(P.epoch);\\n var rng = vec3<u32>(rngStates[v * 3u], rngStates[v * 3u + 1u], rngStates[v * 3u + 2u]);\\n\\n for (var e = rowPtr[v]; e < rowPtr[v + 1u]; e = e + 1u) {\\n if (schedule[e] > n) { continue; }\\n let j = u32(head[e]);\\n let kv = u32(tail[e]);\\n var d2 = 0.0;\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = embedding[j * dim + c] - embedding[kv * dim + c];\\n d2 = d2 + diff * diff;\\n }\\n var gradCoeff = 0.0;\\n if (d2 > 0.0) {\\n gradCoeff = (-2.0 * P.a * P.b * pow(d2, P.b - 1.0)) / (P.a * pow(d2, P.b) + 1.0);\\n }\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = embedding[j * dim + c] - embedding[kv * dim + c];\\n let g = clipv(gradCoeff * diff);\\n // ownership: each endpoint gets one pull per undirected edge (the reverse\\n // directed edge pulls the other endpoint)\\n embedding[j * dim + c] = embedding[j * dim + c] + g * P.alpha;\\n }\\n schedule[e] = schedule[e] + epochsPerSample[e];\\n\\n let epn = epochsPerSample[e] / P.negativeSampleRate;\\n let nNeg = i32((n - schedule[P.nEdges + e]) / epn);\\n for (var p = 0; p < nNeg; p = p + 1) {\\n let r = tau_step(&rng);\\n var kk = r % i32(P.nVertices);\\n if (kk < 0) { kk = kk + i32(P.nVertices); }\\n if (u32(kk) == j) { continue; }\\n var dn = 0.0;\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = embedding[j * dim + c] - embedding[u32(kk) * dim + c];\\n dn = dn + diff * diff;\\n }\\n if (dn > 0.0) {\\n let rep = (2.0 * P.gamma * P.b) / ((0.001 + dn) * (P.a * pow(dn, P.b) + 1.0));\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = embedding[j * dim + c] - embedding[u32(kk) * dim + c];\\n embedding[j * dim + c] = embedding[j * dim + c] + clipv(rep * diff) * P.alpha;\\n }\\n }\\n }\\n schedule[P.nEdges + e] = schedule[P.nEdges + e] + f32(nNeg) * epn;\\n }\\n rngStates[v * 3u] = rng.x;\\n rngStates[v * 3u + 1u] = rng.y;\\n rngStates[v * 3u + 2u] = rng.z;\\n}\\n\\n// ---------------------------------------------------------------------------\\n// (B) edgeAtomic: thread = directed edge; fixed-point atomics\\n// ---------------------------------------------------------------------------\\n\\n@compute @workgroup_size(256)\\nfn packFx(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let i = gid.x;\\n if (i >= P.nVertices * P.dim) { return; }\\n atomicStore(&embeddingFx[i], i32(round(embedding[i] * P.scale)));\\n}\\n\\n@compute @workgroup_size(256)\\nfn unpackFx(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let i = gid.x;\\n if (i >= P.nVertices * P.dim) { return; }\\n embedding[i] = f32(atomicLoad(&embeddingFx[i])) / P.scale;\\n}\\n\\n@compute @workgroup_size(256)\\nfn edgeAtomic(@builtin(global_invocation_id) gid: vec3<u32>) {\\n if (gid.x >= B.edgeCount) { return; }\\n let e = B.edgeOffset + gid.x;\\n if (e >= P.nEdges) { return; }\\n if (schedule[e] > f32(P.epoch)) { return; }\\n let dim = P.dim;\\n let j = u32(head[e]);\\n let kv = u32(tail[e]);\\n var rng = vec3<u32>(rngStates[e * 3u], rngStates[e * 3u + 1u], rngStates[e * 3u + 2u]);\\n\\n // Thread-local running coordinates for j (the CPU kernel's within-edge\\n // update chain); every cross-vertex read comes from the sub-batch snapshot.\\n var cj: array<f32, 8>;\\n var net: array<f32, 8>;\\n for (var c = 0u; c < dim; c = c + 1u) {\\n cj[c] = f32(snapFx[j * dim + c]) / P.scale;\\n net[c] = 0.0;\\n }\\n\\n var d2 = 0.0;\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = cj[c] - f32(snapFx[kv * dim + c]) / P.scale;\\n d2 = d2 + diff * diff;\\n }\\n if (d2 > 0.0) {\\n let gradCoeff = (-2.0 * P.a * P.b * pow(d2, P.b - 1.0)) / (P.a * pow(d2, P.b) + 1.0);\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = cj[c] - f32(snapFx[kv * dim + c]) / P.scale;\\n let g = clipv(gradCoeff * diff) * P.alpha;\\n cj[c] = cj[c] + g;\\n net[c] = net[c] + g;\\n if (P.moveOther == 1u) {\\n atomicAdd(&embeddingFx[kv * dim + c], i32(round(-g * P.scale)));\\n }\\n }\\n }\\n schedule[e] = schedule[e] + epochsPerSample[e];\\n\\n let epn = epochsPerSample[e] / P.negativeSampleRate;\\n let nNeg = i32((f32(P.epoch) - schedule[P.nEdges + e]) / epn);\\n for (var p = 0; p < nNeg; p = p + 1) {\\n let r = tau_step(&rng);\\n var kk = r % i32(P.nVertices);\\n if (kk < 0) { kk = kk + i32(P.nVertices); }\\n if (u32(kk) == j) { continue; }\\n var dn = 0.0;\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = cj[c] - f32(snapFx[u32(kk) * dim + c]) / P.scale;\\n dn = dn + diff * diff;\\n }\\n if (dn > 0.0) {\\n let rep = (2.0 * P.gamma * P.b) / ((0.001 + dn) * (P.a * pow(dn, P.b) + 1.0));\\n for (var c = 0u; c < dim; c = c + 1u) {\\n let diff = cj[c] - f32(snapFx[u32(kk) * dim + c]) / P.scale;\\n let g = clipv(rep * diff) * P.alpha;\\n cj[c] = cj[c] + g;\\n net[c] = net[c] + g;\\n }\\n }\\n }\\n schedule[P.nEdges + e] = schedule[P.nEdges + e] + f32(nNeg) * epn;\\n // one rounded net update per component — less quantization than per-step adds\\n for (var c = 0u; c < dim; c = c + 1u) {\\n atomicAdd(&embeddingFx[j * dim + c], i32(round(net[c] * P.scale)));\\n }\\n rngStates[e * 3u] = rng.x;\\n rngStates[e * 3u + 1u] = rng.y;\\n rngStates[e * 3u + 2u] = rng.z;\\n}\\n\"","/**\n * GPU SGD layout driver (§A2). Two strategies (DECISIONS D-011):\n * 'vertexGather' (conflict-free by ownership) and 'edgeAtomic' (fixed-point\n * atomicAdd, scale 2^20). edgeAtomic epochs run as ordered sub-batches that\n * read a coordinate snapshot and atomically accumulate — bit-deterministic\n * per seed (D-013); alpha via uniform.\n */\n\nimport type { Pcg32 } from '../../rng.js';\nimport { throwIfAborted, UmapBackendError } from '../../types.js';\nimport {\n assertUsable,\n beginErrorScopes,\n createBuffer,\n ensureBufferFits,\n type GpuContext,\n readBuffer,\n} from './device.js';\nimport sgdWgsl from './kernels/sgd.wgsl';\n\nexport type GpuLayoutStrategy = 'vertexGather' | 'edgeAtomic';\n\ninterface SgdPipelines {\n vertexGather: GPUComputePipeline;\n edgeAtomic: GPUComputePipeline;\n packFx: GPUComputePipeline;\n unpackFx: GPUComputePipeline;\n}\n\nconst cache = new WeakMap<GPUDevice, SgdPipelines>();\n\ninterface SgdPipelineSet extends SgdPipelines {\n bindLayout: GPUBindGroupLayout;\n bindLayoutEdge: GPUBindGroupLayout;\n}\n\nfunction pipelines(device: GPUDevice): SgdPipelineSet {\n let p = cache.get(device) as SgdPipelineSet | undefined;\n if (!p) {\n const module = device.createShaderModule({ code: sgdWgsl });\n const storage = (binding: number, type: GPUBufferBindingType): GPUBindGroupLayoutEntry => ({\n binding,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type },\n });\n // shared by vertexGather/packFx/unpackFx (single bind group works for all)\n const bindLayout = device.createBindGroupLayout({\n entries: [\n storage(0, 'storage'),\n storage(1, 'read-only-storage'),\n storage(2, 'read-only-storage'),\n storage(3, 'read-only-storage'),\n storage(4, 'storage'),\n storage(6, 'storage'),\n storage(7, 'uniform'),\n storage(8, 'read-only-storage'),\n storage(9, 'storage'),\n ],\n });\n // edgeAtomic needs the batch uniform + coordinate snapshot; dropping the\n // f32 embedding and rowPtr keeps it at 7 storage buffers (default limit 8)\n const bindLayoutEdge = device.createBindGroupLayout({\n entries: [\n storage(1, 'read-only-storage'),\n storage(2, 'read-only-storage'),\n storage(3, 'read-only-storage'),\n storage(4, 'storage'),\n storage(6, 'storage'),\n storage(7, 'uniform'),\n storage(9, 'storage'),\n storage(10, 'uniform'),\n storage(11, 'read-only-storage'),\n ],\n });\n const layout = device.createPipelineLayout({ bindGroupLayouts: [bindLayout] });\n const layoutEdge = device.createPipelineLayout({ bindGroupLayouts: [bindLayoutEdge] });\n const mk = (entryPoint: string, pl: GPUPipelineLayout = layout) =>\n device.createComputePipeline({ layout: pl, compute: { module, entryPoint } });\n p = {\n vertexGather: mk('vertexGather'),\n edgeAtomic: mk('edgeAtomic', layoutEdge),\n packFx: mk('packFx'),\n unpackFx: mk('unpackFx'),\n bindLayout,\n bindLayoutEdge,\n };\n cache.set(device, p);\n }\n return p;\n}\n\nexport interface GpuLayoutOptions {\n gamma: number;\n initialAlpha: number;\n negativeSampleRate: number;\n moveOther: boolean;\n strategy?: GpuLayoutStrategy;\n onEpoch?: (info: {\n epoch: number;\n nEpochs: number;\n phase: string;\n embedding?: Float32Array;\n }) => void;\n snapshotEvery?: number;\n signal?: AbortSignal;\n}\n\nconst UNIFORM_SIZE = 48;\n\nexport async function gpuOptimizeLayout(\n ctx: GpuContext,\n embedding: Float32Array, // mutated with the final result\n dim: number,\n head: Int32Array,\n tail: Int32Array,\n nEpochs: number,\n nVertices: number,\n epochsPerSample: Float64Array,\n a: number,\n b: number,\n rng: Pcg32,\n opts: GpuLayoutOptions,\n): Promise<Float32Array> {\n const device = ctx.device;\n const strategy = opts.strategy ?? 'edgeAtomic'; // D-011: measured winner\n const nEdges = head.length;\n if (strategy === 'edgeAtomic' && dim > 8) {\n throw new UmapBackendError(`webgpu layout supports dim <= 8 (got ${dim})`);\n }\n const pipes = pipelines(device);\n\n // validate planned allocations against the granted limits up front (§A12)\n assertUsable(ctx, 'gpuOptimizeLayout');\n const fxSizePlanned = strategy === 'edgeAtomic' ? nVertices * dim * 4 : 4;\n ensureBufferFits(ctx, 'gpuOptimizeLayout', 'embedding', embedding.byteLength);\n ensureBufferFits(ctx, 'gpuOptimizeLayout', 'edges', nEdges * 4);\n ensureBufferFits(ctx, 'gpuOptimizeLayout', 'schedule', nEdges * 2 * 4);\n ensureBufferFits(\n ctx,\n 'gpuOptimizeLayout',\n 'rngStates',\n (strategy === 'vertexGather' ? nVertices : nEdges) * 3 * 4,\n );\n ensureBufferFits(ctx, 'gpuOptimizeLayout', 'fixedPoint', fxSizePlanned);\n\n const epsF32 = Float32Array.from(epochsPerSample);\n const scheduleInit = new Float32Array(nEdges * 2);\n scheduleInit.set(epsF32, 0);\n for (let i = 0; i < nEdges; i++) {\n scheduleInit[nEdges + i] = epsF32[i]! / opts.negativeSampleRate;\n }\n\n // every buffer is tracked and destroyed in the finally below (abort-safe)\n const scratch = new Set<GPUBuffer>();\n const track = (buf: GPUBuffer): GPUBuffer => {\n scratch.add(buf);\n return buf;\n };\n const endScopes = beginErrorScopes(device);\n try {\n const embBuf = track(\n createBuffer(\n device,\n embedding,\n GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,\n ),\n );\n const headBuf = track(\n createBuffer(device, head, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST),\n );\n const tailBuf = track(\n createBuffer(device, tail, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST),\n );\n const epsBuf = track(\n createBuffer(device, epsF32, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST),\n );\n const scheduleBuf = track(\n createBuffer(device, scheduleInit, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST),\n );\n\n // rng streams: per vertex (gather) or per edge (atomic)\n const nStreams = strategy === 'vertexGather' ? nVertices : nEdges;\n const states = new Uint32Array(nStreams * 3);\n for (let i = 0; i < states.length; i++) states[i] = rng.nextU32();\n const rngBuf = track(\n createBuffer(device, states, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST),\n );\n\n // vertexGather CSR rowPtr over head-sorted edges\n const rowPtr = new Uint32Array(nVertices + 1);\n for (let e = 0; e < nEdges; e++) rowPtr[head[e]! + 1]!++;\n for (let v = 0; v < nVertices; v++) rowPtr[v + 1]! += rowPtr[v]!;\n const rowPtrBuf = track(\n createBuffer(device, rowPtr, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST),\n );\n\n const scale = 1048576.0; // 2^20 fixed-point: |coord| < 2048, resolution ~1e-6 (D-011)\n const fxSize = fxSizePlanned;\n const fxBuf = track(\n device.createBuffer({\n size: fxSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n }),\n );\n // committed-state snapshot read by each edgeAtomic sub-batch (D-013)\n const snapBuf = track(\n device.createBuffer({\n size: fxSize,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n }),\n );\n\n const uni = track(\n device.createBuffer({\n size: UNIFORM_SIZE,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n }),\n );\n const writeUniform = (epoch: number, alpha: number) => {\n const buf = new ArrayBuffer(UNIFORM_SIZE);\n const u = new Uint32Array(buf);\n const f = new Float32Array(buf);\n u[0] = nVertices;\n u[1] = nEdges;\n u[2] = dim;\n u[3] = epoch;\n f[4] = alpha;\n f[5] = a;\n f[6] = b;\n f[7] = opts.gamma;\n f[8] = opts.negativeSampleRate;\n u[9] = opts.moveOther ? 1 : 0;\n f[10] = scale;\n device.queue.writeBuffer(uni, 0, buf);\n };\n\n // Sequential sub-batches per epoch (edgeAtomic): edges of batch s only start\n // after batch s-1's atomics are committed, approximating the CPU's in-order\n // edge visibility. Slot stride obeys minUniformBufferOffsetAlignment.\n const SUBBATCHES = strategy === 'edgeAtomic' ? Math.min(32, Math.max(1, nEdges)) : 1;\n const chunk = Math.ceil(nEdges / SUBBATCHES);\n const slotStride = Math.max(256, device.limits.minUniformBufferOffsetAlignment);\n const batchUni = track(\n device.createBuffer({\n size: slotStride * SUBBATCHES,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n }),\n );\n for (let s = 0; s < SUBBATCHES; s++) {\n const off = s * chunk;\n const cnt = Math.max(0, Math.min(chunk, nEdges - off));\n device.queue.writeBuffer(batchUni, s * slotStride, new Uint32Array([off, cnt]));\n }\n\n const bindGroup = device.createBindGroup({\n layout: pipes.bindLayout,\n entries: [\n { binding: 0, resource: { buffer: embBuf } },\n { binding: 1, resource: { buffer: headBuf } },\n { binding: 2, resource: { buffer: tailBuf } },\n { binding: 3, resource: { buffer: epsBuf } },\n { binding: 4, resource: { buffer: scheduleBuf } },\n { binding: 6, resource: { buffer: rngBuf } },\n { binding: 7, resource: { buffer: uni } },\n { binding: 8, resource: { buffer: rowPtrBuf } },\n { binding: 9, resource: { buffer: fxBuf } },\n ],\n });\n const edgeBindGroups: GPUBindGroup[] = [];\n for (let s = 0; s < SUBBATCHES; s++) {\n edgeBindGroups.push(\n device.createBindGroup({\n layout: pipes.bindLayoutEdge,\n entries: [\n { binding: 1, resource: { buffer: headBuf } },\n { binding: 2, resource: { buffer: tailBuf } },\n { binding: 3, resource: { buffer: epsBuf } },\n { binding: 4, resource: { buffer: scheduleBuf } },\n { binding: 6, resource: { buffer: rngBuf } },\n { binding: 7, resource: { buffer: uni } },\n { binding: 9, resource: { buffer: fxBuf } },\n { binding: 10, resource: { buffer: batchUni, offset: s * slotStride, size: 8 } },\n { binding: 11, resource: { buffer: snapBuf } },\n ],\n }),\n );\n }\n\n const run = (pipeline: GPUComputePipeline, bg: GPUBindGroup, threads: number) => {\n const enc = device.createCommandEncoder();\n const pass = enc.beginComputePass();\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, bg);\n pass.dispatchWorkgroups(Math.ceil(threads / 256));\n pass.end();\n device.queue.submit([enc.finish()]);\n };\n\n if (strategy === 'edgeAtomic') {\n writeUniform(0, opts.initialAlpha);\n const enc = device.createCommandEncoder();\n const pass = enc.beginComputePass();\n pass.setPipeline(pipes.packFx);\n pass.setBindGroup(0, bindGroup);\n pass.dispatchWorkgroups(Math.ceil((nVertices * dim) / 256));\n pass.end();\n enc.copyBufferToBuffer(fxBuf, 0, snapBuf, 0, fxSize);\n device.queue.submit([enc.finish()]);\n }\n\n let alpha = opts.initialAlpha;\n const SYNC_EVERY = 24; // bound queued work; keeps the device responsive\n for (let epoch = 0; epoch < nEpochs; epoch++) {\n throwIfAborted(opts.signal);\n assertUsable(ctx, 'gpuOptimizeLayout');\n writeUniform(epoch, alpha);\n if (strategy === 'vertexGather') {\n run(pipes.vertexGather, bindGroup, nVertices);\n } else {\n // one submit, SUBBATCHES ordered passes; after each pass the committed\n // coordinates are copied into the snapshot the next pass reads (D-013)\n const enc = device.createCommandEncoder();\n for (let s = 0; s < SUBBATCHES; s++) {\n const off = s * chunk;\n const cnt = Math.min(chunk, nEdges - off);\n if (cnt <= 0) break;\n const pass = enc.beginComputePass();\n pass.setPipeline(pipes.edgeAtomic);\n pass.setBindGroup(0, edgeBindGroups[s]!);\n pass.dispatchWorkgroups(Math.ceil(cnt / 256));\n pass.end();\n enc.copyBufferToBuffer(fxBuf, 0, snapBuf, 0, fxSize);\n }\n device.queue.submit([enc.finish()]);\n }\n if (epoch % SYNC_EVERY === SYNC_EVERY - 1 || epoch === nEpochs - 1) {\n await device.queue.onSubmittedWorkDone();\n }\n alpha = opts.initialAlpha * (1.0 - epoch / nEpochs);\n if (opts.onEpoch) {\n const info: { epoch: number; nEpochs: number; phase: string; embedding?: Float32Array } = {\n epoch,\n nEpochs,\n phase: 'layout',\n };\n if (opts.snapshotEvery && (epoch % opts.snapshotEvery === 0 || epoch === nEpochs - 1)) {\n if (strategy === 'edgeAtomic') run(pipes.unpackFx, bindGroup, nVertices * dim);\n const snap = new Float32Array(await readBuffer(device, embBuf, embedding.length * 4));\n info.embedding = snap;\n }\n opts.onEpoch(info);\n }\n }\n if (strategy === 'edgeAtomic') {\n writeUniform(nEpochs, alpha);\n run(pipes.unpackFx, bindGroup, nVertices * dim);\n }\n await device.queue.onSubmittedWorkDone();\n await endScopes('gpuOptimizeLayout');\n assertUsable(ctx, 'gpuOptimizeLayout');\n const out = new Float32Array(await readBuffer(device, embBuf, embedding.length * 4));\n embedding.set(out);\n return embedding;\n } finally {\n // balance the scope stack even when the body threw first\n await endScopes('gpuOptimizeLayout').catch(() => {});\n for (const b of scratch) b.destroy();\n }\n}\n","\"// Blocked normalized-Laplacian SpMV for the spectral init (D-014):\\n// Y[c*n+i] = X[c*n+i] − dinvsqrt[i] · Σ_p scaled[p]·X[c*n+indices[p]]\\n// One thread per row; each thread walks its CSR row once and accumulates all\\n// block columns. Reduction order per (row, column) is fixed → deterministic.\\n\\nstruct SpmvParams {\\n n: u32,\\n cols: u32,\\n}\\n\\n@group(0) @binding(0) var<storage, read> indptr: array<u32>;\\n@group(0) @binding(1) var<storage, read> indices: array<u32>;\\n@group(0) @binding(2) var<storage, read> scaled: array<f32>;\\n@group(0) @binding(3) var<storage, read> dinv: array<f32>;\\n@group(0) @binding(4) var<storage, read> X: array<f32>;\\n@group(0) @binding(5) var<storage, read_write> Y: array<f32>;\\n@group(0) @binding(6) var<uniform> P: SpmvParams;\\n\\n@compute @workgroup_size(256)\\nfn spmv(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let i = gid.x;\\n if (i >= P.n) { return; }\\n let n = P.n;\\n let start = indptr[i];\\n let end = indptr[i + 1u];\\n var acc: array<f32, 18>; // up to 3·(dim+1) block columns, dim ≤ 5 on this path\\n for (var c = 0u; c < P.cols; c = c + 1u) { acc[c] = 0.0; }\\n for (var p = start; p < end; p = p + 1u) {\\n let v = scaled[p];\\n let j = indices[p];\\n for (var c = 0u; c < P.cols; c = c + 1u) {\\n acc[c] = acc[c] + v * X[c * n + j];\\n }\\n }\\n let di = dinv[i];\\n for (var c = 0u; c < P.cols; c = c + 1u) {\\n Y[c * n + i] = X[c * n + i] - di * acc[c];\\n }\\n}\\n\"","/**\n * GPU-assisted spectral initialization for the WebGPU backend (D-014): the\n * LOBPCG driver stays on the CPU in f64, but the dominant cost — the blocked\n * normalized-Laplacian SpMV — runs on the GPU in f32 (deterministic\n * row-per-thread kernel). Single-component graphs only; callers fall back to\n * the CPU `initializeEmbedding` when this returns null. The CPU spectral path\n * is untouched — this module exists so the webgpu backend's end-to-end time\n * reflects the GPU, not a single-threaded eigensolver.\n */\n\nimport { finalInitRescale, noisyScaleCoords } from '../../init/index.js';\nimport { connectedComponents, degreeInvSqrt, lobpcgSmallestAsync } from '../../init/spectral.js';\nimport type { Pcg32 } from '../../rng.js';\nimport type { Csr } from '../../sparse.js';\nimport type { Logger } from '../../types.js';\nimport { silentLogger, throwIfAborted } from '../../types.js';\nimport {\n assertUsable,\n beginErrorScopes,\n createBuffer,\n ensureBufferFits,\n type GpuContext,\n readBuffer,\n} from './device.js';\nimport spmvWgsl from './kernels/spmv.wgsl';\n\ninterface SpmvPipeline {\n pipeline: GPUComputePipeline;\n bindLayout: GPUBindGroupLayout;\n}\n\nconst cache = new WeakMap<GPUDevice, SpmvPipeline>();\n\nfunction spmvPipeline(device: GPUDevice): SpmvPipeline {\n let p = cache.get(device);\n if (!p) {\n const module = device.createShaderModule({ code: spmvWgsl });\n const entry = (binding: number, type: GPUBufferBindingType): GPUBindGroupLayoutEntry => ({\n binding,\n visibility: GPUShaderStage.COMPUTE,\n buffer: { type },\n });\n const bindLayout = device.createBindGroupLayout({\n entries: [\n entry(0, 'read-only-storage'),\n entry(1, 'read-only-storage'),\n entry(2, 'read-only-storage'),\n entry(3, 'read-only-storage'),\n entry(4, 'read-only-storage'),\n entry(5, 'storage'),\n entry(6, 'uniform'),\n ],\n });\n const layout = device.createPipelineLayout({ bindGroupLayouts: [bindLayout] });\n p = {\n pipeline: device.createComputePipeline({\n layout,\n compute: { module, entryPoint: 'spmv' },\n }),\n bindLayout,\n };\n cache.set(device, p);\n }\n return p;\n}\n\nexport interface GpuInitResult {\n embedding: Float32Array; // n × dim, after the final [0,10] rescale\n spectralFallback: boolean;\n}\n\n/**\n * Spectral init with GPU SpMV. Returns null for multi-component graphs (the\n * caller must then run the CPU init path; no rng draws are consumed here in\n * that case) and for dim > 5 (kernel block bound).\n */\nexport async function gpuSpectralInit(\n ctx: GpuContext,\n graph: Csr,\n dim: number,\n rng: Pcg32,\n logger: Logger = silentLogger,\n signal?: AbortSignal,\n): Promise<GpuInitResult | null> {\n if (dim > 5) return null;\n const { count } = connectedComponents(graph);\n if (count > 1) return null;\n\n const device = ctx.device;\n const n = graph.rows;\n const m = dim + 1;\n const maxCols = 3 * m;\n\n // validate planned allocations against the granted limits up front (§A12)\n assertUsable(ctx, 'gpuSpectralInit');\n ensureBufferFits(ctx, 'gpuSpectralInit', 'graph', graph.data.length * 4);\n ensureBufferFits(ctx, 'gpuSpectralInit', 'block', n * maxCols * 4);\n\n const { deg, dinvsqrt } = degreeInvSqrt(graph);\n\n // X0 exactly as the CPU single-component path builds it\n const X0 = new Float64Array(n * m);\n for (let c = 0; c < m; c++) {\n for (let r = 0; r < n; r++) X0[c * n + r] = rng.normal();\n }\n let norm = 0;\n for (let r = 0; r < n; r++) norm += deg[r]!;\n norm = Math.sqrt(norm);\n for (let r = 0; r < n; r++) X0[r] = Math.sqrt(deg[r]!) / norm;\n\n // pre-scaled off-diagonals A_ij·dinvsqrt[j] in f32\n const nnz = graph.data.length;\n const scaled = new Float32Array(nnz);\n for (let i = 0; i < n; i++) {\n for (let p = graph.indptr[i]!; p < graph.indptr[i + 1]!; p++) {\n scaled[p] = Math.fround(graph.data[p]! * dinvsqrt[graph.indices[p]!]!);\n }\n }\n const indptrU32 = new Uint32Array(n + 1);\n for (let i = 0; i <= n; i++) indptrU32[i] = graph.indptr[i]!;\n const indicesU32 = new Uint32Array(nnz);\n for (let p = 0; p < nnz; p++) indicesU32[p] = graph.indices[p]!;\n const dinvF32 = Float32Array.from(dinvsqrt);\n\n const { pipeline, bindLayout } = spmvPipeline(device);\n const ro = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\n // every buffer is tracked and destroyed in the finally below (abort-safe)\n const scratch = new Set<GPUBuffer>();\n const track = (buf: GPUBuffer): GPUBuffer => {\n scratch.add(buf);\n return buf;\n };\n const endScopes = beginErrorScopes(device);\n try {\n const indptrBuf = track(createBuffer(device, indptrU32, ro));\n const indicesBuf = track(createBuffer(device, indicesU32, ro));\n const scaledBuf = track(createBuffer(device, scaled, ro));\n const dinvBuf = track(createBuffer(device, dinvF32, ro));\n const xBuf = track(\n device.createBuffer({\n size: n * maxCols * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n }),\n );\n const yBuf = track(\n device.createBuffer({\n size: n * maxCols * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n }),\n );\n const uni = track(\n device.createBuffer({\n size: 8,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n }),\n );\n const bindGroup = device.createBindGroup({\n layout: bindLayout,\n entries: [\n { binding: 0, resource: { buffer: indptrBuf } },\n { binding: 1, resource: { buffer: indicesBuf } },\n { binding: 2, resource: { buffer: scaledBuf } },\n { binding: 3, resource: { buffer: dinvBuf } },\n { binding: 4, resource: { buffer: xBuf } },\n { binding: 5, resource: { buffer: yBuf } },\n { binding: 6, resource: { buffer: uni } },\n ],\n });\n\n const xStage = new Float32Array(n * maxCols);\n const applyL = async (\n S: Float64Array,\n cols: number,\n out: Float64Array,\n ): Promise<Float64Array> => {\n throwIfAborted(signal);\n assertUsable(ctx, 'gpuSpectralInit');\n const len = n * cols;\n for (let i = 0; i < len; i++) xStage[i] = Math.fround(S[i]!);\n device.queue.writeBuffer(uni, 0, new Uint32Array([n, cols]));\n device.queue.writeBuffer(xBuf, 0, xStage.buffer, 0, len * 4);\n const enc = device.createCommandEncoder();\n const pass = enc.beginComputePass();\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, bindGroup);\n pass.dispatchWorkgroups(Math.ceil(n / 256));\n pass.end();\n device.queue.submit([enc.finish()]);\n const y = new Float32Array(await readBuffer(device, yBuf, len * 4));\n for (let i = 0; i < len; i++) out[i] = y[i]!;\n return out;\n };\n\n const res = await lobpcgSmallestAsync(\n graph,\n dinvsqrt,\n X0,\n m,\n 1e-4,\n 5 * Math.min(n, 60),\n applyL,\n );\n await endScopes('gpuSpectralInit');\n if (!res.converged) {\n logger.warn(\n 'UmapConvergenceWarning: Spectral initialisation failed! The eigenvector solver failed. This is likely due to too small an eigengap. Consider adding some noise or jitter to your data. Falling back to random initialisation!',\n );\n const emb = new Float64Array(n * dim);\n for (let i = 0; i < emb.length; i++) emb[i] = rng.uniform(-10, 10);\n return { embedding: finalInitRescale(emb, n, dim), spectralFallback: true };\n }\n // drop the trivial eigenvector; columns 1..m → row-major n×dim\n const emb = new Float64Array(n * dim);\n for (let d = 0; d < dim; d++) {\n const c = d + 1;\n for (let r = 0; r < n; r++) emb[r * dim + d] = res.vectors[c * n + r]!;\n }\n noisyScaleCoords(emb, rng, 10, 0.0001);\n return { embedding: finalInitRescale(emb, n, dim), spectralFallback: false };\n } finally {\n // balance the scope stack even when the body threw first\n await endScopes('gpuSpectralInit').catch(() => {});\n for (const b of scratch) b.destroy();\n }\n}\n","/**\n * WebGPU backend entry (§5.4) — separate `umap-web/webgpu` export so browser-only\n * code stays out of the main bundle. The estimator loads this lazily when\n * backend 'webgpu' (or 'auto' with an adapter) is selected.\n */\n\nexport { acquireGpu, type DeviceProvider, type GpuContext } from './device.js';\nexport { type GpuMetricPlan, gpuKnn, gpuMetricPlan } from './knn.js';\nexport {\n type GpuLayoutOptions,\n type GpuLayoutStrategy,\n gpuOptimizeLayout,\n} from './layout.js';\nexport { type GpuInitResult, gpuSpectralInit } from './spectral.js';\n\n/** Which fit configurations the GPU backend supports end-to-end (§4.3). */\nexport function gpuSupportsConfig(opts: {\n metric?: string | ((a: Float32Array, b: Float32Array) => number);\n outputMetric?: string;\n densMap?: boolean;\n nNeighbors?: number;\n nComponents?: number;\n}): { knn: boolean; layout: boolean; reason?: string } {\n const metric = opts.metric ?? 'euclidean';\n const knnOk =\n typeof metric === 'string' &&\n [\n 'euclidean',\n 'l2',\n 'sqeuclidean',\n 'cosine',\n 'correlation',\n 'manhattan',\n 'taxicab',\n 'l1',\n 'hamming',\n 'jaccard',\n ].includes(metric) &&\n (opts.nNeighbors ?? 15) <= 32;\n const outputMetric = opts.outputMetric ?? 'euclidean';\n const layoutOk =\n (outputMetric === 'euclidean' || outputMetric === 'l2') &&\n !opts.densMap &&\n (opts.nComponents ?? 2) <= 8;\n const reason = !knnOk\n ? `metric '${String(metric)}' runs on CPU (GPU subset: euclidean, sqeuclidean, cosine, correlation, manhattan, hamming, jaccard; k<=32)`\n : !layoutOk\n ? 'non-euclidean output / densMAP / dim>8 layout runs on CPU'\n : undefined;\n return { knn: knnOk, layout: layoutOk, ...(reason ? { reason } : {}) };\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { };