Exemple #1
0
def nufft_adjoint(input, coord, oshape=None, oversamp=1.25, width=4):
    """Adjoint non-uniform Fast Fourier Transform.

    Args:
        input (array): input Fourier domain array of shape
            (...) + coord.shape[:-1]. That is, the last dimensions
            of input must match the first dimensions of coord.
            The nufft_adjoint is applied on the last coord.ndim - 1 axes,
            and looped over the remaining axes.
        coord (array): Fourier domain coordinate array of shape (..., ndim).
            ndim determines the number of dimension to apply nufft adjoint.
            coord[..., i] should be scaled to have its range between
            -n_i // 2, and n_i // 2.
        oshape (tuple of ints): output shape of the form
            (..., n_{ndim - 1}, ..., n_1, n_0).
        oversamp (float): oversampling factor.
        width (float): interpolation kernel full-width in terms of
            oversampled grid.
        n (int): number of sampling points of the interpolation kernel.

    Returns:
        array: signal domain array with shape specified by oshape.

    See Also:
        :func:`sigpy.nufft.nufft`

    """
    ndim = coord.shape[-1]
    beta = np.pi * (((width / oversamp) * (oversamp - 0.5))**2 - 0.8)**0.5
    if oshape is None:
        oshape = list(input.shape[:-coord.ndim + 1]) + estimate_shape(coord)
    else:
        oshape = list(oshape)

    os_shape = _get_oversamp_shape(oshape, ndim, oversamp)

    # Gridding
    coord = _scale_coord(coord, oshape, oversamp)
    output = interp.gridding(input,
                             coord,
                             os_shape,
                             kernel='kaiser_bessel',
                             width=width,
                             param=beta)
    output /= width**ndim

    # IFFT
    output = ifft(output, axes=range(-ndim, 0), norm=None)

    # Crop
    output = util.resize(output, oshape)
    output *= util.prod(os_shape[-ndim:]) / util.prod(oshape[-ndim:])**0.5

    # Apodize
    _apodize(output, ndim, oversamp, width, beta)

    return output
Exemple #2
0
def _get_convolve_adjoint_input_params(W, y, input_multi_channel,
                                       output_multi_channel):
    ndim = W.ndim - input_multi_channel - output_multi_channel
    output_shape = y.shape[-ndim:]
    filter_shape = W.shape[-ndim:]
    batch_shape = y.shape[:-ndim - output_multi_channel]
    batch_size = util.prod(batch_shape)

    if y.dtype != W.dtype:
        raise TypeError(
            'y and W must have the same dtype, got {} and {}.'.format(
                y.dtype, W.dtype))

    if backend.get_device(y) != backend.get_device(W):
        raise TypeError(
            'y and W must be on the same device, got {} and {}.'.format(
                backend.get_device(y), backend.get_device(W)))

    if input_multi_channel:
        input_channel = W.shape[-ndim - 1]
    else:
        input_channel = 1

    if output_multi_channel:
        output_channel = y.shape[-ndim - 1]
    else:
        output_channel = 1

    return ndim, output_shape, filter_shape, batch_shape, \
        batch_size, input_channel, output_channel
Exemple #3
0
def _get_convolve_adjoint_filter_params(x, y, ndim, input_multi_channel,
                                        output_multi_channel):
    output_shape = y.shape[-ndim:]
    input_shape = x.shape[-ndim:]
    batch_shape = y.shape[:-ndim - output_multi_channel]
    batch_size = util.prod(batch_shape)

    if x.dtype != y.dtype:
        raise TypeError(
            'x and y must have the same dtype, got {} and {}.'.format(
                x.dtype, y.dtype))

    if backend.get_device(y) != backend.get_device(x):
        raise TypeError(
            'y and x must be on the same device, got {} and {}.'.format(
                backend.get_device(y), backend.get_device(x)))

    if input_multi_channel:
        input_channel = x.shape[-ndim - 1]
    else:
        input_channel = 1

    if output_multi_channel:
        output_channel = y.shape[-ndim - 1]
    else:
        output_channel = 1

    return input_shape, output_shape, batch_shape, \
        batch_size, input_channel, output_channel
Exemple #4
0
def nufft(input, coord, oversamp=1.25, width=4):
    """Non-uniform Fast Fourier Transform.

    Args:
        input (array): input signal domain array of shape
            (..., n_{ndim - 1}, ..., n_1, n_0),
            where ndim is specified by coord.shape[-1]. The nufft
            is applied on the last ndim axes, and looped over
            the remaining axes.
        coord (array): Fourier domain coordinate array of shape (..., ndim).
            ndim determines the number of dimensions to apply the nufft.
            coord[..., i] should be scaled to have its range between
            -n_i // 2, and n_i // 2.
        oversamp (float): oversampling factor.
        width (float): interpolation kernel full-width in terms of
            oversampled grid.
        n (int): number of sampling points of the interpolation kernel.

    Returns:
        array: Fourier domain data of shape
            input.shape[:-ndim] + coord.shape[:-1].

    References:
        Fessler, J. A., & Sutton, B. P. (2003).
        Nonuniform fast Fourier transforms using min-max interpolation
        IEEE Transactions on Signal Processing, 51(2), 560-574.
        Beatty, P. J., Nishimura, D. G., & Pauly, J. M. (2005).
        Rapid gridding reconstruction with a minimal oversampling ratio.
        IEEE transactions on medical imaging, 24(6), 799-808.

    """
    ndim = coord.shape[-1]
    beta = np.pi * (((width / oversamp) * (oversamp - 0.5))**2 - 0.8)**0.5
    os_shape = _get_oversamp_shape(input.shape, ndim, oversamp)

    output = input.copy()

    # Apodize
    _apodize(output, ndim, oversamp, width, beta)

    # Zero-pad
    output /= util.prod(input.shape[-ndim:])**0.5
    output = util.resize(output, os_shape)

    # FFT
    output = fft(output, axes=range(-ndim, 0), norm=None)

    # Interpolate
    coord = _scale_coord(coord, input.shape, oversamp)
    output = interp.interpolate(output,
                                coord,
                                kernel='kaiser_bessel',
                                width=width,
                                param=beta)
    output /= width**ndim

    return output
