def test_svd(self): m = 9 n = 5 k = 5 for dt in [numpy.float32, numpy.float64]: A = ctf.random.random((m,n)) A = ctf.astensor(A,dtype=dt) [U,S,VT]=ctf.svd(A,k) [U1,S1,VT1]=la.svd(ctf.to_nparray(A),full_matrices=False) self.assertTrue(allclose(A, ctf.dot(U,ctf.dot(ctf.diag(S),VT)))) self.assertTrue(allclose(ctf.eye(k), ctf.dot(U.T(), U))) self.assertTrue(allclose(ctf.eye(k), ctf.dot(VT, VT.T()))) A = ctf.tensor((m,n),dtype=numpy.complex64) rA = ctf.tensor((m,n),dtype=numpy.float32) rA.fill_random() A.real(rA) iA = ctf.tensor((m,n),dtype=numpy.float32) iA.fill_random() A.imag(iA) [U,S,VT]=ctf.svd(A,k) self.assertTrue(allclose(A, ctf.dot(U,ctf.dot(ctf.diag(S),VT)))) self.assertTrue(allclose(ctf.eye(k,dtype=numpy.complex64), ctf.dot(ctf.conj(U.T()), U))) self.assertTrue(allclose(ctf.eye(k,dtype=numpy.complex64), ctf.dot(VT, ctf.conj(VT.T())))) A = ctf.tensor((m,n),dtype=numpy.complex128) rA = ctf.tensor((m,n),dtype=numpy.float64) rA.fill_random() A.real(rA) iA = ctf.tensor((m,n),dtype=numpy.float64) iA.fill_random() A.imag(iA) [U,S,VT]=ctf.svd(A,k) self.assertTrue(allclose(A, ctf.dot(U,ctf.dot(ctf.diag(S),VT)))) self.assertTrue(allclose(ctf.eye(k,dtype=numpy.complex128), ctf.dot(ctf.conj(U.T()), U))) self.assertTrue(allclose(ctf.eye(k,dtype=numpy.complex128), ctf.dot(VT, ctf.conj(VT.T()))))
def test_svd(self): m = 9 n = 5 k = 5 for dt in [ numpy.float32, numpy.float64, numpy.complex64, numpy.complex128 ]: A = ctf.random.random((m, n)) A = ctf.astensor(A, dtype=dt) [U, S, VT] = ctf.svd(A, k) [U1, S1, VT1] = la.svd(ctf.to_nparray(A), full_matrices=False) self.assertTrue(allclose(A, ctf.dot(U, ctf.dot(ctf.diag(S), VT)))) self.assertTrue(allclose(ctf.eye(k), ctf.dot(U.T(), U))) self.assertTrue(allclose(ctf.eye(k), ctf.dot(VT, VT.T())))
def einsvd(einstr, A, r=None, transpose=True, compute_uv=True, full_matrices=True, mult_sv=False): str_a, str_uv = einstr.split("->") str_u, str_v = str_uv.split(",") U, S, Vh = A.i(str_a).svd(str_u, str_v, rank=r) if not compute_uv: return S if mult_sv: char_i = list(set(str_v) - set(str_a))[0] char_s = list(set(str_a) - set(str_v))[0] Vh = ctf.einsum( char_s + char_i + "," + str_v + "->" + str_v.replace(char_i, char_s), ctf.diag(S), Vh) if not transpose: Vh = Vh.T return U, S, Vh
def test_diag(self): a0 = ctf.astensor(numpy.arange(9).reshape(3,3)) a1 = a0.diagonal() self.assertTrue(ctf.all(a1 == ctf.diag(a0))) self.assertTrue(ctf.all(ctf.diag(a1) == numpy.diag(numpy.arange(9).reshape(3,3).diagonal())))
def diag(v): return ctf.diag(v)
#!/usr/bin/env python import ctf import sys from ctf import random A = ctf.random.random((32,32)) [U,S,VT]=ctf.svd(A) err = A-ctf.dot(U,ctf.dot(ctf.diag(S),VT)) success=True err_nrm = err.norm2() if err_nrm > 1.E-6: success=False if ctf.comm().rank() == 0: if success: print("success, norm is ", err_nrm) else: print("failure, norm is ", err_nrm) ctf.MPI_Stop() sys.exit(not success)
#!/usr/bin/env python import ctf from ctf import random A = ctf.random.random((32,32)) [U,S,VT]=ctf.svd(A) err = A-ctf.dot(U,ctf.dot(ctf.diag(S),VT)) success=True err_nrm = err.norm2() if err_nrm > 1.E-6: success=False if ctf.comm().rank() == 0: if success: print("success, norm is ", err_nrm) else: print("failure, norm is ", err_nrm) ctf.MPI_Stop()
def inv(matrix): U, s, V = ctf.svd(matrix) return ctf.dot(ctf.transpose(V), ctf.dot(ctf.diag(s**-1), ctf.transpose(U)))
def einsvd(einstr, A, rank=None, threshold=None, size_limit=None, criterion=None, mult_s=True): """ Perform Singular Value Decomposition according to the specified Einstein notation string. Will always preserve at least one singular value during the truncation. Parameters ---------- einstr: str A string of Einstein notations in the form of 'idxofA->idxofU,idxofV'. There must be one and only one contraction index. A: tensor_like The tensor to be decomposed. Should be of order 2 or more. rank: int or None, optional The minimum number of singular values/vectors to preserve. Will influence the actual truncation rank. threshold: float or None, optional The value used with criterion to decide the cutoff. Will influence the actual truncation rank. size_limit: int or tuple or None, optional The size limit(s) for both U and V (when specified as a int) or U and V respectively (when specified as a tuple). Will influence the actual truncation rank. criterion: int or None, optional The norm to be used together with threshold to decide the cutoff. Will influence the actual truncation rank. When being left as None, the threshold is treated as the plain cutoff value. Otherwise, cutoff rank is the largest int satisfies: threshold * norm(s) > norm(s[rank:]). mult_s: bool, optional Whether or not to multiply U and V by S**0.5 to decompose A into two tensors instead of three. True by default. Returns ------- u: tensor_like A unitary tensor with indices ordered by the Einstein notation string. s: 1d tensor_like A 1d tensor containing singular values sorted in descending order. v: tensor_like A unitary tensor with indices ordered by the Einstein notation string. """ str_a, str_uv = einstr.replace(' ', '').split('->') str_u, str_v = str_uv.split(',') char_i = list(set(str_v) - set(str_a))[0] shape_u = np.prod([A.shape[str_a.find(c)] for c in str_u if c != char_i]) shape_v = np.prod([A.shape[str_a.find(c)] for c in str_v if c != char_i]) rank = rank or min(shape_u, shape_v) if size_limit is not None: if np.isscalar(size_limit): size_limit = (size_limit, size_limit) if size_limit[0] is not None: rank = min(rank, int(size_limit[0] / shape_u) or 1) if size_limit[1] is not None: rank = min(rank, int(size_limit[1] / shape_v) or 1) if threshold is None or criterion is None: u, s, vh = A.i(str_a).svd(str_u, str_v, rank, threshold) else: u, s, vh = A.i(str_a).svd(str_u, str_v) threshold = threshold * ctf.norm(s, criterion) # will always preserve at least one singular value for i in range(rank, 0, -1): if ctf.norm(s[i - 1:], criterion) >= threshold: rank = i break if rank < s.size: u = u[tuple(slice(None) for i in range(str_u.find(char_i))) + (slice(0, rank), )] s = s[:rank] vh = vh[tuple(slice(None) for i in range(str_v.find(char_i))) + (slice(0, rank), )] if mult_s: char_s = list(set(string.ascii_letters) - set(str_v))[0] sqrtS = ctf.diag(s**0.5) vh = ctf.einsum( char_s + char_i + ',' + str_v + '->' + str_v.replace(char_i, char_s), sqrtS, vh) char_s = list(set(string.ascii_letters) - set(str_u))[0] u = ctf.einsum( str_u + ',' + char_s + char_i + '->' + str_u.replace(char_i, char_s), u, sqrtS) return u, s, vh