def get_r6_1d_dressed_coupling_nn(V0, rc, L, ktrunc, bc, verbose=False): """ Return coupling list for the following "dressed-state" n-n interaction: V(r) = V0 / (r/r)^6 + 1 """ check_bc(bc) f = get_r6_dressed_interaction(V0, rc) return get_1d_r_coupling_nn(f, L, ktrunc, bc, verbose=verbose)
def get_min_dist(x1, x2, y1, y2, Lx, Ly, bc): check_bc(bc) if bc == 'periodic': dx = min_lin_dist_pbc(x2 - x1, Lx) dy = min_lin_dist_pbc(y2 - y1, Ly) else: dx = np.abs(x2 - x1) dy = np.abs(y2 - y1) return np.sqrt(dx**2 + dy**2)
def make_dressed_r6_1d(Delta, Omega, V0, Rc, ktrunc, basis, gamma=None, bc='periodic', dtype=np.float64, verbose=False): """ Returns quspin hamiltonian: H = -sum_i Delta_i n_i - sum_i (omega_i)/2) x_i + sum_(pairs ij) V_ij n_i n_j where V_ij = V0 / ( (r / Rc)^6 + 1) for a 1d lattice. gamma (optional, default None): a list of two single-site amplitude-decay rates, specifying upper and lower decay rates respectively. If a list of gamma values is specifed, a nonhermitian term -1j * (gamma[0]/2) * sum_i n_i - 1j * (gamma[1]/2) * sum_i (1-n_i) will be added to the hamiltonian ktrunc = integer, interaction truncation. H will include 1/r^6 interactions of the form shown above up to kth-nearest-neighbors If verbose=True: some info on hamiltonian construction is given. """ check_bc(bc) L = basis.L if not isinstance(basis, boson_basis_1d): raise TypeError("invalid basis type") if not (gamma is None): try: if len(gamma) != 2: raise ValueError("List of decay rates should have length 2.") except TypeError: raise TypeError("Gamma should be a list") check_herm = True if gamma is not None: vprint(verbose, "Decay provided. herm=false, dtype=complex") check_herm = False dtype = np.complex128 static = get_r6_1d_dressed_static(Delta, Omega, V0, Rc, L, ktrunc, gamma, bc, verbose=verbose) dynamic = [] return hamiltonian(static, dynamic, basis=basis, dtype=dtype, check_herm=check_herm)
def make_nnZ(n, Jn, Jx, coup_list, L, basis=None, bc='periodic', dtype=np.float64): """ return uniform 1d hamiltonian with interactions up to nth-nearest-neighbors. coup_list = list of couplings [V1, ..., Vn] such that each pair of sites (i, i+n) has an interaction term V_n n_i n_i+n, where n are the on-site density operators. The single-site hamiltonian is """ check_bc(bc) if basis is None: basis = get_hcb_basis(L) if not isinstance(basis, boson_basis_1d): raise TypeError( "this function is only implemented for hard-core bosons") static = get_nnZ_static_hcb(n, Jn, Jx, L, coup_list, bc=bc) dynamic = [] return hamiltonian(static, dynamic, basis=basis, dtype=np.float64)
def get_1d_r_coupling_nn(f, L, ktrunc, bc, verbose=False): """ Return coupling list [[J, i, i+k], ...] for n-n coupling in a boson model (n being the occupation operator) f = some function of r, the inter-site distance, which determines the coupling between sites i and i+r (independent of index i). The form of the corresponding Hamiltonian is H = sum (pairs i,j) f(|i-j|) ni nj the sum running over all distinct pairs. If an LxL hermitian matrix is input as f, the off-diagonal elements of that matrix will be used directly to construct the hamiltonian, ie H = sum (pairs ij) f_ij ni nj In that case, the truncation range will be ignored. ktrunc = defines the cutoff range for the potential f: sites separated by more than ktrunc will not interact (will not be included in the coupling list) """ check_bc(bc) if isinstance(f, np.ndarray): vprint("Direct coupling matrix provided. Truncation length ignored.") coupling_nn = get_coupling_from_matrix(L, f, verbose=verbose) else: vprint(verbose, "Scalar interaction provided. f(r) matrix will be constructed") #max number of couplings per site if bc == 'open': nc = min(ktrunc, L - 1) else: nc = min(ktrunc, L // 2) coup_list = np.empty(nc) if ktrunc >= L: print("Warning--interactions longer than L are discarded.") for i in range(1, nc + 1): v = f(i) if i == L / 2 and bc == 'periodic': #this bond will be overcounted in the final sum v = v / 2.0 coup_list[i - 1] = v coupling_nn = [] for i in range(nc): coupling_nn = coupling_nn + get_nth_order_coupling( coup_list[i], L, i + 1, bc) return coupling_nn
def make_kladder_symmetric_SPIN(Delta, Omega, V1, V2, k, L, basis=None, bc='periodic'): """ Returns the following hamiltonian: H = - Delta sum_i n_i - (Omega/2) sum_i X_i + V1 sum_e (nn)_e where the last term joins any two sites which are the same or adjacent rungs. Assumes periodic boundary conditions (in the sense that the last rung joins to the first) L = number of rungs k = width (number of sites) of each rung Site ordering: The index i of the individual sites always increases left-to-right. At the end of the ladder, it moves down one step and keeps increasing. For a example, for a 2-ladder of length 8 the sites are as follows: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 This is 'thread' ordering, as opposed to 'snake' ordering where sites i, i+1 are always adjacent. """ raise TypeError("deprecated") check_bc(bc) if bc == 'open': raise TypeError("Ladder with open BC's is not implemented!") if basis is None: print("Generating basis") basis = spin_basis_1d(k * L, pauli=True) #coupling strengths in the Pauli basis #special case, the next-nearest will overcount by factor 2 if L == 4: V2 = V2 / 2.0 Jx_pauli = -(Omega / 2.0) Jz_pauli = -Delta / 2.0 + (V1 / 4.0) * (3 * k - 1) + (V2 / 4.0) * 2 * k Jzz_pauli_1nn = V1 / 4.0 Jzz_pauli_2nn = V2 / 4.0 N = k * L coupling_x = get_site_coupling(Jx_pauli, N) coupling_z = get_site_coupling(Jz_pauli, N) #matrix which stores the thread-order labels site_labels = np.empty((k, L), dtype=int) for i in range(k): site_labels[i, :] = np.array(range(L)) + i * L #all terms proportional to V1, ie nearest-neighbor sites coupling_zz_1nn = [] for i in range(L): #this adds the interactions between sites on the same rung prs = get_all_pairs(site_labels[:, i]) coupling_zz_1nn += [[Jzz_pauli_1nn] + p for p in prs] #this adds the interactions between sites on neighboring rungs for j in range(k): coupling_zz_1nn += [[ Jzz_pauli_1nn, site_labels[j, i], site_labels[m, (i + 1) % L] ] for m in range(k)] #all terms proportional to V2, i.e. next-nearest-neighbor rungs coupling_zz_2nn = [] for i in range(L): for j in range(k): coupling_zz_2nn += [[ Jzz_pauli_2nn, site_labels[j, i], site_labels[m, (i + 2) % L] ] for m in range(k)] static = [["z", coupling_z], ["x", coupling_x], ["zz", coupling_zz_1nn + coupling_zz_2nn]] dynamic = [] return hamiltonian(static, dynamic, basis=basis)
def make_kladder_symmetric(Delta, Omega, V1, V2, k, L, basis=None, bc='periodic', dtype=np.float64): """ Returns the following hamiltonian: H = - Delta sum_i n_i - (Omega/2) sum_i X_i + V1 sum_e (nn)_e where the last term joins any two sites which are the same or adjacent rungs. Assumes periodic boundary conditions (in the sense that the last rung joins to the first) L = number of rungs k = width (number of sites) of each rung Site ordering: The index i of the individual sites always increases left-to-right. At the end of the ladder, it moves down one step and keeps increasing. For a example, for a 2-ladder of length 8 the sites are as follows: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 This is 'thread' ordering, as opposed to 'snake' ordering where sites i, i+1 are always adjacent. """ check_bc(bc) if bc == 'open': raise TypeError("Ladder with open BC's is not implemented!") if basis is None: print("Generating basis") basis = get_hcb_basis(k * L) if not (isinstance(basis, boson_basis_1d) or isinstance(basis, boson_basis_general)): raise TypeError("Only implemented for hcb basis") #special case, the next-nearest will overcount by factor 2 if L == 4: V2 = V2 / 2.0 Jx = -(Omega / 2.0) Jn = -Delta Jnn_nn1 = V1 Jnn_nn2 = V2 #total number of sites N = k * L coupling_x = get_site_coupling(Jx, N) coupling_n = get_site_coupling(Jn, N) #matrix which stores the thread-order labels site_labels = np.empty((k, L), dtype=int) for i in range(k): site_labels[i, :] = np.array(range(L)) + i * L #all terms proportional to V1, ie nearest-neighbor sites coupling_nn_nn1 = [] for i in range(L): #this adds the interactions between sites on the same rung prs = get_all_pairs(site_labels[:, i]) coupling_nn_nn1 += [[Jnn_nn1] + p for p in prs] #this adds the interactions between sites on neighboring rungs for j in range(k): coupling_nn_nn1 += [[ Jnn_nn1, site_labels[j, i], site_labels[m, (i + 1) % L] ] for m in range(k)] #all terms proportional to V2, i.e. next-nearest-neighbor rungs coupling_nn_nn2 = [] for i in range(L): for j in range(k): coupling_nn_nn2 += [[ Jnn_nn2, site_labels[j, i], site_labels[m, (i + 2) % L] ] for m in range(k)] static = [["n", coupling_n], ["+", coupling_x], ["-", coupling_x], ["nn", coupling_nn_nn1 + coupling_nn_nn2]] dynamic = [] return hamiltonian(static, dynamic, basis=basis, dtype=dtype)
def make_r6_1d(Delta, Omega, V, ktrunc, basis, gamma=None, bc='open', dtype=np.float64, verbose=False): """returns the hamiltonian operator for a 1d rydberg chain with laser parameters as input. HCB basis. H = -sum_i Delta_i n_i - sum_i (omega_i)/2) x_i + sum_(ij) V_ij n_i n_j where V_ij = C / a^6 (i-j)^6 for a 1d lattice. Inputs: Delta, Omega -- n and x couplings respectively V: the nearest-neighbor interaction (|i-j|=1) If Delta and Omega are scalars, a uniform hamiltonian is generated with delta_i= delta, etc. If they are iterables, the ith element will specify the coupling (eg delta_i) at the ith site. If V is input as a single scalar, Vij= V / |i-j|^6 V may also be input as a hermitian matrix, in which case the i,j element will specify Vij. Note that in that case you'll have to put in power-law behavior by hand. gamma (optional, default None): a list of two single-site amplitude-decay rates, specifying upper and lower decay rates respectively. If a list of gamma values is specifed, a nonhermitian term -1j * (gamma[0]/2) * sum_i n_i - 1j * (gamma[1]/2) * sum_i (1-n_i) will be added to the hamiltonian ktrunc = integer, interaction truncation. H will include 1/r^6 interactions of the form shown above up to kth-nearest-neighbors If verbose=True: some info on hamiltonian construction is given. """ check_bc(bc) L = basis.L if not isinstance(basis, boson_basis_1d): raise TypeError("invalid basis type") if not (gamma is None): try: if len(gamma) != 2: raise ValueError("List of decay rates should have length 2.") except TypeError: raise TypeError("Gamma should be a list") check_herm = True if gamma is not None: vprint(verbose, "Decay provided. herm=false, dtype=complex") check_herm = False dtype = np.complex128 static = get_r6_1d_static(Delta, Omega, V, L, ktrunc, gamma, bc=bc, verbose=verbose) dynamic = [] return hamiltonian(static, dynamic, basis=basis, dtype=dtype, check_herm=check_herm)