Beispiel #1
0
def als(tensor,rank,factors=None,it_max=100,tol=1e-7,list_factors=False,error_fast=True,time_rec=False):
  """
    ALS methode of CP decomposition

    Parameters
    ----------
    tensor : tensor
    rank : int
    factors : list of matrices, optional
        an initial factor matrices. The default is None.
    it_max : int, optional
        maximal number of iteration. The default is 100.
    tol : float, optional
        error tolerance. The default is 1e-7.
    list_factors : boolean, optional
        If true, then return factor matrices of each iteration. The default is False.
    error_fast : boolean, optional
        If true, use err_fast to compute data fitting error, otherwise, use err. The default is True.
    time_rec : boolean, optional
        If true, return computation time of each iteration. The default is False.

    Returns
    -------
    the CP decomposition, number of iteration and termination criterion. 
    list_fac and list_time are optional.
  """
  N=tl.ndim(tensor) # order of tensor
  norm_tensor=tl.norm(tensor) # norm of tensor
  if time_rec == True : list_time=[]
  if list_factors==True : list_fac=[] # list of factor matrices

  if (factors==None): factors=svd_init_fac(tensor,rank)

  weights=None
  it=0
  if list_factors==True : list_fac.append(copy.deepcopy(factors))
  error=[err(tensor,weights,factors)/norm_tensor]
  while (error[len(error)-1]>tol and it<it_max):
    if time_rec == True : tic=time.time() 
    for n in range(N):
      V=np.ones((rank,rank))
      for i in range(len(factors)):
        if i != n : V=V*tl.dot(tl.transpose(factors[i]),factors[i])
      W=tl.cp_tensor.unfolding_dot_khatri_rao(tensor, (None,factors), n) 
      factors[n]= tl.transpose(tl.solve(tl.transpose(V),tl.transpose(W)))
    if list_factors==True : list_fac.append(copy.deepcopy(factors))
    it=it+1
    if (error_fast==False) : error.append(err(tensor,weights,factors)/norm_tensor)
    else : error.append(err_fast(norm_tensor,factors[N-1],V,W)/norm_tensor)
    if time_rec == True : 
      toc=time.time() 
      list_time.append(toc-tic)
  # weights,factors=tl.cp_tensor.cp_normalize((None,factors))
  if list_factors==True and time_rec==True: return(weights,factors,it,error,list_fac,list_time)
  if time_rec==True : return(weights,factors,it,error,list_time)
  if list_factors==True : return(weights,factors,it,error,list_fac)
  return(weights,factors,it,error)
Beispiel #2
0
def test_err():
    """
    Test of err
    """
    # create a kruskal tensor
    # factor matrices
    A = np.arange(9).reshape(3, 3)
    B = np.arange(6).reshape(2, 3) + 9
    C = np.arange(6).reshape(2, 3) + 15
    factors = []
    factors += [A]
    factors += [B]
    factors += [C]
    t_krus = tl.cp_to_tensor((None, factors))
    weights_cp, factors_cp = tl.cp_normalize((None, factors))
    print(base.err(t_krus, weights_cp, factors_cp))
