示例#1
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]
示例#2
0
def contractCost(ta, tb):
    """
    The cost of contraction of two tensors.

    Parameters
    ----------
    ta, tb : Tensor
        Two tensors we want to contract.

    Returns
    -------
    cost : int
        The exact cost for contraction of two tensors(e.g. for two matrices A * B & B * C, the cost is A * B * C. However, for diagonal tensors, the cost is just the size of output tensor).
    costLevel : int
        The order of the cost(how many dimensions). This is used when we want to decide the order of our calculation to a given bond dimension chi.
    """
    diagonalA, diagonalB = ta.diagonalFlag, tb.diagonalFlag
    if (diagonalA and diagonalB):
        return ta.bondDimension(), 1

    diagonal = diagonalA or diagonalB

    bonds = shareBonds(ta, tb)
    intersectionShape = tuple([bond.legs[0].dim for bond in bonds])
    if (not diagonal):
        cost = funcs.tupleProduct(ta.shape) * funcs.tupleProduct(
            tb.shape) // funcs.tupleProduct(intersectionShape)
        costLevel = len(ta.shape) + len(tb.shape) - len(intersectionShape)
    else:
        cost = funcs.tupleProduct(ta.shape) * funcs.tupleProduct(
            tb.shape) // (funcs.tupleProduct(intersectionShape)**2)
        costLevel = len(ta.shape) + len(tb.shape) - 2 * len(intersectionShape)
    return cost, costLevel
示例#3
0
    def renameBonds(self):
        # 'l' and 'r' for internal bonds
        # 'o' for external bonds
        self.internalBonds = set()
        for i in range(self.n - 1):
            bond = shareBonds(self._tensors[i], self._tensors[i + 1])[0]
            bond.sideLeg(self._tensors[i]).name = 'r'
            bond.sideLeg(self._tensors[i + 1]).name = 'l'
            self.internalBonds.add(bond)

        for i in range(self.n):
            for leg in self._tensors[i].legs:
                if (leg.bond not in self.internalBonds):
                    leg.name = 'o'
示例#4
0
    def getChi(self, chi):
        # if chi is None: then take the maximum from bonds shared
        # otherwise, if bonds sharing larger than chi, then warning and update chi
        # otherwise, take chi
        bondChi = -1
        for i in range(self.n - 1):
            bond = shareBonds(self._tensors[i], self._tensors[i + 1])[0]
            bondChi = min(bondChi, bond.legs[0].dim)

        if (chi is None):
            return bondChi
        elif (bondChi > chi):
            warnings.warn(
                funcs.warningMessage(
                    'required chi {} is lower than real bond chi {}, set to {}.'
                    .format(chi, bondChi, bondChi),
                    location="FreeBoundaryMPS.getChi"))
            return bondChi
        else:
            return chi
示例#5
0
    def checkMPSProperty(self, tensorList):
        # MPS property: first and last tensor has one bond out, and another linked to the next
        # others: one to left, one to right, one out

        n = len(tensorList)

        if (n == 0):
            return False

        for i in range(n - 1):
            if (len(shareBonds(tensorList[i], tensorList[i + 1])) != 1):
                return False

        if (n > 1) and ((tensorList[0].dim != 2) or (tensorList[-1].dim != 2)):
            return False

        for i in range(1, n - 1):
            if (tensorList[i].dim != 3):
                return False

        return True