Exemple #5
0
    def __init__(self, proxs):
        self.nops = len(proxs)
        assert(self.nops > 0)

        self.proxs = proxs
        self.shapes = [prox.shape for prox in proxs]
        shape = [sum(util.prod(prox.shape) for prox in proxs)]

        super().__init__(shape)
Exemple #6
0
def _fft_convolve_adjoint_filter(x, y, mode='full'):
    ndim = x.ndim - 2
    batch_size = len(x)
    output_channel = y.shape[1]
    input_channel = x.shape[1]
    output_shape = y.shape[-ndim:]
    input_shape = x.shape[-ndim:]
    if mode == 'full':
        filter_shape = tuple(p - m + 1
                             for m, p in zip(input_shape, output_shape))
        pad_shape = output_shape
    elif mode == 'valid':
        filter_shape = tuple(m - p + 1
                             for m, p in zip(input_shape, output_shape))
        pad_shape = input_shape

    dtype = x.dtype
    device = backend.get_device(x)
    xp = device.xp
    with device:
        x = xp.conj(util.flip(x, axes=range(-ndim, 0)))
        x = x.reshape((batch_size, 1, input_channel) + input_shape)
        y = y.reshape((batch_size, output_channel, 1) + output_shape)

        x_pad = util.resize(x, (batch_size, 1, input_channel) + pad_shape,
                            oshift=[0] * x.ndim)
        y_pad = util.resize(y, (batch_size, output_channel, 1) + pad_shape,
                            oshift=[0] * y.ndim)

        if np.issubdtype(dtype, np.floating):
            x_fft = xp.fft.rfftn(x_pad, axes=range(-ndim, 0), norm='ortho')
            y_fft = xp.fft.rfftn(y_pad, axes=range(-ndim, 0), norm='ortho')
            W_fft = xp.sum(x_fft * y_fft, axis=0)
            W = xp.fft.irfftn(W_fft,
                              pad_shape,
                              axes=range(-ndim, 0),
                              norm='ortho').astype(dtype)
        else:
            x_fft = fourier.fft(x_pad, axes=range(-ndim, 0), center=False)
            y_fft = fourier.fft(y_pad, axes=range(-ndim, 0), center=False)
            W_fft = xp.sum(x_fft * y_fft, axis=0)
            W = fourier.ifft(W_fft, axes=range(-ndim, 0), center=False)

        if mode == 'full':
            shift = [0, 0] + [m - 1 for m in input_shape]
        elif mode == 'valid':
            shift = [0, 0] + [p - 1 for p in output_shape]

        W = util.resize(W, (output_channel, input_channel) + filter_shape,
                        ishift=shift)
        W *= util.prod(pad_shape)**0.5
        return W
Exemple #7
0
def gridding(input, shape, width, kernel, coord):
    """Gridding of points specified by coordinates to array.

    Args:
        input (array): Input array.
        shape (array of ints): Output shape.
        width (float): Interpolation kernel width.
        kernel (array): Interpolation kernel.
        coord (array): Coordinate array of shape [..., ndim]

    Returns:
        output (array): Output array.

    """
    ndim = coord.shape[-1]

    batch_shape = shape[:-ndim]
    batch_size = util.prod(batch_shape)

    pts_shape = coord.shape[:-1]
    npts = util.prod(pts_shape)

    device = backend.get_device(input)
    xp = device.xp
    isreal = np.issubdtype(input.dtype, np.floating)

    with device:
        input = input.reshape([batch_size, npts])
        coord = coord.reshape([npts, ndim])
        output = xp.zeros([batch_size] + list(shape[-ndim:]),
                          dtype=input.dtype)

        _gridding = _select_gridding(ndim, npts, device, isreal)
        if device == backend.cpu_device:
            _gridding(output, input, width, kernel, coord)
        else:  # pragma: no cover
            _gridding(input, width, kernel, coord, output, size=npts)

        return output.reshape(shape)