Beispiel #3
0
def nn_her_Als(tensor,
               rank,
               factors=None,
               it_max=100,
               tol=1e-7,
               beta=0.5,
               eta=1.5,
               gamma=1.05,
               gamma_bar=1.01,
               list_factors=False,
               error_fast=True,
               time_rec=False):
    """
    her ALS methode of CP decomposition for non negative case

    Parameters
    ----------
    tensor : tensor
    rank : int
    factors : list of matrices, optional
        an initial non negative factor matrices. The default is None.
    it_max : int, optional
        maximal number of iteration. The default is 100.
    tol : float, optional
        error tolerance. The default is 1e-7.
    beta : float, optional
        extrapolation parameter. The default is 0.5.
    eta : float, optional
        decrease coefficient of beta. The default is 1.5.
    gamma : float, optional
        increase coefficient of beta. The default is 1.05.
    gamma_bar : float, optional
        increase coeefficient of beta_bar. The default is 1.01.
    list_factors : boolean, optional
        If true, then return factor matrices of each iteration. The default is False.
    error_fast : boolean, optional
        If true, use err_fast to compute data fitting error, otherwise, use err. The default is True.
    time_rec : boolean, optional
        If true, return computation time of each iteration. The default is False.

    Returns
    -------
    the CP decomposition, number of iteration, error and restart pourcentage. 
    list_fac and list_time are optional.
  """
    beta_bar = 1
    N = tl.ndim(tensor)  # order of tensor
    norm_tensor = tl.norm(tensor)  # norm of tensor
    weights = None
    if time_rec == True: list_time = []
    if list_factors == True: list_fac = []

    if (factors == None): factors = svd_init_fac(tensor, rank)

    # Initialization of factor hat matrices by factor matrices
    factors_hat = factors
    if list_factors == True: list_fac.append(copy.deepcopy(factors))

    it = 0
    cpt = 0
    F_hat_bf = err(tensor, None, factors)  # cost
    error = [F_hat_bf / norm_tensor]

    while (error[len(error) - 1] > tol and it < it_max):
        if time_rec == True: tic = time.time()
        for n in range(N):
            V = np.ones((rank, rank))
            for i in range(len(factors)):
                if i != n:
                    V = V * tl.dot(tl.transpose(factors_hat[i]),
                                   factors_hat[i])
            W = tl.cp_tensor.unfolding_dot_khatri_rao(tensor,
                                                      (None, factors_hat), n)
            factor_bf = factors[n]
            # update
            fac, _, _, _ = hals_nnls(tl.transpose(W), V,
                                     tl.transpose(factors[n]))
            factors[n] = tl.transpose(fac)
            # extrapolate
            factors_hat[n] = tl.clip(factors[n] + beta *
                                     (factors[n] - factor_bf),
                                     a_min=0.0)

        if (error_fast == False):
            F_hat_new = err(tensor, None, factors_hat)  # cost update
        else:
            F_hat_new = err_fast(norm_tensor, factors[N - 1], V, W)
        if (F_hat_new > F_hat_bf):
            factors_hat = factors
            beta_bar = beta
            beta = beta / eta
            cpt = cpt + 1
        else:
            factors = factors_hat
            beta_bar = min(1, beta_bar * gamma_bar)
            beta = min(beta_bar, gamma * beta)
        F_hat_bf = F_hat_new
        it = it + 1
        if list_factors == True: list_fac.append(copy.deepcopy(factors))
        error.append(F_hat_new / norm_tensor)
        if time_rec == True:
            toc = time.time()
            list_time.append(toc - tic)
    if time_rec == True and list_factors == True:
        return (weights, factors, it, error, cpt / it, list_fac, list_time)
    if list_factors == True:
        return (weights, factors, it, error, cpt / it, list_fac)
    if time_rec == True:
        return (weights, factors, it, error, cpt / it, list_time)
    return (weights, factors, it, error, cpt / it)
