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 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 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 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 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 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 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 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 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