def FBFMEB(engine,app): ''' This method calculates the energy spectrums of the spin excitations. ''' path,ne=app.path,min(app.ne or engine.nmatrix,engine.nmatrix) if path is not None: bz,reciprocals=engine.basis.BZ,engine.lattice.reciprocals if not isinstance(path,HP.BaseSpace): path=bz.path(HP.KMap(reciprocals,path) if isinstance(path,str) else path,mode='Q') result=np.zeros((path.rank(0),ne+1)) result[:,0]=path.mesh(0) if path.mesh(0).ndim==1 else np.array(range(path.rank(0))) engine.log<<'%s: '%path.rank(0) for i,paras in enumerate(path('+')): engine.log<<'%s%s'%(i,'..' if i<path.rank(0)-1 else '') m=engine.matrix(scalefree=app.scalefree,scaleint=app.scaleint,**paras) result[i,1:]=nl.eigvalsh(m)[:ne] if app.method=='eigvalsh' else HM.eigsh(m,k=ne,evon=False) engine.log<<'\n' else: result=np.zeros((2,ne+1)) result[:,0]=np.array(range(2)) m=engine.matrix(scalefree=app.scalefree,scaleint=app.scaleint) result[0,1:]=nl.eigvalsh(m)[:ne] if app.method=='eigvalsh' else HM.eigsh(m,k=ne,evon=False) result[1,1:]=result[0,1:] name='%s_%s%s'%(engine.tostr(mask=path.tags),app.name,app.suffix) if app.savedata: np.savetxt('%s/%s.dat'%(engine.dout,name),result) if app.plot: app.figure('L',result,'%s/%s'%(engine.dout,name)) if app.returndata: return result
def fedspcom(blocks, omega): ''' This function composes the zero-temperature single-particle Green's function of a fermionic system from its blocks. Parameters ---------- blocks : list of BGF The blocks of the Green's function. omega : number The frequency. Returns ------- 2d ndarray The composed Green's function. ''' assert len(blocks) in (2, 4) if len(blocks) == 2: return blocks[0].gf(omega).T + blocks[1].gf(omega) else: gfdw, indsdw = blocks[0].gf(omega).T + blocks[1].gf( omega), blocks[0].indices gfup, indsup = blocks[2].gf(omega).T + blocks[3].gf( omega), blocks[2].indices return HM.reorder(HM.block_diag(gfdw, gfup), axes=[0, 1], permutation=np.argsort( np.concatenate((indsdw, indsup))))
def VCAGPM(engine,app): ''' This method implements the grand potential based methods. ''' records={} def gp(values,keys): if tuple(values) not in records: engine.cache.pop('ptmesh',None) engine.update(**{key:value for key,value in zip(keys,values)}) engine.rundependences(app.name) records[tuple(values)]=engine.records[app.dependences[0]] return records[tuple(values)] if isinstance(app.BS,HP.BaseSpace): mode,nbs,nder,minormax='+',len(app.BS.tags),app.options.get('nder',0),app.options.get('minormax','min') result=np.zeros((app.BS.rank(0),nbs+nder+1)) for i,paras in enumerate(app.BS(mode)): result[i,0:nbs]=np.array(list(paras.values())) result[i,nbs]=gp(list(paras.values()),list(paras.keys())) if nder>0:result[:,nbs+1:]=HM.derivatives(result[:,0],result[:,nbs],ders=list(range(1,nder+1))).T index=np.argmin(result[:,-1]) if minormax=='min' else np.argmax(result[:,-1]) if minormax=='max' else np.argmax(np.abs(result[:,-1])) engine.log<<'Summary:\n%s\n'%HP.Sheet( cols= app.BS.tags+['%sgp'%('' if nder==0 else '%s der of '%HP.ordinal(nder-1))], contents= np.append(result[index,0:nbs],result[index,-1]).reshape((1,-1)) ) name='%s_%s'%(engine.tostr(mask=app.BS.tags),app.name) if app.savedata: np.savetxt('%s/%s.dat'%(engine.dout,name),result) if app.plot: app.figure('L',result,'%s/%s'%(engine.dout,name),interpolate=True,legend=['%sgp'%('%s der of '%HP.ordinal(k-1) if k>0 else '') for k in range(nder+1)]) if app.returndata: return result else: result=HM.fstable(gp,list(app.BS.values()),args=(list(app.BS.keys()),),**app.options) engine.log<<'Summary:\n%s\n'%HP.Sheet(cols=list(app.BS.keys())+['niter','nfev','gp'],contents=np.append(result.x,[result.nit,result.nfev,result.fun]).reshape((1,-1))) if app.savedata: np.savetxt('%s/%s_%s.dat'%(engine.dout,engine.tostr(mask=list(app.BS.keys())),app.name),np.append(result.x,result.fun)) if app.returndata: return {key:value for key,value in zip(list(app.BS.keys()),result.x)},result.fun
def VCAGPM(engine,app): ''' This method implements the grand potential based methods. ''' records={} def gp(values,keys): if tuple(values) not in records: engine.cache.pop('pt_kmesh',None) engine.update(**{key:value for key,value in zip(keys,values)}) engine.rundependences(app.name) records[tuple(values)]=engine.records[app.dependences[0]] return records[tuple(values)] if isinstance(app.BS,HP.BaseSpace): mode,nbs,nder,minormax='+',len(app.BS.tags),app.options.get('nder',0),app.options.get('minormax','min') result=np.zeros((app.BS.rank(0),nbs+nder+1)) for i,paras in enumerate(app.BS(mode)): result[i,0:nbs]=np.array(paras.values()) result[i,nbs]=gp(paras.values(),paras.keys()) if nder>0:result[:,nbs+1:]=HM.derivatives(result[:,0],result[:,nbs],ders=range(1,nder+1)).T index=np.argmin(result[:,-1]) if minormax=='min' else np.argmax(result[:,-1]) if minormax=='max' else np.argmax(np.abs(result[:,-1])) engine.log<<'Summary:\n%s\n'%HP.Sheet( cols= app.BS.tags+['%sgp'%('' if nder==0 else '%s der of '%HP.ordinal(nder-1))], contents= np.append(result[index,0:nbs],result[index,-1]).reshape((1,-1)) ) name='%s_%s'%(engine.tostr(mask=app.BS.tags),app.name) if app.savedata: np.savetxt('%s/%s.dat'%(engine.dout,name),result) if app.plot: app.figure('L',result,'%s/%s'%(engine.dout,name),interpolate=True,legend=['%sgp'%('%s der of '%HP.ordinal(k-1) if k>0 else '') for k in xrange(nder+1)]) if app.returndata: return result else: result=HM.fstable(gp,app.BS.values(),args=(app.BS.keys(),),**app.options) engine.log<<'Summary:\n%s\n'%HP.Sheet(cols=app.BS.keys()+['niter','nfev','gp'],contents=np.append(result.x,[result.nit,result.nfev,result.fun]).reshape((1,-1))) if app.savedata: np.savetxt('%s/%s_%s.dat'%(engine.dout,engine.tostr(mask=app.BS.keys()),app.name),np.append(result.x,result.fun)) if app.returndata: return {key:value for key,value in zip(app.BS.keys(),result.x)},result.fun
def prepare(self, groundstate, nstep): ''' Prepare the lanczos representation of the block. Parameters ---------- groundstate : 1d ndarray The ground state. nstep : int The number of iterations over the whole starting states. ''' matrix, operators = self.controllers['matrix'], self.controllers[ 'operators'] if self.method == 'S': self.controllers['vecs'], self.controllers['lczs'] = [], [] for operator in operators: v0 = operator.dot(groundstate) self.controllers['vecs'].append(v0.conjugate()) self.controllers['lczs'].append( HM.Lanczos(matrix, [v0], maxiter=nstep, keepstate=False)) self.controllers['vecs'] = np.asarray(self.controllers['vecs']) self.controllers['Qs'] = np.zeros( (len(operators), len(operators), nstep), dtype=matrix.dtype) else: self.controllers['lanczos'] = HM.Lanczos( matrix, v0=[operator.dot(groundstate) for operator in operators], maxiter=nstep * len(operators), keepstate=False)
def FBFMEB(engine, app): ''' This method calculates the energy spectrums of the spin excitations. ''' from mpi4py import MPI rank = MPI.COMM_WORLD.Get_rank() path, ne = app.path, min(app.ne or engine.nmatrix, engine.nmatrix) if path is not None: bz, reciprocals = engine.basis.BZ, engine.lattice.reciprocals if not isinstance(path, HP.BaseSpace): path = bz.path( HP.KMap(reciprocals, path) if isinstance(path, str) else path, mode='Q') result = np.zeros((path.rank(0), ne + 1)) result[:, 0] = path.mesh(0) if path.mesh(0).ndim == 1 else np.array( range(path.rank(0))) if rank == 0: engine.log << '%s: ' % path.rank(0) if app.np in (0, 1, None): for i, paras in enumerate(path('+')): engine.log << '%s%s' % (i, '..' if i < path.rank(0) - 1 else '') m = engine.matrix(scalefree=app.scalefree, scaleint=app.scaleint, **paras) result[i, 1:] = nl.eigvalsh( m)[:ne] if app.method == 'eigvalsh' else HM.eigsh( m, k=ne, which='SA', evon=False) else: def kenergy(paras, engine, app, i): engine.log << '%s%s' % (i, '..') m = engine.matrix(scalefree=app.scalefree, scaleint=app.scaleint, **paras) result = nl.eigvalsh( m)[:ne] if app.method == 'eigvalsh' else HM.eigsh( m, k=ne, which='SA', evon=False) return result for i, data in enumerate( HP.mpirun(kenergy, [(paras, engine, app, i) for i, paras in enumerate(path('+'))])): result[i, 1:] = data if rank == 0: engine.log << '\n' else: result = np.zeros((2, ne + 1)) result[:, 0] = np.array(range(2)) m = engine.matrix(scalefree=app.scalefree, scaleint=app.scaleint) result[0, 1:] = nl.eigvalsh( m)[:ne] if app.method == 'eigvalsh' else HM.eigsh( m, k=ne, evon=False) result[1, 1:] = result[0, 1:] if rank == 0: name = '%s_%s%s' % (engine.tostr(mask=path.tags), app.name, app.suffix) if app.savedata: np.savetxt('%s/%s.dat' % (engine.dout, name), result) if app.plot: app.figure('L', result, '%s/%s' % (engine.dout, name)) if app.returndata: return result
def test_algebra(self): self.assertAlmostEqual(norm(self.overlap*2.0-(self.mpo*2.0).overlap(self.mps1,self.mps2)),0.0) self.assertAlmostEqual(norm(self.overlap*2.0-(2.0*self.mpo).overlap(self.mps1,self.mps2)),0.0) self.assertAlmostEqual(norm(self.overlap/2.0-(self.mpo/2.0).overlap(self.mps1,self.mps2)),0.0) self.assertAlmostEqual(norm(self.overlap-hm.overlap(self.mps1.state,(self.mpo*self.mps2).state)),0.0) self.assertAlmostEqual(norm(hm.overlap(self.mps1.state,self.mopt.dot(self.mopt),self.mps2.state)-(self.mpo*self.mpo).overlap(self.mps1,self.mps2)),0.0) another,overlap=self.mpo/2.0,self.overlap/2.0 self.assertAlmostEqual(norm((self.overlap+overlap)-(self.mpo+another).overlap(self.mps1,self.mps2)),0.0) self.assertAlmostEqual(norm((self.overlap-overlap)-(self.mpo-another).overlap(self.mps1,self.mps2)),0.0)
def test_associativity(self): N,S=2,0.5 a,b,c,d=np.random.random((N,N)),np.random.random((N,N)),np.random.random((N,N)),np.random.random((N,N)) p4_2_2=QuantumNumbers.kron([QuantumNumbers.kron([SQNS(S)]*2,signs=(+1,-1))]*2,signs=(+1,+1)).sorted(history=True)[1] p41111=QuantumNumbers.kron([SQNS(S)]*4,signs=(+1,-1,+1,-1)).sorted(history=True)[1] tmp1,tmp2=np.kron(a,b),np.kron(c,d) m1=hm.reorder(np.kron(tmp1,tmp2),permutation=p4_2_2) m2=hm.reorder(np.kron(np.kron(np.kron(a,b),c),d),permutation=p41111) self.assertAlmostEqual(nl.norm(m2-m1),0.0,delta=10**-14)
def reorder(self, *args): ''' Reorder a dimension of a tensor with a permutation and optionally set a new qns for this dimension. Usage: ``tensor.reorder((axis,permutation,<qns>),(axis,permutation,<qns>),...)`` * axis: int/Label The axis of the dimension to be reordered. * permutation: 1d ndarray of int The permutation array. * qns: QuantumNumbers, optional The new quantum number collection of the dimension if good quantum numbers are used. Returns ------- DTensor The reordered tensor. Notes ----- If `qns` is not passed, the new qns will be automatically set according to the permutation array. ''' result, qnon = copy(self), self.qnon for arg in args: assert len(arg) in (2, 3) axis, permutation = arg[0], arg[1] if permutation is not None: axis = self.axis(axis) if isinstance(axis, Label) else axis label = result.labels[axis] result.labels[axis] = label.replace( qns=arg[2] if len(arg) == 3 else label.qns. reorder(permutation) if qnon else len(permutation)) result.data = hm.reorder(result.data, axes=[axis], permutation=permutation) return result
def set(self,gse): ''' Set the Lambda matrix, Q matrix and QT matrix of the block. Parameters ---------- gse : number The groundstate energy. ''' sign=self.controllers['sign'] if self.method=='S': lczs,Qs=self.controllers['lczs'],self.controllers['Qs'] self.data['niters']=np.zeros(Qs.shape[0],dtype=np.int32) self.data['Lambdas']=np.zeros((Qs.shape[0],Qs.shape[2]),dtype=np.float64) self.data['Qs']=np.zeros(Qs.shape,dtype=Qs.dtype) self.data['QTs']=np.zeros((Qs.shape[0],Qs.shape[2]),dtype=Qs.dtype) for i,(lcz,Q) in enumerate(zip(lczs,Qs)): if lcz.niter>0: E,V=sl.eigh(lcz.T,eigvals_only=False) self.data['niters'][i]=lcz.niter self.data['Lambdas'][i,0:lcz.niter]=sign*(E-gse) self.data['Qs'][i,:,0:lcz.niter]=Q[:,0:lcz.niter].dot(V) self.data['QTs'][i,0:lcz.niter]=lcz.P[0,0]*V[0,:].conjugate() else: lanczos=self.controllers['lanczos'] E,V=sl.eigh(lanczos.T,eigvals_only=False) self.data['Lambda']=sign*(E-gse) self.data['Q']=lanczos.P[:min(lanczos.nv0,lanczos.niter),:].T.conjugate().dot(V[:min(lanczos.nv0,lanczos.niter),:]) self.data['QT']=HM.dagger(self.data['Q'])
def split(self,*args): ''' Split a label into small ones with an optional permutation. Usage: ``tensor.split((old,news,<permutation>),(old,news,<permutation>),...)`` * old: Label/int The label/axis to be split. * news: list of Label The new labels. * permutation: 1d ndarray of int, optional The permutation of the quantum number collection of the old label. Returns ------- DTensor The new tensor. ''' table={(self.axis(arg[0]) if isinstance(arg[0],Label) else arg[0]):i for i,arg in enumerate(args)} shape,labels,axes,permutations=(),[],[],[] for axis,dim,label in zip(range(self.ndim),self.shape,self.labels): if axis in table: arg=args[table[axis]] assert len(arg) in (2,3) shape+=tuple(new.dim for new in arg[1]) labels.extend(arg[1]) axes.append(axis) permutations.append(arg[2] if len(arg)==3 else None) else: shape+=(dim,) labels.append(label) data=self.data for axis,permutation in zip(axes,permutations): data=hm.reorder(data,axes=[axis],permutation=permutation) return DTensor(data.reshape(shape),labels=labels)
def fbfmphaseboundary(task, name, parameters, lattice, terms, interactions, ranges, nk=50, scalefree=1.0, scaleint=1.0): import HamiltonianPy.FBFM as FB import HamiltonianPy.Misc as hm assert len(lattice.vectors) == 2 ns, ne = len(lattice), len(lattice) // 2 basis = FB.FBFMBasis(BZ=FBZ(lattice.reciprocals, nks=(nk, nk)), filling=Fraction(ne, ns * 2)) def updateparam(parameters, key, value): if key == 't2': parameters['t2'] = value if key == 'dU': parameters['Ub'] = parameters['Ua'] - value if task == 'nfm-fm: t2' or task == 'nfm-fm: dU': def phaseboundary(param): updateparam(parameters, task[-2:], param) fbfm = fbfmconstruct(name, parameters, basis, lattice, terms, interactions) print(fbfm) fbfm.register( FB.EB(name='EB%s' % nk, path='H:G-K1,K1-M1,M1-K2,K2-G', ne=nk**2, scalefree=scalefree, scaleint=scaleint, plot=False, savedata=False, run=FB.FBFMEB)) data = fbfm.records['EB%s' % nk] return -1 if np.any(data[:, 1] < -10**-8) else +1 elif task == 'tfm-fm: t2' or task == 'tfm-fm: dU': def phaseboundary(param): updateparam(parameters, task[-2:], param) fbfm = fbfmconstruct(name, parameters, basis, lattice, terms, interactions) fbfm.register( FB.CN(name='CN%s' % nk, BZ=basis.BZ, ns=(0, 1), scalefree=scalefree, scaleint=scaleint, run=FB.FBFMCN)) data = fbfm.records['CN%s' % nk] return -1 if np.abs(data[0]) < 10**-4 else +1 else: raise ValueError("fbfmphaseboundary error: not supported task(%s)." % task) result = hm.bisect(phaseboundary, ranges) print(result) return result
def reorder(self,*args): ''' Reorder a dimension of a tensor with a permutation and optionally set a new qns for this dimension. Usage: ``tensor.reorder((axis,permutation,<qns>),(axis,permutation,<qns>),...)`` * axis: int/Label The axis of the dimension to be reordered. * permutation: 1d ndarray of int The permutation array. * qns: QuantumNumbers, optional The new quantum number collection of the dimension if good quantum numbers are used. Returns ------- DTensor The reordered tensor. Notes ----- If `qns` is not passed, the new qns will be automatically set according to the permutation array. ''' result,qnon=copy(self),self.qnon for arg in args: assert len(arg) in (2,3) axis,permutation=arg[0],arg[1] if permutation is not None: axis=self.axis(axis) if isinstance(axis,Label) else axis label=result.labels[axis] result.labels[axis]=label.replace(qns=arg[2] if len(arg)==3 else label.qns.reorder(permutation) if qnon else len(permutation)) result.data=hm.reorder(result.data,axes=[axis],permutation=permutation) return result
def set(self, gse): ''' Set the Lambda matrix, Q matrix and QT matrix of the block. Parameters ---------- gse : number The groundstate energy. ''' sign = self.controllers['sign'] if self.method == 'S': lczs, Qs = self.controllers['lczs'], self.controllers['Qs'] self.data['niters'] = np.zeros(Qs.shape[0], dtype=np.int32) self.data['Lambdas'] = np.zeros((Qs.shape[0], Qs.shape[2]), dtype=np.float64) self.data['Qs'] = np.zeros(Qs.shape, dtype=Qs.dtype) self.data['QTs'] = np.zeros((Qs.shape[0], Qs.shape[2]), dtype=Qs.dtype) for i, (lcz, Q) in enumerate(zip(lczs, Qs)): if lcz.niter > 0: E, V = sl.eigh(lcz.T, eigvals_only=False) self.data['niters'][i] = lcz.niter self.data['Lambdas'][i, 0:lcz.niter] = sign * (E - gse) self.data['Qs'][i, :, 0:lcz.niter] = Q[:, 0:lcz.niter].dot(V) self.data['QTs'][ i, 0:lcz.niter] = lcz.P[0, 0] * V[0, :].conjugate() else: lanczos = self.controllers['lanczos'] E, V = sl.eigh(lanczos.T, eigvals_only=False) self.data['Lambda'] = sign * (E - gse) self.data['Q'] = lanczos.P[:min( lanczos.nv0, lanczos.niter), :].T.conjugate().dot( V[:min(lanczos.nv0, lanczos.niter), :]) self.data['QT'] = HM.dagger(self.data['Q'])
def kenergy(paras, engine, app, i): engine.log << '%s%s' % (i, '..') m = engine.matrix(scalefree=app.scalefree, scaleint=app.scaleint, **paras) result = nl.eigvalsh( m)[:ne] if app.method == 'eigvalsh' else HM.eigsh( m, k=ne, which='SA', evon=False) return result
def test_mpo_spin(): print 'test_mpo_spin' # set the lattice and terms lattice = Cylinder(name='WG', block=[np.array([0.0, 0.0]), np.array([0.0, 1.0])], translation=np.array([1.0, 0.0]))([0, 1]) terms = [SpinTerm('J', 1.0, neighbour=1, indexpacks=Heisenberg())] # set the degfres S, priority, layers = 0.5, ['scope', 'site', 'orbital', 'S'], [('scope', ), ('site', 'orbital', 'S')] config = IDFConfig(priority=priority, pids=lattice.pids, map=lambda pid: Spin(S=S)) table = config.table(mask=[]) degfres = DegFreTree(mode='QN', layers=layers, priority=priority, leaves=table.keys(), map=lambda index: SQNS(S)) # set the operators opts = Generator(lattice.bonds, config, terms=terms, dtype=np.float64).operators.values() optstrs = [OptStr.from_operator(opt, degfres, layers[-1]) for opt in opts] mpos = [optstr.to_mpo(degfres) for optstr in optstrs] # set the states sites, bonds = degfres.labels(mode='S', layer=layers[-1]), degfres.labels( mode='B', layer=layers[-1]) bonds[+0] = bonds[+0].replace(qns=QuantumNumbers.mono(SQN(0.0))) bonds[-1] = bonds[-1].replace(qns=QuantumNumbers.mono(SQN(0.0))) cut = np.random.randint(0, len(lattice) + 1) mps1, mps2 = MPS.random(sites, bonds, cut=cut, nmax=20), MPS.random(sites, bonds, cut=cut, nmax=20) # set the reference of test mopts = [soptrep(opt, table) for opt in opts] overlaps = [hm.overlap(mps1.state, mopt, mps2.state) for mopt in mopts] # test optstr test_optstr_overlap(optstrs, mps1, mps2, overlaps) test_optstr_algebra(optstrs, mps1, mps2, overlaps) test_optstr_relayer(optstrs, degfres, mps1, mps2, overlaps) # test mpo test_mpo_overlap(mpos, mps1, mps2, overlaps) test_mpo_algebra(mpos, mps1, mps2, mopts, overlaps) test_mpo_relayer(mpos, degfres, mps1, mps2, overlaps) print
def test_mpo_algebra(mpos, mps1, mps2, mopts, overlaps): print 'test_mpo_algebra' mopt, summation = sum(mopts), sum(overlaps) for i, mpo in enumerate(mpos): M = mpo if i == 0 else M + mpo print 'Compression of MPO' print 'Before compression' print 'shapes: %s' % (','.join(str(m.shape) for m in M)) print 'bonds.qnses: %s,%s' % (','.join( repr(m.labels[0].qns) for m in M), repr(M[-1].labels[-1].qns)) M.compress(nsweep=4, method='dpl') print 'After compression' print 'shapes: %s' % (','.join(str(m.shape) for m in M)) print 'bonds.qnses: %s,%s' % (','.join( repr(m.labels[0].qns) for m in M), repr(M[-1].labels[-1].qns)) print print '+,-*,/ of MPO' pos = np.random.randint(len(mpos)) print 'Addition diff: %s' % norm(summation - M.overlap(mps1, mps2)) print 'Subtraction diff: %s' % norm(summation - overlaps[pos] - (M - mpos[pos]).overlap(mps1, mps2)) print 'Left multiplication diff: %s' % norm(summation * 2.0 - (M * 2.0).overlap(mps1, mps2)) print 'Right multiplication diff: %s' % norm(summation * 2.0 - (2.0 * M).overlap(mps1, mps2)) print 'Division diff: %s' % norm(summation / 2.0 - (M / 2.0).overlap(mps1, mps2)) print print 'MPO*MPS, MPO*MPO' print 'mps.cut: %s' % mps2.cut print 'MPO*MPS diff: %s' % norm(summation - hm.overlap(mps1.state, (M * mps2).state)) print 'MPO*MPO diff: %s' % norm( hm.overlap(mps1.state, mopt.dot(mopt), mps2.state) - (M * M).overlap(mps1, mps2)) print
def FBFMEB(engine, app): ''' This method calculates the energy spectrums of the spin excitations. ''' path, ne = app.path, min(app.ne or engine.nmatrix, engine.nmatrix) if path is not None: bz, reciprocals = engine.basis.BZ, engine.lattice.reciprocals parameters = list(path('+')) if isinstance(path, HP.BaseSpace) else [{ 'k': bz[pos] } for pos in bz.path( HP.KMap(reciprocals, path) if isinstance(path, str) else path, mode='I')] result = np.zeros((len(parameters), ne + 1)) result[:, 0] = path.mesh(0) if isinstance( path, HP.BaseSpace) and path.mesh(0).ndim == 1 else np.array( xrange(len(parameters))) engine.log << '%s: ' % len(parameters) for i, paras in enumerate(parameters): engine.log << '%s%s' % (i, '..' if i < len(parameters) - 1 else '') m = engine.matrix(**paras) result[i, 1:] = sl.eigh( m, eigvals_only=False )[0][:ne] if app.method == 'eigh' else HM.eigsh( m, k=ne, return_eigenvectors=False) engine.log << '\n' else: result = np.zeros((2, ne + 1)) result[:, 0] = np.array(xrange(2)) result[0, 1:] = sl.eigh( engine.matrix(), eigvals_only=True)[:ne] if app.method == 'eigh' else HM.eigsh( engine.matrix(), k=ne, return_eigenvectors=False) result[1, 1:] = result[0, 1:] name = '%s_%s' % (engine.tostr( mask=path.tags if isinstance(path, HP.BaseSpace) else ()), app.name) if app.savedata: np.savetxt('%s/%s.dat' % (engine.dout, name), result) if app.plot: app.figure('L', result, '%s/%s' % (engine.dout, name)) if app.returndata: return result
def merge(self, *args): ''' Merge some continuous and ascending labels of a tensor into a new one with an optional permutation. Usage: ``tensor.merge((olds,new,<permutation>),(olds,new,<permutation>),...)`` * olds: list of Label/int The old labels/axes to be merged. * new: Label The new label. * permutation: 1d ndarray of int, optional The permutation of the quantum number collection of the new label. Returns ------- DTensor The new tensor. ''' permutations = {} keep = OrderedDict([(i, i) for i in xrange(self.ndim)]) labels = OrderedDict([(i, label) for i, label in enumerate(self.labels)]) for arg in args: assert len(arg) in (2, 3) olds, new, permutation = (arg[0], arg[1], None) if len(arg) == 2 else arg axes = np.array([ self.axis(old) if isinstance(old, Label) else old for old in olds ]) if len(axes) != max(axes) - min(axes) + 1 or not all( axes[1:] > axes[:-1]): raise ValueError( 'DTensor merge error: the axes to be merged should be continuous and ascending, please call transpose first.' ) permutations[new] = permutation keep[axes[0]] = slice(axes[0], axes[-1] + 1) labels[axes[0]] = new for axis in axes[1:]: keep.pop(axis) labels.pop(axis) data = self.data.reshape( tuple( np.product(self.data.shape[ax] ) if isinstance(ax, slice) else self.data.shape[ax] for ax in keep.itervalues())) labels = labels.values() for label, permutation in permutations.iteritems(): data = hm.reorder(data, axes=[labels.index(label)], permutation=permutation) return DTensor(data, labels=labels)
def fedspcom(blocks,omega): ''' This function composes the zero-temperature single-particle Green's function of a fermionic/hard-core-bosonic system from its blocks. Parameters ---------- blocks : list of BGF The blocks of the Green's function. omega : number The frequency. Returns ------- 2d ndarray The composed Green's function. ''' assert len(blocks) in (2,4) if len(blocks)==2: return blocks[0].gf(omega).T+blocks[1].gf(omega) else: gfdw,indsdw=blocks[0].gf(omega).T+blocks[1].gf(omega),blocks[0].indices gfup,indsup=blocks[2].gf(omega).T+blocks[3].gf(omega),blocks[2].indices return HM.reorder(HM.blockdiag(gfdw,gfup),axes=[0,1],permutation=np.argsort(np.concatenate((indsdw,indsup))))
def qnsort(self,history=False): ''' Sort the quantum numbers of all the dimensions of the tensor. Returns ------- list of 1d ndarray, optional The permutation arrays of the dimensions of the tensor. Returned only when ``history`` is True. ''' permutations=[] for axis,label in enumerate(self.labels): assert label.qnon qns,permutation=(label.qns,None) if label.qns.form=='C' else label.qns.sorted(history=True) self.data=hm.reorder(self.data,axes=[axis],permutation=permutation) self.labels[axis]=label.replace(qns=qns) if history: permutations.append(permutation) if history: return permutations
def deparallelization(tensor,row,new,col,mode='R',zero=10**-8,tol=10**-6): ''' Deparallelize a tensor. Parameters ---------- tensor : DTensor The tensor to be deparalleled. row,col : list of Label or int The labels or axes to be merged as the row/column during the deparallelization. new : Label The label for the new axis after the deparallelization. mode : 'R', 'C', optional 'R' for the deparallelization of the row dimension; 'C' for the deparallelization of the col dimension. zero : float, optional The absolute value to identity zero vectors. tol : float, optional The relative tolerance for rows or columns that can be considered as paralleled. Returns ------- M : DTensor The deparallelized tensor. T : DTensor The coefficient matrix that satisfies T*M==m('R') or M*T==m('C'). ''' 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] rlabel=Label.union(row,'__TENSOR_DEPARALLELIZATION_ROW__',+1 if tensor.qnon else 0,mode=0) clabel=Label.union(col,'__TENSOR_DEPARALLELIZATION_COL__',-1 if tensor.qnon else 0,mode=0) data=tensor.merge((row,rlabel),(col,clabel)).data m1,m2,indices=hm.deparallelization(data,mode=mode,zero=zero,tol=tol,returnindices=True) if mode=='R': new=new.replace(qns=rlabel.qns.reorder(permutation=indices,protocol='EXPANSION') if tensor.qnon else len(indices)) T=DTensor(m1,labels=[rlabel,new.replace(flow=-1 if tensor.qnon else 0)]).split((rlabel,row)) M=DTensor(m2,labels=[new.replace(flow=+1 if tensor.qnon else 0),clabel]).split((clabel,col)) return T,M else: new=new.replace(qns=clabel.qns.reorder(permutation=indices,protocol='EXPANSION') if tensor.qnon else len(indices)) M=DTensor(m1,labels=[rlabel,new.replace(flow=-1 if tensor.qnon else 0)]).split((rlabel,row)) T=DTensor(m2,labels=[new.replace(flow=+1 if tensor.qnon else 0),clabel]).split((clabel,col)) return M,T
def EDEL(engine, app): ''' This method calculates the energy levels of the Hamiltonian. ''' name = '%s_%s' % (engine.tostr(mask=app.path.tags), app.name) result = np.zeros((app.path.rank(0), app.ns * (app.nder + 1) + 1)) result[:, 0] = app.path.mesh(0) if len( app.path.tags) == 1 and app.path.mesh(0).ndim == 1 else np.array( range(app.path.rank(0))) for i, paras in enumerate(app.path('+')): engine.update(**paras) result[i, 1:app.ns + 1] = engine.eigs( sector=app.sector, k=app.ns, evon=False, resetmatrix=True if i == 0 else False, resettimers=True if i == 0 else False)[1] engine.log << '%s\n\n' % engine.timers.tostr(HP.Timers.ALL) if app.plot: engine.timers.graph(parents=HP.Timers.ALL) else: if app.plot: engine.timers.cleancache() if app.savefig: plt.savefig('%s/%s_TIMERS.png' % (engine.log.dir, name)) plt.close() if app.nder > 0: for i in range(app.ns): result.T[[j * app.ns + i + 1 for j in range(1, app.nder + 1) ]] = HM.derivatives(result[:, 0], result[:, i + 1], ders=list(range(1, app.nder + 1))) if app.savedata: np.savetxt('%s/%s.dat' % (engine.dout, name), result) if app.plot: ns = app.ns options = { 'legend': [('%s der of ' % HP.ordinal(k // ns - 1) if k // ns > 0 else '') + '$E_{%s}$' % (k % ns) for k in range(result.shape[1] - 1)], 'legendloc': 'lower right' } if ns <= 10 else {} app.figure('L', result, '%s/%s' % (engine.dout, name), **options) if app.returndata: return result
def merge(self,*args): ''' Merge some continuous and ascending labels of a tensor into a new one with an optional permutation. Usage: ``tensor.merge((olds,new,<permutation>),(olds,new,<permutation>),...)`` * olds: list of Label/int The old labels/axes to be merged. * new: Label The new label. * permutation: 1d ndarray of int, optional The permutation of the quantum number collection of the new label. Returns ------- DTensor The new tensor. ''' permutations={} keep=OrderedDict([(i,i) for i in range(self.ndim)]) labels=OrderedDict([(i,label) for i,label in enumerate(self.labels)]) for arg in args: assert len(arg) in (2,3) olds,new,permutation=(arg[0],arg[1],None) if len(arg)==2 else arg axes=np.array([self.axis(old) if isinstance(old,Label) else old for old in olds]) if len(axes)!=max(axes)-min(axes)+1 or not all(axes[1:]>axes[:-1]): raise ValueError('DTensor merge error: the axes to be merged should be continuous and ascending, please call transpose first.') permutations[new]=permutation keep[axes[0]]=slice(axes[0],axes[-1]+1) labels[axes[0]]=new for axis in axes[1:]: keep.pop(axis) labels.pop(axis) data=self.data.reshape(tuple(np.product(self.data.shape[ax]) if isinstance(ax,slice) else self.data.shape[ax] for ax in keep.values())) labels=list(labels.values()) for label,permutation in permutations.items(): data=hm.reorder(data,axes=[labels.index(label)],permutation=permutation) return DTensor(data,labels=labels)
def EDEL(engine,app): ''' This method calculates the energy levels of the Hamiltonian. ''' name='%s_%s'%(engine.tostr(mask=app.path.tags),app.name) result=np.zeros((app.path.rank(0),app.ns*(app.nder+1)+1)) result[:,0]=app.path.mesh(0) if len(app.path.tags)==1 and app.path.mesh(0).ndim==1 else np.array(range(app.path.rank(0))) for i,paras in enumerate(app.path('+')): engine.update(**paras) result[i,1:app.ns+1]=engine.eigs(sector=app.sector,k=app.ns,evon=False,resetmatrix=True if i==0 else False,resettimers=True if i==0 else False)[1] engine.log<<'%s\n\n'%engine.timers.tostr(HP.Timers.ALL) if app.plot: engine.timers.graph(parents=HP.Timers.ALL) else: if app.plot: engine.timers.cleancache() if app.savefig: plt.savefig('%s/%s_TIMERS.png'%(engine.log.dir,name)) plt.close() if app.nder>0: for i in range(app.ns): result.T[[j*app.ns+i+1 for j in range(1,app.nder+1)]]=HM.derivatives(result[:,0],result[:,i+1],ders=list(range(1,app.nder+1))) if app.savedata: np.savetxt('%s/%s.dat'%(engine.dout,name),result) if app.plot: ns=app.ns options={'legend':[('%s der of '%HP.ordinal(k//ns-1) if k//ns>0 else '')+'$E_{%s}$'%(k%ns) for k in range(result.shape[1]-1)],'legendloc':'lower right'} if ns<=10 else {} app.figure('L',result,'%s/%s'%(engine.dout,name),**options) if app.returndata: return result
def eigs(self,sector,v0=None,k=1,evon=False,resetmatrix=True,resettimers=True,showes=True): ''' Lowest k eigenvalues and optionally, the corresponding eigenvectors. Parameters ---------- sector : any hashable object The sector of the eigensystem. v0 : 1d ndarray, optional The starting vector. k : int, optional The number of eigenvalues to be computed. evon : logical, optional True for returning the eigenvectors and False for not. resetmatrix : logical, optional True for resetting the matrix cache and False for not. resettimers : logical, optional True for resetting the timers and False for not. showes : logical, optional True for showing the calculated eigenvalues and False for not. Returns ------- sectors : list of any hashable object The sectors of the k eigenvalues es : 1d ndarray Array of k eigenvalues. vs : list of 1d ndarray, optional List of k eigenvectors. ''' self.log<<'::<Parameters>:: %s\n'%(', '.join('%s=%s'%(key,HP.decimaltostr(value,n=10)) for key,value in self.parameters.items())) if resettimers: self.timers.reset() if sector is None and len(self.sectors)>1: cols=['nopt','dim','nnz','Mt(s)','Et(s)']+(['E%s'%i for i in range(k-1,-1,-1)] if showes else []) widths=[14,4,8,10,10,10]+([13]*k if showes else []) info=HP.Sheet(corner='sector',rows=[repr(sector) for sector in self.sectors],cols=cols,widths=widths) self.log<<'%s\n%s\n%s\n'%(info.frame(),info.coltagstostr(corneron=True),info.division()) sectors,es,vs=[],[],[] for sector in self.sectors: with self.timers.get('Matrix'): matrix=self.matrix(sector,reset=resetmatrix) V0=None if v0 is None or matrix.shape[0]!=v0.shape[0] else v0 with self.timers.get('ES'): eigs=HM.eigsh(matrix,v0=V0,k=min(k,matrix.shape[0]),which='SA',evon=evon) self.timers.record() sectors.extend([sector]*min(k,matrix.shape[0])) es.extend(eigs[0] if evon else eigs) if evon: vs.extend(eigs[1].T) info[(repr(sector),'nopt')]=len(self.operators) info[(repr(sector),'dim')]=matrix.shape[0] info[(repr(sector),'nnz')]=matrix.nnz info[(repr(sector),'Mt(s)')]=self.timers['Matrix'].records[-1],'%.4e' info[(repr(sector),'Et(s)')]=self.timers['ES'].records[-1],'%.4e' for j in range(k-1,-1,-1): info[(repr(sector),'E%s'%j)]=(es[-1-j],'%.8f') if j<matrix.shape[0] else '' self.log<<'%s\n'%info.rowtostr(row=repr(sector)) indices=np.argsort(es)[:k] sectors=[sectors[index] for index in indices] es=np.asarray(es)[indices] if evon: vs=[vs[index] for index in indices] self.log<<'%s\n'%info.frame() else: if sector is None: sector=next(iter(self.sectors)) with self.timers.get('Matrix'): matrix=self.matrix(sector,reset=resetmatrix) self.log<<'::<Information>:: sector=%r, nopt=%s, dim=%s, nnz=%s, '%(sector,len(self.operators),matrix.shape[0],matrix.nnz) V0=None if v0 is None or matrix.shape[0]!=v0.shape[0] else v0 with self.timers.get('ES'): eigs=HM.eigsh(matrix,v0=V0,k=k,which='SA',evon=evon) self.timers.record() sectors=[sector]*k es=eigs[0] if evon else eigs if evon: vs=list(eigs[1].T) self.log<<'Mt=%.4es, Et=%.4es'%(self.timers['Matrix'].records[-1],self.timers['ES'].records[-1]) self.log<<(', evs=%s\n'%(' '.join('%.8f'%e for e in es)) if showes else '\n') return (sectors,es,vs) if evon else (sectors,es)
def iterate(self, log, info='', sp=True, nmax=200, tol=10**-6, divisor=None, piechart=True): ''' The two site dmrg step. Parameters ---------- log : Log The log file. info : str, optional The information string passed to self.log. sp : logical, optional True for state prediction False for not. nmax : int, optional The maximum singular values to be kept. tol : float, optional The tolerance of the singular values. divisor : int/None, optional * When int, it is used as the divisor to calculated the ground state energy per site; * When None, the default divisor will be used to calculated the ground state energy per site. piechart : logical, optional True for showing the piechart of self.timers while False for not. ''' log << '%s(%s)\n%s\n' % (info, self.ttype, self.graph) with self.timers.get('Preparation'): Ha, Hasite = self.lcontracts[self.cut - 1], self.mpo[self.cut - 1] Hb, Hbsite = self.rcontracts[self.cut + 1], self.mpo[self.cut] Oa, (La, Sa, Ra) = Hasite.labels[MPO.R], self.mps[self.cut - 1].labels Ob, (Lb, Sb, Rb) = Hbsite.labels[MPO.L], self.mps[self.cut].labels assert Ra == Lb and Oa == Ob Lsys, sysinfo = Label.union([La, Sa], '__DMRG_ITERATE_SYS__', flow=+1 if self.mps.qnon else 0, mode=+2 if self.ttype == 'S' else +1) Lenv, envinfo = Label.union([Sb, Rb], '__DMRG_ITERATE_ENV__', flow=-1 if self.mps.qnon else 0, mode=+2 if self.ttype == 'S' else +1) subslice = QuantumNumbers.kron( [Lsys.qns, Lenv.qns], signs=[1, -1]).subslice(targets=( self.target.zero(), )) if self.mps.qnon else slice(None) shape = (len(subslice), len(subslice)) if self.mps.qnon else (Lsys.qns * Lenv.qns, Lsys.qns * Lenv.qns) Hsys = (Ha * Hasite).transpose([Oa, La.P, Sa.P, La, Sa]).merge( ([La.P, Sa.P], Lsys.P.inverse, sysinfo), ([La, Sa], Lsys.inverse, sysinfo)) Henv = (Hbsite * Hb).transpose([Ob, Sb.P, Rb.P, Sb, Rb]).merge( ([Sb.P, Rb.P], Lenv.P.inverse, envinfo), ([Sb, Rb], Lenv.inverse, envinfo)) matvec = DMRGMatVec(Hsys, Henv) def timedmatvec(v): with self.timers.get('matvec'): return matvec(v) matrix = hm.LinearOperator(shape=shape, matvec=timedmatvec, dtype=Hsys.dtype) with self.timers.get('Diagonalization'): u, s, v = self.mps[self.cut - 1], self.mps.Lambda, self.mps[self.cut] v0 = (u * s * v).merge( ([La, Sa], Lsys, sysinfo), ([Sb, Rb], Lenv, envinfo)).toarray().reshape( -1)[subslice] if sp and s.norm > RZERO else None es, vs = hm.eigsh(matrix, which='SA', v0=v0, k=1, tol=tol * 10**-2) energy, Psi = es[0], vs[:, 0] self.info['Etotal'] = energy, '%.6f' self.info['Esite'] = energy / (divisor or self.nsite), '%.8f' self.info['nmatvec'] = matrix.count self.info['overlap'] = np.inf if v0 is None else np.abs( Psi.conjugate().dot(v0) / norm(v0) / norm(Psi)), '%.6f' with self.timers.get('Truncation'): sysantiinfo = sysinfo if self.ttype == 'S' else np.argsort( sysinfo) if self.mps.qnon else None envantiinfo = envinfo if self.ttype == 'S' else np.argsort( envinfo) if self.mps.qnon else None qns = QuantumNumbers.mono( self.target.zero(), count=len(subslice)) if self.mps.qnon else Lsys.qns * Lenv.qns Lgs, new = Label('__DMRG_ITERATE_GS__', qns=qns), Ra.replace(qns=None) u, s, v, err = partitionedsvd(Tensor(Psi, labels=[Lgs]), Lsys, new, Lenv, nmax=nmax, tol=tol, ttype=self.ttype, returnerr=True) self.mps[self.cut - 1] = u.split((Lsys, [La, Sa], sysantiinfo)) self.mps[self.cut] = v.split((Lenv, [Sb, Rb], envantiinfo)) self.mps.Lambda = s self.setlcontract(self.cut) self.setrcontract(self.cut) self.info['nslice'] = Lgs.dim self.info['nbasis'] = s.shape[0] self.info['err'] = err, '%.1e' self.timers.record() log << 'timers of the dmrg:\n%s\n' % self.timers.tostr(Timers.ALL) log << 'info of the dmrg:\n%s\n\n' % self.info if piechart: self.timers.graph(parents=Timers.ALL)
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 random(labels,ttype='D',dtype=np.float64): ''' Construct a random block-structured tensor. Parameters ---------- labels : list of Label The labels of the random tensor. ttype : 'D'/'S', optional Tensor type. 'D' for dense and 'S' for sparse. dtype : np.float64, np.complex128, optional The data type of the random tensor. Returns ------- DTensor/STensor A random block-structured tensor. ''' assert ttype in 'DS' and dtype in (np.float32,np.float64,np.complex64,np.complex128) np.random.seed() if next(iter(labels)).qnon: paxes,plbls,maxes,mlbls=[],[],[],[] for axis,label in enumerate(labels): (paxes if label.flow==1 else maxes).append(axis) (plbls if label.flow==1 else mlbls).append(label) traxes=np.argsort(list(it.chain(paxes,maxes))) if ttype=='D': plabel,ppermutation=Label.union(plbls,'__TENSOR_RANDOM_D_+__',+1,mode=1) mlabel,mpermutation=Label.union(mlbls,'__TENSOR_RANDOM_D_-__',-1,mode=1) data=np.zeros((plabel.dim,mlabel.dim),dtype=dtype) pod,mod=plabel.qns.toordereddict(),mlabel.qns.toordereddict() for qn in filter(lambda key: key in pod,mod): bshape=(pod[qn].stop-pod[qn].start,mod[qn].stop-mod[qn].start) data[pod[qn],mod[qn]]=np.random.random(bshape) if dtype in (np.complex64,np.complex128): data[pod[qn],mod[qn]]+=1j*np.random.random(bshape) for axis,permutation in [(0,np.argsort(ppermutation)),(1,np.argsort(mpermutation))]: data=hm.reorder(data,axes=[axis],permutation=permutation) data=data.reshape(tuple(label.dim for label in it.chain(plbls,mlbls))).transpose(*traxes) result=DTensor(data,labels=labels) else: plabel,precord=Label.union(plbls,'__TENSOR_RANDOM_S_+__',+1,mode=2) mlabel,mrecord=Label.union(mlbls,'__TENSOR_RANDOM_S_-__',-1,mode=2) data={} ods=[label.qns.toordereddict(protocol=QuantumNumbers.COUNTS) for label in labels] pod,mod=plabel.qns.toordereddict(),mlabel.qns.toordereddict() for qn in filter(lambda key: key in pod,mod): for pqns,mqns in it.product(precord[qn],mrecord[qn]): qns=tuple(it.chain(pqns,mqns)) qns=tuple(qns[axis] for axis in traxes) data[qns]=np.zeros(tuple(od[qn] for od,qn in zip(ods,qns)),dtype=dtype) data[qns][...]=np.random.random(data[qns].shape) if dtype in (np.complex64,np.complex128): data[qns][...]+=1j*np.random.random(data[qns].shape) result=STensor(data,labels=labels) else: assert ttype=='D' data=np.zeros(tuple(label.dim for label in labels),dtype=dtype) data[...]=np.random.random(data.shape) if dtype in (np.complex64,np.complex128): data[...]+=1j*np.random.random(data.shape) result=DTensor(data,labels=labels) return result
def setUp(self): self.init() self.overlaps=[hm.overlap(self.mps1.state,mopt,self.mps2.state) for mopt in self.mopts] self.optstrs=[OptStr.fromoperator(opt,self.degfres,layer=self.layer) for opt in self.generator.operators]
def iterate(self, info='', sp=True, nmax=200, tol=hm.TOL, piechart=True): ''' The two site dmrg step. Parameters ---------- info : str, optional The information string passed to self.log. sp : logical, optional True for state prediction False for not. nmax : integer, optional The maximum singular values to be kept. tol : np.float64, optional The tolerance of the singular values. piechart : logical, optional True for showing the piechart of self.timers while False for not. ''' self.log << '%s%s\n%s\n' % (self.state, info, self.graph) eold = self.info['Esite'] with self.timers.get('Preparation'): Ha, Hb = self._Hs_['L'][self.mps.cut - 1], self._Hs_['R'][self.mps.nsite - self.mps.cut - 1] Hasite, Hbsite = self.mpo[self.mps.cut - 1], self.mpo[self.mps.cut] La, Sa, Ra = self.mps[self.mps.cut - 1].labels Lb, Sb, Rb = self.mps[self.mps.cut].labels Oa, Ob = Hasite.labels[MPO.R], Hbsite.labels[MPO.L] assert Ra == Lb if self.mps.mode == 'QN': sysqns, syspt = QuantumNumbers.kron( [La.qns, Sa.qns], signs='++').sort(history=True) envqns, envpt = QuantumNumbers.kron( [Sb.qns, Rb.qns], signs='-+').sort(history=True) sysantipt, envantipt = np.argsort(syspt), np.argsort(envpt) subslice = QuantumNumbers.kron( [sysqns, envqns], signs='+-').subslice(targets=(self.target.zero(), )) qns = QuantumNumbers.mono(self.target.zero(), count=len(subslice)) self.info['nslice'] = len(subslice) else: sysqns, syspt, sysantipt = np.product([La.qns, Sa.qns]), None, None envqns, envpt, envantipt = np.product([Sb.qns, Rb.qns]), None, None subslice, qns = slice(None), sysqns * envqns self.info['nslice'] = qns Lpa, Spa, Spb, Rpb = La.prime, Sa.prime, Sb.prime, Rb.prime Lsys, Lenv, new = Label('__DMRG_TWO_SITE_STEP_SYS__', qns=sysqns), Label( '__DMRG_TWO_SITE_STEP_ENV__', qns=envqns), Ra.replace(qns=None) Lpsys, Lpenv = Lsys.prime, Lenv.prime Hsys = contract([Ha, Hasite], engine='tensordot').transpose( [Oa, Lpa, Spa, La, Sa]).merge(([Lpa, Spa], Lpsys, syspt), ([La, Sa], Lsys, syspt)) Henv = contract([Hbsite, Hb], engine='tensordot').transpose( [Ob, Spb, Rpb, Sb, Rb]).merge(([Spb, Rpb], Lpenv, envpt), ([Sb, Rb], Lenv, envpt)) if self.matvec == 'csr': with self.timers.get('Hamiltonian'): if isinstance(subslice, slice): rcs = None else: rcs = (np.divide(subslice, Henv.shape[1]), np.mod(subslice, Henv.shape[1]), np.zeros(Hsys.shape[1] * Henv.shape[1], dtype=np.int64)) rcs[2][subslice] = xrange(len(subslice)) matrix = 0 for hsys, henv in zip(Hsys, Henv): with self.timers.get('kron'): temp = hm.kron(hsys, henv, rcs=rcs, timers=self.timers) with self.timers.get('sum'): matrix += temp self.info['nnz'] = matrix.nnz self.info['nz'] = ( len(np.argwhere(np.abs(matrix.data) < tol)) * 100.0 / matrix.nnz) if matrix.nnz > 0 else 0, '%1.1f%%' self.info['density'] = 1.0 * self.info['nnz'] / self.info[ 'nslice']**2, '%.1e' matrix = hm.LinearOperator(shape=matrix.shape, matvec=matrix.dot, dtype=self.dtype) else: with self.timers.get('Preparation'): if self.mps.mode == 'QN': sysod, envod = sysqns.to_ordereddict( ), envqns.to_ordereddict() qnpairs = [[ (tuple(qn), tuple(qn - oqn)) for qn in sysqns if tuple(qn) in envod and tuple(qn - oqn) in sysod and tuple(qn - oqn) in envod ] for oqn in Oa.qns] assert len(qnpairs) == len(Hsys) self.cache['vecold'] = np.zeros(Hsys.shape[1] * Henv.shape[1], dtype=self.dtype) self.cache['vecnew'] = np.zeros( (Hsys.shape[1], Henv.shape[1]), dtype=self.dtype) def matvec(v): with self.timers.get('matvec'): vec, result = self.cache['vecold'], self.cache[ 'vecnew'] vec[subslice] = v result[...] = 0.0 vec = vec.reshape((Hsys.shape[1], Henv.shape[1])) for hsys, henv, pairs in zip(Hsys, Henv, qnpairs): for qn1, qn2 in pairs: result[sysod[qn1], envod[qn1]] += hsys[ sysod[qn1], sysod[qn2]].dot( vec[sysod[qn2], envod[qn2]]).dot( henv.T[envod[qn2], envod[qn1]]) return result.reshape(-1)[subslice] matrix = hm.LinearOperator(shape=(len(subslice), len(subslice)), matvec=matvec, dtype=self.dtype) else: def matvec(v): v = v.reshape((Hsys.shape[1], Henv.shape[1])) result = np.zeros_like(v) for hsys, henv in zip(Hsys, Henv): result += hsys.dot(v).dot(henv.T) return result.reshape(-1) matrix = hm.LinearOperator( shape=(Hsys.shape[1] * Henv.shape[1], Hsys.shape[1] * Henv.shape[1]), matvec=matvec, dtype=self.dtype) with self.timers.get('Diagonalization'): u, s, v = self.mps[self.mps.cut - 1], self.mps.Lambda, self.mps[self.mps.cut] if sp and norm(s) > RZERO: v0 = np.asarray( contract([u, s, v], engine='einsum').merge( ([La, Sa], Lsys, syspt), ([Sb, Rb], Lenv, envpt))).reshape(-1)[subslice] else: v0 = None es, vs = hm.eigsh(matrix, which='SA', v0=v0, k=1) energy, Psi = es[0], vs[:, 0] self.info['Etotal'] = energy, '%.6f' self.info['Esite'] = energy / self.mps.nsite, '%.8f' self.info['dE/E'] = None if eold is None else ( norm(self.info['Esite'] - eold) / norm(self.info['Esite'] + eold), '%.1e') self.info['nmatvec'] = matrix.count self.info['overlap'] = np.inf if v0 is None else np.abs( Psi.conjugate().dot(v0) / norm(v0) / norm(Psi)), '%.6f' with self.timers.get('Truncation'): u, s, v, err = Tensor( Psi, labels=[Label('__DMRG_TWO_SITE_STEP__', qns=qns) ]).partitioned_svd(Lsys, new, Lenv, nmax=nmax, tol=tol, return_truncation_err=True) self.mps[self.mps.cut - 1] = u.split((Lsys, [La, Sa], sysantipt)) self.mps[self.mps.cut] = v.split((Lenv, [Sb, Rb], envantipt)) self.mps.Lambda = s self.set_HL_(self.mps.cut - 1, tol=tol) self.set_HR_(self.mps.cut, tol=tol) self.info['nbasis'] = len(s) self.info['err'] = err, '%.1e' self.timers.record() self.log << 'timers of the dmrg:\n%s\n' % self.timers.tostr(Timers.ALL) self.log << 'info of the dmrg:\n%s\n\n' % self.info if piechart: self.timers.graph(parents=Timers.ALL)
def setUp(self): self.init() self.mopt=sum(self.mopts) self.overlap=hm.overlap(self.mps1.state,self.mopt,self.mps2.state) self.mpo=MPO.fromoperators(self.generator.operators,self.degfres,layer=self.layer,ttype=self.ttype)
def test_mpo_fermi(): print 'test_mpo_fermi' # set the lattice Nscope, Nsite = 2, 2 a1, a2, points = np.array([1.0, 0.0]), np.array([0.0, 1.0]), [] for scope in xrange(Nscope): for site in xrange(Nsite): points.append( Point(PID(scope=scope, site=site), rcoord=a1 * site + a2 * scope, icoord=[0.0, 0.0])) lattice = Lattice.compose(name='WG', points=points, neighbours=1) lattice.plot(pidon=True) # set the terms terms = [Hopping('t', 1.0, neighbour=1)] # set the degfres priority, layers = ['scope', 'site', 'orbital', 'spin', 'nambu'], [('scope', ), ('site', 'orbital', 'spin')] config = IDFConfig(priority=priority) for pid in lattice.pids: config[pid] = Fermi(nspin=1) table = config.table(mask=['nambu']) degfres = DegFreTree(mode='QN', layers=layers, priority=priority, leaves=table.keys(), map=lambda index: PQNS(1)) # set the operators opts = Generator(lattice.bonds, config, table=table, terms=terms, dtype=np.complex128).operators.values() optstrs = [OptStr.from_operator(opt, degfres, layers[-1]) for opt in opts] for i, (opt, optstr) in enumerate(zip(opts, optstrs)): print 'operator: %s' % i print repr(opt) print repr(optstr) print mpos = [optstr.to_mpo(degfres) for optstr in optstrs] # set the states sites, bonds = degfres.labels(mode='S', layer=layers[-1]), degfres.labels( mode='B', layer=layers[-1]) bonds[+0] = bonds[+0].replace(qns=QuantumNumbers.mono(PQN(0))) bonds[-1] = bonds[-1].replace( qns=QuantumNumbers.mono(PQN(Nscope * Nsite / 2))) cut = np.random.randint(0, Nsite * Nscope + 1) mps1, mps2 = MPS.random(sites, bonds, cut=cut, nmax=20), MPS.random(sites, bonds, cut=cut, nmax=20) # set the reference of test mopts = [ foptrep(opt, basis=FBasis(nstate=Nscope * Nsite), transpose=True, dtype=np.complex128) for opt in opts ] overlaps = [hm.overlap(mps1.state, mopt, mps2.state) for mopt in mopts] # test optstr test_optstr_overlap(optstrs, mps1, mps2, overlaps) test_optstr_algebra(optstrs, mps1, mps2, overlaps) test_optstr_relayer(optstrs, degfres, mps1, mps2, overlaps) # test mpo test_mpo_overlap(mpos, mps1, mps2, overlaps) test_mpo_algebra(mpos, mps1, mps2, mopts, overlaps) test_mpo_relayer(mpos, degfres, mps1, mps2, overlaps) print
def iterate(self,log,info='',sp=True,nmax=200,tol=10**-6,divisor=None,piechart=True): ''' The two site dmrg step. Parameters ---------- log : Log The log file. info : str, optional The information string passed to self.log. sp : logical, optional True for state prediction False for not. nmax : int, optional The maximum singular values to be kept. tol : float, optional The tolerance of the singular values. divisor : int/None, optional * When int, it is used as the divisor to calculated the ground state energy per site; * When None, the default divisor will be used to calculated the ground state energy per site. piechart : logical, optional True for showing the piechart of self.timers while False for not. ''' log<<'%s(%s)\n%s\n'%(info,self.ttype,self.graph) with self.timers.get('Preparation'): Ha,Hasite=self.lcontracts[self.cut-1],self.mpo[self.cut-1] Hb,Hbsite=self.rcontracts[self.cut+1],self.mpo[self.cut] Oa,(La,Sa,Ra)=Hasite.labels[MPO.R],self.mps[self.cut-1].labels Ob,(Lb,Sb,Rb)=Hbsite.labels[MPO.L],self.mps[self.cut].labels assert Ra==Lb and Oa==Ob Lsys,sysinfo=Label.union([La,Sa],'__DMRG_ITERATE_SYS__',flow=+1 if self.mps.qnon else 0,mode=+2 if self.ttype=='S' else +1) Lenv,envinfo=Label.union([Sb,Rb],'__DMRG_ITERATE_ENV__',flow=-1 if self.mps.qnon else 0,mode=+2 if self.ttype=='S' else +1) subslice=QuantumNumbers.kron([Lsys.qns,Lenv.qns],signs=[1,-1]).subslice(targets=(self.target.zero(),)) if self.mps.qnon else slice(None) shape=(len(subslice),len(subslice)) if self.mps.qnon else (Lsys.qns*Lenv.qns,Lsys.qns*Lenv.qns) Hsys=(Ha*Hasite).transpose([Oa,La.P,Sa.P,La,Sa]).merge(([La.P,Sa.P],Lsys.P.inverse,sysinfo),([La,Sa],Lsys.inverse,sysinfo)) Henv=(Hbsite*Hb).transpose([Ob,Sb.P,Rb.P,Sb,Rb]).merge(([Sb.P,Rb.P],Lenv.P.inverse,envinfo),([Sb,Rb],Lenv.inverse,envinfo)) matvec=DMRGMatVec(Hsys,Henv) def timedmatvec(v): with self.timers.get('matvec'): return matvec(v) matrix=hm.LinearOperator(shape=shape,matvec=timedmatvec,dtype=Hsys.dtype) with self.timers.get('Diagonalization'): u,s,v=self.mps[self.cut-1],self.mps.Lambda,self.mps[self.cut] v0=(u*s*v).merge(([La,Sa],Lsys,sysinfo),([Sb,Rb],Lenv,envinfo)).toarray().reshape(-1)[subslice] if sp and s.norm>RZERO else None es,vs=hm.eigsh(matrix,which='SA',v0=v0,k=1,tol=tol*10**-2) energy,Psi=es[0],vs[:,0] self.info['Etotal']=energy,'%.6f' self.info['Esite']=energy/(divisor or self.nsite),'%.8f' self.info['nmatvec']=matrix.count self.info['overlap']=np.inf if v0 is None else np.abs(Psi.conjugate().dot(v0)/norm(v0)/norm(Psi)),'%.6f' with self.timers.get('Truncation'): sysantiinfo=sysinfo if self.ttype=='S' else np.argsort(sysinfo) if self.mps.qnon else None envantiinfo=envinfo if self.ttype=='S' else np.argsort(envinfo) if self.mps.qnon else None qns=QuantumNumbers.mono(self.target.zero(),count=len(subslice)) if self.mps.qnon else Lsys.qns*Lenv.qns Lgs,new=Label('__DMRG_ITERATE_GS__',qns=qns),Ra.replace(qns=None) u,s,v,err=partitionedsvd(Tensor(Psi,labels=[Lgs]),Lsys,new,Lenv,nmax=nmax,tol=tol,ttype=self.ttype,returnerr=True) self.mps[self.cut-1]=u.split((Lsys,[La,Sa],sysantiinfo)) self.mps[self.cut]=v.split((Lenv,[Sb,Rb],envantiinfo)) self.mps.Lambda=s self.setlcontract(self.cut) self.setrcontract(self.cut) self.info['nslice']=Lgs.dim self.info['nbasis']=s.shape[0] self.info['err']=err,'%.1e' self.timers.record() log<<'timers of the dmrg:\n%s\n'%self.timers.tostr(Timers.ALL) log<<'info of the dmrg:\n%s\n\n'%self.info if piechart: self.timers.graph(parents=Timers.ALL)
def eigs(self, sector, v0=None, k=1, evon=False, resetmatrix=True, resettimers=True, showes=True): ''' Lowest k eigenvalues and optionally, the corresponding eigenvectors. Parameters ---------- sector : any hashable object The sector of the eigensystem. v0 : 1d ndarray, optional The starting vector. k : int, optional The number of eigenvalues to be computed. evon : logical, optional True for returning the eigenvectors and False for not. resetmatrix : logical, optional True for resetting the matrix cache and False for not. resettimers : logical, optional True for resetting the timers and False for not. showes : logical, optional True for showing the calculated eigenvalues and False for not. Returns ------- sectors : list of any hashable object The sectors of the k eigenvalues es : 1d ndarray Array of k eigenvalues. vs : list of 1d ndarray, optional List of k eigenvectors. ''' self.log << '::<Parameters>:: %s\n' % (', '.join( '%s=%s' % (key, HP.decimaltostr(value, n=10)) for key, value in self.parameters.items())) if resettimers: self.timers.reset() if sector is None and len(self.sectors) > 1: cols = ['nopt', 'dim', 'nnz', 'Mt(s)', 'Et(s)' ] + (['E%s' % i for i in range(k - 1, -1, -1)] if showes else []) widths = [14, 4, 8, 10, 10, 10] + ([13] * k if showes else []) info = HP.Sheet(corner='sector', rows=[repr(sector) for sector in self.sectors], cols=cols, widths=widths) self.log << '%s\n%s\n%s\n' % (info.frame( ), info.coltagstostr(corneron=True), info.division()) sectors, es, vs = [], [], [] for sector in self.sectors: with self.timers.get('Matrix'): matrix = self.matrix(sector, reset=resetmatrix) V0 = None if v0 is None or matrix.shape[0] != v0.shape[ 0] else v0 with self.timers.get('ES'): eigs = HM.eigsh(matrix, v0=V0, k=min(k, matrix.shape[0]), which='SA', evon=evon) self.timers.record() sectors.extend([sector] * min(k, matrix.shape[0])) es.extend(eigs[0] if evon else eigs) if evon: vs.extend(eigs[1].T) info[(repr(sector), 'nopt')] = len(self.operators) info[(repr(sector), 'dim')] = matrix.shape[0] info[(repr(sector), 'nnz')] = matrix.nnz info[(repr(sector), 'Mt(s)')] = self.timers['Matrix'].records[-1], '%.4e' info[(repr(sector), 'Et(s)')] = self.timers['ES'].records[-1], '%.4e' for j in range(k - 1, -1, -1): info[(repr(sector), 'E%s' % j)] = (es[-1 - j], '%.8f') if j < matrix.shape[0] else '' self.log << '%s\n' % info.rowtostr(row=repr(sector)) indices = np.argsort(es)[:k] sectors = [sectors[index] for index in indices] es = np.asarray(es)[indices] if evon: vs = [vs[index] for index in indices] self.log << '%s\n' % info.frame() else: if sector is None: sector = next(iter(self.sectors)) with self.timers.get('Matrix'): matrix = self.matrix(sector, reset=resetmatrix) self.log << '::<Information>:: sector=%r, nopt=%s, dim=%s, nnz=%s, ' % ( sector, len(self.operators), matrix.shape[0], matrix.nnz) V0 = None if v0 is None or matrix.shape[0] != v0.shape[0] else v0 with self.timers.get('ES'): eigs = HM.eigsh(matrix, v0=V0, k=k, which='SA', evon=evon) self.timers.record() sectors = [sector] * k es = eigs[0] if evon else eigs if evon: vs = list(eigs[1].T) self.log << 'Mt=%.4es, Et=%.4es' % ( self.timers['Matrix'].records[-1], self.timers['ES'].records[-1]) self.log << (', evs=%s\n' % (' '.join('%.8f' % e for e in es)) if showes else '\n') return (sectors, es, vs) if evon else (sectors, es)
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)