code: def _rsrm(self, X):
          
          subjs = len(X)
          voxels = [X[i].shape[0] for i in range(subjs)]
          TRs = X[0].shape[1]
          features = self.features
  
          # Initialization
          W = self._init_transforms(subjs, voxels, features, self.random_state_)
          S = self._init_individual(subjs, voxels, TRs)
          R = self._update_shared_response(X, S, W, features)
  
          if logger.isEnabledFor(logging.INFO):
              objective = self._objective_function(X, W, R, S, self.lam)
              logger.info('Objective function %f' % objective)
  
          # Main loop
          for i in range(self.n_iter):
              W = self._update_transforms(X, S, R)
              S = self._update_individual(X, W, R, self.lam)
              R = self._update_shared_response(X, S, W, features)
              # Print objective function every iteration
              if logger.isEnabledFor(logging.INFO):
                  objective = self._objective_function(X, W, R, S, self.lam)
                  logger.info('Objective function %f' % objective)
  
          return W, R, S
docs: Block-Coordinate Descent algorithm for fitting RSRM.
  
          Parameters
          ----------
  
          X : list of 2D arrays, element i has shape=[voxels_i, timepoints]
              Each element in the list contains the fMRI data for alignment of
              one subject.
  
          Returns
          -------
  
          W : list of array, element i has shape=[voxels_i, features]
              The orthogonal transforms (mappings) :math:`W_i` for each subject.
  
          R : array, shape=[features, timepoints]
              The shared response.
  
          S : list of array, element i has shape=[voxels_i, timepoints]
              The individual component :math:`S_i` for each subject.