Exemple #1
0
def IsingSiteTensor(betaJ, dim=4, labels=None):
    """
    The site tensor that can be connected to form Ising tensor network.

    Parameters
    ----------
    betaJ : float or list of float
        The interaction combined with inverse temperature, namely, J / T. When a list is given, the length should be dim, and each for one different edge.
    dim : int, default 4
        The degree of sites(the number of edges it is linked to). By default, square lattice value 4.
    labels : list of str, optional
        The labels of the result tensor on each leg. If betaJ is a number, since the legs are the same, the order of labels do not matter. Otherwise please be carefully about the order of labels since it corresponds to the order of betaJ.
    
    Returns
    -------
    Tensor
        The tensor of dim legs, labelled with labels, and representing the local interaction around a site(a diagonal site tensor with multiple edge tensors).
    """
    assert (funcs.isRealNumber(betaJ)
            or (len(betaJ) == dim)), funcs.errorMessage(
                "betaJ {} do not have required dim {}.".format(betaJ, dim))
    assert ((labels is None) or (len(labels) == dim)), funcs.errorMessage(
        "labels {} do not have required dim {}.".format(labels, dim))

    a = xplib.xp.array([1.0, 1.0])
    a = funcs.diagonalNDTensor(a, dim=dim)
    if (funcs.isRealNumber(betaJ)):
        betaJ = [betaJ] * dim
    # edgeMat = IsingEdgeMatrix(betaJ)
    for i in range(dim):
        edgeMat = IsingEdgeMatrix(betaJ[i])
        a = xplib.xp.tensordot(a, edgeMat, (0, 0))
        # print(a)
    return Tensor(data=a, labels=labels)
Exemple #2
0
    def deduceDimension(self, data, labels):
        """
        Deduce the dimension of current diagonal tensor from data and labels. 

        Parameters
        ----------
        data : None or 1D array or ndarray
            The data to be put in the diagonal tensor.
        labels : None or list of Leg
            The labels to be added to the legs of this tensor.
        
        Returns
        -------
        int
            The dimension of the current tensor.
        """
        # if the labels is given: then use labels
        # otherwise, if data is given(as an ndarray), then we return then len(data.shape)
        # otherwise, error

        if (data is not None) and (len(data.shape) != 1) and (labels is not None) and ((len(labels) != len(data.shape)) or (len(labels) == 0 and len(data.shape) == 1)):
            raise ValueError(funcs.errorMessage(location = "DiagonalTensor.deduceDimension", err = "data {} and labels {} are not compatible.".format(data, labels)))
        # what if len(labels) == 0, len(data.shape) == 1?

        if (labels is not None):
            return len(labels)
        elif (data is not None):
            # then data must be an numpy array
            return len(data.shape)
        else:
            raise ValueError(funcs.errorMessage(location = "DiagonalTensor.deduceDimension", err = "both data and labels are None."))
Exemple #3
0
 def __init__(self, leg1, leg2, name = None):
     assert (isinstance(leg1, Leg) and (isinstance(leg2, Leg))), errorMessage(err = "Bond must be initialized with 2 Leg elements.", location = 'Bond.__init__')
     assert (leg1.dim == leg2.dim), errorMessage(err = "{} and {} do not share the same dimension.".format(leg1, leg2), location = 'Bond.__init__')
     # self.name = getBondName(name)
     self.name = name
     self.legs = (leg1, leg2)
     leg1.bond = self 
     leg2.bond = self
