Пример #1
0
    def _mul_mps_(self,other):
        '''
        The multiplication of an mpo and an mps.

        Parameters
        ----------
        other : MPS
            The mps.

        Returns
        -------
        MPS
            The product.
        '''
        assert self.nsite==other.nsite
        u,Lambda=other._merge_ABL_()
        ms=[]
        for i,(m1,m2) in enumerate(zip(self,other)):
            L1,U1,D1,R1=m1.labels
            L2,S,R2=m2.labels
            assert S==D1
            L=L2.replace(qns=QuantumNumbers.kron([L1.qns,L2.qns]) if L1.qnon else L1.qns*L2.qns)
            R=R2.replace(qns=QuantumNumbers.kron([R1.qns,R2.qns]) if R1.qnon else R1.qns*R2.qns)
            m=(m1*m2).transpose((L1,L2,U1,R1,R2)).merge(([L1,L2],L),([R1,R2],R))
            m.relabel(olds=[U1],news=[S])
            ms.append(m)
        other._set_ABL_(u,Lambda)
        return MPS(mode=other.mode,ms=ms)
Пример #2
0
    def _mul_mpo_(self,other):
        '''
        The multiplication of two mpos.

        Parameters
        ----------
        other : MPO
            The other mpo.

        Returns
        -------
        MPO
            The product.
        '''
        assert self.nsite==other.nsite
        ms=[]
        for i,(m1,m2) in enumerate(zip(self,other)):
            assert m1.labels==m2.labels
            m1,m2=copy(m1),copy(m2)
            L1,U1,D1,R1=m1.labels
            L2,U2,D2,R2=m2.labels
            L=L1.replace(qns=QuantumNumbers.kron([L1.qns,L2.qns]) if L1.qnon else L1.qns*L2.qns)
            R=R1.replace(qns=QuantumNumbers.kron([R1.qns,R2.qns]) if R1.qnon else R1.qns*R2.qns)
            s=Label('__MPO_MUL__',qns=U1.qns)
            l1,r1=Label('__MPO_MUL_L1__',qns=L1.qns,flow=L1.flow),Label('__MPO_MUL_R1__',qns=R1.qns,flow=R1.flow)
            l2,r2=Label('__MPO_MUL_L2__',qns=L2.qns,flow=L2.flow),Label('__MPO_MUL_R2__',qns=R2.qns,flow=R2.flow)
            m1.relabel(olds=[L1,D1,R1],news=[l1,s.replace(flow=D1.flow),r1])
            m2.relabel(olds=[L2,U2,R2],news=[l2,s.replace(flow=U2.flow),r2])
            ms.append((m1*m2).transpose((l1,l2,U1,D2,r1,r2)).merge(([l1,l2],L),([r1,r2],R)))
        return MPO(ms)
Пример #3
0
    def union(labels, identifier, flow=0, prime=False, mode=0):
        '''
        The union of a set of labels as a new label.

        Parameters
        ----------
        labels : list of Label
            The set of labels.
        identifier : any hashale object
            The identifier of the union.
        flow : -1/0/+1/None
            The flow of the union.
        prime : logical, optional
            When True, the union is in the prime form; otherwise not.
        mode : -2/-1/0/+1/+2, optional
            * 0: When qnon, use QuantumNumbers.kron to get the qns of the union, no sorting and no returning the permutation array
            * -1: When qnon, use QuantumNumbers.kron to get the qns of the union with sorting but without returning the permutation array
            * +1: When qnon, use QuantumNumbers.kron to get the qns of the union with sorting and with returning the permutation array
            * -2: When qnon, use QuantumNumbers.ukron to get the qns of the union without returning the record dict
            * +2: When qnon, use QuantumNumbers.ukron to get the qns of the union with returning the record dict

        Returns
        -------
        result : Label
            The union of the input set of labels.
        permutation/record : 1d-ndarray-of-int/dict, optional
            The permutation/record of the quantum numbers of the union.
        '''
        qnon = labels[0].qnon
        assert all(label.qnon == qnon
                   for label in labels[1:]) and mode in {-2, -1, 0, 1, 2}
        if qnon:
            assert flow in {-1, 1}
            qnses, signs = [label.qns for label in labels], [
                1 if label.flow == flow else -1 for label in labels
            ]
            if mode in {-1, 0, +1}:
                qns = QuantumNumbers.kron(qnses, signs=signs)
                if mode == -1: qns = qns.sorted(history=False)
                if mode == +1: qns, permutation = qns.sorted(history=True)
                result = Label(identifier, qns, flow=flow, prime=prime)
                return (result, permutation) if mode == 1 else result
            else:
                if mode == -2:
                    qns = QuantumNumbers.ukron(qnses,
                                               signs=signs,
                                               history=False)
                if mode == +2:
                    qns, record = QuantumNumbers.ukron(qnses,
                                                       signs=signs,
                                                       history=True)
                result = Label(identifier, qns, flow=flow, prime=prime)
                return (result, record) if mode == 2 else result
        else:
            result = Label(identifier,
                           np.product([label.qns for label in labels]),
                           flow=None if flow is None else 0,
                           prime=prime)
            return (result, None) if mode in (1, 2) else result
Пример #4
0
    def impsgrowth(self, sites, bonds, osvs, qn=0, ttype=None):
        '''
        Infinite MPS growth.

        Parameters
        ----------
        sites,bonds : list of Label/str
            The site/bond labels/identifiers of the new mps.
        osvs : 1d ndarray
            The old singular values.
        qn : QuantumNumber, optional
            The injected quantum number of the new mps.
        ttype : NOne/'D'/'S', optional
            Tensor type. 'D' for dense, 'S' for sparse and None for automatic.

        Returns
        -------
        MPS
            The imps after growth.
        '''
        if self.nsite > 0:
            assert self.cut == self.nsite // 2 and self.nsite % 2 == 0 and len(
                sites) + 1 == len(bonds)
            ob, nb = self.nsite // 2 + 1, (len(bonds) + 1) // 2
            ns = nb - ob
            cms = self[ob - ns - 1:ob + ns - 1].impsprediction(
                sites[ob - 1:2 * nb - ob - 1],
                bonds[ob - 1:2 * nb - ob],
                osvs,
                qn=qn,
                ttype=ttype)
            lms = MPS([copy(self[pos]) for pos in range(0, self.cut)])
            rms = MPS([copy(self[pos]) for pos in range(self.cut, self.nsite)])
            lms.relabel(sites[:ob - 1], bonds[:ob])
            rms.relabel(sites[-ob + 1:], bonds[-ob:])
            rms.qninject(qn)
            result = MPS(it.chain(lms, cms, rms),
                         Lambda=cms.Lambda,
                         cut=nb - 1,
                         ttype=ttype)
        else:
            bonds = copy(bonds)
            iqns, oqns = (QNS.mono(qn.zero()),
                          QNS.mono(qn)) if isinstance(qn, QN) else (1, 1)
            bonds[+0] = bonds[+0].replace(qns=iqns) if isinstance(
                bonds[+0], Label) else Label(bonds[+0], qns=iqns, flow=None)
            bonds[-1] = bonds[-1].replace(qns=oqns) if isinstance(
                bonds[-1], Label) else Label(bonds[-1], qns=oqns, flow=None)
            result = MPS.random(sites,
                                bonds=bonds,
                                cut=len(sites) // 2,
                                nmax=10,
                                ttype=ttype or 'D')
        return result