示例#6
0
def SchimdtDecomposition(ta,
                         tb,
                         chi,
                         squareRootSeparation=False,
                         swapLabels=([], []),
                         singularValueEps=1e-10):
    '''
    Schimdt decomposition between tensor ta and tb
    return ta, s, tb
    ta should be in canonical form, that is, a a^dagger = I
    to do this, first contract ta and tb, while keeping track of legs from a and legs from b
    then SVD over the matrix, take the required chi singular values
    take first chi eigenvectors for a and b, create a diagonal tensor for singular value tensor

    if squareRootSeparation is True: then divide s into two square root diagonal tensors
    and contract each into ta and tb, return ta, None, tb

    if swapLabels is not ([], []): swap the two set of labels for output, so we swapped the locations of two tensors on MPS
    e.g. t[i], t[i + 1] = SchimdtDecomposition(t[i], t[i + 1], chi = chi, squareRootSeparation = True, swapLabels = (['o'], ['o']))
    we can swap the two tensors t[i] & t[i + 1], both have an "o" leg connected to outside
    while other legs(e.g. internal legs in MPS, usually 'l' and 'r') will not be affected
    '''

    funcName = 'CTL.examples.Schimdt.SchimdtDecomposition'
    sb = shareBonds(ta, tb)
    assert (len(sb) > 0), funcs.errorMessage(
        "Schimdt Decomposition cannot accept two tensors without common bonds, {} and {} gotten."
        .format(ta, tb),
        location=funcName)
    assert (ta.tensorLikeFlag == tb.tensorLikeFlag), funcs.errorMessage(
        "Schimdt Decomposition must havge two objects being either Tensor or TensorLike simultaneously, but {} and {} obtained."
        .format(ta, tb),
        location=funcName)

    TLFlag = ta.tensorLikeFlag
    sbDim = funcs.tupleProduct(tuple([bond.legs[0].dim for bond in sb]))

    sharedLabelA = sb[0].sideLeg(ta).name
    sharedLabelB = sb[0].sideLeg(tb).name
    # if (sharedLabelA.startswith('a-')):
    #     raise ValueError(funcs.errorMessage(err = "shared label {} of tensor A starts with 'a-'.".format(sharedLabelA), location = funcName))
    # if (sharedLabelB.startswith('b-')):
    #     raise ValueError(funcs.errorMessage(err = "shared label {} of tensor B starts with 'b-'.".format(sharedLabelB), location = funcName))

    # assert (ta.xp == tb.xp), funcs.errorMessage("Schimdt Decomposition cannot accept two tensors with different xp: {} and {} gotten.".format(ta.xp, tb.xp), location = funcName)

    assert (len(swapLabels[0]) == len(swapLabels[1])), funcs.errorMessage(
        err="invalid swap labels {}.".format(swapLabels), location=funcName)
    assert ta.labelsInTensor(swapLabels[0]), funcs.errorMessage(
        err="{} not in tensor {}.".format(swapLabels[0], ta),
        location=funcName)
    assert tb.labelsInTensor(swapLabels[1]), funcs.errorMessage(
        err="{} not in tensor {}.".format(swapLabels[1], tb),
        location=funcName)

    ta.addTensorTag('a')
    tb.addTensorTag('b')
    for swapLabel in swapLabels[0]:
        ta.renameLabel('a-' + swapLabel, 'b-' + swapLabel)
    for swapLabel in swapLabels[1]:
        tb.renameLabel('b-' + swapLabel, 'a-' + swapLabel)

    tot = contractTwoTensors(ta, tb)

    legA = [leg for leg in tot.legs if leg.name.startswith('a-')]
    legB = [leg for leg in tot.legs if leg.name.startswith('b-')]

    labelA = [leg.name for leg in legA]
    labelB = [leg.name for leg in legB]
    # not remove a- and b- here, since we need to add an internal leg, and we need to distinguish it from others

    shapeA = tuple([leg.dim for leg in legA])
    shapeB = tuple([leg.dim for leg in legB])

    totShapeA = funcs.tupleProduct(shapeA)
    totShapeB = funcs.tupleProduct(shapeB)

    if (TLFlag):
        u = None
        vh = None
        s = None
        chi = min([chi, totShapeA, totShapeB, sbDim])
    else:
        mat = tot.toMatrix(rows=labelA, cols=labelB)

        # np = ta.xp # default numpy

        u, s, vh = xplib.xp.linalg.svd(mat)

        chi = min([
            chi, totShapeA, totShapeB,
            funcs.nonZeroElementN(s, singularValueEps)
        ])
        u = u[:, :chi]
        s = s[:chi]
        vh = vh[:chi]

    if (squareRootSeparation):
        if (TLFlag):
            uS = None
            vS = None
        else:
            sqrtS = xplib.xp.sqrt(s)
            uS = funcs.rightDiagonalProduct(u, sqrtS)
            vS = funcs.leftDiagonalProduct(vh, sqrtS)

        outLegForU = Leg(None, chi, name=sharedLabelA)
        # inLegForU = Leg(None, chi, name = sharedLabelB)
        # internalLegForS1 = Leg(None, chi, name = 'o')
        # internalLegForS2 = Leg(None, chi, name = 'o')
        # inLegForV = Leg(None, chi, name = sharedLabelA)
        outLegForV = Leg(None, chi, name=sharedLabelB)

        uTensor = Tensor(data=uS,
                         legs=legA + [outLegForU],
                         shape=shapeA + (chi, ),
                         tensorLikeFlag=TLFlag)
        # s1Tensor = DiagonalTensor(data = xplib.xp.sqrt(s), legs = [inLegForU, internalLegForS1], shape = (chi, chi))
        # s2Tensor = DiagonalTensor(data = xplib.xp.sqrt(s), legs = [internalLegForS2, inLegForV], shape = (chi, chi))
        vTensor = Tensor(data=vS,
                         legs=[outLegForV] + legB,
                         shape=(chi, ) + shapeB,
                         tensorLikeFlag=TLFlag)

        # legs should be automatically set by Tensor / DiagonalTensor, so no need for setTensor

        # outLegForU.setTensor(uTensor)
        # outLegForV.setTensor(vTensor)

        # inLegForU.setTensor(sTensor)
        # inLegForV.setTensor(sTensor)

        # remove a- and b-
        for leg in legA:
            if (leg.name.startswith('a-')):
                leg.name = leg.name[2:]

        for leg in legB:
            if (leg.name.startswith('b-')):
                leg.name = leg.name[2:]

        makeLink(outLegForU, outLegForV)

        # makeLink(outLegForU, inLegForU)
        # makeLink(outLegForV, inLegForV)
        # makeLink(internalLegForS1, internalLegForS2)
        # uTensor = contractTwoTensors(uTensor, s1Tensor)
        # vTensor = contractTwoTensors(vTensor, s2Tensor)
        return uTensor, None, vTensor

    outLegForU = Leg(None, chi, name=sharedLabelA)
    inLegForU = Leg(None, chi, name=sharedLabelB)
    inLegForV = Leg(None, chi, name=sharedLabelA)
    outLegForV = Leg(None, chi, name=sharedLabelB)

    uTensor = Tensor(data=u,
                     legs=legA + [outLegForU],
                     shape=shapeA + (chi, ),
                     tensorLikeFlag=TLFlag)
    sTensor = DiagonalTensor(data=s,
                             legs=[inLegForU, inLegForV],
                             shape=(chi, chi),
                             tensorLikeFlag=TLFlag)
    vTensor = Tensor(data=vh,
                     legs=[outLegForV] + legB,
                     shape=(chi, ) + shapeB,
                     tensorLikeFlag=TLFlag)

    # legs should be automatically set by Tensor / DiagonalTensor, so no need for setTensor

    # outLegForU.setTensor(uTensor)
    # outLegForV.setTensor(vTensor)

    # inLegForU.setTensor(sTensor)
    # inLegForV.setTensor(sTensor)

    # remove a- and b-
    for leg in legA:
        if (leg.name.startswith('a-')):
            leg.name = leg.name[2:]

    for leg in legB:
        if (leg.name.startswith('b-')):
            leg.name = leg.name[2:]

    makeLink(outLegForU, inLegForU)
    makeLink(outLegForV, inLegForV)

    return uTensor, sTensor, vTensor
