code: def _nipals_twoblocks_inner_loop(
      X, Y, mode="A", max_iter=500, tol=1e-06, norm_y_weights=False
  ):
      """Inner loop of the iterative NIPALS algorithm.
  
      Provides an alternative to the svd(X'Y); returns the first left and right
      singular vectors of X'Y.  See PLS for the meaning of the parameters.  It is
      similar to the Power method for determining the eigenvectors and
      eigenvalues of a X'Y.
      """
      y_score = Y[:, [0]]
      x_weights_old = 0
      ite = 1
      X_pinv = Y_pinv = None
      eps = np.finfo(X.dtype).eps
      # Inner loop of the Wold algo.
      while True:
          # 1.1 Update u: the X weights
          if mode == "B":
              if X_pinv is None:
                  # We use slower pinv2 (same as np.linalg.pinv) for stability
                  # reasons
                  X_pinv = linalg.pinv2(X, **pinv2_args)
              x_weights = np.dot(X_pinv, y_score)
          else:  # mode A
              # Mode A regress each X column on y_score
              x_weights = np.dot(X.T, y_score) / np.dot(
                  y_score.T, y_score
              )
          # If y_score only has zeros x_weights will only have zeros. In
          # this case add an epsilon to converge to a more acceptable
          # solution
          if np.dot(x_weights.T, x_weights) < eps:
              x_weights += eps
          # 1.2 Normalize u
          x_weights /= np.sqrt(np.dot(x_weights.T, x_weights)) + eps
          # 1.3 Update x_score: the X latent scores
          x_score = np.dot(X, x_weights)
          # 2.1 Update y_weights
          if mode == "B":
              if Y_pinv is None:
                  Y_pinv = linalg.pinv2(
                      Y, **pinv2_args
                  )  # compute once pinv(Y)
              y_weights = np.dot(Y_pinv, x_score)
          else:
              # Mode A regress each Y column on x_score
              y_weights = np.dot(Y.T, x_score) / np.dot(
                  x_score.T, x_score
              )
          # 2.2 Normalize y_weights
          if norm_y_weights:
              y_weights /= np.sqrt(np.dot(y_weights.T, y_weights)) + eps
          # 2.3 Update y_score: the Y latent scores
          y_score = np.dot(Y, y_weights) / (
              np.dot(y_weights.T, y_weights) + eps
          )
          # y_score = np.dot(Y, y_weights) / np.dot(y_score.T, y_score) ## BUG
          x_weights_diff = x_weights - x_weights_old
          if (
              np.dot(x_weights_diff.T, x_weights_diff) < tol
              or Y.shape[1] == 1
          ):
              break
          if ite == max_iter:
              warnings.warn("Maximum number of iterations reached")
              break
          x_weights_old = x_weights
          ite += 1
      return x_weights, y_weights, ite
  
imports: from distutils.version import LooseVersion
  from sklearn.utils.extmath import svd_flip
  from ..base import BaseEstimator, RegressorMixin, TransformerMixin
  from ..utils import check_array, check_consistent_length
  from ..externals import six
  import warnings
  from abc import ABCMeta, abstractmethod
  import numpy
  from scipy import linalg
  from ..utils import arpack
  from ..utils.validation import check_is_fitted, FLOAT_DTYPES
  import scipy
label_desc: Use image node_id 1 for calling a global function with example usage: _nipals_twoblocks_inner_loop(X, Y, mode, max_iter, tol, norm_y_weights) and returns: x_weights,  y_weights,  ite