Exemplo n.º 1
0
def RandomPEPS_SU(N, M, Jk, dE, D_max, bc, t_list, iterations):

    # Tensor Network parameters
    D = D_max  # virtual bond dimension
    d = 2  # physical bond dimension
    h = 0  # Hamiltonian: magnetic field coeffs
    Op = np.eye(d) / np.sqrt(3)
    Opi = [Op, Op, Op]
    Opj = [Op, Op, Op]
    Op_field = np.eye(d)

    # generating the PEPS structure matrix
    if bc == 'open':
        smat, imat = tnf.finitePEPSobcStructureMatrixGenerator(N, M)
    if bc == 'periodic':
        smat, imat = tnf.squareFinitePEPSpbcStructureMatrixGenerator(N * M)

    # generating tensors and bond vectors
    if bc == 'open':
        TT, LL = tnf.randomTensornetGenerator(smat, d, D)
    if bc == 'periodic':
        TT, LL = tnf.randomTensornetGenerator(smat, d, D)
    TT0, LL0 = cp.deepcopy(TT), cp.deepcopy(LL)

    # iterating the gPEPS algorithm
    s = time.time()
    for dt in t_list:
        for j in range(iterations):
            #print('N, D max, dt, j = ', N * M, D_max, dt, j)
            TT1, LL1 = BP.simpleUpdate(TT, LL, dt, Jk, h, Opi, Opj, Op_field,
                                       smat, D_max, 'SU')
            TT2, LL2 = BP.simpleUpdate(TT1, LL1, dt, Jk, h, Opi, Opj, Op_field,
                                       smat, D_max, 'SU')
            error = 0
            for i in range(len(LL1)):
                error += np.sum(np.abs(LL1[i] - LL2[i]))
            #print('error = ', error)
            if error < dE * dt:
                TT = TT2
                LL = LL2
                break
            else:
                TT = TT2
                LL = LL2
        if error < dE * dt:
            break
    tot = time.time() - s
    return [TT0, LL0, TT, LL], tot
Exemplo n.º 2
0
def RandomPEPS_BP(N,
                  M,
                  Jk,
                  dE,
                  D_max,
                  t_max,
                  epsilon,
                  dumping,
                  bc,
                  t_list,
                  iterations,
                  TN=None):

    # Tensor Network parameters
    D = D_max  # virtual bond dimension
    d = 2  # physical bond dimension
    h = 0  # Hamiltonian: magnetic field coeff

    Op = np.eye(d) / np.sqrt(3)
    Opi = [Op, Op, Op]
    Opj = [Op, Op, Op]
    Op_field = np.eye(d)

    # generating the PEPS structure matrix
    if bc == 'open':
        smat, imat = tnf.finitePEPSobcStructureMatrixGenerator(N, M)
    if bc == 'periodic':
        smat, imat = tnf.squareFinitePEPSpbcStructureMatrixGenerator(N * M)

    # generating tensors and bond vectors
    if TN:
        TT, LL = TN
    else:
        if bc == 'open':
            TT, LL = tnf.randomTensornetGenerator(smat, d, D)
        if bc == 'periodic':
            TT, LL = tnf.randomTensornetGenerator(smat, d, D)

    # constructing the dual double-edge factor graph
    graph = defg.defg()
    graph = BP.TNtoDEFGtransform(graph, TT, LL, smat)
    s = time.time()
    graph.sumProduct(t_max, epsilon, dumping)
    tot = time.time() - s
    graph.calculateFactorsBeliefs()
    return graph, tot
        for i in range(len(Opi)):
            hij += np.kron(Opi[i], Opj[i])
        hij = hij.reshape(p, p, p, p)



    #
    ######### CALCULATING ENERGIES  ########
    #
        #for e in environment_size:
        #    E_gPEPS.append(np.real(BP.energy_per_site_with_environment([N, M], e, TT_gPEPS, LL_gPEPS, smat, Jk, h, Opi, Opj, Op_field)))
        #    E_BP.append(np.real(BP.energy_per_site_with_environment([N, M], e, TT_BP, LL_BP, smat, Jk, h, Opi, Opj, Op_field)))
        #    E_BP_factor_belief.append(np.real(BP.BP_energy_per_site_using_factor_belief_with_environment(graph, e, [N, M], smat, Jk, h, Opi, Opj, Op_field)))

        Dp = [D ** 2, 2 * (D ** 2)]
        TT_BP_bmps = BP.absorbAllTensorNetWeights(TT_BP_bmps, LL_BP, smat)
        TT_BP_bmps = tnf.PEPS_OBC_broadcast_to_Itai(TT_BP_bmps, [N, M], p, D)
        BP_peps = bmps.peps(N, M)
        for t, T in enumerate(TT_BP_bmps):
            i, j = np.unravel_index(t, [N, M])
            BP_peps.set_site(T, i, j)
        for dp_idx, dp in enumerate(Dp):
            print('BP: D, Dp = ', D, dp)
            rho_BP_bmps = bmps.calculate_PEPS_2RDM(BP_peps, dp)
            rho_BP_bmps_sum = cp.deepcopy(rho_BP_bmps[0])
            for i in range(1, len(rho_BP_bmps)):
                rho_BP_bmps_sum += rho_BP_bmps[i]
            E_BP_bmps[D_idx, dp_idx] = np.real(np.einsum(rho_BP_bmps_sum, [0, 1, 2, 3], hij, [0, 2, 1, 3]) / (N * M))

        TT_gPEPS_bmps = BP.absorbAllTensorNetWeights(TT_gPEPS_bmps, LL_gPEPS, smat)
        TT_gPEPS_bmps = tnf.PEPS_OBC_broadcast_to_Itai(TT_gPEPS_bmps, [N, M], p, D)