Beispiel #4
0
def her_CPRAND(tensor,
               rank,
               n_samples,
               factors=None,
               exact_err=True,
               it_max=100,
               err_it_max=20,
               tol=1e-7,
               beta=0.1,
               eta=3,
               gamma=1.01,
               gamma_bar=1.005,
               list_factors=False,
               time_rec=False):
    """
    herCPRAND for CP-decomposition
    return also exact error

    Parameters
    ----------
    tensor : tensor
    rank : int
    n_samples : int
        sample size
     factors : list of matrices, optional
        an initial factor matrices. The default is None.
    exact_err : boolean, optional
        whether use err or err_rand_fast for terminaison criterion. The default is False.
        (not useful for this version)
    it_max : int, optional
        maximal number of iteration. The default is 100.
    err_it_max : int, optional
        maximal of iteration if terminaison critirion is not improved. The default is 20.
    tol : float, optional
        error tolerance. The default is 1e-7.
    beta : float, optional
        extrapolation parameter. The default is 0.1.
    eta : float, optional
        decrease coefficient of beta. The default is 3.
    gamma : float, optional
        increase coefficient of beta. The default is 1.01.
    gamma_bar : float, optional
        increase coeefficient of beta_bar. The default is 1.005.
    list_factors : boolean, optional
        If true, then return factor matrices of each iteration. The default is False.
    time_rec : boolean, optional
        If true, return computation time of each iteration. The default is False.

    Returns
    -------
    the CP decomposition, number of iteration and exact / estimated termination criterion. 
    list_fac and list_time are optional.

    """
    beta_bar = 1
    N = tl.ndim(tensor)  # order of tensor
    norm_tensor = tl.norm(tensor)  # norm of tensor
    if list_factors == True: list_fac = []
    if (time_rec == True): list_time = []

    if (factors == None): factors = svd_init_fac(tensor, rank)
    # Initialization of factor hat matrice by factor matrices
    factors_hat = factors
    if list_factors == True: list_fac.append(copy.deepcopy(factors))

    weights = None
    it = 0
    err_it = 0
    cpt = 0
    ########################################
    ######### error initialization #########
    ########################################
    F_hat_bf, ind_bf = err_rand(tensor, None, factors, n_samples)
    F_hat_bf_ex = err(tensor, None, factors)  # exact cost
    rng = tl.random.check_random_state(None)
    error = [F_hat_bf / norm_tensor]
    error_ex = [F_hat_bf_ex / norm_tensor]
    min_err = error[len(error) - 1]

    while (min_err > tol and it < it_max and err_it < err_it_max):
        if time_rec == True: tic = time.time()
        factors_hat_bf = factors_hat
        for n in range(N):
            Zs, indices = sample_khatri_rao(factors_hat,
                                            n_samples,
                                            skip_matrix=n,
                                            random_state=rng)
            indices_list = [i.tolist() for i in indices]
            indices_list.insert(n, slice(None, None, None))
            indices_list = tuple(indices_list)
            V = tl.dot(tl.transpose(Zs), Zs)
            # J'ai du mal avec la syntaxe tensor[indices_list],
            # Ca renvoie une matrices et non un tenseur?
            if (n == 0): sampled_unfolding = tensor[indices_list]
            else: sampled_unfolding = tl.transpose(tensor[indices_list])
            W = tl.dot(sampled_unfolding, Zs)
            factor_bf = factors[n]
            # update
            factors[n] = tl.transpose(
                tl.solve(V, tl.transpose(W))
            )  # solve needs a squared full rank matrix, if rank>nb_sampls ok
            # if (n==N-1) : F_hat_new=tl.norm(tl.dot(Zs,tl.transpose(factors[n]))-sampled_unfolding,2) # cost update
            # extrapolate
            factors_hat[n] = factors[n] + beta * (factors[n] - factor_bf)
        ########################################
        #########      error update    #########
        ########################################

        matrices = factors_hat_bf[:-1]
        Zs_bf = tl.ones((n_samples, rank), **tl.context(matrices[0]))
        for indices, matrix in zip(indices_list, matrices):
            Zs_bf = Zs_bf * matrix[indices, :]
        V_bf = tl.dot(tl.transpose(Zs_bf), Zs_bf)
        W_bf = tl.dot(tl.transpose(tensor[indices_list]), Zs_bf)
        F_hat_bf, a = err_rand_fast(tensor, factor_bf, V_bf, W_bf,
                                    indices_list, n_samples)
        F_hat_new, _ = err_rand_fast(tensor, factors[N - 1], V, W,
                                     indices_list, n_samples)

        if (F_hat_new > F_hat_bf):
            factors_hat = factors
            beta_bar = beta
            beta = beta / eta
            cpt = cpt + 1
        else:
            factors = factors_hat
            beta_bar = min(1, beta_bar * gamma_bar)
            beta = min(beta_bar, gamma * beta)
        ########################################
        ######### update for next it   #########
        ########################################
        it = it + 1
        if list_factors == True: list_fac.append(copy.deepcopy(factors))
        error.append(F_hat_new / norm_tensor)
        if (error[len(error) - 1] < min_err):
            min_err = error[len(error) - 1]  # err update
        else:
            err_it = err_it + 1
        if time_rec == True:
            toc = time.time()
            list_time.append(toc - tic)
        error_ex.append(err(tensor, None, factors) /
                        norm_tensor)  # exact cost update
    # weights,factors=tl.cp_normalize((None,factors))
    if list_factors == True and time_rec == True:
        return (weights, factors, it, error_ex, error, cpt / it, list_fac,
                list_time)
    if list_factors == True:
        return (weights, factors, it, error_ex, error, cpt / it, list_fac)
    if time_rec == True:
        return (weights, factors, it, error_ex, error, cpt / it, list_time)
    return (weights, factors, it, error_ex, error, cpt / it)
