class_docstr: CSP spatial filtering with covariance matrices as inputs.
  
  Implementation of the famous Common Spatial Pattern algorithm [1]_ [2]_,
  but with covariance matrices as input. In addition, the implementation
  allows different metric for the estimation of the class-related mean
  covariance matrices, as described in [3]_.
  
  This implementation support multiclass CSP by means of approximate joint
  diagonalization. In this case, the spatial filter selection is achieved
  according to [4]_.
  
  Parameters
  ----------
  nfilter : int, default=4
      The number of components to decompose M/EEG signals.
  metric : str, default='euclid'
      The metric for the estimation of mean covariance matrices.
  log : bool, default=True
      If true, return the log variance, otherwise return the spatially
      filtered covariance matrices.
  
  Attributes
  ----------
  filters_ : ndarray, shape (min(n_channels, n_filters), n_channels)
      If fit, the CSP spatial filters.
  patterns_ : ndarray, shape (min(n_channels, n_filters), n_channels)
      If fit, the CSP spatial patterns.
  
  See Also
  --------
  MDM, SPoC
  
  References
  ----------
  .. [1] `Spatial Patterns Underlying Population Differences in the
      Background EEG
      <https://link.springer.com/article/10.1007/BF01129656>`_
      Z. Koles, M. Lazar, and S. Zhou. Brain Topography 2(4), 275-284, 1990.
  .. [2] `Optimizing Spatial Filters for Robust EEG Single-Trial Analysis
      <https://ieeexplore.ieee.org/document/4408441>`_
      B. Blankertz, R. Tomioka, S. Lemm, M. Kawanabe, K-R. Muller. IEEE
      Signal Processing Magazine 25(1), 41-56, 2008.
  .. [3] `Common Spatial Pattern revisited by Riemannian geometry
      <https://hal.archives-ouvertes.fr/hal-00602686>`_
      A. Barachant, S. Bonnet, M. Congedo and C. Jutten. IEEE International
      Workshop on Multimedia Signal Processing (MMSP), p. 472-476, 2010.
  .. [4] `Multiclass common spatial patterns and information theoretic
      feature extraction
      <https://ieeexplore.ieee.org/document/4473042>`_
      IEEE Transactions on Biomedical Engineering, Volume 55, Issue 8,
      August 2008. pp. 1991 - 2000
docstr: Train CSP spatial filters.
  
  Parameters
  ----------
  X : ndarray, shape (n_trials, n_channels, n_channels)
      Set of covariance matrices.
  y : ndarray, shape (n_trials,)
      Labels for each trial.
  
  Returns
  -------
  self : CSP instance
      The CSP instance.
docstr_tok: ["Train","CSP","spatial","filters",".","Parameters","--","--","--","--","--","X",":","ndarray",",","shape","(","n_trials",",","n_channels",",","n_channels",")","Set","of","covariance","matrices",".","y",":","ndarray",",","shape","(","n_trials",",",")","Labels","for","each","trial",".","Returns","--","--","--","-","self",":","CSP","instance","The","CSP","instance","."]
code: def fit(self, X, y):
      """Train CSP spatial filters.
  
      Parameters
      ----------
      X : ndarray, shape (n_trials, n_channels, n_channels)
          Set of covariance matrices.
      y : ndarray, shape (n_trials,)
          Labels for each trial.
  
      Returns
      -------
      self : CSP instance
          The CSP instance.
      """
      if not isinstance(self.nfilter, int):
          raise TypeError("nfilter must be an integer")
      if not isinstance(self.log, bool):
          raise TypeError("log must be a boolean")
  
      if not isinstance(X, (np.ndarray, list)):
          raise TypeError("X must be an array.")
      if not isinstance(y, (np.ndarray, list)):
          raise TypeError("y must be an array.")
      X, y = np.asarray(X), np.asarray(y)
      if X.ndim != 3:
          raise ValueError(
              "X must be n_trials * n_channels * n_channels"
          )
      if len(y) != len(X):
          raise ValueError("X and y must have the same length.")
      if np.squeeze(y).ndim != 1:
          raise ValueError("y must be of shape (n_trials,).")
  
      n_trials, n_channels, _ = X.shape
      classes = np.unique(y)
      # estimate class means
      C = []
      for c in classes:
          C.append(mean_covariance(X[y == c], self.metric))
      C = np.array(C)
  
      # Switch between binary and multiclass
      if len(classes) == 2:
          evals, evecs = eigh(C[1], C[0] + C[1])
          # sort eigenvectors
          ix = np.argsort(np.abs(evals - 0.5))[::-1]
      elif len(classes) > 2:
          evecs, D = ajd_pham(C)
          Ctot = mean_covariance(C, self.metric)
          evecs = evecs.T
  
          # normalize
          for i in range(evecs.shape[1]):
              tmp = evecs[:, i].T @ Ctot @ evecs[:, i]
              evecs[:, i] /= np.sqrt(tmp)
  
          mutual_info = []
          # class probability
          Pc = [np.mean(y == c) for c in classes]
          for j in range(evecs.shape[1]):
              a = 0
              b = 0
              for i, c in enumerate(classes):
                  tmp = evecs[:, j].T @ C[i] @ evecs[:, j]
                  a += Pc[i] * np.log(np.sqrt(tmp))
                  b += Pc[i] * (tmp**2 - 1)
              mi = -(a + (3.0 / 16) * (b**2))
              mutual_info.append(mi)
          ix = np.argsort(mutual_info)[::-1]
      else:
          raise ValueError("Number of classes must be >= 2.")
  
      # sort eigenvectors
      evecs = evecs[:, ix]
  
      # spatial patterns
      A = np.linalg.pinv(evecs.T)
  
      self.filters_ = evecs[:, 0 : self.nfilter].T
      self.patterns_ = A[:, 0 : self.nfilter].T
  
      return self
  
imports: import warnings
  import numpy
  from scipy.linalg import eigh, inv
  from sklearn.base import BaseEstimator, TransformerMixin
  from .utils.covariance import _check_cov_est_function, normalize, get_nondiag_weight
  from .utils.mean import mean_covariance
  from .utils.ajd import ajd_pham
  from .None import estimation
  from .preprocessing import Whitening
label_desc: Use image node_id 2 for calling the CSP obj's underlying member method code with example usage: obj.fit(X, y) and returns: self