def test_single_qubit_multiply_pauli(self): # Tests single qubit operation given a pauli index N = 6 # Initialize in |000000> psi0 = State(np.zeros((2 ** N, 1))) psi0[0,0] = 1 # Apply sigma_y on the second qubit to get 1j|010000> # Check Typing psi0 = qubit.multiply(psi0, 1, 'Y') self.assertTrue(psi0[2 ** (N - 2), 0] == 1j) # Apply sigma_z on the second qubit, codes is -1j|010000> psi0 = qubit.multiply(psi0, [1], 'Z') self.assertTrue(psi0[2 ** (N - 2), 0] == -1j) # Apply sigma_x on all qubits but 1 psi0 = qubit.multiply(psi0, [0, 2, 3, 4, 5], ['X'] * (N - 1)) # Vector is still normalized self.assertTrue(np.vdot(psi0, psi0) == 1) # Should be -1j|111111> self.assertTrue(psi0[-1, 0] == -1j) # Density matrix test psi1 = np.array([tools.tensor_product([np.array([1, 1]), np.array([1, 0])]) / 2 ** (1 / 2)]).T psi1 = State(tools.outer_product(psi1, psi1)) # Apply sigma_Y to first qubit psi2 = np.array([np.kron([1j, -1j], [1, 0]) / 2 ** (1 / 2)]).T rho2 = tools.outer_product(psi2, psi2) psi1 = qubit.multiply(psi1, [0], 'Y') self.assertTrue(np.linalg.norm(psi1 - rho2) <= 1e-10)
def test_amplitude_damping_channel(self): psi0 = State(np.zeros((2, 2))) psi0[0, 0] = 1 spontaneous_emission = quantum_channels.AmplitudeDampingChannel() for i in range(200): psi0 = spontaneous_emission.channel(psi0, .1) self.assertTrue(np.allclose(psi0, np.array([[0, 0], [0, 1]]))) psi0 = State(np.zeros((2, 2))) psi0[0, 0] = 1 psi0 = spontaneous_emission.evolve(psi0, 20) self.assertTrue(np.allclose(psi0, np.array([[0, 0], [0, 1]]))) psi0 = State(np.zeros((2, 2)), IS_subspace=True, graph=line_graph(1)) psi0[0, 0] = 1 spontaneous_emission = quantum_channels.AmplitudeDampingChannel( IS_subspace=True, graph=line_graph(1), rates=(2, )) psi0 = spontaneous_emission.evolve(psi0, 20) self.assertTrue(np.allclose(psi0, np.array([[0, 0], [0, 1]]))) psi0 = State(np.zeros((8, 8)), IS_subspace=True, code=rydberg, graph=line_graph(2)) psi0[3, 3] = 1 spontaneous_emission = quantum_channels.AmplitudeDampingChannel( IS_subspace=True, graph=line_graph(2), rates=(2, ), code=rydberg, transition=(1, 2)) psi0 = spontaneous_emission.evolve(psi0, 1) print(psi0)
def ground_state(self, which='S'): """Returns the ground state and ground state energy""" # Construct a LinearOperator for the Hamiltonians linear_operator = False ham = None for h in self.hamiltonians: if not hasattr(h, 'hamiltonian'): linear_operator = True else: if ham is None: ham = h.hamiltonian else: ham = ham + h.hamiltonian if not linear_operator: if which == 'S': w = 'SA' else: w = 'LA' eigvals, eigvecs = scipy.sparse.linalg.eigsh(ham, k=1, which=w) eigvecs = eigvecs.T # Reorder eigenvalues and eigenvectors else: # Construct a LinearOperator from the Hamiltonians raise NotImplementedError if which == 'S': return eigvals[0], State(eigvecs[0, np.newaxis].T, is_ket=True) elif which == 'L': return eigvals[-1], State(eigvecs[-1, np.newaxis].T, is_ket=True)
def test_single_qubit_rotation(self): # Initialize in |000000> N = 6 psi0 = State(np.zeros((rydberg.d**N, 1)), code=rydberg) psi0[0, 0] = 1 psi1 = State(psi0, code=rydberg) # Rotate by exp(-1i*pi/4*sigma_y) every qubit to get |++++++> for i in range(N): psi0 = rydberg.rotation(psi0, [i], np.pi / 4, rydberg.Y, is_involutary=True) # noinspection PyTypeChecker self.assertAlmostEqual( np.vdot(psi0, np.ones((rydberg.d**N, 1)) / 2**(N / 2)), 1) # Apply exp(-1i*pi/4*sigma_x)*exp(-1i*pi/4*sigma_z) on every qubit to get exp(-1j*N*pi/4)*|000000> for i in range(N): psi0 = rydberg.rotation(psi0, [i], np.pi / 4, ['Z'], is_involutary=True) psi0 = rydberg.rotation(psi0, [i], np.pi / 4, rydberg.X, is_involutary=True) self.assertTrue( np.abs(np.vdot(psi1, psi0) * np.exp(1j * np.pi / 4 * N) - 1) <= 1e-10)
def Q(eq: SchrodingerEquation, dissipation): # Diagonalize Hamiltonian # Compute Q matrix elements eigval, eigvec = eq.eig() q = np.zeros((len(eigval), len(eigval))) jump_operators = np.array(dissipation.jump_operators) # For each pair of eigenvectors for pair in itertools.product(range(eigvec.shape[0]), repeat=2): # Compute the rate if pair[0] != pair[1]: eigvec1 = State(tools.outer_product(eigvec[pair[0]].T, eigvec[pair[0]].T), is_ket=False, IS_subspace=True, graph=graph) eigvec2 = State(tools.outer_product(eigvec[pair[1]].T, eigvec[pair[1]].T), is_ket=False, IS_subspace=True, graph=graph) rates = np.sum([ np.trace(eigvec2 @ jump_operators[i] @ eigvec1 @ jump_operators[i].conj().T) for i in range(len(jump_operators)) ]) q[pair[1], pair[0]] = rates.real**2 q[pair[0], pair[0]] = q[pair[0], pair[0]] - rates.real**2 return q
def run(self, param, initial_state=None): if self.code.logical_code and initial_state is None: initial_state = State(tensor_product([self.code.logical_basis[1]] * self.N), code=self.code) elif initial_state is None: if isinstance(self.cost_hamiltonian, HamiltonianMIS): initial_state = State(np.zeros( (self.cost_hamiltonian.hamiltonian.shape[0], 1)), code=self.code) initial_state[-1, -1] = 1 else: initial_state = State( np.ones((self.cost_hamiltonian.hamiltonian.shape[0], 1)) / np.sqrt(self.cost_hamiltonian.hamiltonian.shape[0]), code=self.code) if not (self.noise_model is None or self.noise_model == 'monte_carlo'): # Initial s should be a density matrix initial_state = State(outer_product(initial_state, initial_state), code=self.code) s = initial_state for j in range(self.depth): s = self.hamiltonian[j].evolve(s, param[j]) if self.noise_model is not None: if self.noise[j] is not None: s = self.noise[j].evolve(s, param[j]) # Return the expected value of the cost function # Note that the codes's defined expectation function won't work here due to the shape of C return self.cost_hamiltonian.cost_function(s)
def nh_evolve(self, state: State, time: float): """Non-hermitian time evolution.""" if state.is_ket: return State(expm_multiply(-1j * time * self.nh_hamiltonian, state), is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code, graph=self.graph) else: temp = expm(-1j * time * self.nh_hamiltonian) return State(temp @ state @ temp.conj().T, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code, graph=self.graph)
def evolve(self, state: State, time): if state.is_ket: return State(expm_multiply(-1j * time * self.hamiltonian, state), is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code, graph=self.graph) else: exp_hamiltonian = expm(-1j * time * self.hamiltonian) return State(exp_hamiltonian @ state @ exp_hamiltonian.conj().T, is_ket=state.is_ket, IS_subspace=state.IS_subspace, code=state.code, graph=self.graph)
def test_single_qubit_operation(self): N = 6 # Test single qubit operation psi0 = State(np.zeros((rydberg.d**N, 1)), code=rydberg) psi0[0][0] = 1 # Apply sigma_y on the second qubit to get 1j|020000> psi0 = rydberg.multiply(psi0, [1], rydberg.Y) self.assertTrue(psi0[(rydberg.d - 1) * rydberg.d**(N - 2), 0] == 1j) # Apply sigma_z on the second qubit, codes is -1j|010000> psi0 = rydberg.multiply(psi0, [1], rydberg.Z) self.assertTrue(psi0[(rydberg.d - 1) * rydberg.d**(N - 2), 0] == -1j) # Apply sigma_x on qubits psi0 = rydberg.multiply(psi0, [0, 2, 3, 4, 5], tools.tensor_product([rydberg.X] * (N - 1))) # Vector is still normalized self.assertTrue(np.vdot(psi0, psi0) == 1) # Should be -1j|111111> self.assertTrue(psi0[-1, 0] == -1j) # Test rydberg operations with density matrices psi1 = np.array([ tools.tensor_product([np.array([1, 0, 1]), np.array([1, 0, 0])]) / 2**(1 / 2) ]).T psi1 = State(tools.outer_product(psi1, psi1), code=rydberg) # Apply sigma_Y to first qubit psi2 = np.array([np.kron([1, 0, -1], [1, 0, 0]) * -1j / 2**(1 / 2)]).T rho2 = tools.outer_product(psi2, psi2) psi1 = rydberg.multiply(psi1, [0], ['Y']) self.assertTrue(np.linalg.norm(psi1 - rho2) <= 1e-10) psi0 = np.array([ tools.tensor_product([np.array([1, 0, 1]), np.array([1, 0, 0])]) / 2**(1 / 2) ]).T psi0 = State(tools.outer_product(psi0, psi0), code=rydberg) psi1 = State(psi0.copy(), code=rydberg) # Apply sigma_Y to first qubit psi2 = np.array([np.kron([1, 0, -1], [1, 0, 0]) * -1j / 2**(1 / 2)]).T psi2 = tools.outer_product(psi2, psi2) # Apply single qubit operation to dmatrix psi0 = rydberg.multiply(psi0, [0], rydberg.Y) self.assertTrue(np.linalg.norm(psi0 - psi2) <= 1e-10) # Test on ket psi1 = rydberg.multiply(psi1, [0], rydberg.Y) self.assertTrue(np.linalg.norm(psi1 - psi2) <= 1e-10)
def test_hamiltonian_driver(self): N = 6 hl_qubit = hamiltonian.HamiltonianDriver(graph=tools_test.sample_graph()) psi0 = State(np.zeros((2 ** N, 1))) psi0[0, 0] = 1 psi1 = State(tools.outer_product(psi0, psi0)) # Evolve by e^{-i (\pi/2) \sum_i X_i} psi0 = hl_qubit.evolve(psi0, np.pi / 2) # Should get (-1j)^N |111111> self.assertTrue(np.vdot(psi0, psi0) == 1) self.assertTrue(psi0[-1, 0] == (-1j) ** N) # Evolve by e^{-i (\pi/2) \sum_i X_i} psi1 = hl_qubit.evolve(psi1, np.pi / 2) # Should get (-1j)^N |111111> self.assertTrue(tools.is_valid_state(psi1)) self.assertAlmostEqual(psi1[-1, -1], 1) psi0 = State(np.zeros((2 ** N, 1))) psi0[0, 0] = 1 psi0 = hl_qubit.left_multiply(psi0) psi1 = np.zeros((2 ** N, 1), dtype=np.complex128) for i in range(N): psi1[2 ** i, 0] = 1 self.assertTrue(np.allclose(psi0, psi1)) psi2 = State(np.zeros((2 ** N, 1))) psi2[0, 0] = 1 psi2 = hl_qubit.hamiltonian @ psi2 self.assertTrue(np.allclose(psi0, psi2)) N = 3 hl = hamiltonian.HamiltonianDriver(transition=(0, 1), code=rydberg) psi0 = State(np.zeros((rydberg.d ** N, 1)), code=rydberg) psi0[5, 0] = 1 psi1 = State(tools.outer_product(psi0, psi0), code=rydberg) psi0 = hl.left_multiply(psi0) self.assertTrue(psi0[2, 0] == 1) self.assertTrue(psi0[14, 0] == 1) psi1 = hl.left_multiply(psi1) self.assertTrue(psi1[2, 5] == 1) self.assertTrue(psi1[14, 5] == 1) psi0 = State(np.zeros((rydberg.d ** N, 1)), code=rydberg) psi0[5, 0] = 1 psi0 = hl.evolve(psi0, np.pi / 2) self.assertTrue(np.isclose(psi0[11, 0], -1)) # IS subspace hl = hamiltonian.HamiltonianDriver(transition=(0, 2), code=rydberg, IS_subspace=True, graph=line_graph(2)) psi0 = State(np.zeros((8, 1)), code=rydberg) psi0[-1,0] = 1 psi0 = State(tools.outer_product(psi0, psi0), code=rydberg) self.assertTrue(tools.is_hermitian(hl.evolve(psi0, 1)))
def test_multi_qubit_multiply(self): N = 6 psi0 = np.zeros((2 ** N, 1), dtype=np.complex128) psi0[0, 0] = 1 psi1 = State(psi0) psi0 = State(psi0) op = tools.tensor_product([qubit.X, qubit.Y, qubit.Z]) psi0 = qubit.multiply(psi0, [1, 3, 4], op) psi1 = qubit.multiply(psi1, [1], 'X') psi1 = qubit.multiply(psi1, [3], 'Y') psi1 = qubit.multiply(psi1, [4], 'Z') self.assertTrue(np.allclose(psi0, psi1))
def test_trotterize_noiseless(self): # Noiseless simulations # Compare that the integrator adiabatic results match the trotterized results # First, compare the non-IS subspace results simulation = adiabatic_simulation(sample_graph(), IS_subspace=False) res_trotterize = simulation.performance_vs_total_time( np.arange(1, 5, 1), metric='optimum_overlap', initial_state=State(equal_superposition(6)), schedule=lambda t, tf: simulation.linear_schedule( t, tf, coefficients=[10, 10]), plot=False, verbose=True, method='trotterize') res_RK45 = simulation.performance_vs_total_time( np.arange(1, 5, 1), metric='optimum_overlap', initial_state=State(equal_superposition(6)), schedule=lambda t, tf: simulation.linear_schedule( t, tf, coefficients=[10, 10]), plot=False, verbose=True, method='RK45') # Now test in the IS subspace self.assertTrue( np.allclose(res_trotterize[0]['trotterize']['optimum_overlap'], res_RK45[0]['RK45']['optimum_overlap'], atol=1e-2)) simulation = adiabatic_simulation(sample_graph(), IS_subspace=True) res_trotterize = simulation.performance_vs_total_time( np.arange(1, 4, 1), metric='optimum_overlap', schedule=lambda t, tf: simulation.linear_schedule( t, tf, coefficients=[10, 10]), plot=False, verbose=True, method='trotterize') res_RK45 = simulation.performance_vs_total_time( np.arange(1, 4, 1), metric='optimum_overlap', schedule=lambda t, tf: simulation.linear_schedule( t, tf, coefficients=[10, 10]), plot=False, verbose=True, method='RK45') self.assertTrue( np.allclose(res_trotterize[0]['trotterize']['optimum_overlap'], res_RK45[0]['RK45']['optimum_overlap'], atol=1e-2))
def jump_rate(self, state: State, apply_to=None): assert state.is_ket if apply_to is None: apply_to = list(range(state.number_physical_qudits)) if isinstance(apply_to, int): apply_to = [apply_to] jump_rates = [] jumped_states = [] if not self.IS_subspace: for j in range(len(self.jump_operators)): for i in apply_to: out = self.code.left_multiply(state, i, self.jump_operators[j]) jump_rates.append(np.vdot(out, out).real) # IMPORTANT: add in a factor of sqrt(rates) for normalization purposes later jumped_states.append(out) else: for j in range(len(self.jump_operators)): out = self.jump_operators[j] @ state jump_rates.append(np.vdot(out, out).real) # IMPORTANT: add in a factor of sqrt(rates) for normalization purposes later jumped_states.append( State(out, is_ket=state.is_ket, code=state.code, IS_subspace=state.IS_subspace, graph=state.graph)) return np.asarray(jumped_states), np.asarray(jump_rates)
def liouvillian(self, state: State, apply_to=None): if apply_to is None: apply_to = list(range(state.number_physical_qudits)) out = np.zeros(state.shape) if self.IS_subspace: for i in range(len(self.jump_operators)): out = out + self.jump_operators[i] @ state @ self.jump_operators[i].T - 1 / 2 * self.jump_operators[ i].T @ self.jump_operators[i] @ state - 1 / 2 * state @ self.jump_operators[i].T @ \ self.jump_operators[i] else: for i in range(len(apply_to)): for j in range(len(self.jump_operators)): out = out + self.code.multiply(state, [apply_to[i]], self.jump_operators[j]) - 1 / 2 * \ self.code.left_multiply(state, [apply_to[i]], self.jump_operators[j].T @ self.jump_operators[ j]) - 1 / 2 * self.code.right_multiply( state, [apply_to[i]], self.jump_operators[j].T @ self.jump_operators[j]) return State(out, is_ket=state.is_ket, code=state.code, IS_subspace=state.IS_subspace, graph=self.graph)
def test_single_qubit(self): psi0 = State( tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[0] ])) psi1 = psi0.copy() # Density matrix test psi2 = State(tools.outer_product(psi1, psi1)) psi0 = three_qubit_code.multiply(psi0, [1], ['Y']) # Test non-pauli operation psi1 = three_qubit_code.multiply(psi1, [1], three_qubit_code.Y) psi2 = three_qubit_code.multiply(psi2, [1], three_qubit_code.Y) res = 1j * tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[1] ]) # Should get out 1j|0L>|1L> self.assertTrue(np.allclose(psi0, res)) self.assertTrue(np.allclose(psi1, res)) self.assertTrue(np.allclose(psi2, tools.outer_product(res, res))) self.assertTrue( np.allclose( three_qubit_code.multiply(psi0, [1], ['Z']), -1j * tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[1] ]))) psi0 = three_qubit_code.multiply(psi0, [0], ['X']) # Should get out -1j|1L>|1L> self.assertTrue( np.allclose( psi0, 1j * tools.tensor_product([ three_qubit_code.logical_basis[1], three_qubit_code.logical_basis[1] ]))) # Rotate all qubits for i in range(2): psi0 = three_qubit_code.rotation(psi0, [i], np.pi / 2, three_qubit_code.X) self.assertTrue( np.allclose( psi0, -1j * tools.tensor_product([ three_qubit_code.logical_basis[0], three_qubit_code.logical_basis[0] ])))
def test_state(self): # This method just tests if State initializes property state = np.zeros((16, 1)) state[-1, -1] = 1 state = State(state, code=jordan_farhi_shor) self.assertTrue(state.code == jordan_farhi_shor) self.assertTrue(state.number_physical_qudits == 4) self.assertTrue(state.number_logical_qudits == 1)
def f(t, s): global state if method == 'odeint': t, s = s, t if method != 'odeint': s = np.reshape(np.expand_dims(s, axis=0), state_shape) schedule(t) s = State(s, is_ket=is_ket, code=code, IS_subspace=IS_subspace, graph=graph) return np.asarray(self.evolution_generator(s)).flatten()
def dephasing_performance(): # adiabatic = SimulateAdiabatic(hamiltonian=[laser], noise = [dephasing, dissipation], noise_model='continuous', # graph=graph, IS_subspace=True, cost_hamiltonian=rydberg_hamiltonian_cost) # def schedule(t, tf): # phi = (tf-t)/tf*np.pi/2 # laser.omega_g = np.cos(phi) # laser.omega_r = np.sin(phi) # dissipation.omega_g = np.cos(phi) # dissipation.omega_r = np.sin(phi) # adiabatic.performance_vs_total_time(np.arange(5, 100, 5), schedule=schedule, verbose=True, plot=True, method='odeint') dephasing_rates = 10. ** (np.arange(-3, 0, .2)) performance_3 = [] performance_5 = [] for j in [3, 5]: graph = line_graph(n=j) phi = .02 laser = EffectiveOperatorHamiltonian(omega_g=np.cos(phi), omega_r=np.sin(phi), energies=(1,), graph=graph) dissipation = EffectiveOperatorDissipation(omega_g=np.cos(phi), omega_r=np.sin(phi), rates=(1,), graph=graph) dephasing = lindblad_operators.LindbladPauliOperator(pauli='Z', IS_subspace=True, graph=graph, rates=(.1,)) rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph, IS_subspace=True, code=qubit) eq = LindbladMasterEquation(hamiltonians=[laser], jump_operators=[dissipation, dephasing]) for i in range(len(dephasing_rates)): dissipation.rates = (1,) laser.energies = (1,) dephasing.rates = (dephasing_rates[i],) state = np.zeros(dissipation.nh_hamiltonian.shape) state[-1, -1] = 1 state = State(state, is_ket=False, graph=graph, IS_subspace=True) ss = eq.steady_state(state) ss = ss[1][0] state = State(ss, is_ket=False, graph=graph, IS_subspace=True) print(rydberg_hamiltonian_cost.optimum_overlap(state)) if j == 3: performance_3.append(rydberg_hamiltonian_cost.optimum_overlap(state)) else: performance_5.append(rydberg_hamiltonian_cost.optimum_overlap(state)) plt.scatter(dephasing_rates, performance_3, color='teal', label=r'$n=3$ line graph') plt.scatter(dephasing_rates, performance_5, color='purple', label=r'$n=5$ line graph') plt.ylabel(r'log(-log(optimum overlap))') plt.xlabel(r'$\log(\gamma\Omega^2/(\delta^2\Gamma_{\rm{dephasing}}))$') plt.legend() plt.show()
def plot_6(): size = 6 critical_detuning = -9.604213726908476 #-6.019449429835163 critical_detunings = np.concatenate( [-np.linspace(2, 10, 10), [critical_detuning]]) graph_index = 807 graph_data = loadfile(graph_index, size) grid = graph_data['graph_mask'] print('Initializing graph') graph = unit_disk_grid_graph(grid, periodic=False, radius=1.6) graph_finite = unit_disk_grid_graph(grid, periodic=False, radius=1.1) graph_finite.generate_independent_sets() n_points = 7 times = 2**np.linspace(-2.5, 4.5 / 6 * (n_points - 1) - 2.5, n_points) times = np.concatenate([times, [2.5]]) # np.array([2.5])# times = times + .312 * 2 cost = hamiltonian.HamiltonianMIS(graph, IS_subspace=True) performances = np.zeros((len(critical_detunings), len(times))) * np.nan for (d, detuning) in enumerate(critical_detunings): for (t, tf) in enumerate(times): try: cost.energies = (1, ) state = State(np.load('{}x{}_{}_{}_{}_trotterize.npz'.format( size, size, graph_index, np.round(np.abs(detuning), 2), np.round(np.abs(tf), 2)))['state'], is_ket=True, IS_subspace=True, graph=graph) performances[d, t] = MIS_probability_finite( state, graph, graph_finite) print(tf, detuning, performances[d, t]) except: pass colors = [ 'blue', 'green', 'navy', 'orange', 'firebrick', 'purple', 'magenta', 'cornflowerblue', 'teal', 'grey', 'cyan', 'limegreen', 'red', 'yellow', 'pink', 'orangered', 'salmon', 'violet' ] for (d, detuning) in enumerate(critical_detunings): plt.scatter(times - 2 * .312, performances[d], color=colors[d], label='Detuning $={}$'.format(np.round(detuning, 2))) plt.plot(times - 2 * .312, performances[d], color=colors[d]) print(repr(performances)) plt.xlabel('Total time ($\mu s$)') plt.ylabel('MIS probability') plt.semilogx() plt.legend() plt.show()
def test_multi_qubit_operation(self): N = 6 psi0 = State(np.zeros((rydberg.d**N, 1)), code=rydberg) psi0[0, 0] = 1 psi1 = psi0.copy() op = tools.tensor_product([rydberg.X, rydberg.Y, rydberg.Z]) psi0 = rydberg.multiply(psi0, [1, 3, 4], op) psi1 = rydberg.multiply(psi1, [1], 'X') psi1 = rydberg.multiply(psi1, [3], 'Y') psi1 = rydberg.multiply(psi1, [4], 'Z') self.assertTrue(np.allclose(psi0, psi1))
def test_multi_qubit(self): n = 5 psi0 = State( tools.tensor_product([jordan_farhi_shor.logical_basis[0]] * n)) psi1 = psi0.copy() op = tools.tensor_product( [jordan_farhi_shor.X, jordan_farhi_shor.Y, jordan_farhi_shor.Z]) psi0 = jordan_farhi_shor.multiply(psi0, [1, 3, 4], op) psi1 = jordan_farhi_shor.multiply(psi1, [1, 3, 4], ['X', 'Y', 'Z']) self.assertTrue(np.allclose(psi0, psi1))
def test_multi_qubit(self): N = 5 psi0 = State( tools.tensor_product([two_qubit_code.logical_basis[0]] * N)) psi1 = psi0.copy() op = tools.tensor_product( [two_qubit_code.X, two_qubit_code.Y, two_qubit_code.Z]) psi0 = two_qubit_code.multiply(psi0, [1, 3, 4], op) psi1 = two_qubit_code.multiply(psi1, [1, 3, 4], ['X', 'Y', 'Z']) self.assertTrue(np.allclose(psi0, psi1))
def test_multi_qubit_pauli(self): N = 6 psi0 = np.zeros((2 ** N, 1), dtype=np.complex128) psi0[0, 0] = 1 psi1 = State(psi0) psi2 = State(psi0) psi3 = State(psi0) psi4 = State(psi0) psi0 = State(psi0) psi0 = qubit.multiply(psi0, [1, 3, 4], ['X', 'Y', 'Z']) psi2 = qubit.multiply(psi2, [4, 1, 3], ['Z', 'X', 'Y']) psi3 = qubit.multiply(psi3, [1, 3, 4], tools.tensor_product([qubit.X, qubit.Y, qubit.Z])) psi4 = qubit.multiply(psi4, [4, 1, 3], tools.tensor_product([qubit.Z, qubit.X, qubit.Y])) psi1 = qubit.multiply(psi1, [1], 'X') psi1 = qubit.multiply(psi1, [3], 'Y') psi1 = qubit.multiply(psi1, [4], 'Z') self.assertTrue(np.allclose(psi0, psi1)) self.assertTrue(np.allclose(psi1, psi2)) self.assertTrue(np.allclose(psi2, psi3)) self.assertTrue(np.allclose(psi3, psi4))
def mis_qaoa(n, method='minimize', show=True, analytic_gradient=True): penalty = 1 psi0 = tools.equal_superposition(n) psi0 = State(psi0) G = make_ring_graph_multiring(n) if show: nx.draw_networkx(G) plt.show() depths = [2 * i for i in range(1, 2 * n + 1)] mis = [] # Find MIS optimum # Uncomment to visualize graph hc_qubit = hamiltonian.HamiltonianMIS(G, energies=[1, penalty]) cost = hamiltonian.HamiltonianMIS(G, energies=[1, penalty]) # Set the default variational operators hb_qubit = hamiltonian.HamiltonianDriver() # Create Hamiltonian list sim = qaoa.SimulateQAOA(G, cost_hamiltonian=cost, hamiltonian=[], noise_model=None) sim.hamiltonian = [] for p in depths: sim.hamiltonian.append(hc_qubit) sim.hamiltonian.append(hb_qubit) sim.depth = p # You should get the same thing print(p) if method == 'minimize': results = sim.find_parameters_minimize(verbose=True, initial_state=psi0, analytic_gradient=analytic_gradient) approximation_ratio = np.real(results['approximation_ratio']) mis.append(approximation_ratio) if method == 'brute': results = sim.find_parameters_brute(n=15, verbose=True, initial_state=psi0) approximation_ratio = np.real(results['approximation_ratio']) mis.append(approximation_ratio) if method == 'basinhopping': if p >= 10: results = sim.find_parameters_basinhopping(verbose=True, initial_state=psi0, n=250, analytic_gradient=analytic_gradient) print(results) approximation_ratio = np.real(results['approximation_ratio']) mis.append(approximation_ratio) # plt.plot(list(range(n)), maxcut, c='y', label='maxcut') print(mis) plt.plot(depths, [(i + 1) / (i + 2) for i in depths]) plt.scatter(depths, [i / (i + 1) for i in depths], label='maxcut') plt.scatter(depths, mis, label='mis with $n=$' + str(n)) plt.plot(depths, mis) plt.legend() if show: plt.show()
def f(t, state): if method == 'odeint': t, state = state, t if method != 'odeint': state = np.reshape(np.expand_dims(state, axis=0), state_shape) state = State(state, is_ket=is_ket, code=code, IS_subspace=IS_subspace) return np.asarray( schrodinger_equation.evolution_generator(state)).flatten()
def test_rydberg_hamiltonian(self): # Test normal MIS Hamiltonian # Graph has six nodes and nine edges hc = hamiltonian.HamiltonianMIS(g) self.assertTrue(hc.hamiltonian[0, 0] == -3) self.assertTrue(hc.hamiltonian[-1, -1] == 0) self.assertTrue(hc.hamiltonian[-2, -2] == 1) self.assertTrue(hc.hamiltonian[2, 2] == -1) # Test for qubits hq = hamiltonian.HamiltonianMIS(g, energies=(1, 100)) self.assertTrue(hq.hamiltonian[0, 0] == -894) self.assertTrue(hq.hamiltonian[-1, -1] == 0) self.assertTrue(hq.hamiltonian[2, 2] == -595) psi0 = State(np.zeros((2**g.n, 1))) psi0[-1, -1] = 1 psi1 = State(tools.outer_product(psi0, psi0)) self.assertTrue(hq.cost_function(psi1) == 0) self.assertTrue(hq.cost_function(psi0) == 0) self.assertTrue(hq.optimum_overlap(psi0) == 0) psi2 = State(np.zeros((2**g.n, 1))) psi2[27, -1] = 1 self.assertTrue(hq.optimum_overlap(psi2) == 1) self.assertTrue(hq.cost_function(psi2) == 2) psi2[30, -1] = 1 psi2 = psi2 / np.sqrt(2) self.assertTrue(np.isclose(hq.optimum_overlap(psi2), 1)) self.assertTrue(np.isclose(hq.cost_function(psi2), 2)) # Test for rydberg EIT hr = hamiltonian.HamiltonianMIS(g, energies=(1, 100), code=rydberg) self.assertTrue(hr.hamiltonian[0, 0] == -894) self.assertTrue(hr.hamiltonian[-1, -1] == 0) self.assertTrue(hr.hamiltonian[6, 6] == -595) psi0 = State(np.zeros((rydberg.d**g.n, 1))) psi0[-1, -1] = 1 psi1 = State(tools.outer_product(psi0, psi0)) self.assertTrue(hr.cost_function(psi1) == 0) self.assertTrue(hr.cost_function(psi0) == 0)
def simple_stochastic(dt=0.001): """Simple stochastic integrator with no Hamiltonian evolution""" graph = nx.Graph() graph.add_nodes_from([0, 1, 2]) graph.add_edges_from([(0, 1), (1, 2)]) graph = Graph(graph) psi0 = np.array([[0, 1, 0, 0, 0, 0, 0, 0]]).T s = State(psi0, 3, is_ket=True) hamiltonian = GreedyNoiseTwoLocal(graph, rate = 1) sw = StochasticWavefunction(hamiltonians=[hamiltonian], jumps=[hamiltonian]) output = sw.run(s.state, 0, 3, dt) print(output)
def generate_inital_state_cf(graph, diff=2, verbose=False): cost = hamiltonian.HamiltonianMaxCut(graph, cost_function=True) maxcut = np.max(cost.hamiltonian) target = maxcut - diff where_target = sparse.find(cost.hamiltonian.real == target)[0] state = np.zeros(2**graph.n) state[where_target] = 1 if verbose: print('num nonzero', len(np.argwhere(state != 0))) return State(state[:, np.newaxis] / np.linalg.norm(state), is_ket=True, graph=graph)
def compute_rate(): # Construct the first order transition matrix energies, states = eq.eig(k='all') rates = np.zeros(len(bad)) for j in range(graph.n): for i in range(len(bad)): rates[i] = rates[i] + (np.abs( states[i].conj() @ qubit.left_multiply( State(states[index].T), [j], qubit.Z))**2)[0, 0] # Select the relevant rates from 'good' to 'bad' print(rates) return rates
def evolution_generator(self, s: State): res = State(np.zeros(s.shape), is_ket=s.is_ket, code=s.code, IS_subspace=s.IS_subspace, graph=s.graph) for i in range(len(self.hamiltonians)): res = res - 1j * (self.hamiltonians[i].left_multiply(s) - self.hamiltonians[i].right_multiply(s)) for i in range(len(self.jump_operators)): res = res + self.jump_operators[i].liouvillian(s) return res