Esempio n. 1
0
def prepare_magnetized_state(tensor, spin):
    """Returns magnetized state (i.e. polarized state) |0> = (1 1 1)."""

    sx, sy, sz, _ = constants.get_spin_operators(spin)

    """
    # step = 100.
    step = 10.
    op = construct_ite_operator(- step, sx + sy + sz)
    i = 0
    while psi_zero_test(tensor, spin) > 1.E-15:
        tensor = np.tensordot(op, tensor, axes=(1, 0))
        # tensor = tensor / math.sqrt(np.real(complex_inner_product(tensor)))
        tensor = tensor / linalg.norm(tensor)
        if i % 10 == 0:
            print(i, psi_zero_test(tensor, spin))
        i += 1
    print(i, psi_zero_test(tensor, spin))
    """

    _, v = linalg.eigh(-(sx + sy + sz))
    for i, x in enumerate(v[:, 0]):
        tensor[i][0][0][0] = x

    return tensor
Esempio n. 2
0
def construct_kitaev_hamiltonian(h, spin, k=1.):
    """Returns list of two-site Hamiltonian in [x, y, z]-direction for Kitaev model"""

    sx, sy, sz, one = constants.get_spin_operators(spin)
    hamiltonian = - k * np.array([np.kron(sx, sx), np.kron(sy, sy), np.kron(sz, sz)])
    hamiltonian -= h * (np.kron(sx, one) + np.kron(one, sx) +
                        np.kron(sy, one) + np.kron(one, sy) +
                        np.kron(sz, one) + np.kron(one, sz)) / (3 * math.sqrt(3))
    return hamiltonian
Esempio n. 3
0
def psi_zero_test(psi, spin):
    """Returns <psi|(sx + sy + sz)|psi> - 1/sqrt(3).

    Note: For magnetized state, we have <psi|(sx + sy + sz)|psi> = 1/sqrt(3).
    """

    sx, sy, sz, _ = constants.get_spin_operators(spin)
    sigmas = sx, sy, sz
    factor = {"1/2": 1., "1": 1., "3/2": 3 / 2, "2": 2., "5/2": 5 / 2, "3": 3.}[spin]
    return sum(abs(psi_sigma_psi(psi, s) - 1 / math.sqrt(3) * factor) for s in sigmas)
Esempio n. 4
0
def construct_ising_hamiltonian(h, spin, k=1.):
    """
    Returns list of two-site Hamiltonian in [x, y, z]-direction for transverse-field Ising model.

    Notice that the same Hamiltonian term is used in all three directions
    in order to achieve compatibility with the rest of the code.

    """

    sx, sy, sz, one = constants.get_spin_operators(spin)
    hamiltonian = - k * np.kron(sx, sx) - h * (np.kron(sz, one) + np.kron(one, sz)) / 2
    return np.array([hamiltonian, hamiltonian, hamiltonian]) / 2
Esempio n. 5
0
def construct_heisenberg_hamiltonian(h, spin, k=1.):
    """
    Returns list of two-site Hamiltonian in [x, y, z]-direction for Heisenberg model.

    Notice that the same Hamiltonian term is used in all three directions
    in order to achieve compatibility with the rest of the code.

    """

    sx, sy, sz, one = constants.get_spin_operators(spin)
    hamiltonian = k * (np.kron(sx, sx) + np.kron(sy, sy) + np.kron(sz, sz))
    hamiltonian += h * (np.kron(sz, one) + np.kron(one, sz)) / 3
    return np.array([hamiltonian, hamiltonian, hamiltonian]) / 2
Esempio n. 6
0
    def test_get_spin_operators(self):

        spin_to_ops = {
            '1/2': (constants.sx12, constants.sy12, constants.sz12, np.eye(2)),
            '1': (constants.SX1, constants.SY1, constants.SZ1, np.eye(3)),
            '3/2': (constants.sx32, constants.sy32, constants.sz32, np.eye(4)),
            '2': (constants.SX2, constants.SY2, constants.SZ2, np.eye(5)),
            '5/2': (constants.sx52, constants.sy52, constants.sz52, np.eye(6)),
            '3': (constants.SX3, constants.SY3, constants.SZ3, np.eye(7))
        }

        for spin in ('1/2', '1', '3/2', '2', '5/2', '3'):
            for o1, o2 in zip(constants.get_spin_operators(spin),
                              spin_to_ops[spin]):
                self.assertTrue(np.allclose(o1, o2, atol=1.E-16))
