def svd(tensor, row, new, col, nmax=None, tol=None, return_truncation_err=False, **karg): ''' Perform the svd. Parameters ---------- tensor : DTensor/STensor The tensor to be svded. row,col : list of Label or int The labels or axes to be merged as the row/column during the svd. new : Label The label for the singular values. nmax,tol,return_truncation_err : Please refer to HamiltonianPy.Misc.Linalg.truncated_svd for details. Returns ------- U,S,V : DTensor/STensor The result tensor. err : np.float64, optional The truncation error. ''' assert len(row) + len(col) == tensor.ndim row = [r if isinstance(r, Label) else tensor.label(r) for r in row] col = [c if isinstance(c, Label) else tensor.label(c) for c in col] if isinstance(tensor, STensor): row_label, row_record = Label.union(row, '__TENSOR_SVD_ROW__', +1, mode=2) col_label, col_record = Label.union(col, '__TENSOR_SVD_COL__', -1, mode=2) m = tensor.merge((row, row_label, row_record), (col, col_label, col_record)).data us, ss, vs, qns = [], [], [], [] for (rowqn, colqn), block in m.iteritems(): assert rowqn == colqn u, s, v = sl.svd(block, full_matrices=False, lapack_driver='gesvd')[0:3] us.append(u) ss.append(s) vs.append(v) qns.append(rowqn) temp = np.sort(np.concatenate([-s for s in ss])) nmax = len(temp) if nmax is None else min(nmax, len(temp)) tol = temp[nmax - 1] if tol is None else min(-tol, temp[nmax - 1]) Us, Ss, Vs, contents = {}, [], {}, ([], []) for u, s, v, qn in zip(us, ss, vs, qns): cut = np.searchsorted(-s, tol, side='right') if cut > 0: Us[(qn, qn)] = u[:, 0:cut] Ss.append(s[0:cut]) Vs[(qn, qn)] = v[0:cut, :] contents[0].append(qn) contents[1].append(cut) new = new.replace(qns=QuantumNumbers('U', contents, protocol=QuantumNumbers.COUNTS), flow=None) U = STensor(Us, labels=[row_label, new.replace(flow=-1)]).split( (row_label, row, row_record)) S = DTensor(np.concatenate(Ss), labels=[new]) V = STensor(Vs, labels=[new.replace(flow=+1), col_label]).split( (col_label, col, col_record)) if return_truncation_err: err = (temp[nmax:]**2).sum() elif tensor.qnon: row_label, row_permutation = Label.union(row, '__TENSOR_SVD_ROW__', +1, mode=1) col_label, col_permutation = Label.union(col, '__TENSOR_SVD_COL__', -1, mode=1) m = tensor.merge((row, row_label, row_permutation), (col, col_label, col_permutation)).data row_od, col_od = row_label.qns.to_ordereddict( ), col_label.qns.to_ordereddict() us, ss, vs, qns = [], [], [], [] for qn in it.ifilter(row_od.has_key, col_od): u, s, v = sl.svd(m[row_od[qn], col_od[qn]], full_matrices=False, lapack_driver='gesvd')[0:3] us.append(u) ss.append(s) vs.append(v) qns.append(qn) temp = np.sort(np.concatenate([-s for s in ss])) nmax = len(temp) if nmax is None else min(nmax, len(temp)) tol = temp[nmax - 1] if tol is None else min(-tol, temp[nmax - 1]) Us, Ss, Vs, contents = [], [], [], ([], []) for u, s, v, qn in zip(us, ss, vs, qns): cut = np.searchsorted(-s, tol, side='right') if cut > 0: Us.append(u[:, 0:cut]) Ss.append(s[0:cut]) Vs.append(v[0:cut, :]) contents[0].append(qn) contents[1].append(cut) S = np.concatenate(Ss) new = new.replace(qns=QuantumNumbers('U', contents, protocol=QuantumNumbers.COUNTS), flow=None) od = new.qns.to_ordereddict() U = np.zeros((row_label.dim, new.dim), dtype=tensor.dtype) V = np.zeros((new.dim, col_label.dim), dtype=tensor.dtype) for u, v, qn in zip(Us, Vs, od): U[row_od[qn], od[qn]] = u V[od[qn], col_od[qn]] = v U = DTensor(U, labels=[row_label, new.replace(flow=-1)]).split( (row_label, row, np.argsort(row_permutation))) S = DTensor(S, labels=[new]) V = DTensor(V, labels=[new.replace(flow=+1), col_label]).split( (col_label, col, np.argsort(col_permutation))) if return_truncation_err: err = (temp[nmax:]**2).sum() else: row_label = Label('__TENSOR_SVD_ROW__', qns=np.product([label.dim for label in row])) col_label = Label('__TENSOR_SVD_COL__', qns=np.product([label.dim for label in col])) m = tensor.merge((row, row_label), (col, col_label)).data temp = hm.truncated_svd(m, full_matrices=False, nmax=nmax, tol=tol, return_truncation_err=return_truncation_err, **karg) u, s, v = temp[0], temp[1], temp[2] new = new.replace(qns=len(s), flow=None) U = DTensor(u, labels=[row_label, new.replace(flow=0)]).split( (row_label, row)) S = DTensor(s, labels=[new]) V = DTensor(v, labels=[new.replace(flow=0), col_label]).split( (col_label, col)) if return_truncation_err: err = temp[3] return (U, S, V, err) if return_truncation_err else (U, S, V)
def partitioned_svd(tensor, L, new, R, mode='D', nmax=None, tol=None, return_truncation_err=False): ''' Partition a 1d-tensor according to L and R and then perform the Schmitt decomposition. Parameters ---------- tensor : DTensor The tensor to be partitioned_svded. L,R : Label The left/right part of the partition. new : Label The label for the singular values. mode : 'D'/'S', optional 'D' for dense and 'S' for sparse. nmax,tol,return_truncation_err : Please refer to HamiltonianPy.Misc.Linalg.truncated_svd for details. Returns ------- U,S,V : DTensor/STensor The Schmitt decomposition of the 1d tensor. err : np.float64, optional The truncation error. ''' assert tensor.ndim == 1 and mode in 'DS' if tensor.qnon: data, qns = tensor.data, tensor.labels[0].qns assert qns.num == 1 and sl.norm(qns.contents) < 10**-6 lod, rod = L.qns.to_ordereddict(), R.qns.to_ordereddict() us, ss, vs, qns, count = [], [], [], [], 0 for qn in it.ifilter(lod.has_key, rod): s1, s2 = lod[qn], rod[qn] n1, n2 = s1.stop - s1.start, s2.stop - s2.start u, s, v = sl.svd(data[count:count + n1 * n2].reshape((n1, n2)), full_matrices=False, lapack_driver='gesvd')[0:3] us.append(u) ss.append(s) vs.append(v) qns.append(qn) count += n1 * n2 temp = np.sort(np.concatenate([-s for s in ss])) nmax = len(temp) if nmax is None else min(nmax, len(temp)) tol = temp[nmax - 1] if tol is None else min(-tol, temp[nmax - 1]) if mode == 'D': Us, Ss, Vs, contents = [], [], [], ([], []) for u, s, v, qn in zip(us, ss, vs, qns): cut = np.searchsorted(-s, tol, side='right') if cut > 0: Us.append(u[:, 0:cut]) Ss.append(s[0:cut]) Vs.append(v[0:cut, :]) contents[0].append(qn) contents[1].append(cut) new = new.replace(qns=QuantumNumbers('U', contents, QuantumNumbers.COUNTS), flow=None) nod = new.qns.to_ordereddict() U = np.zeros((L.dim, new.dim), dtype=tensor.dtype) S = np.concatenate(Ss) V = np.zeros((new.dim, R.dim), dtype=tensor.dtype) for u, v, qn in zip(Us, Vs, nod): U[lod[qn], nod[qn]] = u V[nod[qn], rod[qn]] = v U = DTensor(U, labels=[L, new.replace(flow=-1)]) S = DTensor(S, labels=[new]) V = DTensor(V, labels=[new.replace(flow=+1), R]) else: Us, Ss, Vs, contents = {}, [], {}, ([], []) for u, s, v, qn in zip(us, ss, vs, qns): cut = np.searchsorted(-s, tol, side='right') if cut > 0: Us[(qn, qn)] = u[:, 0:cut] Ss.append(s[0:cut]) Vs[(qn, qn)] = v[0:cut, :] contents[0].append(qn) contents[1].append(cut) new = new.replace(qns=QuantumNumbers('U', contents, QuantumNumbers.COUNTS), flow=None) U = STensor(Us, labels=[L, new.replace(flow=-1)]) S = DTensor(np.concatenate(Ss), labels=[new]) V = STensor(Vs, labels=[new.replace(flow=+1), R]) if return_truncation_err: err = (temp[nmax:]**2).sum() else: m = tensor.data.reshape((L.dim, R.dim)) data = hm.truncated_svd(m, full_matrices=False, nmax=nmax, tol=tol, return_truncation_err=return_truncation_err) new = new.replace(qns=len(data[1]), flow=None) U = DTensor(data[0], labels=[L, new.replace(flow=0)]) S = DTensor(data[1], labels=[new]) V = DTensor(data[2], labels=[new.replace(flow=0), R]) if return_truncation_err: err = data[3] return (U, S, V, err) if return_truncation_err else (U, S, V)