code: def partial_tucker(
      tensor,
      rank,
      modes=None,
      n_iter_max=100,
      init="svd",
      tol=10e-5,
      svd="truncated_svd",
      random_state=None,
      verbose=False,
      mask=None,
      svd_mask_repeats=5,
  ):
      """Partial tucker decomposition via Higher Order Orthogonal Iteration (HOI)
  
          Decomposes `tensor` into a Tucker decomposition exclusively along the provided modes.
  
      Parameters
      ----------
      tensor : ndarray
      rank : None, int or int list
          size of the core tensor, ``(len(ranks) == tensor.ndim)``
          if int, the same rank is used for all modes
      modes : None, int list
              list of the modes on which to perform the decomposition
      n_iter_max : int
                   maximum number of iteration
      init : {'svd', 'random'}, or TuckerTensor optional
          if a TuckerTensor is provided, this is used for initialization
      svd : str, default is 'truncated_svd'
          function to use to compute the SVD,
          acceptable values in tensorly.tenalg.svd.SVD_FUNS
      tol : float, optional
            tolerance: the algorithm stops when the variation in
            the reconstruction error is less than the tolerance
      random_state : {None, int, np.random.RandomState}
      verbose : int, optional
          level of verbosity
      mask : ndarray
          array of booleans with the same shape as ``tensor`` should be 0 where
          the values are missing and 1 everywhere else. Note:  if tensor is
          sparse, then mask should also be sparse with a fill value of 1 (or
          True).
  
      Returns
      -------
      core : ndarray
              core tensor of the Tucker decomposition
      factors : ndarray list
              list of factors of the Tucker decomposition.
              with ``core.shape[i] == (tensor.shape[i], ranks[i]) for i in modes``
  
      """
      if modes is None:
          modes = list(range(tl.ndim(tensor)))
  
      if rank is None:
          message = "No value given for 'rank'. The decomposition will preserve the original size."
          warnings.warn(message, Warning)
          rank = [tl.shape(tensor)[mode] for mode in modes]
      elif isinstance(rank, int):
          message = f"Given only one int for 'rank' instead of a list of {len(modes)} modes. Using this rank for all modes."
          warnings.warn(message, Warning)
          rank = tuple(rank for _ in modes)
      else:
          rank = tuple(rank)
  
      # SVD init
      core, factors = initialize_tucker(
          tensor,
          rank,
          modes,
          init=init,
          svd=svd,
          random_state=random_state,
          mask=mask,
          svd_mask_repeats=svd_mask_repeats,
      )
  
      rec_errors = []
      norm_tensor = tl.norm(tensor, 2)
  
      for iteration in range(n_iter_max):
          if mask is not None:
              tensor = tensor * mask + multi_mode_dot(
                  core, factors, modes=modes, transpose=False
              ) * (1 - mask)
  
          for index, mode in enumerate(modes):
              core_approximation = multi_mode_dot(
                  tensor,
                  factors,
                  modes=modes,
                  skip=index,
                  transpose=True,
              )
              eigenvecs, _, _ = svd_interface(
                  unfold(core_approximation, mode),
                  n_eigenvecs=rank[index],
                  random_state=random_state,
              )
              factors[index] = eigenvecs
  
          core = multi_mode_dot(
              tensor, factors, modes=modes, transpose=True
          )
  
          # The factors are orthonormal and therefore do not affect the reconstructed tensor's norm
          rec_error = (
              sqrt(abs(norm_tensor**2 - tl.norm(core, 2) ** 2))
              / norm_tensor
          )
          rec_errors.append(rec_error)
  
          if iteration > 1:
              if verbose:
                  print(
                      f"reconstruction error={rec_errors[-1]}, variation={rec_errors[-2] - rec_errors[-1]}."
                  )
  
              if tol and abs(rec_errors[-2] - rec_errors[-1]) < tol:
                  if verbose:
                      print(f"converged in {iteration} iterations.")
                  break
  
      return (core, factors), rec_errors
  
imports: import tensorly
  from ._base_decomposition import DecompositionMixin
  from ..base import unfold
  from ..tenalg import multi_mode_dot, mode_dot
  from ..tucker_tensor import tucker_to_tensor, TuckerTensor, validate_tucker_rank, tucker_normalize
  from ..tenalg.proximal import hals_nnls, active_set_nnls, fista
  from math import sqrt
  import warnings
  from collections.abc import Iterable
  from ..tenalg.svd import svd_interface
label_desc: Use image node_id 2 for calling a global function with example usage: partial_tucker(tensor, rank, modes, n_iter_max, init, tol, svd, random_state, verbose, mask, svd_mask_repeats) and returns: core,  factors,  rec_errors