def normalize_tensor(tensor, if_flatten=False, is_enforce=False): """ Normalize a tensor :param tensor: a tensor :param if_flatten: if flat the tensor into a vector :return: a tensor or a vector, and the norm Example: >>>T = np.array([[[1, 1], [1, 1]],[[1, 1], [1, 1]]]) >>>print(normalize_tensor(T)) (array([[[0.35355339, 0.35355339], [0.35355339, 0.35355339]], [[0.35355339, 0.35355339], [0.35355339, 0.35355339]]]), 2.8284271247461903) """ v = tensor.reshape(-1, ) norm = np.linalg.norm(v) if norm < 1e-30 and not is_enforce: cprint('InfWarning: norm is too small to normalize', 'magenta') trace_stack() if if_flatten: return v, norm else: return tensor, norm else: if if_flatten: return v/norm, norm else: return tensor/norm, norm
def bound_vec_operator_right2left(tensor, op=np.zeros(0), v=np.zeros(0), normalize=False, symme=False): """ Contract right boundary vector with transfer matrix of MPS :param tensor: a tensor of MPS :param op: operator on physical bonds :param v: left boundary :param normalize: if normalized the outcome vector :param symme: if symmertrized the outcome vector :return: the outcome vector Notes: 1.if v leaves empty, this function will use identity as default Examples: >>>T = np.array([[[1, 2, 1], [2, 1, 2]], [[2, 0, 2], [1, 3, 1]], [[3, 1, 0], [2, 2, 1]]]) >>>print(bound_vec_operator_right2left(T)) [[15 11 13] [11 19 15] [13 15 19]] >>>print(bound_vec_operator_right2left(T, v = np.array([[1, 1, 1], [1, 2, 1], [2, 2, 1]]))) [[55 54 57] [53 58 59] [48 51 50]] """ s = tensor.shape if op.size != 0: # deal with the operator tensor1 = absorb_matrix2tensor(tensor, op.T, 1) else: # no operator tensor1 = tensor.copy() if v.size == 0: # no input boundary vector v tensor = tensor.reshape(s[0], s[1]*s[2]).conj() tensor1 = tensor1.reshape(s[0], s[1]*s[2]) v1 = tensor.dot(tensor1.T) else: # there is an input boundary vector v if is_debug: if v.shape[0] != s[2]: cprint('BondDimError: the v_right has inconsistent dimension with the tensor', 'magenta') cprint('v.shape = ' + str(v.shape) + '; T.shape = ' + str(s)) trace_stack() tensor = tensor.reshape(s[0]*s[1], s[2]).conj().dot(v) v1 = tensor.reshape(s[0], s[1]*s[2]).dot(tensor1.reshape(s[0], s[1]*s[2]).T) if normalize: v1 = normalize_tensor(v1)[0] if symme: v1 = (v1 + v1.conj().T)/2 return v1
def absorb_matrices2tensor_full_fast(tensor, mats): """ Absorb tensor with matrices on all bonds :param tensor: a tensor :param mats: matrices to contracted on all bonds :return: tensor after absorb matrices Example: >>>T = np.array([[[1, 1], [1, 1]],[[1, 1], [1, 1]]]) >>>M = [np.array([[1, 2], [2, 3]]), np.array([[2, 3], [3, 4]]), np.array([[3, 4], [4, 5]])] >>>print(absorb_matrices2tensor_full_fast(T, M)) [[[105 135] [147 189]] [[175 225] [245 315]]] """ # generally, recommend to use the function 'absorb_matrices2tensor' # each bond will have a matrix to contract with # the matrices must be in the right order # contract the 1st bond of mat with tensor nb = tensor.ndim s = np.array(tensor.shape) is_bug = False if is_debug: for n in range(0, nb): if mats[n].shape[1] != s[n]: cprint('Error: the %d-th matrix has inconsistent dimension with the tensor' % n, 'magenta') cprint('T.shape = ' + str(s) + ', mat.shape = ' + str(mats[n].shape), 'magenta') is_bug = True for n in range(nb-1, -1, -1): tensor = tensor.reshape(np.prod(s[:nb-1]), s[nb-1]).dot(mats[n]) s[-1] = mats[n].shape[1] ind = [nb-1] + list(range(0, nb-1)) tensor = tensor.reshape(s).transpose(ind) s = s[ind] if is_debug and is_bug: trace_stack() # tensor = CONT([tensor] + mats, [[1, 2, 3], [1, -1], [2, -2], [3, -3]]) return tensor