def prod(v1, v2, base): #find tensor product of v1,v2. For use with eg gen_clock_H #must be used with full base^N basis,can project after dim1 = np.size(v1) dim2 = np.size(v2) N1 = int(np.log2(dim1)) N2 = int(np.log2(dim2)) dim = np.power(base, N1 + N2) M = np.outer(v1, v2) out = np.zeros(dim, dtype=complex) for n in range(0, np.size(M, axis=0)): for m in range(0, np.size(M, axis=1)): state1 = int_to_bin_base_m(n, base, N1) state2 = int_to_bin_base_m(m, base, N2) state = np.append(state1, state2) ref = int(bin_to_int_base_m(state, base)) out[ref] = out[ref] + M[n, m] return out
for n in range(0, np.size(to_remove_refs, axis=0)): print(pxp.basis[pxp.keys[to_remove_refs[n]]]) #redo basis pxp.basis_refs_new = np.zeros( np.size(pxp.basis_refs) - np.size(to_remove_refs)) c = 0 for n in range(0, np.size(pxp.basis_refs, axis=0)): if pxp.basis_refs[n] not in to_remove_refs: pxp.basis_refs_new[c] = pxp.basis_refs[n] c = c + 1 pxp.basis_refs = pxp.basis_refs_new pxp.basis = np.zeros((np.size(pxp.basis_refs), pxp.N)) for n in range(0, np.size(pxp.basis_refs)): pxp.basis[n] = int_to_bin_base_m(pxp.basis_refs[n], pxp.base, pxp.N) pxp.keys = dict() for n in range(0, np.size(pxp.basis_refs)): pxp.keys[int(pxp.basis_refs[n])] = n # pxp_syms = model_sym_data(pxp,[translational(pxp),parity(pxp),]) # pxp_syms = model_sym_data(pxp,[translational(pxp)]) # # pxp_syms = model_sym_data(pxp,[parity(pxp)]) H = spin_Hamiltonian(pxp, "x") H.gen() H.sector.find_eig() e, u = H.sector.eigvalues(), H.sector.eigvectors() # H=H.sector.matrix() # e,u = np.linalg.eigh(H)
def __init__(self,ref,system): self.system = system self.ref = ref self.bits = int_to_bin_base_m(self.ref,self.system.base,self.system.N) self.key = system.keys[self.ref]
def perm_inv_key(ref): bits = int_to_bin_base_m(ref,int(N/2)+1,2) return bits
def update_H_pos_sweep(self, state, i_index, block_references, block_keys, op_sizes, k_vec=None): new_refs_coef = dict( ) #for storing all refs and there coef from looping positions for position in range(0, self.system.N): #indices operators act on (ie check pbc and loop around if at edge) #periodic site_indices (wrap around chain) if self.system.bc == "periodic": site_indices = dict() for op_index in range(0, np.size(self.model, axis=0)): d = np.size(self.model[op_index]) site_indices[op_index] = np.zeros(d) for n in range(0, d): if position + n < self.system.N: site_indices[op_index][n] = position + n else: site_indices[op_index][ n] = position + n - self.system.N #open (convention: Just throw away all terms that would wrap around chain) #eg, nn int x_i x_{i+1}, run to x_{N-2} X_{N-1} elif self.system.bc == "open": site_indices = dict() for op_index in range(0, np.size(self.model, axis=0)): d = np.size(self.model[op_index]) if position + d - 1 < self.system.N: site_indices[op_index] = np.zeros(d) for n in range(0, d): site_indices[op_index][n] = position + n else: site_indices[op_index] = None #filter these sites for identitys, projectors and operators to act with #0 is projector, -1 is identity P_indices = dict() non_projector_site_indices = dict() non_projector_op_indices = dict() #throw away keys where site_indices[op_index] = None (OBC) op_index_keys = list(site_indices.keys()) to_del = [] for n in range(0, np.size(op_index_keys, axis=0)): if site_indices[op_index_keys[n]] is None: to_del = np.append(to_del, n) for n in range(np.size(to_del, axis=0) - 1, -1, -1): op_index_keys = np.delete(op_index_keys, to_del[n], axis=0) for op_index in op_index_keys: for n in range(0, np.size(self.model[op_index], axis=0)): if self.model[op_index][n] != 0 and self.model[op_index][ n] != -1: #init dictionary if empty if op_index not in list( non_projector_site_indices.keys()): non_projector_site_indices[op_index] = np.array( [site_indices[op_index][n]]) non_projector_op_indices[op_index] = np.array([n]) else: non_projector_site_indices[op_index] = np.append( non_projector_site_indices[op_index], site_indices[op_index][n]) non_projector_op_indices[op_index] = np.append( non_projector_op_indices[op_index], n) elif self.model[op_index][n] == 0: if op_index not in list(P_indices.keys()): P_indices[op_index] = np.array( [site_indices[op_index][n]]) else: P_indices[op_index] = np.append( P_indices[op_index], site_indices[op_index][n]) #loop through all ops in sum to get all the product states mapped to + coef (full H space, sym eq state used later) for op_index in op_index_keys: #check state survives projectors first: survives_projectors = 1 if op_index in list(P_indices.keys()): for n in range(0, np.size(P_indices[op_index], axis=0)): if state[int(P_indices[op_index][n])] != 0: survives_projectors = 0 break if survives_projectors == 1: site_indices = non_projector_site_indices[op_index].astype( int) #matrix whos rows are the (on site H space) vectors formed when operator acts on site v = np.zeros((np.size(site_indices), self.system.base), dtype=complex) for n in range(0, np.size(site_indices)): v[n] = self.site_ops[self.model[op_index][int( non_projector_op_indices[op_index][n])]][int( state[int(site_indices[n])])] #seq of tensor products gives all combo of final states due to product of ops Q1 Q2... if np.size(site_indices) > 1: x = prod(v[0], v[1], self.system.base) for n in range(2, np.size(site_indices)): x = prod(x, v[n], self.system.base) else: x = v[0] #put this data in 2d array with rows (coef,[c1,c2,c3]) #c1,c2,c3... the new bits after operator acted on state (eg |010>->2*|000>, row=2,0) new_bits = np.zeros(np.size(site_indices), dtype=int) coefficients = [] for n in range(0, np.size(x, axis=0)): if np.abs(x[n]) > 0: new_bits = np.vstack( (new_bits, int_to_bin_base_m( n, self.system.base, np.size(site_indices)).astype(int))) coefficients = np.append(coefficients, x[n]) new_bits = np.delete(new_bits, 0, axis=0) #delete init row if np.size(coefficients) != 0: for n in range(0, np.size(new_bits, axis=0)): #form new state bit representation new_state = np.zeros(np.size(state), dtype=int) for m in range(0, np.size(state, axis=0)): if m not in site_indices: new_state[m] = state[m] if np.size(site_indices) > 1: for m in range(0, np.size(site_indices, axis=0)): new_state[site_indices[m]] = new_bits[n, m] else: new_state[site_indices] = new_bits[n, 0] new_ref = bin_to_int_base_m( new_state, self.system.base) if new_ref not in list(new_refs_coef.keys()): if self.uc_size is False: new_refs_coef[new_ref] = coefficients[ n] * self.model_coef[op_index] else: #check position is correct wrt uc size + site if position % self.uc_size[ op_index] == self.uc_pos[op_index]: new_refs_coef[new_ref] = coefficients[ n] * self.model_coef[op_index] else: if self.uc_size is False: new_refs_coef[new_ref] = new_refs_coef[ new_ref] + coefficients[ n] * self.model_coef[op_index] else: #check position is correct wrt uc size + site if position % self.uc_size[ op_index] == self.uc_pos[op_index]: new_refs_coef[new_ref] = new_refs_coef[ new_ref] + coefficients[ n] * self.model_coef[op_index] #Use bit maps (refs) mapped from all postions and there coef to update H elements all_new_refs = list(new_refs_coef.keys()) for ref_index in range(0, np.size(all_new_refs, axis=0)): if k_vec is None: #if not using syms, simply find location of new state in basis and update H_ij if all_new_refs[ref_index] in self.system.basis_refs: new_ref_index = self.system.keys[all_new_refs[ref_index]] self.sector.update_H_entry( i_index, new_ref_index, new_refs_coef[all_new_refs[ref_index]], dim=np.size(block_references)) else: #must lookup locations in symmetry basis, orbit ref states etc if using symmetries if all_new_refs[ref_index] in self.system.basis_refs: #location of state in full basis (to extract periodicty, norm data) j_full_index = self.system.keys[all_new_refs[ref_index]] #sym connected ref state new_ref_sym_conn_ref = self.syms.sym_data[j_full_index, 0] if new_ref_sym_conn_ref in block_references: #location of ref state in sym block basis (for index of Hamiltionian) j_ref_index = block_keys[new_ref_sym_conn_ref] i_ref = block_references[i_index] i_ref_full_index = self.system.keys[i_ref] L = self.syms.sym_data[j_full_index, 2:] N_a = self.syms.sym_data[i_ref_full_index, 1] N_b = self.syms.sym_data[j_full_index, 1] element = N_b / N_a * np.exp( 1j * 2 * math.pi / self.system.N * np.vdot(k_vec, L)) # print(i_index,j_ref_index,np.real(element),new_refs_coef[all_new_refs[ref_index]]) self.sector.update_H_entry( i_index, j_ref_index, element * new_refs_coef[all_new_refs[ref_index]], k_vec, dim=np.size(block_references))