Beispiel #5
0
def test_err_fast():
    """
    Test err_fast for 3 tensors.
    plot the terminaison criterion (obtained by err_fast) and exact error.
    """
    # create a kruskal tensor
    # factor matrices
    A = np.arange(9).reshape(3, 3)
    B = np.arange(6).reshape(2, 3) + 9
    C = np.arange(6).reshape(2, 3) + 15
    factors = []
    factors += [A]
    factors += [B]
    factors += [C]
    t_krus = tl.cp_to_tensor((None, factors))
    weights, factors, it, error, l = als(t_krus, 3, list_factors=True)
    err_ex = []
    for i in l:
        err_ex += [err(t_krus, weights, i)]
    plt.figure(0)
    plt.plot(range(len(err_ex)), err_ex / tl.norm(t_krus), 'b-', label="exact")
    plt.plot(range(len(error)), error, 'r--', label="err fast")
    plt.xlabel('it')
    plt.yscale('log')
    plt.title('als for t_krus')
    plt.ylabel('terminaison criterion')
    plt.legend(loc='best')

    # create an complicated random tensor
    I = 50
    J = 50
    K = 50
    r = 10  # rank
    fac_true, noise = init_factors(I, J, K, r, True)
    t = tl.cp_to_tensor((None, fac_true)) + noise
    weights, factors, it, error, l = als(t, r, list_factors=True)
    err_ex = []
    for i in l:
        err_ex += [err(t, weights, i)]
    plt.figure(1)
    plt.plot(range(len(err_ex)), err_ex / tl.norm(t), 'b-', label="exact")
    plt.plot(range(len(error)), error, 'r--', label="err fast")
    plt.xlabel('it')
    plt.yscale('log')
    plt.title('als for complicated case')
    plt.ylabel('terminaison criterion')
    plt.legend(loc='best')

    # create a simple random tensor
    fac_true, noise = init_factors(I, J, K, r, False)
    t = tl.cp_to_tensor((None, fac_true)) + noise
    weights, factors, it, error, l = als(t, r, list_factors=True)
    err_ex = []
    for i in l:
        err_ex += [err(t, weights, i)]
    plt.figure(2)
    plt.plot(range(len(err_ex)), err_ex / tl.norm(t), 'b-', label="exact")
    plt.plot(range(len(error)), error, 'r--', label="err fast")
    plt.xlabel('it')
    plt.yscale('log')
    plt.title('als for simple case')
    plt.ylabel('terminaison criterion')
    plt.legend(loc='best')
