code: def seq_kernel(
      X,
      kernelfun=None,
      L=2,
      D=1,
      theta=1.0,
      normalize=False,
      lowrank=False,
      rankbound=float("inf"),
  ):
      """Compute the sequential kernel between sequence/time series.
  
      Provides interface for vanilla sequential kernel, low-rank, and higher-order.
  
      Parameters
      ----------
      X : 3D np.ndarray of shape (N, d, _)
          collection of sequences/time series
          1st index = instance index
          2nd index = variable/feature index
          3rd index = time index
      kernelfun : function (2D np.ndarray x 2D np.ndarray) -> 2D np.ndarray
          pairwise kernel function, matrix sizes (n, d) x (m, d) -> (n x m)
          optional, default = Euclidean (linear) kernel with scale parameter 1
      L : int, optional, default = 2
          an integer >= 1, representing the level of truncation
      D : int, optional, default = 1
          an integer >= 1, representing the order of approximation
          can be set only if lowrank = False, otherwise ignored (always = 1)
      theta : float, optional, default=1.0
          a positive scaling factor for the levels, i-th level is scaled by theta^i
      normalize : bool, optional, default = False
          whether the output kernel matrix is normalized
          if True, sums and cumsums are divided by prod(K.shape)
      lowrank : bool, optional, default = False
          whether to use low rank approximation in computing the kernel
      rankbound : int, optional, default = infinity
          a hard threshold for the rank of the level matrices
          used only if lowrank = True
  
      Returns
      -------
      np.ndarray of shape (N, N), sequential kernel matrix
          [i,j]-th entry is sequential kernel between X[i] and X[j]
      """
      N = np.shape(X)[0]
      KSeq = np.zeros((N, N))
  
      if kernelfun is None:
          kernelfun = partial(k_euclid, scale=1)
  
      if not lowrank:
          if D == 1:
              for row1ind in range(N):
                  for row2ind in range(row1ind + 1):
                      KSeq[row1ind, row2ind] = sqize_kernel(
                          K=kernelfun(X[row1ind].T, X[row2ind].T),
                          L=L,
                          theta=theta,
                          normalize=normalize,
                      )
          else:
              for row1ind in range(N):
                  for row2ind in range(row1ind + 1):
                      KSeq[row1ind, row2ind] = sqize_kernel_ho(
                          K=kernelfun(X[row1ind].T, X[row2ind].T),
                          L=L,
                          D=D,
                          theta=theta,
                          normalize=normalize,
                      )
      else:
          R = sqize_kernel_low_rank_fast(
              K=X.transpose([0, 2, 1]),
              L=L,
              theta=theta,
              normalize=normalize,
              rankbound=rankbound,
          )
          KSeq = np.inner(R, R)
          # todo: kernelfun gives back a LRdec object
          #  for now, linear low-rank approximation is done
          # KSeq[row1ind,row2ind] = qqize_kernel_low_rank(
          #   kernelfun(X[row1ind].T,X[row2ind].T),L,theta,normalize = True)
      return mirror(KSeq)
  
imports: import collections
  from functools import partial
  import numpy
  from scipy.sparse.linalg import svds
  from sklearn.base import BaseEstimator, TransformerMixin
  from sktime.dists_kernels.base import BasePairwiseTransformerPanel
label_desc: Use image node_id 30 for calling a global function with example usage: seq_kernel(X, kernelfun, L, D, theta, normalize, lowrank, rankbound) and returns: mirror