fftconv1d_bhl#

fftconv1d_bhl(x, kernel, shortcut=None)#

1D non-causal (“same”) convolution via subq_ops CUDA kernels, BHL layout [B, H, L].

Drop-in replacement for nvsubquadratic.ops.fftconv.fftconv1d_fp32_bhl(): y[l] = sum_m kernel[K // 2 + l - m] * x[m] (the kernel centre K // 2 is lag zero), plus shortcut * x. Unlike the torch.fft path it runs in the input dtype end to end: the dense Toeplitz-GEMM explicit_conv1d for bf16/fp16 inputs on compute capability 10.x at its supported sequence lengths (multiples of 128 up to 2048), fft_conv1d otherwise. Both compute the same convolution.

Unlike torch_fft it caps the length (subquadratic-ops-torch 0.3.1): with K = 2L - 1 (grid_type="double"), L <= 4096 on SM8x / SM12x, L <= 8192 on SM90-SM11x and L <= 2048 in fp64; with K ~ L (grid_type="single") the caps double. The cap follows K, so a Box window does not lift it. Compiled graphs specialise on L (on 0.3.1 one graph per fft_conv1d FFT size, e.g. L 300-500 share 1024), so bucket L or use fft_backend="torch_fft" for variable-length compile.

Parameters:
  • x (Tensor) – Input tensor [B, H, L].

  • kernel (Tensor) – Kernel tensor [1, H, K] or [H, K] with K <= 2 * L; cast to x.dtype, so an fp32 kernel with bf16/fp16 x gets a gradient rounded to that dtype. Per-sample FiLM weights are not supported.

  • shortcut (Tensor | None) – Optional per-channel scale [H].

Returns:

Output tensor [B, H, L] in x.dtype.

Raises:

ValueError – If L exceeds the cap above, or kernel does not have H channels.

Return type:

Tensor