def Heisenberg_PEPS_gPEPS(N, M, Jk, dE, D_max, bc, t_list, iterations):

    # Tensor Network parameters

    d = 2  # virtual bond dimension
    p = 2  # physical bond dimension
    h = 0  # Hamiltonian: magnetic field coeffs
    gPEPS_energy = []
    print('running Heisenberg_PEPS_SU: D = ', D_max)

    pauli_z = np.array([[1, 0], [0, -1]])
    pauli_y = np.array([[0, -1j], [1j, 0]])
    pauli_x = np.array([[0, 1], [1, 0]])
    sz = 0.5 * pauli_z
    sy = 0.5 * pauli_y
    sx = 0.5 * pauli_x
    Opi = [sx, sy, sz]
    Opj = [sx, sy, sz]
    Op_field = np.eye(p)

    # generating the PEPS structure matrix

    if bc == 'open':
        smat, imat = tnf.finitePEPSobcStructureMatrixGenerator(N, M)
    if bc == 'periodic':
        smat, imat = tnf.squareFinitePEPSpbcStructureMatrixGenerator(N * M)
    '''
    smat = np.array([[1, 2, 3, 4, 0, 0, 0, 0],
                     [1, 2, 0, 0, 3, 4, 0, 0],
                     [0, 0, 1, 2, 0, 0, 3, 4],
                     [0, 0, 0, 0, 1, 2, 3, 4]])
    '''
    n, m = smat.shape

    # generating tensors and bond vectors

    if bc == 'open':
        TT, LL = tnf.randomTensornetGenerator(smat, p, d)
    if bc == 'periodic':
        TT, LL = tnf.randomTensornetGenerator(smat, p, d)

    # iterating the gPEPS algorithm

    for dt in t_list:
        for j in range(iterations):
            #print('N, D max, dt, j = ', N * M, D_max, dt, j)
            TT1, LL1 = BP.simpleUpdate(TT, LL, dt, Jk, h, Opi, Opj, Op_field,
                                       smat, D_max, 'gPEPS')
            TT2, LL2 = BP.simpleUpdate(TT1, LL1, dt, Jk, h, Opi, Opj, Op_field,
                                       smat, D_max, 'gPEPS')
            energy1 = BP.energyPerSite(TT1, LL1, smat, Jk, h, Opi, Opj,
                                       Op_field)
            energy2 = BP.energyPerSite(TT2, LL2, smat, Jk, h, Opi, Opj,
                                       Op_field)

            gPEPS_energy.append(energy1)
            gPEPS_energy.append(energy2)

            #print(energy1, energy2)

            if np.abs(energy1 - energy2) < dE * dt:
                TT = TT2
                LL = LL2
                break
            else:
                TT = TT2
                LL = LL2

    return [TT, LL, gPEPS_energy]
