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
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
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)
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
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
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))
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
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
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