Пример #5
0
    def reset(self,
              mode=None,
              layers=None,
              priority=None,
              leaves=(),
              map=None):
        '''
        Reset the DegFreTree.

        Parameters
        ----------
        mode,layers,priority,leaves,map :
            Please see DegFreTree.__init__ for details.
        '''
        self.clear()
        Tree.__init__(self)
        assert mode in (None, 'QN', 'NB')
        if mode is not None: self.mode = mode
        if layers is not None: self.layers = layers
        if priority is not None: self.priority = priority
        if map is not None: self.map = map
        self.cache = {}
        if len(leaves) > 0:
            temp = [key for layer in self.layers for key in layer]
            assert set(range(len(PID._fields))) == set(
                [temp.index(key) for key in PID._fields])
            temp = set(temp)
            self.add_leaf(parent=None,
                          leaf=tuple([None] * len(leaves[0])),
                          data=None)
            for layer in self.layers:
                temp -= set(layer)
                indices = set([
                    index.replace(**{key: None
                                     for key in temp}) for index in leaves
                ])
                self.cache[('indices', layer)] = sorted(
                    indices,
                    key=lambda index: index.to_tuple(priority=self.priority))
                self.cache[('table', layer)] = Table(self.indices(layer=layer))
                for index in self.indices(layer=layer):
                    self.add_leaf(
                        parent=index.replace(**{key: None
                                                for key in layer}),
                        leaf=index,
                        data=None)
            for i, layer in enumerate(reversed(self.layers)):
                if i == 0:
                    for index in self.indices(layer):
                        self[index] = self.map(index)
                else:
                    for index in self.indices(layer):
                        if self.mode == 'QN':
                            self[index] = QuantumNumbers.kron([
                                self[child] for child in self.children(index)
                            ])
                        else:
                            self[index] = np.product([
                                self[child] for child in self.children(index)
                            ])
Пример #6
0
    def union(labels,identifier,flow=0,prime=False,mode=0):
        '''
        The union of a set of labels as a new label.

        Parameters
        ----------
        labels : list of Label
            The set of labels.
        identifier : any hashale object
            The identifier of the union.
        flow : -1/0/+1/None
            The flow of the union.
        prime : logical, optional
            When True, the union is in the prime form; otherwise not.
        mode : -2/-1/0/+1/+2, optional
            * 0: When qnon, use QuantumNumbers.kron to get the qns of the union, no sorting and no returning the permutation array
            * -1: When qnon, use QuantumNumbers.kron to get the qns of the union with sorting but without returning the permutation array
            * +1: When qnon, use QuantumNumbers.kron to get the qns of the union with sorting and with returning the permutation array
            * -2: When qnon, use QuantumNumbers.ukron to get the qns of the union without returning the record dict
            * +2: When qnon, use QuantumNumbers.ukron to get the qns of the union with returning the record dict

        Returns
        -------
        result : Label
            The union of the input set of labels.
        permutation/record : 1d-ndarray-of-int/dict, optional
            The permutation/record of the quantum numbers of the union.
        '''
        qnon=labels[0].qnon
        assert all(label.qnon==qnon for label in labels[1:]) and mode in {-2,-1,0,1,2}
        if qnon:
            assert flow in {-1,1}
            qnses,signs=[label.qns for label in labels],[1 if label.flow==flow else -1 for label in labels]
            if mode in {-1,0,+1}:
                qns=QuantumNumbers.kron(qnses,signs=signs)
                if mode==-1: qns=qns.sorted(history=False)
                if mode==+1: qns,permutation=qns.sorted(history=True)
                result=Label(identifier,qns,flow=flow,prime=prime)
                return (result,permutation) if mode==1 else result
            else:
                if mode==-2: qns=QuantumNumbers.ukron(qnses,signs=signs,history=False)
                if mode==+2: qns,record=QuantumNumbers.ukron(qnses,signs=signs,history=True)
                result=Label(identifier,qns,flow=flow,prime=prime)
                return (result,record) if mode==2 else result
        else:
            result=Label(identifier,np.product([label.qns for label in labels]),flow=None if flow is None else 0,prime=prime)
            return (result,None) if mode in (1,2) else result
