import torch
from torch.utils.cpp_extension import load_inline

source = """
#include <torch/extension.h>
#include <cuda_runtime.h>

__global__ void softplus_bias_kernel(const float* x, const float* bias, float* y, int dim, long long total) {
    long long idx = blockIdx.x * blockDim.x + threadIdx.x;
    long long stride = blockDim.x * gridDim.x;
    for (long long i = idx; i < total; i += stride) {
        int j = (int)(i % dim);
        float z = x[i] + bias[j];
        if (z > 0.0f) {
            y[i] = z + log1pf(expf(-z));
        } else {
            y[i] = log1pf(expf(z));
        }
    }
}

torch::Tensor softplus_bias_cuda(torch::Tensor x, torch::Tensor bias) {
    auto x_contig = x.contiguous();
    auto b_contig = bias.contiguous();
    auto y = torch::empty_like(x_contig);
    long long total = x_contig.numel();
    int dim = (int)x_contig.size(-1);
    int block = 512;
    long long grid = (total + block - 1) / block;
    grid = grid > 65535 ? 65535 : grid;
    softplus_bias_kernel<<<(int)grid, block>>>(x_contig.data_ptr<float>(), b_contig.data_ptr<float>(), y.data_ptr<float>(), dim, total);
    return y;
}
"""

cpp_source = """
torch::Tensor softplus_bias_cuda(torch::Tensor x, torch::Tensor bias);
"""

ops = load_inline(
    name="softplus_bias",
    cpp_sources=cpp_source,
    cuda_sources=source,
    functions=["softplus_bias_cuda"],
    verbose=True
)

class ModelNew(torch.nn.Module):
    def __init__(self, bias: torch.Tensor):
        super(ModelNew, self).__init__()
        self.ops = ops
        self.register_buffer("bias", bias)

    def forward(self, x):
        return self.ops.softplus_bias_cuda(x, self.bias)