Beispiel #6
0
def CPRAND(tensor,
           rank,
           n_samples,
           factors=None,
           exact_err=False,
           it_max=100,
           err_it_max=20,
           tol=1e-7,
           list_factors=False,
           time_rec=False):
    """
    CPRAND for CP-decomposition
    return also exact error

    Parameters
    ----------
    tensor : tensor
    rank : int
    n_samples : int
        sample size
    factors : list of matrices, optional
        initial factor matrices. The default is None.
    exact_err : boolean, optional
        whether use err or err_rand_fast for terminaison criterion. The default is False.
        (not useful for this version)
    it_max : int, optional
        maximal number of iteration. The default is 100.
    err_it_max : int, optional
        maximal of iteration if terminaison critirion is not improved. The default is 20.
    tol : float, optional
        error tolerance. The default is 1e-7.
    list_factors : boolean, optional
        If true, then return factor matrices of each iteration. The default is False.
    time_rec : boolean, optional
        If true, return computation time of each iteration. The default is False.

    Returns
    -------
    the CP decomposition, number of iteration and exact / estimated termination criterion. 
    list_fac and list_time are optional.

    """
    N = tl.ndim(tensor)  # order of tensor
    norm_tensor = tl.norm(tensor)  # norm of tensor

    if list_factors == True: list_fac = []
    if time_rec == True: list_time = []
    if (factors == None): factors = svd_init_fac(tensor, rank)
    # weights,factors=tl.cp_tensor.cp_normalize((None,factors))
    if list_factors == True: list_fac.append(copy.deepcopy(factors))
    weights = None
    it = 0
    err_it = 0
    ########################################
    ######### error initialization #########
    ########################################
    temp, ind_err = err_rand(tensor, weights, factors, 400)
    error = [temp / norm_tensor]
    error_ex = [err(tensor, weights, factors) / norm_tensor]

    min_err = error[len(error) - 1]
    rng = tl.random.check_random_state(None)
    while (min_err > tol and it < it_max and err_it < err_it_max):
        if time_rec == True: tic = time.time()
        for n in range(N):
            Zs, indices = sample_khatri_rao(factors,
                                            n_samples,
                                            skip_matrix=n,
                                            random_state=rng)
            indices_list = [i.tolist() for i in indices]
            indices_list.insert(n, slice(None, None, None))
            indices_list = tuple(indices_list)
            if (n == 0): sampled_unfolding = tensor[indices_list]
            else: sampled_unfolding = tl.transpose(tensor[indices_list])
            V = tl.dot(tl.transpose(Zs), Zs)
            W = tl.dot(sampled_unfolding, Zs)
            # update
            factors[n] = tl.transpose(tl.solve(
                V, tl.transpose(W)))  # solve needs a squared matrix

        if list_factors == True: list_fac.append(copy.deepcopy(factors))
        it = it + 1

        ################################
        ######### error update #########
        ################################
        error.append(
            err_rand_fast(tensor, factors[N - 1], V, W, indices_list,
                          n_samples)[0] / norm_tensor
        )  # same indices used as for Random Lesat Square Calculation

        if (error[len(error) - 1] < min_err):
            min_err = error[len(error) - 1]  # err update
        else:
            err_it = err_it + 1
        if time_rec == True:
            toc = time.time()
            list_time.append(toc - tic)
        error_ex.append(err(tensor, weights, factors) / norm_tensor)
    # weights,factors=tl.cp_tensor.cp_normalize((None,factors))
    if time_rec == True and list_factors == True:
        return (weights, factors, it, error_ex, error, list_fac, list_time)
    if list_factors == True:
        return (weights, factors, it, error_ex, error, list_fac)
    if time_rec == True:
        return (weights, factors, it, error_ex, error, list_time)
    return (weights, factors, it, error_ex, error)
