docs: def build_kernel(self):
          """Build the MNN kernel.
  
          Build a mutual nearest neighbors kernel.
  
          Returns
          -------
          K : kernel matrix, shape=[n_samples, n_samples]
              symmetric matrix with ones down the diagonal
              with no non-negative entries.
          """
          tasklogger.log_start("subgraphs")
          self.subgraphs = []
          from .api import Graph
          # iterate through sample ids
          for i, idx in enumerate(self.samples):
              tasklogger.log_debug("subgraph {}: sample {}, "
                                   "n = {}, knn = {}".format(
                                       i, idx, np.sum(self.sample_idx == idx),
                                       self.knn))
              # select data for sample
              data = self.data_nu[self.sample_idx == idx]
              # build a kNN graph for cells within sample
              graph = Graph(data, n_pca=None,
                            knn=self.knn,
                            decay=self.decay,
                            bandwidth=self.bandwidth,
                            distance=self.distance,
                            thresh=self.thresh,
                            verbose=self.verbose,
                            random_state=self.random_state,
                            n_jobs=self.n_jobs,
                            kernel_symm='+',
                            initialize=True)
              self.subgraphs.append(graph)  # append to list of subgraphs
          tasklogger.log_complete("subgraphs")
  
          tasklogger.log_start("MNN kernel")
          if self.thresh > 0 or self.decay is None:
              K = sparse.lil_matrix(
                  (self.data_nu.shape[0], self.data_nu.shape[0]))
          else:
              K = np.zeros([self.data_nu.shape[0], self.data_nu.shape[0]])
          for i, X in enumerate(self.subgraphs):
              K = set_submatrix(K, self.sample_idx == self.samples[i],
                                self.sample_idx == self.samples[i], X.K)
              within_batch_norm = np.array(np.sum(X.K, 1)).flatten()
              for j, Y in enumerate(self.subgraphs):
                  if i == j:
                      continue
                  tasklogger.log_start(
                      "kernel from sample {} to {}".format(self.samples[i],
                                                           self.samples[j]))
                  Kij = Y.build_kernel_to_data(
                      X.data_nu,
                      knn=self.knn)
                  between_batch_norm = np.array(np.sum(Kij, 1)).flatten()
                  scale = np.minimum(1, within_batch_norm /
                                     between_batch_norm) * self.beta
                  if sparse.issparse(Kij):
                      Kij = Kij.multiply(scale[:, None])
                  else:
                      Kij = Kij * scale[:, None]
                  K = set_submatrix(K, self.sample_idx == self.samples[i],
                                    self.sample_idx == self.samples[j], Kij)
                  tasklogger.log_complete(
                      "kernel from sample {} to {}".format(self.samples[i],
                                                           self.samples[j]))
          tasklogger.log_complete("MNN kernel")
          return K