Exemple #4
0
def matrixSchimdtDecomposition(a, dim, chi=None):
    '''
    Schimdt decomposition of matrix a
    a can be either 1D or 2D
    1. if a is 1D: then we reshape a to (dim, -1)
    and then SVD to obtain u(dim, chi), s(chi, chi), vh(chi, -1), return u and s @ vh 
    2. if a is 2D: (s0, s1): then we reshape a to (s0 * dim, s1 // dim)
    SVD to obtain u(s0 * dim, chi), s(chi, chi), vh(chi, -1)
    return u(s0, dim, chi), s @ vh(chi, s1 // dim)
    '''

    funcName = 'CTL.examples.Schimdt.matrixSchimdtDecomposition'

    shape = a.shape

    assert (len(shape) in [1, 2]), funcs.errorMessage(
        "matrix shape can only be 1D or 2D, {} obtained.".format(shape),
        location=funcName)

    if (len(shape) == 1):
        l = shape[0]
        assert ((dim != 0) and (l % dim == 0)), funcs.errorMessage(
            "matrix shape {} cannot be Schimdt decomposed with dimension {}.".
            format(shape, dim),
            location=funcName)
        a = a.reshape((dim, -1))
        u, s, vh = xplib.xp.linalg.svd(a)
        if (chi is None):
            chi = min([u.shape[0], vh.shape[1], funcs.nonZeroElementN(s)])
        else:
            chi = min([u.shape[0], vh.shape[1], chi, funcs.nonZeroElementN(s)])

        u = u[:, :chi]
        s = s[:chi]
        vh = vh[:chi]

        return u, funcs.leftDiagonalProduct(vh, s)

    else:
        s0, s1 = shape
        assert ((dim != 0) and (s1 % dim == 0)), funcs.errorMessage(
            "matrix shape {} cannot be Schimdt decomposed with dimension {}.".
            format(shape, dim),
            location=funcName)
        a = a.reshape(s0 * dim, -1)
        u, s, vh = xplib.xp.linalg.svd(a)
        if (chi is None):
            chi = min([u.shape[0], vh.shape[1], funcs.nonZeroElementN(s)])
        else:
            chi = min([u.shape[0], vh.shape[1], chi, funcs.nonZeroElementN(s)])

        u = u[:, :chi].reshape(s0, dim, chi)
        s = s[:chi]
        vh = vh[:chi]
        return u, funcs.leftDiagonalProduct(vh, s)
Exemple #5
0
 def getIndex(d, x, y):
     # d == 0: "up/bottom" of plaquettes, (n + 1) * m
     # d == 1: "left/right" of plaquettes, n * (m + 1)
     # order: up to down, left to right
     assert (d != 0) or (x >= 0 and x <= n and y >= 0 and y < m), funcs.errorMessage('({}, {}) is not a valid coordinate in ({}, {}) lattice.'.format(x, y, n, m), location = funcName + ".getIndex")
     assert (d != 1) or (x >= 0 and x < n and y >= 0 and y <= m), funcs.errorMessage('({}, {}) is not a valid coordinate in ({}, {}) lattice.'.format(x, y, n, m), location = funcName + ".getIndex")
     
     if (d == 0):
         return x * m + y
     else:
         return (n + 1) * m + x * (m + 1) + y
Exemple #6
0
 def makeAdjacent(self, idx1, idx2):
     funcName = 'FreeBoundaryMPS.makeAdjacent'
     assert (self.isIndex(idx1) and self.isIndex(idx2)), funcs.errorMessage(
         "{} or {} is invalid index.".format(idx1, idx2), location=funcName)
     assert (idx1 != idx2), funcs.errorMessage(
         "cannot make two identical indices adjacent: {} and {}.".format(
             idx1, idx2),
         location=funcName)
     if (idx1 > idx2):
         idx1, idx2 = idx2, idx1
     for i in range(idx1, idx2 - 1):
         self.swap(i, i + 1)
     return idx2 - 1, idx2
Exemple #7
0
def getBondTensorIndices(mpsA, mpsB, bond):
    funcName = 'CTL.examples.MPS.getBondTensorIndices'
    legA, legB = bond.legs
    tensorA, tensorB = legA.tensor, legB.tensor
    if (not mpsA.hasTensor(tensorA)):
        tensorA, tensorB = tensorB, tensorA

    assert (mpsA.hasTensor(tensorA)), funcs.errorMessage(
        '{} does not contain {}.'.format(mpsA, tensorA), location=funcName)
    assert (mpsB.hasTensor(tensorB)), funcs.errorMessage(
        '{} does not contain {}.'.format(mpsA, tensorB), location=funcName)

    return mpsA.tensorIndex(tensorA), mpsB.tensorIndex(tensorB)