Exemple #8
0
def interpolate(input, width, kernel, coord):
    """Interpolation from array to points specified by coordinates.

    Args:
        input (array): Input array of shape [..., ny, nx]
        width (float): Interpolation kernel width.
        kernel (array): Interpolation kernel.
        coord (array): Coordinate array of shape [..., ndim]

    Returns:
        output (array): Output array of coord.shape[:-1]

    """
    ndim = coord.shape[-1]

    batch_shape = input.shape[:-ndim]
    batch_size = util.prod(batch_shape)

    pts_shape = coord.shape[:-1]
    npts = util.prod(pts_shape)

    device = backend.get_device(input)
    xp = device.xp
    isreal = np.issubdtype(input.dtype, np.floating)
    coord = backend.to_device(coord, device)
    kernel = backend.to_device(kernel, device)

    with device:
        input = input.reshape([batch_size] + list(input.shape[-ndim:]))
        coord = coord.reshape([npts, ndim])
        output = xp.zeros([batch_size, npts], dtype=input.dtype)

        _interpolate = _select_interpolate(ndim, npts, device, isreal)
        if device == backend.cpu_device:
            _interpolate(output, input, width, kernel, coord)
        else:  # pragma: no cover
            _interpolate(input, width, kernel, coord, output, size=npts)

        return output.reshape(batch_shape + pts_shape)
Exemple #9
0
def _fft_convolve_adjoint_input(W, y, mode='full'):
    ndim = y.ndim - 2
    batch_size = len(y)
    output_channel, input_channel = W.shape[:2]
    output_shape = y.shape[-ndim:]
    filter_shape = W.shape[-ndim:]
    if mode == 'full':
        input_shape = tuple(p - n + 1
                            for p, n in zip(output_shape, filter_shape))
        pad_shape = output_shape
    elif mode == 'valid':
        input_shape = tuple(p + n - 1
                            for p, n in zip(output_shape, filter_shape))
        pad_shape = input_shape

    dtype = y.dtype
    device = backend.get_device(y)
    xp = device.xp
    with device:
        y = y.reshape((batch_size, output_channel, 1) + output_shape)
        W = xp.conj(util.flip(W, axes=range(-ndim, 0)))

        y_pad = util.resize(y, (batch_size, output_channel, 1) + pad_shape,
                            oshift=[0] * y.ndim)
        W_pad = util.resize(W, (output_channel, input_channel) + pad_shape,
                            oshift=[0] * W.ndim)

        if np.issubdtype(dtype, np.floating):
            y_fft = xp.fft.rfftn(y_pad, axes=range(-ndim, 0), norm='ortho')
            W_fft = xp.fft.rfftn(W_pad, axes=range(-ndim, 0), norm='ortho')
            x_fft = xp.sum(y_fft * W_fft, axis=-ndim - 2)
            x = xp.fft.irfftn(x_fft,
                              pad_shape,
                              axes=range(-ndim, 0),
                              norm='ortho').astype(dtype)
        else:
            y_fft = fourier.fft(y_pad, axes=range(-ndim, 0), center=False)
            W_fft = fourier.fft(W_pad, axes=range(-ndim, 0), center=False)
            x_fft = xp.sum(y_fft * W_fft, axis=-ndim - 2)
            x = fourier.ifft(x_fft, axes=range(-ndim, 0), center=False)

        if mode == 'full':
            shift = [0, 0] + [n - 1 for n in filter_shape]
        elif mode == 'valid':
            shift = [0] * x.ndim

        x = util.resize(x, (batch_size, input_channel) + input_shape,
                        ishift=shift)
        x *= util.prod(pad_shape)**0.5
        return x
Exemple #10
0
def _fft_convolve(x, W, mode='full'):
    ndim = x.ndim - 2
    batch_size = len(x)
    output_channel, input_channel = W.shape[:2]
    input_shape = x.shape[-ndim:]
    filter_shape = W.shape[-ndim:]
    if mode == 'full':
        output_shape = tuple(m + n - 1
                             for m, n in zip(input_shape, filter_shape))
        pad_shape = output_shape
    elif mode == 'valid':
        output_shape = tuple(m - n + 1
                             for m, n in zip(input_shape, filter_shape))
        pad_shape = input_shape

    dtype = x.dtype
    device = backend.get_device(x)
    xp = device.xp
    with device:
        x = x.reshape((batch_size, 1, input_channel) + input_shape)
        x_pad = util.resize(x, (batch_size, 1, input_channel) + pad_shape,
                            oshift=[0] * x.ndim)
        W_pad = util.resize(W, (output_channel, input_channel) + pad_shape,
                            oshift=[0] * W.ndim)

        if np.issubdtype(dtype, np.floating):
            x_fft = xp.fft.rfftn(x_pad, axes=range(-ndim, 0), norm='ortho')
            W_fft = xp.fft.rfftn(W_pad, axes=range(-ndim, 0), norm='ortho')
            y_fft = xp.sum(x_fft * W_fft, axis=-ndim - 1)
            y = xp.fft.irfftn(y_fft,
                              pad_shape,
                              axes=range(-ndim, 0),
                              norm='ortho').astype(dtype)
        else:
            x_fft = fourier.fft(x_pad, axes=range(-ndim, 0), center=False)
            W_fft = fourier.fft(W_pad, axes=range(-ndim, 0), center=False)
            y_fft = xp.sum(x_fft * W_fft, axis=-ndim - 1)
            y = fourier.ifft(y_fft, axes=range(-ndim, 0), center=False)

        if mode == 'full':
            shift = [0] * y.ndim
        elif mode == 'valid':
            shift = [0, 0] + [n - 1 for n in filter_shape]

        y = util.resize(y, (batch_size, output_channel) + output_shape,
                        ishift=shift)
        y *= util.prod(pad_shape)**0.5
        return y