Пример #7
0
def directsum(tensors,labels,axes=()):
    '''
    The directsum of a couple of tensors.

    Parameters
    ----------
    tensors : list of DTensor/STensor
        The tensors to be directsummed.
    labels : list of Label
        The labels of the directsum.
    axes : list of int, optional
            The axes along which the directsum is block diagonal.

    Returns
    -------
    DTensor/STensor
        The directsum of the tensors.
    '''
    TENSOR=next(iter(tensors))
    assert TENSOR.ndim>len(axes)
    assert len({tensor.ndim for tensor in tensors})==1
    assert len({tuple(tensor.shape[axis] for axis in axes) for tensor in tensors})==1
    assert len({tuple(label.flow for label in tensor.labels) for tensor in tensors})==1
    alters=set(range(TENSOR.ndim))-set(axes)
    dtype=np.find_common_type([],[tensor.dtype for tensor in tensors])
    if isinstance(TENSOR,DTensor):
        assert len({tensor.qnon for tensor in tensors})==1
        for alter in alters: labels[alter].qns=(QuantumNumbers.union if TENSOR.qnon else np.sum)([tensor.labels[alter].qns for tensor in tensors])
        for axis in range(TENSOR.ndim): labels[axis].flow=TENSOR.labels[axis].flow
        for axis in axes: labels[axis].qns=TENSOR.labels[axis].qns
        data=np.zeros(tuple(len(label.qns) if isinstance(label.qns,QuantumNumbers) else label.qns for label in labels),dtype=dtype)
        slices=[slice(0,0,0) if axis in alters else slice(None,None,None) for axis in range(TENSOR.ndim)]
        for tensor in tensors:
            for alter in alters: slices[alter]=slice(slices[alter].stop,slices[alter].stop+tensor.shape[alter])
            data[tuple(slices)]=tensor.data
    else:
        for alter in alters: labels[alter].qns=QuantumNumbers.union([tensor.labels[alter].qns for tensor in tensors]).sorted(history=False)
        for axis in range(TENSOR.ndim): labels[axis].flow=TENSOR.labels[axis].flow
        for axis in axes: labels[axis].qns=TENSOR.labels[axis].qns
        ods=[label.qns.toordereddict(protocol=QuantumNumbers.COUNTS) for label in labels]
        data,counts={},{alter:{} for alter in alters}
        for tensor in tensors:
            for alter in alters:
                for qn,count in tensor.labels[alter].qns.items(protocol=QuantumNumbers.COUNTS):
                    counts[alter][qn]=counts[alter].get(qn,0)+count
            for qns,block in tensor.data.items():
                if qns not in data:
                    data[qns]=np.zeros(tuple(od[qn] for od,qn in zip(ods,qns)),dtype=dtype)
                slices=[slice(counts[i][qns[i]]-block.shape[i],counts[i][qns[i]],None) if i in alters else slice(None,None,None) for i in range(TENSOR.ndim)]
                data[qns][tuple(slices)]=block
    return type(TENSOR)(data,labels=labels)
