def generate_independent_sets(self): # Construct generator containing independent sets # Don't generate anything that depends on the entire Hilbert space as to save space # Generate complement graph complement = nx.complement(self.graph) # These are your independent sets of the original graphs, ordered by node and size independent_sets, backup = tee( nx.algorithms.clique.enumerate_all_cliques(complement)) self.num_independent_sets = sum( 1 for _ in backup) + 1 # We add one to include the empty set # Generate a list of integers corresponding to the independent sets in binary indices = np.zeros(self.num_independent_sets, dtype=int) indices[-1] = 2**self.n - 1 k = self.num_independent_sets - 2 self.mis_size = 0 IS = dict.fromkeys(np.arange(self.num_independent_sets)) # All spins down should be at the end IS[self.num_independent_sets - 1] = (2**self.n - 1, 0, np.ones(self.n, dtype=int)) for i in independent_sets: indices[k] = 2**self.n - sum(2**j for j in i) - 1 IS[k] = (indices[k], len(i), tools.int_to_nary(indices[k], size=self.n)) if len(i) > self.mis_size: self.mis_size = len(i) k -= 1 binary_to_index = dict.fromkeys(indices) for j in range(self.num_independent_sets): binary_to_index[indices[j]] = j self.binary_to_index = binary_to_index self.independent_sets = IS return IS, binary_to_index, self.num_independent_sets
def return_probability(graph, times, verbose=False, h=1, exact=True): # For random product states in the computational basis, time evolve then compute if verbose: print('beginning') czz_tot = np.zeros((len(times), graph.n)) num = 0 for _ in range(1): for k in range(2**graph.n): print(k) # Compute the total magnetization z_mags_init = 2 * (1 / 2 - tools.int_to_nary(k, size=graph.n)) if np.sum(z_mags_init) == 0: num += 1 if verbose: print(z_mags_init) subspace = np.sum(z_mags_init) if path.exists('heisenberg_' + str(graph.n) + '_' + str(subspace) + '.pickle'): heisenberg = dill.load( open( 'heisenberg_' + str(graph.n) + '_' + str(subspace) + '.pickle', 'rb')) else: heisenberg = qsim.evolution.hamiltonian.HamiltonianHeisenberg( graph, subspace=subspace, energies=(1 / 4, 1 / 2)) dill.dump( heisenberg, open( 'heisenberg_' + str(graph.n) + '_' + str(subspace) + '.pickle', 'wb')) if verbose: print('initialized Hamiltonian') # For every computational basis state, dim = int(comb(graph.n, int((graph.n + subspace) / 2))) print(dim, subspace) hamiltonian = heisenberg.hamiltonian + disorder_hamiltonian( heisenberg.states, h=h) n_times = len(times) # hamiltonian_exp = expm(-1j *hamiltonian * (times[1] - times[0])) # print(2*(1-heisenberg.states-1/2),z_mags_init) ind = np.argwhere( np.sum(np.abs(2 * (1 - heisenberg.states - 1 / 2) - z_mags_init), axis=1) == 0)[0, 0] # print(ind) state = np.zeros((dim, 1)) state[ind, 0] = 1 states = np.zeros((dim, n_times), dtype=np.complex128) states[:, 0] = state.flatten() for i in range(n_times - 1): if verbose: print(i) states[..., i + 1] = expm_multiply( -1j * hamiltonian * (times[i + 1] - times[i]), states[..., i]) z_mags = ( (np.abs(states)**2).T @ (1 - heisenberg.states - 1 / 2) * 2).real # print(z_mags_init, z_mags, z_mags*z_mags_init/4) czz = z_mags * z_mags_init czz_tot = czz_tot + czz print(num) return czz_tot / num
def index_to_state(i, size=None): """Given an index i, return the ket associated with that index""" return int_to_nary(i, base=d, size=size, pad_with=0)
def spin_hamiltonian(): s = np.zeros((1, 2 ** n)) for j in range(2**n): s[0,j] = n-np.sum(np.array([tools.int_to_nary(j)])) return s.T