code: def partial_tucker(
      x: Union[ivy.Array, ivy.NativeArray],
      rank: Optional[Sequence[int]] = None,
      modes: Optional[Sequence[int]] = None,
      /,
      *,
      n_iter_max: Optional[int] = 100,
      init: Optional[
          Union[Literal["svd", "random"], ivy.TuckerTensor]
      ] = "svd",
      svd: Optional[Literal["truncated_svd"]] = "truncated_svd",
      seed: Optional[int] = None,
      mask: Optional[Union[ivy.Array, ivy.NativeArray]] = None,
      svd_mask_repeats: Optional[int] = 5,
      tol: Optional[float] = 10e-5,
      verbose: Optional[bool] = False,
      return_errors: Optional[bool] = False,
  ) -> Tuple[ivy.Array, Sequence[ivy.Array]]:
      """Partial tucker decomposition via Higher Order Orthogonal Iteration (HOI)
  
          Decomposes `tensor` into a Tucker decomposition
          exclusively along the provided modes.
  
      Parameters
      ----------
      x
          the  input tensor
      rank
          size of the core tensor, ``(len(ranks) == tensor.ndim)``
          if int, the same rank is used for all modes
          if None, original tensors size will be preserved.
      modes
          list of the modes on which to perform the decomposition
      n_iter_max
          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,
      seed
          Used to create a random seed distribution
          when init == 'random'
      mask
          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).
      svd_mask_repeats
          number of iterations for imputing the values in the SVD matrix when
          mask is not None
      tol
          tolerance: the algorithm stops when the variation in
          the reconstruction error is less than the tolerance.
      verbose
          if True, different in reconstruction errors are returned at each
          iteration.
      return_erros
          if True, list of reconstruction errors are returned.
  
      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(len(x.shape)))
  
      if rank is None:
          logging.warning(
              "No value given for 'rank'. The decomposition will preserve the original"
              " size."
          )
          rank = [ivy.shape(x)[mode] for mode in modes]
      elif isinstance(rank, int):
          logging.warning(
              f"Given only one int for 'rank' instead of a list of {len(modes)} modes."
              " Using this rank for all modes."
          )
          rank = tuple(rank for _ in modes)
      else:
          rank = ivy.TuckerTensor.validate_tucker_rank(
              x.shape, rank=rank
          )
  
      # SVD init
      core, factors = initialize_tucker(
          x,
          rank,
          modes,
          init=init,
          svd=svd,
          seed=seed,
          mask=mask,
          svd_mask_repeats=svd_mask_repeats,
      )
  
      rec_errors = []
      norm_tensor = ivy.sqrt(ivy.sum(x**2))
  
      for iteration in range(n_iter_max):
          if mask is not None:
              x = x * mask + multi_mode_dot(
                  core, factors, modes=modes, transpose=False
              ) * (1 - mask)
  
          for index, mode in enumerate(modes):
              core_approximation = multi_mode_dot(
                  x, factors, modes=modes, skip=index, transpose=True
              )
              eigenvecs, _, _ = _svd_interface(
                  ivy.unfold(core_approximation, mode),
                  n_eigenvecs=rank[index],
                  # random_state=random_state,
              )
              factors[index] = eigenvecs
  
          core = multi_mode_dot(x, factors, modes=modes, transpose=True)
  
          # The factors are orthonormal and
          #  therefore do not affect the reconstructed tensor's norm
          norm_core = ivy.sqrt(ivy.sum(core**2))
          rec_error = (
              ivy.sqrt(abs(norm_tensor**2 - norm_core**2))
              / norm_tensor
          )
          rec_errors.append(rec_error)
  
          if iteration > 1:
              if verbose:
                  print(
                      f"reconstruction error={rec_errors[-1]},"
                      f" 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
  
      if return_errors:
          return (core, factors), rec_errors
      return (core, factors)
  
imports: import logging
  from typing import Union, Optional, Tuple, List, Sequence, Literal
  import ivy
  from ivy.utils.backend import current_backend
  from ivy.func_wrapper import to_native_arrays_and_back, handle_out_argument, handle_nestable, handle_array_like_without_promotion, handle_array_function, handle_device, inputs_to_ivy_arrays, handle_backend_invalid
  from ivy.utils.exceptions import handle_exceptions
label_desc: Use image node_id 23 for calling a global function with example usage: partial_tucker() and returns: core,  factors, core,  factors,  rec_errors