Пример #8
0
    def impsgrowth(self,sites,bonds,osvs,qn=0,ttype=None):
        '''
        Infinite MPS growth.

        Parameters
        ----------
        sites,bonds : list of Label/str
            The site/bond labels/identifiers of the new mps.
        osvs : 1d ndarray
            The old singular values.
        qn : QuantumNumber, optional
            The injected quantum number of the new mps.
        ttype : NOne/'D'/'S', optional
            Tensor type. 'D' for dense, 'S' for sparse and None for automatic.

        Returns
        -------
        MPS
            The imps after growth.
        '''
        if self.nsite>0:
            assert self.cut==self.nsite//2 and self.nsite%2==0 and len(sites)+1==len(bonds)
            ob,nb=self.nsite//2+1,(len(bonds)+1)//2
            ns=nb-ob
            cms=self[ob-ns-1:ob+ns-1].impsprediction(sites[ob-1:2*nb-ob-1],bonds[ob-1:2*nb-ob],osvs,qn=qn,ttype=ttype)
            lms=MPS([copy(self[pos]) for pos in range(0,self.cut)])
            rms=MPS([copy(self[pos]) for pos in range(self.cut,self.nsite)])
            lms.relabel(sites[:ob-1],bonds[:ob])
            rms.relabel(sites[-ob+1:],bonds[-ob:])
            rms.qninject(qn)
            result=MPS(it.chain(lms,cms,rms),Lambda=cms.Lambda,cut=nb-1,ttype=ttype)
        else:
            bonds=copy(bonds)
            iqns,oqns=(QNS.mono(qn.zero()),QNS.mono(qn)) if isinstance(qn,QN) else (1,1)
            bonds[+0]=bonds[+0].replace(qns=iqns) if isinstance(bonds[+0],Label) else Label(bonds[+0],qns=iqns,flow=None)
            bonds[-1]=bonds[-1].replace(qns=oqns) if isinstance(bonds[-1],Label) else Label(bonds[-1],qns=oqns,flow=None)
            result=MPS.random(sites,bonds=bonds,cut=len(sites)//2,nmax=10,ttype=ttype or 'D')
        return result
Пример #9
0
    def qngenerate(self, flow, axes, qnses, flows, tol=None):
        '''
        Generate the quantum numbers of a tensor.

        Parameters
        ----------
        flow : +1/-1
            The flow of the unknown axis.
        axes : list of Label/int
            The labels/axes whose quantum number collections are known.
        qnses : list of QuantumNumbers
            The quantum number collections of the known axes.
        flows : tuple of int
            The flows of the quantum numbers of the known axes.
        tol : float64, optional
            The tolerance of the non-zeros.
        '''
        axes = [
            self.axis(axis) if isinstance(axis, Label) else axis
            for axis in axes
        ]
        assert flow in {
            -1, 1
        } and len(axes) == len(qnses) == len(flows) == self.ndim - 1
        type = next(iter(qnses)).type
        for axis, qns, f in zip(axes, qnses, flows):
            self.labels[axis].qns = qns
            self.labels[axis].flow = f
            assert qns.type is type
        unkownaxis = (set(xrange(self.ndim)) - set(axes)).pop()
        expansions = [qns.expansion() for qns in qnses]
        contents = [None] * self.shape[unkownaxis]
        for index in sorted(np.argwhere(
                np.abs(self.data) > hm.TOL if tol is None else tol),
                            key=lambda index: index[unkownaxis]):
            qn = type.regularization(
                sum([
                    expansions[i][index[axis]] * f * (-flow)
                    for i, (axis, f) in enumerate(zip(axes, flows))
                ]))
            if contents[index[unkownaxis]] is None:
                contents[index[unkownaxis]] = qn
            else:
                assert (contents[index[unkownaxis]] == qn).all()
        self.labels[unkownaxis].qns = QuantumNumbers(
            'G', (type, contents, np.arange(len(contents) + 1)),
            protocol=QuantumNumbers.INDPTR)
        self.labels[unkownaxis].flow = flow
Пример #10
0
    def tompo(self, ttype='D', **karg):
        '''
        Convert to the tensor-formatted mpo.

        Parameters
        ----------
        ttype : 'D'/'S', optional
            Tensor type. 'D' for dense and 'S' for sparse.
        karg : dict with keys containing 'nsweep','method' and 'options'
            Please see MPO.compress for details.

        Returns
        -------
        MPO
            The corresponding tensor-formatted MPO.
        '''
        Ms = []
        type = self[0][0, 0].site.qns.type if isinstance(
            self[0][0, 0].site.qns, QuantumNumbers) else None
        for pos, m in enumerate(self):
            dim = self.sites[pos].dim
            L = Label(self.bonds[pos], qns=m.shape[0], flow=0)
            U = self.sites[pos].replace(prime=True, qns=dim, flow=0)
            D = self.sites[pos].replace(qns=dim, flow=0)
            R = Label(self.bonds[pos + 1], qns=m.shape[1], flow=0)
            Ms.append(
                DTensor(np.zeros((m.shape[0], dim, dim, m.shape[1]),
                                 dtype=self.dtype),
                        labels=[L, U, D, R]))
            for i, j in it.product(range(m.shape[0]), range(m.shape[1])):
                Ms[-1].data[i, :, :, j] = m[i, j].matrix
        result = MPO(Ms)
        result.compress(**karg)
        if type is not None:
            for pos in range(len(result)):
                lqns, sqns = QuantumNumbers.mono(
                    type.zero()) if pos == 0 else result[pos - 1].labels[
                        MPO.R].qns, self.sites[pos].qns
                result[pos].qngenerate(flow=-1,
                                       axes=[MPO.L, MPO.U, MPO.D],
                                       qnses=[lqns, sqns, sqns],
                                       flows=[1, 1, -1])
        if ttype == 'S':
            assert issubclass(type, QuantumNumber)
            for i, m in enumerate(result):
                m.qnsort()
                result[i] = m.tostensor()
        return result
Пример #11
0
    def tompo(self,degfres,ttype='D'):
        '''
        Convert an optstr to the full-formatted mpo.

        Parameters
        ----------
        degfres : DegFreTree
            The tree of the site degrees of freedom.
        ttype : 'D'/'S', optional
            Tensor type. 'D' for dense and 'S' for sparse.

        Returns
        -------
        MPO
            The corresponding MPO.
        '''
        index=self[0].site.identifier
        type,layer=degfres.dtype,degfres.layers[degfres.level(index)-1]
        table,sites,bonds=degfres.table(layer),degfres.labels('S',layer),degfres.labels('O',layer)
        poses,matrices=set(table[opt.site.identifier] for opt in self),[opt.matrix for opt in self]
        ms,count=[],0
        for pos in range(len(sites)):
            ndegfre=sites[pos].dim
            if issubclass(type,QuantumNumbers):
                L=Label(bonds[pos],qns=QuantumNumbers.mono(type.zero()) if pos==0 else ms[-1].labels[MPO.R].qns,flow=None)
                U=sites[pos].P
                D=copy(sites[pos])
                R=Label(bonds[pos+1],qns=1,flow=None)
            else:
                L=Label(bonds[pos],qns=1,flow=0)
                U=sites[pos].P.replace(flow=0)
                D=sites[pos].replace(flow=0)
                R=Label(bonds[pos+1],qns=1,flow=0)
            if pos in poses:
                ms.append(DTensor(np.asarray(matrices[count],dtype=self.dtype).reshape((1,ndegfre,ndegfre,1)),labels=[L,U,D,R]))
                count+=1
            else:
                ms.append(DTensor(np.identity(ndegfre,dtype=self.dtype).reshape((1,ndegfre,ndegfre,1)),labels=[L,U,D,R]))
            if issubclass(type,QuantumNumbers): ms[-1].qngenerate(flow=-1,axes=[MPO.L,MPO.U,MPO.D],qnses=[L.qns,U.qns,D.qns],flows=[1,1,-1])
        if ttype=='S':
            assert issubclass(type,QuantumNumbers)
            for m in ms: m.qnsort()
            ms=[m.tostensor() for m in ms]
        return MPO(ms)
Пример #12
0
    def tompo(self,ttype='D',**karg):
        '''
        Convert to the tensor-formatted mpo.

        Parameters
        ----------
        ttype : 'D'/'S', optional
            Tensor type. 'D' for dense and 'S' for sparse.
        karg : dict with keys containing 'nsweep','method' and 'options'
            Please see MPO.compress for details.

        Returns
        -------
        MPO
            The corresponding tensor-formatted MPO.
        '''
        Ms=[]
        type=self[0][0,0].site.qns.type if isinstance(self[0][0,0].site.qns,QuantumNumbers) else None
        for pos,m in enumerate(self):
            dim=self.sites[pos].dim
            L=Label(self.bonds[pos],qns=m.shape[0],flow=0)
            U=self.sites[pos].replace(prime=True,qns=dim,flow=0)
            D=self.sites[pos].replace(qns=dim,flow=0)
            R=Label(self.bonds[pos+1],qns=m.shape[1],flow=0)
            Ms.append(DTensor(np.zeros((m.shape[0],dim,dim,m.shape[1]),dtype=self.dtype),labels=[L,U,D,R]))
            for i,j in it.product(range(m.shape[0]),range(m.shape[1])):
                Ms[-1].data[i,:,:,j]=m[i,j].matrix
        result=MPO(Ms)
        result.compress(**karg)
        if type is not None:
            for pos in range(len(result)):
                lqns,sqns=QuantumNumbers.mono(type.zero()) if pos==0 else result[pos-1].labels[MPO.R].qns,self.sites[pos].qns
                result[pos].qngenerate(flow=-1,axes=[MPO.L,MPO.U,MPO.D],qnses=[lqns,sqns,sqns],flows=[1,1,-1])
        if ttype=='S':
            assert issubclass(type,QuantumNumber)
            for i,m in enumerate(result):
                m.qnsort()
                result[i]=m.tostensor()
        return result
Пример #13
0
    def to_mpo(self,degfres):
        '''
        Convert an optstr to the full-formatted mpo.

        Parameters
        ----------
        degfres : DegFreTree
            The tree of the site degrees of freedom.

        Returns
        -------
        MPO
            The corresponding MPO.
        '''
        index=self[0].site.identifier
        type,layer=degfres[index].type if degfres.mode=='QN' else None,degfres.layers[degfres.level(index)-1]
        table,sites,bonds=degfres.table(layer),degfres.labels('S',layer),degfres.labels('O',layer)
        poses,matrices=set(table[opt.site.identifier] for opt in self),[opt.matrix for opt in self]
        ms,count=[],0
        for pos in xrange(len(sites)):
            ndegfre=sites[pos].dim
            if degfres.mode=='QN':
                L=bonds[pos].replace(qns=QuantumNumbers.mono(type.zero()) if pos==0 else ms[-1].labels[MPO.R].qns)
                U=sites[pos].P
                D=copy(sites[pos])
                R=bonds[pos+1].replace(qns=1)
            else:
                L=bonds[pos].replace(qns=1,flow=0)
                U=sites[pos].P.replace(flow=0)
                D=sites[pos].replace(flow=0)
                R=bonds[pos+1].replace(qns=1,flow=0)
            if pos in poses:
                ms.append(DTensor(np.asarray(matrices[count],dtype=self.dtype).reshape((1,ndegfre,ndegfre,1)),labels=[L,U,D,R]))
                count+=1
            else:
                ms.append(DTensor(np.identity(ndegfre,dtype=self.dtype).reshape((1,ndegfre,ndegfre,1)),labels=[L,U,D,R]))
            if degfres.mode=='QN': ms[-1].qngenerate(flow=-1,axes=[MPO.L,MPO.U,MPO.D],qnses=[L.qns,U.qns,D.qns],flows=[1,1,-1])
        return MPO(ms)
Пример #14
0
    def to_mpo(self,**karg):
        '''
        Convert to the tensor-formatted mpo.

        Parameters
        ----------
        karg : dict with keys containing 'nsweep','method' and 'options'
            Please see MPO.compress for details.

        Returns
        -------
        MPO
            The corresponding tensor-formatted MPO.
        '''
        Ms=[]
        type=self[0][0,0].site.qns.type if isinstance(self[0][0,0].site.qns,QuantumNumbers) else None
        for pos,m in enumerate(self):
            dim=self.sites[pos].dim
            if type is None:
                L=self.bonds[pos].replace(qns=m.shape[0],flow=0)
                U=self.sites[pos].replace(prime=True,flow=0)
                D=self.sites[pos].replace(flow=0)
                R=self.bonds[pos+1].replace(qns=m.shape[1],flow=0)
            else:
                L=copy(self.bonds[pos])
                U=self.sites[pos].P
                D=self.sites[pos]
                R=copy(self.bonds[pos+1])
            Ms.append(DTensor(np.zeros((m.shape[0],dim,dim,m.shape[1]),dtype=dtype),labels=[L,U,D,R]))
            for i,j in it.product(xrange(m.shape[0]),xrange(m.shape[1])):
                Ms[-1][i,:,:,j]=m[i,j].matrix
        result=MPO(Ms)
        result.compress(**karg)
        if type is not None:
            for pos in xrange(len(result)):
                lqns,sqns=QuantumNumbers.mono(type.zero()) if pos==0 else result[pos-1].labels[MPO.R].qns,self.sites[pos].qns
                result[pos].qngenerate(flow=-1,axes=[MPO.L,MPO.U,MPO.D],qnses=[lqns,sqns,sqns],flows=[1,1,-1])
        return result
Пример #15
0
    def tompo(self, degfres, ttype='D'):
        '''
        Convert an optstr to the full-formatted mpo.

        Parameters
        ----------
        degfres : DegFreTree
            The tree of the site degrees of freedom.
        ttype : 'D'/'S', optional
            Tensor type. 'D' for dense and 'S' for sparse.

        Returns
        -------
        MPO
            The corresponding MPO.
        '''
        index = self[0].site.identifier
        type, layer = degfres.dtype, degfres.layers[degfres.level(index) - 1]
        table, sites, bonds = degfres.table(layer), degfres.labels(
            'S', layer), degfres.labels('O', layer)
        poses, matrices = set(table[opt.site.identifier]
                              for opt in self), [opt.matrix for opt in self]
        ms, count = [], 0
        for pos in range(len(sites)):
            ndegfre = sites[pos].dim
            if issubclass(type, QuantumNumbers):
                L = Label(bonds[pos],
                          qns=QuantumNumbers.mono(type.zero())
                          if pos == 0 else ms[-1].labels[MPO.R].qns,
                          flow=None)
                U = sites[pos].P
                D = copy(sites[pos])
                R = Label(bonds[pos + 1], qns=1, flow=None)
            else:
                L = Label(bonds[pos], qns=1, flow=0)
                U = sites[pos].P.replace(flow=0)
                D = sites[pos].replace(flow=0)
                R = Label(bonds[pos + 1], qns=1, flow=0)
            if pos in poses:
                ms.append(
                    DTensor(np.asarray(matrices[count],
                                       dtype=self.dtype).reshape(
                                           (1, ndegfre, ndegfre, 1)),
                            labels=[L, U, D, R]))
                count += 1
            else:
                ms.append(
                    DTensor(np.identity(ndegfre, dtype=self.dtype).reshape(
                        (1, ndegfre, ndegfre, 1)),
                            labels=[L, U, D, R]))
            if issubclass(type, QuantumNumbers):
                ms[-1].qngenerate(flow=-1,
                                  axes=[MPO.L, MPO.U, MPO.D],
                                  qnses=[L.qns, U.qns, D.qns],
                                  flows=[1, 1, -1])
        if ttype == 'S':
            assert issubclass(type, QuantumNumbers)
            for m in ms:
                m.qnsort()
            ms = [m.tostensor() for m in ms]
        return MPO(ms)
Пример #16
0
    def random(sites, bonds=None, cut=None, nmax=None, dtype=np.float64):
        '''
        Generate a random mps.

        Parameters
        ----------
        sites : list of Label/int/QuantumNumbers
            The labels/number-of-degrees-of-freedom/quantum-numbers of the physical legs.
        bonds : optional
            * list of Label
                The labels of the virtual legs.
            * 2-list of QuantumNumber
                The quantum number of the first and last virtual legs.
        cut : int, optional
            The index of the connecting link.
        nmax : int, optional
            The maximum number of singular values to be kept.
        dtype : np.float64, np.complex128, optional
            The data type of the random mps.

        Returns
        -------
        MPS
            The random mixed-canonical mps.
        '''
        np.random.seed()
        sites = [
            site if isinstance(site, Label) else Label(
                '__MPS_RANDOM_S_%s__' % i, qns=site)
            for i, site in enumerate(sites)
        ]
        if bonds is not None and all(
                isinstance(bond, Label) for bond in bonds):
            assert len(bonds) == len(sites) + 1
        else:
            if bonds is not None:
                assert len(bonds) == 2 and isinstance(
                    bonds[0], QN) and isinstance(bonds[1], QN)
            iqns, oqns = (QNS.mono(bonds[0]),
                          QNS.mono(bonds[1])) if bonds is not None else (1, 1)
            bonds = [
                Label(
                    '__MPS_RANDOM_B_%s__' % i,
                    qns=iqns if i == 0 else oqns if i == len(sites) else None)
                for i in xrange(len(sites) + 1)
            ]
        mode, shape = 'QN' if next(iter(sites)).qnon else 'NB', tuple(
            [site.dim for site in sites])
        if mode == 'QN':
            result = 0
            if dtype in (np.float32, np.float64):
                coeffs = np.random.random(nmax)
            else:
                coeffs = np.random.random(nmax) + 1j * np.random.random(nmax)
            for k, indices in enumerate(
                    QNS.decomposition([site.qns for site in sites],
                                      bonds[-1].qns[0] - bonds[0].qns[0],
                                      method='monte carlo',
                                      nmax=nmax)):
                ms = [
                    np.array(
                        [1.0 if i == index else 0.0 for i in xrange(site.dim)],
                        dtype=dtype) for site, index in zip(sites, indices)
                ]
                result += MPS.productstate(ms, sites, copy(bonds)) * coeffs[k]
        else:
            ms = []
            for i in xrange(len(sites)):
                if dtype in (np.float32, np.float64):
                    ms.append(np.random.random((nmax, shape[i], nmax)))
                else:
                    ms.append(
                        np.random.random((nmax, shape[i], nmax)) +
                        1j * np.random.random((nmax, shape[i], nmax)))
            result = MPS(mode=mode, ms=ms, sites=sites, bonds=bonds)
        if cut is None:
            result.canonicalize(cut=len(sites) / 2, nmax=nmax)
            result._merge_ABL_()
        else:
            result.canonicalize(cut=cut, nmax=nmax)
        return result
Пример #17
0
    def random(sites,
               bonds=None,
               cut=None,
               nmax=None,
               ttype='D',
               dtype=np.float64):
        '''
        Generate a random mps.

        Parameters
        ----------
        sites : list of Label/int/QuantumNumbers
            The labels/number-of-degrees-of-freedom/quantum-numbers of the physical legs.
        bonds : optional
            * list of Label/str
                The labels/identifiers of the virtual legs.
            * 2-list of QuantumNumber
                The quantum number of the first and last virtual legs.
        cut : int, optional
            The index of the connecting link.
        nmax : int, optional
            The maximum number of singular values to be kept.
        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 mps.

        Returns
        -------
        MPS
            The random mixed-canonical mps.
        '''
        np.random.seed()
        sites = [
            site if isinstance(site, Label) else Label(
                '__MPS_RANDOM_S_%s__' % i, qns=site)
            for i, site in enumerate(sites)
        ]
        if bonds is None or not isinstance(bonds[+0], Label) or not isinstance(
                bonds[-1], Label):
            if bonds is not None:
                iqns = bonds[+0].qns if isinstance(
                    bonds[+0], Label) else bonds[+0] if isinstance(
                        bonds[+0], QNS) else QNS.mono(bonds[+0]) if isinstance(
                            bonds[+0], QN) else 1
                oqns = bonds[-1].qns if isinstance(
                    bonds[-1], Label) else bonds[-1] if isinstance(
                        bonds[-1], QNS) else QNS.mono(bonds[-1]) if isinstance(
                            bonds[-1], QN) else 1
            else:
                iqns, oqns = 1, 1
            bonds = [
                Label('__MPS_RANDOM_B_%s__' % i, None, None)
                for i in range(len(sites) + 1)
            ]
            bonds[+0] = bonds[+0].replace(qns=iqns)
            bonds[-1] = bonds[-1].replace(qns=oqns)
        else:
            assert len(bonds) == len(sites) + 1
            bonds = [
                bond if isinstance(bond, Label) else Label(bond, None, None)
                for bond in bonds
            ]
        qnon, shape = next(iter(sites)).qnon, tuple(
            [site.dim for site in sites])
        if ttype == 'S': assert qnon
        if qnon:
            result = 0
            if dtype in (np.float32, np.float64):
                coeffs = np.random.random(nmax)
            else:
                coeffs = np.random.random(nmax) + 1j * np.random.random(nmax)
            for k, indices in enumerate(
                    QNS.decomposition([site.qns for site in sites],
                                      bonds[-1].qns[0] - bonds[+0].qns[0],
                                      method='monte carlo',
                                      nmax=nmax)):
                ms = [
                    np.array(
                        [1.0 if i == index else 0.0 for i in range(site.dim)],
                        dtype=dtype) for site, index in zip(sites, indices)
                ]
                result += MPS.productstate(ms, sites, copy(bonds)) * coeffs[k]
            if ttype == 'S':
                for m in result:
                    m.qnsort()
                result = result.tosparse()
        else:
            ms = []
            for i in range(len(sites)):
                if dtype in (np.float32, np.float64):
                    ms.append(np.random.random((nmax, shape[i], nmax)))
                else:
                    ms.append(
                        np.random.random((nmax, shape[i], nmax)) +
                        1j * np.random.random((nmax, shape[i], nmax)))
            result = MPS.compose(ms=ms, sites=sites, bonds=bonds)
        if cut is None:
            result.canonicalize(cut=len(sites) / 2, nmax=nmax)
            result._merge_ABL_()
        else:
            result.canonicalize(cut=cut, nmax=nmax)
        return result
Пример #18
0
    def relayer(self,degfres,layer,nmax=None,tol=None):
        '''
        Construct a new mpo with the site labels living on a specific layer of degfres.

        Parameters
        ----------
        degfres : DegFreTree
            The tree of the site degrees of freedom.
        layer : int/tuple-of-str
            The layer where the site labels live.
        nmax : int, optional
            The maximum number of singular values to be kept.
        tol : np.float64, optional
            The tolerance of the singular values.

        Returns
        -------
        MPO
            The new mpo.
        '''
        new=layer if type(layer) in (int,long) else degfres.layers.index(layer)
        old=degfres.level(next(iter(self)).labels[MPO.U].identifier)-1
        assert 0<=new<len(degfres.layers)
        if new==old:
            return copy(self)
        else:
            olayer,nlayer=degfres.layers[old],degfres.layers[new]
            sites,bonds=[site.replace(flow=-1 if site.qnon else 0) for site in degfres.labels('S',nlayer)],degfres.labels('O',nlayer)
            Ms=[]
            if new<old:
                table=degfres.table(olayer)
                for i,site in enumerate(sites):
                    ms,ups,dws=[],[],[]
                    for index in degfres.descendants(site.identifier,generation=old-new):
                        m=self[table[index]]
                        ms.append(m)
                        ups.append(m.labels[MPO.U])
                        dws.append(m.labels[MPO.D])
                    M=np.product(ms)
                    o1,o2=M.labels[0],M.labels[-1]
                    n1,n2=bonds[i].replace(qns=o1.qns,flow=o1.flow),bonds[i+1].replace(qns=o2.qns,flow=o2.flow)
                    M.relabel(olds=[o1,o2],news=[n1,n2])
                    Ms.append(M.transpose([n1]+ups+dws+[n2]).merge((ups,site.P),(dws,site)))
            else:
                table=degfres.table(nlayer)
                for i,m in enumerate(self):
                    if i>0: m=s*v*m
                    L,U,D,R=m.labels
                    indices=degfres.descendants(D.identifier,generation=new-old)
                    start,stop=table[indices[0]],table[indices[-1]]+1
                    ups,dws,orders,labels,qnses=[],[],[],[],[]
                    for j,site in enumerate(sites[start:stop]):
                        ups.append(site.P)
                        dws.append(site)
                        orders.append(ups[-1])
                        orders.append(dws[-1])
                        qns=QuantumNumbers.kron([site.qns]*2,signs=(+1,-1)) if site.qnon else site.dim**2
                        labels.append(Label('__MPO_RELAYER_%s__'%j,qns=qns,flow=+1 if site.qnon else 0))
                        qnses.append(qns)
                    S=Label('__MPO_RELAYER__',qns=(QuantumNumbers.kron if U.qnon else np.product)(qnses),flow=+1 if U.qnon else 0)
                    m=m.split((U,ups),(D,dws)).transpose([L]+orders+[R]).merge((orders,S))
                    us,s,v=expanded_svd(m,L=[L],S=S,R=[R],E=labels,I=bonds[start+1:stop+1],cut=stop-start,nmax=nmax,tol=tol)
                    for u,up,dw,label in zip(us,ups,dws,labels):
                        Ms.append(u.split((label,[up,dw])))
                Ms[-1]=Ms[-1]*s*v
                Ms[+0].relabel(olds=[MPO.L],news=[Ms[+0].labels[MPO.L].replace(identifier=bonds[+0].identifier)])
                Ms[-1].relabel(olds=[MPO.R],news=[Ms[-1].labels[MPO.R].replace(identifier=bonds[-1].identifier)])
            return MPO(Ms)
Пример #19
0
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)
Пример #20
0
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)
Пример #21
0
    def random(sites,bonds=None,cut=None,nmax=None,ttype='D',dtype=np.float64):
        '''
        Generate a random mps.

        Parameters
        ----------
        sites : list of Label/int/QuantumNumbers
            The labels/number-of-degrees-of-freedom/quantum-numbers of the physical legs.
        bonds : optional
            * list of Label/str
                The labels/identifiers of the virtual legs.
            * 2-list of QuantumNumber
                The quantum number of the first and last virtual legs.
        cut : int, optional
            The index of the connecting link.
        nmax : int, optional
            The maximum number of singular values to be kept.
        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 mps.

        Returns
        -------
        MPS
            The random mixed-canonical mps.
        '''
        np.random.seed()
        sites=[site if isinstance(site,Label) else Label('__MPS_RANDOM_S_%s__'%i,qns=site) for i,site in enumerate(sites)]
        if bonds is None or not isinstance(bonds[+0],Label) or not isinstance(bonds[-1],Label):
            if bonds is not None:
                iqns=bonds[+0].qns if isinstance(bonds[+0],Label) else bonds[+0] if isinstance(bonds[+0],QNS) else QNS.mono(bonds[+0]) if isinstance(bonds[+0],QN) else 1
                oqns=bonds[-1].qns if isinstance(bonds[-1],Label) else bonds[-1] if isinstance(bonds[-1],QNS) else QNS.mono(bonds[-1]) if isinstance(bonds[-1],QN) else 1
            else:
                iqns,oqns=1,1
            bonds=[Label('__MPS_RANDOM_B_%s__'%i,None,None) for i in range(len(sites)+1)]
            bonds[+0]=bonds[+0].replace(qns=iqns)
            bonds[-1]=bonds[-1].replace(qns=oqns)
        else:
            assert len(bonds)==len(sites)+1
            bonds=[bond if isinstance(bond,Label) else Label(bond,None,None) for bond in bonds]
        qnon,shape=next(iter(sites)).qnon,tuple([site.dim for site in sites])
        if ttype=='S': assert qnon
        if qnon:
            result=0
            if dtype in (np.float32,np.float64):
                coeffs=np.random.random(nmax)
            else:
                coeffs=np.random.random(nmax)+1j*np.random.random(nmax)
            for k,indices in enumerate(QNS.decomposition([site.qns for site in sites],bonds[-1].qns[0]-bonds[+0].qns[0],method='monte carlo',nmax=nmax)):
                ms=[np.array([1.0 if i==index else 0.0 for i in range(site.dim)],dtype=dtype) for site,index in zip(sites,indices)]
                result+=MPS.productstate(ms,sites,copy(bonds))*coeffs[k]
            if ttype=='S':
                for m in result: m.qnsort()
                result=result.tosparse()
        else:
            ms=[]
            for i in range(len(sites)):
                if dtype in (np.float32,np.float64):
                    ms.append(np.random.random((nmax,shape[i],nmax)))
                else:
                    ms.append(np.random.random((nmax,shape[i],nmax))+1j*np.random.random((nmax,shape[i],nmax)))
            result=MPS.compose(ms=ms,sites=sites,bonds=bonds)
        if cut is None:
            result.canonicalize(cut=len(sites)/2,nmax=nmax)
            result._merge_ABL_()
        else:
            result.canonicalize(cut=cut,nmax=nmax)
        return result
