# Buggy code
def _generate_nd_kernel(
    name,
    pre,
    found,
    post,
    mode,
    w_shape,
    int_type,
    offsets,
    cval,
    ctype="X",
    preamble="",
    options=(),
    has_weights=True,
    has_structure=False,
    has_mask=False,
    binary_morphology=False,
    all_weights_nonzero=False,
):
    # Currently this code uses CArray for weights but avoids using CArray for
    # the input data and instead does the indexing itself since it is faster.
    # If CArray becomes faster than follow the comments that start with
    # CArray: to switch over to using CArray for the input data as well.

    ndim = len(w_shape)
    in_params = "raw X x"
    if has_weights:
        in_params += ", raw W w"
    if has_structure:
        in_params += ", raw S s"
    if has_mask:
        in_params += ", raw M mask"
    out_params = "Y y"

    # CArray: remove xstride_{j}=... from string
    size = (
        "%s xsize_{j}=x.shape()[{j}], ysize_{j} = _raw_y.shape()[{j}]"
        ", xstride_{j}=x.strides()[{j}];" % int_type
    )
    sizes = [size.format(j=j) for j in range(ndim)]
    inds = _util._generate_indices_ops(ndim, int_type, offsets)
    # CArray: remove expr entirely
    expr = " + ".join(["ix_{}".format(j) for j in range(ndim)])

    ws_init = ws_pre = ws_post = ""
    if has_weights or has_structure:
        ws_init = "int iws = 0;"
        if has_structure:
            ws_pre = "S sval = s[iws];\n"
        if has_weights:
            ws_pre += "W wval = w[iws];\n"
            if not all_weights_nonzero:
                ws_pre += "if (nonzero(wval))"
        ws_post = "iws++;"

    loops = []
    for j in range(ndim):
        if w_shape[j] == 1:
            # CArray: string becomes 'inds[{j}] = ind_{j};', remove (int_)type
            loops.append(
                "{{ {type} ix_{j} = ind_{j} * xstride_{j};".format(j=j, type=int_type)
            )
        else:
            boundary = _util._generate_boundary_condition_ops(
                mode, "ix_{}".format(j), "xsize_{}".format(j)
            )
            # CArray: last line of string becomes inds[{j}] = ix_{j};
            loops.append(
                """
    for (int iw_{j} = 0; iw_{j} < {wsize}; iw_{j}++)
    {{
        {type} ix_{j} = ind_{j} + iw_{j};
        {boundary}
        ix_{j} *= xstride_{j};
        """.format(j=j, wsize=w_shape[j], boundary=boundary, type=int_type)
            )

    # CArray: string becomes 'x[inds]', no format call needed
    value = "(*(X*)&data[{expr}])".format(expr=expr)
    if mode == "constant":
        cond = " || ".join(["(ix_{} < 0)".format(j) for j in range(ndim)])

    if binary_morphology:
        found = found.format(cond=cond, value=value)
    else:
        if mode == "constant":
            value = "(({cond}) ? cast<{ctype}>({cval}) : {value})".format(
                cond=cond, ctype=ctype, cval=cval, value=value
            )
        found = found.format(value=value)

    # CArray: replace comment and next line in string with
    #   {type} inds[{ndim}] = {{0}};
    # and add ndim=ndim, type=int_type to format call
    operation = """
    {sizes}
    {inds}
    // don't use a CArray for indexing (faster to deal with indexing ourselves)
    const unsigned char* data = (const unsigned char*)&x[0];
    {ws_init}
    {pre}
    {loops}
        // inner-most loop
        {ws_pre} {{
            {found}
        }}
        {ws_post}
    {end_loops}
    {post}
    """.format(
        sizes="\n".join(sizes),
        inds=inds,
        pre=pre,
        post=post,
        ws_init=ws_init,
        ws_pre=ws_pre,
        ws_post=ws_post,
        loops="\n".join(loops),
        found=found,
        end_loops="}" * ndim,
    )

    name = "cupy_ndimage_{}_{}d_{}_w{}".format(
        name, ndim, mode, "_".join(["{}".format(x) for x in w_shape])
    )
    if all_weights_nonzero:
        name += "_all_nonzero"
    if int_type == "ptrdiff_t":
        name += "_i64"
    if has_structure:
        name += "_with_structure"
    if has_mask:
        name += "_with_mask"
    preamble = _CAST_FUNCTION + preamble
    return cupy.ElementwiseKernel(
        in_params,
        out_params,
        operation,
        name,
        reduce_dims=False,
        preamble=preamble,
        options=("--std=c++11",) + options,
    )


