Repository: kymatio/kymatio

Issue:
T → N
As part of our discussion on separating the wavelet scale from the averaging scale, we realized that the variable T is already being used in 1D for the size of the signals. In the 2D code (and in scatnet, I think), this is denoted N, so I suggest we rename T to N. This would then free up T as the averaging scale parameter.


Discussion:
Ping @lostanlen.
yes, N is good. Eventually i'd like to make this argument optional (i.e. defaulting to some multiple of Q * 2**J) and rely on overlap-add convolutions (#305). But it's too early for that.

Agreed. Will put together a PR.
Agreed. Will put together a PR.

Resolving patch:
diff --git a/kymatio/scattering1d/core/scattering1d.py b/kymatio/scattering1d/core/scattering1d.py
--- a/kymatio/scattering1d/core/scattering1d.py
+++ b/kymatio/scattering1d/core/scattering1d.py
@@ -8,7 +8,7 @@ def scattering1d(x, pad, unpad, backend, J, psi1, psi2, phi, pad_left=0,
     Parameters
     ----------
     x : Tensor
-        a torch Tensor of size `(B, 1, T)` where `T` is the temporal size
+        a torch Tensor of size `(B, 1, N)` where `N` is the temporal size
     psi1 : dictionary
         a dictionary of filters (in the Fourier domain), with keys (`j`, `q`).
         `j` corresponds to the downsampling factor for
diff --git a/kymatio/scattering1d/filter_bank.py b/kymatio/scattering1d/filter_bank.py
--- a/kymatio/scattering1d/filter_bank.py
+++ b/kymatio/scattering1d/filter_bank.py
@@ -258,20 +258,20 @@ def compute_temporal_support(h_f, criterion_amplitude=1e-3):
     Computes the (half) temporal support of a family of centered,
     symmetric filters h provided in the Fourier domain
 
-    This function computes the support T which is the smallest integer
+    This function computes the support N which is the smallest integer
     such that for all signals x and all filters h,
 
-    \\| x \\conv h - x \\conv h_{[-T, T]} \\|_{\\infty} \\leq \\epsilon
+    \\| x \\conv h - x \\conv h_{[-N, N]} \\|_{\\infty} \\leq \\epsilon
         \\| x \\|_{\\infty}  (1)
 
-    where 0<\\epsilon<1 is an acceptable error, and h_{[-T, T]} denotes the
-    filter h whose support is restricted in the interval [-T, T]
+    where 0<\\epsilon<1 is an acceptable error, and h_{[-N, N]} denotes the
+    filter h whose support is restricted in the interval [-N, N]
 
-    The resulting value T used to pad the signals to avoid boundary effects
+    The resulting value N used to pad the signals to avoid boundary effects
     and numerical errors.
 
-    If the support is too small, no such T might exist.
-    In this case, T is defined as the half of the support of h, and a
+    If the support is too small, no such N might exist.
+    In this case, N is defined as the half of the support of h, and a
     UserWarning is raised.
 
     Parameters
@@ -293,21 +293,21 @@ def compute_temporal_support(h_f, criterion_amplitude=1e-3):
     """
     h = ifft(h_f, axis=1)
     half_support = h.shape[1] // 2
-    # compute ||h - h_[-T, T]||_1
+    # compute ||h - h_[-N, N]||_1
     l1_residual = np.fliplr(
         np.cumsum(np.fliplr(np.abs(h)[:, :half_support]), axis=1))
     # find the first point above criterion_amplitude
     if np.any(np.max(l1_residual, axis=0) <= criterion_amplitude):
         # if it is possible
-        T = np.min(
+        N = np.min(
             np.where(np.max(l1_residual, axis=0) <= criterion_amplitude)[0])\
             + 1
     else:
         # if there is none:
-        T = half_support
+        N = half_support
         # Raise a warning to say that there will be border effects
         warnings.warn('Signal support is too small to avoid border effects')
-    return T
+    return N
 
 
 def get_max_dyadic_subsampling(xi, sigma, alpha=5.):
@@ -670,11 +670,11 @@ def scattering_filter_factory(J_support, J_scattering, Q, r_psi=math.sqrt(0.5),
         else:
             max_sub_psi2 = max_subsampling
         # We first compute the filter without subsampling
-        T = 2**J_support
+        N = 2**J_support
 
         psi_f = {}
         psi_f[0] = morlet_1d(
-            T, xi2[n2], sigma2[n2], normalize=normalize, P_max=P_max,
+            N, xi2[n2], sigma2[n2], normalize=normalize, P_max=P_max,
             eps=eps)
         # compute the filter after subsampling at all other subsamplings
         # which might be received by the network, based on this first filter
@@ -685,11 +685,11 @@ def scattering_filter_factory(J_support, J_scattering, Q, r_psi=math.sqrt(0.5),
         psi2_f.append(psi_f)
 
     # for the 1st order filters, the input is not subsampled so we
-    # can only compute them with T=2**J_support
+    # can only compute them with N=2**J_support
     for (n1, j1) in enumerate(j1s):
-        T = 2**J_support
+        N = 2**J_support
         psi1_f.append({0: morlet_1d(
-            T, xi1[n1], sigma1[n1], normalize=normalize,
+            N, xi1[n1], sigma1[n1], normalize=normalize,
             P_max=P_max, eps=eps)})
 
     # compute the low-pass filters phi
@@ -704,7 +704,7 @@ def scattering_filter_factory(J_support, J_scattering, Q, r_psi=math.sqrt(0.5),
         max_sub_phi = max_subsampling
 
     # compute the filters at all possible subsamplings
-    phi_f[0] = gauss_1d(T, sigma_low, P_max=P_max, eps=eps)
+    phi_f[0] = gauss_1d(N, sigma_low, P_max=P_max, eps=eps)
     for subsampling in range(1, max_sub_phi + 1):
         factor_subsampling = 2**subsampling
         # compute the low_pass filter
diff --git a/kymatio/scattering1d/frontend/base_frontend.py b/kymatio/scattering1d/frontend/base_frontend.py
--- a/kymatio/scattering1d/frontend/base_frontend.py
+++ b/kymatio/scattering1d/frontend/base_frontend.py
@@ -42,9 +42,9 @@ def build(self):
 
         # check the shape
         if isinstance(self.shape, numbers.Integral):
-            self.T = self.shape
+            self.N = self.shape
         elif isinstance(self.shape, tuple):
-            self.T = self.shape[0]
+            self.N = self.shape[0]
             if len(self.shape) > 1:
                 raise ValueError("If shape is specified as a tuple, it must "
                                  "have exactly one element")
@@ -53,20 +53,20 @@ def build(self):
 
         # Compute the minimum support to pad (ideally)
         min_to_pad = compute_minimum_support_to_pad(
-            self.T, self.J, self.Q, r_psi=self.r_psi, sigma0=self.sigma0,
+            self.N, self.J, self.Q, r_psi=self.r_psi, sigma0=self.sigma0,
             alpha=self.alpha, P_max=self.P_max, eps=self.eps,
             criterion_amplitude=self.criterion_amplitude,
             normalize=self.normalize)
-        # to avoid padding more than T - 1 on the left and on the right,
+        # to avoid padding more than N - 1 on the left and on the right,
         # since otherwise torch sends nans
-        J_max_support = int(np.floor(np.log2(3 * self.T - 2)))
-        self.J_pad = min(int(np.ceil(np.log2(self.T + 2 * min_to_pad))),
+        J_max_support = int(np.floor(np.log2(3 * self.N - 2)))
+        self.J_pad = min(int(np.ceil(np.log2(self.N + 2 * min_to_pad))),
                          J_max_support)
         # compute the padding quantities:
-        self.pad_left, self.pad_right = compute_padding(self.J_pad, self.T)
+        self.pad_left, self.pad_right = compute_padding(self.J_pad, self.N)
         # compute start and end indices
         self.ind_start, self.ind_end = compute_border_indices(
-            self.J, self.pad_left, self.pad_left + self.T)
+            self.J, self.pad_left, self.pad_left + self.N)
 
     def create_filters(self):
         # Create the filters
@@ -110,9 +110,9 @@ def output_size(self, detail=False):
         return precompute_size_scattering(
             self.J, self.Q, max_order=self.max_order, detail=detail)
 
-    _doc_shape = 'T'
+    _doc_shape = 'N'
 
-    _doc_instantiation_shape = {True: 'S = Scattering1D(J, T, Q)',
+    _doc_instantiation_shape = {True: 'S = Scattering1D(J, N, Q)',
                                 False: 'S = Scattering1D(J, Q)'}
 
     _doc_param_shape = \
@@ -221,12 +221,12 @@ def output_size(self, detail=False):
         :math:`S_J^{{(0)}} x`, $S_J^{{(1)}} x$, and $S_J^{{(2)}} x$ or just
         $S_J^{{(0)}} x$ and $S_J^{{(1)}} x$.
         {frontend_paragraph}
-        Given an input `{array}` `x` of shape `(B, T)`, where `B` is the
-        number of signals to transform (the batch size) and `T` is the length
+        Given an input `{array}` `x` of shape `(B, N)`, where `B` is the
+        number of signals to transform (the batch size) and `N` is the length
         of the signal, we compute its scattering transform by passing it to
         the `scattering` method (or calling the alias `{alias_name}`). Note
         that `B` can be one, in which case it may be omitted, giving an input
-        of shape `(T,)`.
+        of shape `(N,)`.
 
         Example
         -------
@@ -234,7 +234,7 @@ def output_size(self, detail=False):
 
             # Set the parameters of the scattering transform.
             J = 6
-            T = 2 ** 13
+            N = 2 ** 13
             Q = 8
 
             # Generate a sample signal.
@@ -249,7 +249,7 @@ def output_size(self, detail=False):
             # Equivalently, use the alias.
             Sx = S{alias_call}(x)
 
-        Above, the length of the signal is :math:`T = 2^{{13}} = 8192`, while the
+        Above, the length of the signal is :math:`N = 2^{{13}} = 8192`, while the
         maximum scale of the scattering transform is set to :math:`2^J = 2^6 =
         64`. The time-frequency resolution of the first-order wavelets
         :math:`\psi_\lambda^{{(1)}}(t)` is set to `Q = 8` wavelets per octave.
@@ -295,12 +295,12 @@ def output_size(self, detail=False):
     _doc_scattering = \
     """Apply the scattering transform
 
-       Given an input `{array}` of size `(B, T)`, where `B` is the batch
-       size (it can be potentially an integer or a shape) and `T` is the length
+       Given an input `{array}` of size `(B, N)`, where `B` is the batch
+       size (it can be potentially an integer or a shape) and `N` is the length
        of the individual signals, this function computes its scattering
        transform. If the `vectorize` flag is set to `True` (or if it is not
        available in this frontend), the output is in the form of a `{array}`
-       or size `(B, C, T1)`, where `T1` is the signal length after subsampling
+       or size `(B, C, N1)`, where `N1` is the signal length after subsampling
        to the scale :math:`2^J` (with the appropriate oversampling factor to
        reduce aliasing), and `C` is the number of scattering coefficients. If
        `vectorize` is set `False`, however, the output is a dictionary
@@ -326,7 +326,7 @@ def output_size(self, detail=False):
        Parameters
        ----------
        x : {array}
-           An input `{array}` of size `(B, T)`.
+           An input `{array}` of size `(B, N)`.
 
        Returns
        -------


Test patch: