We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unexpected crush with J=1 
Hi, 

I faced the following problem: I get unexpected and unexplained crush when J=1 regardless of other parameters values. Please, find the code and the error message below. 

Here's the code:

```
data = torch.Tensor(np.random.rand(128,3,32,32))
print("shape before scattering: {}".format(data.shape))

scatModel = Scattering2D(J=1,L=8, shape = (32,32), max_order=2)
a = scatModel(data)

print("shape after scattering: {}".format(a.shape))
```

And the error message: 

> shape before scattering: torch.Size([128, 3, 32, 32])
> Traceback (most recent call last):
>   File "/user/HS221/dm00314/PycharmProjects/ScatterNetsTestFramework/venv/mixingMallatTest.py", line 24, in <module>
>     a = scatModel(data)
>   File "/user/HS221/dm00314/PycharmProjects/ScatterNetsTestFramework/venv/lib/python3.5/site-packages/kymatio-0.2.0.dev0-py3.5.egg/kymatio/scattering2d/scattering2d.py", line 235, in __call__
>   File "/user/HS221/dm00314/PycharmProjects/ScatterNetsTestFramework/venv/lib/python3.5/site-packages/kymatio-0.2.0.dev0-py3.5.egg/kymatio/scattering2d/scattering2d.py", line 202, in forward
> KeyError: 0

Is it me or something is wrong?

Thank you, 
Dmitry

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

{"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@@ -46,7 +46,7 @@\n             psi_signal_fourier = fft2(psi_signal)\n             # drop the imaginary part, it is zero anyway\n             psi_signal_fourier = np.real(psi_signal_fourier)\n-            for res in range(min(j + 1, J - 1)):\n+            for res in range(min(j + 1, max(J - 1, 1))):\n                 psi_signal_fourier_res = periodize_filter_fft(\n                     psi_signal_fourier, res)\n                 # add a trailing singleton dimension to mark it as non-complex\n@@ -54,6 +54,7 @@\n                 psi[res] = psi_signal_fourier_res\n                 # Normalization to avoid doing it with the FFT.\n                 psi[res] /= M*N// 2**(2*j)\n+\n             filters['psi'].append(psi)\n \n     filters['phi'] = {}\n", "issue": "Unexpected crush with J=1 \nHi, \r\n\r\nI faced the following problem: I get unexpected and unexplained crush when J=1 regardless of other parameters values. Please, find the code and the error message below. \r\n\r\nHere's the code:\r\n\r\n```\r\ndata = torch.Tensor(np.random.rand(128,3,32,32))\r\nprint(\"shape before scattering: {}\".format(data.shape))\r\n\r\nscatModel = Scattering2D(J=1,L=8, shape = (32,32), max_order=2)\r\na = scatModel(data)\r\n\r\nprint(\"shape after scattering: {}\".format(a.shape))\r\n```\r\n\r\nAnd the error message: \r\n\r\n> shape before scattering: torch.Size([128, 3, 32, 32])\r\n> Traceback (most recent call last):\r\n>   File \"/user/HS221/dm00314/PycharmProjects/ScatterNetsTestFramework/venv/mixingMallatTest.py\", line 24, in <module>\r\n>     a = scatModel(data)\r\n>   File \"/user/HS221/dm00314/PycharmProjects/ScatterNetsTestFramework/venv/lib/python3.5/site-packages/kymatio-0.2.0.dev0-py3.5.egg/kymatio/scattering2d/scattering2d.py\", line 235, in __call__\r\n>   File \"/user/HS221/dm00314/PycharmProjects/ScatterNetsTestFramework/venv/lib/python3.5/site-packages/kymatio-0.2.0.dev0-py3.5.egg/kymatio/scattering2d/scattering2d.py\", line 202, in forward\r\n> KeyError: 0\r\n\r\nIs it me or something is wrong?\r\n\r\nThank you, \r\nDmitry\n", "before_files": [{"content": "\"\"\"\nAuthors: Eugene Belilovsky, Edouard Oyallon and Sergey Zagoruyko\nAll rights reserved, 2017.\n\"\"\"\n\n__all__ = ['filter_bank']\n\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    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)\n            psi_signal_fourier = fft2(psi_signal)\n            # drop the imaginary part, it is zero anyway\n            psi_signal_fourier = np.real(psi_signal_fourier)\n            for res in range(min(j + 1, J - 1)):\n                psi_signal_fourier_res = periodize_filter_fft(\n                    psi_signal_fourier, res)\n                # add a trailing singleton dimension to mark it as non-complex\n                psi_signal_fourier_res = psi_signal_fourier_res[..., np.newaxis]\n                psi[res] = psi_signal_fourier_res\n                # Normalization to avoid doing it with the FFT.\n                psi[res] /= 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)\n    phi_signal_fourier = fft2(phi_signal)\n    # drop the imaginary part, it is zero anyway\n    phi_signal_fourier = np.real(phi_signal_fourier)\n    filters['phi']['j'] = J\n    for res in range(J):\n        phi_signal_fourier_res = periodize_filter_fft(phi_signal_fourier, res)\n        # add a trailing singleton dimension to mark it as non-complex\n        phi_signal_fourier_res = phi_signal_fourier_res[..., np.newaxis]\n        filters['phi'][res] = phi_signal_fourier_res\n        # Normalization to avoid doing it with the FFT.\n        filters['phi'][res] /= 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), x.dtype)\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 += np.exp(arg)\n\n    norm_factor = (2 * 3.1415 * sigma * sigma / slant)\n    gab /= norm_factor\n\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 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    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)\n            psi_signal_fourier = fft2(psi_signal)\n            # drop the imaginary part, it is zero anyway\n            psi_signal_fourier = np.real(psi_signal_fourier)\n            for res in range(min(j + 1, max(J - 1, 1))):\n                psi_signal_fourier_res = periodize_filter_fft(\n                    psi_signal_fourier, res)\n                # add a trailing singleton dimension to mark it as non-complex\n                psi_signal_fourier_res = psi_signal_fourier_res[..., np.newaxis]\n                psi[res] = psi_signal_fourier_res\n                # Normalization to avoid doing it with the FFT.\n                psi[res] /= M*N// 2**(2*j)\n\n            filters['psi'].append(psi)\n\n    filters['phi'] = {}\n    phi_signal = gabor_2d(M, N, 0.8 * 2**(J-1), 0, 0)\n    phi_signal_fourier = fft2(phi_signal)\n    # drop the imaginary part, it is zero anyway\n    phi_signal_fourier = np.real(phi_signal_fourier)\n    filters['phi']['j'] = J\n    for res in range(J):\n        phi_signal_fourier_res = periodize_filter_fft(phi_signal_fourier, res)\n        # add a trailing singleton dimension to mark it as non-complex\n        phi_signal_fourier_res = phi_signal_fourier_res[..., np.newaxis]\n        filters['phi'][res] = phi_signal_fourier_res\n        # Normalization to avoid doing it with the FFT.\n        filters['phi'][res] /= 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), x.dtype)\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 += np.exp(arg)\n\n    norm_factor = (2 * 3.1415 * sigma * sigma / slant)\n    gab /= norm_factor\n\n    return gab\n", "path": "kymatio/scattering2d/filter_bank.py"}]}