Пример #22
0
def directsum(tensors, labels, axes=()):
    '''
    The directsum of a couple of tensors.

    Parameters
    ----------
    tensors : list of DTensor/STensor
        The tensors to be directsummed.
    labels : list of Label
        The labels of the directsum.
    axes : list of int, optional
            The axes along which the directsum is block diagonal.

    Returns
    -------
    DTensor/STensor
        The directsum of the tensors.
    '''
    TENSOR = next(iter(tensors))
    assert TENSOR.ndim > len(axes)
    assert len({tensor.ndim for tensor in tensors}) == 1
    assert len(
        {tuple(tensor.shape[axis] for axis in axes)
         for tensor in tensors}) == 1
    assert len(
        {tuple(label.flow for label in tensor.labels)
         for tensor in tensors}) == 1
    alters = set(xrange(TENSOR.ndim)) - set(axes)
    if isinstance(TENSOR, DTensor):
        assert len({tensor.qnon for tensor in tensors}) == 1
        shape, dtypes = [
            0 if axis in alters else TENSOR.shape[axis]
            for axis in xrange(TENSOR.ndim)
        ], []
        for tensor in tensors:
            for alter in alters:
                shape[alter] += tensor.shape[alter]
            dtypes.append(tensor.dtype)
        data = np.zeros(tuple(shape), dtype=np.find_common_type([], dtypes))
        slices = [
            slice(0, 0, 0) if axis in alters else slice(None, None, None)
            for axis in xrange(TENSOR.ndim)
        ]
        for tensor in tensors:
            for alter in alters:
                slices[alter] = slice(slices[alter].stop,
                                      slices[alter].stop + tensor.shape[alter])
            data[tuple(slices)] = tensor.data
        for alter in alters:
            labels[alter].qns = (QuantumNumbers.union
                                 if TENSOR.qnon else np.sum)([
                                     tensor.labels[alter].qns
                                     for tensor in tensors
                                 ])
    else:
        content = {}
        for qns, block in it.chain(*tuple(tensor.iteritems()
                                          for tensor in tensors)):
            if qns not in content:
                content[qns] = ([
                    0 if axis in alters else block.shape[axis]
                    for axis in xrange(block.ndim)
                ], [], [])
            for alter in alters:
                content[qns][0] += block.shape[alter]
            content[qns][1].append(block.dtype)
            content[qns][2].append(block)
        data = {}
        for qns, (shape, dtypes, blocks) in content.iteritems():
            data[qns] = np.zeros(tuple(shape),
                                 dtype=np.find_common_type([], dtypes))
            slices = [
                slice(0, 0, 0) if axis in alters else slice(None, None, None)
                for axis in xrange(TENSOR.ndim)
            ]
            for block in blocks:
                for alter in alters:
                    slices[alter] = slice(
                        slices[alter].stop,
                        slices[alter].stop + block.shape[alter])
                data[tupe(slices)] = block
        for alter in alters:
            labels[alter].qns = QuantumNumbers.union([
                tensor.labels[alter].qns for tensor in tensors
            ]).sorted(history=False)
    for axis in xrange(TENSOR.ndim):
        labels[axis].flow = TENSOR.labels[axis].flow
    for axis in axes:
        labels[axis].qns = tensor.labels[axis].qns
    return type(TENSOR)(data, labels=labels)