Exemple #11
0
def _get_convolve_adjoint_filter_params(x, y, ndim, input_multi_channel,
                                        output_multi_channel):
    output_shape = y.shape[-ndim:]
    input_shape = x.shape[-ndim:]
    batch_shape = y.shape[:-ndim - output_multi_channel]
    batch_size = util.prod(batch_shape)

    if input_multi_channel:
        input_channel = x.shape[-ndim - 1]
    else:
        input_channel = 1

    if output_multi_channel:
        output_channel = y.shape[-ndim - 1]
    else:
        output_channel = 1

    return input_shape, output_shape, batch_shape, \
        batch_size, input_channel, output_channel
Exemple #12
0
def _get_convolve_params(data_shape, filt_shape, mode, strides, multi_channel):
    D = len(filt_shape) - 2 * multi_channel
    m = tuple(data_shape[-D:])
    n = tuple(filt_shape[-D:])
    b = tuple(data_shape[:-D - multi_channel])
    B = util.prod(b)

    if multi_channel:
        if filt_shape[-D - 1] != data_shape[-D - 1]:
            raise ValueError('Data channel mismatch, '
                             'got {} from data and {} from filt.'.format(
                                 data_shape[-D - 1], filt_shape[-D - 1]))

        c_i = filt_shape[-D - 1]
        c_o = filt_shape[-D - 2]
    else:
        c_i = 1
        c_o = 1

    if strides is None:
        s = (1, ) * D
    else:
        if len(strides) != D:
            raise ValueError('Strides must have length {}.'.format(D))

        s = tuple(strides)

    if mode == 'full':
        p = tuple(
            (m_d + n_d - 1 + s_d - 1) // s_d for m_d, n_d, s_d in zip(m, n, s))
    elif mode == 'valid':
        if (any(m_d >= n_d for m_d, n_d in zip(m, n))
                and any(m_d < n_d for m_d, n_d in zip(m, n))):
            raise ValueError('In valid mode, either data or filter must be '
                             'at least as large as the other in every axis.')

        p = tuple(
            (m_d - n_d + 1 + s_d - 1) // s_d for m_d, n_d, s_d in zip(m, n, s))
    else:
        raise ValueError('Invalid mode, got {}'.format(mode))

    return D, b, B, m, n, s, c_i, c_o, p
Exemple #13
0
def _get_convolve_adjoint_input_params(W, y, input_multi_channel,
                                       output_multi_channel):
    ndim = W.ndim - input_multi_channel - output_multi_channel
    output_shape = y.shape[-ndim:]
    filter_shape = W.shape[-ndim:]
    batch_shape = y.shape[:-ndim - output_multi_channel]
    batch_size = util.prod(batch_shape)

    if input_multi_channel:
        input_channel = W.shape[-ndim - 1]
    else:
        input_channel = 1

    if output_multi_channel:
        output_channel = y.shape[-ndim - 1]
    else:
        output_channel = 1

    return ndim, output_shape, filter_shape, batch_shape, \
        batch_size, input_channel, output_channel
Exemple #14
0
def elitist_thresh(lamda, input, axes=None):
    """Elitist threshold.

    Solves for

    :math::
        \text{argmin}_x \| x - y \|_2^2 + \lambda \| x \|_1^2

    Args:
        lamda (float, or array): Threshold parameter.
        input (array): Input array.
        axes (None or tuple of ints): Axes to perform threshold.

    Returns:
        array: Result.

    References:
        Kowalski, M. 2009. Sparse regression using mixed norms.

    """
    shape = input.shape
    axes = util._normalize_axes(axes, input.ndim)
    remain_axes = tuple(set(range(input.ndim)) - set(axes))

    length = util.prod([shape[a] for a in axes])
    batch = input.size // length

    input = input.transpose(remain_axes + axes)
    input = input.reshape([batch, length])

    thresh = find_elitist_thresh(lamda, input)
    output = soft_thresh(thresh, input)

    output = output.reshape([shape[a] for a in remain_axes + axes])
    output = output.transpose(np.argsort(remain_axes + axes))

    return output
Exemple #15
0
def _vstack_params(shapes, axis):
    if axis is None:
        return _vstack_params([[util.prod(shape)] for shape in shapes], 0)

    oshape = list(shapes[0])
    ndim = len(oshape)
    idx = shapes[0][axis]
    indices = []

    for shape in shapes[1:]:
        if len(shape) != ndim:
            raise Exception(
                'Shapes must have the same lengths to concatenate.')

        for i in range(ndim):
            if i == axis:
                oshape[i] += shape[i]
                indices.append(idx)
                idx += shape[i]
            elif shape[i] != oshape[i]:
                raise Exception(
                    'Shapes not along axis must be the same to concatenate.')

    return oshape, indices
Exemple #16
0
def blocks_to_array(input, oshape, blk_shape, blk_strides):
    """Accumulate blocks into an array in a sliding window manner.

    Args:
        input (array): input array of shape [...] + num_blks + blk_shape
        oshape (tuple): output shape.
        blk_shape (tuple): block shape of length D.
        blk_strides (tuple): block strides of length D.

    Returns:
        array: array of shape oshape.

    """
    if len(blk_shape) != len(blk_strides):
        raise ValueError('blk_shape must have the same length as blk_strides.')

    D = len(blk_shape)
    num_blks = input.shape[-(2 * D):-D]
    batch_shape = list(oshape[:-D])
    batch_size = util.prod(batch_shape)
    device = backend.get_device(input)
    xp = device.xp
    with device:
        output = xp.zeros([batch_size] + list(oshape[-D:]), dtype=input.dtype)
        input = input.reshape([batch_size] + list(input.shape[-2 * D:]))

        if D == 1:
            if device == backend.cpu_device:
                _blocks_to_array1(output, input, batch_size, blk_shape[-1],
                                  blk_strides[-1], num_blks[-1])
            else:  # pragma: no cover
                if np.issubdtype(input.dtype, np.floating):
                    _blocks_to_array1_cuda(input,
                                           batch_size,
                                           blk_shape[-1],
                                           blk_strides[-1],
                                           num_blks[-1],
                                           output,
                                           size=batch_size * num_blks[-1] *
                                           blk_shape[-1])
                else:
                    _blocks_to_array1_cuda_complex(
                        input,
                        batch_size,
                        blk_shape[-1],
                        blk_strides[-1],
                        num_blks[-1],
                        output,
                        size=batch_size * num_blks[-1] * blk_shape[-1])
        elif D == 2:
            if device == backend.cpu_device:
                _blocks_to_array2(output, input, batch_size, blk_shape[-1],
                                  blk_shape[-2], blk_strides[-1],
                                  blk_strides[-2], num_blks[-1], num_blks[-2])
            else:  # pragma: no cover
                if np.issubdtype(input.dtype, np.floating):
                    _blocks_to_array2_cuda(input,
                                           batch_size,
                                           blk_shape[-1],
                                           blk_shape[-2],
                                           blk_strides[-1],
                                           blk_strides[-2],
                                           num_blks[-1],
                                           num_blks[-2],
                                           output,
                                           size=batch_size * num_blks[-1] *
                                           num_blks[-2] * blk_shape[-1] *
                                           blk_shape[-2])
                else:  # pragma: no cover
                    _blocks_to_array2_cuda_complex(
                        input,
                        batch_size,
                        blk_shape[-1],
                        blk_shape[-2],
                        blk_strides[-1],
                        blk_strides[-2],
                        num_blks[-1],
                        num_blks[-2],
                        output,
                        size=batch_size * num_blks[-1] * num_blks[-2] *
                        blk_shape[-1] * blk_shape[-2])
        elif D == 3:
            if device == backend.cpu_device:
                _blocks_to_array3(output, input, batch_size, blk_shape[-1],
                                  blk_shape[-2], blk_shape[-3],
                                  blk_strides[-1], blk_strides[-2],
                                  blk_strides[-3], num_blks[-1], num_blks[-2],
                                  num_blks[-3])
            else:  # pragma: no cover
                if np.issubdtype(input.dtype, np.floating):
                    _blocks_to_array3_cuda(input,
                                           batch_size,
                                           blk_shape[-1],
                                           blk_shape[-2],
                                           blk_shape[-3],
                                           blk_strides[-1],
                                           blk_strides[-2],
                                           blk_strides[-3],
                                           num_blks[-1],
                                           num_blks[-2],
                                           num_blks[-3],
                                           output,
                                           size=batch_size * num_blks[-1] *
                                           num_blks[-2] * num_blks[-3] *
                                           blk_shape[-1] * blk_shape[-2] *
                                           blk_shape[-3])
                else:
                    _blocks_to_array3_cuda_complex(
                        input,
                        batch_size,
                        blk_shape[-1],
                        blk_shape[-2],
                        blk_shape[-3],
                        blk_strides[-1],
                        blk_strides[-2],
                        blk_strides[-3],
                        num_blks[-1],
                        num_blks[-2],
                        num_blks[-3],
                        output,
                        size=batch_size * num_blks[-1] * num_blks[-2] *
                        num_blks[-3] * blk_shape[-1] * blk_shape[-2] *
                        blk_shape[-3])
        elif D == 4:
            if device == backend.cpu_device:
                _blocks_to_array4(output, input, batch_size, blk_shape[-1],
                                  blk_shape[-2], blk_shape[-3], blk_shape[-4],
                                  blk_strides[-1], blk_strides[-2],
                                  blk_strides[-3], blk_strides[-4],
                                  num_blks[-1], num_blks[-2], num_blks[-3],
                                  num_blks[-4])
            else:  # pragma: no cover
                if np.issubdtype(input.dtype, np.floating):
                    _blocks_to_array4_cuda(
                        input,
                        batch_size,
                        blk_shape[-1],
                        blk_shape[-2],
                        blk_shape[-3],
                        blk_shape[-4],
                        blk_strides[-1],
                        blk_strides[-2],
                        blk_strides[-3],
                        blk_strides[-4],
                        num_blks[-1],
                        num_blks[-2],
                        num_blks[-3],
                        num_blks[-4],
                        output,
                        size=batch_size * num_blks[-1] * num_blks[-2] *
                        num_blks[-3] * num_blks[-4] * blk_shape[-1] *
                        blk_shape[-2] * blk_shape[-3] * blk_shape[-4])
                else:
                    _blocks_to_array4_cuda_complex(
                        input,
                        batch_size,
                        blk_shape[-1],
                        blk_shape[-2],
                        blk_shape[-3],
                        blk_shape[-4],
                        blk_strides[-1],
                        blk_strides[-2],
                        blk_strides[-3],
                        blk_strides[-4],
                        num_blks[-1],
                        num_blks[-2],
                        num_blks[-3],
                        num_blks[-4],
                        output,
                        size=batch_size * num_blks[-1] * num_blks[-2] *
                        num_blks[-3] * num_blks[-4] * blk_shape[-1] *
                        blk_shape[-2] * blk_shape[-3] * blk_shape[-4])
        else:
            raise ValueError('Only support D <= 4, got {}'.format(D))

        return output.reshape(oshape)
Exemple #17
0
def array_to_blocks(input, blk_shape, blk_strides):
    """Extract blocks from an array in a sliding window manner.

    Args:
        input (array): input array of shape [..., N_1, ..., N_D]
        blk_shape (tuple): block shape of length D, with D <= 4.
        blk_strides (tuple): block strides of length D.

    Returns:
        array: array of shape [...] + num_blks + blk_shape, where
            num_blks = (N - blk_shape + blk_strides) // blk_strides.

    Example:

        >>> input = np.array([0, 1, 2, 3, 4, 5])
        >>> print(array_to_blocks(input, [2], [2]))
        [[0, 1],
         [2, 3],
         [4, 5]]

    """
    if len(blk_shape) != len(blk_strides):
        raise ValueError('blk_shape must have the same length as blk_strides.')

    D = len(blk_shape)
    num_blks = [(i - b + s) // s
                for i, b, s in zip(input.shape[-D:], blk_shape, blk_strides)]
    batch_shape = list(input.shape[:-D])
    batch_size = util.prod(batch_shape)
    device = backend.get_device(input)
    xp = device.xp
    with device:
        output = xp.zeros([batch_size] + num_blks + blk_shape,
                          dtype=input.dtype)
        input = input.reshape([batch_size] + list(input.shape[-D:]))

        if D == 1:
            if device == backend.cpu_device:
                _array_to_blocks1(output, input, batch_size, blk_shape[-1],
                                  blk_strides[-1], num_blks[-1])
            else:  # pragma: no cover
                _array_to_blocks1_cuda(input,
                                       batch_size,
                                       blk_shape[-1],
                                       blk_strides[-1],
                                       num_blks[-1],
                                       output,
                                       size=batch_size * num_blks[-1] *
                                       blk_shape[-1])
        elif D == 2:
            if device == backend.cpu_device:
                _array_to_blocks2(output, input, batch_size, blk_shape[-1],
                                  blk_shape[-2], blk_strides[-1],
                                  blk_strides[-2], num_blks[-1], num_blks[-2])
            else:  # pragma: no cover
                _array_to_blocks2_cuda(input,
                                       batch_size,
                                       blk_shape[-1],
                                       blk_shape[-2],
                                       blk_strides[-1],
                                       blk_strides[-2],
                                       num_blks[-1],
                                       num_blks[-2],
                                       output,
                                       size=batch_size * num_blks[-1] *
                                       num_blks[-2] * blk_shape[-1] *
                                       blk_shape[-2])
        elif D == 3:
            if device == backend.cpu_device:
                _array_to_blocks3(output, input, batch_size, blk_shape[-1],
                                  blk_shape[-2], blk_shape[-3],
                                  blk_strides[-1], blk_strides[-2],
                                  blk_strides[-3], num_blks[-1], num_blks[-2],
                                  num_blks[-3])
            else:  # pragma: no cover
                _array_to_blocks3_cuda(input,
                                       batch_size,
                                       blk_shape[-1],
                                       blk_shape[-2],
                                       blk_shape[-3],
                                       blk_strides[-1],
                                       blk_strides[-2],
                                       blk_strides[-3],
                                       num_blks[-1],
                                       num_blks[-2],
                                       num_blks[-3],
                                       output,
                                       size=batch_size * num_blks[-1] *
                                       num_blks[-2] * num_blks[-3] *
                                       blk_shape[-1] * blk_shape[-2] *
                                       blk_shape[-3])
        elif D == 4:
            if device == backend.cpu_device:
                _array_to_blocks4(output, input, batch_size, blk_shape[-1],
                                  blk_shape[-2], blk_shape[-3], blk_shape[-4],
                                  blk_strides[-1], blk_strides[-2],
                                  blk_strides[-3], blk_strides[-4],
                                  num_blks[-1], num_blks[-2], num_blks[-3],
                                  num_blks[-4])
            else:  # pragma: no cover
                _array_to_blocks4_cuda(
                    input,
                    batch_size,
                    blk_shape[-1],
                    blk_shape[-2],
                    blk_shape[-3],
                    blk_shape[-4],
                    blk_strides[-1],
                    blk_strides[-2],
                    blk_strides[-3],
                    blk_strides[-4],
                    num_blks[-1],
                    num_blks[-2],
                    num_blks[-3],
                    num_blks[-4],
                    output,
                    size=batch_size * num_blks[-1] * num_blks[-2] *
                    num_blks[-3] * num_blks[-4] * blk_shape[-1] *
                    blk_shape[-2] * blk_shape[-3] * blk_shape[-4])
        else:
            raise ValueError('Only support D <= 4, got {}'.format(D))

        return output.reshape(batch_shape + num_blks + blk_shape)
Exemple #18
0
def gridding(input, coord, shape, kernel="spline", width=2, param=1):
    r"""Gridding of points specified by coordinates to array.

    Let :math:`y` be the input, :math:`x` be the output,
    :math:`c` be the coordinates, :math:`W` be the kernel width,
    and :math:`K` be the interpolation kernel, then the function computes,

    .. math ::
        x[i] = \sum_{j : \| i - c[j] \|_\infty \leq W / 2}
               K\left(\frac{i - c[j]}{W / 2}\right) y[j]

    There are two types of kernels: 'spline' and 'kaiser_bessel'.

    'spline' uses the cardinal B-spline functions as kernels.
    The order of the spline can be specified using param.
    For example, param=1 performs linear interpolation.
    Concretely, for param=0, :math:`K(x) = 1`,
    for param=1, :math:`K(x) = 1 - |x|`, and
    for param=2, :math:`K(x) = \frac{9}{8} (1 - |x|)^2`
    for :math:`|x| > \frac{1}{3}`
    and :math:`K(x) = \frac{3}{4} (1 - 3 x^2)` for :math:`|x| < \frac{1}{3}`.

    These function expressions are derived from the reference wikipedia
    page by shifting and scaling the range to -1 to 1.
    When the coordinates specifies a uniformly spaced grid,
    it is recommended to use the original scaling with width=param + 1
    so that the interpolation weights add up to one.

    'kaiser_bessel' uses the Kaiser-Bessel function as kernel.
    Concretely, :math:`K(x) = I_0(\beta \sqrt{1 - x^2})`,
    where :math:`I_0` is the modified Bessel function of the first kind.
    The beta parameter can be specified with param.
    The modified Bessel function of the first kind is approximated
    using the power series, following the reference.

    Args:
        input (array): Input array.
        coord (array): Coordinate array of shape [..., ndim]
        width (float or tuple of floats): Interpolation kernel full-width.
        kernel (str): Interpolation kernel, {"spline", "kaiser_bessel"}.
        param (float or tuple of floats): Kernel parameter.

    Returns:
        output (array): Output array.

    References:
        https://en.wikipedia.org/wiki/Spline_wavelet#Cardinal_B-splines_of_small_orders
        http://people.math.sfu.ca/~cbm/aands/page_378.htm
    """
    ndim = coord.shape[-1]

    batch_shape = shape[:-ndim]
    batch_size = util.prod(batch_shape)

    pts_shape = coord.shape[:-1]
    npts = util.prod(pts_shape)

    xp = backend.get_array_module(input)
    isreal = np.issubdtype(input.dtype, np.floating)

    input = input.reshape([batch_size, npts])
    coord = coord.reshape([npts, ndim])
    output = xp.zeros([batch_size] + list(shape[-ndim:]), dtype=input.dtype)

    if np.isscalar(param):
        param = xp.array([param] * ndim, coord.dtype)
    else:
        param = xp.array(param, coord.dtype)

    if np.isscalar(width):
        width = xp.array([width] * ndim, coord.dtype)
    else:
        width = xp.array(width, coord.dtype)

    if xp == np:
        _gridding[kernel][ndim - 1](output, input, coord, width, param)
    else:  # pragma: no cover
        if isreal:
            _gridding_cuda[kernel][ndim - 1](
                input, coord, width, param, output, size=npts)
        else:
            _gridding_cuda_complex[kernel][ndim - 1](
                input, coord, width, param, output, size=npts)

    return output.reshape(shape)
Exemple #19
0
def blocks_to_array(input, oshape, blk_shape, blk_strides):
    """Accumulate blocks into an array in a sliding window manner.

    Args:
        input (array): input array of shape [...] + num_blks + blk_shape
        oshape (tuple): output shape.
        blk_shape (tuple): block shape of length ndim.
        blk_strides (tuple): block strides of length ndim.

    Returns:
        array: array of shape oshape.

    """
    if len(blk_shape) != len(blk_strides):
        raise ValueError('blk_shape must have the same length as blk_strides.')

    ndim = len(blk_shape)
    num_blks = input.shape[-(2 * ndim):-ndim]
    batch_shape = list(oshape[:-ndim])
    batch_size = util.prod(batch_shape)
    xp = backend.get_array_module(input)
    output = xp.zeros([batch_size] + list(oshape[-ndim:]), dtype=input.dtype)
    input = input.reshape([batch_size] + list(input.shape[-2 * ndim:]))

    if ndim == 1:
        if xp == np:
            _blocks_to_array1(output, input, batch_size, blk_shape[-1],
                              blk_strides[-1], num_blks[-1])
        else:  # pragma: no cover
            _blocks_to_array1_cuda(input,
                                   batch_size,
                                   blk_shape[-1],
                                   blk_strides[-1],
                                   num_blks[-1],
                                   output,
                                   size=output.size)
    elif ndim == 2:
        if xp == np:
            _blocks_to_array2(output, input, batch_size, blk_shape[-1],
                              blk_shape[-2], blk_strides[-1], blk_strides[-2],
                              num_blks[-1], num_blks[-2])
        else:  # pragma: no cover
            _blocks_to_array2_cuda(input,
                                   batch_size,
                                   blk_shape[-1],
                                   blk_shape[-2],
                                   blk_strides[-1],
                                   blk_strides[-2],
                                   num_blks[-1],
                                   num_blks[-2],
                                   output,
                                   size=output.size)
    elif ndim == 3:
        if xp == np:
            _blocks_to_array3(output, input, batch_size, blk_shape[-1],
                              blk_shape[-2], blk_shape[-3], blk_strides[-1],
                              blk_strides[-2], blk_strides[-3], num_blks[-1],
                              num_blks[-2], num_blks[-3])
        else:  # pragma: no cover
            _blocks_to_array3_cuda(input,
                                   batch_size,
                                   blk_shape[-1],
                                   blk_shape[-2],
                                   blk_shape[-3],
                                   blk_strides[-1],
                                   blk_strides[-2],
                                   blk_strides[-3],
                                   num_blks[-1],
                                   num_blks[-2],
                                   num_blks[-3],
                                   output,
                                   size=output.size)
    else:
        raise ValueError('Only support ndim=1, 2, or 3, got {}'.format(ndim))

    return output.reshape(oshape)
Exemple #20
0
def array_to_blocks(input, blk_shape, blk_strides):
    """Extract blocks from an array in a sliding window manner.

    Args:
        input (array): input array of shape [..., N_1, ..., N_ndim]
        blk_shape (tuple): block shape of length ndim, with ndim={1, 2, 3}.
        blk_strides (tuple): block strides of length ndim.

    Returns:
        array: array of shape [...] + num_blks + blk_shape, where
            num_blks = (N - blk_shape + blk_strides) // blk_strides.

    Example:

        >>> input = np.array([0, 1, 2, 3, 4, 5])
        >>> print(array_to_blocks(input, [2], [2]))
        [[0, 1],
         [2, 3],
         [4, 5]]

    """
    if len(blk_shape) != len(blk_strides):
        raise ValueError('blk_shape must have the same length as blk_strides.')

    ndim = len(blk_shape)
    num_blks = [(i - b + s) // s
                for i, b, s in zip(input.shape[-ndim:], blk_shape, blk_strides)
                ]
    batch_shape = list(input.shape[:-ndim])
    batch_size = util.prod(batch_shape)
    xp = backend.get_array_module(input)
    output = xp.zeros([batch_size] + num_blks + list(blk_shape),
                      dtype=input.dtype)
    input = input.reshape([batch_size] + list(input.shape[-ndim:]))

    if ndim == 1:
        if xp == np:
            _array_to_blocks1(output, input, batch_size, blk_shape[-1],
                              blk_strides[-1], num_blks[-1])
        else:  # pragma: no cover
            _array_to_blocks1_cuda(input,
                                   batch_size,
                                   blk_shape[-1],
                                   blk_strides[-1],
                                   num_blks[-1],
                                   output,
                                   size=output.size)
    elif ndim == 2:
        if xp == np:
            _array_to_blocks2(output, input, batch_size, blk_shape[-1],
                              blk_shape[-2], blk_strides[-1], blk_strides[-2],
                              num_blks[-1], num_blks[-2])
        else:  # pragma: no cover
            _array_to_blocks2_cuda(input,
                                   batch_size,
                                   blk_shape[-1],
                                   blk_shape[-2],
                                   blk_strides[-1],
                                   blk_strides[-2],
                                   num_blks[-1],
                                   num_blks[-2],
                                   output,
                                   size=output.size)
    elif ndim == 3:
        if xp == np:
            _array_to_blocks3(output, input, batch_size, blk_shape[-1],
                              blk_shape[-2], blk_shape[-3], blk_strides[-1],
                              blk_strides[-2], blk_strides[-3], num_blks[-1],
                              num_blks[-2], num_blks[-3])
        else:  # pragma: no cover
            _array_to_blocks3_cuda(input,
                                   batch_size,
                                   blk_shape[-1],
                                   blk_shape[-2],
                                   blk_shape[-3],
                                   blk_strides[-1],
                                   blk_strides[-2],
                                   blk_strides[-3],
                                   num_blks[-1],
                                   num_blks[-2],
                                   num_blks[-3],
                                   output,
                                   size=output.size)
    else:
        raise ValueError('Only support ndim=1, 2, or 3, got {}'.format(ndim))

    return output.reshape(batch_shape + num_blks + list(blk_shape))