"""C++ ABI wrappers for the Chakra Triton causal-conv1d kernels. Upstream ``mamba_ssm`` imports these symbols from ``causal_conv1d.cpp_functions``. We provide thin wrappers that delegate to our Triton implementations so that ``selective_scan_interface`` and ``ssd_combined`` can resolve the fast path without requiring the upstream C++/CUDA extension. """ from __future__ import annotations from typing import Optional import torch from .functional import causal_conv1d_fn, causal_conv1d_update def causal_conv1d_fwd_function( x: torch.Tensor, weight: torch.Tensor, bias: Optional[torch.Tensor], seq_idx: Optional[torch.Tensor], cu_seqlens: Optional[torch.Tensor], max_seqlen: Optional[int], activation: bool = True, ) -> tuple[torch.Tensor, torch.Tensor]: """C++ ABI wrapper for ``causal_conv1d_fn``. Upstream signature: (x, weight, bias, seq_idx, cu_seqlens, max_seqlen, activation) -> (y, final_states) """ activation_str = "silu" if activation else "identity" y, final_states = causal_conv1d_fn( x, weight, bias=bias, seq_idx=seq_idx, initial_states=None, return_final_states=True, activation=activation_str, ) return y, final_states def causal_conv1d_bwd_function( x: torch.Tensor, weight: torch.Tensor, bias: Optional[torch.Tensor], seq_idx: Optional[torch.Tensor], cu_seqlens: Optional[torch.Tensor], max_seqlen: Optional[int], dy: torch.Tensor, dconv_state: Optional[torch.Tensor], dinitial_states: Optional[torch.Tensor], activation: bool = True, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """C++ ABI wrapper for the Triton backward path. Returns ``(dx, dweight, dbias, dinitial_states, None)`` to match the upstream C extension tuple layout. """ activation_str = "silu" if activation else "identity" x_in = x if dinitial_states is not None and dinitial_states.numel() > 0: x_in = torch.cat([dinitial_states.to(x.dtype), x], dim=-1).contiguous() y = torch.empty_like(x_in) b, d, l_full = x_in.shape width = weight.shape[-1] from .triton_kernels import causal_conv1d_fwd_kernel BLOCK_L = 256 BLOCK_D = 64 apply_silu = activation in ("silu", True) apply_relu = activation == "relu" grid = (b, __import__("triton").cdiv(l_full, BLOCK_L), __import__("triton").cdiv(d, BLOCK_D)) causal_conv1d_fwd_kernel[grid]( x_in, weight, bias if bias is not None else torch.zeros(d, device=x.device, dtype=x.dtype), y, b, l_full, d, width, x_in.stride(0), x_in.stride(1), x_in.stride(2), weight.stride(0), weight.stride(1), y.stride(0), y.stride(1), y.stride(2), apply_silu, apply_relu, BLOCK_L, BLOCK_D, ) pre_act = y if (apply_silu or apply_relu) else None if apply_silu: sig = torch.sigmoid(pre_act) d_pre = dy * sig * (1.0 + pre_act * (1.0 - sig)) elif apply_relu: d_pre = dy * (pre_act > 0).to(dy.dtype) else: d_pre = dy from .triton_kernels import causal_conv1d_bwd_dx_kernel, causal_conv1d_bwd_dw_kernel, causal_conv1d_bwd_db_kernel dx = torch.empty_like(x_in) grid_dx = (b, __import__("triton").cdiv(l_full, BLOCK_L), __import__("triton").cdiv(d, BLOCK_D)) causal_conv1d_bwd_dx_kernel[grid_dx]( d_pre, weight, dx, b, l_full, d, width, d_pre.stride(0), d_pre.stride(1), d_pre.stride(2), weight.stride(0), weight.stride(1), dx.stride(0), dx.stride(1), dx.stride(2), BLOCK_L, BLOCK_D, ) dw = torch.zeros(d, width, dtype=x.dtype, device=x.device) grid_dw = (__import__("triton").cdiv(d, BLOCK_D), width) causal_conv1d_bwd_dw_kernel[grid_dw]( d_pre, x_in, dw, b, l_full, d, width, d_pre.stride(0), d_pre.stride(1), d_pre.stride(2), x_in.stride(0), x_in.stride(1), x_in.stride(2), dw.stride(0), dw.stride(1), BLOCK_D, ) db = torch.zeros(d, dtype=x.dtype, device=x.device) grid_db = (__import__("triton").cdiv(d, BLOCK_D),) causal_conv1d_bwd_db_kernel[grid_db]( d_pre, db, b, l_full, d, d_pre.stride(0), d_pre.stride(1), d_pre.stride(2), db.stride(0), BLOCK_D, ) orig_len = l_full - (x_in.shape[-1] - x.shape[-1]) dx = dx[..., -orig_len:] if orig_len is not None and orig_len < dx.shape[-1] else dx dinitial_states_out = torch.zeros(0) return dx, dw, db, dinitial_states_out, None def causal_conv1d_update_function( x: torch.Tensor, conv_state: torch.Tensor, weight: torch.Tensor, bias: Optional[torch.Tensor], activation: bool = True, ) -> torch.Tensor: """C++ ABI wrapper for ``causal_conv1d_update``.""" activation_str = "silu" if activation else "identity" return causal_conv1d_update( x, conv_state, weight, bias if bias is not None else torch.zeros(x.shape[1], device=x.device, dtype=x.dtype), activation=activation_str, )