/** * GPU Compute - Compute shader infrastructure for WebGPU * * Provides GPU-accelerated data analysis capabilities. */ export declare const STATS_COMPUTE_WGSL = "\nstruct StatsResult {\n min_val: f32,\n max_val: f32,\n sum: f32,\n sum_sq: f32,\n count: u32,\n padding: vec3,\n}\n\n@group(0) @binding(0) var input_data: array;\n@group(0) @binding(1) var result: StatsResult;\n\nvar local_min: array;\nvar local_max: array;\nvar local_sum: array;\nvar local_sum_sq: array;\nvar local_count: array;\n\n@compute @workgroup_size(256)\nfn main(\n @builtin(global_invocation_id) global_id: vec3,\n @builtin(local_invocation_id) local_id: vec3,\n @builtin(workgroup_id) workgroup_id: vec3\n) {\n let idx = global_id.x;\n let lid = local_id.x;\n let data_len = arrayLength(&input_data);\n \n // Initialize local values\n if (idx < data_len) {\n let val = input_data[idx];\n local_min[lid] = val;\n local_max[lid] = val;\n local_sum[lid] = val;\n local_sum_sq[lid] = val * val;\n local_count[lid] = 1u;\n } else {\n local_min[lid] = 3.402823e+38; // f32 max\n local_max[lid] = -3.402823e+38; // f32 min\n local_sum[lid] = 0.0;\n local_sum_sq[lid] = 0.0;\n local_count[lid] = 0u;\n }\n \n workgroupBarrier();\n \n // Parallel reduction\n for (var stride: u32 = 128u; stride > 0u; stride = stride >> 1u) {\n if (lid < stride) {\n local_min[lid] = min(local_min[lid], local_min[lid + stride]);\n local_max[lid] = max(local_max[lid], local_max[lid + stride]);\n local_sum[lid] = local_sum[lid] + local_sum[lid + stride];\n local_sum_sq[lid] = local_sum_sq[lid] + local_sum_sq[lid + stride];\n local_count[lid] = local_count[lid] + local_count[lid + stride];\n }\n workgroupBarrier();\n }\n \n // First thread writes result (atomic for multi-workgroup)\n if (lid == 0u) {\n // Use atomics for multi-workgroup reduction\n // For now, we assume single workgroup or post-process on CPU\n result.min_val = local_min[0];\n result.max_val = local_max[0];\n result.sum = local_sum[0];\n result.sum_sq = local_sum_sq[0];\n result.count = local_count[0];\n }\n}\n"; export declare const MINMAX_COMPUTE_WGSL = "\nstruct MinMax {\n min_x: f32,\n max_x: f32,\n min_y: f32,\n max_y: f32,\n}\n\n@group(0) @binding(0) var points: array>;\n@group(0) @binding(1) var result: MinMax;\n\nvar local_min_x: array;\nvar local_max_x: array;\nvar local_min_y: array;\nvar local_max_y: array;\n\n@compute @workgroup_size(256)\nfn main(\n @builtin(global_invocation_id) global_id: vec3,\n @builtin(local_invocation_id) local_id: vec3\n) {\n let idx = global_id.x;\n let lid = local_id.x;\n let data_len = arrayLength(&points);\n \n if (idx < data_len) {\n let pt = points[idx];\n local_min_x[lid] = pt.x;\n local_max_x[lid] = pt.x;\n local_min_y[lid] = pt.y;\n local_max_y[lid] = pt.y;\n } else {\n local_min_x[lid] = 3.402823e+38;\n local_max_x[lid] = -3.402823e+38;\n local_min_y[lid] = 3.402823e+38;\n local_max_y[lid] = -3.402823e+38;\n }\n \n workgroupBarrier();\n \n for (var stride: u32 = 128u; stride > 0u; stride = stride >> 1u) {\n if (lid < stride) {\n local_min_x[lid] = min(local_min_x[lid], local_min_x[lid + stride]);\n local_max_x[lid] = max(local_max_x[lid], local_max_x[lid + stride]);\n local_min_y[lid] = min(local_min_y[lid], local_min_y[lid + stride]);\n local_max_y[lid] = max(local_max_y[lid], local_max_y[lid + stride]);\n }\n workgroupBarrier();\n }\n \n if (lid == 0u) {\n result.min_x = local_min_x[0];\n result.max_x = local_max_x[0];\n result.min_y = local_min_y[0];\n result.max_y = local_max_y[0];\n }\n}\n"; export declare const DOWNSAMPLE_COMPUTE_WGSL = "\nstruct Params {\n input_count: u32,\n output_count: u32,\n bucket_size: u32,\n padding: u32,\n}\n\n@group(0) @binding(0) var params: Params;\n@group(0) @binding(1) var input_points: array>;\n@group(0) @binding(2) var output_points: array>;\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) global_id: vec3) {\n let bucket_idx = global_id.x;\n \n if (bucket_idx >= params.output_count / 2u) {\n return;\n }\n \n let start = bucket_idx * params.bucket_size;\n let end = min(start + params.bucket_size, params.input_count);\n \n if (start >= params.input_count) {\n return;\n }\n \n var min_y = input_points[start].y;\n var max_y = input_points[start].y;\n var min_idx = start;\n var max_idx = start;\n \n for (var i = start; i < end; i = i + 1u) {\n let y = input_points[i].y;\n if (y < min_y) {\n min_y = y;\n min_idx = i;\n }\n if (y > max_y) {\n max_y = y;\n max_idx = i;\n }\n }\n \n // Output min and max points (preserving x,y pairs)\n let out_base = bucket_idx * 2u;\n \n // Ensure min comes before max in x order\n if (min_idx <= max_idx) {\n output_points[out_base] = input_points[min_idx];\n output_points[out_base + 1u] = input_points[max_idx];\n } else {\n output_points[out_base] = input_points[max_idx];\n output_points[out_base + 1u] = input_points[min_idx];\n }\n}\n"; export declare const PEAK_DETECT_COMPUTE_WGSL = "\nstruct Params {\n data_count: u32,\n threshold: f32,\n min_distance: u32,\n padding: u32,\n}\n\nstruct Peak {\n index: u32,\n value: f32,\n is_peak: u32,\n padding: u32,\n}\n\n@group(0) @binding(0) var params: Params;\n@group(0) @binding(1) var data: array;\n@group(0) @binding(2) var peaks: array;\n\n@compute @workgroup_size(64)\nfn main(@builtin(global_invocation_id) global_id: vec3) {\n let idx = global_id.x;\n \n if (idx >= params.data_count) {\n return;\n }\n \n peaks[idx].index = idx;\n peaks[idx].value = data[idx];\n peaks[idx].is_peak = 0u;\n \n // Skip edges\n if (idx < params.min_distance || idx >= params.data_count - params.min_distance) {\n return;\n }\n \n let val = data[idx];\n \n // Check if above threshold\n if (val < params.threshold) {\n return;\n }\n \n // Check if local maximum\n var is_max = true;\n for (var i = 1u; i <= params.min_distance; i = i + 1u) {\n if (data[idx - i] >= val || data[idx + i] >= val) {\n is_max = false;\n break;\n }\n }\n \n if (is_max) {\n peaks[idx].is_peak = 1u;\n }\n}\n";