code: def _validate_parafac2_tensor(parafac2_tensor):
      """Validates a parafac2_tensor in the form (weights, factors)
  
          Returns the rank and shape of the validated tensor
  
      Parameters
      ----------
      parafac2_tensor : Parafac2Tensor or (weights, factors)
  
      Returns
      -------
      (shape, rank) : (int tuple, int)
          size of the full tensor and rank of the CP tensor
      """
      if isinstance(parafac2_tensor, Parafac2Tensor):
          # it's already been validated at creation
          return parafac2_tensor.shape, parafac2_tensor.rank
  
      weights, factors, projections = parafac2_tensor
  
      if len(factors) != 3:
          raise ValueError(
              "A PARAFAC2 tensor should be composed of exactly three factors."
              f"However, {len(factors)} factors was given."
          )
  
      if len(projections) != factors[0].shape[0]:
          raise ValueError(
              "A PARAFAC2 tensor should have one projection matrix for each horisontal"
              f" slice. However, {len(projections)} projection matrices was given and the first mode has"
              f"length {factors[0].shape[0]}"
          )
  
      rank = int(T.shape(factors[0])[1])
  
      shape = []
      for i, projection in enumerate(projections):
          current_mode_size, current_rank = T.shape(projection)
          if current_rank != rank:
              raise ValueError(
                  "All the projection matrices of a PARAFAC2 tensor should have the same number of "
                  f"columns as the rank. However, rank={rank} but projections[{i}].shape[1]={T.shape(projection)[1]}"
              )
  
          inner_product = T.dot(T.transpose(projection), projection)
          if (
              T.max(
                  T.abs(
                      inner_product
                      - T.eye(rank, **T.context(inner_product))
                  )
              )
              > 1e-5
          ):
              raise ValueError(
                  "All the projection matrices must be orthonormal, that is, P.T@P = I. "
                  f"However, T.norm(projection[{i}].T@projection[{i}] - T.eye(rank)) = "
                  f"{T.norm(inner_product - T.eye(rank, **T.context(inner_product)))}"
              )
  
          shape.append(
              (current_mode_size, *[f.shape[0] for f in factors[2:]])
          )  # Tuple unpacking to possibly support higher order PARAFAC2 tensors in the future
  
      # Skip first factor matrix since the rank is extracted from it.
      for i, factor in enumerate(factors[1:]):
          current_mode_size, current_rank = T.shape(factor)
          if current_rank != rank:
              raise ValueError(
                  "All the factors of a PARAFAC2 tensor should have the same number of columns."
                  f"However, factors[0].shape[1]={rank} but factors[{i}].shape[1]={current_rank}."
              )
  
      if weights is not None and T.shape(weights)[0] != rank:
          raise ValueError(
              f"Given factors for a rank-{rank} PARAFAC2 tensor but len(weights)={T.shape(weights)[0]}."
          )
  
      return tuple(shape), rank
  
imports: from .None import backend
  from .base import unfold, tensor_to_vec
  from ._factorized_tensor import FactorizedTensor
label_desc: Use image node_id 1 for calling a global function with example usage: _validate_parafac2_tensor(parafac2_tensor) and returns: tuple,  rank, parafac2_tensor,  parafac2_tensor