def Heisenberg_PEPS_BP(N,
                       M,
                       Jk,
                       dE,
                       D_max,
                       t_max,
                       epsilon,
                       dumping,
                       bc,
                       t_list,
                       iterations,
                       TN=None):

    # Tensor Network parameters
    d = D_max  # virtual bond dimension
    p = 2  # physical bond dimension
    h = 0  # Hamiltonian: magnetic field coeffs
    BP_energy = []
    print('running Heisenberg_PEPS_BP: D = ', D_max)
    # pauli matrices
    pauli_z = np.array([[1, 0], [0, -1]])
    pauli_y = np.array([[0, -1j], [1j, 0]])
    pauli_x = np.array([[0, 1], [1, 0]])
    sz = 0.5 * pauli_z
    sy = 0.5 * pauli_y
    sx = 0.5 * pauli_x
    Opi = [sx, sy, sz]
    Opj = [sx, sy, sz]
    Op_field = np.eye(p)

    # generating the PEPS structure matrix

    if bc == 'open':
        smat, imat = tnf.finitePEPSobcStructureMatrixGenerator(N, M)
    if bc == 'periodic':
        smat, imat = tnf.squareFinitePEPSpbcStructureMatrixGenerator(N * M)
    '''
    smat = np.array([[1, 2, 3, 4, 0, 0, 0, 0],
                     [1, 2, 0, 0, 3, 4, 0, 0],
                     [0, 0, 1, 2, 0, 0, 3, 4],
                     [0, 0, 0, 0, 1, 2, 3, 4]])
    '''
    n, m = smat.shape

    # generating tensors and bond vectors

    if TN:
        TT, LL = TN
    else:
        if bc == 'open':
            TT, LL = tnf.randomTensornetGenerator(smat, p, d)
        if bc == 'periodic':
            TT, LL = tnf.randomTensornetGenerator(smat, p, d)

    # constructing the dual double-edge factor graph

    graph = defg.defg()
    graph = BP.TNtoDEFGtransform(graph, TT, LL, smat)
    graph.sumProduct(t_max, epsilon, dumping)

    # iterating the BP truncation algorithm

    for dt in t_list:
        for j in range(iterations):
            #print('BP_N, D max, dt, j = ', N, D_max, dt, j)
            TT1, LL1 = BP.simpleUpdate(TT, LL, dt, Jk, h, Opi, Opj, Op_field,
                                       smat, D_max, 'BP', graph)
            graph.sumProduct(t_max, epsilon, dumping, 'init_with_old_messages')
            energy1 = BP.BPenergyPerSite(graph, smat, Jk, h, Opi, Opj,
                                         Op_field)
            TT2, LL2 = BP.simpleUpdate(TT1, LL1, dt, Jk, h, Opi, Opj, Op_field,
                                       smat, D_max, 'BP', graph)
            graph.sumProduct(t_max, epsilon, dumping, 'init_with_old_messages')
            energy2 = BP.BPenergyPerSite(graph, smat, Jk, h, Opi, Opj,
                                         Op_field)

            BP_energy.append(np.real(energy1))
            BP_energy.append(np.real(energy2))

            #print(energy1, energy2)

            if np.abs(energy1 - energy2) < dE * dt:
                TT = TT2
                LL = LL2
                break
            else:
                TT = TT2
                LL = LL2

    return [graph, TT, LL, BP_energy]