Beispiel #7
0
def her_CPRAND5(tensor,
                rank,
                n_samples,
                factors=None,
                exact_err=True,
                it_max=100,
                err_it_max=20,
                tol=1e-7,
                beta=0.1,
                eta=3,
                gamma=1.01,
                gamma_bar=1.005,
                list_factors=False,
                time_rec=False):
    """
      different err sample taking mean value
    """
    beta_bar = 1
    N = tl.ndim(tensor)  # order of tensor
    norm_tensor = tl.norm(tensor)  # norm of tensor
    if list_factors == True: list_fac = []
    if (time_rec == True): list_time = []

    if (factors == None): factors = svd_init_fac(tensor, rank)
    # Initialization of factor hat matrice by factor matrices
    factors_hat = factors
    if list_factors == True: list_fac.append(copy.deepcopy(factors))
    list_F_hat_bf = []

    weights = None
    it = 0
    err_it = 0
    cpt = 0
    n_samples_err = 400  # assuming that miu max = 1
    ########################################
    ######### error initialization #########
    ########################################
    F_hat_bf, ind_bf = err_rand(tensor, None, factors, n_samples_err)
    list_F_hat_bf.append(F_hat_bf)

    F_hat_bf_ex = err(tensor, None, factors)  # exact cost
    rng = tl.check_random_state(None)
    error = [F_hat_bf / norm_tensor]
    error_ex = [F_hat_bf_ex / norm_tensor]
    min_err = error[len(error) - 1]

    while (min_err > tol and it < it_max and err_it < err_it_max):
        if time_rec == True: tic = time.time()
        for n in range(N):
            Zs, indices = sample_khatri_rao(factors_hat,
                                            n_samples,
                                            skip_matrix=n,
                                            random_state=rng)
            indices_list = [i.tolist() for i in indices]
            indices_list.insert(n, slice(None, None, None))
            indices_list = tuple(indices_list)
            V = tl.dot(tl.transpose(Zs), Zs)
            # J'ai du mal avec la syntaxe tensor[indices_list],
            # Ca renvoie une matrices et non un tenseur?
            if (n == 0): sampled_unfolding = tensor[indices_list]
            else: sampled_unfolding = tl.transpose(tensor[indices_list])
            W = tl.dot(sampled_unfolding, Zs)
            factor_bf = factors[n]
            # update
            factors[n] = tl.transpose(
                tl.solve(V, tl.transpose(W))
            )  # solve needs a squared full rank matrix, if rank>nb_sampls ok
            # if (n==N-1) : F_hat_new=tl.norm(tl.dot(Zs,tl.transpose(factors[n]))-sampled_unfolding,2) # cost update
            # extrapolate
            factors_hat[n] = factors[n] + beta * (factors[n] - factor_bf)
        ########################################
        #########      error update    #########
        ########################################
        F_hat_new, _ = err_rand(tensor,
                                weights,
                                factors,
                                n_samples_err,
                                indices_list=ind_bf)
        #
        # added
        # a new sample
        ind_bf = [
            np.random.choice(tl.shape(m)[0], n_samples_err) for m in factors
        ]
        ind_bf = [i.tolist() for i in ind_bf]
        ind_bf = tuple(ind_bf)
        list_F_hat_bf.append(F_hat_new)

        if (F_hat_new > F_hat_bf):
            factors_hat = factors
            beta_bar = beta
            beta = beta / eta
            cpt = cpt + 1
        else:
            factors = factors_hat
            beta_bar = min(1, beta_bar * gamma_bar)
            beta = min(beta_bar, gamma * beta)
        ########################################
        ######### update for next it   #########
        ########################################
        it = it + 1

        if it < 10:
            F_hat_bf = np.mean(list_F_hat_bf)
        else:
            F_hat_bf = np.mean(list_F_hat_bf[(len(list_F_hat_bf) -
                                              10):(len(list_F_hat_bf) - 1)])

        if list_factors == True: list_fac.append(copy.deepcopy(factors))
        error.append(F_hat_new / norm_tensor)
        if (error[len(error) - 1] < min_err):
            min_err = error[len(error) - 1]  # err update
        else:
            err_it = err_it + 1
        if time_rec == True:
            toc = time.time()
            list_time.append(toc - tic)
        error_ex.append(err(tensor, None, factors) /
                        norm_tensor)  # exact cost update
    # weights,factors=tl.cp_normalize((None,factors))
    if list_factors == True and time_rec == True:
        return (weights, factors, it, error_ex, error, cpt / it, list_fac,
                list_time)
    if list_factors == True:
        return (weights, factors, it, error_ex, error, cpt / it, list_fac)
    if time_rec == True:
        return (weights, factors, it, error_ex, error, cpt / it, list_time)
    return (weights, factors, it, error_ex, error, cpt / it)