Exemple #8
0
    def newString(self, inputStr=None):
        """
        Parameters
        ----------
        inputStr : str, optional
            The string that is preferred to be added. If None, then generate a new string.

        Returns
        -------
        str
            A new string generated, or the input string if it is not None.

        Raises
        ------
        AssertionError
            Raised when inputStr is not None, but the string has already appeared in this set.
        """
        if (inputStr is None):
            res = randomString(self.n)
            while (res in self.stringSet):
                res = randomString(self.n)
        else:
            assert not (inputStr in self.stringSet), funcs.errorMessage(
                err="Error: name '{}' is already used.".format(inputStr),
                location="StringSet.newString")
            res = inputStr

        self.stringSet.add(res)
        return res
Exemple #9
0
def getIsingWeight(g, S):
    """
    Calculate the weight of Ising model for a graph and given spins.

    Parameters
    ----------
    g : UndirectedGraph
        The site-graph to add interaction. The weights represent the betaJ on each edge.
    S : int
        The bitmask of the Ising spin states.
    
    Returns
    -------
    float
        The Boltzmann weight for this configuration.

    """
    funcName = 'CTL.models.Ising.getIsingWeight'
    assert (isinstance(g, UndirectedGraph)), funcs.errorMessage(
        err=
        "only UndirectedGraph can be trasferred to Ising tensor network, {} obtained."
        .format(g),
        location=funcName)

    E = 0.0
    n = len(g.v)
    spin = funcs.intToBitList(S, n)
    for edge in g.getEdges():
        v1, v2 = edge.vertices
        s1, s2 = spin[v1.index], spin[v2.index]
        if (s1 == s2):
            E -= edge.weight
        else:
            E += edge.weight
    return xplib.xp.exp(-E)
Exemple #10
0
    def sideLeg(self, tensor):
        """
        Given tensor on one side, return the corresponding leg. If both legs are from that tensor, return the first.

        Parameters
        ----------
        tensor : Tensor
            Tensor on one side.

        Returns
        -------
        Leg
            The leg in the given tensor.
        
        Raises
        ------
        AssertionError
            Raised if the both legs are not in given tensor.
        """
        if (self.legs[0] in tensor.legs):
            return self.legs[0]
        elif (self.legs[1] in tensor.legs):
            return self.legs[1]
        else:
            raise ValueError(errorMessage("legs {} is not in tensor {}.".format(self.legs, tensor), location = 'Bond.sideLeg'))

# getBondName = Bond.bondNameSet.newString
Exemple #11
0
def doubleMerge(mpsA, mpsB, idxA, idxB):

    funcName = 'CTL.examples.MPS.doubleMerge'
    tensorA = contractTwoTensors(mpsA.getTensor(idxA),
                                 mpsA.getTensor(idxA + 1))
    tensorB = contractTwoTensors(mpsB.getTensor(idxB),
                                 mpsB.getTensor(idxB + 1))

    tensorA, tensorB = merge(tensorA, tensorB, chi=None, bondName='o')
    mpsA.mergeTensor(idxA, tensorA)
    mpsB.mergeTensor(idxB, tensorB)

    mpsA.canonicalize(idx=idxA)
    mpsB.canonicalize(idx=idxB)

    tensorA, tensorB = mpsA.getTensor(idxA), mpsB.getTensor(idxB)
    tensorA, tensorB = merge(tensorA,
                             tensorB,
                             chi=min(mpsA.chi, mpsB.chi),
                             bondName='o',
                             renameWarning=False)
    mpsA.setTensor(idxA, tensorA)
    mpsB.setTensor(idxB, tensorB)

    sb = shareBonds(tensorA, tensorB)
    assert (len(sb) == 1), funcs.errorMessage(
        "{} and {} do not share exactly one bond.".format(tensorA, tensorB),
        location=funcName)
    return sb[0]
