Source code for hottbox.rank.rank_estimation
import numpy as np
from ..core.structures import Tensor
from ..algorithms.decomposition.cpd import CPD
[docs]def rankest(tensor, rank_range, epsilon=10e-3, verbose=False):
""" Estimate the optimal Kruskal rank of a tensor
Parameters
----------
tensor : Tensor
Multi-dimensional data which Kruskal rank is to be estimated
rank_range : list[int]
List of rank values to be tested
epsilon : float
Threshold for the relative error of approximation.
verbose : bool
Enable verbose output
Returns
-------
optimal_rank : tuple
Optimal Kruskal rank. For consistency, the type of the returned value is tuple
"""
if not isinstance(rank_range, list):
raise TypeError("The `rank_range` should be passed as a list of integers")
if not all(isinstance(value, int) for value in rank_range):
raise TypeError("The `rank_range` should consist of integers only")
cpd = CPD(verbose=False)
rel_error = []
for rank in rank_range:
cpd.decompose(tensor=tensor, rank=(rank,))
rel_error.append(cpd.cost[-1])
if verbose:
print('Rank = {}, Approximation error = {}'.format((rank,), cpd.cost[-1]))
if rel_error[-1] <= epsilon:
break
# Reset cost value for cpd. Should work even without it
cpd.cost = []
optimal_value = rank_range[rel_error.index(min(rel_error))]
optimal_rank = (optimal_value,)
return optimal_rank
[docs]def mlrank(tensor):
""" Calculate the multi-linear rank of a tensor
Parameters
----------
tensor : Tensor
Multidimensional data which multi-linear rank is to be computed
Returns
-------
ml_rank : tuple
Multi-linear rank
"""
# TODO: implement setting a threshold for singular values
order = tensor.order
ml_rank = [np.linalg.matrix_rank(tensor.unfold(mode=i, inplace=False).data) for i in range(order)]
ml_rank = tuple(ml_rank)
return ml_rank