def test_fidelity(self): a = np.ones((2,1))/2**.5 a[0] = -1 * a[0] b = a * 1j a = tools.outer_product(a, a) b = tools.outer_product(b, b) assert tools.fidelity(a, b) == 1
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_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_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_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 ARvstime_EIT(tf=10, graph=None, mis=None, show_graph=False, n=3): schedule = lambda t, tf: [[t / tf, (tf - t) / tf, 1], [1]] if graph is None: graph, mis = line_graph(n=n) graph = Graph(graph) if show_graph: nx.draw(graph) plt.show() rabi1 = 3 rabi2 = 3 # Generate the driving laser1 = hamiltonian.HamiltonianDriver(transition=(0, 1), energy=rabi1, code=rydberg, IS_subspace=True, graph=graph) laser2 = hamiltonian.HamiltonianDriver(transition=(1, 2), energy=rabi2, code=rydberg, IS_subspace=True, graph=graph) rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph, code=rydberg, detuning=1, energy=0, IS_subspace=True) # Initialize spontaneous emission spontaneous_emission_rate = 1 spontaneous_emission = lindblad_operators.SpontaneousEmission( transition=(1, 2), rate=spontaneous_emission_rate, code=rydberg, IS_subspace=True, graph=graph) # Initialize master equation master_equation = LindbladMasterEquation( hamiltonians=[laser2, laser1], jump_operators=[spontaneous_emission]) # Begin with all qubits in the ground codes psi = np.zeros((rydberg_hamiltonian_cost.hamiltonian.shape[0], 1), dtype=np.complex128) psi[-1, -1] = 1 psi = tools.outer_product(psi, psi) # Generate annealing schedule results = master_equation.run_ode_solver( psi, 0, tf, num_from_time(tf), schedule=lambda t: schedule(t, tf)) cost_function = [ rydberg_hamiltonian_cost.cost_function(results[i], is_ket=False) / mis for i in range(results.shape[0]) ] print(cost_function[-1]) plt.scatter(np.linspace(0, tf, num_from_time(tf)), cost_function, c='teal', label='approximation ratio') plt.legend() plt.xlabel(r'Approximation ratio') plt.ylabel(r'Time $t$') plt.show()
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 eit_steady_state(graph, show_graph=False, gamma=1): if show_graph: nx.draw(graph) plt.show() # Generate the driving and Rydberg Hamiltonians laser1 = hamiltonian.HamiltonianDriver(transition=(1, 2), IS_subspace=True, graph=graph, code=rydberg) laser2 = hamiltonian.HamiltonianDriver(transition=(0, 1), IS_subspace=True, graph=graph, code=rydberg) rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph, IS_subspace=True, code=rydberg) spontaneous_emission = lindblad_operators.SpontaneousEmission( graph=graph, transition=(1, 2), rates=[gamma], IS_subspace=True, code=rydberg) # Initialize adiabatic algorithm simulation = SimulateAdiabatic(graph, hamiltonian=[laser1, laser2], cost_hamiltonian=rydberg_hamiltonian_cost, IS_subspace=True, noise_model='continuous', code=rydberg, noise=[spontaneous_emission]) master_equation = LindbladMasterEquation( hamiltonians=[laser1, laser2], jump_operators=[spontaneous_emission]) initial_state = State(tools.outer_product( np.array([[0, 0, 0, 0, 0, 0, 0, 1]]).T, np.array([[0, 0, 0, 0, 0, 0, 0, 1]]).T), code=rydberg, IS_subspace=True, is_ket=False) print(master_equation.steady_state(initial_state)) return simulation
def test_depolarize(self): # First test single qubit channel psi0 = State(np.zeros((4, 1))) psi0[0] = 1 psi0 = State(tools.outer_product(psi0, psi0)) psi1 = psi0.copy() psi2 = psi0.copy() psi3 = psi0.copy() psi4 = psi0.copy() p = 0.093 op0 = quantum_channels.DepolarizingChannel() psi0 = op0.channel(psi0, p, apply_to=1) op1 = quantum_channels.DepolarizingChannel() psi1 = op1.channel(psi1, 2 * p, apply_to=0) self.assertTrue(psi1[2, 2] == 0.124) self.assertTrue(psi0[1, 1] == 0.062) # Now test multi qubit channel psi2 = op0.channel(psi2, p, apply_to=[0, 1]) psi3 = op0.channel(psi3, p, apply_to=0) psi3 = op0.channel(psi3, p, apply_to=1) psi4 = op0.channel(psi4, p) self.assertTrue(np.allclose(psi2, psi3)) self.assertTrue(np.allclose(psi2, psi4)) expected = np.zeros((4, 4)) expected[0, 0] = 0.46827 expected[1, 1] = 0.03173 expected[2, 2] = 0.46827 expected[3, 3] = 0.03173 psi0 = op0.evolve(psi0, 20) self.assertTrue(np.allclose(expected, psi0)) psi0 = State(np.array([[1, 0], [0, 0]])) psi0 = op0.evolve(psi0, 20) self.assertTrue(np.allclose(psi0, .5 * np.identity(2)))
plt.show()""" # Generate the driving and Rydberg Hamiltonians # Initialize spontaneous emission IS_penalty = 20 mis_dissipation = lindblad_operators.MISDissipation(graph, IS_penalty=IS_penalty, code=qubit) hadamard_dissipation = Hadamard_Dissipation(code=qubit) rydberg = hamiltonian.HamiltonianMIS(graph, energies=[IS_penalty], code=qubit) # Initialize master equation master_equation = LindbladMasterEquation(jump_operators=[mis_dissipation]) # Begin with all qubits in the ground codes psi = tools.equal_superposition(graph.number_of_nodes()) psi = State(tools.outer_product(psi, psi)) dt = 0.1 def ARvstime(tf=10, schedule=lambda t, tf: [[], [t / tf, (tf - t) / tf]]): def ground_overlap(state): g = np.array([[0, 0], [0, 1]]) op = tools.tensor_product([g] * graph.number_of_nodes()) return np.real(np.trace(op @ state)) t_cutoff = 5 def step_schedule(t, tf): if t < t_cutoff: return [[], [t / tf, (tf - t) / tf]]
__all__ = ['multiply', 'right_multiply', 'left_multiply', 'rotation'] logical_code = True X = tools.tensor_product([tools.X(), tools.identity()]) Y = tools.tensor_product([tools.Y(), tools.Z()]) Z = tools.tensor_product([tools.Z(), tools.Z()]) n = 2 d = 2 logical_basis = np.array([[[1], [0], [0], [1]], [[0], [1], [1], [0]]]).astype( np.complex128) / np.sqrt(2) Q = 1 / 2 * (np.identity(d**n) + Z) P = 1 / 2 * (np.identity(d**n) - Z) code_space_projector = tools.outer_product( logical_basis[0], logical_basis[0]) + tools.outer_product( logical_basis[1], logical_basis[1]) def rotation(state: State, apply_to: Union[int, list], angle: float, op, is_involutary=False, is_idempotent=False): """ Apply a single qubit rotation :math:`e^{-i \\alpha A}` to the input ``codes``. :param apply_to: :param is_idempotent: :param is_involutary:
def effective_operator_comparison(graph=None, mis=None, tf=10, show_graph=False, n=3, gamma=500): # Generate annealing schedule def schedule1(t, tf): return [[t / tf, (tf - t) / tf, 1], [1]] if graph is None: graph, mis = line_graph(n=n) graph = Graph(graph) if show_graph: nx.draw(graph) plt.show() # Generate the driving and Rydberg Hamiltonians rabi1 = 1 laser1 = hamiltonian.HamiltonianDriver(transition=(0, 1), energies=[rabi1], code=rydberg, IS_subspace=True, graph=graph) rabi2 = 1 laser2 = hamiltonian.HamiltonianDriver(transition=(1, 2), energies=[rabi2], code=rydberg, IS_subspace=True, graph=graph) rydberg_hamiltonian_cost = hamiltonian.HamiltonianRydberg(graph, code=rydberg, detuning=1, energy=0, IS_subspace=True) # Initialize spontaneous emission spontaneous_emission_rate = gamma spontaneous_emission = lindblad_operators.SpontaneousEmission( transition=(1, 2), rate=spontaneous_emission_rate, code=rydberg, IS_subspace=True, graph=graph) strong_spontaneous_emission_rate = (1, 1) strong_spontaneous_emission = lindblad_operators.StrongSpontaneousEmission( transition=(0, 2), rates=strong_spontaneous_emission_rate, code=rydberg, IS_subspace=True, graph=graph) def schedule2(t, tf): return [[], [(2 * t / tf / np.sqrt(spontaneous_emission_rate), 2 * (tf - t) / tf / np.sqrt(spontaneous_emission_rate))]] # Initialize master equation master_equation = LindbladMasterEquation( hamiltonians=[laser2, laser1], jump_operators=[spontaneous_emission]) # Begin with all qubits in the ground codes psi = np.zeros((rydberg_hamiltonian_cost.hamiltonian.shape[0], 1), dtype=np.complex128) psi[-1, -1] = 1 psi = tools.outer_product(psi, psi) # Integrate the master equation results1 = master_equation.run_ode_solver( psi, 0, tf, num_from_time(tf), schedule=lambda t: schedule1(t, tf)) cost_function = [ rydberg_hamiltonian_cost.cost_function(results1[i], is_ket=False) / mis for i in range(results1.shape[0]) ] # Initialize master equation master_equation = LindbladMasterEquation( hamiltonians=[], jump_operators=[strong_spontaneous_emission]) # Integrate the master equation results2 = master_equation.run_ode_solver( psi, 0, tf, num_from_time(tf), schedule=lambda t: schedule2(t, tf)) cost_function_strong = [ rydberg_hamiltonian_cost.cost_function(results2[i], is_ket=False) / mis for i in range(results2.shape[0]) ] print(results2[-1]) times = np.linspace(0, tf, num_from_time(tf)) # Compute the fidelity of the results fidelities = [ tools.fidelity(results1[i], results2[i]) for i in range(results1.shape[0]) ] plt.plot(times, fidelities, color='r', label='Fidelity') plt.plot(times, cost_function, color='teal', label='Rydberg EIT approximation ratio') plt.plot(times, cost_function_strong, color='y', linestyle=':', label='Effective operator approximation ratio') plt.hlines(1, 0, max(times), linestyles=':', colors='k') plt.legend(loc='lower right') plt.ylim(0, 1.03) plt.xlabel(r'Annealing time $t$') plt.ylabel(r'Approximation ratio') plt.show()
p_len = 10 # Hamiltonian strength kappa = 1 # np.linspace(0, 10, 10) # Bit flip rate p_error = 1 * dt bit_flip = lindblad_operators.PauliNoise((p_error, 0, 0)) # Dissipative evolution rate rate = np.linspace(0, n, p_len) corrective = lindblad_operators.AmplitudeDampingNoise(1) noisy_results = np.zeros((p_len, n)) ec_results = np.zeros((p_len, n)) for j in range(p_len): ideal = ThreeQubitCodeTwoAncillas.basis[0] # Noise with no error correction noisy = ThreeQubitCodeTwoAncillas(tools.outer_product(ideal, ideal), N, is_ket=False) # Dissipative error correction ec = ThreeQubitCodeTwoAncillas(tools.outer_product(ideal, ideal), N, is_ket=False) # Ideal codes for fidelity calculations ideal = ThreeQubitCodeTwoAncillas(tools.outer_product(ideal, ideal), N, is_ket=False) corrective.p = rate[j] * dt for i in range(n): # Evolve density matrix # Apply bit flip evolution hamiltonian.evolve(ec, dt * kappa)
for c in G.nodes: C = C + tools.tensor_product([myeye(c), sigma_plus, myeye(N - c - 1)]) return C rydberg_noise_rate = 10 G = nx.Graph() G.add_edge(0, 1, weight=rydberg_noise_rate) #G.add_edge(2, 3, weight=rydberg_noise_rate) G.add_edge(0, 2, weight=rydberg_noise_rate) G.add_edge(1, 2, weight=rydberg_noise_rate) zero = np.zeros([1, 2**N], dtype=np.complex128) zero[-1, -1] = 1 zero = zero.T zero = tools.outer_product(zero, zero) #plot.draw_graph(G) # Goal: numerically integrate master equation with (1) spontaneous emission and (2) IS constraint evolution # with Hb hamiltonian p = 2 spacing = 10 #se_noise_rate = 0.01 #se_noise = jump_operators.SpontaneousEmission(se_noise_rate) rydberg_noise = MISLoweringJumpOperator(G, rydberg_noise_rate) hb_x = hamiltonian.HamiltonianDriver(pauli='X') hb_y = hamiltonian.HamiltonianDriver(pauli='Y') hb_z = hamiltonian.HamiltonianDriver(pauli='Z') hMIS = hamiltonian.HamiltonianMIS(G, blockade_energy=rydberg_noise_rate) C = cost_function(G, rydberg_noise_rate) C = C / np.max(C) is_proj = IS_projector(G)