docs: def _create_w_objective(m, X, R):
      """
      Creates an objective function and its derivative for W, given M and X (data)
  
      Args:
          m (array): genes x clusters
          X (array): genes x cells
          R (array): 1 x genes
      """
      genes, clusters = m.shape
      cells = X.shape[1]
      R1 = R.reshape((genes, 1)).dot(np.ones((1, cells)))
      def objective(w):
          # convert w into a matrix first... because it's a vector for
          # optimization purposes
          w = w.reshape((m.shape[1], X.shape[1]))
          d = m.dot(w)+eps
          return np.sum((X + R1)*np.log(d + R1) - X*np.log(d))/genes
      def deriv(w):
          # derivative of objective wrt all elements of w
          # for w_{ij}, the derivative is... m_j1+...+m_jn sum over genes minus 
          # x_ij
          w2 = w.reshape((m.shape[1], X.shape[1]))
          d = m.dot(w2)+eps
          temp = X/d
          temp2 = (X+R1)/(d+R1)
          m1 = m.T.dot(temp2)
          m2 = m.T.dot(temp)
          deriv = m1 - m2
          return deriv.flatten()/genes
      return objective, deriv