Esempio n. 7
0
def dimer_gas_operator(spin, phi):
    """Returns dimer gas operator (or variational ansatz) R for spin=1/2 or spin=1 Kitaev model."""

    zeta = np.zeros((2, 2, 2), dtype=complex)  # tau_tensor_{i j k}

    """
    if spin == "1":
        zeta[0][0][0] = math.cos(phi)
        zeta[1][0][0] = zeta[0][1][0] = zeta[0][0][1] = math.sin(phi)
    elif spin == "1/2":
        # Dimer Gas:
        # zeta[0][0][0] = 1
        # zeta[1][0][0] = zeta[0][1][0] = zeta[0][0][1] = phi
        # Variational Ansatz:
        zeta[0][0][0] = math.cos(phi)
        zeta[1][0][0] = zeta[0][1][0] = zeta[0][0][1] = math.sin(phi)
    """

    zeta[0][0][0] = math.cos(phi)
    zeta[1][0][0] = zeta[0][1][0] = zeta[0][0][1] = math.sin(phi)

    sx, sy, sz, one = constants.get_spin_operators(spin)
    d = one.shape[0]
    R = np.zeros((d, d, 2, 2, 2), dtype=complex)  # R_DG_{s s' i j k}

    p = 1
    """
    if spin == "1":
        p = 1
    elif spin == "1/2":
        p = 0
    """

    for i in range(2):
        for j in range(2):
            for k in range(2):
                temp = np.eye(d)
                if i == p:
                    temp = temp @ sx
                if j == p:
                    temp = temp @ sy
                if k == p:
                    temp = temp @ sz
                for s in range(d):
                    for sp in range(d):
                        R[s][sp][i][j][k] = zeta[i][j][k] * temp[s][sp]
    return R
Esempio n. 8
0
def init_weight_impurity_ctmrg(ten_a, ten_b, lam, model):
    """Returns impurity weight for energy calculation by CTMRG."""

    # d = ten_a.shape[0]  # physical dimension
    spin = constants.physical_dimension_to_spin(ten_a.shape[0])

    sx, sy, sz, _ = constants.get_spin_operators(spin)
    if model == "Heisenberg":
        op = (sx / 2, sy / 2, sz / 2)
    if model == "Kitaev":
        op = 1j * sx

    a_imp = create_double_impurity(ten_a, lam, op)
    b_imp = create_double_impurity(ten_b, lam, op)

    if isinstance(a_imp, list):
        w_imp = functools.reduce(lambda x, y: x + y,
                                 (np.tensordot(a, b, axes=(0, 0))
                                  for a, b in zip(a_imp, b_imp)))
    else:
        w_imp = np.tensordot(a_imp, b_imp, axes=(0, 0))

    return w_imp