Пример #23
0
    def relayer(self,degfres,layer,nmax=None,tol=None):
        '''
        Construct a new mpo with the site labels living on a specific layer of degfres.

        Parameters
        ----------
        degfres : DegFreTree
            The tree of the site degrees of freedom.
        layer : int/tuple-of-str
            The layer where the site labels live.
        nmax : int, optional
            The maximum number of singular values to be kept.
        tol : np.float64, optional
            The tolerance of the singular values.

        Returns
        -------
        MPO
            The new mpo.
        '''
        assert all(isinstance(m,DTensor) for m in self)
        new=layer if type(layer) is int else degfres.layers.index(layer)
        old=degfres.level(next(iter(self)).labels[MPO.U].identifier)-1
        assert 0<=new<len(degfres.layers)
        if new==old:
            return copy(self)
        else:
            olayer,nlayer=degfres.layers[old],degfres.layers[new]
            sites,bonds=[site.replace(flow=-1 if site.qnon else 0) for site in degfres.labels('S',nlayer)],degfres.labels('O',nlayer)
            Ms=[]
            if new<old:
                table=degfres.table(olayer)
                for i,site in enumerate(sites):
                    ms,ups,dws=[],[],[]
                    for index in degfres.descendants(site.identifier,generation=old-new):
                        m=self[table[index]]
                        ms.append(m)
                        ups.append(m.labels[MPO.U])
                        dws.append(m.labels[MPO.D])
                    M=np.product(ms)
                    o1,o2=M.labels[0],M.labels[-1]
                    n1,n2=o1.replace(identifier=bonds[i]),o2.replace(identifier=bonds[i+1])
                    M.relabel(olds=[o1,o2],news=[n1,n2])
                    Ms.append(M.transpose([n1]+ups+dws+[n2]).merge((ups,site.P),(dws,site)))
            else:
                table,s,v=degfres.table(nlayer),1.0,1.0
                for i,m in enumerate(self):
                    m=s*v*m
                    L,U,D,R=m.labels
                    indices=degfres.descendants(D.identifier,generation=new-old)
                    start,stop=table[indices[0]],table[indices[-1]]+1
                    ups,dws,orders,labels,qnses=[],[],[],[],[]
                    for j,site in enumerate(sites[start:stop]):
                        ups.append(site.P)
                        dws.append(site)
                        orders.append(ups[-1])
                        orders.append(dws[-1])
                        qns=QuantumNumbers.kron([site.qns]*2,signs=(+1,-1)) if site.qnon else site.dim**2
                        labels.append(Label('__MPO_RELAYER_%s__'%j,qns=qns,flow=+1 if site.qnon else 0))
                        qnses.append(qns)
                    S=Label('__MPO_RELAYER__',qns=(QuantumNumbers.kron if U.qnon else np.product)(qnses),flow=+1 if U.qnon else 0)
                    m=m.split((U,ups),(D,dws)).transpose([L]+orders+[R]).merge((orders,S))
                    us,s,v=expandedsvd(m,L=[L],S=S,R=[R],E=labels,I=[Label(bond,None,None) for bond in bonds[start+1:stop+1]],cut=stop-start,nmax=nmax,tol=tol)
                    for u,up,dw,label in zip(us,ups,dws,labels):
                        Ms.append(u.split((label,[up,dw])))
                Ms[-1]=Ms[-1]*s*v
                Ms[+0].relabel(olds=[MPO.L],news=[Ms[+0].labels[MPO.L].replace(identifier=bonds[+0])])
                Ms[-1].relabel(olds=[MPO.R],news=[Ms[-1].labels[MPO.R].replace(identifier=bonds[-1])])
            return MPO(Ms)