def apply_H_cin(self, i): """ @param i : unsigned integer, state in occupation representation. """ targets = [] # for each site for site in range(1, self.nb_sites + 1): # Perform the following tasks for both spins for spin in [site, site + self.nb_sites]: # if there is a current spin at site if (gmpy2.bit_test(i, spin - 1)): # loop over each neighbors for neighbor in self.get_neighbors(site): # add element to the answer if site is vacant if (not gmpy2.bit_test( i, int(spin - site + neighbor - 1))): # count the number of electrons between the creation and annihilation sites create_at = int(spin - site + neighbor - 1) destroy_at = int(spin - 1) n_el = 0 for c in np.arange( min(create_at, destroy_at) + 1, max(create_at, destroy_at)): if gmpy2.bit_test(i, int(c)): n_el += 1 targets.append([ ((-1)**(1 + n_el)) * self.t, gmpy2.bit_flip(gmpy2.bit_flip(i, spin - 1), int(spin - site + neighbor - 1)) ]) return targets
def get_rho_from_v(self,v,l): ''' :param v: wave vector :param l: number of sites :return: <psi|cidci|psi> ''' # initialize the density matrix rho = np.zeros([4*l,4*l],dtype=complex) # populate the matrix # iterate over all impurity+bath positions i for i in np.arange(4*l,dtype=int): # iterate over all impurity+bath positions j for j in np.arange(4*l,dtype=int): #iterate over all elements in the basis of the look-up table for run_k,k in enumerate(self.J): #check if a+i aj|k> is not null if(gmpy2.bit_test(int(k),int(j))): if(gmpy2.bit_test(int(k),int(i))==0 or i==j): new_state=gmpy2.bit_flip(int(k),int(j)) new_state=gmpy2.bit_flip(new_state,int(i)) run_new = self.state2index(new_state) #and don't forget the sign ! occupancy_between=0 for l in np.arange(min(i,j)+1,max(i,j)): occupancy_between+=gmpy2.bit_test(int(k),int(l)) rho[i,j]+=(-1)**occupancy_between*np.conjugate(v[run_new])*v[run_k] return rho
def get_rho_impurity(self, impurity_index, verbose=False): ''' :param impurity_index: index of the impurity :return: single particle density matrix in the impurity basis ''' # Get ground state (updates the chemical potential) vs = self.get_ground_state(impurity_index, verbose) v = np.zeros(np.shape(vs[0]), dtype=complex) if verbose: print(np.around(vs, 2)) # initialize the density matrix rho = np.zeros([4 * len(impurity_index), 4 * len(impurity_index)], dtype=complex) # the coefs part ensures that the ground state has a defined spin on the impurity if it is degenerated coefs = np.zeros(len(vs), dtype=complex) for k, psi in enumerate(vs): for i in np.arange(len(psi)): impurity_down = 0 for j in np.arange(len(impurity_index)): if (gmpy2.bit_test(int(i), int(j + len(impurity_index))) and not gmpy2.bit_test(int(i), int(j))): impurity_down += 1 coefs[k] += impurity_down * psi[i] if len(coefs) == 2: if (np.abs(coefs[0]) > 0.0001): c = coefs[1] / coefs[0] beta = 1 / np.sqrt(1 + c**2) alpha = -beta * c v = alpha * vs[0] + beta * vs[1] else: v = vs[0] else: v = vs[0] v = v / np.linalg.norm(v) if verbose: print("new ground state") print(v) # populate the matrix # iterate over all impurity+bath positions i for i in np.arange(4 * len(impurity_index), dtype=int): # iterate over all impurity+bath positions j for j in np.arange(4 * len(impurity_index), dtype=int): #iterate over all elements in the basis of the Fock space for k in np.arange(2**(4 * len(impurity_index)), dtype=int): #check if a+i aj|k> is not null if (gmpy2.bit_test(int(k), int(j))): if (gmpy2.bit_test(int(k), int(i)) == 0 or i == j): new_state = gmpy2.bit_flip(int(k), int(j)) new_state = gmpy2.bit_flip(new_state, int(i)) #and don't forget the sign ! occupancy_between = 0 for l in np.arange(min(i, j) + 1, max(i, j)): occupancy_between += gmpy2.bit_test( int(k), int(l)) rho[i, j] += (-1)**occupancy_between * np.conjugate( v[new_state]) * v[k] return rho
def h_2_cdef(self,state_i,state_j): ''' :param state_j: (int) state where the destruction happened :param state_i: (int) state where the creation happened :return: The "2 particles" energy for 2 jump from site d towards site c ''' jumps = state_i^state_j # get the position of the 2 destruction and creation sites d_sites = int(state_j & jumps) c_sites = int((state_i & jumps)) found_c1 = False found_d1 = False c1=0 c2=0 d1=0 d2=0 for i in np.arange(self.imp_bath_size): i=int(i) if(gmpy2.bit_test(d_sites,i)): if found_d1: d2=i else: found_d1=True d1=i elif(gmpy2.bit_test(c_sites,i)): if found_c1: c2=i else: found_c1=True c1=i # compute the term h=self.get_U_tilda(c1,d1,c2,d2)-self.get_U_tilda(c1,d2,c2,d1)-self.get_U_tilda(c2,d1,c1,d2)+self.get_U_tilda(c2,d2,c1,d1) # get the occupation between c2 d2 occupied = 0 for k in np.arange((min(c2, d2) + 1), max(c2, d2)): occupied += gmpy2.bit_test(state_j, int(k)) s1 = (-1) ** (occupied) # compute the intermediary state tmp_state = gmpy2.bit_flip(state_j,c2) tmp_state = gmpy2.bit_flip(tmp_state,d2) # get the occupation berween c1 d1 occupied = 0 for k in np.arange((min(c1, d1) + 1), max(c1, d1)): occupied += gmpy2.bit_test(tmp_state, int(k)) s2 = (-1) ** (occupied) return s1*s2*h
def get_random_adjacent_state(self, i): ''' :param i: (integer) state which is in the binary representation state :return: state j which is obtained by permuting one electron and one hole from state i ''' pos_e = random.randint( 1, self.nb_electrons) # we will move the pos_e.th. electron pos_h = random.randint( 1, self.nb_sites * self.nb_flavors - self.nb_electrons ) # we will permute the electron with the pos_h th. hole count_e = 0 count_h = 0 #count the number of visited bit with electrons and holes has_flipped = False # if we have already made a move for site in range(0, self.nb_flavors * self.nb_sites): #we loop over each bit of i. #update the number of visited bits with electrons and holes if (gmpy2.bit_test(i, site)): count_e += 1 else: count_h += 1 #Flip the bit if it's the correct position if (count_e == pos_e): i = gmpy2.bit_flip(i, site) count_e += 1 #update count_e to not enter the condition on the next loop if not has_flipped: #if it's the first flip has_flipped = True else: #if we already made a move, then we can exist the loop break elif (count_h == pos_h): i = gmpy2.bit_flip(i, site) count_h += 1 if not has_flipped: #if it's the first flip has_flipped = True else: #if we already made a move, then we can exist the loop break return i
def apply_c(self, a, i, dagger=False): ''' compute C(?dagger)(a)|i> :param i: (int) binary representation of state i in occupation state :param a: (int) number of the site(+spin) on which we want to apply cdagger :param dagger: (bool) if True, return cdagger|i>, othervise c|i> :return: (int,int) 1 or -1, binary representation of state cd|i> in occupation state ''' #Get the ath state ath_state = gmpy2.bit_test(i, a) #if the site is empty and we want to destroy of occupied and we want to create if (ath_state == dagger): return [0, 0] # Othervise else: # count the number of occupied states before a to get the phase nb_bits_on_before_a = gmpy2.popcount(i % (1 << a)) # flip the ath bit new_state = gmpy2.bit_flip(i, a) # return the phase and the new state return [(-1)**nb_bits_on_before_a, new_state]
def apply_c_dagger(self,state,a): ''' Compute c_a+|state> :param state: integer representation of quantum state :param a: spin-site where we will apply c :return: sign (+-1) and new state ''' # Make sure that state and the site are casted correctly state = int(state) a = int(a) # check the occupation until a sgn = (-1)**self.occupation_between(state,-1,a) # -1 because we count the first state at 0 # check that there is an electron at a if gmpy2.bit_test(state, a): # if there is already an electron, set the sgn to 0 (and state to 0 as a convention) sgn=0 state=0 else : # otherwise we flip the bit state = gmpy2.bit_flip(state,a) return sgn,state