Esempio n. 9
0
def coarse_graining_procedure(tensor_a,
                              tensor_b,
                              lambdas,
                              dim_cut,
                              model="Kitaev"):
    """
    Returns the converged energy given the quantum state (tensor_a, tensor_b) for Kitaev model and
    prints log of the convergence wrt iterative steps of coarse-graining.
    """

    # dim_cut = D * D
    # d = tensor_a.shape[0]  # physical dimension
    spin = constants.physical_dimension_to_spin(tensor_a.shape[0])

    # norm_a = np.max(np.abs(tensor_a))
    # norm_b = np.max(np.abs(tensor_b))
    # tensor_a /= norm_a
    # tensor_b /= norm_b

    double_tensor_a = create_double_tensor(tensor_a, lambdas)
    double_tensor_b = create_double_tensor(tensor_b, lambdas)

    print('double_tensor_a.shape', double_tensor_a.shape)
    print('double_tensor_b.shape', double_tensor_b.shape)

    # print('double_tensor_a', double_tensor_a)
    # print('double_tensor_b', double_tensor_b)
    """
    dimp_ten_a_init = create_double_impurity(tensor_a, lambdas)  # x-direction
    dimp_ten_b_init = create_double_impurity(tensor_b, lambdas)  # x-direction
    """

    sx, sy, sz, _ = constants.get_spin_operators(spin)

    double_impurity_tensors = []  # used for calculating energy
    for op in (sx, sy, sz):
        a = create_double_impurity(tensor_a, lambdas, op)
        b = create_double_impurity(tensor_b, lambdas, op)
        # tensor_a = np.transpose(tensor_a, (0, 2, 3, 1))
        # tensor_b = np.transpose(tensor_b, (0, 2, 3, 1))
        # lambdas = lambdas[1:] + [lambdas[0]]
        double_impurity_tensors.append([a, b])

    # dimp_ten_a_mag = copy.deepcopy(double_impurity_tensors[0][0])
    # dimp_ten_b_mag = copy.deepcopy(double_tensor_b)

    double_impurity_6ring = [
        None
    ] * 6  # A, B, C, D, E, F - double impurity tensors

    spin_rotation_operators = None
    """
    if spin == "1/2":
        spin_rotation_operators = (sx, sy, sz)
    elif spin == '3/2' or spin == '5/2':
        spin_rotation_operators = tuple(map(lambda x: -1j * linalg.expm(1j * math.pi * x), (sx, sy, sz)))
    elif spin == "1" or spin == '2' or spin == '3':
        spin_rotation_operators = tuple(map(lambda x: linalg.expm(1j * math.pi * x), (sx, sy, sz)))
    """

    if spin == "1/2":
        spin_rotation_operators = (sx, sy, sz)
    elif '/' in spin:
        spin_rotation_operators = tuple(
            map(lambda x: -1j * linalg.expm(1j * math.pi * x), (sx, sy, sz)))
    else:
        spin_rotation_operators = tuple(
            map(lambda x: linalg.expm(1j * math.pi * x), (sx, sy, sz)))
    """
    if spin == "1":
        spin_rotation_operators = (constants.UZ, constants.UY, constants.UX)
    """

    tensors = (tensor_a, tensor_b)
    for i in range(
            6):  # impurity_6_ring initialization used for flux calculation
        double_impurity_6ring[i] = create_double_impurity(
            tensors[i % 2], lambdas, spin_rotation_operators[i % 3])
    """
    w_horizontal = calculate_global_flux_horizontal(tensor_a, tensor_b, lambdas, True, False)
    print('global flux w_horizontal = ', w_horizontal)
    w_vertical = calculate_global_flux_vertical(tensor_a, tensor_b, lambdas, False, True)
    print('global flux w_vertical = ', w_vertical)
    """

    # operator = (sx / 2, sy / 2, sz / 2)  # operators for Heisenberg model energy calculation
    # operator = operators[0] * 2  # operators for Kitaev model energy calculation

    # impurity_6_ring initialization used for energy calculation
    # double_impurity_6ring[0] = create_double_impurity(tensor_a, lambdas, sx)  # A
    # double_impurity_6ring[1] = create_double_impurity(tensor_b, lambdas, sx)  # B
    # double_impurity_6ring[2] = copy.deepcopy(double_tensor_a)  # C
    # double_impurity_6ring[3] = copy.deepcopy(double_tensor_b)  # D
    # double_impurity_6ring[4] = copy.deepcopy(double_tensor_a)  # E
    # double_impurity_6ring[5] = copy.deepcopy(double_tensor_b)  # F

    # double_impurity_6ring_helper = [None] * 6  # A, B, C, D, E, F - double impurity tensors - helpers
    # for i in range(6):
    #    double_impurity_6ring_helper[i] = create_double_impurity(tensors[i % 2], lambdas, np.eye(d))

    # dimp_ten_a = copy.deepcopy(double_impurity_tensors[0][0])
    # create_double_impurity(tensor_a, lambdas, constants.SX)
    # dimp_ten_b = copy.deepcopy(double_impurity_tensors[0][1])
    # create_double_impurity(tensor_b, lambdas, constants.SX)

    if model == "Heisenberg":
        operator = (sx / 2, sy / 2, sz / 2)
    if model == "Kitaev":
        operator = 1j * sx

    dimp_ten_a = create_double_impurity(tensor_a, lambdas, operator)
    dimp_ten_b = create_double_impurity(tensor_b, lambdas, operator)

    tensor_a, tensor_b, lambdas = None, None, None

    # norm = partition_function(*double_impurity_6ring_helper)

    ################################################################

    if model != "Heisenberg":

        ten_a = ten_c = ten_e = double_tensor_a
        ten_b = ten_d = ten_f = double_tensor_b
        norm = partition_function(ten_a, ten_b, ten_c, ten_d, ten_e, ten_f)

        ten_a = ten_c = ten_e = double_tensor_a
        ten_b = ten_d = ten_f = double_tensor_b
        ten_a = dimp_ten_a
        ten_b = dimp_ten_b
        measurement = partition_function(ten_a, ten_b, ten_c, ten_d, ten_e,
                                         ten_f)

        # measurement1 = partition_function(*double_impurity_6ring)
        print('norm', norm)
        # print('measurement', measurement)
        # print('flux', measurement / norm)
        print('energy', 1.5 * measurement / norm)

        # impurity_plaquette = create_plaquette(*double_impurity_6ring)  # {x xx y yy z zz}
        # measurement2 = np.einsum('x x y y z z->', impurity_plaquette)
        # print('measurement12', measurement1)
        # return measurement1 / norm, 0
        # return measurement2 / norm, 0
        # return measurement / norm, 0

        energy_six_directions(double_tensor_a,
                              double_tensor_b,
                              double_impurity_tensors,
                              num_of_iter=0)

        # o = np.tensordot(dimp_ten_a, dimp_ten_b, axes=([0, 1, 2], [0, 1, 2]))
        # o = np.tensordot(double_impurity_tensors[0][0], double_impurity_tensors[0][1], axes=([0, 1, 2], [0, 1, 2]))
        # norm = np.tensordot(double_tensor_a, double_tensor_b, axes=([0, 1, 2], [0, 1, 2]))
        # norm = partition_function(*double_impurity_6ring_helper)
        # print('partition function', norm)

    ################################################################

    energy = 1
    energy_mem = -1
    num_of_iter = 0
    num_of_iter += 1

    # for _ in range(100):
    while abs(energy - energy_mem) > 1.E-10:

        # print(double_tensor_a.shape)
        # print(double_tensor_b.shape)
        # print(dimp_ten_a[2].shape)
        # print(dimp_ten_b[2].shape)

        deformed_tensors = create_deformed_tensors(double_tensor_a,
                                                   double_tensor_b, dim_cut)

        ###########################################
        """
        deformed_12ring = create_deformed_12ring(double_impurity_6ring, double_tensor_a, double_tensor_b, dim_cut)
        double_impurity_6ring = update_6ring(deformed_12ring, deformed_tensors)

        deformed_12ring_helper = create_deformed_12ring(double_impurity_6ring_helper, double_tensor_a, double_tensor_b, dim_cut)
        double_impurity_6ring_helper = update_6ring(deformed_12ring_helper, deformed_tensors)
        """

        ###########################################

        # impurity update is here

        # dimp_sx_a_mag, dimp_sx_b_mag, _ = deform_and_renorm_impurity(dimp_ten_a_mag, dimp_ten_b_mag, dim_cut)

        deformed_imp_tensors = create_deformed_tensors(
            *zip(*double_impurity_tensors), dim_cut)

        # dimp_ten_a_mag = update_double_tensor(dimp_sx_a_mag, deformed_tensors[1][0], deformed_tensors[2][0])
        # dimp_ten_b_mag = update_double_tensor(dimp_sx_b_mag, deformed_tensors[1][1], deformed_tensors[2][1])

        # dimp_sx_a, dimp_sx_b, _ = \
        # deform_and_renorm_impurity(double_impurity_tensors[0][0], double_impurity_tensors[0][1], dim_cut)

        # dimp_sx_a, dimp_sx_b, _ = deform_and_renorm_impurity(dimp_ten_a, dimp_ten_b, dim_cut)
        # dimp_ten_a = update_double_tensor(dimp_sx_a, deformed_tensors[1][0], deformed_tensors[2][0])
        # dimp_ten_b = update_double_tensor(dimp_sx_b, deformed_tensors[1][1], deformed_tensors[2][1])

        double_impurity_tensors[0][0] = \
            update_double_tensor(deformed_imp_tensors[0][0], deformed_tensors[1][0], deformed_tensors[2][0])

        double_impurity_tensors[0][1] = \
            update_double_tensor(deformed_imp_tensors[0][1], deformed_tensors[1][1], deformed_tensors[2][1])

        double_impurity_tensors[1][0] = \
            update_double_tensor(deformed_tensors[0][0], deformed_imp_tensors[1][0], deformed_tensors[2][0])
        double_impurity_tensors[1][1] = \
            update_double_tensor(deformed_tensors[0][1], deformed_imp_tensors[1][1], deformed_tensors[2][1])

        double_impurity_tensors[2][0] = \
            update_double_tensor(deformed_tensors[0][0], deformed_tensors[1][0], deformed_imp_tensors[2][0])
        double_impurity_tensors[2][1] = \
            update_double_tensor(deformed_tensors[0][1], deformed_tensors[1][1], deformed_imp_tensors[2][1])

        ###########################################

        double_tensor_a = update_double_tensor(*(x[0]
                                                 for x in deformed_tensors))
        norm_a = np.max(np.abs(double_tensor_a))
        double_tensor_b = update_double_tensor(*(x[1]
                                                 for x in deformed_tensors))
        norm_b = np.max(np.abs(double_tensor_b))

        # norm_a = norm_b = max(norm_a, norm_b)

        print('norm_a', norm_a)
        print('norm_b', norm_b)

        ###########################################

        double_tensor_a /= norm_a
        double_tensor_b /= norm_b

        ###########################################

        # rot_y = rot_neg_z = lambda ten3: np.transpose(ten3, (1, 2, 0))  # rotate by 1
        # tensor_norms = (norm_a, norm_b)
        """
        for position in range(6):
            double_impurity_6ring[position] /= tensor_norms[position % 2]
            double_impurity_6ring[position] = rot_y(double_impurity_6ring[position])

            double_impurity_6ring_helper[position] /= tensor_norms[position % 2]
            double_impurity_6ring_helper[position] = rot_y(double_impurity_6ring_helper[position])
        """

        ###########################################

        double_impurity_tensors[0][0] /= norm_a
        double_impurity_tensors[0][1] /= norm_b
        double_impurity_tensors[1][0] /= norm_a
        double_impurity_tensors[1][1] /= norm_b
        double_impurity_tensors[2][0] /= norm_a
        double_impurity_tensors[2][1] /= norm_b

        ###########################################

        # dimp_ten_a /= norm_a
        # dimp_ten_b /= norm_b

        # dimp_ten_a_mag /= norm_a
        # dimp_ten_b_mag /= norm_b

        ###########################################

        # energy calculation

        # o = np.tensordot(dimp_ten_a, dimp_ten_b, axes=([0, 1, 2], [0, 1, 2]))
        # o = np.tensordot(double_impurity_tensors[0][0], double_impurity_tensors[0][1], axes=([0, 1, 2], [0, 1, 2]))
        # norm = np.tensordot(double_tensor_a, double_tensor_b, axes=([0, 1, 2], [0, 1, 2]))

        energy_list = energy_six_directions(double_tensor_a, double_tensor_b,
                                            double_impurity_tensors,
                                            num_of_iter)
        ox1, ox2, oy1, oy2, oz1, oz2 = energy_list

        # print('Expect. iter:', num_of_iter, 'energy:', - (O / norm) / 4)

        # energy_6ring = partition_function(*double_impurity_6ring) / norm
        # print('energy_6ring', - 3 * energy_6ring / 2)
        # print('flux', energy_6ring)

        energy_mem = energy
        # energy = energy_6ring
        energy = ox1
        # energy = (ox1 + ox2 + oy1 + oy2 + oz1 + oz2) / (6 * norm)
        # energy = O / norm
        print('energy', -3 * energy / 2)

        # Magnetization calculation at position 0
        """
        ten_a = ten_c = ten_e = double_tensor_a
        ten_b = ten_d = ten_f = double_tensor_b
        ten_a = dimp_ten_a_mag
        ten_b = dimp_ten_b_mag
        sx_0 = partition_function(ten_a, ten_b, ten_c, ten_d, ten_e, ten_f)
        """
        # print('<S>', sx_0 / norm)

        num_of_iter += 1

    # return energy, sx_0 / norm, num_of_iter
    return energy, abs(energy - energy_mem), num_of_iter