Exemple #12
0
    def canonicalize(self, idx):
        '''
        canonicalize the MPS, and the only non-isometry will be put at 0 <= idx < n
        after this, activeIdx will be set to idx
        and we can check the canonicalization of the MPS with self.checkCanonical
        if None for excepIdx(or set to the idx), it will give true before modified
        '''
        assert (isinstance(idx, int) and (idx >= 0)
                and (idx < self.n)), funcs.errorMessage(
                    'index must in [0, n - 1), {} gotten.'.format(idx),
                    location="FreeBoundaryMPS.canonicalize")
        for i in range(idx):
            # print('canonicalizing {} to {}'.format(i, i + 1))
            u, s, v = SchimdtDecomposition(self._tensors[i],
                                           self._tensors[i + 1], self.chi)
            sv = contractTwoTensors(s, v)
            self._tensors[i] = u
            self._tensors[i + 1] = sv
        for i in range(self.n - 1, idx, -1):
            # print('canonicalizing {} to {}'.format(i, i - 1))
            u, s, v = SchimdtDecomposition(self._tensors[i],
                                           self._tensors[i - 1], self.chi)
            # print('isometry = {}'.format(isIsometry(u, ['o'])))
            sv = contractTwoTensors(s, v)
            self._tensors[i] = u
            self._tensors[i - 1] = sv

        self.activeIdx = idx
Exemple #13
0
def exactZFromGraphIsing(g):
    """
    Calculate the exact partition function by enumerating configurations of Ising model.

    Parameters
    ----------
    g : UndirectedGraph
        The site-graph to add interaction. The weights represent the betaJ on each edge.

    Returns
    -------
    float
        The exact Z.
    """

    funcName = 'CTL.models.Ising.exactZFromGraphIsing'
    assert (isinstance(g, UndirectedGraph)), funcs.errorMessage(
        err=
        "only UndirectedGraph can be trasferred to Ising tensor network, {} obtained."
        .format(g),
        location=funcName)

    res = 0.0
    n = len(g.v)
    # for S in range(1 << n):
    #     if (S % 10000 == 0):
    #         print('{}/{}'.format(S, 1 << n))
    #     res += getIsingWeight(g, S)
    res = xplib.xp.sum(
        xplib.xp.array([getIsingWeight(g, S) for S in range(1 << n)]))

    return res
Exemple #14
0
    def trace(self, rows=None, cols=None):
        """
        Trace of the current tensor after making a matrix according to rows and cols. For details, check Tensor.toMatrix

        Parameters
        ----------
        rows : None or list of str or list of Leg
            The legs for the rows of the matrix. If None, deducted from cols.
        cols : None or list of str or list of Leg
            The legs for the cols of the matrix. If None, deducted from rows.
        
        Returns
        -------
        float
            The trace of the matrix generated by given cols and rows.
        """
        assert (not self.tensorLikeFlag), funcs.errorMessage(
            'TensorLike do not have trace since no data contained.',
            'Tensor.trace')
        mat = self.toMatrix(rows=rows, cols=cols)
        assert (
            mat.shape[0] == mat.shape[1]
        ), "Error: Tensor.trace must have the same dimension for cols and rows, but shape {} gotten.".format(
            mat.shape)
        return xplib.xp.trace(mat)
