We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unused `fftshift` option
In the `gabor_2d` function, we have an [`fftshift` argument](https://github.com/kymatio/kymatio/blob/02f31a7824011ef7c7c1145342473d32a1133b51/kymatio/scattering2d/filter_bank.py#L196) that is never used. Is there a reason for keeping this?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kymatio/scattering2d/filter_bank.py`
Content:
```
1 """
2 Authors: Eugene Belilovsky, Edouard Oyallon and Sergey Zagoruyko
3 All rights reserved, 2017.
4 """
5 
6 __all__ = ['filter_bank']
7 
8 import torch
9 import numpy as np
10 from .utils import fft2
11 
12 
13 def filter_bank(M, N, J, L=8):
14     """
15         Builds in Fourier the Morlet filters used for the scattering transform.
16         Each single filter is provided as a dictionary with the following keys:
17         * 'j' : scale
18         * 'theta' : angle used
19         Parameters
20         ----------
21         M, N : int
22             spatial support of the input
23         J : int
24             logscale of the scattering
25         L : int, optional
26             number of angles used for the wavelet transform
27         Returns
28         -------
29         filters : list
30             A two list of dictionary containing respectively the low-pass and
31              wavelet filters.
32         Notes
33         -----
34         The design of the filters is optimized for the value L = 8.
35     """
36     filters = {}
37     filters['psi'] = []
38 
39     offset_unpad = 0
40     for j in range(J):
41         for theta in range(L):
42             psi = {}
43             psi['j'] = j
44             psi['theta'] = theta
45             psi_signal = morlet_2d(M, N, 0.8 * 2**j,
46                 (int(L-L/2-1)-theta) * np.pi / L,
47                 3.0 / 4.0 * np.pi /2**j, 4.0/L, offset=offset_unpad)
48             psi_signal_fourier = fft2(psi_signal)
49             for res in range(min(j + 1, J - 1)):
50                 psi_signal_fourier_res = periodize_filter_fft(
51                     psi_signal_fourier, res)
52                 psi[res] = torch.FloatTensor(
53                     np.stack((np.real(psi_signal_fourier_res),
54                     np.imag(psi_signal_fourier_res)), axis=2))
55                 # Normalization to avoid doing it with the FFT.
56                 psi[res].div_(M*N// 2**(2*j))
57             filters['psi'].append(psi)
58 
59     filters['phi'] = {}
60     phi_signal = gabor_2d(M, N, 0.8 * 2**(J-1), 0, 0, offset=offset_unpad)
61     phi_signal_fourier = fft2(phi_signal)
62     filters['phi']['j'] = J
63     for res in range(J):
64         phi_signal_fourier_res = periodize_filter_fft(phi_signal_fourier, res)
65         filters['phi'][res] = torch.FloatTensor(np.stack(
66             (np.real(phi_signal_fourier_res), np.imag(phi_signal_fourier_res)),
67             axis=2))
68         filters['phi'][res].div_(M*N // 2 ** (2 * J))
69 
70     return filters
71 
72 
73 def periodize_filter_fft(x, res):
74     """
75         Parameters
76         ----------
77         x : numpy array
78             signal to periodize in Fourier
79         res :
80             resolution to which the signal is cropped.
81 
82         Returns
83         -------
84         crop : numpy array
85             It returns a crop version of the filter, assuming that
86              the convolutions will be done via compactly supported signals.
87     """
88     M = x.shape[0]
89     N = x.shape[1]
90 
91     crop = np.zeros((M // 2 ** res, N // 2 ** res), np.complex64)
92 
93     mask = np.ones(x.shape, np.float32)
94     len_x = int(M * (1 - 2 ** (-res)))
95     start_x = int(M * 2 ** (-res - 1))
96     len_y = int(N * (1 - 2 ** (-res)))
97     start_y = int(N * 2 ** (-res - 1))
98     mask[start_x:start_x + len_x,:] = 0
99     mask[:, start_y:start_y + len_y] = 0
100     x = np.multiply(x,mask)
101 
102     for k in range(int(M / 2 ** res)):
103         for l in range(int(N / 2 ** res)):
104             for i in range(int(2 ** res)):
105                 for j in range(int(2 ** res)):
106                     crop[k, l] += x[k + i * int(M / 2 ** res), l + j * int(N / 2 ** res)]
107 
108     return crop
109 
110 
111 def morlet_2d(M, N, sigma, theta, xi, slant=0.5, offset=0, fft_shift=False):
112     """
113         Computes a 2D Morlet filter.
114         A Morlet filter is the sum of a Gabor filter and a low-pass filter
115         to ensure that the sum has exactly zero mean in the temporal domain.
116         It is defined by the following formula in space:
117         psi(u) = g_{sigma}(u) (e^(i xi^T u) - beta)
118         where g_{sigma} is a Gaussian envelope, xi is a frequency and beta is
119         the cancelling parameter.
120 
121         Parameters
122         ----------
123         M, N : int
124             spatial sizes
125         sigma : float
126             bandwidth parameter
127         xi : float
128             central frequency (in [0, 1])
129         theta : float
130             angle in [0, pi]
131         slant : float, optional
132             parameter which guides the elipsoidal shape of the morlet
133         offset : int, optional
134             offset by which the signal starts
135         fft_shift : boolean
136             if true, shift the signal in a numpy style
137 
138         Returns
139         -------
140         morlet_fft : ndarray
141             numpy array of size (M, N)
142     """
143     wv = gabor_2d(M, N, sigma, theta, xi, slant, offset, fft_shift)
144     wv_modulus = gabor_2d(M, N, sigma, theta, 0, slant, offset, fft_shift)
145     K = np.sum(wv) / np.sum(wv_modulus)
146 
147     mor = wv - K * wv_modulus
148     return mor
149 
150 
151 def gabor_2d(M, N, sigma, theta, xi, slant=1.0, offset=0, fft_shift=False):
152     """
153         Computes a 2D Gabor filter.
154         A Gabor filter is defined by the following formula in space:
155         psi(u) = g_{sigma}(u) e^(i xi^T u)
156         where g_{sigma} is a Gaussian envelope and xi is a frequency.
157 
158         Parameters
159         ----------
160         M, N : int
161             spatial sizes
162         sigma : float
163             bandwidth parameter
164         xi : float
165             central frequency (in [0, 1])
166         theta : float
167             angle in [0, pi]
168         slant : float, optional
169             parameter which guides the elipsoidal shape of the morlet
170         offset : int, optional
171             offset by which the signal starts
172         fft_shift : boolean
173             if true, shift the signal in a numpy style
174 
175         Returns
176         -------
177         morlet_fft : ndarray
178             numpy array of size (M, N)
179     """
180     gab = np.zeros((M, N), np.complex64)
181     R = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]], np.float32)
182     R_inv = np.array([[np.cos(theta), np.sin(theta)], [-np.sin(theta), np.cos(theta)]], np.float32)
183     D = np.array([[1, 0], [0, slant * slant]])
184     curv = np.dot(R, np.dot(D, R_inv)) / ( 2 * sigma * sigma)
185 
186     for ex in [-2, -1, 0, 1, 2]:
187         for ey in [-2, -1, 0, 1, 2]:
188             [xx, yy] = np.mgrid[offset + ex * M:offset + M + ex * M, offset + ey * N:offset + N + ey * N]
189             arg = -(curv[0, 0] * np.multiply(xx, xx) + (curv[0, 1] + curv[1, 0]) * np.multiply(xx, yy) + curv[
190                 1, 1] * np.multiply(yy, yy)) + 1.j * (xx * xi * np.cos(theta) + yy * xi * np.sin(theta))
191             gab = gab + np.exp(arg)
192 
193     norm_factor = (2 * 3.1415 * sigma * sigma / slant)
194     gab = gab / norm_factor
195 
196     if (fft_shift):
197         gab = np.fft.fftshift(gab, axes=(0, 1))
198     return gab
199
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kymatio/scattering2d/filter_bank.py b/kymatio/scattering2d/filter_bank.py
--- a/kymatio/scattering2d/filter_bank.py
+++ b/kymatio/scattering2d/filter_bank.py
@@ -108,7 +108,7 @@
     return crop
 
 
-def morlet_2d(M, N, sigma, theta, xi, slant=0.5, offset=0, fft_shift=False):
+def morlet_2d(M, N, sigma, theta, xi, slant=0.5, offset=0):
     """
         Computes a 2D Morlet filter.
         A Morlet filter is the sum of a Gabor filter and a low-pass filter
@@ -132,23 +132,21 @@
             parameter which guides the elipsoidal shape of the morlet
         offset : int, optional
             offset by which the signal starts
-        fft_shift : boolean
-            if true, shift the signal in a numpy style
 
         Returns
         -------
         morlet_fft : ndarray
             numpy array of size (M, N)
     """
-    wv = gabor_2d(M, N, sigma, theta, xi, slant, offset, fft_shift)
-    wv_modulus = gabor_2d(M, N, sigma, theta, 0, slant, offset, fft_shift)
+    wv = gabor_2d(M, N, sigma, theta, xi, slant, offset)
+    wv_modulus = gabor_2d(M, N, sigma, theta, 0, slant, offset)
     K = np.sum(wv) / np.sum(wv_modulus)
 
     mor = wv - K * wv_modulus
     return mor
 
 
-def gabor_2d(M, N, sigma, theta, xi, slant=1.0, offset=0, fft_shift=False):
+def gabor_2d(M, N, sigma, theta, xi, slant=1.0, offset=0):
     """
         Computes a 2D Gabor filter.
         A Gabor filter is defined by the following formula in space:
@@ -169,8 +167,6 @@
             parameter which guides the elipsoidal shape of the morlet
         offset : int, optional
             offset by which the signal starts
-        fft_shift : boolean
-            if true, shift the signal in a numpy style
 
         Returns
         -------
@@ -192,7 +188,4 @@
 
     norm_factor = (2 * 3.1415 * sigma * sigma / slant)
     gab = gab / norm_factor
-
-    if (fft_shift):
-        gab = np.fft.fftshift(gab, axes=(0, 1))
     return gab

{"golden_diff": "diff --git a/kymatio/scattering2d/filter_bank.py b/kymatio/scattering2d/filter_bank.py\n--- a/kymatio/scattering2d/filter_bank.py\n+++ b/kymatio/scattering2d/filter_bank.py\n@@ -108,7 +108,7 @@\n     return crop\n \n \n-def morlet_2d(M, N, sigma, theta, xi, slant=0.5, offset=0, fft_shift=False):\n+def morlet_2d(M, N, sigma, theta, xi, slant=0.5, offset=0):\n     \"\"\"\n         Computes a 2D Morlet filter.\n         A Morlet filter is the sum of a Gabor filter and a low-pass filter\n@@ -132,23 +132,21 @@\n             parameter which guides the elipsoidal shape of the morlet\n         offset : int, optional\n             offset by which the signal starts\n-        fft_shift : boolean\n-            if true, shift the signal in a numpy style\n \n         Returns\n         -------\n         morlet_fft : ndarray\n             numpy array of size (M, N)\n     \"\"\"\n-    wv = gabor_2d(M, N, sigma, theta, xi, slant, offset, fft_shift)\n-    wv_modulus = gabor_2d(M, N, sigma, theta, 0, slant, offset, fft_shift)\n+    wv = gabor_2d(M, N, sigma, theta, xi, slant, offset)\n+    wv_modulus = gabor_2d(M, N, sigma, theta, 0, slant, offset)\n     K = np.sum(wv) / np.sum(wv_modulus)\n \n     mor = wv - K * wv_modulus\n     return mor\n \n \n-def gabor_2d(M, N, sigma, theta, xi, slant=1.0, offset=0, fft_shift=False):\n+def gabor_2d(M, N, sigma, theta, xi, slant=1.0, offset=0):\n     \"\"\"\n         Computes a 2D Gabor filter.\n         A Gabor filter is defined by the following formula in space:\n@@ -169,8 +167,6 @@\n             parameter which guides the elipsoidal shape of the morlet\n         offset : int, optional\n             offset by which the signal starts\n-        fft_shift : boolean\n-            if true, shift the signal in a numpy style\n \n         Returns\n         -------\n@@ -192,7 +188,4 @@\n \n     norm_factor = (2 * 3.1415 * sigma * sigma / slant)\n     gab = gab / norm_factor\n-\n-    if (fft_shift):\n-        gab = np.fft.fftshift(gab, axes=(0, 1))\n     return gab\n", "issue": "Unused `fftshift` option\nIn the `gabor_2d` function, we have an [`fftshift` argument](https://github.com/kymatio/kymatio/blob/02f31a7824011ef7c7c1145342473d32a1133b51/kymatio/scattering2d/filter_bank.py#L196) that is never used. Is there a reason for keeping this?\n", "before_files": [{"content": "\"\"\"\nAuthors: Eugene Belilovsky, Edouard Oyallon and Sergey Zagoruyko\nAll rights reserved, 2017.\n\"\"\"\n\n__all__ = ['filter_bank']\n\nimport torch\nimport numpy as np\nfrom .utils import fft2\n\n\ndef filter_bank(M, N, J, L=8):\n    \"\"\"\n        Builds in Fourier the Morlet filters used for the scattering transform.\n        Each single filter is provided as a dictionary with the following keys:\n        * 'j' : scale\n        * 'theta' : angle used\n        Parameters\n        ----------\n        M, N : int\n            spatial support of the input\n        J : int\n            logscale of the scattering\n        L : int, optional\n            number of angles used for the wavelet transform\n        Returns\n        -------\n        filters : list\n            A two list of dictionary containing respectively the low-pass and\n             wavelet filters.\n        Notes\n        -----\n        The design of the filters is optimized for the value L = 8.\n    \"\"\"\n    filters = {}\n    filters['psi'] = []\n\n    offset_unpad = 0\n    for j in range(J):\n        for theta in range(L):\n            psi = {}\n            psi['j'] = j\n            psi['theta'] = theta\n            psi_signal = morlet_2d(M, N, 0.8 * 2**j,\n                (int(L-L/2-1)-theta) * np.pi / L,\n                3.0 / 4.0 * np.pi /2**j, 4.0/L, offset=offset_unpad)\n            psi_signal_fourier = fft2(psi_signal)\n            for res in range(min(j + 1, J - 1)):\n                psi_signal_fourier_res = periodize_filter_fft(\n                    psi_signal_fourier, res)\n                psi[res] = torch.FloatTensor(\n                    np.stack((np.real(psi_signal_fourier_res),\n                    np.imag(psi_signal_fourier_res)), axis=2))\n                # Normalization to avoid doing it with the FFT.\n                psi[res].div_(M*N// 2**(2*j))\n            filters['psi'].append(psi)\n\n    filters['phi'] = {}\n    phi_signal = gabor_2d(M, N, 0.8 * 2**(J-1), 0, 0, offset=offset_unpad)\n    phi_signal_fourier = fft2(phi_signal)\n    filters['phi']['j'] = J\n    for res in range(J):\n        phi_signal_fourier_res = periodize_filter_fft(phi_signal_fourier, res)\n        filters['phi'][res] = torch.FloatTensor(np.stack(\n            (np.real(phi_signal_fourier_res), np.imag(phi_signal_fourier_res)),\n            axis=2))\n        filters['phi'][res].div_(M*N // 2 ** (2 * J))\n\n    return filters\n\n\ndef periodize_filter_fft(x, res):\n    \"\"\"\n        Parameters\n        ----------\n        x : numpy array\n            signal to periodize in Fourier\n        res :\n            resolution to which the signal is cropped.\n\n        Returns\n        -------\n        crop : numpy array\n            It returns a crop version of the filter, assuming that\n             the convolutions will be done via compactly supported signals.\n    \"\"\"\n    M = x.shape[0]\n    N = x.shape[1]\n\n    crop = np.zeros((M // 2 ** res, N // 2 ** res), np.complex64)\n\n    mask = np.ones(x.shape, np.float32)\n    len_x = int(M * (1 - 2 ** (-res)))\n    start_x = int(M * 2 ** (-res - 1))\n    len_y = int(N * (1 - 2 ** (-res)))\n    start_y = int(N * 2 ** (-res - 1))\n    mask[start_x:start_x + len_x,:] = 0\n    mask[:, start_y:start_y + len_y] = 0\n    x = np.multiply(x,mask)\n\n    for k in range(int(M / 2 ** res)):\n        for l in range(int(N / 2 ** res)):\n            for i in range(int(2 ** res)):\n                for j in range(int(2 ** res)):\n                    crop[k, l] += x[k + i * int(M / 2 ** res), l + j * int(N / 2 ** res)]\n\n    return crop\n\n\ndef morlet_2d(M, N, sigma, theta, xi, slant=0.5, offset=0, fft_shift=False):\n    \"\"\"\n        Computes a 2D Morlet filter.\n        A Morlet filter is the sum of a Gabor filter and a low-pass filter\n        to ensure that the sum has exactly zero mean in the temporal domain.\n        It is defined by the following formula in space:\n        psi(u) = g_{sigma}(u) (e^(i xi^T u) - beta)\n        where g_{sigma} is a Gaussian envelope, xi is a frequency and beta is\n        the cancelling parameter.\n\n        Parameters\n        ----------\n        M, N : int\n            spatial sizes\n        sigma : float\n            bandwidth parameter\n        xi : float\n            central frequency (in [0, 1])\n        theta : float\n            angle in [0, pi]\n        slant : float, optional\n            parameter which guides the elipsoidal shape of the morlet\n        offset : int, optional\n            offset by which the signal starts\n        fft_shift : boolean\n            if true, shift the signal in a numpy style\n\n        Returns\n        -------\n        morlet_fft : ndarray\n            numpy array of size (M, N)\n    \"\"\"\n    wv = gabor_2d(M, N, sigma, theta, xi, slant, offset, fft_shift)\n    wv_modulus = gabor_2d(M, N, sigma, theta, 0, slant, offset, fft_shift)\n    K = np.sum(wv) / np.sum(wv_modulus)\n\n    mor = wv - K * wv_modulus\n    return mor\n\n\ndef gabor_2d(M, N, sigma, theta, xi, slant=1.0, offset=0, fft_shift=False):\n    \"\"\"\n        Computes a 2D Gabor filter.\n        A Gabor filter is defined by the following formula in space:\n        psi(u) = g_{sigma}(u) e^(i xi^T u)\n        where g_{sigma} is a Gaussian envelope and xi is a frequency.\n\n        Parameters\n        ----------\n        M, N : int\n            spatial sizes\n        sigma : float\n            bandwidth parameter\n        xi : float\n            central frequency (in [0, 1])\n        theta : float\n            angle in [0, pi]\n        slant : float, optional\n            parameter which guides the elipsoidal shape of the morlet\n        offset : int, optional\n            offset by which the signal starts\n        fft_shift : boolean\n            if true, shift the signal in a numpy style\n\n        Returns\n        -------\n        morlet_fft : ndarray\n            numpy array of size (M, N)\n    \"\"\"\n    gab = np.zeros((M, N), np.complex64)\n    R = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]], np.float32)\n    R_inv = np.array([[np.cos(theta), np.sin(theta)], [-np.sin(theta), np.cos(theta)]], np.float32)\n    D = np.array([[1, 0], [0, slant * slant]])\n    curv = np.dot(R, np.dot(D, R_inv)) / ( 2 * sigma * sigma)\n\n    for ex in [-2, -1, 0, 1, 2]:\n        for ey in [-2, -1, 0, 1, 2]:\n            [xx, yy] = np.mgrid[offset + ex * M:offset + M + ex * M, offset + ey * N:offset + N + ey * N]\n            arg = -(curv[0, 0] * np.multiply(xx, xx) + (curv[0, 1] + curv[1, 0]) * np.multiply(xx, yy) + curv[\n                1, 1] * np.multiply(yy, yy)) + 1.j * (xx * xi * np.cos(theta) + yy * xi * np.sin(theta))\n            gab = gab + np.exp(arg)\n\n    norm_factor = (2 * 3.1415 * sigma * sigma / slant)\n    gab = gab / norm_factor\n\n    if (fft_shift):\n        gab = np.fft.fftshift(gab, axes=(0, 1))\n    return gab\n", "path": "kymatio/scattering2d/filter_bank.py"}], "after_files": [{"content": "\"\"\"\nAuthors: Eugene Belilovsky, Edouard Oyallon and Sergey Zagoruyko\nAll rights reserved, 2017.\n\"\"\"\n\n__all__ = ['filter_bank']\n\nimport torch\nimport numpy as np\nfrom .utils import fft2\n\n\ndef filter_bank(M, N, J, L=8):\n    \"\"\"\n        Builds in Fourier the Morlet filters used for the scattering transform.\n        Each single filter is provided as a dictionary with the following keys:\n        * 'j' : scale\n        * 'theta' : angle used\n        Parameters\n        ----------\n        M, N : int\n            spatial support of the input\n        J : int\n            logscale of the scattering\n        L : int, optional\n            number of angles used for the wavelet transform\n        Returns\n        -------\n        filters : list\n            A two list of dictionary containing respectively the low-pass and\n             wavelet filters.\n        Notes\n        -----\n        The design of the filters is optimized for the value L = 8.\n    \"\"\"\n    filters = {}\n    filters['psi'] = []\n\n    offset_unpad = 0\n    for j in range(J):\n        for theta in range(L):\n            psi = {}\n            psi['j'] = j\n            psi['theta'] = theta\n            psi_signal = morlet_2d(M, N, 0.8 * 2**j,\n                (int(L-L/2-1)-theta) * np.pi / L,\n                3.0 / 4.0 * np.pi /2**j, 4.0/L, offset=offset_unpad)\n            psi_signal_fourier = fft2(psi_signal)\n            for res in range(min(j + 1, J - 1)):\n                psi_signal_fourier_res = periodize_filter_fft(\n                    psi_signal_fourier, res)\n                psi[res] = torch.FloatTensor(\n                    np.stack((np.real(psi_signal_fourier_res),\n                    np.imag(psi_signal_fourier_res)), axis=2))\n                # Normalization to avoid doing it with the FFT.\n                psi[res].div_(M*N// 2**(2*j))\n            filters['psi'].append(psi)\n\n    filters['phi'] = {}\n    phi_signal = gabor_2d(M, N, 0.8 * 2**(J-1), 0, 0, offset=offset_unpad)\n    phi_signal_fourier = fft2(phi_signal)\n    filters['phi']['j'] = J\n    for res in range(J):\n        phi_signal_fourier_res = periodize_filter_fft(phi_signal_fourier, res)\n        filters['phi'][res] = torch.FloatTensor(np.stack(\n            (np.real(phi_signal_fourier_res), np.imag(phi_signal_fourier_res)),\n            axis=2))\n        filters['phi'][res].div_(M*N // 2 ** (2 * J))\n\n    return filters\n\n\ndef periodize_filter_fft(x, res):\n    \"\"\"\n        Parameters\n        ----------\n        x : numpy array\n            signal to periodize in Fourier\n        res :\n            resolution to which the signal is cropped.\n\n        Returns\n        -------\n        crop : numpy array\n            It returns a crop version of the filter, assuming that\n             the convolutions will be done via compactly supported signals.\n    \"\"\"\n    M = x.shape[0]\n    N = x.shape[1]\n\n    crop = np.zeros((M // 2 ** res, N // 2 ** res), np.complex64)\n\n    mask = np.ones(x.shape, np.float32)\n    len_x = int(M * (1 - 2 ** (-res)))\n    start_x = int(M * 2 ** (-res - 1))\n    len_y = int(N * (1 - 2 ** (-res)))\n    start_y = int(N * 2 ** (-res - 1))\n    mask[start_x:start_x + len_x,:] = 0\n    mask[:, start_y:start_y + len_y] = 0\n    x = np.multiply(x,mask)\n\n    for k in range(int(M / 2 ** res)):\n        for l in range(int(N / 2 ** res)):\n            for i in range(int(2 ** res)):\n                for j in range(int(2 ** res)):\n                    crop[k, l] += x[k + i * int(M / 2 ** res), l + j * int(N / 2 ** res)]\n\n    return crop\n\n\ndef morlet_2d(M, N, sigma, theta, xi, slant=0.5, offset=0):\n    \"\"\"\n        Computes a 2D Morlet filter.\n        A Morlet filter is the sum of a Gabor filter and a low-pass filter\n        to ensure that the sum has exactly zero mean in the temporal domain.\n        It is defined by the following formula in space:\n        psi(u) = g_{sigma}(u) (e^(i xi^T u) - beta)\n        where g_{sigma} is a Gaussian envelope, xi is a frequency and beta is\n        the cancelling parameter.\n\n        Parameters\n        ----------\n        M, N : int\n            spatial sizes\n        sigma : float\n            bandwidth parameter\n        xi : float\n            central frequency (in [0, 1])\n        theta : float\n            angle in [0, pi]\n        slant : float, optional\n            parameter which guides the elipsoidal shape of the morlet\n        offset : int, optional\n            offset by which the signal starts\n\n        Returns\n        -------\n        morlet_fft : ndarray\n            numpy array of size (M, N)\n    \"\"\"\n    wv = gabor_2d(M, N, sigma, theta, xi, slant, offset)\n    wv_modulus = gabor_2d(M, N, sigma, theta, 0, slant, offset)\n    K = np.sum(wv) / np.sum(wv_modulus)\n\n    mor = wv - K * wv_modulus\n    return mor\n\n\ndef gabor_2d(M, N, sigma, theta, xi, slant=1.0, offset=0):\n    \"\"\"\n        Computes a 2D Gabor filter.\n        A Gabor filter is defined by the following formula in space:\n        psi(u) = g_{sigma}(u) e^(i xi^T u)\n        where g_{sigma} is a Gaussian envelope and xi is a frequency.\n\n        Parameters\n        ----------\n        M, N : int\n            spatial sizes\n        sigma : float\n            bandwidth parameter\n        xi : float\n            central frequency (in [0, 1])\n        theta : float\n            angle in [0, pi]\n        slant : float, optional\n            parameter which guides the elipsoidal shape of the morlet\n        offset : int, optional\n            offset by which the signal starts\n\n        Returns\n        -------\n        morlet_fft : ndarray\n            numpy array of size (M, N)\n    \"\"\"\n    gab = np.zeros((M, N), np.complex64)\n    R = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]], np.float32)\n    R_inv = np.array([[np.cos(theta), np.sin(theta)], [-np.sin(theta), np.cos(theta)]], np.float32)\n    D = np.array([[1, 0], [0, slant * slant]])\n    curv = np.dot(R, np.dot(D, R_inv)) / ( 2 * sigma * sigma)\n\n    for ex in [-2, -1, 0, 1, 2]:\n        for ey in [-2, -1, 0, 1, 2]:\n            [xx, yy] = np.mgrid[offset + ex * M:offset + M + ex * M, offset + ey * N:offset + N + ey * N]\n            arg = -(curv[0, 0] * np.multiply(xx, xx) + (curv[0, 1] + curv[1, 0]) * np.multiply(xx, yy) + curv[\n                1, 1] * np.multiply(yy, yy)) + 1.j * (xx * xi * np.cos(theta) + yy * xi * np.sin(theta))\n            gab = gab + np.exp(arg)\n\n    norm_factor = (2 * 3.1415 * sigma * sigma / slant)\n    gab = gab / norm_factor\n    return gab\n", "path": "kymatio/scattering2d/filter_bank.py"}]}