Beispiel #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)
Beispiel #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)
Beispiel #3
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)
                            ])
Beispiel #4
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
Beispiel #5
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
Beispiel #6
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)
Beispiel #7
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)