Exemple #15
0
def doubleSquareLatticeFBC(n, m = None, weight = 0.0):
    """
    Create a graph of double square lattice, free boundary condition.

    Double square lattice: take the plaquette tensor as checker board, and they form a square lattice. The (n, m) lattice contains n(m + 1) + m(n + 1) sites.

    Parameters
    ----------
    n : int
        The number of rows of the lattice.
    m : int, optional
        The number of columns of the lattice. By default, the same as n.
    weight : float or tuple of float, optional
        The weight of edges between vertices. If a tuple is given, then the first for left-up to right-bottom edges and the second for right-up to left-bottom edges. By default, both weights are 0.0. This will be used in models like Ising model, where the weight can represent interactions.
    
    Returns
    -------
    UndirectedGraph
        A graph representing the lattice. 
    """
    funcName = 'CTL.funcs.graphFuncs.doubleSquareLatticeFBC'
    assert isinstance(n, int), funcs.errorMessage('n must be int, {} obtained.'.format(n), location = funcName)

    if funcs.isRealNumber(weight):
        weight = (weight, weight)

    weightTTB, weightBTT = weight

    if (m is None):
        m = n 

    nn = n * (m + 1) + m * (n + 1)

    def getIndex(d, x, y):
        # d == 0: "up/bottom" of plaquettes, (n + 1) * m
        # d == 1: "left/right" of plaquettes, n * (m + 1)
        # order: up to down, left to right
        assert (d != 0) or (x >= 0 and x <= n and y >= 0 and y < m), funcs.errorMessage('({}, {}) is not a valid coordinate in ({}, {}) lattice.'.format(x, y, n, m), location = funcName + ".getIndex")
        assert (d != 1) or (x >= 0 and x < n and y >= 0 and y <= m), funcs.errorMessage('({}, {}) is not a valid coordinate in ({}, {}) lattice.'.format(x, y, n, m), location = funcName + ".getIndex")
        
        if (d == 0):
            return x * m + y
        else:
            return (n + 1) * m + x * (m + 1) + y

    g = UndirectedGraph(nn)
    for x in range(n):
        for y in range(m):
            # add edges for square (x, y)
            g.addEdge(idx1 = getIndex(1, x, y), idx2 = getIndex(0, x, y), weight = weightBTT)
            g.addEdge(idx1 = getIndex(1, x, y), idx2 = getIndex(0, x + 1, y), weight = weightTTB)
            g.addEdge(idx1 = getIndex(1, x, y + 1), idx2 = getIndex(0, x, y), weight = weightTTB)
            g.addEdge(idx1 = getIndex(1, x, y + 1), idx2 = getIndex(0, x + 1, y), weight = weightBTT)
            # if (y < m - 1):
            #     g.addEdge(idx1 = getIndex(x, y), idx2 = getIndex(x, y + 1), weight = weightH)
            # if (x < n - 1):
            #     g.addEdge(idx1 = getIndex(x, y), idx2 = getIndex(x + 1, y), weight = weightV)
    
    return g 
Exemple #16
0
 def mergeTensor(self, idx, newTensor):
     # merge idx & (idx + 1) to newTensor
     funcName = 'FreeBoundaryMPS.mergeTensor'
     assert (self.isIndex(idx)
             and self.isIndex(idx + 1)), funcs.errorMessage(
                 "{} or {} is invalid index.".format(idx, idx + 1),
                 location=funcName)
     self._tensors = self._tensors[:idx] + [newTensor
                                            ] + self._tensors[(idx + 2):]
Exemple #17
0
 def getLegsByLabel(self, labelList):
     indices = funcs.generateIndices(self.labels, labelList)
     for index, label in zip(indices, labelList):
         if (index is None):
             raise ValueError(
                 funcs.errorMessage('{} is not in tensor {}'.format(
                     label, self),
                                    location='Tensor.getLegsByLabel'))
     return [self.legs[index] for index in indices]
Exemple #18
0
    def outProduct(self, labelList, newLabel):
        """
        Deprecated

        Comment
        -------
        The outer product will destroy the shape of diagonal tensor: we cannot easily combine several legs if it is a full diagonal tensor, so a TypeError will be raised.
        """
        raise TypeError(funcs.errorMessage(location = "DiagonalTensor.outProduct", err = "DiagonalTensor cannot perform outProduct, since the diagonal nature will be destroyed."))
Exemple #19
0
    def norm(self):
        """
        Norm of the current tensor. O(n).

        Returns
        -------
        float
            The norm of data.
        """
        assert (not self.tensorLikeFlag), funcs.errorMessage('DiagonalTensorLike do not have norm since no data contained.', 'DiagonalTensor.norm')
        return xplib.xp.linalg.norm(self.a)
Exemple #20
0
    def checkCanonical(self, excepIdx=None):
        '''
        check if the current MPS is in canonical(isometry except for excepIdx)
        if the index is not given: check with the index the last time the MPS has been canonicalized for
        !!! Note that: this will be not true when excepIdx is None if the MPS has been changed directly by self._tensors[...] = ...
        '''
        funcName = 'FreeBoundaryMPS.checkCanonical'
        assert (excepIdx is not None) or (
            self.activeIdx is not None
        ), funcs.errorMessage(
            "exception index and MPS.activeIdx cannot be None at the same time.",
            location=funcName)
        if (excepIdx is None):
            excepIdx = self.activeIdx
        assert (isinstance(excepIdx, int) and (excepIdx >= 0)
                and (excepIdx < self.n)), funcs.errorMessage(
                    "exception index must in [0, self.n), {} obtained.".format(
                        excepIdx),
                    location=funcName)
        if (self.n == 0):
            warnings.warn(
                funcs.warningMessage(
                    "number of tensors in MPS is 0, return True",
                    location=funcName))
            return True
        # print([isIsometry(tensor, ['o']) for tensor in self._tensors])
        for i in range(self.n):
            if (i == excepIdx):
                continue
            if (i == 0) or (i == self.n - 1):
                labels = ['o']
            elif (i < excepIdx):
                labels = ['l', 'o']
            else:
                labels = ['r', 'o']
            # print(i, labels, isIsometry(self._tensors[i], labels))
            if not isIsometry(self._tensors[i], labels):
                return False

        return True