Beispiel #8
0
def nn_her_CPRAND(tensor,
                  rank,
                  n_samples,
                  n_samples_err=400,
                  factors=None,
                  exact_err=False,
                  it_max=100,
                  err_it_max=20,
                  tol=1e-7,
                  beta=0.1,
                  eta=3,
                  gamma=1.01,
                  gamma_bar=1.005,
                  list_factors=False,
                  time_rec=False,
                  filter=10):
    """
     herCPRAND for nonnegative CP-decomposition
     same err sample taking mean value of last filter values
     
     Parameters
    ----------
    tensor : tensor
    rank : int
    n_samples : int
        sample size
    n_samples_err : int, optional
        sample size used for error estimation. The default is 400.
    factors : list of matrices, optional
        an initial factor matrices. The default is None.
    exact_err : boolean, optional
        whether use err or err_rand_fast for terminaison criterion. The default is False.
    it_max : int, optional
        maximal number of iteration. The default is 100.
    err_it_max : int, optional
        maximal of iteration if terminaison critirion is not improved. The default is 20.
    tol : float, optional
        error tolerance. The default is 1e-7.
    beta : float, optional
        extrapolation parameter. The default is 0.5.
    eta : float, optional
        decrease coefficient of beta. The default is 1.5.
    gamma : float, optional
        increase coefficient of beta. The default is 1.05.
    gamma_bar : float, optional
        increase coeefficient of beta_bar. The default is 1.01.
    list_factors : boolean, optional
        If true, then return factor matrices of each iteration. The default is False.
    time_rec : boolean, optional
        If true, return computation time of each iteration. The default is False.
    filter : int, optional
        The filter size used for the mean value

    Returns
    -------
    the CP decomposition, number of iteration, error and restart pourcentage. 
    list_fac and list_time are optional.
    """
    beta_bar = 1
    N = tl.ndim(tensor)  # order of tensor
    norm_tensor = tl.norm(tensor)  # norm of tensor
    if list_factors == True: list_fac = []
    if (time_rec == True): list_time = []

    if (factors == None): factors = svd_init_fac(tensor, rank)
    # Initialization of factor hat matrice by factor matrices
    factors_hat = factors
    if list_factors == True: list_fac.append(copy.deepcopy(factors))
    list_F_hat_bf = []

    weights = None
    it = 0
    err_it = 0
    cpt = 0
    ########################################
    ######### error initialization #########
    ########################################
    if (exact_err == True):
        F_hat_bf = err(tensor, weights, factors)
    else:
        F_hat_bf, ind_bf = err_rand(tensor, None, factors, n_samples_err)
    list_F_hat_bf.append(F_hat_bf)

    rng = tl.check_random_state(None)
    error = [F_hat_bf / norm_tensor]
    min_err = error[len(error) - 1]

    while (min_err > tol and it < it_max and err_it < err_it_max):
        if time_rec == True: tic = time.time()
        for n in range(N):
            Zs, indices = sample_khatri_rao(factors_hat,
                                            n_samples,
                                            skip_matrix=n,
                                            random_state=rng)
            indices_list = [i.tolist() for i in indices]
            indices_list.insert(n, slice(None, None, None))
            indices_list = tuple(indices_list)
            V = tl.dot(tl.transpose(Zs), Zs)
            if (n == 0): sampled_unfolding = tensor[indices_list]
            else: sampled_unfolding = tl.transpose(tensor[indices_list])
            W = tl.dot(sampled_unfolding, Zs)
            factor_bf = factors[n]
            # update
            fac, _, _, _ = hals_nnls(tl.transpose(W), V,
                                     tl.transpose(factors[n]))
            factors[n] = tl.transpose(
                fac
            )  # solve needs a squared full rank matrix, if rank>nb_sampls ok
            # extrapolate
            factors_hat[n] = tl.clip(factors[n] + beta *
                                     (factors[n] - factor_bf),
                                     a_min=0.0)
        ########################################
        #########      error update    #########
        ########################################
        if (exact_err == False):

            F_hat_new, _ = err_rand(tensor,
                                    weights,
                                    factors,
                                    n_samples_err,
                                    indices_list=ind_bf)
        else:
            F_hat_new = err(tensor, weights, factors)
        list_F_hat_bf.append(F_hat_new)

        if (F_hat_new > F_hat_bf):
            factors_hat = factors
            beta_bar = beta
            beta = beta / eta
            cpt = cpt + 1
        else:
            factors = factors_hat
            beta_bar = min(1, beta_bar * gamma_bar)
            beta = min(beta_bar, gamma * beta)
        ########################################
        ######### update for next it   #########
        ########################################
        it = it + 1
        if (exact_err == False):
            if it < filter:
                F_hat_bf = np.mean(list_F_hat_bf)
            else:
                F_hat_bf = np.mean(list_F_hat_bf[(len(list_F_hat_bf) -
                                                  filter):(len(list_F_hat_bf) -
                                                           1)])
        else:
            F_hat_bf = F_hat_new

        if list_factors == True: list_fac.append(copy.deepcopy(factors))
        error.append(F_hat_new / norm_tensor)
        if (error[len(error) - 1] < min_err):
            min_err = error[len(error) - 1]  # err update
        else:
            err_it = err_it + 1
        if time_rec == True:
            toc = time.time()
            list_time.append(toc - tic)
    if list_factors == True and time_rec == True:
        return (weights, factors, it, error, cpt / it, list_fac, list_time)
    if list_factors == True:
        return (weights, factors, it, error, cpt / it, list_fac)
    if time_rec == True:
        return (weights, factors, it, error, cpt / it, list_time)
    return (weights, factors, it, error, cpt / it)