Exemplo n.º 6
0
file_name = date + experimentNum + PEPSsize

# Set lists for ttd (total trace distance)
ttd_SU_bMPO = np.zeros((1, n), dtype=float)
ttd_SU_BP = np.zeros((1, n), dtype=float)
ttd_bMPO16_bMPO32 = np.zeros((1, n), dtype=float)

# Run experiment
for i in range(n):
    print('\n')
    print('i:', i)
    rho_SU_0_bmps_single, rho_SU, rho_BP = randomPEPSmainFunction(N, M)
    rho_SU_0_bmps16_single = rho_SU_0_bmps_single[0]
    rho_SU_0_bmps32_single = rho_SU_0_bmps_single[1]
    for j in range(N):
        ttd_SU_bMPO[0][i] += BP.traceDistance(rho_SU_0_bmps16_single[j],
                                              rho_SU[j]) / N
        ttd_SU_BP[0][i] += BP.traceDistance(rho_BP[j], rho_SU[j]) / N
        ttd_bMPO16_bMPO32[0][i] += BP.traceDistance(
            rho_SU_0_bmps16_single[j], rho_SU_0_bmps32_single[j]) / N
av_ttd_SU_bMPO = np.sum(ttd_SU_bMPO) / n
av_ttd_SU_BP = np.sum(ttd_SU_BP) / n
av_ttd_bMPO16_bMPO32 = np.sum(ttd_bMPO16_bMPO32) / n

# Display to screen
print('\n')
print('----------------------------------------------------------------')
print('                           RESULTS                              ')
print('----------------------------------------------------------------')
print(' Average total trace-distance (bMPO16 - bMPO32) = %.12f' %
      av_ttd_bMPO16_bMPO32)
print(' Average total trace-distance (SU - bMPO16)     = %.12f' %
Exemplo n.º 7
0
def randomPEPSmainFunction(N, M):

    # PEPS parameters
    bc = 'open'
    dE = 1e-5
    t_max = 200
    dumping = 0.2
    epsilon = 1e-5
    D_max = [3]
    mu = -1
    sigma = 0
    Jk = np.random.normal(mu, sigma, np.int((N - 1) * M + (M - 1) * N))
    dt = [0.1, 0.05, 0.01]
    iterations = 10
    Dp = [4, 8]
    d = 2
    smat, imat = tnf.finitePEPSobcStructureMatrixGenerator(N, M)

    # Set lists
    BP_data = []
    SU_data = []
    rho_SU = []
    rho_SU_0_bmps = []
    rho_SU_0_bmps_single = []

    # Run Simple Update & Belief Propagation
    for D in D_max:
        b, time_su = rpeps.RandomPEPS_SU(N, M, Jk, dE, D, bc, dt, iterations)
        TT0, LL0 = b[0], b[1]
        a, time_bp = rpeps.RandomPEPS_BP(N, M, Jk, dE, D, t_max, epsilon,
                                         dumping, bc, dt, iterations,
                                         [TT0, LL0])
        BP_data.append(a)
        SU_data.append(b)

    # Arrange single site rdms order in list as in bmpslib
    indices = []
    counter = 0
    counter2 = N * (M - 1) - 1 + (N - 1) * (M - 1) + 1
    counter3 = 0
    while counter3 < N:
        indices += range(counter, counter + M - 1)
        indices.append(counter2)
        counter += (M - 1)
        counter2 += 1
        counter3 += 1
    indices.pop()

    # Caclualting reduced density matrices
    for ii in range(len(D_max)):
        graph = BP_data[ii]
        TT_SU_0, LL_SU_0, TT_SU, LL_SU = SU_data[ii]
        TT_SU_0_bmps = cp.deepcopy(TT_SU_0)

        # RDMS using BP and SU
        for i in range(len(TT_SU)):
            rho_SU.append(BP.singleSiteRDM(i, TT_SU, LL_SU, smat))
        rho_BP = graph.calculateRDMSfromFactorBeliefs()

        # RDMS using BMPO from bmpslib
        TT_SU_0_bmps = BP.absorbAllTensorNetWeights(TT_SU_0_bmps, LL_SU_0,
                                                    smat)
        TT_SU_0_bmps = tnf.PEPS_OBC_broadcast_to_Itai(TT_SU_0_bmps, [N, M], d,
                                                      D_max[ii])
        SU_0_peps = bmps.peps(N, M)
        for t, T in enumerate(TT_SU_0_bmps):
            i, j = np.unravel_index(t, [N, M])
            SU_0_peps.set_site(T, i, j)
        for dp_idx, dp in enumerate(Dp):
            print('Dp:', dp)
            rho_SU_0_bmps.append(bmps.calculate_PEPS_2RDM(SU_0_peps, dp))
            rho_SU_0_bmps_single.append([])
            for jj in indices:
                rho_SU_0_bmps_single[dp_idx].append(
                    np.einsum(rho_SU_0_bmps[dp_idx][jj], [0, 1, 2, 2], [0, 1]))
            rho_SU_0_bmps_single[dp_idx].append(
                np.einsum(rho_SU_0_bmps[dp_idx][jj], [1, 1, 2, 3], [2, 3]))
    return rho_SU_0_bmps_single, rho_SU, rho_BP
Exemplo n.º 8
0
        ATD_tot = []
        BP_iters = []
        tSU_iters = []
        print('\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=')
        print('|               D = {}               |'.format(D_max))
        print('=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=')

        for e in range(num_experiments):

            print('experiment = ', e)
            # draw some random PEPS Tensor Network
            tensors, weights = smg.randomTensornetGenerator(smat, d, D_max)
            interactionConstants = -np.random.rand(m)

            BPU_graph = defg.defg()
            BPU_graph = su.TNtoDEFGtransform(BPU_graph, tensors, weights, smat)
            BPU_graph.sumProduct(t_max,
                                 epsilon,
                                 dumping,
                                 initializeMessages=1,
                                 printTime=0,
                                 RDMconvergence=0)
            counter = 0
            for dt in timeStep:
                for i in range(BPU_iterations):
                    counter += 1
                    if i % 45 == 0:
                        print('i, dt = ', i, dt)
                    weights_prev = cp.deepcopy(weights)
                    tensors_next, weights_next = su.simpleUpdate(
                        tensors,
Exemplo n.º 9
0
Sy = 0.5 * Y
Sx = 0.5 * X
Opi = [Sx, Sy, Sz]
Opj = [Sx, Sy, Sz]
Op_field = np.eye(d)

for e in range(num_experiments):
    # draw some random PEPS Tensor Network
    tensors, weights = smg.randomTensornetGenerator(smat, d, bond_dimension)
    # draw some random uniform(-1, 0) ATH couplings
    interactionConstants = -np.random.rand(m)
    #interactionConstants = [-1] * m

    # calculate the BP fixed point messages and the two-body RDMs
    BPU_graph = defg.defg()
    BPU_graph = su.TNtoDEFGtransform(BPU_graph, tensors, weights, smat)
    BPU_graph.sumProduct(t_max,
                         epsilon,
                         dumping,
                         initializeMessages=1,
                         printTime=0,
                         RDMconvergence=0)
    BP_rdm = []
    for j in range(m):
        BP_rdm.append(
            tsu.BPdoubleSiteRDM1(j, cp.deepcopy(tensors), cp.deepcopy(weights),
                                 smat, cp.deepcopy(BPU_graph.messages_n2f)))

    # run BPU until convergence criteria is met
    # the convergence criteria is taken to be an upper bound over the Averaged Trace Distance (ATD) Between
    # two consecutive BPU iterations two body RDMs --- ATD < 1e-6
Exemplo n.º 10
0
    tSU_iters = []
    print('\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=')
    print('|               D = {}               |'.format(D_max))
    print('=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=')

    for e in range(num_experiments):
        #if e % 10 == 0:
        print(e)

        # draw some random PEPS Tensor Network
        tensors, weights = smg.randomTensornetGenerator(smat, d, D_max)
        BP_tensors, BP_weights = cp.deepcopy(tensors), cp.deepcopy(weights)

        # constructing the dual double-edge factor graph and run a single BP iteration
        graph = defg.defg()
        graph = su.TNtoDEFGtransform(graph, BP_tensors, BP_weights, smat)
        graph.sumProduct(1,
                         epsilon,
                         dumping,
                         initializeMessages=1,
                         printTime=0,
                         RDMconvergence=0)
        BP_rdm = []
        for j in range(m):
            BP_rdm.append(
                tsu.BPdoubleSiteRDM1(j, BP_tensors, BP_weights, smat,
                                     cp.deepcopy(graph.messages_n2f)))

        # run BP and calculate two body rdms between two consecutive BP iterations
        for t in range(t_max):
            graph.sumProduct(1,
Exemplo n.º 11
0
                                                                 weights_tsu,
                                                                 smat,
                                                                 D_max)
    error = np.sum(np.abs(np.asarray(weights_tsu) - np.asarray(weights_tsu_next)))
    errors_tsu.append(error)
    if error < dw:
        print('The error is: {}'.format(error))
        tensors_tsu = tensors_tsu_next
        weights_tsu = weights_tsu_next
        break
    tensors_tsu = tensors_tsu_next
    weights_tsu = weights_tsu_next

# constructing the dual double-edge factor graph
graph = defg.defg()
graph = su.TNtoDEFGtransform(graph, tensors_tsu, weights_tsu, smat)
s = time.time()
graph.sumProduct(t_max, epsilon, dumping, printTime=1)
tot = time.time() - s
graph.calculateFactorsBeliefs()


tSU_1rdm = []
for i in range(n):
    tSU_1rdm.append(su.singleSiteRDM(i, tensors_tsu, weights_tsu, smat))

plt.figure()
plt.plot(range(len(errors_tsu)), errors_tsu)
plt.show()

Exemplo n.º 12
0
'''
for i in range(iterations):
    tensors_tsu_next, weights_tsu_next = tsu.trivialsimpleUpdate(tensors_tsu, weights_tsu, smat, D_max)
    error = np.sum(np.abs(np.asarray(weights_tsu) - np.asarray(weights_tsu_next)))
    errors_tsu.append(error)
    if error < dw:
        print('The error is: {}'.format(error))
        tensors_tsu = tensors_tsu_next
        weights_tsu = weights_tsu_next
        break
    tensors_tsu = tensors_tsu_next
    weights_tsu = weights_tsu_next
'''
# constructing the dual double-edge factor graph
pre_graph = defg.defg()
pre_graph = su.TNtoDEFGtransform(pre_graph, tensors_su, weights_su, smat)
s = time.time()
pre_graph.sumProduct(t_max, epsilon, dumping, printTime=1, RDMconvergence=0)
pre_tot = time.time() - s
pre_graph.calculateFactorsBeliefs()

for i in range(iterations):
    tensors_su_next, weights_su_next = su.simpleUpdate(tensors_su,
                                                       weights_su,
                                                       timeStep,
                                                       interactionConstants,
                                                       0,
                                                       Opi,
                                                       Opj,
                                                       Op_field,
                                                       smat,
Opj = [Sx, Sy, Sz]
Op_field = np.eye(d)
timeStep = 0.1
interactionConstants = [-1] * m
dE = 1e-5
flag = 1
counter = 0
energyPerSite = []
magZ0 = []

# run simple update
tensorsNew, lambdasNew = cp.deepcopy(tensors), cp.deepcopy(lambdas)
while flag:
    energyPerSite.append(
        np.real(
            su.energyPerSite(tensorsNew, lambdasNew, structureMat,
                             interactionConstants, 0, Opi, Opj, Op_field)))
    magZ0.append(
        su.singleSiteExpectation(0, tensorsNew, lambdasNew, structureMat, Sz))
    tensorsNew, lambdasNew = su.simpleUpdate(
        tensors=tensorsNew,
        weights=lambdasNew,
        timeStep=timeStep,
        interactionConst=interactionConstants,
        fieldConst=0,
        iOperators=Opi,
        jOperators=Opj,
        fieldOperators=Op_field,
        smat=structureMat,
        Dmax=D,
        type='SU')
    if counter >= 1:
def randomPEPSmainFunction():

    #np.random.seed(seed=9)

    N, M = 4, 4
    bc = 'open'
    dE = 1e-5
    t_max = 200
    dumping = 0.2
    epsilon = 1e-5
    D_max = [3]
    mu = -1
    sigma = 0
    Jk = np.random.normal(mu, sigma, np.int((N - 1) * M + (M - 1) * N))
    dt = [0.5, 0.1, 0.05, 0.01, 0.005]
    iterations = 10
    Dp = [16, 32]
    d = 2

    smat, imat = tnf.finitePEPSobcStructureMatrixGenerator(N, M)
    BP_data = []
    SU_data = []

    for D in D_max:
        b, time_su = hmf.RandomPEPS_SU(N, M, Jk, dE, D, bc, dt, iterations)
        TT0, LL0 = b[0], b[1]
        a, time_bp = hmf.RandomPEPS_BP(N, M, Jk, dE, D, t_max, epsilon,
                                       dumping, bc, dt, iterations, [TT0, LL0])
        BP_data.append(a)
        SU_data.append(b)

    rho_SU = []
    rho_SU_0_bmps = []
    rho_SU_0_bmps_single = []

    data_bp = BP_data
    data_su = SU_data

    indices = []
    counter = 0
    counter2 = N * (M - 1) - 1 + (N - 1) * (M - 1) + 1
    counter3 = 0
    while counter3 < N:
        indices += range(counter, counter + M - 1)
        indices.append(counter2)
        counter += (M - 1)
        counter2 += 1
        counter3 += 1
    indices.pop()

    print('calc_rdms')
    for ii in range(len(D_max)):

        graph = data_bp[ii]
        TT_SU_0, LL_SU_0, TT_SU, LL_SU = data_su[ii]
        TT_SU_0_bmps = cp.deepcopy(TT_SU_0)

        #
        ######### CALCULATING REDUCED DENSITY MATRICES  ########
        #

        for i in range(len(TT_SU)):
            rho_SU.append(BP.singleSiteRDM(i, TT_SU, LL_SU, smat))
        rho_BP = graph.calculateRDMSfromFactorBeliefs()

        TT_SU_0_bmps = BP.absorbAllTensorNetWeights(TT_SU_0_bmps, LL_SU_0,
                                                    smat)
        TT_SU_0_bmps = tnf.PEPS_OBC_broadcast_to_Itai(TT_SU_0_bmps, [N, M], d,
                                                      D_max[ii])
        SU_0_peps = bmps.peps(N, M)
        for t, T in enumerate(TT_SU_0_bmps):
            i, j = np.unravel_index(t, [N, M])
            SU_0_peps.set_site(T, i, j)
        for dp_idx, dp in enumerate(Dp):
            print('Dp:', dp)
            rho_SU_0_bmps.append(bmps.calculate_PEPS_2RDM(SU_0_peps, dp))
            rho_SU_0_bmps_single.append([])
            for jj in indices:
                rho_SU_0_bmps_single[dp_idx].append(
                    np.einsum(rho_SU_0_bmps[dp_idx][jj], [0, 1, 2, 2], [0, 1]))
            rho_SU_0_bmps_single[dp_idx].append(
                np.einsum(rho_SU_0_bmps[dp_idx][jj], [1, 1, 2, 3], [2, 3]))

    return rho_SU_0_bmps_single, rho_SU, rho_BP