code: def test_parafac(
      linesearch,
      orthogonalise,
      true_rank,
      rank,
      init,
      normalize_factors,
      random_state,
      complex,
      monkeypatch,
  ):
      """Test for the CANDECOMP-PARAFAC decomposition"""
      rng = tl.check_random_state(random_state)
      tol_norm_2 = 0.01
      tol_max_abs = 0.05
      shape = (6, 8, 7)
  
      factors = random_cp(
          shape,
          rank=true_rank,
          orthogonal=orthogonalise,
          full=False,
          random_state=rng,
          dtype=tl.float64,
      )
  
      # Generate a random complex tensor if requested
      if complex:
          factors_imag = random_cp(
              shape,
              rank=true_rank,
              orthogonal=orthogonalise,
              full=False,
              random_state=rng,
              dtype=tl.float64,
          )
          factors.factors = [
              fm_re + (fm_im * 1.0j)
              for fm_re, fm_im in zip(
                  factors.factors, factors_imag.factors
              )
          ]
  
      tensor = tl.cp_to_tensor(factors)
  
      # Callback to record error
      errors = ErrorTracker()
  
      rng = tl.check_random_state(random_state)
      fac = parafac(
          tensor,
          rank=rank,
          n_iter_max=70,
          init=init,
          tol=1e-6,
          random_state=rng,
          normalize_factors=normalize_factors,
          orthogonalise=orthogonalise,
          linesearch=linesearch,
          callback=errors,
      )
  
      # Given all the random seed is set, this should provide the same answer for random initialization
      if init == "random":
          # Callback to record error
          errorsTwo = ErrorTracker()
  
          rng = tl.check_random_state(random_state)
          facTwo = parafac(
              tensor,
              rank=rank,
              n_iter_max=70,
              init=init,
              tol=1e-6,
              random_state=rng,
              normalize_factors=normalize_factors,
              orthogonalise=orthogonalise,
              linesearch=linesearch,
              callback=errorsTwo,
          )
          assert_array_almost_equal(errors.error, errorsTwo.error)
          assert_array_almost_equal(fac.factors[0], facTwo.factors[0])
          assert_array_almost_equal(fac.factors[1], facTwo.factors[1])
          assert_array_almost_equal(fac.factors[2], facTwo.factors[2])
  
      # Check that the error monotonically decreases
      if not orthogonalise:
          assert_(np.all(np.diff(errors.error) <= 1.0e-7))
  
      rec = cp_to_tensor(fac)
      error = T.norm(rec - tensor, 2)
      error /= T.norm(tensor, 2)
      assert_(
          error < tol_norm_2,
          f"norm 2 of reconstruction higher = {error} than tolerance={tol_norm_2}",
      )
      # Test the max abs difference between the reconstruction and the tensor
      assert_(
          T.max(T.abs(rec - tensor)) < tol_max_abs,
          f"abs norm of reconstruction error = {T.max(T.abs(rec - tensor))} higher than tolerance={tol_max_abs}",
      )
  
      # Test fixing mode 0 or 1 with given init
      fixed_tensor = random_cp(
          shape,
          rank=true_rank,
          normalise_factors=False,
          **tl.context(tensor),
      )
      rec_svd_fixed_mode_0 = parafac(
          tensor,
          rank=true_rank,
          n_iter_max=2,
          init=fixed_tensor,
          fixed_modes=[0],
          linesearch=linesearch,
      )
      rec_svd_fixed_mode_1 = parafac(
          tensor,
          rank=true_rank,
          n_iter_max=2,
          init=fixed_tensor,
          fixed_modes=[1],
          linesearch=linesearch,
      )
      # Check if modified after 2 iterations
      assert_array_equal(
          rec_svd_fixed_mode_0.factors[0],
          fixed_tensor.factors[0],
          err_msg="Fixed mode 0 was modified in candecomp_parafac",
      )
      assert_array_equal(
          rec_svd_fixed_mode_1.factors[1],
          fixed_tensor.factors[1],
          err_msg="Fixed mode 1 was modified in candecomp_parafac",
      )
  
      # Check that sparse component works
      rec_sparse, sparse_component = parafac(
          tensor,
          rank=rank,
          n_iter_max=70,
          init=init,
          tol=1.0e-6,
          sparsity=0.9,
          orthogonalise=orthogonalise,
          linesearch=linesearch,
      )
  
      rec_sparse = cp_to_tensor(rec_sparse) + sparse_component
      error = T.norm(rec_sparse - tensor, 2)
      error /= T.norm(tensor, 2)
      assert_(
          error < tol_norm_2,
          "l2 Reconstruction error for sparsity!=None too high",
      )
      assert_(
          T.max(T.abs(rec_sparse - tensor)) < tol_max_abs,
          "abs Reconstruction error for sparsity!=None too high",
      )
  
      with np.testing.assert_raises(ValueError):
          _, _ = initialize_cp(tensor, rank, init="bogus init type")
  
      assert_class_wrapper_correctly_passes_arguments(
          monkeypatch,
          parafac,
          CP,
          ignore_args={"return_errors"},
          rank=3,
      )
  
imports: import numpy
  import pytest
  import tensorly
  from .._cp import parafac, initialize_cp, sample_khatri_rao, randomised_parafac, CP, RandomizedCP, CPTensor
  from .._nn_cp import non_negative_parafac, non_negative_parafac_hals, CP_NN, CP_NN_HALS
  from ...cp_tensor import cp_to_tensor
  from ...cp_tensor import cp_to_tensor
  from ...random import random_cp
  from ...tenalg import khatri_rao
  from ...None import backend
  from ...testing import assert_array_equal, assert_, assert_class_wrapper_correctly_passes_arguments, assert_array_almost_equal
  from ...metrics.factors import congruence_coefficient
label_desc: Use image node_id 1 for calling a global function with example usage: test_parafac(linesearch, orthogonalise, true_rank, rank, init, normalize_factors, random_state, complex, monkeypatch) without return types