Exemple #21
0
    def __init__(self, a, chi=16):
        self.a = a.copy()
        self.chi = chi

        assert funcs.compareLists(a.labels, [
            'l', 'r', 'u', 'd'
        ]), funcs.errorMessage(
            'CTMRG can only accept tensor with legs ["l", "r", "u", "d"], {} obtained.'
            .format(a))

        self.setRecords()
        self.setFTNs()
        self.setInitialTensors()
Exemple #22
0
    def toMatrix(self, rows=None, cols=None):
        """
        Make a matrix of the data of this tensor, given the labels or legs of rows and cols.

        Parameters
        ----------
        rows : None or list of str or list of Leg
            The legs for the rows of the matrix. If None, deducted from cols.
        cols : None or list of str or list of Leg
            The legs for the cols of the matrix. If None, deducted from rows.

        Returns
        -------
        2D ndarray of float
            The data of this tensor, in the form of (rows, cols).
        """
        # print(rows, cols)
        # print(self.labels)
        # input two set of legs
        assert (not self.tensorLikeFlag), funcs.errorMessage(
            'TensorLike cannot be transferred to matrix since no data contained.',
            'Tensor.toMatrix')
        assert not (
            (rows is None) and (cols is None)
        ), "Error in Tensor.toMatrix: toMatrix must have at least row or col exist."
        if (rows is not None) and (isinstance(rows[0], str)):
            rows = [self.getLeg(label) for label in rows]
        if (cols is not None) and (isinstance(cols[0], str)):
            cols = [self.getLeg(label) for label in cols]
        if (cols is None):
            cols = funcs.listDifference(self.legs, rows)
        if (rows is None):
            rows = funcs.listDifference(self.legs, cols)
        assert (
            funcs.compareLists(rows + cols, self.legs)
        ), "Error Tensor.toMatrix: rows + cols must contain(and only contain) all legs of tensor."

        colIndices = self.getLegIndices(cols)
        rowIndices = self.getLegIndices(rows)

        colShape = tuple([self.shape[x] for x in colIndices])
        rowShape = tuple([self.shape[x] for x in rowIndices])
        colTotalSize = funcs.tupleProduct(colShape)
        rowTotalSize = funcs.tupleProduct(rowShape)

        moveFrom = rowIndices + colIndices
        moveTo = list(range(len(moveFrom)))

        data = xplib.xp.moveaxis(xplib.xp.copy(self.a), moveFrom, moveTo)
        data = xplib.xp.reshape(data, (rowTotalSize, colTotalSize))
        return data
Exemple #23
0
def IsingTNFromUndirectedGraph(g):
    """
    Create a tensor network of Ising model basing on an undirected graph.

    Parameters
    ----------
    g : UndirectedGraph
        The site-graph to add interaction. The weights represent the betaJ on each edge.
    
    Returns
    -------
    list of Tensor
        A tensor network, each of the tensors represents one site, and the contraction of this tensor network will give the exact partition function Z.
    """

    funcName = 'CTL.models.Ising.IsingTNFromUndirectedGraph'
    assert (isinstance(g, UndirectedGraph)), funcs.errorMessage(
        err=
        "only UndirectedGraph can be trasferred to Ising tensor network, {} obtained."
        .format(g),
        location=funcName)

    nodes = g.v
    edgeIndex = dict()
    for ei, edge in enumerate(g.getEdges()):
        edgeIndex[edge] = ei

    def getLegName(edge, toV):
        return str(toV.index) + '-' + str(edgeIndex[edge])

    def getLabels(v):
        return [getLegName(edge=e, toV=e.anotherSide(v)) for e in v.edges]

    def getWeights(v):
        return [e.weight for e in v.edges]

    tensors = [
        IsingSiteTensor(betaJ=getWeights(v),
                        dim=len(v.edges),
                        labels=getLabels(v)) for v in nodes
    ]

    for ei, edge in enumerate(g.getEdges()):
        v1, v2 = edge.vertices
        idx1, idx2 = v1.index, v2.index
        makeLink(getLegName(edge=edge, toV=v2), getLegName(edge=edge, toV=v1),
                 tensors[idx1], tensors[idx2])

    return tensors
