def get_T(pars): # We always get the invariant tensor here, and cast it to the # non-invariant if needed. This gets around the silly fact that the # basis of the original tensor depends on symmetry_tensors, # something that should be fixed. T = tensordispenser.get_tensor(pars, iter_count=0, symmetry_tensors=True)[0] if not pars["symmetry_tensors"]: T = Tensor.from_ndarray(T.to_ndarray()) log_fact = 0 Fs = [] Ns = [] cum = T for i in range(1, pars["n_normalization"]): cum = toolbox.contract2x2(cum) log_fact *= 4 m = cum.abs().max() if m != 0: cum /= m log_fact += np.log(m) N = 4**i F = np.log(scon(cum, [1, 2, 1, 2]).value()) + log_fact Fs.append(F) Ns.append(N) A, B = np.polyfit(Ns[pars["n_discard"]:], Fs[pars["n_discard"]:], 1) T /= np.exp(A) return T
def get_KW_unitary(pars): eye = np.eye(2, dtype=np.complex_) CZ = Csigma_np("z") U = scon( (CZ, R_np(np.pi / 4, 'z'), R_np(np.pi / 4, 'x'), R_np(np.pi / 4, 'y')), ([-1, -2, 5, 6], [-3, 5], [3, 6], [-4, 3])) u = symmetry_bases["ising"] u_dg = u.T.conjugate() U = scon((U, u, u_dg, u_dg, u), ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4])) U *= -1j if pars["symmetry_tensors"]: U = TensorZ2.from_ndarray(U, shape=[[1, 1]] * 4, qhape=[[0, 1]] * 4, dirs=[1, 1, -1, -1]) else: U = Tensor.from_ndarray(U, dirs=[1, 1, 1, -1, -1, -1]) return U
def get_initial_tensor(pars, **kwargs): if kwargs: pars = pars.copy() pars.update(kwargs) model_name = pars["model"].strip().lower() ham = hamiltonians[model_name](pars) boltz = np.exp(-pars["beta"] * ham) T_0 = np.einsum('ab,bc,cd,da->abcd', boltz, boltz, boltz, boltz) if pars["symmetry_tensors"]: u = symmetry_bases[model_name] u_dg = u.T.conjugate() T_0 = scon((T_0, u, u, u_dg, u_dg), ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4])) cls, dim, qim = symmetry_classes_dims_qims[model_name] T_0 = cls.from_ndarray(T_0, shape=[dim] * 4, qhape=[qim] * 4, dirs=[1, 1, -1, -1]) else: T_0 = Tensor.from_ndarray(T_0) return T_0
def get_D(t, pars): ham = (-pars["J"] * np.array([[1, -1], [-1, 1]], dtype=pars["dtype"]) + pars["H"] * np.array([[-1, 0], [0, 1]], dtype=pars["dtype"])) boltz = np.exp(-pars["beta"] * ham) ham_g = -pars["g"] * pars["J"] * np.array([[1, -1], [-1, 1]], dtype=pars["dtype"]) boltz_g = np.exp(-pars["beta"] * ham_g) ones = np.ones((2, 2), dtype=pars["dtype"]) D = np.einsum('ab,bc,cd,da->abcd', boltz, boltz_g, boltz_g, boltz) u = np.array([[1, 1], [1, -1]]) / np.sqrt(2) u_dg = u.T.conjugate() D = scon((D, u, u, u_dg, u_dg), ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4])) if pars["symmetry_tensors"]: D = TensorZ2.from_ndarray(D, shape=[[1, 1]] * 4, qhape=[[0, 1]] * 4, dirs=[1, 1, -1, -1]) else: D = Tensor.from_ndarray(D) return D
def get_KW_tensor(pars): eye = np.eye(2, dtype=np.complex_) ham = hamiltonians["ising"](pars) B = np.exp(-pars["beta"] * ham) H = np.array([[1, 1], [1, -1]], dtype=np.complex_) / np.sqrt(2) y_trigged = np.ndarray((2, 2, 2), dtype=np.complex_) y_trigged[:, :, 0] = eye y_trigged[:, :, 1] = sigma_np('y') D_sigma = np.sqrt(2) * np.einsum('ab,abi,ic,ad,adk,kc->abcd', B, y_trigged, H, B, y_trigged.conjugate(), H) u = symmetry_bases["ising"] u_dg = u.T.conjugate() D_sigma = scon((D_sigma, u, u, u_dg, u_dg), ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4])) if pars["symmetry_tensors"]: D_sigma = TensorZ2.from_ndarray(D_sigma, shape=[[1, 1]] * 4, qhape=[[0, 1]] * 4, dirs=[1, 1, -1, -1]) else: D_sigma = Tensor.from_ndarray(D_sigma, dirs=[1, 1, -1, -1]) return D_sigma
def generate_initial_tensors(pars): ham = (-pars["J"] * np.array([[1, -1], [-1, 1]], dtype=pars["dtype"]) + pars["H"] * np.array([[-1, 0], [0, 1]], dtype=pars["dtype"])) boltz = np.exp(-pars["beta"] * ham) ham_g = -pars["g"] * pars["J"] * np.array([[1, -1], [-1, 1]], dtype=pars["dtype"]) boltz_g = np.exp(-pars["beta"] * ham_g) ones = np.ones((2, 2), dtype=pars["dtype"]) D = np.einsum('ab,bc,cd,da->abcd', boltz, boltz_g, boltz_g, boltz) if pars["symmetry_tensors"]: u = np.array([[1, 1], [1, -1]]) / np.sqrt(2) u_dg = u.T.conjugate() D = scon((D, u, u, u_dg, u_dg), ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4])) D = TensorZ2.from_ndarray(D, shape=[[1, 1]] * 4, qhape=[[0, 1]] * 4, dirs=[1, 1, -1, -1]) else: D = Tensor.from_ndarray(D) T = initialtensors.get_initial_tensor(pars, iter_count=0) A_list = [D, T] log_fact_list = [0, 0] return A_list, log_fact_list
def get_cft_data(pars): T = get_T(pars) scaldims_by_alpha = {} if pars["do_momenta"]: momenta_by_alpha = {} if pars["do_eigenvectors"]: evects_by_alpha = {} for alpha in pars["defect_angles"]: print("Building the matrix to diagonalize.") T_first = get_T_first(T, pars, alpha=alpha) # Get the eigenvalues and their logarithms. block_width = pars["block_width"] n_dims_do = pars["n_dims_do"] if pars["do_momenta"]: translation = list(range(1, block_width)) + [0] else: translation = range(block_width) scon_list = [T_first] + [T] * (block_width - 1) index_list = [[block_width * 2, -101, 2, -1]] for i in range(2, block_width + 1): index_list += [[2 * i - 2, -100 - i, 2 * i, -(2 * i - 1)]] if pars["KW"] and pars["do_momenta"]: U = initialtensors.get_KW_unitary(pars) scon_list += [U] for l in index_list: l[0] += 2 l[2] += 2 l[3] += -2 index_list[0][3] *= -1 index_list[1][3] *= -1 U_indices = [3, 5, -1, -2] index_list.append(U_indices) if not pars["symmetry_tensors"]: # Cast to non-invariant tensors. scon_list = [ Tensor.from_ndarray(T.to_ndarray()) for T in scon_list ] hermitian = not pars["do_momenta"] res = scon_sparseeig(scon_list, index_list, translation, range(block_width), hermitian=hermitian, return_eigenvectors=pars["do_eigenvectors"], qnums_do=pars["qnums_do"], maxiter=500, tol=1e-8, k=pars["n_dims_do"]) if pars["do_eigenvectors"]: es, evects = res else: es = res # Convert es to complex for taking the log. es = es.astype(np.complex_, copy=False) # Log and scale the eigenvalues. block_width = pars["block_width"] if pars["KW"]: block_width -= 0.5 log_es = es.log() * block_width / (2 * np.pi) # Extract the central charge. if alpha == 0: if pars["KW"]: c = (log_es.real().max() + 0.0625) * 12 else: c = log_es.real().max() * 12 try: log_es -= c / 12 except NameError: raise ValueError("Need to provide 0 in defect_angles to be able " "to obtain the central charge.") log_es *= -1 scaldims = log_es.real() if (not pars["symmetry_tensors"]) and pars["sep_qnums"]: qnums = qnums_from_eigenvectors(evects, pars) scaldims = separate_vector_by_qnum(scaldims, qnums, pars) scaldims_by_alpha[alpha] = scaldims if pars["do_momenta"]: momenta = log_es.imag() if (not pars["symmetry_tensors"]) and pars["sep_qnums"]: momenta = separate_vector_by_qnum(momenta, qnums, pars) momenta_by_alpha[alpha] = momenta if pars["do_eigenvectors"]: evects_by_alpha[alpha] = evects ret_val = (scaldims_by_alpha, c) if pars["do_momenta"]: ret_val += (momenta_by_alpha, ) if pars["do_eigenvectors"]: ret_val += (evects_by_alpha, ) return ret_val
else: dirs2 = None T2 = rtensor(shape=shp2, qhape=qhp2, dirs=dirs2) T2_orig = T2.copy() T1_np = T1.to_ndarray() T2_np = T2.to_ndarray() T = T1.dot(T2, (i_list, j_list)) assert ((T1 == T1_orig).all()) assert ((T2 == T2_orig).all()) test_internal_consistency(T) i_list_compl = sorted(set(range(len(shp1))) - set(i_list)) j_list_compl = sorted(set(range(len(shp2))) - set(j_list)) product_shp = [shp1[i] for i in i_list_compl]\ + [shp2[j] for j in j_list_compl] if type(T) == Tensor: product_shp = Tensor.flatten_shape(product_shp) assert (T.shape == product_shp) T_np = np.tensordot(T1_np, T2_np, (i_list, j_list)) assert (np.allclose(T_np, T.to_ndarray())) # Products of non-invariant vectors. n1 = np.random.randint(1, 3) T1 = rtensor(n=n1, chilow=1, invar=(n1 != 1)) n2 = np.random.randint(1, 3) shp2 = rshape(n=n2, chilow=1) qhp2 = rqhape(shape=shp2) dirs2 = rdirs(shape=shp2) c2 = rcharge() shp2[0] = T1.shape[-1] if T1.qhape is not None: