def svd(tensor,row,new,col,nmax=None,tol=None,returnerr=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,returnerr : Please refer to HamiltonianPy.Misc.Linalg.truncatedsvd for details. Returns ------- U,S,V : DTensor/STensor The result tensor. err : float, 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): rowlabel,rowrecord=Label.union(row,'__TENSOR_SVD_ROW__',+1,mode=2) collabel,colrecord=Label.union(col,'__TENSOR_SVD_COL__',-1,mode=2) m=tensor.merge((row,rowlabel,rowrecord),(col,collabel,colrecord)).data us,ss,vs,qns=[],[],[],[] for (rowqn,colqn),block in m.items(): 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=[rowlabel,new.replace(flow=-1)]).split((rowlabel,row,rowrecord)) S=DTensor(np.concatenate(Ss),labels=[new]) V=STensor(Vs,labels=[new.replace(flow=+1),collabel]).split((collabel,col,colrecord)) if returnerr: err=(temp[nmax:]**2).sum() elif tensor.qnon: rowlabel,rowpermutation=Label.union(row,'__TENSOR_SVD_ROW__',+1,mode=1) collabel,colpermutation=Label.union(col,'__TENSOR_SVD_COL__',-1,mode=1) m=tensor.merge((row,rowlabel,rowpermutation),(col,collabel,colpermutation)).data rowod,colod=rowlabel.qns.toordereddict(),collabel.qns.toordereddict() us,ss,vs,qns=[],[],[],[] for qn in filter(lambda key: key in rowod,colod): u,s,v=sl.svd(m[rowod[qn],colod[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.toordereddict() U=np.zeros((rowlabel.dim,new.dim),dtype=tensor.dtype) V=np.zeros((new.dim,collabel.dim),dtype=tensor.dtype) for u,v,qn in zip(Us,Vs,od): U[rowod[qn],od[qn]]=u V[od[qn],colod[qn]]=v U=DTensor(U,labels=[rowlabel,new.replace(flow=-1)]).split((rowlabel,row,np.argsort(rowpermutation))) S=DTensor(S,labels=[new]) V=DTensor(V,labels=[new.replace(flow=+1),collabel]).split((collabel,col,np.argsort(colpermutation))) if returnerr: err=(temp[nmax:]**2).sum() else: rowlabel=Label('__TENSOR_SVD_ROW__',qns=np.product([label.dim for label in row])) collabel=Label('__TENSOR_SVD_COL__',qns=np.product([label.dim for label in col])) m=tensor.merge((row,rowlabel),(col,collabel)).data temp=hm.truncatedsvd(m,full_matrices=False,nmax=nmax,tol=tol,returnerr=returnerr,**karg) u,s,v=temp[0],temp[1],temp[2] new=new.replace(qns=len(s),flow=None) U=DTensor(u,labels=[rowlabel,new.replace(flow=0)]).split((rowlabel,row)) S=DTensor(s,labels=[new]) V=DTensor(v,labels=[new.replace(flow=0),collabel]).split((collabel,col)) if returnerr: err=temp[3] return (U,S,V,err) if returnerr else (U,S,V)
def partitionedsvd(tensor,L,new,R,nmax=None,tol=None,ttype='D',returnerr=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. ttype : 'D'/'S', optional Tensor type. 'D' for dense and 'S' for sparse. nmax,tol,returnerr : Please refer to HamiltonianPy.Misc.Linalg.truncatedsvd for details. Returns ------- U,S,V : DTensor/STensor The Schmitt decomposition of the 1d tensor. err : float, optional The truncation error. ''' assert tensor.ndim==1 and ttype 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.toordereddict(),R.qns.toordereddict() us,ss,vs,qns,count=[],[],[],[],0 for qn in filter(lambda key: key in lod,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 ttype=='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.toordereddict() 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 returnerr: err=(temp[nmax:]**2).sum() else: m=tensor.data.reshape((L.dim,R.dim)) data=hm.truncatedsvd(m,full_matrices=False,nmax=nmax,tol=tol,returnerr=returnerr) 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 returnerr: err=data[3] return (U,S,V,err) if returnerr else (U,S,V)