Exemple #24
0
    def toVector(self):
        """
        Flatten the data contained to a 1D-vector.

        Returns
        -------
        1D ndarray of float
            A vector contains the data in this tensor, following the current order of labels.
        
        """

        assert (not self.tensorLikeFlag), funcs.errorMessage(
            'TensorLike cannot be transferred to vector since no data contained.',
            'Tensor.toVector')
        return xplib.xp.copy(xplib.xp.ravel(self.a))
Exemple #25
0
    def trace(self, rows = None, cols = None):
        """
        Trace of the current diagonal tensor. To not destroy the property for the diagonal tensors, this function can only be used to calculate the global trace on the main diagonal.

        Parameters
        ----------
        rows, cols: None
            Only set to be compatible with the usage for Tensor
        
        Returns
        -------
        float
            The trace of the matrix generated by given cols and rows.
        """
        assert (not self.tensorLikeFlag), funcs.errorMessage('DiagonalTensorLike do not have trace since no data contained.', 'DiagonalTensor.trace')
        return xplib.xp.sum(self.a)
Exemple #26
0
def doubleMergeByBond(mpsA, mpsB, bond1, bond2):
    funcName = 'CTL.examples.MPS.doubleMergeByBond'
    idxA1, idxB1 = getBondTensorIndices(mpsA, mpsB, bond1)
    idxA2, idxB2 = getBondTensorIndices(mpsA, mpsB, bond2)

    idxA1, idxA2 = mpsA.makeAdjacent(idxA1, idxA2)
    idxB1, idxB2 = mpsB.makeAdjacent(idxB1, idxB2)

    # print('mpsA after swap = {}'.format(mpsA))
    # print('mpsB after swap = {}'.format(mpsB))

    assert (idxA1 + 1 == idxA2) and (idxB1 + 1 == idxB2), funcs.errorMessage(
        "index is not adjacent after swapping: ({}, {}) and ({}, {}).".format(
            idxA1, idxA2, idxB1, idxB2),
        location=funcName)
    return doubleMerge(mpsA, mpsB, idxA1, idxB1)
Exemple #27
0
    def toMatrix(self, rows, cols):
        """
        Deprecated

        Make a matrix of the data of this diagonal tensor, given the labels or legs of rows and cols. 

        Deprecated since this function is time comsuming(O(n^d)), and for most of the cases there are much better ways to use the data rather than making a matrix. For details, see CTL.tensor.contract for more information.

        Parameters
        ----------
        rows : None or list of str or list of Leg
            The legs for the rows of the matrix. If None, deducted from cols.
        cols : None or list of str or list of Leg
            The legs for the cols of the matrix. If None, deducted from rows.

        Returns
        -------
        2D ndarray of float
            The data of this tensor, in the form of (rows, cols).
        """
        assert (not self.tensorLikeFlag), funcs.errorMessage('DiagonalTensorLike cannot be transferred to matrix since no data contained.', 'DiagonalTensor.toMatrix')
        # print(rows, cols)
        # print(self.labels)
        # input two set of legs
        funcs.deprecatedFuncWarning(funcName = "DiagonalTensor.toMatrix", deprecateMessage = "Diagonal tensors should be used in a better way for linear algebra calculation rather than be made into a matrix.")
        assert not ((rows is None) and (cols is None)), "Error in Tensor.toMatrix: toMatrix must have at least row or col exist."
        if (rows is not None) and (isinstance(rows[0], str)):
            rows = [self.getLeg(label) for label in rows]
        if (cols is not None) and (isinstance(cols[0], str)):
            cols = [self.getLeg(label) for label in cols]
        if (cols is None):
            cols = funcs.listDifference(self.legs, rows)
        if (rows is None):
            rows = funcs.listDifference(self.legs, cols)
        assert (funcs.compareLists(rows + cols, self.legs)), "Error Tensor.toMatrix: rows + cols must contain(and only contain) all legs of tensor."

        colIndices = self.getLegIndices(cols)
        rowIndices = self.getLegIndices(rows)

        colShape = tuple([self.shape[x] for x in colIndices])
        rowShape = tuple([self.shape[x] for x in rowIndices])
        colTotalSize = funcs.tupleProduct(colShape)
        rowTotalSize = funcs.tupleProduct(rowShape)

        data = funcs.diagonalNDTensor(self.a, self.dim)
        data = xplib.xp.reshape(data, (rowTotalSize, colTotalSize))
        return data
