code: def _fit_projected_gradient(
      X, W, H, tol, max_iter, nls_max_iter, alpha, l1_ratio
  ):
      gradW = np.dot(W, np.dot(H, H.T)) - safe_sparse_dot(
          X, H.T, dense_output=True
      )
      gradH = np.dot(np.dot(W.T, W), H) - safe_sparse_dot(
          W.T, X, dense_output=True
      )
  
      init_grad = squared_norm(gradW) + squared_norm(gradH.T)
      # max(0.001, tol) to force alternating minimizations of W and H
      tolW = max(0.001, tol) * np.sqrt(init_grad)
      tolH = tolW
  
      for n_iter in range(1, max_iter + 1):
          # stopping condition as discussed in paper
          proj_grad_W = squared_norm(
              gradW * np.logical_or(gradW < 0, W > 0)
          )
          proj_grad_H = squared_norm(
              gradH * np.logical_or(gradH < 0, H > 0)
          )
  
          if (proj_grad_W + proj_grad_H) / init_grad < tol**2:
              break
  
          # update W
          Wt, gradWt, iterW = _nls_subproblem(
              X.T,
              H.T,
              W.T,
              tolW,
              nls_max_iter,
              alpha=alpha,
              l1_ratio=l1_ratio,
          )
          W, gradW = Wt.T, gradWt.T
  
          if iterW == 1:
              tolW = 0.1 * tolW
  
          # update H
          H, gradH, iterH = _nls_subproblem(
              X,
              W,
              H,
              tolH,
              nls_max_iter,
              alpha=alpha,
              l1_ratio=l1_ratio,
          )
          if iterH == 1:
              tolH = 0.1 * tolH
  
      H[H == 0] = 0  # fix up negative zeros
  
      if n_iter == max_iter:
          Wt, _, _ = _nls_subproblem(
              X.T,
              H.T,
              W.T,
              tolW,
              nls_max_iter,
              alpha=alpha,
              l1_ratio=l1_ratio,
          )
          W = Wt.T
  
      return W, H, n_iter
  
imports: import numbers
  import sys
  import warnings
  from time import time
  import matplotlib.pyplot
  import numpy
  import pandas
  from joblib import Memory
  from sklearn.decomposition import NMF
  from sklearn.decomposition._nmf import _beta_divergence, _check_init, _initialize_nmf
  from sklearn.exceptions import ConvergenceWarning
  from sklearn.feature_extraction.text import TfidfVectorizer
  from sklearn.utils import check_array
  from sklearn.utils._testing import ignore_warnings
  from sklearn.utils.extmath import safe_sparse_dot, squared_norm
  from sklearn.utils.validation import check_is_fitted, check_non_negative
label_desc: Use image node_id 3 for calling a global function with example usage: _fit_projected_gradient(X, W, H, tol, max_iter, nls_max_iter, alpha, l1_ratio) and returns: W,  H,  n_iter