示例#7
0
文件: test_merge.py 项目: CaoRX/CTL
    def test_merge(self):
        '''
        test the merge(ta, tb) for merge the bonds between ta and tb
        '''

        # normal tensor merge case: 2 shared bonds
        ta = Tensor(shape=(3, 4, 5), labels=['a3', 'a4', 'a5'])
        tb = Tensor(shape=(4, 3, 6), labels=['b4', 'b3', 'b6'])

        makeLink('a3', 'b3', ta, tb)
        makeLink('a4', 'b4', ta, tb)

        ta, tb = merge(ta, tb)

        self.assertTrue(funcs.compareLists(ta.labels, ['a3|a4', 'a5']))
        self.assertTrue(funcs.compareLists(tb.labels, ['b3|b4', 'b6']))
        ta.reArrange(['a3|a4', 'a5'])
        self.assertTupleEqual(ta.shape, (12, 5))
        tb.reArrange(['b3|b4', 'b6'])
        self.assertTupleEqual(tb.shape, (12, 6))
        self.assertEqual(len(shareBonds(ta, tb)), 1)

        # normal tensor merge case, order changed

        ta = Tensor(shape=(3, 4, 5), labels=['a3', 'a4', 'a5'])
        tb = Tensor(shape=(4, 3, 6), labels=['b4', 'b3', 'b6'])

        makeLink('a3', 'b3', ta, tb)
        makeLink('a4', 'b4', ta, tb)

        tb, ta = merge(tb, ta)

        self.assertTrue(funcs.compareLists(ta.labels, ['a4|a3', 'a5']))
        self.assertTrue(funcs.compareLists(tb.labels, ['b4|b3', 'b6']))

        # test single shared bond: with warning, and do nothing but rename

        ta = Tensor(shape=(3, 4, 5), labels=['a3', 'a4', 'a5'])
        tb = Tensor(shape=(4, 3, 6), labels=['b4', 'b3', 'b6'])

        makeLink('a3', 'b3', ta, tb)
        # tb, ta = merge(tb, ta, bondName = 'o')

        with self.assertWarns(RuntimeWarning) as cm:
            tb, ta = merge(tb, ta, bondName='o')

        self.assertIn('link.py', cm.filename)
        message = cm.warning.__str__()
        self.assertIn('mergeLink cannot merge links', message)
        self.assertIn('sharing one bond', message)
        self.assertTrue(funcs.compareLists(['o', 'a4', 'a5'], ta.labels))
        self.assertTrue(funcs.compareLists(['o', 'b4', 'b6'], tb.labels))

        # test for normal merge, tensorLike

        ta = Tensor(shape=(3, 4, 5),
                    labels=['a3', 'a4', 'a5'],
                    tensorLikeFlag=True)
        tb = Tensor(shape=(4, 3, 6),
                    labels=['b4', 'b3', 'b6'],
                    tensorLikeFlag=True)

        makeLink('a3', 'b3', ta, tb)
        makeLink('a4', 'b4', ta, tb)

        ta, tb = merge(ta, tb)

        self.assertTrue(funcs.compareLists(ta.labels, ['a3|a4', 'a5']))
        self.assertTrue(funcs.compareLists(tb.labels, ['b3|b4', 'b6']))
        ta.reArrange(['a3|a4', 'a5'])
        self.assertTupleEqual(ta.shape, (12, 5))
        tb.reArrange(['b3|b4', 'b6'])
        self.assertTupleEqual(tb.shape, (12, 6))
        self.assertEqual(len(shareBonds(ta, tb)), 1)
        self.assertTrue(ta.tensorLikeFlag and tb.tensorLikeFlag)

        # test for single bond merge, tensorLike

        ta = Tensor(shape=(3, 4, 5),
                    labels=['a3', 'a4', 'a5'],
                    tensorLikeFlag=True)
        tb = Tensor(shape=(4, 3, 6),
                    labels=['b4', 'b3', 'b6'],
                    tensorLikeFlag=True)

        makeLink('a3', 'b3', ta, tb)
        # tb, ta = merge(tb, ta, bondName = 'o')

        with self.assertWarns(RuntimeWarning) as cm:
            tb, ta = merge(tb, ta, bondName='o')

        self.assertIn('link.py', cm.filename)
        message = cm.warning.__str__()
        self.assertIn('mergeLink cannot merge links', message)
        self.assertIn('sharing one bond', message)
        self.assertTrue(ta.tensorLikeFlag and tb.tensorLikeFlag)

        ta = Tensor(shape=(3, 4, 5), labels=['a3', 'a4', 'a5'])
        tb = Tensor(shape=(4, 3, 6), labels=['b4', 'b3', 'b6'])

        with self.assertWarns(RuntimeWarning) as cm:
            ta, tb = merge(ta, tb, bondName='o')
        self.assertIn('link.py', cm.filename)

        ta = Tensor(shape=(3, 4, 5), labels=['a3', 'a4', 'a5'])
        tb = Tensor(shape=(4, 3, 6), labels=['b4', 'b3', 'b6'])

        with self.assertWarns(RuntimeWarning) as cm:
            ta, tb = merge(ta, tb, bondName='o', chi=2)
        # print(cm.__dict__)
        self.assertIn('link.py', cm.filename)

        ta = Tensor(shape=(3, 4, 5), labels=['a3', 'a4', 'a5'])
        tb = Tensor(shape=(4, 3, 6), labels=['b4', 'b3', 'b6'])

        makeLink('a3', 'b3', ta, tb)
        makeLink('a4', 'b4', ta, tb)

        ta, tb = merge(ta, tb, chi=2)

        self.assertTrue(funcs.compareLists(ta.labels, ['a3|a4', 'a5']))
        self.assertTrue(funcs.compareLists(tb.labels, ['b3|b4', 'b6']))
        ta.reArrange(['a3|a4', 'a5'])
        self.assertTupleEqual(ta.shape, (2, 5))
        tb.reArrange(['b3|b4', 'b6'])
        self.assertTupleEqual(tb.shape, (2, 6))
        self.assertEqual(len(shareBonds(ta, tb)), 1)

        ta = Tensor(shape=(3, 4, 5),
                    labels=['a3', 'a4', 'a5'],
                    tensorLikeFlag=True)
        tb = Tensor(shape=(4, 3, 6),
                    labels=['b4', 'b3', 'b6'],
                    tensorLikeFlag=True)

        makeLink('a3', 'b3', ta, tb)
        makeLink('a4', 'b4', ta, tb)

        ta, tb = merge(ta, tb, chi=2)
        # print(ta, tb)

        self.assertTrue(funcs.compareLists(ta.labels, ['a3|a4', 'a5']))
        self.assertTrue(funcs.compareLists(tb.labels, ['b3|b4', 'b6']))
        ta.reArrange(['a3|a4', 'a5'])
        self.assertTupleEqual(ta.shape, (2, 5))
        tb.reArrange(['b3|b4', 'b6'])
        self.assertTupleEqual(tb.shape, (2, 6))
        self.assertEqual(len(shareBonds(ta, tb)), 1)
        self.assertTrue(ta.tensorLikeFlag and tb.tensorLikeFlag)

        ta = Tensor(shape=(3, 4, 5), labels=['a3', 'a4', 'a5'])
        tb = Tensor(shape=(4, 3, 6), labels=['b4', 'b3', 'b6'])

        makeLink('a3', 'b3', ta, tb)
        makeLink('a4', 'b4', ta, tb)

        # large chi test
        ta, tb = merge(ta, tb, chi=15)
        # the real internal bond size is chosen by min(chi, ta.remainShape, tb.remainShape, mergeShape)

        self.assertTrue(funcs.compareLists(ta.labels, ['a3|a4', 'a5']))
        self.assertTrue(funcs.compareLists(tb.labels, ['b3|b4', 'b6']))
        ta.reArrange(['a3|a4', 'a5'])
        self.assertTupleEqual(ta.shape, (5, 5))
        tb.reArrange(['b3|b4', 'b6'])
        self.assertTupleEqual(tb.shape, (5, 6))
        self.assertEqual(len(shareBonds(ta, tb)), 1)