Exemple #28
0
def plaquetteIsingTensor(weight, diamondForm=False):
    """
    A local tensor of Ising model, based on plaquette. Including the interactions on four edges.

    Parameters
    ----------
    weight : float or length-2 tuple of float
        The weights(J) of Ising model. If a length-2 tuple, then two values represent (J_vertical, J_horizontal)
    diamondForm : bool, default False
        If True, then instead of usual ['lu', 'ru', 'rd', 'ld'] tensor, the tensor will be rotated 45 degrees clockwise, so that the ['lu', 'ru', 'rd', 'ld'] will be ['u', 'r', 'd', 'l'], so vertical weight will become the weight from left-bottom to right-top

    Returns
    -------
    Tensor
        Plaquette tensor of labels ['lu', 'ru', 'rd', 'ld'] or ['l', 'd', 'r', 'u']
    """

    funcName = 'CTL.models.Ising.plaquetteIsingTensor'
    if isinstance(weight, float):
        weight = [weight, weight]
    else:
        assert len(weight) == 2, funcs.errorMessage(
            'Only float or (float, float) is accepted by {}, {} obtained.'.
            format(funcName, weight),
            location=funcName)
        weight = list(weight)

    data = xplib.xp.zeros((2, 2, 2, 2), dtype=xplib.xp.float64)
    # ru, rd, ld, lu
    for s in range(16):
        idx = funcs.intToBitTuple(s, 4)
        localE = 0.0

        for i in range(4):
            if (idx[i] == idx[(i + 1) % 4]):
                localE -= weight[i % 2]
                # e.g. ru & rd will share a bond of weight[0](J_vertical)
            else:
                localE += weight[i % 2]

        data[idx] = xplib.xp.exp(-localE)

    labels = ['ru', 'rd', 'ld', 'lu']
    if diamondForm:
        labels = ['r', 'd', 'l', 'u']
    return Tensor(labels=labels, data=data, degreeOfFreedom=2)
Exemple #29
0
    def swap(self, aIdx, bIdx):
        # tensorA and tensorB are tensors in tensorList
        assert ((aIdx >= 0) and (aIdx < self.n) and (bIdx < self.n)
                and (bIdx >= 0)
                and (abs(aIdx - bIdx) == 1)), funcs.errorMessage(
                    "index {} and {} are not valid for MPS with {} tensors.".
                    format(aIdx, bIdx, self.n),
                    location="FreeBoundaryMPS.swap")

        self._tensors[aIdx], _, self._tensors[bIdx] = SchimdtDecomposition(
            self._tensors[aIdx],
            self._tensors[bIdx],
            self.chi,
            squareRootSeparation=True,
            swapLabels=(['o'], ['o']))

        self.activeIdx = None
Exemple #30
0
    def single(self):
        """
        Generate a single value from a shapeless tensor.

        Returns
        -------
        float
            A single value of this tensor.

        """
        # return the single value of this tensor
        # only works if shape == (,)
        assert (not self.tensorLikeFlag), funcs.errorMessage(
            'TensorLike cannot be transferred to single value since no data contained.',
            'Tensor.single')
        assert self.shape == (
        ), "Error: cannot get single value from tensor whose shape is not ()."
        return self.a