docs: def _create_m_objective(w, X):
      """
      Creates an objective function and its derivative for M, given W and X
  
      Args:
          w (array): clusters x cells
          X (array): genes x cells
      """
      clusters, cells = w.shape
      genes = X.shape[0]
      w_sum = w.sum(1)
      def objective(m):
          m = m.reshape((X.shape[0], w.shape[0]))
          d = m.dot(w)+eps
          temp = X/d
          w2 = w.dot(temp.T)
          deriv = w_sum - w2.T
          return np.sum(d - X*np.log(d))/genes, deriv.flatten()/genes
      return objective