docstr: Return cp_tensor with factors normalised to unit length.
  
  Turns ``factors = [|U_1, ... U_n|]`` into ``[weights;
  |V_1, ... V_n|]``, where the columns of each `V_k` are
  normalized to unit Euclidean length from the columns of
  `U_k` with the normalizing constants absorbed into
  `weights`. In the special case of a symmetric tensor,
  `weights` holds the eigenvalues of the tensor.
  
  Parameters
  ----------
  cp_tensor
      factors is list of matrices,
        all with the same number of columns
      i.e.::
  
          for u in U:
              u[i].shape == (s_i, R)
  
      where `R` is fixed while `s_i` can vary with `i`
  
  Returns
  -------
  CPTensor = (normalisation_weights, normalised_factors)
docstr_tok: ["Return","cp_tensor","with","factors","normalised","to","unit","length",".","Turns","``","factors","=","[","|U_1",",","...","U_n|","]","``","into","``","[","weights",";","|V_1",",","...","V_n|","]","``",",","where","the","columns","of","each","`","V_k","`","are","normalized","to","unit","Euclidean","length","from","the","columns","of","`","U_k","`","with","the","normalizing","constants","absorbed","into","`","weights","`",".","In","the","special","case","of","a","symmetric","tensor",",","`","weights","`","holds","the","eigenvalues","of","the","tensor",".","Parameters","--","--","--","--","--","cp_tensor","factors","is","list","of","matrices",",","all","with","the","same","number","of","columns","i.e",".",":",":","for","u","in","U",":","u","[","i","]",".shape","==","(","s_i",",","R",")","where","`","R","`","is","fixed","while","`","s_i","`","can","vary","with","`","i","`","Returns","--","--","--","-","CPTensor","=","(","normalisation_weights",",","normalised_factors",")"]
code: def cp_normalize(cp_tensor):
      """Return cp_tensor with factors normalised to unit length.
  
      Turns ``factors = [|U_1, ... U_n|]`` into ``[weights;
      |V_1, ... V_n|]``, where the columns of each `V_k` are
      normalized to unit Euclidean length from the columns of
      `U_k` with the normalizing constants absorbed into
      `weights`. In the special case of a symmetric tensor,
      `weights` holds the eigenvalues of the tensor.
  
      Parameters
      ----------
      cp_tensor
          factors is list of matrices,
            all with the same number of columns
          i.e.::
  
              for u in U:
                  u[i].shape == (s_i, R)
  
          where `R` is fixed while `s_i` can vary with `i`
  
      Returns
      -------
      CPTensor = (normalisation_weights, normalised_factors)
      """
      _, rank = ivy.CPTensor.validate_cp_tensor(cp_tensor)
      weights, factors = cp_tensor
  
      if weights is None:
          weights = ivy.ones(rank, dtype=factors[0].dtype)
  
      normalized_factors = []
      for i, factor in enumerate(factors):
          if i == 0:
              factor = factor * weights
              weights = ivy.ones((rank,), dtype=factor.dtype)
  
          scales = ivy.sqrt(ivy.sum(ivy.square(factor), axis=0))
          scales_non_zero = ivy.where(
              scales == 0,
              ivy.ones(ivy.shape(scales), dtype=factor.dtype),
              scales,
          )
          weights = weights * scales
          normalized_factors.append(
              factor / ivy.reshape(scales_non_zero, (1, -1))
          )
  
      return CPTensor((weights, normalized_factors))
  
imports: from .base import FactorizedTensor
  import ivy
label_desc: Use image node_id 18 for calling the CPTensor obj's underlying member method code with example usage: obj.cp_normalize(cp_tensor) and returns: CPTensor