import tensorly as tl def matrix_product_state(input_tensor, rank, verbose=False): """MPS decomposition via recursive SVD Decomposes `input_tensor` into a sequence of order-3 tensors (factors) -- also known as Tensor-Train decomposition [1]_. Parameters ---------- input_tensor : tensorly.tensor rank : {int, int list} maximum allowable MPS rank of the factors if int, then this is the same for all the factors if int list, then rank[k] is the rank of the kth factor verbose : boolean, optional level of verbosity Returns ------- factors : MPS factors order-3 tensors of the MPS decomposition References ---------- .. [1] Ivan V. Oseledets. "Tensor-train decomposition", SIAM J. Scientific Computing, 33(5):2295–2317, 2011. """ # Check user input for errors tensor_size = input_tensor.shape n_dim = len(tensor_size) if isinstance(rank, int): rank = [1] + [rank] * (n_dim-1) + [1] elif n_dim+1 != len(rank): message = 'Provided incorrect number of ranks. Should verify len(rank) == tl.ndim(tensor)+1, but len(rank) = {} while tl.ndim(tensor) + 1 = {}'.format( len(rank), n_dim + 1) raise(ValueError(message)) # Make sure it's not a tuple but a list rank = list(rank) # Initialization if rank[0] != 1: message = 'Provided rank[0] == {} but boundaring conditions dictatate rank[0] == rank[-1] == 1: setting rank[0] to 1.'.format(rank[0]) raise ValueError(message) if rank[-1] != 1: message = 'Provided rank[-1] == {} but boundaring conditions dictatate rank[0] == rank[-1] == 1: setting rank[-1] to 1.'.format(rank[0]) raise ValueError(message) unfolding = input_tensor factors = [None] * n_dim # Getting the MPS factors up to n_dim - 1 for k in range(n_dim - 1): # Reshape the unfolding matrix of the remaining factors n_row = int(rank[k]*tensor_size[k]) unfolding = tl.reshape(unfolding, (n_row, -1)) # SVD of unfolding matrix (n_row, n_column) = unfolding.shape current_rank = min(n_row, n_column, rank[k+1]) U, S, V = tl.partial_svd(unfolding, current_rank) rank[k+1] = current_rank # Get kth MPS factor factors[k] = tl.reshape(U, (rank[k], tensor_size[k], rank[k+1])) if(verbose is True): print("MPS factor " + str(k) + " computed with shape " + str(factors[k].shape)) # Get new unfolding matrix for the remaining factors unfolding= tl.reshape(S, (-1, 1))*V # Getting the last factor (prev_rank, last_dim) = unfolding.shape factors[-1] = tl.reshape(unfolding, (prev_rank, last_dim, 1)) if(verbose is True): print("MPS factor " + str(n_dim-1) + " computed with shape " + str(factors[n_dim-1].shape)) return factors