# Traceback (cupy_backends.cuda.libs.nvrtc.NVRTCError)
/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupyx/scipy/ndimage/interpolation.py:15: UserWarning: In the current feature the default order of shift is 1. It is different from scipy.ndimage and can change in the future.
warnings.warn('In the current feature the default order of {} is 1. '
Traceback (most recent call last):
File "/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupy/cuda/compiler.py", line 516, in compile
nvrtc.compileProgram(self.ptr, options)
File "cupy_backends/cuda/libs/nvrtc.pyx", line 108, in cupy_backends.cuda.libs.nvrtc.compileProgram
File "cupy_backends/cuda/libs/nvrtc.pyx", line 120, in cupy_backends.cuda.libs.nvrtc.compileProgram
File "cupy_backends/cuda/libs/nvrtc.pyx", line 58, in cupy_backends.cuda.libs.nvrtc.check_status
cupy_backends.cuda.libs.nvrtc.NVRTCError: NVRTC_ERROR_COMPILATION (6)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupyx/scipy/ndimage/interpolation.py", line 379, in shift
kern(input, shift, output)
File "cupy/core/_kernel.pyx", line 821, in cupy.core._kernel.ElementwiseKernel.__call__
File "cupy/core/_kernel.pyx", line 846, in cupy.core._kernel.ElementwiseKernel._get_elementwise_kernel
File "cupy/_util.pyx", line 103, in cupy._util.memoize.decorator.ret
File "cupy/core/_kernel.pyx", line 639, in cupy.core._kernel._get_elementwise_kernel
File "cupy/core/_kernel.pyx", line 37, in cupy.core._kernel._get_simple_elementwise_kernel
File "cupy/core/_kernel.pyx", line 60, in cupy.core._kernel._get_simple_elementwise_kernel
File "cupy/core/core.pyx", line 1937, in cupy.core.core.compile_with_cache
File "/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupy/cuda/compiler.py", line 335, in compile_with_cache
return _compile_with_cache_cuda(
File "/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupy/cuda/compiler.py", line 402, in _compile_with_cache_cuda
ptx, mapping = compile_using_nvrtc(
File "/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupy/cuda/compiler.py", line 173, in compile_using_nvrtc
return _compile(source, options, cu_path,
File "/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupy/cuda/compiler.py", line 157, in _compile
ptx, mapping = prog.compile(options, log_stream)
File "/home/croat/.local/share/virtualenvs/starmap-T47byR32/lib/python3.8/site-packages/cupy/cuda/compiler.py", line 527, in compile
raise CompileException(log, self.src, self.name, options,
cupy.cuda.compiler.CompileException: /tmp/tmpbp6idobr/064ead033e63783c4dfe62433771dbed_2.cubin.cu(28): error: invalid type conversion

/tmp/tmpbp6idobr/064ead033e63783c4dfe62433771dbed_2.cubin.cu(20): warning: variable "s" was declared but never referenced

/tmp/tmpbp6idobr/064ead033e63783c4dfe62433771dbed_2.cubin.cu(20): warning: variable "t" was declared but never referenced

1 error detected in the compilation of "/tmp/tmpbp6idobr/064ead033e63783c4dfe62433771dbed_2.cubin.cu".

# Fixed code
def _generate_nd_kernel(
    name,
    pre,
    found,
    post,
    mode,
    w_shape,
    int_type,
    offsets,
    cval,
    ctype="X",
    preamble="",
    options=(),
    has_weights=True,
    has_structure=False,
    has_mask=False,
    binary_morphology=False,
    all_weights_nonzero=False,
):
    # Currently this code uses CArray for weights but avoids using CArray for
    # the input data and instead does the indexing itself since it is faster.
    # If CArray becomes faster than follow the comments that start with
    # CArray: to switch over to using CArray for the input data as well.

    ndim = len(w_shape)
    in_params = "raw X x"
    if has_weights:
        in_params += ", raw W w"
    if has_structure:
        in_params += ", raw S s"
    if has_mask:
        in_params += ", raw M mask"
    out_params = "Y y"

    # CArray: remove xstride_{j}=... from string
    size = (
        "%s xsize_{j}=x.shape()[{j}], ysize_{j} = _raw_y.shape()[{j}]"
        ", xstride_{j}=x.strides()[{j}];" % int_type
    )
    sizes = [size.format(j=j) for j in range(ndim)]
    inds = _util._generate_indices_ops(ndim, int_type, offsets)
    # CArray: remove expr entirely
    expr = " + ".join(["ix_{}".format(j) for j in range(ndim)])

    ws_init = ws_pre = ws_post = ""
    if has_weights or has_structure:
        ws_init = "int iws = 0;"
        if has_structure:
            ws_pre = "S sval = s[iws];\n"
        if has_weights:
            ws_pre += "W wval = w[iws];\n"
            if not all_weights_nonzero:
                ws_pre += "if (nonzero(wval))"
        ws_post = "iws++;"

    loops = []
    for j in range(ndim):
        if w_shape[j] == 1:
            # CArray: string becomes 'inds[{j}] = ind_{j};', remove (int_)type
            loops.append(
                "{{ {type} ix_{j} = ind_{j} * xstride_{j};".format(j=j, type=int_type)
            )
        else:
            boundary = _util._generate_boundary_condition_ops(
                mode, "ix_{}".format(j), "xsize_{}".format(j)
            )
            # CArray: last line of string becomes inds[{j}] = ix_{j};
            loops.append(
                """
    for (int iw_{j} = 0; iw_{j} < {wsize}; iw_{j}++)
    {{
        {type} ix_{j} = ind_{j} + iw_{j};
        {boundary}
        ix_{j} *= xstride_{j};
        """.format(j=j, wsize=w_shape[j], boundary=boundary, type=int_type)
            )

    # CArray: string becomes 'x[inds]', no format call needed
    value = "(*(X*)&data[{expr}])".format(expr=expr)
    if mode == "constant":
        cond = " || ".join(["(ix_{} < 0)".format(j) for j in range(ndim)])

    if cval is numpy.nan:
        cval = "CUDART_NAN"
    elif cval == numpy.inf:
        cval = "CUDART_INF"
    elif cval == -numpy.inf:
        cval = "-CUDART_INF"

    if binary_morphology:
        found = found.format(cond=cond, value=value)
    else:
        if mode == "constant":
            value = "(({cond}) ? cast<{ctype}>({cval}) : {value})".format(
                cond=cond, ctype=ctype, cval=cval, value=value
            )
        found = found.format(value=value)

    # CArray: replace comment and next line in string with
    #   {type} inds[{ndim}] = {{0}};
    # and add ndim=ndim, type=int_type to format call
    operation = """
    {sizes}
    {inds}
    // don't use a CArray for indexing (faster to deal with indexing ourselves)
    const unsigned char* data = (const unsigned char*)&x[0];
    {ws_init}
    {pre}
    {loops}
        // inner-most loop
        {ws_pre} {{
            {found}
        }}
        {ws_post}
    {end_loops}
    {post}
    """.format(
        sizes="\n".join(sizes),
        inds=inds,
        pre=pre,
        post=post,
        ws_init=ws_init,
        ws_pre=ws_pre,
        ws_post=ws_post,
        loops="\n".join(loops),
        found=found,
        end_loops="}" * ndim,
    )

    name = "cupy_ndimage_{}_{}d_{}_w{}".format(
        name, ndim, mode, "_".join(["{}".format(x) for x in w_shape])
    )
    if all_weights_nonzero:
        name += "_all_nonzero"
    if int_type == "ptrdiff_t":
        name += "_i64"
    if has_structure:
        name += "_with_structure"
    if has_mask:
        name += "_with_mask"
    preamble = math_constants_preamble + _CAST_FUNCTION + preamble
    return cupy.ElementwiseKernel(
        in_params,
        out_params,
        operation,
        name,
        reduce_dims=False,
        preamble=preamble,
        options=("--std=c++11",) + options,
    )