# Source code for pylops.signalprocessing.Shift

import numpy as np

from pylops.basicoperators import Diagonal
from pylops.signalprocessing import FFT

[docs]def Shift(
dims,
shift,
dir=0,
nfft=None,
sampling=1.0,
real=False,
engine="numpy",
dtype="complex128",
**kwargs_fftw
):
r"""Shift operator

Apply fractional shift in the frequency domain along a specific direction
dir of a multi-dimensional array of size dim.

Parameters
----------
dims : :obj:tuple
Number of samples for each dimension
shift : :obj:float
Fractional shift to apply in the same unit as sampling.
dir : :obj:int, optional
Direction along which FFT is applied.
nfft : :obj:int, optional
Number of samples in Fourier Transform (same as input if nfft=None)
sampling : :obj:float, optional
Sampling step :math:\Delta t.
real : :obj:bool, optional
Model to which fft is applied has real numbers (True) or not
(False). Used to enforce that the output of adjoint of a real
model is real.
engine : :obj:str, optional
Engine used for fft computation (numpy, scipy, or fftw). Choose
numpy when working with CuPy arrays.
dtype : :obj:str, optional
Type of elements in input array.
**kwargs_fftw
Arbitrary keyword arguments
for :py:class:pyfftw.FTTW

Attributes
----------
shape : :obj:tuple
Operator shape
explicit : :obj:bool
Operator contains a matrix that can be solved explicitly
(True) or not (False)

Raises
------
ValueError
If dims is provided and dir is bigger than len(dims)
NotImplementedError
If engine is neither numpy, scipy, nor fftw

Notes
-----
The Shift operator applies the forward Fourier transform, an element-wise
complex scaling, and inverse fourier transform

.. math::
\mathbf{y}= \mathbf{F}^{-1} \mathbf{S} \mathbf{F} \mathbf{x}

Here :math:\mathbf{S} is a diagonal operator that scales the Fourier
transformed input by :math:e^{-j2\pi f t_S}, where :math:t_S is the
chosen shift.

"""
# TODO: Use offer the same keywords as new FFT
Fop = FFT(
dims, dir, nfft, sampling, real=real, engine=engine, dtype=dtype, **kwargs_fftw
)
if isinstance(dims, int):
dimsdiag = None
else:
dimsdiag = list(dims)
dimsdiag[dir] = len(Fop.f)
shift = np.exp(-1j * 2 * np.pi * Fop.f * shift)
Sop = Diagonal(shift, dims=dimsdiag, dir=dir, dtype=Fop.cdtype)
Op = Fop.H * Sop * Fop
# force dtype to that of input (FFT always upcasts it to complex)
Op.dtype = dtype
return Op